[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]
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.
[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]