mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-17 13:39:36 +02:00
1145 lines
26 KiB
ObjectPascal
1145 lines
26 KiB
ObjectPascal
{
|
|
This file is part of the Free Component Library (FCL)
|
|
Copyright (c) 2002 by Florian Klaempfl
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
{$ifdef fpc}
|
|
{$mode objfpc}
|
|
{$endif}
|
|
{$H+}
|
|
unit contnrs;
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils,Classes;
|
|
|
|
|
|
Type
|
|
|
|
{$inline on}
|
|
|
|
TFPObjectList = class(TObject)
|
|
private
|
|
FFreeObjects : Boolean;
|
|
FList: TFPList;
|
|
function GetCount: integer;
|
|
procedure SetCount(const AValue: integer);
|
|
protected
|
|
function GetItem(Index: Integer): TObject; {$ifdef HASINLINE} inline;{$endif}
|
|
procedure SetItem(Index: Integer; AObject: TObject); {$ifdef HASINLINE} inline;{$endif}
|
|
procedure SetCapacity(NewCapacity: Integer);
|
|
function GetCapacity: integer;
|
|
public
|
|
constructor Create;
|
|
constructor Create(FreeObjects : Boolean);
|
|
destructor Destroy; override;
|
|
procedure Clear;
|
|
function Add(AObject: TObject): Integer; {$ifdef HASINLINE} inline;{$endif}
|
|
procedure Delete(Index: Integer); {$ifdef HASINLINE} inline;{$endif}
|
|
procedure Exchange(Index1, Index2: Integer);
|
|
function Expand: TFPObjectList;
|
|
function Extract(Item: TObject): TObject;
|
|
function Remove(AObject: TObject): Integer;
|
|
function IndexOf(AObject: TObject): Integer;
|
|
function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
|
|
procedure Insert(Index: Integer; AObject: TObject); {$ifdef HASINLINE} inline;{$endif}
|
|
function First: TObject;
|
|
function Last: TObject;
|
|
procedure Move(CurIndex, NewIndex: Integer);
|
|
procedure Assign(Obj:TFPObjectList);
|
|
procedure Pack;
|
|
procedure Sort(Compare: TListSortCompare);
|
|
property Capacity: Integer read GetCapacity write SetCapacity;
|
|
property Count: Integer read GetCount write SetCount;
|
|
property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
|
|
property Items[Index: Integer]: TObject read GetItem write SetItem; default;
|
|
property List: TFPList read FList;
|
|
end;
|
|
|
|
|
|
TObjectList = class(TList)
|
|
private
|
|
ffreeobjects : boolean;
|
|
Protected
|
|
Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
|
|
function GetItem(Index: Integer): TObject;
|
|
Procedure SetItem(Index: Integer; AObject: TObject);
|
|
public
|
|
constructor create;
|
|
constructor create(freeobjects : boolean);
|
|
function Add(AObject: TObject): Integer;
|
|
function Extract(Item: TObject): TObject;
|
|
function Remove(AObject: TObject): Integer;
|
|
function IndexOf(AObject: TObject): Integer;
|
|
function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
|
|
Procedure Insert(Index: Integer; AObject: TObject);
|
|
function First: TObject;
|
|
Function Last: TObject;
|
|
property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
|
|
property Items[Index: Integer]: TObject read GetItem write SetItem; default;
|
|
end;
|
|
|
|
TComponentList = class(TObjectList)
|
|
Private
|
|
FNotifier : TComponent;
|
|
Protected
|
|
Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
|
|
Function GetItems(Index: Integer): TComponent;
|
|
Procedure SetItems(Index: Integer; AComponent: TComponent);
|
|
Procedure HandleFreeNotify(Sender: TObject; AComponent: TComponent);
|
|
public
|
|
destructor Destroy; override;
|
|
Function Add(AComponent: TComponent): Integer;
|
|
Function Extract(Item: TComponent): TComponent;
|
|
Function Remove(AComponent: TComponent): Integer;
|
|
Function IndexOf(AComponent: TComponent): Integer;
|
|
Function First: TComponent;
|
|
Function Last: TComponent;
|
|
Procedure Insert(Index: Integer; AComponent: TComponent);
|
|
property Items[Index: Integer]: TComponent read GetItems write SetItems; default;
|
|
end;
|
|
|
|
TClassList = class(TList)
|
|
protected
|
|
Function GetItems(Index: Integer): TClass;
|
|
Procedure SetItems(Index: Integer; AClass: TClass);
|
|
public
|
|
Function Add(AClass: TClass): Integer;
|
|
Function Extract(Item: TClass): TClass;
|
|
Function Remove(AClass: TClass): Integer;
|
|
Function IndexOf(AClass: TClass): Integer;
|
|
Function First: TClass;
|
|
Function Last: TClass;
|
|
Procedure Insert(Index: Integer; AClass: TClass);
|
|
property Items[Index: Integer]: TClass read GetItems write SetItems; default;
|
|
end;
|
|
|
|
TOrderedList = class(TObject)
|
|
private
|
|
FList: TList;
|
|
protected
|
|
Procedure PushItem(AItem: Pointer); virtual; abstract;
|
|
Function PopItem: Pointer; virtual;
|
|
Function PeekItem: Pointer; virtual;
|
|
property List: TList read FList;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
Function Count: Integer;
|
|
Function AtLeast(ACount: Integer): Boolean;
|
|
Function Push(AItem: Pointer): Pointer;
|
|
Function Pop: Pointer;
|
|
Function Peek: Pointer;
|
|
end;
|
|
|
|
{ TStack class }
|
|
|
|
TStack = class(TOrderedList)
|
|
protected
|
|
Procedure PushItem(AItem: Pointer); override;
|
|
end;
|
|
|
|
{ TObjectStack class }
|
|
|
|
TObjectStack = class(TStack)
|
|
public
|
|
Function Push(AObject: TObject): TObject;
|
|
Function Pop: TObject;
|
|
Function Peek: TObject;
|
|
end;
|
|
|
|
{ TQueue class }
|
|
|
|
TQueue = class(TOrderedList)
|
|
protected
|
|
Procedure PushItem(AItem: Pointer); override;
|
|
end;
|
|
|
|
{ TObjectQueue class }
|
|
|
|
TObjectQueue = class(TQueue)
|
|
public
|
|
Function Push(AObject: TObject): TObject;
|
|
Function Pop: TObject;
|
|
Function Peek: TObject;
|
|
end;
|
|
|
|
{ ---------------------------------------------------------------------
|
|
Hash support, implemented by Dean Zobec
|
|
---------------------------------------------------------------------}
|
|
|
|
|
|
{ Must return a Longword value in the range 0..TableSize,
|
|
usually via a mod operator; }
|
|
THashFunction = function(const S: string; const TableSize: Longword): Longword;
|
|
|
|
TIteratorMethod = procedure(Item: Pointer; const Key: string;
|
|
var Continue: Boolean) of object;
|
|
|
|
{ THTNode }
|
|
|
|
THTNode = class(TObject)
|
|
private
|
|
FData: pointer;
|
|
FKey: string;
|
|
public
|
|
constructor CreateWith(const AString: String);
|
|
function HasKey(const AKey: string): boolean;
|
|
property Key: string read FKey;
|
|
property Data: pointer read FData write FData;
|
|
end;
|
|
|
|
{ TFPHashTable }
|
|
|
|
TFPHashTable = class(TObject)
|
|
private
|
|
FHashTable: TFPObjectList;
|
|
FHashTableSize: Longword;
|
|
FHashFunction: THashFunction;
|
|
FCount: Int64;
|
|
function GetDensity: Longword;
|
|
function GetNumberOfCollisions: Int64;
|
|
procedure SetHashTableSize(const Value: Longword);
|
|
procedure InitializeHashTable;
|
|
function GetVoidSlots: Longword;
|
|
function GetLoadFactor: double;
|
|
function GetAVGChainLen: double;
|
|
function GetMaxChainLength: Longword;
|
|
function Chain(const index: Longword):TFPObjectList;
|
|
protected
|
|
function ChainLength(const ChainIndex: Longword): Longword; virtual;
|
|
procedure SetData(const index: string; const AValue: Pointer); virtual;
|
|
function GetData(const index: string):Pointer; virtual;
|
|
function FindOrCreateNew(const aKey: string): THTNode; virtual;
|
|
function ForEachCall(aMethod: TIteratorMethod): THTNode; virtual;
|
|
procedure SetHashFunction(AHashFunction: THashFunction); virtual;
|
|
public
|
|
constructor Create;
|
|
constructor CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction);
|
|
destructor Destroy; override;
|
|
procedure ChangeTableSize(const ANewSize: Longword); virtual;
|
|
procedure Clear; virtual;
|
|
procedure Add(const aKey: string; AItem: pointer); virtual;
|
|
procedure Delete(const aKey: string); virtual;
|
|
function Find(const aKey: string): THTNode;
|
|
function IsEmpty: boolean;
|
|
property HashFunction: THashFunction read FHashFunction write SetHashFunction;
|
|
property Count: Int64 read FCount;
|
|
property HashTableSize: Longword read FHashTableSize write SetHashTableSize;
|
|
property Items[const index: string]: Pointer read GetData write SetData; default;
|
|
property HashTable: TFPObjectList read FHashTable;
|
|
property VoidSlots: Longword read GetVoidSlots;
|
|
property LoadFactor: double read GetLoadFactor;
|
|
property AVGChainLen: double read GetAVGChainLen;
|
|
property MaxChainLength: Int64 read GetMaxChainLength;
|
|
property NumberOfCollisions: Int64 read GetNumberOfCollisions;
|
|
property Density: Longword read GetDensity;
|
|
end;
|
|
|
|
EDuplicate = class(Exception);
|
|
EKeyNotFound = class(Exception);
|
|
|
|
|
|
function RSHash(const S: string; const TableSize: Longword): Longword;
|
|
|
|
implementation
|
|
|
|
ResourceString
|
|
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.';
|
|
|
|
const
|
|
NPRIMES = 28;
|
|
|
|
PRIMELIST: array[0 .. NPRIMES-1] of Longword =
|
|
( 53, 97, 193, 389, 769,
|
|
1543, 3079, 6151, 12289, 24593,
|
|
49157, 98317, 196613, 393241, 786433,
|
|
1572869, 3145739, 6291469, 12582917, 25165843,
|
|
50331653, 100663319, 201326611, 402653189, 805306457,
|
|
1610612741, 3221225473, 4294967291 );
|
|
|
|
constructor TFPObjectList.Create(FreeObjects : boolean);
|
|
begin
|
|
Create;
|
|
FFreeObjects := Freeobjects;
|
|
end;
|
|
|
|
destructor TFPObjectList.Destroy;
|
|
begin
|
|
if (FList <> nil) then
|
|
begin
|
|
Clear;
|
|
FList.Destroy;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TFPObjectList.Clear;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if FFreeObjects then
|
|
for i := 0 to FList.Count - 1 do
|
|
TObject(FList[i]).Free;
|
|
FList.Clear;
|
|
end;
|
|
|
|
constructor TFPObjectList.Create;
|
|
begin
|
|
inherited Create;
|
|
FList := TFPList.Create;
|
|
FFreeObjects := True;
|
|
end;
|
|
|
|
function TFPObjectList.GetCount: integer;
|
|
begin
|
|
Result := FList.Count;
|
|
end;
|
|
|
|
procedure TFPObjectList.SetCount(const AValue: integer);
|
|
begin
|
|
if FList.Count <> AValue then
|
|
FList.Count := AValue;
|
|
end;
|
|
|
|
function TFPObjectList.GetItem(Index: Integer): TObject; {$ifdef HASINLINE} inline;{$endif}
|
|
begin
|
|
Result := TObject(FList[Index]);
|
|
end;
|
|
|
|
procedure TFPObjectList.SetItem(Index: Integer; AObject: TObject); {$ifdef HASINLINE} inline;{$endif}
|
|
begin
|
|
if OwnsObjects then
|
|
TObject(FList[Index]).Free;
|
|
FList[index] := AObject;
|
|
end;
|
|
|
|
procedure TFPObjectList.SetCapacity(NewCapacity: Integer);
|
|
begin
|
|
FList.Capacity := NewCapacity;
|
|
end;
|
|
|
|
function TFPObjectList.GetCapacity: integer;
|
|
begin
|
|
Result := FList.Capacity;
|
|
end;
|
|
|
|
function TFPObjectList.Add(AObject: TObject): Integer; {$ifdef HASINLINE} inline;{$endif}
|
|
begin
|
|
Result := FList.Add(AObject);
|
|
end;
|
|
|
|
procedure TFPObjectList.Delete(Index: Integer); {$ifdef HASINLINE} inline;{$endif}
|
|
begin
|
|
if OwnsObjects then
|
|
TObject(FList[Index]).Free;
|
|
FList.Delete(Index);
|
|
end;
|
|
|
|
procedure TFPObjectList.Exchange(Index1, Index2: Integer);
|
|
begin
|
|
FList.Exchange(Index1, Index2);
|
|
end;
|
|
|
|
function TFPObjectList.Expand: TFPObjectList;
|
|
begin
|
|
FList.Expand;
|
|
Result := Self;
|
|
end;
|
|
|
|
function TFPObjectList.Extract(Item: TObject): TObject;
|
|
begin
|
|
Result := TObject(FList.Extract(Item));
|
|
end;
|
|
|
|
function TFPObjectList.Remove(AObject: TObject): Integer;
|
|
begin
|
|
Result := IndexOf(AObject);
|
|
if (Result <> -1) then
|
|
begin
|
|
if OwnsObjects then
|
|
TObject(FList[Result]).Free;
|
|
FList.Delete(Result);
|
|
end;
|
|
end;
|
|
|
|
function TFPObjectList.IndexOf(AObject: TObject): Integer;
|
|
begin
|
|
Result := FList.IndexOf(Pointer(AObject));
|
|
end;
|
|
|
|
function TFPObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
|
|
var
|
|
I : Integer;
|
|
begin
|
|
I:=AStartAt;
|
|
Result:=-1;
|
|
If AExact then
|
|
while (I<Count) and (Result=-1) do
|
|
If Items[i].ClassType=AClass then
|
|
Result:=I
|
|
else
|
|
Inc(I)
|
|
else
|
|
while (I<Count) and (Result=-1) do
|
|
If Items[i].InheritsFrom(AClass) then
|
|
Result:=I
|
|
else
|
|
Inc(I);
|
|
end;
|
|
|
|
procedure TFPObjectList.Insert(Index: Integer; AObject: TObject); {$ifdef HASINLINE} inline;{$endif}
|
|
begin
|
|
FList.Insert(Index, Pointer(AObject));
|
|
end;
|
|
|
|
procedure TFPObjectList.Move(CurIndex, NewIndex: Integer);
|
|
begin
|
|
FList.Move(CurIndex, NewIndex);
|
|
end;
|
|
|
|
procedure TFPObjectList.Assign(Obj: TFPObjectList);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Clear;
|
|
for I := 0 to Obj.Count - 1 do
|
|
Add(Obj[i]);
|
|
end;
|
|
|
|
procedure TFPObjectList.Pack;
|
|
begin
|
|
FList.Pack;
|
|
end;
|
|
|
|
procedure TFPObjectList.Sort(Compare: TListSortCompare);
|
|
begin
|
|
FList.Sort(Compare);
|
|
end;
|
|
|
|
function TFPObjectList.First: TObject;
|
|
begin
|
|
Result := TObject(FList.First);
|
|
end;
|
|
|
|
function TFPObjectList.Last: TObject;
|
|
begin
|
|
Result := TObject(FList.Last);
|
|
end;
|
|
|
|
{ TObjectList }
|
|
|
|
constructor tobjectlist.create(freeobjects : boolean);
|
|
|
|
begin
|
|
inherited create;
|
|
ffreeobjects:=freeobjects;
|
|
end;
|
|
|
|
Constructor tobjectlist.create;
|
|
|
|
begin
|
|
inherited create;
|
|
ffreeobjects:=True;
|
|
end;
|
|
|
|
Procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
|
|
|
|
begin
|
|
if FFreeObjects then
|
|
if (Action=lnDeleted) then
|
|
TObject(Ptr).Free;
|
|
inherited Notify(Ptr,Action);
|
|
end;
|
|
|
|
|
|
Function TObjectList.GetItem(Index: Integer): TObject;
|
|
|
|
begin
|
|
Result:=TObject(Inherited Get(Index));
|
|
end;
|
|
|
|
|
|
Procedure TObjectList.SetItem(Index: Integer; AObject: TObject);
|
|
|
|
Var
|
|
O : TObject;
|
|
|
|
begin
|
|
if OwnsObjects then
|
|
begin
|
|
O:=GetItem(Index);
|
|
O.Free;
|
|
end;
|
|
Put(Index,Pointer(AObject));
|
|
end;
|
|
|
|
|
|
Function TObjectList.Add(AObject: TObject): Integer;
|
|
|
|
begin
|
|
Result:=Inherited Add(Pointer(AObject));
|
|
end;
|
|
|
|
|
|
Function TObjectList.Extract(Item: TObject): TObject;
|
|
|
|
begin
|
|
Result:=Tobject(Inherited Extract(Pointer(Item)));
|
|
end;
|
|
|
|
|
|
Function TObjectList.Remove(AObject: TObject): Integer;
|
|
|
|
begin
|
|
Result:=Inherited Remove(Pointer(AObject));
|
|
end;
|
|
|
|
|
|
Function TObjectList.IndexOf(AObject: TObject): Integer;
|
|
|
|
begin
|
|
Result:=Inherited indexOF(Pointer(AObject));
|
|
end;
|
|
|
|
|
|
Function TObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
|
|
|
|
Var
|
|
I : Integer;
|
|
|
|
begin
|
|
I:=AStartAt;
|
|
Result:=-1;
|
|
If AExact then
|
|
While (I<Count) and (Result=-1) do
|
|
If Items[i].ClassType=AClass then
|
|
Result:=I
|
|
else
|
|
Inc(I)
|
|
else
|
|
While (I<Count) and (Result=-1) do
|
|
If Items[i].InheritsFrom(AClass) then
|
|
Result:=I
|
|
else
|
|
Inc(I);
|
|
end;
|
|
|
|
|
|
procedure TObjectList.Insert(Index: Integer; AObject: TObject);
|
|
begin
|
|
Inherited Insert(Index,Pointer(AObject));
|
|
end;
|
|
|
|
|
|
function TObjectList.First: TObject;
|
|
|
|
begin
|
|
Result := TObject(Inherited First);
|
|
end;
|
|
|
|
|
|
function TObjectList.Last: TObject;
|
|
|
|
begin
|
|
Result := TObject(Inherited Last);
|
|
end;
|
|
|
|
{ TListComponent }
|
|
|
|
Type
|
|
TlistComponent = Class(TComponent)
|
|
Private
|
|
Flist : TComponentList;
|
|
Public
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
end;
|
|
|
|
procedure TlistComponent.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
If (Operation=opremove) then
|
|
Flist.HandleFreeNotify(Self,AComponent);
|
|
inherited;
|
|
end;
|
|
|
|
{ TComponentList }
|
|
|
|
Function TComponentList.Add(AComponent: TComponent): Integer;
|
|
begin
|
|
Result:=Inherited Add(AComponent);
|
|
end;
|
|
|
|
destructor TComponentList.Destroy;
|
|
begin
|
|
FNotifier.Free;
|
|
inherited;
|
|
end;
|
|
|
|
Function TComponentList.Extract(Item: TComponent): TComponent;
|
|
begin
|
|
Result:=TComponent(Inherited Extract(Item));
|
|
end;
|
|
|
|
Function TComponentList.First: TComponent;
|
|
begin
|
|
Result:=TComponent(Inherited First);
|
|
end;
|
|
|
|
Function TComponentList.GetItems(Index: Integer): TComponent;
|
|
begin
|
|
Result:=TComponent(Inherited Items[Index]);
|
|
end;
|
|
|
|
Procedure TComponentList.HandleFreeNotify(Sender: TObject;
|
|
AComponent: TComponent);
|
|
begin
|
|
Extract(Acomponent);
|
|
end;
|
|
|
|
Function TComponentList.IndexOf(AComponent: TComponent): Integer;
|
|
begin
|
|
Result:=Inherited IndexOf(AComponent);
|
|
end;
|
|
|
|
Procedure TComponentList.Insert(Index: Integer; AComponent: TComponent);
|
|
begin
|
|
Inherited Insert(Index,Acomponent)
|
|
end;
|
|
|
|
Function TComponentList.Last: TComponent;
|
|
begin
|
|
Result:=TComponent(Inherited Last);
|
|
end;
|
|
|
|
Procedure TComponentList.Notify(Ptr: Pointer; Action: TListNotification);
|
|
begin
|
|
If FNotifier=NIl then
|
|
begin
|
|
FNotifier:=TlistComponent.Create(nil);
|
|
TlistComponent(FNotifier).FList:=Self;
|
|
end;
|
|
If Assigned(Ptr) then
|
|
With TComponent(Ptr) do
|
|
case Action of
|
|
lnAdded : FreeNotification(FNotifier);
|
|
lnExtracted, lnDeleted: RemoveFreeNotification(FNotifier);
|
|
end;
|
|
inherited Notify(Ptr, Action);
|
|
end;
|
|
|
|
Function TComponentList.Remove(AComponent: TComponent): Integer;
|
|
begin
|
|
Result:=Inherited Remove(AComponent);
|
|
end;
|
|
|
|
Procedure TComponentList.SetItems(Index: Integer; AComponent: TComponent);
|
|
begin
|
|
Put(Index,AComponent);
|
|
end;
|
|
|
|
{ TClassList }
|
|
|
|
Function TClassList.Add(AClass: TClass): Integer;
|
|
begin
|
|
Result:=Inherited Add(Pointer(AClass));
|
|
end;
|
|
|
|
Function TClassList.Extract(Item: TClass): TClass;
|
|
begin
|
|
Result:=TClass(Inherited Extract(Pointer(Item)));
|
|
end;
|
|
|
|
Function TClassList.First: TClass;
|
|
begin
|
|
Result:=TClass(Inherited First);
|
|
end;
|
|
|
|
Function TClassList.GetItems(Index: Integer): TClass;
|
|
begin
|
|
Result:=TClass(Inherited Items[Index]);
|
|
end;
|
|
|
|
Function TClassList.IndexOf(AClass: TClass): Integer;
|
|
begin
|
|
Result:=Inherited IndexOf(Pointer(AClass));
|
|
end;
|
|
|
|
Procedure TClassList.Insert(Index: Integer; AClass: TClass);
|
|
begin
|
|
Inherited Insert(index,Pointer(AClass));
|
|
end;
|
|
|
|
Function TClassList.Last: TClass;
|
|
begin
|
|
Result:=TClass(Inherited Last);
|
|
end;
|
|
|
|
Function TClassList.Remove(AClass: TClass): Integer;
|
|
begin
|
|
Result:=Inherited Remove(Pointer(AClass));
|
|
end;
|
|
|
|
Procedure TClassList.SetItems(Index: Integer; AClass: TClass);
|
|
begin
|
|
Put(Index,Pointer(Aclass));
|
|
end;
|
|
|
|
{ TOrderedList }
|
|
|
|
Function TOrderedList.AtLeast(ACount: Integer): Boolean;
|
|
begin
|
|
Result:=(FList.Count>=Acount)
|
|
end;
|
|
|
|
Function TOrderedList.Count: Integer;
|
|
begin
|
|
Result:=FList.Count;
|
|
end;
|
|
|
|
constructor TOrderedList.Create;
|
|
begin
|
|
FList:=Tlist.Create;
|
|
end;
|
|
|
|
destructor TOrderedList.Destroy;
|
|
begin
|
|
FList.Free;
|
|
end;
|
|
|
|
Function TOrderedList.Peek: Pointer;
|
|
begin
|
|
If AtLeast(1) then
|
|
Result:=PeekItem
|
|
else
|
|
Result:=Nil;
|
|
end;
|
|
|
|
Function TOrderedList.PeekItem: Pointer;
|
|
begin
|
|
With Flist do
|
|
Result:=Items[Count-1]
|
|
end;
|
|
|
|
Function TOrderedList.Pop: Pointer;
|
|
begin
|
|
If Atleast(1) then
|
|
Result:=PopItem
|
|
else
|
|
Result:=Nil;
|
|
end;
|
|
|
|
Function TOrderedList.PopItem: Pointer;
|
|
begin
|
|
With FList do
|
|
If Count>0 then
|
|
begin
|
|
Result:=Items[Count-1];
|
|
Delete(Count-1);
|
|
end
|
|
else
|
|
Result:=Nil;
|
|
end;
|
|
|
|
Function TOrderedList.Push(AItem: Pointer): Pointer;
|
|
begin
|
|
PushItem(Aitem);
|
|
Result:=AItem;
|
|
end;
|
|
|
|
{ TStack }
|
|
|
|
Procedure TStack.PushItem(AItem: Pointer);
|
|
begin
|
|
FList.Add(Aitem);
|
|
end;
|
|
|
|
{ TObjectStack }
|
|
|
|
Function TObjectStack.Peek: TObject;
|
|
begin
|
|
Result:=TObject(Inherited Peek);
|
|
end;
|
|
|
|
Function TObjectStack.Pop: TObject;
|
|
begin
|
|
Result:=TObject(Inherited Pop);
|
|
end;
|
|
|
|
Function TObjectStack.Push(AObject: TObject): TObject;
|
|
begin
|
|
Result:=TObject(Inherited Push(Pointer(AObject)));
|
|
end;
|
|
|
|
{ TQueue }
|
|
|
|
Procedure TQueue.PushItem(AItem: Pointer);
|
|
begin
|
|
With Flist Do
|
|
Insert(0,AItem);
|
|
end;
|
|
|
|
{ TObjectQueue }
|
|
|
|
Function TObjectQueue.Peek: TObject;
|
|
begin
|
|
Result:=TObject(Inherited Peek);
|
|
end;
|
|
|
|
Function TObjectQueue.Pop: TObject;
|
|
begin
|
|
Result:=TObject(Inherited Pop);
|
|
end;
|
|
|
|
Function TObjectQueue.Push(AObject: TObject): TObject;
|
|
begin
|
|
Result:=TObject(Inherited Push(Pointer(Aobject)));
|
|
end;
|
|
|
|
{ ---------------------------------------------------------------------
|
|
Hash support, by Dean Zobec
|
|
---------------------------------------------------------------------}
|
|
|
|
{ Default hash function }
|
|
|
|
function RSHash(const S: string; const TableSize: Longword): Longword;
|
|
const
|
|
b = 378551;
|
|
var
|
|
a: Longword;
|
|
i: Longword;
|
|
begin
|
|
a := 63689;
|
|
Result := 0;
|
|
for i := 1 to Length(S) do
|
|
begin
|
|
Result := Result * a + Ord(S[i]);
|
|
a := a * b;
|
|
end;
|
|
Result := (Result and $7FFFFFFF) mod TableSize;
|
|
end;
|
|
|
|
{ THTNode }
|
|
|
|
constructor THTNode.CreateWith(const AString: string);
|
|
begin
|
|
inherited Create;
|
|
FKey := AString;
|
|
end;
|
|
|
|
function THTNode.HasKey(const AKey: string): boolean;
|
|
begin
|
|
if Length(AKey) <> Length(FKey) then
|
|
begin
|
|
Result := false;
|
|
exit;
|
|
end
|
|
else
|
|
Result := CompareMem(PChar(FKey), PChar(AKey), length(AKey));
|
|
end;
|
|
|
|
{ TFPHashTable }
|
|
|
|
constructor TFPHashTable.Create;
|
|
begin
|
|
Inherited Create;
|
|
FHashTable := TFPObjectList.Create(True);
|
|
HashTableSize := 196613;
|
|
FHashFunction := @RSHash;
|
|
end;
|
|
|
|
constructor TFPHashTable.CreateWith(AHashTableSize: Longword;
|
|
aHashFunc: THashFunction);
|
|
begin
|
|
Inherited Create;
|
|
FHashTable := TFPObjectList.Create(True);
|
|
HashTableSize := AHashTableSize;
|
|
FHashFunction := aHashFunc;
|
|
end;
|
|
|
|
destructor TFPHashTable.Destroy;
|
|
begin
|
|
FHashTable.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TFPHashTable.GetDensity: Longword;
|
|
begin
|
|
Result := FHashTableSize - VoidSlots
|
|
end;
|
|
|
|
function TFPHashTable.GetNumberOfCollisions: Int64;
|
|
begin
|
|
Result := FCount -(FHashTableSize - VoidSlots)
|
|
end;
|
|
|
|
procedure TFPHashTable.SetData(const index: string; const AValue: Pointer);
|
|
begin
|
|
FindOrCreateNew(index).Data := AValue;
|
|
end;
|
|
|
|
procedure TFPHashTable.SetHashTableSize(const Value: Longword);
|
|
var
|
|
i: Longword;
|
|
newSize: Longword;
|
|
begin
|
|
if Value <> FHashTableSize then
|
|
begin
|
|
i := 0;
|
|
while (PRIMELIST[i] < Value) and (i < 27) do
|
|
inc(i);
|
|
newSize := PRIMELIST[i];
|
|
if Count = 0 then
|
|
begin
|
|
FHashTableSize := newSize;
|
|
InitializeHashTable;
|
|
end
|
|
else
|
|
ChangeTableSize(newSize);
|
|
end;
|
|
end;
|
|
|
|
procedure TFPHashTable.InitializeHashTable;
|
|
var
|
|
i: LongWord;
|
|
begin
|
|
for i := 0 to FHashTableSize-1 do
|
|
FHashTable.Add(nil);
|
|
FCount := 0;
|
|
end;
|
|
|
|
procedure TFPHashTable.ChangeTableSize(const ANewSize: Longword);
|
|
var
|
|
SavedTable: TFPObjectList;
|
|
SavedTableSize: Longword;
|
|
i, j: Longword;
|
|
temp: THTNode;
|
|
begin
|
|
SavedTable := FHashTable;
|
|
SavedTableSize := FHashTableSize;
|
|
FHashTableSize := ANewSize;
|
|
FHashTable := TFPObjectList.Create(True);
|
|
InitializeHashTable;
|
|
for i := 0 to SavedTableSize-1 do
|
|
begin
|
|
if Assigned(SavedTable[i]) then
|
|
for j := 0 to TFPObjectList(SavedTable[i]).Count -1 do
|
|
begin
|
|
temp := THTNode(TFPObjectList(SavedTable[i])[j]);
|
|
Add(temp.Key, temp.Data);
|
|
end;
|
|
end;
|
|
SavedTable.Free;
|
|
end;
|
|
|
|
procedure TFPHashTable.SetHashFunction(AHashFunction: THashFunction);
|
|
begin
|
|
if IsEmpty then
|
|
FHashFunction := AHashFunction
|
|
else
|
|
raise Exception.Create(NotEmptyMsg);
|
|
end;
|
|
|
|
function TFPHashTable.Find(const aKey: string): THTNode;
|
|
var
|
|
hashCode: Longword;
|
|
chn: TFPObjectList;
|
|
i: Longword;
|
|
begin
|
|
hashCode := FHashFunction(aKey, FHashTableSize);
|
|
chn := Chain(hashCode);
|
|
if Assigned(chn) then
|
|
begin
|
|
for i := 0 to chn.Count - 1 do
|
|
if THTNode(chn[i]).HasKey(aKey) then
|
|
begin
|
|
result := THTNode(chn[i]);
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TFPHashTable.GetData(const Index: string): Pointer;
|
|
var
|
|
node: THTNode;
|
|
begin
|
|
node := Find(Index);
|
|
if Assigned(node) then
|
|
Result := node.Data
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TFPHashTable.FindOrCreateNew(const aKey: string): THTNode;
|
|
var
|
|
hashCode: Longword;
|
|
chn: TFPObjectList;
|
|
i: Longword;
|
|
begin
|
|
hashCode := FHashFunction(aKey, FHashTableSize);
|
|
chn := Chain(hashCode);
|
|
if Assigned(chn) then
|
|
begin
|
|
for i := 0 to chn.Count - 1 do
|
|
if THTNode(chn[i]).HasKey(aKey) then
|
|
begin
|
|
Result := THTNode(chn[i]);
|
|
exit;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
FHashTable[hashcode] := TFPObjectList.Create(true);
|
|
chn := Chain(hashcode);
|
|
end;
|
|
inc(FCount);
|
|
Result := THTNode.CreateWith(aKey);
|
|
chn.Add(Result);
|
|
end;
|
|
|
|
function TFPHashTable.ChainLength(const ChainIndex: Longword): Longword;
|
|
begin
|
|
if Assigned(Chain(ChainIndex)) then
|
|
Result := Chain(ChainIndex).Count
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TFPHashTable.Clear;
|
|
var
|
|
i: Longword;
|
|
begin
|
|
for i := 0 to FHashTableSize - 1 do
|
|
begin
|
|
if Assigned(Chain(i)) then
|
|
Chain(i).Clear;
|
|
end;
|
|
FCount := 0;
|
|
end;
|
|
|
|
function TFPHashTable.ForEachCall(aMethod: TIteratorMethod): THTNode;
|
|
var
|
|
i, j: Longword;
|
|
continue: boolean;
|
|
begin
|
|
Result := nil;
|
|
continue := true;
|
|
for i := 0 to FHashTableSize-1 do
|
|
begin
|
|
if assigned(Chain(i)) then
|
|
begin
|
|
for j := 0 to Chain(i).Count-1 do
|
|
begin
|
|
aMethod(THTNode(Chain(i)[j]).Data, THTNode(Chain(i)[j]).Key, continue);
|
|
if not continue then
|
|
begin
|
|
Result := THTNode(Chain(i)[j]);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TFPHashTable.Add(const aKey: string; aItem: pointer);
|
|
var
|
|
hashCode: Longword;
|
|
chn: TFPObjectList;
|
|
i: Longword;
|
|
NewNode: THtNode;
|
|
begin
|
|
hashCode := FHashFunction(aKey, FHashTableSize);
|
|
chn := Chain(hashCode);
|
|
if Assigned(chn) then
|
|
begin
|
|
for i := 0 to chn.Count - 1 do
|
|
if THTNode(chn[i]).HasKey(aKey) then
|
|
Raise EDuplicate.CreateFmt(DuplicateMsg, [aKey]);
|
|
end
|
|
else
|
|
begin
|
|
FHashTable[hashcode] := TFPObjectList.Create(true);
|
|
chn := Chain(hashcode);
|
|
end;
|
|
inc(FCount);
|
|
NewNode := THTNode.CreateWith(aKey);
|
|
NewNode.Data := aItem;
|
|
chn.Add(NewNode);
|
|
end;
|
|
|
|
procedure TFPHashTable.Delete(const aKey: string);
|
|
var
|
|
hashCode: Longword;
|
|
chn: TFPObjectList;
|
|
i: Longword;
|
|
begin
|
|
hashCode := FHashFunction(aKey, FHashTableSize);
|
|
chn := Chain(hashCode);
|
|
if Assigned(chn) then
|
|
begin
|
|
for i := 0 to chn.Count - 1 do
|
|
if THTNode(chn[i]).HasKey(aKey) then
|
|
begin
|
|
chn.Delete(i);
|
|
dec(FCount);
|
|
exit;
|
|
end;
|
|
end;
|
|
raise EKeyNotFound.CreateFmt(KeyNotFoundMsg, ['Delete', aKey]);
|
|
end;
|
|
|
|
function TFPHashTable.IsEmpty: boolean;
|
|
begin
|
|
Result := (FCount = 0);
|
|
end;
|
|
|
|
function TFPHashTable.Chain(const index: Longword): TFPObjectList;
|
|
begin
|
|
Result := TFPObjectList(FHashTable[index]);
|
|
end;
|
|
|
|
function TFPHashTable.GetVoidSlots: Longword;
|
|
var
|
|
i: Longword;
|
|
num: Longword;
|
|
begin
|
|
num := 0;
|
|
for i:= 0 to FHashTableSize-1 do
|
|
if Not Assigned(Chain(i)) then
|
|
inc(num);
|
|
result := num;
|
|
end;
|
|
|
|
function TFPHashTable.GetLoadFactor: double;
|
|
begin
|
|
Result := Count / FHashTableSize;
|
|
end;
|
|
|
|
function TFPHashTable.GetAVGChainLen: double;
|
|
begin
|
|
result := Count / (FHashTableSize - VoidSlots);
|
|
end;
|
|
|
|
function TFPHashTable.GetMaxChainLength: Longword;
|
|
var
|
|
i: Longword;
|
|
begin
|
|
Result := 0;
|
|
for i := 0 to FHashTableSize-1 do
|
|
if ChainLength(i) > Result then
|
|
Result := ChainLength(i);
|
|
end;
|
|
|
|
end.
|