337 lines
7.3 KiB
ObjectPascal
337 lines
7.3 KiB
ObjectPascal
{
|
|
:: X2UtHashes contains a base class for hashes (also known as associative
|
|
:: arrays), as well as various default implementations.
|
|
::
|
|
:: This unit contains code based on Bob Jenkins' optimized hashing algorithm:
|
|
:: http://burtleburtle.net/bob/hash/doobs.html
|
|
::
|
|
:: Last changed: $Date$
|
|
:: Revision: $Rev$
|
|
:: Author: $Author$
|
|
}
|
|
unit X2UtHashes;
|
|
|
|
interface
|
|
uses
|
|
SysUtils,
|
|
X2UtBinaryTree;
|
|
|
|
type
|
|
{
|
|
:$ Internal representation of a hash node
|
|
}
|
|
PX2UtHashNode = ^TX2UtHashNode;
|
|
TX2UtHashNode = record
|
|
Prev: PX2UtHashNode;
|
|
Next: PX2UtHashNode;
|
|
Key: String;
|
|
Value: record end;
|
|
end;
|
|
|
|
{
|
|
:$ Hash implementation
|
|
|
|
:: This class implements a hash without knowing anything about
|
|
:: the data it contains.
|
|
}
|
|
TX2UtCustomHash = class(TX2UtCustomBTree)
|
|
private
|
|
FHashCursor: PX2UtHashNode;
|
|
FHashDataSize: Cardinal;
|
|
|
|
function GetCurrentKey(): String;
|
|
protected
|
|
function Hash(const AValue: String): Cardinal; virtual;
|
|
|
|
function LookupNode(const AKey: String;
|
|
const ACanCreate: Boolean = False;
|
|
const ASetCursor: Boolean = False): PX2UtBTreeNode;
|
|
|
|
procedure InitNode(var ANode: PX2UtBTreeNode); override;
|
|
procedure FreeNode(var ANode: PX2UtBTreeNode); override;
|
|
|
|
procedure ClearCursor(); override;
|
|
function ValidCursor(const ARaiseError: Boolean = True): Boolean; override;
|
|
|
|
procedure InitHashNode(var ANode: PX2UtHashNode); virtual;
|
|
procedure FreeHashNode(var ANode: PX2UtHashNode); virtual;
|
|
|
|
property HashDataSize: Cardinal read FHashDataSize write FHashDataSize;
|
|
|
|
//:$ Returns the key at the current cursor location.
|
|
property CurrentKey: String read GetCurrentKey;
|
|
public
|
|
//:$ Deletes an item from the hash.
|
|
procedure Delete(const AKey: String);
|
|
|
|
function Next(): Boolean; override;
|
|
|
|
//:$ Checks if a key exists in the hash.
|
|
//:: If the ASetCursor parameter is set to True, the cursor will be
|
|
//:: positioned at the item if it is found.
|
|
function Exists(const AKey: String; const ASetCursor: Boolean = False): Boolean;
|
|
end;
|
|
|
|
{
|
|
:$ Hash implementation for pointer values
|
|
}
|
|
(*
|
|
TX2UtHash = class(TX2UtCustomHash)
|
|
private
|
|
function GetItem(Key: String): Pointer;
|
|
procedure SetItem(Key: String; const Value: Pointer);
|
|
|
|
function GetCurrentValue(): Pointer;
|
|
public
|
|
constructor Create(); override;
|
|
property CurrentKey;
|
|
|
|
//:$ Gets or sets an item.
|
|
property Items[Key: String]: Pointer read GetItem
|
|
write SetItem; default;
|
|
|
|
//:$ Returns the value at the current cursor location.
|
|
property CurrentValue: Pointer read GetCurrentValue;
|
|
end;
|
|
|
|
{
|
|
:$ Hash implementation for string values
|
|
}
|
|
TX2UtStringHash = class(TX2UtCustomHash)
|
|
private
|
|
function GetItem(Key: String): String;
|
|
procedure SetItem(Key: String; const Value: String);
|
|
|
|
function GetCurrentValue(): String;
|
|
protected
|
|
procedure InitNode(var ANode: PX2UtBTreeNode); override;
|
|
procedure FreeNode(var ANode: PX2UtBTreeNode); override;
|
|
public
|
|
constructor Create(); override;
|
|
property CurrentKey;
|
|
|
|
//:$ Gets or sets an item.
|
|
property Items[Key: String]: String read GetItem
|
|
write SetItem; default;
|
|
|
|
//:$ Returns the value at the current cursor location.
|
|
property CurrentValue: String read GetCurrentValue;
|
|
end;
|
|
*)
|
|
|
|
implementation
|
|
|
|
{======================== TX2UtCustomHash
|
|
Hashing
|
|
========================================}
|
|
function TX2UtCustomHash.Hash;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
|
|
|
|
|
|
{======================== TX2UtCustomHash
|
|
Tree Traversing
|
|
========================================}
|
|
function TX2UtCustomHash.ValidCursor;
|
|
begin
|
|
Result := inherited ValidCursor(ARaiseError);
|
|
if Result then
|
|
begin
|
|
end;
|
|
end;
|
|
|
|
procedure TX2UtCustomHash.ClearCursor;
|
|
begin
|
|
inherited;
|
|
|
|
FHashCursor := nil;
|
|
end;
|
|
|
|
function TX2UtCustomHash.Next;
|
|
begin
|
|
if Assigned(FHashCursor) then
|
|
FHashCursor := FHashCursor^.Next;
|
|
|
|
if not Assigned(FHashCursor) then
|
|
begin
|
|
Result := inherited Next();
|
|
if Result then
|
|
FHashCursor := GetNodeData(Cursor);
|
|
end else
|
|
Result := True;
|
|
end;
|
|
|
|
|
|
{======================== TX2UtCustomHash
|
|
Item Management
|
|
========================================}
|
|
function TX2UtCustomHash.LookupNode;
|
|
var
|
|
iIndex: Integer;
|
|
pNode: PX2UtBTreeNode;
|
|
|
|
begin
|
|
iIndex := Hash(AKey);
|
|
pNode := inherited LookupNode(iIndex, ACanCreate, ASetCursor);
|
|
end;
|
|
|
|
|
|
procedure TX2UtCustomHash.Delete;
|
|
begin
|
|
inherited Delete(Hash(AKey));
|
|
end;
|
|
|
|
function TX2UtCustomHash.Exists;
|
|
begin
|
|
Result := inherited Exists(Hash(AKey), ASetCursor);
|
|
end;
|
|
|
|
|
|
function TX2UtCustomHash.GetCurrentKey;
|
|
var
|
|
pKey: PString;
|
|
|
|
begin
|
|
Result := '';
|
|
if ValidCursor(True) then
|
|
begin
|
|
{
|
|
pKey := GetNodeInternal(Cursor);
|
|
Result := pKey^;
|
|
}
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TX2UtCustomHash.InitNode;
|
|
var
|
|
pData: PString;
|
|
|
|
begin
|
|
inherited;
|
|
|
|
{
|
|
pData := GetNodeInternal(ANode);
|
|
Initialize(pData^);
|
|
}
|
|
end;
|
|
|
|
procedure TX2UtCustomHash.FreeNode;
|
|
var
|
|
pData: PString;
|
|
|
|
begin
|
|
{
|
|
pData := GetNodeInternal(ANode);
|
|
Finalize(pData^);
|
|
}
|
|
|
|
inherited;
|
|
end;
|
|
|
|
|
|
{============================== TX2UtHash
|
|
Item Management
|
|
========================================}
|
|
constructor TX2UtHash.Create;
|
|
begin
|
|
inherited;
|
|
|
|
DataSize := SizeOf(Pointer);
|
|
end;
|
|
|
|
function TX2UtHash.GetItem;
|
|
var
|
|
pNode: PX2UtBTreeNode;
|
|
|
|
begin
|
|
pNode := LookupNode(Key);
|
|
if Assigned(pNode) then
|
|
Result := PPointer(GetNodeData(pNode))^;
|
|
end;
|
|
|
|
procedure TX2UtHash.SetItem;
|
|
var
|
|
pNode: PX2UtBTreeNode;
|
|
|
|
begin
|
|
pNode := LookupNode(Key, True);
|
|
if Assigned(pNode) then
|
|
PPointer(GetNodeData(pNode))^ := Value;
|
|
end;
|
|
|
|
function TX2UtHash.GetCurrentValue;
|
|
begin
|
|
Result := nil;
|
|
if ValidCursor(True) then
|
|
Result := PPointer(GetNodeData(Cursor))^;
|
|
end;
|
|
|
|
|
|
{======================== TX2UtStringHash
|
|
Item Management
|
|
========================================}
|
|
constructor TX2UtStringHash.Create;
|
|
begin
|
|
inherited;
|
|
|
|
DataSize := SizeOf(PString);
|
|
end;
|
|
|
|
function TX2UtStringHash.GetItem;
|
|
var
|
|
pNode: PX2UtBTreeNode;
|
|
|
|
begin
|
|
pNode := LookupNode(Key);
|
|
if Assigned(pNode) then
|
|
Result := PString(GetNodeData(pNode))^;
|
|
end;
|
|
|
|
procedure TX2UtStringHash.SetItem;
|
|
var
|
|
pNode: PX2UtBTreeNode;
|
|
|
|
begin
|
|
pNode := LookupNode(Key, True);
|
|
if Assigned(pNode) then
|
|
PString(GetNodeData(pNode))^ := Value;
|
|
end;
|
|
|
|
|
|
procedure TX2UtStringHash.InitNode;
|
|
var
|
|
pData: PString;
|
|
|
|
begin
|
|
inherited;
|
|
|
|
pData := GetNodeData(ANode);
|
|
Initialize(pData^);
|
|
end;
|
|
|
|
procedure TX2UtStringHash.FreeNode;
|
|
var
|
|
pData: PString;
|
|
|
|
begin
|
|
pData := GetNodeData(ANode);
|
|
Finalize(pData^);
|
|
|
|
inherited;
|
|
end;
|
|
|
|
|
|
function TX2UtStringHash.GetCurrentValue;
|
|
var
|
|
pData: PString;
|
|
|
|
begin
|
|
if ValidCursor() then
|
|
Result := PString(GetNodeData(Cursor))^;
|
|
end;
|
|
|
|
end.
|