* Added bucket lists implementation

git-svn-id: trunk@11086 -
This commit is contained in:
michael 2008-05-26 18:26:47 +00:00
parent 0cf0c22521
commit b9956b2c6f

View File

@ -471,22 +471,113 @@ type
Property OwnsObjects : Boolean Read FOwnsObjects Write FOwnsObjects;
end;
EDuplicate = class(Exception);
EKeyNotFound = class(Exception);
function RSHash(const S: string; const TableSize: Longword): Longword;
{ ---------------------------------------------------------------------
Bucket lists as in Delphi
---------------------------------------------------------------------}
Type
TBucketItem = record
Item, Data: Pointer;
end;
TBucketItemArray = array of TBucketItem;
TBucket = record
Count : Integer;
Items : TBucketItemArray;
end;
PBucket = ^TBucket;
TBucketArray = array of TBucket;
TBucketProc = procedure(AInfo, AItem, AData: Pointer; out AContinue: Boolean);
TBucketProcObject = procedure(AItem, AData: Pointer; out AContinue: Boolean) of Object;
{ ---------------------------------------------------------------------
TCustomBucketList
---------------------------------------------------------------------}
{ TCustomBucketList }
TCustomBucketList = class(TObject)
private
FBuckets: TBucketArray;
function GetBucketCount: Integer;
function GetData(AItem: Pointer): Pointer;
procedure SetData(AItem: Pointer; const AData: Pointer);
procedure SetBucketCount(const Value: Integer);
protected
Procedure GetBucketItem(AItem: Pointer; out ABucket, AIndex: Integer);
function AddItem(ABucket: Integer; AItem, AData: Pointer): Pointer; virtual;
function BucketFor(AItem: Pointer): Integer; virtual; abstract;
function DeleteItem(ABucket: Integer; AIndex: Integer): Pointer; virtual;
Procedure Error(Msg : String; Args : Array of Const);
function FindItem(AItem: Pointer; out ABucket, AIndex: Integer): Boolean; virtual;
property Buckets: TBucketArray read FBuckets;
property BucketCount: Integer read GetBucketCount write SetBucketCount;
public
destructor Destroy; override;
procedure Clear;
function Add(AItem, AData: Pointer): Pointer;
procedure Assign(AList: TCustomBucketList);
function Exists(AItem: Pointer): Boolean;
function Find(AItem: Pointer; out AData: Pointer): Boolean;
function ForEach(AProc: TBucketProc; AInfo: Pointer = nil): Boolean;
function ForEach(AProc: TBucketProcObject): Boolean;
function Remove(AItem: Pointer): Pointer;
property Data[AItem: Pointer]: Pointer read GetData write SetData; default;
end;
{ ---------------------------------------------------------------------
TBucketList
---------------------------------------------------------------------}
TBucketListSizes = (bl2, bl4, bl8, bl16, bl32, bl64, bl128, bl256);
{ TBucketList }
TBucketList = class(TCustomBucketList)
private
FBucketMask: Byte;
protected
function BucketFor(AItem: Pointer): Integer; override;
public
constructor Create(ABuckets: TBucketListSizes = bl16);
end;
{ ---------------------------------------------------------------------
TObjectBucketList
---------------------------------------------------------------------}
{ TObjectBucketList }
TObjectBucketList = class(TBucketList)
protected
function GetData(AItem: TObject): TObject;
procedure SetData(AItem: TObject; const AData: TObject);
public
function Add(AItem, AData: TObject): TObject;
function Remove(AItem: TObject): TObject;
property Data[AItem: TObject]: TObject read GetData write SetData; default;
end;
implementation
uses
RtlConsts;
ResourceString
DuplicateMsg = 'An item with key %0:s already exists';
DuplicateMsg = 'An item with key %0:s already exists';
KeyNotFoundMsg = 'Method: %0:s key [''%1:s''] not found in container';
NotEmptyMsg = 'Hash table not empty.';
NotEmptyMsg = 'Hash table not empty.';
SErrNoSuchItem = 'No item in list for %p';
SDuplicateItem = 'Item already exists in list: %p';
const
NPRIMES = 28;
@ -2342,4 +2433,291 @@ begin
Inherited;
end;
{ TCustomBucketList }
function TCustomBucketList.GetData(AItem: Pointer): Pointer;
Var
B,I : Integer;
begin
GetBucketItem(AItem,B,I);
Result:=FBuckets[B].Items[I].Data;
end;
function TCustomBucketList.GetBucketCount: Integer;
begin
Result:=Length(FBuckets);
end;
procedure TCustomBucketList.SetData(AItem: Pointer; const AData: Pointer);
Var
B,I : Integer;
begin
GetBucketItem(AItem,B,I);
FBuckets[B].Items[I].Data:=AData;
end;
procedure TCustomBucketList.SetBucketCount(const Value: Integer);
begin
If (Value<>GetBucketCount) then
SetLength(FBuckets,Value);
end;
procedure TCustomBucketList.GetBucketItem(AItem: Pointer; out ABucket,
AIndex: Integer);
begin
If Not FindItem(AItem,ABucket,AIndex) then
Error(SErrNoSuchItem,[AItem]);
end;
function TCustomBucketList.AddItem(ABucket: Integer; AItem, AData: Pointer
): Pointer;
Var
B : PBucket;
L : Integer;
begin
B:=@FBuckets[ABucket];
L:=Length(B^.Items);
If (B^.Count=L) then
begin
If L<8 then
L:=8
else
L:=L+L div 2;
SetLength(B^.Items,L);
end;
With B^ do
begin
Items[Count].Item:=AItem;
Items[Count].Data:=AData;
Result:=AData;
Inc(Count);
end;
end;
function TCustomBucketList.DeleteItem(ABucket: Integer; AIndex: Integer): Pointer;
Var
B : PBucket;
L : Integer;
begin
B:=@FBuckets[ABucket];
Result:=B^.Items[Aindex].Data;
If B^.Count=1 then
SetLength(B^.Items,0)
else
begin
L:=(B^.Count-AIndex-1);// No point in moving if last one...
If L>0 then
Move(B^.Items[AIndex+1],B^.Items[AIndex],L*SizeOf(TBucketItem));
end;
Dec(B^.Count);
end;
procedure TCustomBucketList.Error(Msg: String; Args: array of const);
begin
Raise ElistError.CreateFmt(Msg,Args);
end;
function TCustomBucketList.FindItem(AItem: Pointer; out ABucket, AIndex: Integer
): Boolean;
Var
I : Integer;
B : TBucket;
begin
ABucket:=BucketFor(AItem);
B:=FBuckets[ABucket];
I:=B.Count-1;
While (I>=0) And (B.Items[I].Item<>AItem) do
Dec(I);
Result:=I>=0;
If Result then
AIndex:=I;
end;
destructor TCustomBucketList.Destroy;
begin
Clear;
inherited Destroy;
end;
procedure TCustomBucketList.Clear;
Var
B : TBucket;
I,J : Integer;
begin
For I:=0 to Length(FBuckets)-1 do
begin
B:=FBuckets[I];
For J:=B.Count-1 downto 0 do
DeleteItem(I,J);
end;
SetLength(FBuckets,0);
end;
function TCustomBucketList.Add(AItem, AData: Pointer): Pointer;
Var
B,I : Integer;
begin
If FindItem(AItem,B,I) then
Error(SDuplicateItem,[AItem]);
Result:=AddItem(B,AItem,AData);
end;
procedure TCustomBucketList.Assign(AList: TCustomBucketList);
Var
I,J : Integer;
begin
Clear;
SetLength(FBuckets,Length(Alist.FBuckets));
For I:=0 to BucketCount-1 do
begin
SetLength(FBuckets[i].Items,Length(AList.Fbuckets[I].Items));
For J:=0 to AList.Fbuckets[I].Count-1 do
With AList.Fbuckets[I].Items[J] do
AddItem(I,Item,Data);
end;
end;
function TCustomBucketList.Exists(AItem: Pointer): Boolean;
Var
B,I : Integer;
begin
Result:=FindItem(Aitem,B,I);
end;
function TCustomBucketList.Find(AItem: Pointer; out AData: Pointer): Boolean;
Var
B,I : integer;
begin
Result:=FindItem(AItem,B,I);
If Result then
AData:=FBuckets[B].Items[I].Data;
end;
function TCustomBucketList.ForEach(AProc: TBucketProc; AInfo: Pointer
): Boolean;
Var
I,J,S : Integer;
Bu : TBucket;
begin
I:=0;
Result:=True;
S:=GetBucketCount;
While Result and (I<S) do
begin
J:=0;
Bu:=FBuckets[I];
While Result and (J<Bu.Count) do
begin
With Bu.Items[J] do
AProc(AInfo,Item,Data,Result);
Inc(J);
end;
Inc(I);
end;
end;
function TCustomBucketList.ForEach(AProc: TBucketProcObject): Boolean;
Var
I,J,S : Integer;
Bu : TBucket;
begin
I:=0;
Result:=True;
S:=GetBucketCount;
While Result and (I<S) do
begin
J:=0;
Bu:=FBuckets[I];
While Result and (J<Bu.Count) do
begin
With Bu.Items[J] do
AProc(Item,Data,Result);
Inc(J);
end;
Inc(I);
end;
end;
function TCustomBucketList.Remove(AItem: Pointer): Pointer;
Var
B,I : integer;
begin
If FindItem(AItem,B,I) then
begin
Result:=FBuckets[B].Items[I].Data;
DeleteItem(B,I);
end
else
Result:=Nil;
end;
{ TBucketList }
function TBucketList.BucketFor(AItem: Pointer): Integer;
begin
// Pointers on average have a granularity of 4
Result:=(PtrInt(AItem) shr 2) and FBucketMask;
end;
constructor TBucketList.Create(ABuckets: TBucketListSizes);
Var
L : Integer;
begin
Inherited Create;
L:=1 shl (Ord(Abuckets)+1);
SetBucketCount(L);
FBucketMask:=L-1;
end;
{ TObjectBucketList }
function TObjectBucketList.GetData(AItem: TObject): TObject;
begin
Result:=TObject(Inherited GetData(AItem));
end;
procedure TObjectBucketList.SetData(AItem: TObject; const AData: TObject);
begin
Inherited SetData(Pointer(AItem),Pointer(AData));
end;
function TObjectBucketList.Add(AItem, AData: TObject): TObject;
begin
Result:=TObject(Inherited Add(Pointer(AItem),Pointer(AData)));
end;
function TObjectBucketList.Remove(AItem: TObject): TObject;
begin
Result:=TObject(Inherited Remove(Pointer(AItem)));
end;
end.