home *** CD-ROM | disk | FTP | other *** search
- unit STIAlloc;
-
- {$S-,R-,I-,V-,B-,D-}
-
- interface
-
- procedure STI_GetMem(var Point; NoBytes : LongInt);
- procedure STI_FreeMem(var Point; NoBytes : LongInt);
- function STI_Ptr2Linear(Point : Pointer) : LongInt;
- function STI_Linear2Ptr(Long : LongInt) : Pointer;
- function STI_Difference(Point1, Point2 : Pointer) : LongInt;
- function STI_Normalise(Point : Pointer) : Pointer;
-
- implementation
-
- Type
- STI_Point = record {the structure of a pointer }
- Offset, {the offset }
- Segment : Word; {the segment }
- end;
-
- FreeListRec = record
- BeginPtr : Pointer; {pointer to the start of a block}
- EndPtr : Pointer; {pointer to the end of a block }
- end;
- FreeListRecPtr = ^FreeListRec; {pointer to a free list entry }
-
- {---------------------------------------------------------------------------}
-
- function STI_Normalise(Point : Pointer) : Pointer;
-
- begin {return a normalised pointer }
- inline(
- $58/ {pop ax ;pop offset into AX }
- $5A/ {pop dx ;pop segment into DX }
- $89/$C3/ {mov bx,ax ;BX = Ofs(P^) }
- $B1/$04/ {mov cl,4 ;CL = 4 }
- $D3/$EB/ {shr bx,cl ;BX = Ofs(P^) div 16 }
- $01/$DA/ {add dx,bx ;add BX to segment }
- $25/$0F/$00); {and ax,$F ;mask unwanted bits }
- end;
-
- {---------------------------------------------------------------------------}
-
- function STI_Ptr2Linear(Point : Pointer) : LongInt;
-
- begin {convert a pointer to linear }
- with STI_Point(Point) do
- STI_Ptr2Linear :=
- (LongInt(Segment) shl 4)+LongInt(Offset);
- end;
-
- {---------------------------------------------------------------------------}
-
- function STI_Linear2Ptr(Long : LongInt) : Pointer;
-
- begin {convert Long to a pointer }
- STI_Linear2Ptr :=
- Ptr(Word(Long shr 4), Word(Long and $0000000F));
- end;
-
- {---------------------------------------------------------------------------}
-
- function STI_Difference(Point1, Point2 : Pointer) : LongInt;
-
- begin {return difference in bytes }
- STI_Difference :=
- Abs(STI_Ptr2Linear(Point1)-STI_Ptr2Linear(Point2));
- end;
-
- {---------------------------------------------------------------------------}
-
- procedure STI_GetMem(var Point; NoBytes : LongInt);
-
- var
- NewPoint : Pointer absolute Point;
- NewFreePtr : FreeListRecPtr;
- Top : Pointer;
- ThisBlock : LongInt;
-
- begin
- NewPoint := NIL; {null the new pointer }
- NewFreePtr := FreePtr; {save the old free pointer }
- if STI_Point(NewFreePtr).Offset = 0 then {check the segment boundary }
- Inc(STI_Point(NewFreePtr).Segment,$1000);
-
- {point to top of free memory ????}
- if FreeMin = 0 then
- Top := Ptr(STI_Point(FreePtr).Segment+$1000, 0)
- else
- Top := Ptr(STI_Point(FreePtr).Segment, -FreeMin);
- if STI_Ptr2Linear(NewFreePtr) < STI_Ptr2Linear(Top) then
- Top := NewFreePtr;
-
- {check block at HeapPtr^}
- if STI_Difference(Top, HeapPtr) >= NoBytes then
- begin
- {use this block}
- NewPoint := HeapPtr;
-
- {adjust HeapPtr}
- HeapPtr := STI_Linear2Ptr(STI_Ptr2Linear(HeapPtr)+NoBytes);
- end
- else
- while STI_Point(NewFreePtr).Offset <> 0 do
- begin
- {search the free list for a memory block that is big enough}
- with NewFreePtr^ do
- begin
- {calculate the size of the block}
- ThisBlock := STI_Difference(EndPtr, BeginPtr);
-
- if ThisBlock > NoBytes then
- begin
- {bigger than we need--shrink the size of the block}
- NewPoint := BeginPtr;
- BeginPtr := STI_Linear2Ptr(STI_Ptr2Linear(BeginPtr)+NoBytes);
- Exit;
- end
- else
- if ThisBlock = NoBytes then
- begin
- {exact size--remove the record from the free list}
- NewPoint := BeginPtr;
-
- {move the entry at the bottom of the free list up}
- NewFreePtr^ := FreeListRecPtr(FreePtr)^;
-
- {adjust FreePtr}
- with STI_point(FreePtr) do
- Inc(Offset, SizeOf(FreeListRec));
- Exit;
- end;
- end;
-
- {point to next record on free list}
- Inc(STI_Point(NewFreePtr).Offset, SizeOf(FreeListRec));
- end;
- end;
-
- {---------------------------------------------------------------------------}
-
- procedure STI_FreeMem(var Point; NoBytes : LongInt);
-
- var
- NewPoint : Pointer absolute Point;
- EndP : Pointer;
- FP, SaveFP, NewFreePtr : FreeListRecPtr;
- I : Word;
- Found : Boolean;
-
- begin
- {exit if P is nil}
- if (NewPoint = nil) then
- Exit;
-
- {calculate pointer to end of block}
- EndP := STI_Linear2Ptr(STI_Ptr2Linear(NewPoint)+NoBytes);
-
- {see if this is just below HeapPtr^}
- if EndP = HeapPtr then
- {just reset HeapPtr}
- HeapPtr := NewPoint
- else begin
- {search for a free list entry to combine this block with}
- Found := False;
- FP := FreePtr;
- while (STI_Point(FP).Offset <> 0) and not Found do begin
- with FP^ do
- {does the end of our block match the start of this one?}
- if BeginPtr = EndP then begin
- BeginPtr := NewPoint;
- Found := True;
- end
- {does the start of our block match the end of this one?}
- else if EndPtr = NewPoint then begin
- EndPtr := EndP;
- Found := True;
- end;
-
- {point to next record on free list}
- if not Found then
- Inc(STI_Point(FP).Offset, SizeOf(FreeListRec));
- end;
-
- if Found then begin
- {save pointer into free list and get pointers to search for}
- SaveFP := FP;
- with FP^ do begin
- NewPoint := BeginPtr;
- EndP := EndPtr;
- end;
-
- {see if we can combine this block with a second}
- Found := False;
- FP := FreePtr;
- while (STI_Point(FP).Offset <> 0) and not Found do begin
- with FP^ do
- {does the end of our block match the start of this one?}
- if BeginPtr = EndP then begin
- BeginPtr := NewPoint;
- Found := True;
- end
- {does the start of our block match the end of this one?}
- else if EndPtr = NewPoint then begin
- EndPtr := EndP;
- Found := True;
- end;
-
- {point to next record on free list}
- if not Found then
- Inc(STI_Point(FP).Offset, SizeOf(FreeListRec));
- end;
-
- if Found then begin
- {we combined two blocks--get rid of the 1st free list entry we found}
-
- {move the entry at the bottom of the free list up into its place}
- SaveFP^ := FreeListRecPtr(FreePtr)^;
-
- {adjust FreePtr}
- with STI_Point(FreePtr) do
- Inc(Offset, SizeOf(FreeListRec));
- end;
- end
- else begin
- {can't combine with anything--add an entry to the free list}
-
- {calculate new FreePtr}
- with STI_Point(FreePtr) do
- NewFreePtr := Ptr(Segment, Offset-SizeOf(FreeListRec));
-
- {make sure the free list isn't full}
- with STI_Point(NewFreePtr) do
- if (STI_Ptr2Linear(NewFreePtr) < STI_Ptr2Linear(HeapPtr)) or (Offset = 0) then begin
- {it's full--let real FreeMem generate a runtime error}
- if NoBytes > 65521 then
- I := 65521
- else
- I := NoBytes;
- FreeMem(NewPoint, I);
- Exit;
- end;
-
- {fill in the new free list entry}
- with NewFreePtr^ do begin
- BeginPtr := NewPoint;
- EndPtr := EndP;
- end;
-
- {adjust FreePtr}
- FreePtr := NewFreePtr;
- end;
-
- {set P to nil}
- NewPoint := nil;
- end;
- end;
-
- {---------------------------------------------------------------------------}
-
- begin
- end.