292 lines
11 KiB
ObjectPascal
292 lines
11 KiB
ObjectPascal
unit dpgrtl.charqueue;
|
|
|
|
interface
|
|
uses
|
|
dpgrtl.types;
|
|
|
|
type
|
|
TCharQueue = class( TInterfacedObject)
|
|
private
|
|
fBlockLog : integer; // log2 of block size
|
|
fBlockSize : integer; // block size
|
|
|
|
fOffset : integer; // logical start of the vector
|
|
fCount : integer; // items in a vector
|
|
fArray : TCharMatrix; // data
|
|
|
|
private
|
|
procedure Expand( i: integer);
|
|
|
|
protected
|
|
function GetItem( i:integer): AnsiChar;
|
|
procedure SetItem( i:integer; Value:AnsiChar);
|
|
|
|
public
|
|
procedure Clear;
|
|
procedure Add( Value : AnsiChar);
|
|
procedure Remove( ACount: integer);
|
|
|
|
public
|
|
procedure AfterConstruction; override;
|
|
procedure BeforeDestruction; override;
|
|
|
|
public
|
|
property Count : integer read fCount;
|
|
property Items[i:integer] : AnsiChar read GetItem write SetItem;
|
|
end;
|
|
|
|
implementation
|
|
uses
|
|
System.Math,
|
|
System.SysUtils;
|
|
|
|
{ TCharQueue }
|
|
|
|
// @@@: construction/destruction ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// construction/destruction
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// After Construction
|
|
// ================================================================================================
|
|
procedure TCharQueue.AfterConstruction;
|
|
begin
|
|
inherited;
|
|
|
|
fBlockLog := trunc( log2( 4096));
|
|
fBlockSize := trunc( IntPower(2, fBlockLog));
|
|
|
|
fArray := nil;
|
|
fOffset := 0;
|
|
fCount := 0;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Before Destruction
|
|
// ================================================================================================
|
|
procedure TCharQueue.BeforeDestruction;
|
|
var
|
|
i: integer;
|
|
|
|
begin
|
|
Clear;
|
|
|
|
for i:=Low(fArray) to High(fArray) do
|
|
fArray[i] := nil;
|
|
|
|
fArray := nil;
|
|
inherited;
|
|
end;
|
|
|
|
// @@@: Interface +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Interface
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// Add
|
|
// ================================================================================================
|
|
procedure TCharQueue.Add(Value: AnsiChar);
|
|
begin
|
|
Items[ fCount +1] := Value
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Remove
|
|
//
|
|
// Removes 'Count' items from the beginning of the queue. If the 'Count' is bigger than the
|
|
// count then simply clear the Queue.
|
|
// ================================================================================================
|
|
procedure TCharQueue.Remove( ACount: integer);
|
|
var
|
|
tmp: TCharMatrix;
|
|
i : integer;
|
|
|
|
begin
|
|
if ACount > 0 then
|
|
begin
|
|
// ------------------------------------------------------------
|
|
// if the removable item count > than the item count, then
|
|
// simply clear the queue...
|
|
// ------------------------------------------------------------
|
|
if ACount > fCount then
|
|
Clear
|
|
|
|
|
|
// ------------------------------------------------------------
|
|
// ...else calculate the new offset and count values. If the
|
|
// one or more blocks in the vector beginning is freed, then
|
|
// move these blocks to the end of the vector.
|
|
// ------------------------------------------------------------
|
|
else begin
|
|
INC( fOffset, ACount);
|
|
DEC( fCount, ACount);
|
|
|
|
SetLength( tmp, 1);
|
|
|
|
// ---------------------------------------------------------
|
|
// Well, not so efficient, but simple
|
|
// ---------------------------------------------------------
|
|
while fOffset > fBlockSize -1 do
|
|
begin
|
|
tmp[0] := fArray[0];
|
|
|
|
// --------------------------------------------
|
|
// clear the free block
|
|
// --------------------------------------------
|
|
for i:=0 to High(tmp[0]) do
|
|
tmp[0,i] := #0;
|
|
|
|
// --------------------------------------------
|
|
// shift blocks down
|
|
// --------------------------------------------
|
|
for i:=0 to High(fArray)-1 do
|
|
fArray[i] := fArray[i+1];
|
|
|
|
// --------------------------------------------
|
|
// set the vector's last block
|
|
// --------------------------------------------
|
|
fArray[High(fArray)] := tmp[0];
|
|
|
|
DEC( fOffset, fBlockSize)
|
|
end;
|
|
|
|
tmp := nil
|
|
end
|
|
end
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Clear
|
|
//
|
|
// This is a real pain in the ass. I'm not in the mood to optimize it.
|
|
// ================================================================================================
|
|
procedure TCharQueue.Clear;
|
|
var
|
|
i: integer;
|
|
|
|
begin
|
|
for i:=1 to fCount do
|
|
Items[i] := #0;
|
|
|
|
fOffset := 0;
|
|
fCount := 0;
|
|
end;
|
|
|
|
|
|
// @@@: Property Handlers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Property Handlers
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// Get Item
|
|
//
|
|
// Get the item specified by it's index. If the index less than 1 or bigger than the size of
|
|
// the queue, an ERangeError exception will be generated.
|
|
// ================================================================================================
|
|
function TCharQueue.GetItem(i: integer): AnsiChar;
|
|
var
|
|
block: integer;
|
|
index: integer;
|
|
|
|
begin
|
|
// -------------------------------------------------------------------------
|
|
// Check for valid index value.
|
|
// -------------------------------------------------------------------------
|
|
if i > fCount then raise ERangeError.CreateFmt( 'Index "%d" is too big', [i]);
|
|
if i < 1 then raise ERangeError.CreateFmt( 'Index is less than 1', []);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Now process the request.
|
|
// -------------------------------------------------------------------------
|
|
block := (i -1 +fOffset) shr fBlockLog;
|
|
index := (i -1 +fOffset) and (fBlockSize -1);
|
|
|
|
result := fArray[block,index];
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Set Item
|
|
//
|
|
// Set the item specified by it's index. If the the index bigger than the count of the Queue
|
|
// then the Queue will be resized to hold this data. If the index less than 1 an ERangeError
|
|
// exception will be generated.
|
|
// ================================================================================================
|
|
procedure TCharQueue.SetItem(i: integer; Value: AnsiChar);
|
|
var
|
|
block: integer;
|
|
index: integer;
|
|
|
|
begin
|
|
// -------------------------------------------------------------------------
|
|
// Check for valid index value.
|
|
// -------------------------------------------------------------------------
|
|
if i < 1 then raise ERangeError.CreateFmt( 'Index is less than 1', []);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// If the index bigger than the size of the Queue then expand the Queue.
|
|
// -------------------------------------------------------------------------
|
|
if i > fCount then
|
|
begin
|
|
Expand(i);
|
|
fCount := i;
|
|
end;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Now process the request.
|
|
// -------------------------------------------------------------------------
|
|
block := (i -1 +fOffset) shr fBlockLog;
|
|
index := (i -1 +fOffset) and (fBlockSize -1);
|
|
|
|
fArray[block,index] := Value
|
|
end;
|
|
|
|
// @@@: Internals +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Internals
|
|
//
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// ================================================================================================
|
|
// Expand
|
|
//
|
|
// Expands the Queue. The size of expanding is always fBlockSize*n.
|
|
// ================================================================================================
|
|
procedure TCharQueue.Expand(i: integer);
|
|
var
|
|
hi: integer;
|
|
bn: integer;
|
|
j : integer;
|
|
|
|
begin
|
|
if (i-1)+fOffset >= (High(fArray)+1) * fBlockSize then
|
|
begin
|
|
hi := High(fArray) +1;
|
|
bn := (i-1+fOffset) shr fBlockLog;
|
|
|
|
SetLength( fArray, bn+1);
|
|
|
|
for j:=hi to bn do
|
|
SetLength( fArray[j], fBlockSize);
|
|
end;
|
|
end;
|
|
|
|
end.
|