-
Notifications
You must be signed in to change notification settings - Fork 0
/
Uhashtable.pas
155 lines (129 loc) · 3.12 KB
/
Uhashtable.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
unit Uhashtable;
{$MODE objfpc}{$H+}
(*
* Hashtable Unit - unknown author
* Uses ELF hash algorithm to convert a string to a hash value
*
* RJO: Added collision detection - no handling, only warning.
*)
interface
type
PHashRec = ^THashRec;
THashRec = record
Next: PHashRec;
hash: int64;
index: integer;
end;
THashTable = class
table: PHashRec;
collisiondetection: boolean;
constructor Create;
function ELFHash(const Value: string): int64;
function DeleteHash(hash: int64): integer;
function InsertHash(hash: int64; index: integer): boolean;
// If false is returned a collision was detected
function GetStrIndex(element: string): integer;
function GetIndex(hash: int64): integer;
destructor Destroy; override;
end;
implementation
// Hash function: converts string to hash value
function THashTable.ELFHash(const Value: string): int64;
var
i: integer;
x: int64;
begin
Result := 0;
{$R-}// Range check off
for i := 1 to Length(Value) do
begin
Result := (Result shl 4) + Ord(Value[i]);
x := Result and $F0000000;
if (x <> 0) then
Result := Result xor (x shr 24);
Result := Result and (not x);
end;
{$R+}
end;
constructor THashTable.Create;
begin
inherited;
table := nil;
collisiondetection := True;
end;
// DeleteHash locates an element in the list, fixes the list pointers so
// that this element is no longer referenced, releases the memory for
// the element, and returns the element's index.
function THashTable.DeleteHash(hash: int64): integer;
var
P, Q: PHashRec;
begin
P := Table;
Q := nil;
while (P <> nil) and (P^.hash <> hash) do
begin
Q := P;
P := P^.Next;
end;
if P <> nil then
begin
Result := P^.index;
if Q = nil then
Table := P^.Next
else
Q^.Next := P^.Next;
Dispose(P);
end
else
Result := 0;
end;
// InsertHash adds an element to the head (beginning) of the list
// New(P) allocates memory on the stack
function THashTable.InsertHash(hash: int64; index: integer): boolean;
var
P: PHashRec;
begin
if collisiondetection then
Result := (GetIndex(hash) = -1) // Check if hash already is in table
else
Result := True;
New(P);
P^.Next := Table;
P^.hash := hash;
P^.index := index;
Table := P;
end;
function THashTable.GetStrIndex(element: string): integer;
begin
Result := GetIndex(ELFHash(element));
end;
// GetIndex walks the list using P := P^.Next
// Notice that hash does not refer to a position in the list,
// instead, it refers to a value stored in the list element (record of
// type THashRec)
function THashTable.GetIndex(hash: int64): integer;
var
P: PHashRec;
begin
P := Table;
while (P <> nil) and (P^.hash <> hash) do
P := P^.Next;
if P = nil then
Result := -1
else
Result := P^.index;
end;
destructor THashTable.Destroy;
var
P, Q: PHashRec;
begin
p := table;
while p <> nil do
begin
q := p^.Next;
dispose(p);
p := q;
end;
inherited;
end;
end.