1
0
mirror of synced 2024-09-07 21:45:03 +00:00
x2utils/X2UtHashes.pas
Mark van Renswoude c249606540 WideString compatibility for NamedFormat
WideString compatibility for Hashes
PersistTest is incomplete and fails; commented out
2013-12-30 09:31:32 +00:00

2472 lines
61 KiB
ObjectPascal

{
:: X2UtHashes contains a base class for hashes (also known as associative
:: arrays), as well as various default implementations.
::
:: The useable implementations have a naming convention of TX2<tt>Hash,
:: where <tt> are two characters representing the key and value types,
:: according to the following table:
::
:: P = Pointer
:: I = Integer
:: O = Object
:: S = String
::
:: For example; TX2SOHash indicates that it uses String keys to identify
:: Object values.
::
:: As of Delphi 2006, all default hashes support the for...in structure.
:: To enumerate all keys, use "for x in Hash". As of yet, there is no
:: direct support for value enumeration yet; you can use
:: First/Next/CurrentValue for that.
::
:: Last changed: $Date$
:: Revision: $Rev$
:: Author: $Author$
}
unit X2UtHashes;
{$I X2UtCompilerVersion.inc}
interface
uses
Classes,
SysUtils;
const
// Do NOT change these values unless you really know
// what you are doing!
LeafSize = 256;
BucketSize = 8;
type
//:$ Raised when the cursor is not available
EX2HashNoCursor = class(Exception);
// Forward declarations
TX2CustomHash = class;
{$IFDEF D2005PLUS}
{$REGION 'Internal hash structures'}
{$ENDIF}
{
:$ Internal representation of a hash item.
}
PX2HashCookie = Pointer;
PX2HashItem = ^TX2HashItem;
TX2HashItem = record
ID: Cardinal;
end;
PX2HashBucket = ^TX2HashBucket;
TX2HashBucket = record
ID: Cardinal;
Level: Integer;
Count: Integer;
Items: array[0..Pred(LeafSize)] of PX2HashItem;
end;
PX2HashValue = ^TX2HashValue;
TX2HashValue = record
ID: Cardinal;
Next: PX2HashValue;
Key: PX2HashCookie;
Value: PX2HashCookie;
end;
TX2BucketPath = record
Bucket: PX2HashBucket;
Index: Integer;
end;
PX2HashStringCookie = ^TX2HashStringCookie;
TX2HashStringCookie = record
Length: Cardinal;
Value: PChar;
end;
{
:$ Default cursor implementation.
:: Traverses the hash tree from top-to-bottom, left-to-right.
}
TX2HashCursor = class(TObject)
private
FBucketPath: array of TX2BucketPath;
FCurrent: PX2HashValue;
protected
function GetCurrent: PX2HashValue; virtual;
public
constructor Create(const ABucket: PX2HashBucket); virtual;
procedure First; virtual;
function Next: Boolean; virtual;
property Current: PX2HashValue read GetCurrent;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Internal value managers'}
{$ENDIF}
{
:$ Base value manager.
}
TX2CustomHashManager = class(TObject)
protected
procedure FreeCookie(var ACookie: PX2HashCookie); virtual;
function Hash(ACookie: PX2HashCookie): Cardinal; virtual; abstract;
function Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean; virtual; abstract;
function Clone(const ACookie: PX2HashCookie): PX2HashCookie; virtual; abstract;
end;
TX2HashPointerManager = class(TX2CustomHashManager)
protected
function CreateCookie(const AValue: Pointer): PX2HashCookie; overload;
function GetValue(const ACookie: PX2HashCookie): Pointer; overload;
function Hash(ACookie: PX2HashCookie): Cardinal; override;
function Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean; override;
function Clone(const ACookie: PX2HashCookie): PX2HashCookie; override;
end;
{
:$ Integer value class.
}
TX2HashIntegerManager = class(TX2CustomHashManager)
protected
function CreateCookie(const AValue: Integer): PX2HashCookie; overload;
function GetValue(const ACookie: PX2HashCookie): Integer; overload;
function Hash(ACookie: PX2HashCookie): Cardinal; override;
function Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean; override;
function Clone(const ACookie: PX2HashCookie): PX2HashCookie; override;
end;
{
:$ Object value class.
}
TX2HashObjectManager = class(TX2CustomHashManager)
private
FOwnsObjects: Boolean;
protected
procedure FreeCookie(var ACookie: PX2HashCookie); override;
function CreateCookie(const AValue: TObject): PX2HashCookie; overload;
function GetValue(const ACookie: PX2HashCookie): TObject; overload;
function Hash(ACookie: PX2HashCookie): Cardinal; override;
function Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean; override;
function Clone(const ACookie: PX2HashCookie): PX2HashCookie; override;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;
{
:$ String value class.
}
TX2HashStringManager = class(TX2CustomHashManager)
protected
procedure FreeCookie(var ACookie: PX2HashCookie); override;
function CreateCookie(const AValue: string): PX2HashCookie; overload;
function GetValue(const ACookie: PX2HashCookie): string; overload;
function Hash(ACookie: PX2HashCookie): Cardinal; override;
function Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean; override;
function Clone(const ACookie: PX2HashCookie): PX2HashCookie; override;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Delphi 2006 enumerator support'}
{$ENDIF}
{
:$ Base enumerator class.
}
TX2HashEnumerator = class(TObject)
private
FCursor: TX2HashCursor;
FManager: TX2CustomHashManager;
FEnumKeys: Boolean;
function GetCursor: PX2HashCookie;
protected
property Manager: TX2CustomHashManager read FManager;
property Cursor: PX2HashCookie read GetCursor;
public
constructor Create(const AHash: TX2CustomHash;
const AEnumKeys: Boolean);
destructor Destroy; override;
function MoveNext: Boolean;
end;
{
:$ Enumerator for pointer values.
}
TX2HashPointerEnumerator = class(TX2HashEnumerator)
private
function GetCurrent: Pointer;
public
property Current: Pointer read GetCurrent;
end;
{
:$ Enumerator for integer values.
}
TX2HashIntegerEnumerator = class(TX2HashEnumerator)
private
function GetCurrent: Integer;
public
property Current: Integer read GetCurrent;
end;
{
:$ Enumerator for object values.
}
TX2HashObjectEnumerator = class(TX2HashEnumerator)
private
function GetCurrent: TObject;
public
property Current: TObject read GetCurrent;
end;
{
:$ Enumerator for string values
}
TX2HashStringEnumerator = class(TX2HashEnumerator)
private
function GetCurrent: String;
public
property Current: String read GetCurrent;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Abstract hash implementation'}
{$ENDIF}
{
:$ Hash implementation.
}
TX2CustomHash = class(TPersistent)
private
FRoot: PX2HashBucket;
FCount: Integer;
FCursor: TX2HashCursor;
FKeyManager: TX2CustomHashManager;
FValueManager: TX2CustomHashManager;
protected
function CreateCursor: TX2HashCursor; virtual;
function CreateKeyManager: TX2CustomHashManager; virtual; abstract;
function CreateValueManager: TX2CustomHashManager; virtual; abstract;
procedure InvalidateCursor;
function CursorRequired(const ARaiseException: Boolean = True): Boolean;
function InternalFind(const ABucket: PX2HashBucket;
const AHash: Cardinal; const AKey: PX2HashCookie;
const AAllowCreate: Boolean;
const AExisting: PX2HashValue = nil): PX2HashValue;
function InternalDelete(const ABucket: PX2HashBucket;
const AHash: Cardinal; const AKey: PX2HashCookie): Boolean;
{ :$ AKey will be freed by these methods, so make sure to pass a Clone
:$ if you need it afterwards! }
function Find(const AKey: PX2HashCookie; const AAllowCreate: Boolean): PX2HashValue; overload;
function Exists(const AKey: PX2HashCookie): Boolean; overload;
function Delete(const AKey: PX2HashCookie): Boolean; overload;
procedure SetValue(const AValue: PX2HashValue; const AData: Pointer);
property Cursor: TX2HashCursor read FCursor;
property KeyManager: TX2CustomHashManager read FKeyManager;
property ValueManager: TX2CustomHashManager read FValueManager;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Clear;
procedure First;
function Next: Boolean;
property Count: Integer read FCount;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Base hash classes'}
{$ENDIF}
{
:$ Base hash implementation for pointer keys.
}
TX2CustomPointerHash = class(TX2CustomHash)
private
function GetCurrentKey: Pointer;
function GetKeyManager: TX2HashPointerManager;
protected
function CreateKeyManager: TX2CustomHashManager; override;
function Find(const AKey: Pointer; const AAllowCreate: Boolean): PX2HashValue; overload;
property KeyManager: TX2HashPointerManager read GetKeyManager;
public
function GetEnumerator: TX2HashPointerEnumerator;
function Exists(const AKey: Pointer): Boolean; overload;
function Delete(const AKey: Pointer): Boolean; overload;
property CurrentKey: Pointer read GetCurrentKey;
end;
{
:$ Base hash implementation for integer keys.
}
TX2CustomIntegerHash = class(TX2CustomHash)
private
function GetCurrentKey: Integer;
function GetKeyManager: TX2HashIntegerManager;
protected
function CreateKeyManager: TX2CustomHashManager; override;
function Find(const AKey: Integer; const AAllowCreate: Boolean): PX2HashValue; overload;
property KeyManager: TX2HashIntegerManager read GetKeyManager;
public
function GetEnumerator: TX2HashIntegerEnumerator;
function Exists(const AKey: Integer): Boolean; overload;
function Delete(const AKey: Integer): Boolean; overload;
property CurrentKey: Integer read GetCurrentKey;
end;
{
:$ Base hash implementation for object keys.
}
TX2CustomObjectHash = class(TX2CustomHash)
private
function GetCurrentKey: TObject;
function GetKeyManager: TX2HashObjectManager;
protected
function CreateKeyManager: TX2CustomHashManager; override;
function Find(const AKey: TObject; const AAllowCreate: Boolean): PX2HashValue; overload;
property KeyManager: TX2HashObjectManager read GetKeyManager;
public
function GetEnumerator: TX2HashObjectEnumerator;
function Exists(const AKey: TObject): Boolean; overload;
function Delete(const AKey: TObject): Boolean; overload;
property CurrentKey: TObject read GetCurrentKey;
end;
{
:$ Base hash implementation for string keys.
}
TX2CustomStringHash = class(TX2CustomHash)
protected
function GetCurrentKey: String;
private
function GetKeyManager: TX2HashStringManager;
protected
function CreateKeyManager: TX2CustomHashManager; override;
function Find(const AKey: String; const AAllowCreate: Boolean): PX2HashValue; overload;
property KeyManager: TX2HashStringManager read GetKeyManager;
public
function GetEnumerator: TX2HashStringEnumerator;
function Exists(const AKey: String): Boolean; overload;
function Delete(const AKey: String): Boolean; overload;
property CurrentKey: String read GetCurrentKey;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Concrete hash classes'}
{$ENDIF}
{
:$ Pointer-to-Pointer hash.
}
TX2PPHash = class(TX2CustomPointerHash)
protected
function GetCurrentValue: Pointer;
function GetValue(Key: Pointer): Pointer;
procedure SetValue(Key: Pointer; const Value: Pointer);
private
function GetValueManager: TX2HashPointerManager;
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashPointerManager read GetValueManager;
public
property CurrentValue: Pointer read GetCurrentValue;
property Values[Key: Pointer]: Pointer read GetValue write SetValue; default;
end;
{
:$ Pointer-to-Integer hash.
}
TX2PIHash = class(TX2CustomPointerHash)
protected
function GetCurrentValue: Integer;
function GetValue(Key: Pointer): Integer;
procedure SetValue(Key: Pointer; const Value: Integer);
private
function GetValueManager: TX2HashIntegerManager;
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashIntegerManager read GetValueManager;
public
property CurrentValue: Integer read GetCurrentValue;
property Values[Key: Pointer]: Integer read GetValue write SetValue; default;
end;
{
:$ Pointer-to-Object hash.
}
TX2POHash = class(TX2CustomPointerHash)
protected
function GetCurrentValue: TObject;
function GetOwnsObjects: Boolean;
procedure SetOwnsObjects(const Value: Boolean);
function GetValue(Key: Pointer): TObject;
procedure SetValue(Key: Pointer; const Value: TObject);
private
function GetValueManager: TX2HashObjectManager;
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashObjectManager read GetValueManager;
public
constructor Create(const AOwnsObjects: Boolean = False); reintroduce;
property CurrentValue: TObject read GetCurrentValue;
property OwnsObjects: Boolean read GetOwnsObjects write SetOwnsObjects;
property Values[Key: Pointer]: TObject read GetValue write SetValue; default;
end;
{
:$ Pointer-to-String hash.
}
TX2PSHash = class(TX2CustomPointerHash)
protected
function GetCurrentValue: String;
function GetValue(Key: Pointer): String;
procedure SetValue(Key: Pointer; const Value: String);
private
function GetValueManager: TX2HashStringManager;
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashStringManager read GetValueManager;
public
property CurrentValue: String read GetCurrentValue;
property Values[Key: Pointer]: String read GetValue write SetValue; default;
end;
{
:$ Integer-to-Pointer hash.
}
TX2IPHash = class(TX2CustomIntegerHash)
protected
function GetCurrentValue: Pointer;
function GetValue(Key: Integer): Pointer;
procedure SetValue(Key: Integer; const Value: Pointer);
private
function GetValueManager: TX2HashPointerManager;
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashPointerManager read GetValueManager;
public
property CurrentValue: Pointer read GetCurrentValue;
property Values[Key: Integer]: Pointer read GetValue write SetValue; default;
end;
{
:$ Integer-to-Integer hash.
}
TX2IIHash = class(TX2CustomIntegerHash)
protected
function GetCurrentValue: Integer;
function GetValue(Key: Integer): Integer;
procedure SetValue(Key: Integer; const Value: Integer);
private
function GetValueManager: TX2HashIntegerManager;
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashIntegerManager read GetValueManager;
public
property CurrentValue: Integer read GetCurrentValue;
property Values[Key: Integer]: Integer read GetValue write SetValue; default;
end;
{
:$ Integer-to-Object hash.
}
TX2IOHash = class(TX2CustomIntegerHash)
private
function GetValueManager: TX2HashObjectManager;
protected
function GetCurrentValue: TObject;
function GetOwnsObjects: Boolean;
procedure SetOwnsObjects(const Value: Boolean);
function GetValue(Key: Integer): TObject;
procedure SetValue(Key: Integer; const Value: TObject);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashObjectManager read GetValueManager;
public
constructor Create(const AOwnsObjects: Boolean = False); reintroduce;
property CurrentValue: TObject read GetCurrentValue;
property OwnsObjects: Boolean read GetOwnsObjects write SetOwnsObjects;
property Values[Key: Integer]: TObject read GetValue write SetValue; default;
end;
{
:$ Integer-to-String hash.
}
TX2ISHash = class(TX2CustomIntegerHash)
private
function GetValueManager: TX2HashStringManager;
protected
function GetCurrentValue: String;
function GetValue(Key: Integer): String;
procedure SetValue(Key: Integer; const Value: String);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashStringManager read GetValueManager;
public
property CurrentValue: String read GetCurrentValue;
property Values[Key: Integer]: String read GetValue write SetValue; default;
end;
{
:$ Object-to-Pointer hash.
}
TX2OPHash = class(TX2CustomObjectHash)
private
function GetValueManager: TX2HashPointerManager;
protected
function GetCurrentValue: Pointer;
function GetValue(Key: TObject): Pointer;
procedure SetValue(Key: TObject; const Value: Pointer);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashPointerManager read GetValueManager;
public
property CurrentValue: Pointer read GetCurrentValue;
property Values[Key: TObject]: Pointer read GetValue write SetValue; default;
end;
{
:$ Object-to-Integer hash.
}
TX2OIHash = class(TX2CustomObjectHash)
private
function GetValueManager: TX2HashIntegerManager;
protected
function GetCurrentValue: Integer;
function GetValue(Key: TObject): Integer;
procedure SetValue(Key: TObject; const Value: Integer);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashIntegerManager read GetValueManager;
public
property CurrentValue: Integer read GetCurrentValue;
property Values[Key: TObject]: Integer read GetValue write SetValue; default;
end;
{
:$ Object-to-Object hash.
}
TX2OOHash = class(TX2CustomObjectHash)
private
function GetValueManager: TX2HashObjectManager;
protected
function GetCurrentValue: TObject;
function GetOwnsObjects: Boolean;
procedure SetOwnsObjects(const Value: Boolean);
function GetValue(Key: TObject): TObject;
procedure SetValue(Key: TObject; const Value: TObject);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashObjectManager read GetValueManager;
public
constructor Create(const AOwnsObjects: Boolean = False); reintroduce;
property CurrentValue: TObject read GetCurrentValue;
property OwnsObjects: Boolean read GetOwnsObjects write SetOwnsObjects;
property Values[Key: TObject]: TObject read GetValue write SetValue; default;
end;
{
:$ Object-to-String hash.
}
TX2OSHash = class(TX2CustomObjectHash)
private
function GetValueManager: TX2HashStringManager;
protected
function GetCurrentValue: String;
function GetValue(Key: TObject): String;
procedure SetValue(Key: TObject; const Value: String);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashStringManager read GetValueManager;
public
property CurrentValue: String read GetCurrentValue;
property Values[Key: TObject]: String read GetValue write SetValue; default;
end;
{
:$ String-to-Pointer hash.
}
TX2SPHash = class(TX2CustomStringHash)
private
function GetValueManager: TX2HashPointerManager;
protected
function GetCurrentValue: Pointer;
function GetValue(Key: String): Pointer;
procedure SetValue(Key: String; const Value: Pointer);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashPointerManager read GetValueManager;
public
property CurrentValue: Pointer read GetCurrentValue;
property Values[Key: String]: Pointer read GetValue write SetValue; default;
end;
{
:$ String-to-Integer hash.
}
TX2SIHash = class(TX2CustomStringHash)
private
function GetValueManager: TX2HashIntegerManager;
protected
function GetCurrentValue: Integer;
function GetValue(Key: String): Integer;
procedure SetValue(Key: String; const Value: Integer);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashIntegerManager read GetValueManager;
public
property CurrentValue: Integer read GetCurrentValue;
property Values[Key: String]: Integer read GetValue write SetValue; default;
end;
{
:$ String-to-Object hash.
}
TX2SOHash = class(TX2CustomStringHash)
private
function GetValueManager: TX2HashObjectManager;
protected
function GetCurrentValue: TObject;
function GetOwnsObjects: Boolean;
procedure SetOwnsObjects(const Value: Boolean);
function GetValue(Key: String): TObject;
procedure SetValue(Key: String; const Value: TObject);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashObjectManager read GetValueManager;
public
constructor Create(const AOwnsObjects: Boolean = False); reintroduce;
property CurrentValue: TObject read GetCurrentValue;
property OwnsObjects: Boolean read GetOwnsObjects write SetOwnsObjects;
property Values[Key: String]: TObject read GetValue write SetValue; default;
end;
{
:$ String-to-String hash.
}
TX2SSHash = class(TX2CustomStringHash)
private
function GetValueManager: TX2HashStringManager;
protected
function GetCurrentValue: String;
function GetValue(Key: String): String;
procedure SetValue(Key: String; const Value: String);
protected
function CreateValueManager: TX2CustomHashManager; override;
property ValueManager: TX2HashStringManager read GetValueManager;
public
property CurrentValue: String read GetCurrentValue;
property Values[Key: String]: String read GetValue write SetValue; default;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$ENDIF}
implementation
const
HIDBucket = 1;
HIDValue = 2;
CRC32Poly = $edb88320;
var
CRC32Table: array[Byte] of Cardinal;
{========================================
CRC32
========================================}
procedure CRC32Init;
var
iItem: Integer;
iPoly: Integer;
iValue: Cardinal;
begin
for iItem := 255 downto 0 do
begin
iValue := iItem;
for iPoly := 8 downto 1 do
if (iValue and $1) <> 0 then
iValue := (iValue shr $1) xor CRC32Poly
else
iValue := iValue shr $1;
CRC32Table[iItem] := iValue;
end;
end;
function CRC32(const AKey: Pointer; const ASize: Cardinal): Cardinal; overload;
var
iByte: Integer;
pByte: ^Byte;
begin
Result := $FFFFFFFF;
pByte := AKey;
for iByte := Pred(ASize) downto 0 do
begin
Result := (((Result shr 8) and $00FFFFFF) xor
(CRC32Table[(Result xor pByte^) and $FF]));
Inc(pByte);
end;
end;
function CRC32(const AKey: string): Cardinal; overload;
begin
Result := CRC32(PChar(AKey), Length(AKey) * SizeOf(Char));
end;
{$IFDEF D2005PLUS}
{$REGION 'Internal hash structures'}
{$ENDIF}
{========================================
TX2HashCursor
========================================}
constructor TX2HashCursor.Create(const ABucket: PX2HashBucket);
begin
inherited Create;
SetLength(FBucketPath, 1);
with FBucketPath[0] do
begin
Bucket := ABucket;
Index := 0;
end;
FCurrent := nil;
end;
function TX2HashCursor.GetCurrent: PX2HashValue;
begin
Result := FCurrent;
end;
procedure TX2HashCursor.First;
begin
if Length(FBucketPath) > 1 then
SetLength(FBucketPath, 1);
FBucketPath[0].Index := 0;
FCurrent := nil;
end;
function TX2HashCursor.Next: Boolean;
var
bFound: Boolean;
iIndex: Integer;
pBucket: PX2HashBucket;
pItem: PX2HashItem;
begin
Result := False;
iIndex := High(FBucketPath);
if iIndex = -1 then
exit;
if Assigned(FCurrent) and Assigned(FCurrent^.Next) then
begin
FCurrent := FCurrent^.Next;
Result := True;
exit;
end;
repeat
pBucket := FBucketPath[iIndex].Bucket;
bFound := False;
while FBucketPath[iIndex].Index < LeafSize do
begin
pItem := pBucket^.Items[FBucketPath[iIndex].Index];
if pItem = nil then
Inc(FBucketPath[iIndex].Index)
else
case pItem^.ID of
HIDBucket:
begin
// Bucket, continue down the path
Inc(iIndex);
SetLength(FBucketPath, iIndex + 1);
with FBucketPath[iIndex] do
begin
Bucket := PX2HashBucket(pItem);
Index := 0;
end;
bFound := True;
break;
end;
HIDValue:
begin
// Got a value
FCurrent := PX2HashValue(pItem);
Result := True;
Inc(FBucketPath[iIndex].Index);
exit;
end;
end;
end;
if not bFound then
// Nothing found
if iIndex > 0 then
begin
// Go up in the bucket path
SetLength(FBucketPath, iIndex);
Dec(iIndex);
Inc(FBucketPath[iIndex].Index);
end else
// No more items
break;
until False;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Internal value managers'}
{$ENDIF}
{========================================
TX2CustomHashManager
========================================}
procedure TX2CustomHashManager.FreeCookie(var ACookie: Pointer);
begin
ACookie := nil;
end;
{========================================
TX2HashPointerManager
========================================}
function TX2HashPointerManager.CreateCookie(const AValue: Pointer): PX2HashCookie;
begin
Result := AValue;
end;
function TX2HashPointerManager.GetValue(const ACookie: PX2HashCookie): Pointer;
begin
Result := ACookie;
end;
function TX2HashPointerManager.Hash(ACookie: PX2HashCookie): Cardinal;
var
value: Pointer;
begin
value := GetValue(ACookie);
Result := CRC32(@value, SizeOf(Pointer));
end;
function TX2HashPointerManager.Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean;
begin
Result := (GetValue(ACookie1) = GetValue(ACookie2));
end;
function TX2HashPointerManager.Clone(const ACookie: PX2HashCookie): PX2HashCookie;
begin
Result := ACookie;
end;
{========================================
TX2HashIntegerManager
========================================}
function TX2HashIntegerManager.CreateCookie(const AValue: Integer): PX2HashCookie;
begin
Result := PX2HashCookie(AValue);
end;
function TX2HashIntegerManager.GetValue(const ACookie: PX2HashCookie): Integer;
begin
Result := Integer(ACookie);
end;
function TX2HashIntegerManager.Hash(ACookie: PX2HashCookie): Cardinal;
var
value: Integer;
begin
value := GetValue(ACookie);
Result := CRC32(@value, SizeOf(Integer));
end;
function TX2HashIntegerManager.Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean;
begin
Result := (GetValue(ACookie1) = GetValue(ACookie2));
end;
function TX2HashIntegerManager.Clone(const ACookie: PX2HashCookie): PX2HashCookie;
begin
Result := ACookie;
end;
{========================================
TX2HashObjectManager
========================================}
procedure TX2HashObjectManager.FreeCookie(var ACookie: PX2HashCookie);
begin
if Assigned(ACookie) and (FOwnsObjects) then
GetValue(ACookie).Free;
inherited;
end;
function TX2HashObjectManager.CreateCookie(const AValue: TObject): PX2HashCookie;
begin
Result := PX2HashCookie(AValue);
end;
function TX2HashObjectManager.GetValue(const ACookie: PX2HashCookie): TObject;
begin
Result := TObject(ACookie);
end;
function TX2HashObjectManager.Hash(ACookie: PX2HashCookie): Cardinal;
var
value: TObject;
begin
value := GetValue(ACookie);
Result := CRC32(@value, SizeOf(TObject));
end;
function TX2HashObjectManager.Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean;
begin
Result := (GetValue(ACookie1) = GetValue(ACookie2));
end;
function TX2HashObjectManager.Clone(const ACookie: PX2HashCookie): PX2HashCookie;
begin
Result := ACookie;
end;
{========================================
TX2HashStringManager
========================================}
procedure TX2HashStringManager.FreeCookie(var ACookie: PX2HashCookie);
var
stringCookie: PX2HashStringCookie;
begin
if Assigned(ACookie) then
begin
stringCookie := ACookie;
if stringCookie^.Length > 0 then
FreeMem(stringCookie^.Value, Succ(stringCookie^.Length));
Dispose(stringCookie);
end;
inherited;
end;
function TX2HashStringManager.CreateCookie(const AValue: string): PX2HashCookie;
var
stringCookie: PX2HashStringCookie;
begin
New(stringCookie);
stringCookie^.Length := Length(AValue);
GetMem(stringCookie^.Value, Succ(Length(AValue)) * SizeOf(Char));
StrPCopy(stringCookie^.Value, AValue);
Result := stringCookie;
end;
function TX2HashStringManager.GetValue(const ACookie: PX2HashCookie): string;
var
stringCookie: PX2HashStringCookie;
begin
Result := '';
if Assigned(ACookie) then
begin
stringCookie := ACookie;
if stringCookie^.Length > 0 then
begin
SetLength(Result, stringCookie^.Length);
Move(stringCookie^.Value^, Result[1], stringCookie^.Length * SizeOf(Char));
end;
end;
end;
function TX2HashStringManager.Hash(ACookie: PX2HashCookie): Cardinal;
var
stringCookie: PX2HashStringCookie;
begin
Result := 0;
if Assigned(ACookie) then
begin
stringCookie := ACookie;
Result := CRC32(stringCookie^.Value);
end;
end;
function TX2HashStringManager.Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean;
begin
Result := (GetValue(ACookie1) = GetValue(ACookie2));
end;
function TX2HashStringManager.Clone(const ACookie: PX2HashCookie): PX2HashCookie;
begin
Result := CreateCookie(GetValue(ACookie));
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Abstract hash implementation'}
{$ENDIF}
{========================== TX2CustomHash
Initialization
========================================}
constructor TX2CustomHash.Create;
begin
inherited;
FKeyManager := CreateKeyManager;
FValueManager := CreateValueManager;
end;
destructor TX2CustomHash.Destroy;
begin
Clear;
FreeAndNil(FValueManager);
FreeAndNil(FKeyManager);
FreeAndNil(FCursor);
inherited;
end;
function TX2CustomHash.CreateCursor: TX2HashCursor;
begin
Result := nil;
if Assigned(FRoot) then
Result := TX2HashCursor.Create(FRoot);
end;
procedure TX2CustomHash.InvalidateCursor;
begin
FreeAndNil(FCursor);
end;
{========================== TX2CustomHash
Item Management
========================================}
function ROR(const AValue: Cardinal; const AShift: Byte = 8): Cardinal;
asm
MOV cl, dl
ROR eax, cl
end;
function TX2CustomHash.CursorRequired(const ARaiseException: Boolean): Boolean;
begin
Result := True;
if not Assigned(FCursor) then
if Assigned(FRoot) then
FCursor := CreateCursor
else
begin
Result := False;
if ARaiseException then
raise EX2HashNoCursor.Create('Cursor not available!');
end;
end;
function TX2CustomHash.InternalFind(const ABucket: PX2HashBucket;
const AHash: Cardinal; const AKey: PX2HashCookie;
const AAllowCreate: Boolean;
const AExisting: PX2HashValue): PX2HashValue;
function CreateValue: PX2HashValue;
begin
if AExisting = nil then
begin
GetMem(Result, SizeOf(TX2HashValue));
FillChar(Result^, SizeOf(TX2HashValue), #0);
Result^.ID := HIDValue;
Result^.Key := KeyManager.Clone(AKey);
Inc(FCount);
end else
Result := AExisting;
InvalidateCursor;
end;
var
bucketCount: Integer;
bucketIndex: Integer;
bucket: PX2HashBucket;
key: Pointer;
nextValue: PX2HashValue;
value: PX2HashValue;
begin
Result := nil;
bucketIndex := (AHash and $FF);
if ABucket^.Items[bucketIndex] = nil then
begin
if AAllowCreate then
begin
// New value
Result := CreateValue;
ABucket^.Items[bucketIndex] := PX2HashItem(Result);
Inc(ABucket^.Count);
end;
end else
case ABucket^.Items[bucketIndex]^.ID of
HIDBucket:
// Bucket, continue down
Result := InternalFind(PX2HashBucket(ABucket^.Items[bucketIndex]),
ROR(AHash), AKey, AAllowCreate);
HIDValue:
begin
bucketCount := 0;
value := PX2HashValue(ABucket^.Items[bucketIndex]);
while Assigned(value) do
begin
if KeyManager.Compare(value^.Key, AKey) then
begin
// Found existing key
Result := value;
exit;
end;
value := value^.Next;
Inc(bucketCount);
end;
if AAllowCreate then
if (bucketCount >= BucketSize) then
begin
// Bucket full
GetMem(bucket, SizeOf(TX2HashBucket));
FillChar(bucket^, SizeOf(TX2HashBucket), #0);
bucket^.ID := HIDBucket;
bucket^.Level := ABucket^.Level + 1;
value := PX2HashValue(ABucket^.Items[bucketIndex]);
while Assigned(value) do
begin
// Transfer item
key := KeyManager.Clone(value^.Key);
nextValue := value^.Next;
value^.Next := nil;
InternalFind(bucket, ROR(KeyManager.Hash(key), bucket^.Level * 8),
key, True, value);
value := nextValue;
end;
Result := InternalFind(bucket, ROR(AHash), AKey, True);
ABucket^.Items[bucketIndex] := PX2HashItem(bucket);
end else
begin
// New value
Result := CreateValue;
Result^.Next := PX2HashValue(ABucket^.Items[bucketIndex]);
ABucket^.Items[bucketIndex] := PX2HashItem(Result);
end;
end;
end;
end;
function TX2CustomHash.InternalDelete(const ABucket: PX2HashBucket;
const AHash: Cardinal;
const AKey: PX2HashCookie): Boolean;
var
iIndex: Integer;
pBucket: PX2HashBucket;
pPrev: PX2HashValue;
pValue: PX2HashValue;
begin
Result := False;
iIndex := (AHash and $FF);
if Assigned(ABucket^.Items[iIndex]) then
case ABucket^.Items[iIndex]^.ID of
HIDBucket:
begin
// Bucket, continue down
pBucket := PX2HashBucket(ABucket^.Items[iIndex]);
Result := InternalDelete(pBucket, ROR(AHash), AKey);
if pBucket^.Count = 0 then
begin
FreeMem(pBucket, SizeOf(TX2HashBucket));
ABucket^.Items[iIndex] := nil;
end;
end;
HIDValue:
begin
pPrev := nil;
pValue := PX2HashValue(ABucket^.Items[iIndex]);
while Assigned(pValue) do
begin
if KeyManager.Compare(pValue^.Key, AKey) then
begin
// Found key
if pPrev = nil then
begin
ABucket^.Items[iIndex] := PX2HashItem(pValue^.Next);
if ABucket^.Items[iIndex] = nil then
Dec(ABucket^.Count);
end else
pPrev^.Next := pValue^.Next;
KeyManager.FreeCookie(pValue^.Key);
ValueManager.FreeCookie(pValue^.Value);
FreeMem(pValue, SizeOf(TX2HashValue));
Dec(FCount);
Result := True;
exit;
end;
pPrev := pValue;
pValue := pValue^.Next;
end;
end;
end;
end;
function TX2CustomHash.Find(const AKey: PX2HashCookie; const AAllowCreate: Boolean): PX2HashValue;
var
cookie: PX2HashCookie;
begin
Result := nil;
try
if not Assigned(FRoot) then
if AAllowCreate then
begin
// Create root bucket
GetMem(FRoot, SizeOf(TX2HashBucket));
FillChar(FRoot^, SizeOf(TX2HashBucket), #0);
FRoot^.ID := HIDBucket;
end else
exit;
Result := InternalFind(FRoot, KeyManager.Hash(AKey), AKey, AAllowCreate);
finally
cookie := AKey;
KeyManager.FreeCookie(cookie);
end;
end;
procedure TX2CustomHash.Clear;
procedure DestroyBucket(const ABucket: PX2HashBucket);
var
iItem: Integer;
pNext: PX2HashValue;
pValue: PX2HashValue;
begin
for iItem := Pred(LeafSize) downto 0 do
if Assigned(ABucket^.Items[iItem]) then
case ABucket^.Items[iItem].ID of
HIDBucket:
DestroyBucket(PX2HashBucket(ABucket^.Items[iItem]));
HIDValue:
begin
pValue := PX2HashValue(ABucket^.Items[iItem]);
repeat
KeyManager.FreeCookie(pValue^.Key);
ValueManager.FreeCookie(pValue^.Value);
pNext := pValue^.Next;
FreeMem(pValue, SizeOf(TX2HashValue));
pValue := pNext;
until pValue = nil;
end;
end;
FreeMem(ABucket, SizeOf(TX2HashBucket));
end;
begin
if Assigned(FRoot) then
begin
DestroyBucket(FRoot);
InvalidateCursor;
FCount := 0;
FRoot := nil;
end;
end;
function TX2CustomHash.Exists(const AKey: PX2HashCookie): Boolean;
begin
Result := Assigned(Find(AKey, False));
end;
function TX2CustomHash.Delete(const AKey: PX2HashCookie): Boolean;
var
cookie: PX2HashCookie;
begin
try
Result := False;
if not Assigned(FRoot) then
exit;
Result := InternalDelete(FRoot, KeyManager.Hash(AKey), AKey);
if Result then
InvalidateCursor;
finally
cookie := AKey;
KeyManager.FreeCookie(cookie);
end;
end;
procedure TX2CustomHash.SetValue(const AValue: PX2HashValue;
const AData: Pointer);
begin
ValueManager.FreeCookie(AValue^.Value);
AValue^.Value := AData;
end;
procedure TX2CustomHash.First;
begin
if not CursorRequired(False) then
exit;
Cursor.First;
end;
function TX2CustomHash.Next: Boolean;
begin
Result := False;
if not CursorRequired(False) then
exit;
Result := Cursor.Next;
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Delphi 2006 enumerator support'}
{$ENDIF}
{========================================
TX2HashEnumerator
========================================}
constructor TX2HashEnumerator.Create(const AHash: TX2CustomHash;
const AEnumKeys: Boolean);
begin
inherited Create;
FEnumKeys := AEnumKeys;
if AEnumKeys then
FManager := AHash.KeyManager
else
FManager := AHash.ValueManager;
FCursor := AHash.CreateCursor;
end;
destructor TX2HashEnumerator.Destroy;
begin
FreeAndNil(FCursor);
inherited;
end;
function TX2HashEnumerator.GetCursor: PX2HashCookie;
begin
if FEnumKeys then
Result := FCursor.Current^.Key
else
Result := FCursor.Current^.Value;
end;
function TX2HashEnumerator.MoveNext: Boolean;
begin
Result := False;
if Assigned(FCursor) then
Result := FCursor.Next;
end;
{ TX2HashPointerEnumerator }
function TX2HashPointerEnumerator.GetCurrent: Pointer;
begin
Result := TX2HashPointerManager(Manager).GetValue(Cursor);
end;
{ TX2HashIntegerEnumerator }
function TX2HashIntegerEnumerator.GetCurrent: Integer;
begin
Result := TX2HashIntegerManager(Manager).GetValue(Cursor);
end;
{ TX2HashObjectEnumerator }
function TX2HashObjectEnumerator.GetCurrent: TObject;
begin
Result := TX2HashObjectManager(Manager).GetValue(Cursor);
end;
{ TX2HashStringEnumerator }
function TX2HashStringEnumerator.GetCurrent: String;
begin
Result := TX2HashStringManager(Manager).GetValue(Cursor);
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Base hash classes'}
{$ENDIF}
{========================================
TX2CustomPointerHash
========================================}
function TX2CustomPointerHash.CreateKeyManager: TX2CustomHashManager;
begin
Result := TX2HashPointerManager.Create;
end;
function TX2CustomPointerHash.GetCurrentKey: Pointer;
begin
CursorRequired;
Result := KeyManager.GetValue(Cursor.Current^.Key);
end;
function TX2CustomPointerHash.GetEnumerator: TX2HashPointerEnumerator;
begin
Result := TX2HashPointerEnumerator.Create(Self, True);
end;
function TX2CustomPointerHash.Find(const AKey: Pointer;
const AAllowCreate: Boolean): PX2HashValue;
begin
Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate);
end;
function TX2CustomPointerHash.Exists(const AKey: Pointer): Boolean;
begin
Result := inherited Exists(KeyManager.CreateCookie(AKey));
end;
function TX2CustomPointerHash.Delete(const AKey: Pointer): Boolean;
begin
Result := inherited Delete(KeyManager.CreateCookie(AKey));
end;
function TX2CustomPointerHash.GetKeyManager: TX2HashPointerManager;
begin
Result := TX2HashPointerManager(inherited KeyManager);
end;
{========================================
TX2CustomIntegerHash
========================================}
function TX2CustomIntegerHash.CreateKeyManager: TX2CustomHashManager;
begin
Result := TX2HashIntegerManager.Create;
end;
function TX2CustomIntegerHash.GetCurrentKey: Integer;
begin
CursorRequired;
Result := KeyManager.GetValue(Cursor.Current^.Key);
end;
function TX2CustomIntegerHash.GetEnumerator: TX2HashIntegerEnumerator;
begin
Result := TX2HashIntegerEnumerator.Create(Self, True);
end;
function TX2CustomIntegerHash.Find(const AKey: Integer;
const AAllowCreate: Boolean): PX2HashValue;
begin
Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate);
end;
function TX2CustomIntegerHash.Exists(const AKey: Integer): Boolean;
begin
Result := inherited Exists(KeyManager.CreateCookie(AKey));
end;
function TX2CustomIntegerHash.Delete(const AKey: Integer): Boolean;
begin
Result := inherited Delete(KeyManager.CreateCookie(AKey));
end;
function TX2CustomIntegerHash.GetKeyManager: TX2HashIntegerManager;
begin
Result := TX2HashIntegerManager(inherited KeyManager);
end;
{========================================
TX2CustomObjectHash
========================================}
function TX2CustomObjectHash.CreateKeyManager: TX2CustomHashManager;
begin
Result := TX2HashObjectManager.Create;
end;
function TX2CustomObjectHash.GetCurrentKey: TObject;
begin
CursorRequired;
Result := KeyManager.GetValue(Cursor.Current^.Key);
end;
function TX2CustomObjectHash.GetEnumerator: TX2HashObjectEnumerator;
begin
Result := TX2HashObjectEnumerator.Create(Self, True);
end;
function TX2CustomObjectHash.Find(const AKey: TObject;
const AAllowCreate: Boolean): PX2HashValue;
begin
Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate);
end;
function TX2CustomObjectHash.Exists(const AKey: TObject): Boolean;
begin
Result := inherited Exists(KeyManager.CreateCookie(AKey));
end;
function TX2CustomObjectHash.Delete(const AKey: TObject): Boolean;
begin
Result := inherited Delete(KeyManager.CreateCookie(AKey));
end;
function TX2CustomObjectHash.GetKeyManager: TX2HashObjectManager;
begin
Result := TX2HashObjectManager(inherited KeyManager);
end;
{========================================
TX2CustomStringHash
========================================}
function TX2CustomStringHash.CreateKeyManager: TX2CustomHashManager;
begin
Result := TX2HashStringManager.Create;
end;
function TX2CustomStringHash.GetCurrentKey: String;
begin
CursorRequired;
Result := TX2HashStringManager(KeyManager).GetValue(Cursor.Current^.Key);
end;
function TX2CustomStringHash.GetEnumerator: TX2HashStringEnumerator;
begin
Result := TX2HashStringEnumerator.Create(Self, True);
end;
function TX2CustomStringHash.Find(const AKey: String;
const AAllowCreate: Boolean): PX2HashValue;
begin
Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate);
end;
function TX2CustomStringHash.Exists(const AKey: String): Boolean;
begin
Result := inherited Exists(KeyManager.CreateCookie(AKey));
end;
function TX2CustomStringHash.Delete(const AKey: String): Boolean;
begin
Result := inherited Delete(KeyManager.CreateCookie(AKey));
end;
function TX2CustomStringHash.GetKeyManager: TX2HashStringManager;
begin
Result := TX2HashStringManager(inherited KeyManager);
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$REGION 'Concrete hash classes'}
{$ENDIF}
{========================================
TX2PPHash
========================================}
function TX2PPHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashPointerManager.Create;
end;
function TX2PPHash.GetCurrentValue: Pointer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2PPHash.GetValue(Key: Pointer): Pointer;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2PPHash.SetValue(Key: Pointer; const Value: Pointer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2PPHash.GetValueManager: TX2HashPointerManager;
begin
Result := TX2HashPointerManager(inherited ValueManager);
end;
{========================================
TX2PIHash
========================================}
function TX2PIHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashIntegerManager.Create;
end;
function TX2PIHash.GetCurrentValue: Integer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2PIHash.GetValue(Key: Pointer): Integer;
var
item: PX2HashValue;
begin
Result := 0;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2PIHash.SetValue(Key: Pointer; const Value: Integer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2PIHash.GetValueManager: TX2HashIntegerManager;
begin
Result := TX2HashIntegerManager(inherited ValueManager);
end;
{========================================
TX2POHash
========================================}
constructor TX2POHash.Create(const AOwnsObjects: Boolean);
begin
inherited Create;
OwnsObjects := AOwnsObjects;
end;
function TX2POHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashObjectManager.Create;
end;
function TX2POHash.GetCurrentValue: TObject;
begin
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2POHash.GetOwnsObjects: Boolean;
begin
Result := ValueManager.OwnsObjects;
end;
procedure TX2POHash.SetOwnsObjects(const Value: Boolean);
begin
ValueManager.OwnsObjects := Value;
end;
function TX2POHash.GetValue(Key: Pointer): TObject;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2POHash.SetValue(Key: Pointer; const Value: TObject);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2POHash.GetValueManager: TX2HashObjectManager;
begin
Result := TX2HashObjectManager(inherited ValueManager);
end;
{========================================
TX2PSHash
========================================}
function TX2PSHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashStringManager.Create;
end;
function TX2PSHash.GetCurrentValue: String;
begin
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2PSHash.GetValue(Key: Pointer): String;
var
item: PX2HashValue;
begin
Result := '';
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2PSHash.SetValue(Key: Pointer; const Value: String);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2PSHash.GetValueManager: TX2HashStringManager;
begin
Result := TX2HashStringManager(inherited ValueManager);
end;
{========================================
TX2IPHash
========================================}
function TX2IPHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashPointerManager.Create;
end;
function TX2IPHash.GetCurrentValue: Pointer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2IPHash.GetValue(Key: Integer): Pointer;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2IPHash.SetValue(Key: Integer; const Value: Pointer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2IPHash.GetValueManager: TX2HashPointerManager;
begin
Result := TX2HashPointerManager(inherited ValueManager);
end;
{========================================
TX2IIHash
========================================}
function TX2IIHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashIntegerManager.Create;
end;
function TX2IIHash.GetCurrentValue: Integer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2IIHash.GetValue(Key: Integer): Integer;
var
item: PX2HashValue;
begin
Result := 0;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2IIHash.SetValue(Key: Integer; const Value: Integer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2IIHash.GetValueManager: TX2HashIntegerManager;
begin
Result := TX2HashIntegerManager(inherited ValueManager);
end;
{========================================
TX2IOHash
========================================}
constructor TX2IOHash.Create(const AOwnsObjects: Boolean);
begin
inherited Create;
OwnsObjects := AOwnsObjects;
end;
function TX2IOHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashObjectManager.Create;
end;
function TX2IOHash.GetCurrentValue: TObject;
begin
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2IOHash.GetOwnsObjects: Boolean;
begin
Result := ValueManager.OwnsObjects;
end;
procedure TX2IOHash.SetOwnsObjects(const Value: Boolean);
begin
ValueManager.OwnsObjects := Value;
end;
function TX2IOHash.GetValue(Key: Integer): TObject;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2IOHash.SetValue(Key: Integer; const Value: TObject);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2IOHash.GetValueManager: TX2HashObjectManager;
begin
Result := TX2HashObjectManager(inherited ValueManager);
end;
{========================================
TX2ISHash
========================================}
function TX2ISHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashStringManager.Create;
end;
function TX2ISHash.GetCurrentValue: String;
begin
Result := TX2HashStringManager(ValueManager).GetValue(Cursor.Current^.Value);
end;
function TX2ISHash.GetValue(Key: Integer): String;
var
item: PX2HashValue;
begin
Result := '';
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2ISHash.SetValue(Key: Integer; const Value: String);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2ISHash.GetValueManager: TX2HashStringManager;
begin
Result := TX2HashStringManager(inherited ValueManager);
end;
{========================================
TX2OPHash
========================================}
function TX2OPHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashPointerManager.Create;
end;
function TX2OPHash.GetCurrentValue: Pointer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2OPHash.GetValue(Key: TObject): Pointer;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2OPHash.SetValue(Key: TObject; const Value: Pointer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2OPHash.GetValueManager: TX2HashPointerManager;
begin
Result := TX2HashPointerManager(inherited ValueManager);
end;
{========================================
TX2OIHash
========================================}
function TX2OIHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashIntegerManager.Create;
end;
function TX2OIHash.GetCurrentValue: Integer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2OIHash.GetValue(Key: TObject): Integer;
var
item: PX2HashValue;
begin
Result := 0;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2OIHash.SetValue(Key: TObject; const Value: Integer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2OIHash.GetValueManager: TX2HashIntegerManager;
begin
Result := TX2HashIntegerManager(inherited ValueManager);
end;
{========================================
TX2OOHash
========================================}
constructor TX2OOHash.Create(const AOwnsObjects: Boolean);
begin
inherited Create;
OwnsObjects := AOwnsObjects;
end;
function TX2OOHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashObjectManager.Create;
end;
function TX2OOHash.GetCurrentValue: TObject;
begin
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2OOHash.GetOwnsObjects: Boolean;
begin
Result := ValueManager.OwnsObjects;
end;
procedure TX2OOHash.SetOwnsObjects(const Value: Boolean);
begin
TX2HashObjectManager(ValueManager).OwnsObjects := Value;
end;
function TX2OOHash.GetValue(Key: TObject): TObject;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2OOHash.SetValue(Key: TObject; const Value: TObject);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2OOHash.GetValueManager: TX2HashObjectManager;
begin
Result := TX2HashObjectManager(inherited ValueManager);
end;
{========================================
TX2OSHash
========================================}
function TX2OSHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashStringManager.Create;
end;
function TX2OSHash.GetCurrentValue: String;
begin
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2OSHash.GetValue(Key: TObject): String;
var
item: PX2HashValue;
begin
Result := '';
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2OSHash.SetValue(Key: TObject; const Value: String);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2OSHash.GetValueManager: TX2HashStringManager;
begin
Result := TX2HashStringManager(inherited ValueManager);
end;
{========================================
TX2SPHash
========================================}
function TX2SPHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashPointerManager.Create;
end;
function TX2SPHash.GetCurrentValue: Pointer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2SPHash.GetValue(Key: String): Pointer;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2SPHash.SetValue(Key: String; const Value: Pointer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2SPHash.GetValueManager: TX2HashPointerManager;
begin
Result := TX2HashPointerManager(inherited ValueManager);
end;
{========================================
TX2SIHash
========================================}
function TX2SIHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashIntegerManager.Create;
end;
function TX2SIHash.GetCurrentValue: Integer;
begin
CursorRequired;
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2SIHash.GetValue(Key: String): Integer;
var
item: PX2HashValue;
begin
Result := 0;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2SIHash.SetValue(Key: String; const Value: Integer);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2SIHash.GetValueManager: TX2HashIntegerManager;
begin
Result := TX2HashIntegerManager(inherited ValueManager);
end;
{========================================
TX2SOHash
========================================}
constructor TX2SOHash.Create(const AOwnsObjects: Boolean);
begin
inherited Create;
OwnsObjects := AOwnsObjects;
end;
function TX2SOHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashObjectManager.Create;
end;
function TX2SOHash.GetCurrentValue: TObject;
begin
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2SOHash.GetOwnsObjects: Boolean;
begin
Result := ValueManager.OwnsObjects;
end;
procedure TX2SOHash.SetOwnsObjects(const Value: Boolean);
begin
TX2HashObjectManager(ValueManager).OwnsObjects := Value;
end;
function TX2SOHash.GetValue(Key: String): TObject;
var
item: PX2HashValue;
begin
Result := nil;
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2SOHash.SetValue(Key: String; const Value: TObject);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2SOHash.GetValueManager: TX2HashObjectManager;
begin
Result := TX2HashObjectManager(inherited ValueManager);
end;
{========================================
TX2SSHash
========================================}
function TX2SSHash.CreateValueManager: TX2CustomHashManager;
begin
Result := TX2HashStringManager.Create;
end;
function TX2SSHash.GetCurrentValue: String;
begin
Result := ValueManager.GetValue(Cursor.Current^.Value);
end;
function TX2SSHash.GetValue(Key: String): String;
var
item: PX2HashValue;
begin
Result := '';
item := Find(Key, False);
if Assigned(item) then
Result := ValueManager.GetValue(item^.Value);
end;
procedure TX2SSHash.SetValue(Key: String; const Value: String);
begin
inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value));
end;
function TX2SSHash.GetValueManager: TX2HashStringManager;
begin
Result := TX2HashStringManager(inherited ValueManager);
end;
{$IFDEF D2005PLUS}
{$ENDREGION}
{$ENDIF}
initialization
CRC32Init;
end.