From 5b05c3237c077fe6e9dbf4c49aa7df5cdbd827bb Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Fri, 12 Mar 2010 12:27:49 +0000 Subject: [PATCH] Refactoring in the key/value managers for X2UtHashes - Improved code clarity - Solves an obscure access violation with large amounts of data --- UnitTests/Units/HashesTest.pas | 124 +-- UnitTests/X2UtUnitTests.dpr | 4 +- UnitTests/X2UtUnitTests.dproj | 43 +- X2UtHashes.pas | 1742 +++++++++++++++++++------------- X2UtHashesVariants.pas | 244 +++-- 5 files changed, 1289 insertions(+), 868 deletions(-) diff --git a/UnitTests/Units/HashesTest.pas b/UnitTests/Units/HashesTest.pas index a371d3c..eb5bbbd 100644 --- a/UnitTests/Units/HashesTest.pas +++ b/UnitTests/Units/HashesTest.pas @@ -13,65 +13,65 @@ type private FHash: TX2CustomHash; protected - procedure TearDown(); override; - procedure FillTestItems(); virtual; abstract; + procedure TearDown; override; + procedure FillTestItems; virtual; abstract; published - procedure testSet(); virtual; abstract; - procedure testGet(); virtual; abstract; - procedure testClear(); - procedure testDelete(); virtual; abstract; - procedure testIterate(); virtual; abstract; - procedure testEnumerator(); virtual; abstract; + procedure testSet; virtual; abstract; + procedure testGet; virtual; abstract; + procedure testClear; + procedure testDelete; virtual; abstract; + procedure testIterate; virtual; abstract; + procedure testEnumerator; virtual; abstract; end; // Two test cases involving all value managers. // This should be sufficient for a realistic scenario. THashesSITest = class(THashesTest) private - function GetHash(): TX2SIHash; + function GetHash: TX2SIHash; property Hash: TX2SIHash read GetHash; protected - procedure SetUp(); override; - procedure FillTestItems(); override; + procedure SetUp; override; + procedure FillTestItems; override; published - procedure testSet(); override; - procedure testGet(); override; - procedure testDelete(); override; - procedure testIterate(); override; - procedure testEnumerator(); override; + procedure testSet; override; + procedure testGet; override; + procedure testDelete; override; + procedure testIterate; override; + procedure testEnumerator; override; end; THashesPOTest = class(THashesTest) private - function GetHash(): TX2POHash; + function GetHash: TX2POHash; property Hash: TX2POHash read GetHash; protected - procedure SetUp(); override; - procedure FillTestItems(); override; + procedure SetUp; override; + procedure FillTestItems; override; published - procedure testSet(); override; - procedure testGet(); override; - procedure testDelete(); override; - procedure testIterate(); override; - procedure testEnumerator(); override; + procedure testSet; override; + procedure testGet; override; + procedure testDelete; override; + procedure testIterate; override; + procedure testEnumerator; override; end; THashesVariantTest = class(THashesTest) private - function GetHash(): TX2SVHash; + function GetHash: TX2SVHash; property Hash: TX2SVHash read GetHash; protected - procedure SetUp(); override; - procedure FillTestItems(); override; + procedure SetUp; override; + procedure FillTestItems; override; published - procedure testSet(); override; - procedure testGet(); override; - procedure testDelete(); override; - procedure testIterate(); override; - procedure testEnumerator(); override; + procedure testSet; override; + procedure testGet; override; + procedure testDelete; override; + procedure testIterate; override; + procedure testEnumerator; override; end; THashesBugTest = class(TTestCase) @@ -101,8 +101,8 @@ end; procedure THashesTest.testClear; begin - FillTestItems(); - FHash.Clear(); + FillTestItems; + FHash.Clear; CheckEquals(0, FHash.Count); end; @@ -112,7 +112,7 @@ procedure THashesSITest.SetUp; begin inherited; - FHash := TX2SIHash.Create(); + FHash := TX2SIHash.Create; end; procedure THashesSITest.FillTestItems; @@ -124,13 +124,13 @@ end; procedure THashesSITest.testSet; begin - FillTestItems(); + FillTestItems; CheckEquals(3, Hash.Count); end; procedure THashesSITest.testGet; begin - FillTestItems(); + FillTestItems; CheckEquals(1, Hash['Key1']); CheckEquals(2, Hash['Key2']); CheckEquals(3, Hash['Key3']); @@ -138,7 +138,7 @@ end; procedure THashesSITest.testDelete; begin - FillTestItems(); + FillTestItems; Hash.Delete('Key2'); CheckEquals(2, Hash.Count); @@ -154,7 +154,7 @@ var begin {$IFDEF D2006PLUS} - FillTestItems(); + FillTestItems; FillChar(aPresent, SizeOf(aPresent), #0); for sKey in Hash do @@ -188,10 +188,10 @@ var aPresent: array[1..3] of Boolean; begin - FillTestItems(); + FillTestItems; FillChar(aPresent, SizeOf(aPresent), #0); - Hash.First(); - while Hash.Next() do + Hash.First; + while Hash.Next do if ((Hash.CurrentKey = 'Key1') and (Hash.CurrentValue = 1)) or ((Hash.CurrentKey = 'Key2') and (Hash.CurrentValue = 2)) or ((Hash.CurrentKey = 'Key3') and (Hash.CurrentValue = 3)) then @@ -203,7 +203,7 @@ begin end; -function THashesSITest.GetHash(): TX2SIHash; +function THashesSITest.GetHash: TX2SIHash; begin Result := TX2SIHash(FHash); end; @@ -219,20 +219,20 @@ end; procedure THashesPOTest.FillTestItems; begin - Hash[Pointer(0)] := TObject0.Create(); - Hash[Pointer(1)] := TObject1.Create(); - Hash[Pointer(2)] := TObject2.Create(); + Hash[Pointer(0)] := TObject0.Create; + Hash[Pointer(1)] := TObject1.Create; + Hash[Pointer(2)] := TObject2.Create; end; procedure THashesPOTest.testSet; begin - FillTestItems(); + FillTestItems; CheckEquals(3, Hash.Count); end; procedure THashesPOTest.testGet; begin - FillTestItems(); + FillTestItems; CheckTrue(Hash[Pointer(0)] is TObject0); CheckTrue(Hash[Pointer(1)] is TObject1); CheckTrue(Hash[Pointer(2)] is TObject2); @@ -240,7 +240,7 @@ end; procedure THashesPOTest.testDelete; begin - FillTestItems(); + FillTestItems; Hash.Delete(Pointer(1)); CheckEquals(2, Hash.Count); @@ -256,7 +256,7 @@ var begin {$IFDEF D2006PLUS} - FillTestItems(); + FillTestItems; FillChar(aPresent, SizeOf(aPresent), #0); for pKey in Hash do @@ -273,10 +273,10 @@ var aPresent: array[0..2] of Boolean; begin - FillTestItems(); + FillTestItems; FillChar(aPresent, SizeOf(aPresent), #0); - Hash.First(); - while Hash.Next() do + Hash.First; + while Hash.Next do if ((Hash.CurrentKey = Pointer(0)) and (Hash.CurrentValue is TObject0)) or ((Hash.CurrentKey = Pointer(1)) and (Hash.CurrentValue is TObject1)) or ((Hash.CurrentKey = Pointer(2)) and (Hash.CurrentValue is TObject2)) then @@ -288,7 +288,7 @@ begin end; -function THashesPOTest.GetHash(): TX2POHash; +function THashesPOTest.GetHash: TX2POHash; begin Result := TX2POHash(FHash); end; @@ -298,10 +298,10 @@ procedure THashesVariantTest.SetUp; begin inherited; - FHash := TX2SVHash.Create(); + FHash := TX2SVHash.Create; end; -function THashesVariantTest.GetHash(): TX2SVHash; +function THashesVariantTest.GetHash: TX2SVHash; begin Result := TX2SVHash(FHash); end; @@ -315,13 +315,13 @@ end; procedure THashesVariantTest.testSet; begin - FillTestItems(); + FillTestItems; CheckEquals(3, Hash.Count); end; procedure THashesVariantTest.testGet; begin - FillTestItems(); + FillTestItems; CheckTrue(Hash['Key1'] = 'String'); CheckTrue(Hash['Key2'] = 5); CheckTrue(Hash['Key3'] = 40.4); @@ -329,7 +329,7 @@ end; procedure THashesVariantTest.testDelete; begin - FillTestItems(); + FillTestItems; Hash.Delete('Key2'); CheckEquals(2, Hash.Count); @@ -348,10 +348,10 @@ var aPresent: array[0..2] of Boolean; begin - FillTestItems(); + FillTestItems; FillChar(aPresent, SizeOf(aPresent), #0); - Hash.First(); - while Hash.Next() do + Hash.First; + while Hash.Next do if ((Hash.CurrentKey = 'Key1') and (Hash.CurrentValue = 'String')) then aPresent[0] := True else if ((Hash.CurrentKey = 'Key2') and (Hash.CurrentValue = 5)) then diff --git a/UnitTests/X2UtUnitTests.dpr b/UnitTests/X2UtUnitTests.dpr index 9bffaa8..ee10f01 100644 --- a/UnitTests/X2UtUnitTests.dpr +++ b/UnitTests/X2UtUnitTests.dpr @@ -7,7 +7,9 @@ uses BitsTest in 'Units\BitsTest.pas', HashesTest in 'Units\HashesTest.pas', PersistTest in 'Units\PersistTest.pas', - X2UtSingleInstance in '..\X2UtSingleInstance.pas'; + X2UtSingleInstance in '..\X2UtSingleInstance.pas', + X2UtHashes in '..\X2UtHashes.pas', + X2UtHashesVariants in '..\X2UtHashesVariants.pas'; //SettingsTest in 'Units\SettingsTest.pas', //IniParserTest in 'Units\IniParserTest.pas'; diff --git a/UnitTests/X2UtUnitTests.dproj b/UnitTests/X2UtUnitTests.dproj index dde386d..89568c0 100644 --- a/UnitTests/X2UtUnitTests.dproj +++ b/UnitTests/X2UtUnitTests.dproj @@ -42,53 +42,18 @@ Delphi.Personality VCLApplication - - ip-to-country.csv countries.csv geo.db - False - True - False - - - False - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1043 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - X2UtUnitTests.dpr - - +ip-to-country.csv countries.csv geo.dbFalseTrueFalseFalseFalse1000FalseFalseFalseFalseFalse104312521.0.0.01.0.0.0X2UtUnitTests.dpr - + MainSource + + - \ No newline at end of file diff --git a/X2UtHashes.pas b/X2UtHashes.pas index da2560c..f583b7c 100644 --- a/X2UtHashes.pas +++ b/X2UtHashes.pas @@ -52,11 +52,14 @@ type { :$ Internal representation of a hash item. } + PX2HashCookie = Pointer; + PX2HashItem = ^TX2HashItem; TX2HashItem = record ID: Cardinal; end; + PX2HashBucket = ^TX2HashBucket; TX2HashBucket = record ID: Cardinal; @@ -65,135 +68,154 @@ type Items: array[0..Pred(LeafSize)] of PX2HashItem; end; + PX2HashValue = ^TX2HashValue; TX2HashValue = record ID: Cardinal; Next: PX2HashValue; - Key: Pointer; - Value: Pointer; + 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 trie from top-to-bottom, left-to-right. + :: Traverses the hash tree from top-to-bottom, left-to-right. } TX2HashCursor = class(TObject) private - FBucketPath: array of TX2BucketPath; - FCurrent: PX2HashValue; + FBucketPath: array of TX2BucketPath; + FCurrent: PX2HashValue; protected - function GetCurrent(): PX2HashValue; virtual; + function GetCurrent: PX2HashValue; virtual; public constructor Create(const ABucket: PX2HashBucket); virtual; - procedure First(); virtual; - function Next(): Boolean; virtual; + procedure First; virtual; + function Next: Boolean; virtual; - property Current: PX2HashValue read GetCurrent; + property Current: PX2HashValue read GetCurrent; end; {$IFDEF D2005PLUS} {$ENDREGION} + {$REGION 'Internal value managers'} {$ENDIF} { :$ Base value manager. } - TX2CustomHashManager = class(TObject) + TX2CustomHashManager = class(TObject) protected - procedure Initialize(var AData: Pointer); virtual; - procedure Finalize(var AData: Pointer); virtual; + procedure FreeCookie(var ACookie: PX2HashCookie); virtual; - function DataSize(const AData: Pointer): Cardinal; virtual; - function DataPointer(const AData: Pointer): Pointer; virtual; - - function ToPointer(const AValue: Pointer; const ASize: Cardinal): Pointer; overload; virtual; - function ToValue(const AData: Pointer; var AValue): Cardinal; overload; virtual; - - function Compare(const AData: Pointer; const AValue: Pointer; - const ASize: Cardinal): Boolean; 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 ToPointer(const AValue: Pointer): Pointer; overload; - function ToValue(const AData: Pointer): Pointer; overload; + 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 ToPointer(const AValue: Integer): Pointer; overload; - function ToValue(const AData: Pointer): Integer; overload; + 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) + TX2HashObjectManager = class(TX2CustomHashManager) private - FOwnsObjects: Boolean; + FOwnsObjects: Boolean; protected - procedure Finalize(var AData: Pointer); override; + procedure FreeCookie(var ACookie: PX2HashCookie); override; - function ToPointer(const AValue: TObject): Pointer; overload; - function ToValue(const AData: Pointer): TObject; overload; + function CreateCookie(const AValue: TObject): PX2HashCookie; overload; + function GetValue(const ACookie: PX2HashCookie): TObject; overload; - property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects; + 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) + TX2HashStringManager = class(TX2CustomHashManager) protected - procedure Finalize(var AData: Pointer); override; + procedure FreeCookie(var ACookie: PX2HashCookie); override; - function DataSize(const AData: Pointer): Cardinal; override; - function DataPointer(const AData: Pointer): Pointer; override; + function CreateCookie(const AValue: string): PX2HashCookie; overload; + function GetValue(const ACookie: PX2HashCookie): string; overload; - function ToPointer(const AValue: Pointer; const ASize: Cardinal): Pointer; override; - function ToValue(const AData: Pointer; var AValue): Cardinal; override; - function ToPointer(const AValue: String): Pointer; overload; - function ToValue(const AData: Pointer): String; overload; - - function Compare(const AData: Pointer; const AValue: Pointer; - const ASize: Cardinal): Boolean; override; + 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) + TX2HashEnumerator = class(TObject) private FCursor: TX2HashCursor; FManager: TX2CustomHashManager; FEnumKeys: Boolean; - function GetCursor(): Pointer; + function GetCursor: PX2HashCookie; protected property Manager: TX2CustomHashManager read FManager; - property Cursor: Pointer read GetCursor; + property Cursor: PX2HashCookie read GetCursor; public constructor Create(const AHash: TX2CustomHash; const AEnumKeys: Boolean); - destructor Destroy(); override; + destructor Destroy; override; - function MoveNext(): Boolean; + function MoveNext: Boolean; end; + { :$ Enumerator for pointer values. } @@ -201,9 +223,10 @@ type private function GetCurrent: Pointer; public - property Current: Pointer read GetCurrent; + property Current: Pointer read GetCurrent; end; + { :$ Enumerator for integer values. } @@ -211,9 +234,10 @@ type private function GetCurrent: Integer; public - property Current: Integer read GetCurrent; + property Current: Integer read GetCurrent; end; + { :$ Enumerator for object values. } @@ -221,21 +245,23 @@ type private function GetCurrent: TObject; public - property Current: TObject read GetCurrent; + property Current: TObject read GetCurrent; end; + { :$ Enumerator for string values } TX2HashStringEnumerator = class(TX2HashEnumerator) private - function GetCurrent(): String; + function GetCurrent: String; public - property Current: String read GetCurrent; + property Current: String read GetCurrent; end; {$IFDEF D2005PLUS} {$ENDREGION} + {$REGION 'Abstract hash implementation'} {$ENDIF} { @@ -250,47 +276,46 @@ type FKeyManager: TX2CustomHashManager; FValueManager: TX2CustomHashManager; protected - function CreateCursor(): TX2HashCursor; virtual; - function CreateKeyManager(): TX2CustomHashManager; virtual; abstract; - function CreateValueManager(): TX2CustomHashManager; virtual; abstract; - procedure InvalidateCursor(); + function CreateCursor: TX2HashCursor; virtual; + function CreateKeyManager: TX2CustomHashManager; virtual; abstract; + function CreateValueManager: TX2CustomHashManager; virtual; abstract; + procedure InvalidateCursor; - function Hash(const AKey: Pointer; const ASize: Cardinal): Cardinal; virtual; function CursorRequired(const ARaiseException: Boolean = True): Boolean; function InternalFind(const ABucket: PX2HashBucket; - const AHash: Cardinal; const AKey: Pointer; - const ASize: Cardinal; + const AHash: Cardinal; const AKey: PX2HashCookie; const AAllowCreate: Boolean; const AExisting: PX2HashValue = nil): PX2HashValue; function InternalDelete(const ABucket: PX2HashBucket; - const AHash: Cardinal; const AKey: Pointer; - const ASize: Cardinal): Boolean; + const AHash: Cardinal; const AKey: PX2HashCookie): Boolean; - function Find(const AKey: Pointer; const ASize: Cardinal; - const AAllowCreate: Boolean): PX2HashValue; overload; - function Exists(const AKey: Pointer; const ASize: Cardinal): Boolean; overload; - function Delete(const AKey: Pointer; const ASize: Cardinal): Boolean; overload; + { :$ 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; + property Cursor: TX2HashCursor read FCursor; + property KeyManager: TX2CustomHashManager read FKeyManager; + property ValueManager: TX2CustomHashManager read FValueManager; public - constructor Create(); virtual; - destructor Destroy(); override; + constructor Create; virtual; + destructor Destroy; override; - procedure Clear(); + procedure Clear; - procedure First(); - function Next(): Boolean; + procedure First; + function Next: Boolean; - property Count: Integer read FCount; + property Count: Integer read FCount; end; {$IFDEF D2005PLUS} {$ENDREGION} + {$REGION 'Base hash classes'} {$ENDIF} { @@ -298,79 +323,92 @@ type } TX2CustomPointerHash = class(TX2CustomHash) private - function GetCurrentKey(): Pointer; + function GetCurrentKey: Pointer; + function GetKeyManager: TX2HashPointerManager; protected - function CreateKeyManager(): TX2CustomHashManager; override; - function Find(const AKey: Pointer; - const AAllowCreate: Boolean): PX2HashValue; overload; + function CreateKeyManager: TX2CustomHashManager; override; + function Find(const AKey: Pointer; const AAllowCreate: Boolean): PX2HashValue; overload; + + property KeyManager: TX2HashPointerManager read GetKeyManager; public - function GetEnumerator(): TX2HashPointerEnumerator; + function GetEnumerator: TX2HashPointerEnumerator; function Exists(const AKey: Pointer): Boolean; overload; function Delete(const AKey: Pointer): Boolean; overload; - property CurrentKey: Pointer read GetCurrentKey; + property CurrentKey: Pointer read GetCurrentKey; end; + { :$ Base hash implementation for integer keys. } TX2CustomIntegerHash = class(TX2CustomHash) private - function GetCurrentKey(): Integer; + function GetCurrentKey: Integer; + function GetKeyManager: TX2HashIntegerManager; protected - function CreateKeyManager(): TX2CustomHashManager; override; - function Find(const AKey: Integer; - const AAllowCreate: Boolean): PX2HashValue; overload; + function CreateKeyManager: TX2CustomHashManager; override; + function Find(const AKey: Integer; const AAllowCreate: Boolean): PX2HashValue; overload; + + property KeyManager: TX2HashIntegerManager read GetKeyManager; public - function GetEnumerator(): TX2HashIntegerEnumerator; + function GetEnumerator: TX2HashIntegerEnumerator; function Exists(const AKey: Integer): Boolean; overload; function Delete(const AKey: Integer): Boolean; overload; - property CurrentKey: Integer read GetCurrentKey; + property CurrentKey: Integer read GetCurrentKey; end; + { :$ Base hash implementation for object keys. } TX2CustomObjectHash = class(TX2CustomHash) private - function GetCurrentKey(): TObject; + function GetCurrentKey: TObject; + function GetKeyManager: TX2HashObjectManager; protected - function CreateKeyManager(): TX2CustomHashManager; override; - function Find(const AKey: TObject; - const AAllowCreate: Boolean): PX2HashValue; overload; + function CreateKeyManager: TX2CustomHashManager; override; + function Find(const AKey: TObject; const AAllowCreate: Boolean): PX2HashValue; overload; + + property KeyManager: TX2HashObjectManager read GetKeyManager; public - function GetEnumerator(): TX2HashObjectEnumerator; + function GetEnumerator: TX2HashObjectEnumerator; function Exists(const AKey: TObject): Boolean; overload; function Delete(const AKey: TObject): Boolean; overload; - property CurrentKey: TObject read GetCurrentKey; + property CurrentKey: TObject read GetCurrentKey; end; + { :$ Base hash implementation for string keys. } TX2CustomStringHash = class(TX2CustomHash) protected - function GetCurrentKey(): String; + function GetCurrentKey: String; + private + function GetKeyManager: TX2HashStringManager; protected - function CreateKeyManager(): TX2CustomHashManager; override; - function Find(const AKey: String; - const AAllowCreate: Boolean): PX2HashValue; overload; + function CreateKeyManager: TX2CustomHashManager; override; + function Find(const AKey: String; const AAllowCreate: Boolean): PX2HashValue; overload; + + property KeyManager: TX2HashStringManager read GetKeyManager; public - function GetEnumerator(): TX2HashStringEnumerator; + function GetEnumerator: TX2HashStringEnumerator; function Exists(const AKey: String): Boolean; overload; function Delete(const AKey: String): Boolean; overload; - property CurrentKey: String read GetCurrentKey; + property CurrentKey: String read GetCurrentKey; end; {$IFDEF D2005PLUS} {$ENDREGION} + {$REGION 'Concrete hash classes'} {$ENDIF} { @@ -378,264 +416,344 @@ type } TX2PPHash = class(TX2CustomPointerHash) protected - function GetCurrentValue(): Pointer; + function GetCurrentValue: Pointer; function GetValue(Key: Pointer): Pointer; procedure SetValue(Key: Pointer; const Value: Pointer); + private + function GetValueManager: TX2HashPointerManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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 GetCurrentValue: Integer; function GetValue(Key: Pointer): Integer; procedure SetValue(Key: Pointer; const Value: Integer); + private + function GetValueManager: TX2HashIntegerManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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; + 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; + 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; + 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 GetCurrentValue: String; function GetValue(Key: Pointer): String; procedure SetValue(Key: Pointer; const Value: String); + private + function GetValueManager: TX2HashStringManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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 GetCurrentValue: Pointer; function GetValue(Key: Integer): Pointer; procedure SetValue(Key: Integer; const Value: Pointer); + private + function GetValueManager: TX2HashPointerManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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 GetCurrentValue: Integer; function GetValue(Key: Integer): Integer; procedure SetValue(Key: Integer; const Value: Integer); + private + function GetValueManager: TX2HashIntegerManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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; + 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; + 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; + 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 GetCurrentValue: String; function GetValue(Key: Integer): String; procedure SetValue(Key: Integer; const Value: String); protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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 GetCurrentValue: Pointer; function GetValue(Key: TObject): Pointer; procedure SetValue(Key: TObject; const Value: Pointer); protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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 GetCurrentValue: Integer; function GetValue(Key: TObject): Integer; procedure SetValue(Key: TObject; const Value: Integer); protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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; + 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; + 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; + 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 GetCurrentValue: String; function GetValue(Key: TObject): String; procedure SetValue(Key: TObject; const Value: String); protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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 GetCurrentValue: Pointer; function GetValue(Key: String): Pointer; procedure SetValue(Key: String; const Value: Pointer); protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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 GetCurrentValue: Integer; function GetValue(Key: String): Integer; procedure SetValue(Key: String; const Value: Integer); protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + 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; + 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; + 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; + 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 GetCurrentValue: String; function GetValue(Key: String): String; procedure SetValue(Key: String; const Value: String); protected - function CreateValueManager(): TX2CustomHashManager; override; + 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; + property CurrentValue: String read GetCurrentValue; + property Values[Key: String]: String read GetValue write SetValue; default; end; {$IFDEF D2005PLUS} {$ENDREGION} {$ENDIF} + implementation const HIDBucket = 1; @@ -650,7 +768,7 @@ var {======================================== CRC32 ========================================} -procedure CRC32Init(); +procedure CRC32Init; var iItem: Integer; iPoly: Integer; @@ -659,30 +777,31 @@ var begin for iItem := 255 downto 0 do begin - iValue := iItem; + iValue := iItem; for iPoly := 8 downto 1 do if (iValue and $1) <> 0 then - iValue := (iValue shr $1) xor CRC32Poly + iValue := (iValue shr $1) xor CRC32Poly else - iValue := iValue shr $1; + iValue := iValue shr $1; CRC32Table[iItem] := iValue; end; end; + function CRC32(const AKey: Pointer; const ASize: Cardinal): Cardinal; var iByte: Integer; pByte: ^Byte; begin - Result := $FFFFFFFF; - pByte := AKey; + Result := $FFFFFFFF; + pByte := AKey; for iByte := Pred(ASize) downto 0 do begin - Result := (((Result shr 8) and $00FFFFFF) xor + Result := (((Result shr 8) and $00FFFFFF) xor (CRC32Table[(Result xor pByte^) and $FF])); Inc(pByte); end; @@ -697,34 +816,36 @@ end; ========================================} constructor TX2HashCursor.Create(const ABucket: PX2HashBucket); begin - inherited Create(); + inherited Create; SetLength(FBucketPath, 1); with FBucketPath[0] do begin - Bucket := ABucket; - Index := 0; + Bucket := ABucket; + Index := 0; end; - FCurrent := nil; + FCurrent := nil; end; -function TX2HashCursor.GetCurrent(): PX2HashValue; + +function TX2HashCursor.GetCurrent: PX2HashValue; begin - Result := FCurrent; + Result := FCurrent; end; -procedure TX2HashCursor.First(); +procedure TX2HashCursor.First; begin if Length(FBucketPath) > 1 then SetLength(FBucketPath, 1); - FBucketPath[0].Index := 0; - FCurrent := nil; + FBucketPath[0].Index := 0; + FCurrent := nil; end; -function TX2HashCursor.Next(): Boolean; + +function TX2HashCursor.Next: Boolean; var bFound: Boolean; iIndex: Integer; @@ -732,21 +853,21 @@ var pItem: PX2HashItem; begin - Result := False; - iIndex := High(FBucketPath); + Result := False; + iIndex := High(FBucketPath); if iIndex = -1 then exit; - if (FCurrent <> nil) and (FCurrent^.Next <> nil) then + if Assigned(FCurrent) and Assigned(FCurrent^.Next) then begin - FCurrent := FCurrent^.Next; - Result := True; + FCurrent := FCurrent^.Next; + Result := True; exit; end; repeat pBucket := FBucketPath[iIndex].Bucket; - bFound := False; + bFound := False; while FBucketPath[iIndex].Index < LeafSize do begin @@ -763,17 +884,17 @@ begin SetLength(FBucketPath, iIndex + 1); with FBucketPath[iIndex] do begin - Bucket := PX2HashBucket(pItem); - Index := 0; + Bucket := PX2HashBucket(pItem); + Index := 0; end; - bFound := True; + bFound := True; break; end; HIDValue: begin // Got a value - FCurrent := PX2HashValue(pItem); - Result := True; + FCurrent := PX2HashValue(pItem); + Result := True; Inc(FBucketPath[iIndex].Index); exit; end; @@ -802,172 +923,210 @@ end; {======================================== TX2CustomHashManager ========================================} -procedure TX2CustomHashManager.Initialize(var AData: Pointer); +procedure TX2CustomHashManager.FreeCookie(var ACookie: Pointer); begin - AData := nil; -end; - -procedure TX2CustomHashManager.Finalize(var AData: Pointer); -begin - AData := nil; -end; - -function TX2CustomHashManager.DataSize(const AData: Pointer): Cardinal; -begin - Result := SizeOf(Pointer); -end; - -function TX2CustomHashManager.DataPointer(const AData: Pointer): Pointer; -begin - Result := AData; -end; - -function TX2CustomHashManager.ToPointer(const AValue: Pointer; - const ASize: Cardinal): Pointer; -begin - Result := Pointer(AValue^); -end; - -function TX2CustomHashManager.ToValue(const AData: Pointer; - var AValue): Cardinal; -begin - Result := DataSize(AData); - Pointer(AValue) := AData; -end; - -function TX2CustomHashManager.Compare(const AData: Pointer; const AValue: Pointer; - const ASize: Cardinal): Boolean; -begin - Result := (Pointer(AValue^) = AData); + ACookie := nil; end; {======================================== TX2HashPointerManager ========================================} -function TX2HashPointerManager.ToPointer(const AValue: Pointer): Pointer; +function TX2HashPointerManager.CreateCookie(const AValue: Pointer): PX2HashCookie; begin - Result := ToPointer(@AValue, SizeOf(Pointer)); + Result := AValue; end; -function TX2HashPointerManager.ToValue(const AData: Pointer): Pointer; + +function TX2HashPointerManager.GetValue(const ACookie: PX2HashCookie): Pointer; begin - ToValue(AData, Result); + 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.ToPointer(const AValue: Integer): Pointer; +function TX2HashIntegerManager.CreateCookie(const AValue: Integer): PX2HashCookie; begin - Result := ToPointer(@AValue, SizeOf(Integer)); + Result := PX2HashCookie(AValue); end; -function TX2HashIntegerManager.ToValue(const AData: Pointer): Integer; + +function TX2HashIntegerManager.GetValue(const ACookie: PX2HashCookie): Integer; begin - ToValue(AData, Result); + 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.Finalize(var AData: Pointer); +procedure TX2HashObjectManager.FreeCookie(var ACookie: PX2HashCookie); begin - if (AData <> nil) and (FOwnsObjects) then - TObject(AData).Free(); + if Assigned(ACookie) and (FOwnsObjects) then + GetValue(ACookie).Free; inherited; end; -function TX2HashObjectManager.ToPointer(const AValue: TObject): Pointer; + +function TX2HashObjectManager.CreateCookie(const AValue: TObject): PX2HashCookie; begin - Result := ToPointer(@AValue, SizeOf(Integer)); + Result := PX2HashCookie(AValue); end; -function TX2HashObjectManager.ToValue(const AData: Pointer): TObject; + +function TX2HashObjectManager.GetValue(const ACookie: PX2HashCookie): TObject; begin - ToValue(AData, Result); + 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.Finalize(var AData: Pointer); +procedure TX2HashStringManager.FreeCookie(var ACookie: PX2HashCookie); +var + stringCookie: PX2HashStringCookie; + begin - if AData <> nil then - FreeMem(AData, PCardinal(AData)^ + SizeOf(Cardinal)); - + 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.DataSize(const AData: Pointer): Cardinal; -begin - Result := PCardinal(AData)^; -end; -function TX2HashStringManager.DataPointer(const AData: Pointer): Pointer; -begin - Result := AData; - Inc(PCardinal(Result)); -end; - -function TX2HashStringManager.ToPointer(const AValue: Pointer; - const ASize: Cardinal): Pointer; +function TX2HashStringManager.CreateCookie(const AValue: string): PX2HashCookie; var - pData: Pointer; + stringCookie: PX2HashStringCookie; begin - // Add a 4-byte Length to the start, emulating AnsiStrings - // (except for the reference counting) - GetMem(Result, ASize + SizeOf(Cardinal)); - PCardinal(Result)^ := ASize; - pData := Result; - Inc(PCardinal(pData)); - Move(AValue^, pData^, ASize); + New(stringCookie); + stringCookie^.Length := Length(AValue); + + GetMem(stringCookie^.Value, Succ(Length(AValue))); + StrPCopy(stringCookie^.Value, AValue); + + Result := stringCookie; end; -function TX2HashStringManager.ToValue(const AData: Pointer; - var AValue): Cardinal; + +function TX2HashStringManager.GetValue(const ACookie: PX2HashCookie): string; var - pData: Pointer; - -begin - Result := DataSize(AData); - pData := DataPointer(AData); + stringCookie: PX2HashStringCookie; - SetLength(String(AValue), Result); - if Result > 0 then - Move(pData^, PChar(String(AValue))^, Result); -end; - -function TX2HashStringManager.ToPointer(const AValue: String): Pointer; begin - Result := ToPointer(PChar(AValue), Length(AValue)); + 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); + end; + end; end; -function TX2HashStringManager.ToValue(const AData: Pointer): String; -begin - ToValue(AData, Result); -end; - -function TX2HashStringManager.Compare(const AData: Pointer; const AValue: Pointer; - const ASize: Cardinal): Boolean; +function TX2HashStringManager.Hash(ACookie: PX2HashCookie): Cardinal; var - pSource: PChar; + stringCookie: PX2HashStringCookie; begin - Result := False; - if ASize <> PCardinal(AData)^ then - exit; + Result := 0; + if Assigned(ACookie) then + begin + stringCookie := ACookie; + Result := CRC32(stringCookie^.Value, stringCookie^.Length); + end; +end; - pSource := AData; - Inc(PCardinal(pSource)); - Result := CompareMem(pSource, AValue, ASize); +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} @@ -978,17 +1137,18 @@ end; {========================== TX2CustomHash Initialization ========================================} -constructor TX2CustomHash.Create(); +constructor TX2CustomHash.Create; begin inherited; - FKeyManager := CreateKeyManager(); - FValueManager := CreateValueManager(); + FKeyManager := CreateKeyManager; + FValueManager := CreateValueManager; end; -destructor TX2CustomHash.Destroy(); + +destructor TX2CustomHash.Destroy; begin - Clear(); + Clear; FreeAndNil(FValueManager); FreeAndNil(FKeyManager); FreeAndNil(FCursor); @@ -997,14 +1157,15 @@ begin end; -function TX2CustomHash.CreateCursor(): TX2HashCursor; +function TX2CustomHash.CreateCursor: TX2HashCursor; begin - Result := nil; + Result := nil; if Assigned(FRoot) then - Result := TX2HashCursor.Create(FRoot); + Result := TX2HashCursor.Create(FRoot); end; -procedure TX2CustomHash.InvalidateCursor(); + +procedure TX2CustomHash.InvalidateCursor; begin FreeAndNil(FCursor); end; @@ -1019,20 +1180,16 @@ asm ROR eax, cl end; -function TX2CustomHash.Hash(const AKey: Pointer; const ASize: Cardinal): Cardinal; -begin - Result := CRC32(AKey, ASize); -end; function TX2CustomHash.CursorRequired(const ARaiseException: Boolean): Boolean; begin - Result := True; + Result := True; if not Assigned(FCursor) then if Assigned(FRoot) then - FCursor := CreateCursor() + FCursor := CreateCursor else begin - Result := False; + Result := False; if ARaiseException then raise EX2HashNoCursor.Create('Cursor not available!'); end; @@ -1040,113 +1197,109 @@ end; function TX2CustomHash.InternalFind(const ABucket: PX2HashBucket; - const AHash: Cardinal; const AKey: Pointer; - const ASize: Cardinal; + const AHash: Cardinal; const AKey: PX2HashCookie; const AAllowCreate: Boolean; const AExisting: PX2HashValue): PX2HashValue; - function CreateValue(): PX2HashValue; + function CreateValue: PX2HashValue; begin if AExisting = nil then begin GetMem(Result, SizeOf(TX2HashValue)); FillChar(Result^, SizeOf(TX2HashValue), #0); - Result^.ID := HIDValue; - Result^.Key := FKeyManager.ToPointer(AKey, ASize); + Result^.ID := HIDValue; + Result^.Key := KeyManager.Clone(AKey); Inc(FCount); end else - Result := AExisting; + Result := AExisting; - InvalidateCursor(); + InvalidateCursor; end; var - iCount: Integer; - iIndex: Integer; - iKey: Integer; - pBucket: PX2HashBucket; - pKey: Pointer; - pNext: PX2HashValue; - pValue: PX2HashValue; + bucketCount: Integer; + bucketIndex: Integer; + bucket: PX2HashBucket; + key: Pointer; + nextValue: PX2HashValue; + value: PX2HashValue; begin - Result := nil; - iIndex := (AHash and $FF); + Result := nil; + bucketIndex := (AHash and $FF); - if ABucket^.Items[iIndex] = nil then + if ABucket^.Items[bucketIndex] = nil then begin if AAllowCreate then begin // New value - Result := CreateValue(); - ABucket^.Items[iIndex] := PX2HashItem(Result); + Result := CreateValue; + ABucket^.Items[bucketIndex] := PX2HashItem(Result); Inc(ABucket^.Count); end; end else - case ABucket^.Items[iIndex]^.ID of + case ABucket^.Items[bucketIndex]^.ID of HIDBucket: // Bucket, continue down - Result := InternalFind(PX2HashBucket(ABucket^.Items[iIndex]), - ROR(AHash), AKey, ASize, AAllowCreate); + Result := InternalFind(PX2HashBucket(ABucket^.Items[bucketIndex]), + ROR(AHash), AKey, AAllowCreate); HIDValue: begin - iCount := 0; - pValue := PX2HashValue(ABucket^.Items[iIndex]); - while pValue <> nil do + bucketCount := 0; + value := PX2HashValue(ABucket^.Items[bucketIndex]); + while Assigned(value) do begin - if FKeyManager.Compare(pValue^.Key, AKey, ASize) then + if KeyManager.Compare(value^.Key, AKey) then begin // Found existing key - Result := pValue; + Result := value; exit; end; - pValue := pValue^.Next; - Inc(iCount); + value := value^.Next; + Inc(bucketCount); end; if AAllowCreate then - if (iCount >= BucketSize) then + if (bucketCount >= BucketSize) then begin // Bucket full - GetMem(pBucket, SizeOf(TX2HashBucket)); - FillChar(pBucket^, SizeOf(TX2HashBucket), #0); - pBucket^.ID := HIDBucket; - pBucket^.Level := ABucket^.Level + 1; + GetMem(bucket, SizeOf(TX2HashBucket)); + FillChar(bucket^, SizeOf(TX2HashBucket), #0); + bucket^.ID := HIDBucket; + bucket^.Level := ABucket^.Level + 1; - pValue := PX2HashValue(ABucket^.Items[iIndex]); - while pValue <> nil do + value := PX2HashValue(ABucket^.Items[bucketIndex]); + while Assigned(value) do begin // Transfer item - iKey := FKeyManager.DataSize(pValue^.Key); - pKey := FKeyManager.DataPointer(pValue^.Key); - pNext := pValue^.Next; - pValue^.Next := nil; + key := KeyManager.Clone(value^.Key); + nextValue := value^.Next; + value^.Next := nil; - InternalFind(pBucket, ROR(Hash(@pKey, iKey), pBucket^.Level * 8), - pKey, iKey, True, pValue); + InternalFind(bucket, ROR(KeyManager.Hash(key), bucket^.Level * 8), + key, True, value); - - pValue := pNext; + value := nextValue; end; - Result := InternalFind(pBucket, ROR(AHash), AKey, ASize, True); - ABucket^.Items[iIndex] := PX2HashItem(pBucket); + Result := InternalFind(bucket, ROR(AHash), AKey, True); + ABucket^.Items[bucketIndex] := PX2HashItem(bucket); end else begin // New value - Result := CreateValue(); - Result^.Next := PX2HashValue(ABucket^.Items[iIndex]); - ABucket^.Items[iIndex] := PX2HashItem(Result); + 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: Pointer; - const ASize: Cardinal): Boolean; + const AKey: PX2HashCookie): Boolean; var iIndex: Integer; pBucket: PX2HashBucket; @@ -1154,77 +1307,83 @@ var pValue: PX2HashValue; begin - Result := False; - iIndex := (AHash and $FF); + Result := False; + iIndex := (AHash and $FF); - if ABucket^.Items[iIndex] <> nil then + 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, ASize); + Result := InternalDelete(pBucket, ROR(AHash), AKey); if pBucket^.Count = 0 then begin FreeMem(pBucket, SizeOf(TX2HashBucket)); - ABucket^.Items[iIndex] := nil; + ABucket^.Items[iIndex] := nil; end; end; HIDValue: begin - pPrev := nil; - pValue := PX2HashValue(ABucket^.Items[iIndex]); - while pValue <> nil do + pPrev := nil; + pValue := PX2HashValue(ABucket^.Items[iIndex]); + while Assigned(pValue) do begin - if FKeyManager.Compare(pValue^.Key, AKey, ASize) then + if KeyManager.Compare(pValue^.Key, AKey) then begin // Found key if pPrev = nil then begin - ABucket^.Items[iIndex] := PX2HashItem(pValue^.Next); + ABucket^.Items[iIndex] := PX2HashItem(pValue^.Next); if ABucket^.Items[iIndex] = nil then Dec(ABucket^.Count); end else pPrev^.Next := pValue^.Next; - FKeyManager.Finalize(pValue^.Key); - FValueManager.Finalize(pValue^.Value); + KeyManager.FreeCookie(pValue^.Key); + ValueManager.FreeCookie(pValue^.Value); FreeMem(pValue, SizeOf(TX2HashValue)); Dec(FCount); - Result := True; + Result := True; exit; end; - pPrev := pValue; - pValue := pValue^.Next; + pPrev := pValue; + pValue := pValue^.Next; end; end; end; end; -function TX2CustomHash.Find(const AKey: Pointer; const ASize: Cardinal; - const AAllowCreate: Boolean): PX2HashValue; +function TX2CustomHash.Find(const AKey: PX2HashCookie; const AAllowCreate: Boolean): PX2HashValue; +var + cookie: PX2HashCookie; + begin - Result := nil; - 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 := 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, Hash(AKey, ASize), AKey, ASize, - AAllowCreate); + Result := InternalFind(FRoot, KeyManager.Hash(AKey), AKey, AAllowCreate); + finally + cookie := AKey; + KeyManager.FreeCookie(cookie); + end; end; -procedure TX2CustomHash.Clear(); +procedure TX2CustomHash.Clear; procedure DestroyBucket(const ABucket: PX2HashBucket); var iItem: Integer; @@ -1233,20 +1392,20 @@ procedure TX2CustomHash.Clear(); begin for iItem := Pred(LeafSize) downto 0 do - if ABucket^.Items[iItem] <> nil then + 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]); + pValue := PX2HashValue(ABucket^.Items[iItem]); repeat - FKeyManager.Finalize(pValue^.Key); - FValueManager.Finalize(pValue^.Value); + KeyManager.FreeCookie(pValue^.Key); + ValueManager.FreeCookie(pValue^.Value); - pNext := pValue^.Next; + pNext := pValue^.Next; FreeMem(pValue, SizeOf(TX2HashValue)); - pValue := pNext; + pValue := pNext; until pValue = nil; end; end; @@ -1255,58 +1414,65 @@ procedure TX2CustomHash.Clear(); end; begin - if FRoot <> nil then + if Assigned(FRoot) then begin DestroyBucket(FRoot); - FCount := 0; - FRoot := nil; + FCount := 0; + FRoot := nil; end; end; -function TX2CustomHash.Exists(const AKey: Pointer; - const ASize: Cardinal): Boolean; +function TX2CustomHash.Exists(const AKey: PX2HashCookie): Boolean; begin - Result := (Assigned(FRoot) and (Find(AKey, ASize, False) <> nil)); + Result := Assigned(Find(AKey, False)); end; -function TX2CustomHash.Delete(const AKey: Pointer; - const ASize: Cardinal): Boolean; -begin - Result := False; - if not Assigned(FRoot) then - exit; - Result := InternalDelete(FRoot, Hash(AKey, ASize), AKey, ASize); - if Result then - InvalidateCursor(); +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.Finalize(AValue^.Value); + ValueManager.FreeCookie(AValue^.Value); AValue^.Value := AData; end; - -procedure TX2CustomHash.First(); +procedure TX2CustomHash.First; begin if not CursorRequired(False) then exit; - Cursor.First(); + Cursor.First; end; -function TX2CustomHash.Next(): Boolean; + +function TX2CustomHash.Next: Boolean; begin - Result := False; + Result := False; if not CursorRequired(False) then exit; - Result := Cursor.Next(); + Result := Cursor.Next; end; {$IFDEF D2005PLUS} {$ENDREGION} @@ -1320,62 +1486,68 @@ end; constructor TX2HashEnumerator.Create(const AHash: TX2CustomHash; const AEnumKeys: Boolean); begin - inherited Create(); + inherited Create; FEnumKeys := AEnumKeys; if AEnumKeys then - FManager := AHash.KeyManager + FManager := AHash.KeyManager else - FManager := AHash.ValueManager; + FManager := AHash.ValueManager; - FCursor := AHash.CreateCursor(); + FCursor := AHash.CreateCursor; end; -destructor TX2HashEnumerator.Destroy(); + +destructor TX2HashEnumerator.Destroy; begin FreeAndNil(FCursor); inherited; end; -function TX2HashEnumerator.GetCursor(): Pointer; + +function TX2HashEnumerator.GetCursor: PX2HashCookie; begin if FEnumKeys then - Result := FCursor.Current^.Key + Result := FCursor.Current^.Key else - Result := FCursor.Current^.Value; + Result := FCursor.Current^.Value; end; -function TX2HashEnumerator.MoveNext(): Boolean; + +function TX2HashEnumerator.MoveNext: Boolean; begin - Result := False; + Result := False; if Assigned(FCursor) then - Result := FCursor.Next(); + Result := FCursor.Next; end; { TX2HashPointerEnumerator } -function TX2HashPointerEnumerator.GetCurrent(): Pointer; +function TX2HashPointerEnumerator.GetCurrent: Pointer; begin - Result := TX2HashPointerManager(Manager).ToValue(Cursor); + Result := TX2HashPointerManager(Manager).GetValue(Cursor); end; + { TX2HashIntegerEnumerator } -function TX2HashIntegerEnumerator.GetCurrent(): Integer; +function TX2HashIntegerEnumerator.GetCurrent: Integer; begin - Result := TX2HashIntegerManager(Manager).ToValue(Cursor); + Result := TX2HashIntegerManager(Manager).GetValue(Cursor); end; + { TX2HashObjectEnumerator } -function TX2HashObjectEnumerator.GetCurrent(): TObject; +function TX2HashObjectEnumerator.GetCurrent: TObject; begin - Result := TX2HashObjectManager(Manager).ToValue(Cursor); + Result := TX2HashObjectManager(Manager).GetValue(Cursor); end; + { TX2HashStringEnumerator } -function TX2HashStringEnumerator.GetCurrent(): String; +function TX2HashStringEnumerator.GetCurrent: String; begin - Result := TX2HashStringManager(Manager).ToValue(Cursor); + Result := TX2HashStringManager(Manager).GetValue(Cursor); end; {$IFDEF D2005PLUS} {$ENDREGION} @@ -1386,145 +1558,188 @@ end; {======================================== TX2CustomPointerHash ========================================} -function TX2CustomPointerHash.CreateKeyManager(): TX2CustomHashManager; +function TX2CustomPointerHash.CreateKeyManager: TX2CustomHashManager; begin - Result := TX2HashPointerManager.Create(); + Result := TX2HashPointerManager.Create; end; -function TX2CustomPointerHash.GetCurrentKey(): Pointer; + +function TX2CustomPointerHash.GetCurrentKey: Pointer; begin - CursorRequired(); - Result := TX2HashPointerManager(KeyManager).ToValue(Cursor.Current^.Key); + CursorRequired; + Result := KeyManager.GetValue(Cursor.Current^.Key); end; -function TX2CustomPointerHash.GetEnumerator(): TX2HashPointerEnumerator; + +function TX2CustomPointerHash.GetEnumerator: TX2HashPointerEnumerator; begin - Result := TX2HashPointerEnumerator.Create(Self, True); + Result := TX2HashPointerEnumerator.Create(Self, True); end; + function TX2CustomPointerHash.Find(const AKey: Pointer; const AAllowCreate: Boolean): PX2HashValue; begin - Result := inherited Find(@AKey, SizeOf(Pointer), AAllowCreate); + Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate); end; + function TX2CustomPointerHash.Exists(const AKey: Pointer): Boolean; begin - Result := inherited Exists(@AKey, SizeOf(Pointer)); + Result := inherited Exists(KeyManager.CreateCookie(AKey)); end; + function TX2CustomPointerHash.Delete(const AKey: Pointer): Boolean; begin - Result := inherited Delete(@AKey, SizeOf(Pointer)); + Result := inherited Delete(KeyManager.CreateCookie(AKey)); +end; + + +function TX2CustomPointerHash.GetKeyManager: TX2HashPointerManager; +begin + Result := TX2HashPointerManager(inherited KeyManager); end; {======================================== TX2CustomIntegerHash ========================================} -function TX2CustomIntegerHash.CreateKeyManager(): TX2CustomHashManager; +function TX2CustomIntegerHash.CreateKeyManager: TX2CustomHashManager; begin - Result := TX2HashIntegerManager.Create(); + Result := TX2HashIntegerManager.Create; end; -function TX2CustomIntegerHash.GetCurrentKey(): Integer; + +function TX2CustomIntegerHash.GetCurrentKey: Integer; begin - CursorRequired(); - Result := TX2HashIntegerManager(KeyManager).ToValue(Cursor.Current^.Key); + CursorRequired; + Result := KeyManager.GetValue(Cursor.Current^.Key); end; -function TX2CustomIntegerHash.GetEnumerator(): TX2HashIntegerEnumerator; + +function TX2CustomIntegerHash.GetEnumerator: TX2HashIntegerEnumerator; begin - Result := TX2HashIntegerEnumerator.Create(Self, True); + Result := TX2HashIntegerEnumerator.Create(Self, True); end; + function TX2CustomIntegerHash.Find(const AKey: Integer; const AAllowCreate: Boolean): PX2HashValue; begin - Result := inherited Find(@AKey, SizeOf(Pointer), AAllowCreate); + Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate); end; + function TX2CustomIntegerHash.Exists(const AKey: Integer): Boolean; begin - Result := inherited Exists(@AKey, SizeOf(Pointer)); + Result := inherited Exists(KeyManager.CreateCookie(AKey)); end; + function TX2CustomIntegerHash.Delete(const AKey: Integer): Boolean; begin - Result := inherited Delete(@AKey, SizeOf(Pointer)); + Result := inherited Delete(KeyManager.CreateCookie(AKey)); +end; + + +function TX2CustomIntegerHash.GetKeyManager: TX2HashIntegerManager; +begin + Result := TX2HashIntegerManager(inherited KeyManager); end; {======================================== TX2CustomObjectHash ========================================} -function TX2CustomObjectHash.CreateKeyManager(): TX2CustomHashManager; +function TX2CustomObjectHash.CreateKeyManager: TX2CustomHashManager; begin - Result := TX2HashObjectManager.Create(); + Result := TX2HashObjectManager.Create; end; -function TX2CustomObjectHash.GetCurrentKey(): TObject; + +function TX2CustomObjectHash.GetCurrentKey: TObject; begin - CursorRequired(); - Result := TX2HashObjectManager(KeyManager).ToValue(Cursor.Current^.Key); + CursorRequired; + Result := KeyManager.GetValue(Cursor.Current^.Key); end; -function TX2CustomObjectHash.GetEnumerator(): TX2HashObjectEnumerator; + +function TX2CustomObjectHash.GetEnumerator: TX2HashObjectEnumerator; begin - Result := TX2HashObjectEnumerator.Create(Self, True); + Result := TX2HashObjectEnumerator.Create(Self, True); end; + function TX2CustomObjectHash.Find(const AKey: TObject; const AAllowCreate: Boolean): PX2HashValue; begin - Result := inherited Find(@AKey, SizeOf(Pointer), AAllowCreate); + Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate); end; + function TX2CustomObjectHash.Exists(const AKey: TObject): Boolean; begin - Result := inherited Exists(@AKey, SizeOf(Pointer)); + Result := inherited Exists(KeyManager.CreateCookie(AKey)); end; + function TX2CustomObjectHash.Delete(const AKey: TObject): Boolean; begin - Result := inherited Delete(@AKey, SizeOf(Pointer)); + Result := inherited Delete(KeyManager.CreateCookie(AKey)); +end; + + +function TX2CustomObjectHash.GetKeyManager: TX2HashObjectManager; +begin + Result := TX2HashObjectManager(inherited KeyManager); end; {======================================== TX2CustomStringHash ========================================} -function TX2CustomStringHash.CreateKeyManager(): TX2CustomHashManager; +function TX2CustomStringHash.CreateKeyManager: TX2CustomHashManager; begin - Result := TX2HashStringManager.Create(); -end; - -function TX2CustomStringHash.GetCurrentKey(): String; -begin - CursorRequired(); - Result := TX2HashStringManager(KeyManager).ToValue(Cursor.Current^.Key); + Result := TX2HashStringManager.Create; end; -function TX2CustomStringHash.GetEnumerator(): TX2HashStringEnumerator; +function TX2CustomStringHash.GetCurrentKey: String; begin - Result := TX2HashStringEnumerator.Create(Self, True); + 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(PChar(AKey), Length(AKey), AAllowCreate); + Result := inherited Find(KeyManager.CreateCookie(AKey), AAllowCreate); end; + function TX2CustomStringHash.Exists(const AKey: String): Boolean; begin - Result := inherited Exists(PChar(AKey), Length(AKey)); + Result := inherited Exists(KeyManager.CreateCookie(AKey)); end; + function TX2CustomStringHash.Delete(const AKey: String): Boolean; begin - Result := inherited Delete(PChar(AKey), Length(AKey)); + Result := inherited Delete(KeyManager.CreateCookie(AKey)); +end; + + +function TX2CustomStringHash.GetKeyManager: TX2HashStringManager; +begin + Result := TX2HashStringManager(inherited KeyManager); end; {$IFDEF D2005PLUS} {$ENDREGION} @@ -1535,557 +1750,707 @@ end; {======================================== TX2PPHash ========================================} -function TX2PPHash.CreateValueManager(): TX2CustomHashManager; +function TX2PPHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashPointerManager.Create(); + Result := TX2HashPointerManager.Create; end; -function TX2PPHash.GetCurrentValue(): Pointer; + +function TX2PPHash.GetCurrentValue: Pointer; begin - CursorRequired(); - Result := TX2HashPointerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2PPHash.GetValue(Key: Pointer): Pointer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashPointerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashPointerManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); end; + +function TX2PPHash.GetValueManager: TX2HashPointerManager; +begin + Result := TX2HashPointerManager(inherited ValueManager); +end; + + {======================================== TX2PIHash ========================================} -function TX2PIHash.CreateValueManager(): TX2CustomHashManager; +function TX2PIHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashIntegerManager.Create(); + Result := TX2HashIntegerManager.Create; end; -function TX2PIHash.GetCurrentValue(): Integer; + +function TX2PIHash.GetCurrentValue: Integer; begin - CursorRequired(); - Result := TX2HashIntegerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2PIHash.GetValue(Key: Pointer): Integer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := 0; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashIntegerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashIntegerManager(ValueManager).ToPointer(Value)); + 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(); + inherited Create; OwnsObjects := AOwnsObjects; end; -function TX2POHash.CreateValueManager(): TX2CustomHashManager; + +function TX2POHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashObjectManager.Create(); + Result := TX2HashObjectManager.Create; end; -function TX2POHash.GetCurrentValue(): TObject; + +function TX2POHash.GetCurrentValue: TObject; begin - Result := TX2HashObjectManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := ValueManager.GetValue(Cursor.Current^.Value); end; -function TX2POHash.GetOwnsObjects(): Boolean; + +function TX2POHash.GetOwnsObjects: Boolean; begin - Result := TX2HashObjectManager(ValueManager).OwnsObjects; + Result := ValueManager.OwnsObjects; end; + procedure TX2POHash.SetOwnsObjects(const Value: Boolean); begin - TX2HashObjectManager(ValueManager).OwnsObjects := Value; + ValueManager.OwnsObjects := Value; end; + function TX2POHash.GetValue(Key: Pointer): TObject; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashObjectManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashObjectManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2POHash.GetValueManager: TX2HashObjectManager; +begin + Result := TX2HashObjectManager(inherited ValueManager); end; {======================================== TX2PSHash ========================================} -function TX2PSHash.CreateValueManager(): TX2CustomHashManager; +function TX2PSHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashStringManager.Create(); + Result := TX2HashStringManager.Create; end; -function TX2PSHash.GetCurrentValue(): String; + +function TX2PSHash.GetCurrentValue: String; begin - Result := TX2HashStringManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2PSHash.GetValue(Key: Pointer): String; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := ''; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashStringManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashStringManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); end; + +function TX2PSHash.GetValueManager: TX2HashStringManager; +begin + Result := TX2HashStringManager(inherited ValueManager); +end; + + {======================================== TX2IPHash ========================================} -function TX2IPHash.CreateValueManager(): TX2CustomHashManager; +function TX2IPHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashPointerManager.Create(); + Result := TX2HashPointerManager.Create; end; -function TX2IPHash.GetCurrentValue(): Pointer; + +function TX2IPHash.GetCurrentValue: Pointer; begin - CursorRequired(); - Result := TX2HashPointerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2IPHash.GetValue(Key: Integer): Pointer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashPointerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashPointerManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); end; + +function TX2IPHash.GetValueManager: TX2HashPointerManager; +begin + Result := TX2HashPointerManager(inherited ValueManager); +end; + + {======================================== TX2IIHash ========================================} -function TX2IIHash.CreateValueManager(): TX2CustomHashManager; +function TX2IIHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashIntegerManager.Create(); + Result := TX2HashIntegerManager.Create; end; -function TX2IIHash.GetCurrentValue(): Integer; + +function TX2IIHash.GetCurrentValue: Integer; begin - CursorRequired(); - Result := TX2HashIntegerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2IIHash.GetValue(Key: Integer): Integer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := 0; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashIntegerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashIntegerManager(ValueManager).ToPointer(Value)); + 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(); + inherited Create; OwnsObjects := AOwnsObjects; end; -function TX2IOHash.CreateValueManager(): TX2CustomHashManager; + +function TX2IOHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashObjectManager.Create(); + Result := TX2HashObjectManager.Create; end; -function TX2IOHash.GetCurrentValue(): TObject; +function TX2IOHash.GetCurrentValue: TObject; begin - Result := TX2HashObjectManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := ValueManager.GetValue(Cursor.Current^.Value); end; -function TX2IOHash.GetOwnsObjects(): Boolean; + +function TX2IOHash.GetOwnsObjects: Boolean; begin - Result := TX2HashObjectManager(ValueManager).OwnsObjects; + Result := ValueManager.OwnsObjects; end; + procedure TX2IOHash.SetOwnsObjects(const Value: Boolean); begin - TX2HashObjectManager(ValueManager).OwnsObjects := Value; + ValueManager.OwnsObjects := Value; end; + function TX2IOHash.GetValue(Key: Integer): TObject; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashObjectManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashObjectManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2IOHash.GetValueManager: TX2HashObjectManager; +begin + Result := TX2HashObjectManager(inherited ValueManager); end; {======================================== TX2ISHash ========================================} -function TX2ISHash.CreateValueManager(): TX2CustomHashManager; +function TX2ISHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashStringManager.Create(); + Result := TX2HashStringManager.Create; end; -function TX2ISHash.GetCurrentValue(): String; + +function TX2ISHash.GetCurrentValue: String; begin - Result := TX2HashStringManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := TX2HashStringManager(ValueManager).GetValue(Cursor.Current^.Value); end; + function TX2ISHash.GetValue(Key: Integer): String; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := ''; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashStringManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashStringManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); end; + +function TX2ISHash.GetValueManager: TX2HashStringManager; +begin + Result := TX2HashStringManager(inherited ValueManager); +end; + + {======================================== TX2OPHash ========================================} -function TX2OPHash.CreateValueManager(): TX2CustomHashManager; +function TX2OPHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashPointerManager.Create(); + Result := TX2HashPointerManager.Create; end; -function TX2OPHash.GetCurrentValue(): Pointer; + +function TX2OPHash.GetCurrentValue: Pointer; begin - CursorRequired(); - Result := TX2HashPointerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2OPHash.GetValue(Key: TObject): Pointer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashPointerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashPointerManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); end; + +function TX2OPHash.GetValueManager: TX2HashPointerManager; +begin + Result := TX2HashPointerManager(inherited ValueManager); +end; + + {======================================== TX2OIHash ========================================} -function TX2OIHash.CreateValueManager(): TX2CustomHashManager; +function TX2OIHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashIntegerManager.Create(); + Result := TX2HashIntegerManager.Create; end; -function TX2OIHash.GetCurrentValue(): Integer; + +function TX2OIHash.GetCurrentValue: Integer; begin - CursorRequired(); - Result := TX2HashIntegerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2OIHash.GetValue(Key: TObject): Integer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := 0; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashIntegerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashIntegerManager(ValueManager).ToPointer(Value)); + 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(); + inherited Create; OwnsObjects := AOwnsObjects; end; -function TX2OOHash.CreateValueManager(): TX2CustomHashManager; + +function TX2OOHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashObjectManager.Create(); + Result := TX2HashObjectManager.Create; end; -function TX2OOHash.GetCurrentValue(): TObject; + +function TX2OOHash.GetCurrentValue: TObject; begin - Result := TX2HashObjectManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := ValueManager.GetValue(Cursor.Current^.Value); end; -function TX2OOHash.GetOwnsObjects(): Boolean; + +function TX2OOHash.GetOwnsObjects: Boolean; begin - Result := TX2HashObjectManager(ValueManager).OwnsObjects; + Result := ValueManager.OwnsObjects; end; + procedure TX2OOHash.SetOwnsObjects(const Value: Boolean); begin - TX2HashObjectManager(ValueManager).OwnsObjects := Value; + TX2HashObjectManager(ValueManager).OwnsObjects := Value; end; + function TX2OOHash.GetValue(Key: TObject): TObject; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashObjectManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashObjectManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2OOHash.GetValueManager: TX2HashObjectManager; +begin + Result := TX2HashObjectManager(inherited ValueManager); end; {======================================== TX2OSHash ========================================} -function TX2OSHash.CreateValueManager(): TX2CustomHashManager; +function TX2OSHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashStringManager.Create(); + Result := TX2HashStringManager.Create; end; -function TX2OSHash.GetCurrentValue(): String; + +function TX2OSHash.GetCurrentValue: String; begin - Result := TX2HashStringManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2OSHash.GetValue(Key: TObject): String; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := ''; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashStringManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashStringManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); end; + +function TX2OSHash.GetValueManager: TX2HashStringManager; +begin + Result := TX2HashStringManager(inherited ValueManager); +end; + + {======================================== TX2SPHash ========================================} -function TX2SPHash.CreateValueManager(): TX2CustomHashManager; +function TX2SPHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashPointerManager.Create(); + Result := TX2HashPointerManager.Create; end; -function TX2SPHash.GetCurrentValue(): Pointer; + +function TX2SPHash.GetCurrentValue: Pointer; begin - CursorRequired(); - Result := TX2HashPointerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2SPHash.GetValue(Key: String): Pointer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashPointerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashPointerManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); end; + +function TX2SPHash.GetValueManager: TX2HashPointerManager; +begin + Result := TX2HashPointerManager(inherited ValueManager); +end; + + {======================================== TX2SIHash ========================================} -function TX2SIHash.CreateValueManager(): TX2CustomHashManager; +function TX2SIHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashIntegerManager.Create(); + Result := TX2HashIntegerManager.Create; end; -function TX2SIHash.GetCurrentValue(): Integer; + +function TX2SIHash.GetCurrentValue: Integer; begin - CursorRequired(); - Result := TX2HashIntegerManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2SIHash.GetValue(Key: String): Integer; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := 0; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashIntegerManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashIntegerManager(ValueManager).ToPointer(Value)); + 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(); + inherited Create; OwnsObjects := AOwnsObjects; end; -function TX2SOHash.CreateValueManager(): TX2CustomHashManager; + +function TX2SOHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashObjectManager.Create(); + Result := TX2HashObjectManager.Create; end; -function TX2SOHash.GetCurrentValue(): TObject; + +function TX2SOHash.GetCurrentValue: TObject; begin - Result := TX2HashObjectManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := ValueManager.GetValue(Cursor.Current^.Value); end; -function TX2SOHash.GetOwnsObjects(): Boolean; + +function TX2SOHash.GetOwnsObjects: Boolean; begin - Result := TX2HashObjectManager(ValueManager).OwnsObjects; + Result := ValueManager.OwnsObjects; end; + procedure TX2SOHash.SetOwnsObjects(const Value: Boolean); begin - TX2HashObjectManager(ValueManager).OwnsObjects := Value; + TX2HashObjectManager(ValueManager).OwnsObjects := Value; end; + function TX2SOHash.GetValue(Key: String): TObject; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := nil; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashObjectManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashObjectManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2SOHash.GetValueManager: TX2HashObjectManager; +begin + Result := TX2HashObjectManager(inherited ValueManager); end; {======================================== TX2SSHash ========================================} -function TX2SSHash.CreateValueManager(): TX2CustomHashManager; +function TX2SSHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashStringManager.Create(); + Result := TX2HashStringManager.Create; end; -function TX2SSHash.GetCurrentValue(): String; + +function TX2SSHash.GetCurrentValue: String; begin - Result := TX2HashStringManager(ValueManager).ToValue(Cursor.Current^.Value); + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2SSHash.GetValue(Key: String): String; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := ''; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashStringManager(ValueManager).ToValue(pItem^.Value); + 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), - TX2HashStringManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2SSHash.GetValueManager: TX2HashStringManager; +begin + Result := TX2HashStringManager(inherited ValueManager); end; {$IFDEF D2005PLUS} {$ENDREGION} @@ -2093,6 +2458,7 @@ end; initialization - CRC32Init(); + CRC32Init; end. + diff --git a/X2UtHashesVariants.pas b/X2UtHashesVariants.pas index 83a9232..b7410a6 100644 --- a/X2UtHashesVariants.pas +++ b/X2UtHashesVariants.pas @@ -13,244 +13,332 @@ uses X2UtHashes; + type { :$ Variant value class. } TX2HashVariantManager = class(TX2CustomHashManager) public - procedure Finalize(var AData: Pointer); override; + procedure FreeCookie(var ACookie: PX2HashCookie); override; - function DataSize(const AData: Pointer): Cardinal; override; + function CreateCookie(const AValue: Variant): PX2HashCookie; overload; + function GetValue(const ACookie: PX2HashCookie): Variant; overload; - function ToPointer(const AValue: Variant): Pointer; overload; - function ToValue(const AData: Pointer): Variant; overload; - - function Compare(const AData: Pointer; const AValue: Pointer; - const ASize: Cardinal): Boolean; override; + function Hash(ACookie: PX2HashCookie): Cardinal; override; + function Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean; override; + function Clone(const ACookie: PX2HashCookie): PX2HashCookie; override; end; + { :$ Pointer-to-Variant hash. } TX2PVHash = class(TX2CustomPointerHash) private - function GetCurrentValue(): Variant; + function GetCurrentValue: Variant; function GetValue(Key: Pointer): Variant; procedure SetValue(Key: Pointer; const Value: Variant); + function GetValueManager: TX2HashVariantManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + function CreateValueManager: TX2CustomHashManager; override; + + property ValueManager: TX2HashVariantManager read GetValueManager; public property CurrentValue: Variant read GetCurrentValue; property Values[Key: Pointer]: Variant read GetValue write SetValue; default; end; + { :$ Integer-to-Variant hash. } TX2IVHash = class(TX2CustomIntegerHash) private - function GetCurrentValue(): Variant; + function GetCurrentValue: Variant; function GetValue(Key: Integer): Variant; procedure SetValue(Key: Integer; const Value: Variant); + function GetValueManager: TX2HashVariantManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + function CreateValueManager: TX2CustomHashManager; override; + + property ValueManager: TX2HashVariantManager read GetValueManager; public property CurrentValue: Variant read GetCurrentValue; property Values[Key: Integer]: Variant read GetValue write SetValue; default; end; + { :$ Object-to-Variant hash. } TX2OVHash = class(TX2CustomObjectHash) private - function GetCurrentValue(): Variant; + function GetCurrentValue: Variant; function GetValue(Key: TObject): Variant; procedure SetValue(Key: TObject; const Value: Variant); + function GetValueManager: TX2HashVariantManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + function CreateValueManager: TX2CustomHashManager; override; + + property ValueManager: TX2HashVariantManager read GetValueManager; public property CurrentValue: Variant read GetCurrentValue; property Values[Key: TObject]: Variant read GetValue write SetValue; default; end; + { :$ String-to-Variant hash. } TX2SVHash = class(TX2CustomStringHash) private - function GetCurrentValue(): Variant; + function GetCurrentValue: Variant; function GetValue(Key: String): Variant; procedure SetValue(Key: String; const Value: Variant); + function GetValueManager: TX2HashVariantManager; protected - function CreateValueManager(): TX2CustomHashManager; override; + function CreateValueManager: TX2CustomHashManager; override; + + property ValueManager: TX2HashVariantManager read GetValueManager; public property CurrentValue: Variant read GetCurrentValue; property Values[Key: String]: Variant read GetValue write SetValue; default; end; + implementation +uses + SysUtils; + {======================================== TX2HashVariantManager ========================================} -function TX2HashVariantManager.DataSize(const AData: Pointer): Cardinal; -begin - Result := SizeOf(Variant); -end; +procedure TX2HashVariantManager.FreeCookie(var ACookie: PX2HashCookie); +var + variantCookie: PVariant; -procedure TX2HashVariantManager.Finalize(var AData: Pointer); begin - if AData <> nil then - Dispose(PVariant(AData)); + if Assigned(ACookie) then + begin + variantCookie := ACookie; + VarClear(variantCookie^); + + Dispose(variantCookie); + end; inherited; end; -function TX2HashVariantManager.ToPointer(const AValue: Variant): Pointer; + +function TX2HashVariantManager.CreateCookie(const AValue: Variant): PX2HashCookie; +var + variantCookie: PVariant; + begin - New(PVariant(Result)); - PVariant(Result)^ := AValue; + New(variantCookie); + VarCopy(variantCookie^, AValue); + + Result := variantCookie; end; -function TX2HashVariantManager.ToValue(const AData: Pointer): Variant; + +function TX2HashVariantManager.GetValue(const ACookie: PX2HashCookie): Variant; begin - Result := PVariant(AData)^; + VarCopy(Result, PVariant(ACookie)^); end; -function TX2HashVariantManager.Compare(const AData, AValue: Pointer; - const ASize: Cardinal): Boolean; + +function TX2HashVariantManager.Hash(ACookie: PX2HashCookie): Cardinal; begin - Result := (VarCompareValue(PVariant(AData)^, PVariant(AValue)^) = vrEqual); + { For now, this manager is only used for Values, which aren't hashed. } + raise Exception.Create('Hash method is not supported for Variants'); end; +function TX2HashVariantManager.Compare(const ACookie1, ACookie2: PX2HashCookie): Boolean; +begin + Result := (VarCompareValue(PVariant(ACookie1)^, PVariant(ACookie2)^) = vrEqual); +end; + + +function TX2HashVariantManager.Clone(const ACookie: PX2HashCookie): PX2HashCookie; +begin + Result := CreateCookie(PVariant(ACookie)^); +end; + +// +//function TX2HashVariantManager.ToValue(const AData: Pointer): Variant; +//begin +// Result := PVariant(AData)^; +//end; +// +// +//function TX2HashVariantManager.Compare(const AData, AValue: Pointer; +// const ASize: Cardinal): Boolean; +//begin +// Result := (VarCompareValue(PVariant(AData)^, PVariant(AValue)^) = vrEqual); +//end; + + {======================================== TX2PVHash ========================================} -function TX2PVHash.CreateValueManager(): TX2CustomHashManager; +function TX2PVHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashVariantManager.Create(); + Result := TX2HashVariantManager.Create; end; -function TX2PVHash.GetCurrentValue(): Variant; + +function TX2PVHash.GetCurrentValue: Variant; begin - CursorRequired(); - Result := TX2HashVariantManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2PVHash.GetValue(Key: Pointer): Variant; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := Unassigned; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashVariantManager(ValueManager).ToValue(pItem^.Value); + Result := Unassigned; + item := Find(Key, False); + if Assigned(item) then + Result := ValueManager.GetValue(item^.Value); end; + procedure TX2PVHash.SetValue(Key: Pointer; const Value: Variant); begin - inherited SetValue(Find(Key, True), - TX2HashVariantManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2PVHash.GetValueManager: TX2HashVariantManager; +begin + Result := TX2HashVariantManager(inherited ValueManager); end; {======================================== TX2IVHash ========================================} -function TX2IVHash.CreateValueManager(): TX2CustomHashManager; +function TX2IVHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashVariantManager.Create(); + Result := TX2HashVariantManager.Create; end; -function TX2IVHash.GetCurrentValue(): Variant; + +function TX2IVHash.GetCurrentValue: Variant; begin - CursorRequired(); - Result := TX2HashVariantManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2IVHash.GetValue(Key: Integer): Variant; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := Unassigned; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashVariantManager(ValueManager).ToValue(pItem^.Value); + Result := Unassigned; + item := Find(Key, False); + if Assigned(item) then + Result := ValueManager.GetValue(item^.Value); end; + procedure TX2IVHash.SetValue(Key: Integer; const Value: Variant); begin - inherited SetValue(Find(Key, True), - TX2HashVariantManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2IVHash.GetValueManager: TX2HashVariantManager; +begin + Result := TX2HashVariantManager(inherited ValueManager); end; {======================================== TX2OVHash ========================================} -function TX2OVHash.CreateValueManager(): TX2CustomHashManager; +function TX2OVHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashVariantManager.Create(); + Result := TX2HashVariantManager.Create; end; -function TX2OVHash.GetCurrentValue(): Variant; + +function TX2OVHash.GetCurrentValue: Variant; begin - CursorRequired(); - Result := TX2HashVariantManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2OVHash.GetValue(Key: TObject): Variant; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := Unassigned; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashVariantManager(ValueManager).ToValue(pItem^.Value); + Result := Unassigned; + item := Find(Key, False); + if Assigned(item) then + Result := ValueManager.GetValue(item^.Value); end; + procedure TX2OVHash.SetValue(Key: TObject; const Value: Variant); begin - inherited SetValue(Find(Key, True), - TX2HashVariantManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2OVHash.GetValueManager: TX2HashVariantManager; +begin + Result := TX2HashVariantManager(inherited ValueManager); end; {======================================== TX2SVHash ========================================} -function TX2SVHash.CreateValueManager(): TX2CustomHashManager; +function TX2SVHash.CreateValueManager: TX2CustomHashManager; begin - Result := TX2HashVariantManager.Create(); + Result := TX2HashVariantManager.Create; end; -function TX2SVHash.GetCurrentValue(): Variant; + +function TX2SVHash.GetCurrentValue: Variant; begin - CursorRequired(); - Result := TX2HashVariantManager(ValueManager).ToValue(Cursor.Current^.Value); + CursorRequired; + Result := ValueManager.GetValue(Cursor.Current^.Value); end; + function TX2SVHash.GetValue(Key: String): Variant; var - pItem: PX2HashValue; + item: PX2HashValue; begin - Result := Unassigned; - pItem := Find(Key, False); - if Assigned(pItem) then - Result := TX2HashVariantManager(ValueManager).ToValue(pItem^.Value); + Result := Unassigned; + item := Find(Key, False); + if Assigned(item) then + Result := ValueManager.GetValue(item^.Value); end; + procedure TX2SVHash.SetValue(Key: String; const Value: Variant); begin - inherited SetValue(Find(Key, True), - TX2HashVariantManager(ValueManager).ToPointer(Value)); + inherited SetValue(Find(Key, True), ValueManager.CreateCookie(Value)); +end; + + +function TX2SVHash.GetValueManager: TX2HashVariantManager; +begin + Result := TX2HashVariantManager(inherited ValueManager); end; end.