[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]