unit BigArray; { This unit contains an objects that allows for the creation of arrays larger than 64K. } interface { The ifdefs allow compiling under windows or protected mode } {$ifdef windows} uses WinTypes, WinProcs, WinAPI; {$else} uses WinAPI; {$endif} const SegSize = 65536; { Size of a selector } { Our BigArray object will allow us to allocate large chucks of memory (>64k) and index our way through the items } type PBigArray = ^TBigArray; TBigArray = object MemStart : THandle; MemOffset : longint; MemSize : longint; MaxItems : longint; ItemSize : longint; constructor Init(NoItems : longint; Size : Word); destructor Done; virtual; procedure PutData(var Item; Index : longint); virtual; procedure GetData(var Item; Index : longint); virtual; procedure Resize(NoItems : longint); virtual; function GetMeMSize : longint; virtual; end; implementation constructor TBigArray.Init(NoItems : longint; Size : Word); { Determine the size of the memory we need, allocate using the GlobalAlloc() routine, and initialize the fields } begin MaxItems := NoItems; ItemSize := Size; { compute memory size } MemSize := MaxItems * ItemSize; { allocate the memory } MemStart := GlobalAlloc(gmem_Moveable, MemSize); { any error? } if MemStart = 0 then RunError(203); MemOffset := 0; end; destructor TBigArray.Done; { Free up the memory } begin GlobalFree(MemStart); end; procedure TBigArray.PutData(var Item; Index : longint); { Put the item in the allocated memory } var Sel, Off : word; P : pointer; FinishIt : boolean; TempItemSize : word; begin if Index >= MaxItems then RunError(201); inc(MemOffset, ItemSize); { compute index into memory } Index := Index * ItemSize; { determine the starting selector to access } Sel := (Index div SegSize) * SelectorInc + MemStart; { determine the offset into that selector } Off := Index mod SegSize; if (SegSize - Off) < ItemSize then begin TempItemSize := SegSize - Off; FinishIt := true; end else begin TempItemSize := ItemSize; FinishIt := false; end; { lock the memory - this only applies to windows } GlobalLock(Sel); { get the pointer value } P := ptr(Sel, Off); { move the data into memory } Move(Item, P^, TempItemSize); { unlock the memory - this only applies to windows } GlobalUnLock(Sel); if FinishIt then begin Sel := Sel + SelectorInc; Off := 0; { lock the memory - this only applies to windows } GlobalLock(Sel); { get the pointer value } P := ptr(Sel, Off); { move the data into memory } Move(Item, P^, TempItemSize); { unlock the memory - this only applies to windows } GlobalUnLock(Sel); end; end; procedure TBigArray.GetData(var Item; Index : longint); { Get the item out of memory } var Sel, Off : word; P : pointer; FinishIt : boolean; TempItemSize : word; begin if Index >= MaxItems then RunError(201); { compute index into memory } Index := Index * ItemSize; { determine the starting selector to access } Sel := (Index div SegSize) * SelectorInc + MemStart; { determine the offset into that selector } Off := Index mod SegSize; if (SegSize - Off) < ItemSize then begin TempItemSize := SegSize - Off; FinishIt := true; end else begin TempItemSize := ItemSize; FinishIt := false; end; { lock the memory - this only applies to windows } GlobalLock(Sel); { get the pointer value } P := ptr(Sel, Off); { move the data from memory to the field } Move(P^, Item, TempItemSize); { unlock the memory - this only applies to windows } GlobalUnLock(Sel); if FinishIt then begin Sel := Sel + SelectorInc; Off := 0; { lock the memory - this only applies to windows } GlobalLock(Sel); { get the pointer value } P := ptr(Sel, Off); { move the data into memory } Move(Item, P^, TempItemSize); { unlock the memory - this only applies to windows } GlobalUnLock(Sel); end; dec(MemOffset, ItemSize); end; procedure TBigArray.Resize(NoItems : longint); { With a call to GlobalReAlloc() we can resize the array with out loosing any data. Here we also reinitialize the fields } var TempMem : THandle; begin MaxItems := NoItems; { compute new memory size } MemSize := MaxItems * ItemSize; { resize the memory allocated } TempMem := GlobalReAlloc(MemStart, MemSize, gmem_Moveable); { any errors? } if TempMem = 0 then RunError(203); MemStart := TempMem; end; function TBigArray.GetMemSize : longint; { returns the current number of bytes allocated for the array } begin GetMemSize := MemSize; end; end. {------------------------ DEMO PROGRAM --------------------- } program TestBigArray; {$ifdef Windows} uses WinDos, WinCrt, WinTypes, WinProcs, BigArray; {$else} uses Dos, Crt, WinAPI, BigArray; {$endif} const elnum = 2000; type TRec = record i : integer; r : real; s : string; a : array[0..3000] of char; end; var Rec : TRec; BArray : PBigArray; X : longint; begin clrscr; writeln('memory available = ', memavail); new(BArray, Init(elnum, SizeOf(TRec))); for x := 0 to elnum-1 do begin Rec.i := x; BArray^.PutData(Rec, x); end; for x := elnum-1 downto 0 do begin BArray^.GetData(Rec, x); if x <> Rec.i then writeln(Rec.i); end; writeln('first size of mem for array = ', BArray^.GetMemSize); { BArray^.Resize(20000); for x := 10000 to 19999 do begin Rec.i := x; BArray^.PutData(Rec, x); end; for x := 19999 downto 0 do begin BArray^.GetData(Rec, x); writeln(Rec.i); end; writeln('second size of mem for array = ', BArray^.GetMemSize); } dispose(BArray, Done); readln; end.