Unit Arrays;

{Author ROBERT WARREN CIS ID 70303,537}

{
	Unit provides support for arrays and huge (>64K) arrays of data.
	Each item size stored in the array must be a multiple of 2 (2,4,8,16,32..)
	in order to work using the huge arrays and matrices. This is needed so
	that you don't straddle the segment boundaries.

	To use these objects merely create the object using the appropriate
	constructor. The object will be created with it's data initialized to
	zeros (GMEM_ZEROINIT). to access an element of the object use the
	AT() method. This will return you a pointer to the element you specified.
	for huge objects it will do the segment math correctly. Then you can
	dereference the pointer and work with the data.

	This unit merely simplifies the use of huge type arrays and matrices.
	It does not do much more.

}

interface

uses WObjects,WinTypes,WinProcs;

type

PArray = ^TArray;
TArray = object(TObject)
	Handle: THandle;
	ItemSize: Word;
	Limit: LongInt;
	Address: Pointer;
	constructor Init(aItemSize: Word; aLimit: LongInt);
	destructor done; virtual;
	function At(index: LongInt): Pointer; virtual;
 end;

PMatrix = ^TMatrix;
TMatrix = object(TObject)
	Handle: THandle;
	ItemSize: Word;
	Rows,Cols: LongInt;
	Address: Pointer;
	constructor Init(aItemSize: Word; aRows,aCols: LongInt);
	destructor done; virtual;
	function At(aRow,aCol: LongInt): Pointer; virtual;
 end;

PHugeMatrix = ^THugeMatrix;
THugeMatrix = object(TMatrix)
	SegIncr : Word;
	constructor Init(aItemSize: Word; aRows,aCols: LongInt);
	function At(aRow,aCol: LongInt): Pointer; virtual;
 end;

PHugeArray = ^THugeArray;
THugeArray = object(TArray)
	SegIncr: Word;
	constructor Init(aItemSize: Word; aLimit: LongInt);
	function At(index: LongInt): Pointer; virtual;
end;

function NewArray(aItemSize: Word; aLimit: LongInt): PArray;
function NewMatrix(aItemSize: Word; aRows,aCols: LongInt): PMatrix;

implementation

{
 returns a pointer to an Array if small enough otherwise a HugeArray
}
function NewArray(aItemSize: Word; aLimit: LongInt): PArray;
var
 TempArrayPtr: PArray;
begin
 TempArrayPtr:=New(PArray,Init(aItemSize,aLimit));
 if TempArrayPtr = nil then
	TempArrayPtr:=New(PHugeArray,Init(aItemSize,aLimit));
 NewArray:=TempArrayPtr;
end;

{
 returns a pointer to an Matrix if small enough otherwise a HugeMatrix
}
function NewMatrix(aItemSize: Word; aRows,aCols: LongInt): PMatrix;
var
 TempMatrixPtr: PMatrix;
begin
 TempMatrixPtr:=New(PMatrix,Init(aItemSize,aRows,aCols));
 if TempMatrixPtr = nil then
	TempMatrixPtr:=New(PHugeMatrix,Init(aItemSize,aRows,aCols));
 NewMatrix:=TempMatrixPtr;
end;

procedure AHIncr; far; external 'KERNEL' index 114;

{ ----------------------------------------------
				TMatrix
	---------------------------------------------- }

constructor TMatrix.Init(aItemSize: Word; aRows,aCols: LongInt);
var
 InitSize: LongInt;
begin
	TObject.Init;
	Rows:=aRows;
	Cols:=aCols;
	ItemSize:=aItemSize;
	InitSize:=LongInt(ItemSize * Rows * Cols);
	if InitSize > $FFFF then fail;
	Handle:=GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT,ItemSize * Rows * Cols);
	if handle = 0 then fail;
	Address:=GlobalLock(Handle);
end;

destructor TMatrix.done;
begin
 GlobalUnlock(Handle);
 GlobalFree(Handle);
end;

function TMatrix.At(aRow,aCol: LongInt): Pointer;
var
 pos: Word;
begin
 pos:=(aRow * Cols * ItemSize) + (ACol * ItemSize);
 At:=Pointer(MakeLong(pos,HiWord(LongInt(Address))));
end;

{ ----------------------------------------------
				THugeMatrix
	---------------------------------------------- }

constructor THugeMatrix.Init(aItemSize: Word; aRows,aCols: LongInt);
begin
	TObject.Init;
	Rows:=aRows;
	Cols:=aCols;
	ItemSize:=aItemSize;

	Handle:=GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT,LongInt(ItemSize * Rows * Cols));
	if handle = 0 then fail;
	Address:=GlobalLock(Handle);
	SegIncr:=Ofs(AHIncr);
end;

function THugeMatrix.At(aRow,aCol: LongInt): Pointer;
var
 Segs,Offs: Word;
 Pos: LongInt;
begin
	pos:=(aRow * Cols * ItemSize) + (ACol * ItemSize);
	Segs:=Pos div $FFFF;
	Offs:=Pos mod $FFFF;
	At:=Pointer(MakeLong(Offs,((Segs*SegIncr)+(HiWord(LongInt(Address))))));
end;


{ ----------------------------------------------
				TArray
	---------------------------------------------- }

constructor TArray.Init(aItemSize: Word; aLimit: LongInt);
var
 InitSize: LongInt;
begin
	TObject.Init;
	ItemSize:=aItemSize;
	Limit:=aLimit;
	InitSize:=ItemSize * Limit;
	if InitSize > $FFFF then fail;
	Handle:=GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT,InitSize);
	if handle = 0 then fail;
	Address:=GlobalLock(Handle);
end;

destructor TArray.Done;
begin
 TObject.Done;
 GlobalUnlock(Handle);
 GlobalFree(Handle);
end;

function TArray.At(index: LongInt): Pointer;
begin
	At:=Pointer(LongInt(ItemSize * index) + LongInt(Address));
end;

{ ----------------------------------------------
				THugeArray
	---------------------------------------------- }

constructor THugeArray.Init(aItemSize: Word; aLimit: LongInt);
begin
	TObject.Init;
	ItemSize:=aItemSize;
	Limit:=aLimit;
	Handle:=GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT,ItemSize * Limit);
	if handle = 0 then fail;
	Address:=GlobalLock(Handle);
	SegIncr:=Ofs(AHIncr);
end;

function THugeArray.At(index: LongInt): Pointer;
var
 Segs,Offs: Word;
 Pos: LongInt;
begin
	Pos:=Index * ItemSize;
	Segs:=Pos div $FFFF;
	Offs:=Pos mod $FFFF;
	At:=Pointer(MakeLong(Offs,((Segs*SegIncr)+(HiWord(LongInt(Address))))));
end;

begin
end.