Tiberian Technologies Scripts Reference Revision: 9000
Loading...
Searching...
No Matches
HashTemplateClass.h
1/* Renegade Scripts.dll
2 Copyright 2013 Tiberian Technologies
3
4 This file is part of the Renegade scripts.dll
5 The Renegade scripts.dll is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2, or (at your option) any later
8 version. See the file COPYING for more details.
9 In addition, an exemption is given to allow Run Time Dynamic Linking of this code with any closed source module that does not contain code covered by this licence.
10 Only the source code to the module(s) containing the licenced code has to be released.
11*/
12#ifndef TT_INCLUDE__HASHTEMPLATECLASS_H
13#define TT_INCLUDE__HASHTEMPLATECLASS_H
14
15
16
17#include "HashTemplateKeyClass.h"
18#include "engine_math.h"
19
20
21template<typename Key, typename Value> class HashTemplateIterator;
22
23
24
25template<typename Key, typename Value> class HashTemplateClass
26{
27
28private:
29
30 friend HashTemplateIterator<Key, Value>;
31
32 struct Entry
33 {
34 int next;
35 Key key;
36 Value value;
37 };
38
39 int* indices; // 0000
40 Entry* entries; // 0004
41 int unusedEntryIndex; // 0008
42 uint maxHashCount; // 000C
43
44
45
46 static uint computeHash(const Key& key, uint maxHashCount)
47 {
48 TT_ASSERT(isPowerOfTwo(maxHashCount)); // Make sure maxHashCount is a power of two, or the fast modulo code below will not work
49 return HashTemplateKeyClass<Key>::Get_Hash_Value(key) & (maxHashCount - 1);
50 }
51
52
53
54 uint computeHash(const Key& key) const
55 {
56 return computeHash(key, maxHashCount);
57 }
58
59
60
61 void Re_Hash()
62 {
63 uint newMaxHashCount = max(maxHashCount * 2, 4); // Increase the size and make sure there are at least 4 entries.
64
65 Entry* newEntries = new Entry[newMaxHashCount];
66 int* newIndices = new int[newMaxHashCount];
67 unusedEntryIndex = 0;
68
69 for (uint index = 0; index < newMaxHashCount; index++)
70 newIndices[index] = -1;
71
72 for (uint hash = 0; hash < maxHashCount; hash++)
73 {
74 for (int index = indices[hash]; index != -1; index = entries[index].next)
75 {
76 uint hash2 = computeHash(entries[index].key, newMaxHashCount);
77
78 newEntries[unusedEntryIndex].next = newIndices[hash2];
79 newEntries[unusedEntryIndex].key = entries[index].key;
80 newEntries[unusedEntryIndex].value = entries[index].value;
81
82 newIndices[hash2] = unusedEntryIndex;
83 unusedEntryIndex++;
84 }
85 }
86
87 delete[] indices;
88 delete[] entries;
89
90 for (uint i = unusedEntryIndex; i < newMaxHashCount-1; i++)
91 newEntries[i].next = i + 1;
92
93 newEntries[newMaxHashCount-1].next = -1;
94
95 indices = newIndices;
96 entries = newEntries;
97 maxHashCount = newMaxHashCount;
98 }
99
100
101
102public:
103
104
105
106 HashTemplateClass()
107 {
108 indices = NULL;
109 entries = NULL;
110 unusedEntryIndex = -1;
111 maxHashCount = 0;
112 }
113
114
115
116 HashTemplateClass(const HashTemplateClass& o) : unusedEntryIndex(o.unusedEntryIndex), maxHashCount(o.maxHashCount)
117 {
118 if (o.indices)
119 {
120 indices = new int[o.maxHashCount];
121 memcpy(indices, o.indices, sizeof(int) * o.maxHashCount);
122 }
123 else
124 {
125 indices = NULL;
126 }
127
128 if (o.entries)
129 {
130 entries = new Entry[o.maxHashCount];
131 memcpy(entries, o.entries, sizeof(Entry) * o.maxHashCount);
132 }
133 else
134 {
135 entries = NULL;
136 }
137 }
138
139
140 HashTemplateClass& operator= (const HashTemplateClass& o)
141 {
142 if (this == &o)
143 return *this;
144
145 delete[] indices;
146 delete[] entries;
147 unusedEntryIndex = o.unusedEntryIndex;
148 maxHashCount = o.maxHashCount;
149
150 if (o.indices)
151 {
152 indices = new int[o.maxHashCount];
153 memcpy(indices, o.indices, sizeof(int) * o.maxHashCount);
154 }
155 else
156 {
157 indices = NULL;
158 }
159
160 if (o.entries)
161 {
162 entries = new Entry[o.maxHashCount];
163 memcpy(entries, o.entries, sizeof(Entry) * o.maxHashCount);
164 }
165 else
166 {
167 entries = NULL;
168 }
169
170 return *this;
171 }
172
173
174 ~HashTemplateClass()
175 {
176 delete[] indices;
177 delete[] entries;
178 }
179
180
181
182 Value* Get(const Key& key) const
183 {
184 if (indices)
185 for (uint index = indices[computeHash(key)]; index != -1; index = entries[index].next)
186 if (entries[index].key == key)
187 return &entries[index].value;
188
189 return NULL;
190 }
191
192
193
194 Value Get(const Key& key, Value default) const
195 {
196 Value* result = Get(key);
197 return result ? *result : default;
198 }
199
200
201
202 bool Exists(const Key& key) const
203 {
204 return Get(key) != NULL;
205 }
206
207
208
209 void Insert(const Key& key, const Value& value)
210 {
211 // If all entries are in use, enlarge the table
212 if (unusedEntryIndex == -1)
213 Re_Hash();
214
215 uint index = unusedEntryIndex;
216 unusedEntryIndex = entries[index].next;
217
218 uint hash = computeHash(key);
219 entries[index].key = key;
220 entries[index].value = value;
221 entries[index].next = indices[hash];
222 indices[hash] = index;
223 }
224
225
226
227 void Remove(const Key& key)
228 {
229 if (indices)
230 {
231 uint hash = computeHash(key);
232 int* lastEntryNext = &indices[hash];
233
234 for (uint index = indices[hash]; index != -1; index = entries[index].next)
235 {
236 Entry& entry = entries[index];
237 if (entry.key == key)
238 {
239 *lastEntryNext = entry.next;
240 entries[index].next = unusedEntryIndex;
241 unusedEntryIndex = index;
242
243 break;
244 }
245
246 lastEntryNext = &entries[index].next;
247 }
248 }
249 }
250
251
252
253 // Remove if keys and values match
254 void Remove(const Key& key, const Value& value)
255 {
256 if (indices)
257 {
258 uint hash = computeHash(key);
259 int* lastEntryNext = &indices[hash];
260
261 for (uint index = indices[hash]; index != -1; index = entries[index].next)
262 {
263 Entry& entry = entries[index];
264 if (entry.key == key && entry.value == value)
265 {
266 *lastEntryNext = entry.next;
267 entries[index].next = unusedEntryIndex;
268 unusedEntryIndex = index;
269
270 break;
271 }
272
273 lastEntryNext = &entries[index].next;
274 }
275 }
276 }
277
278
279
280 void Remove_All()
281 {
282 for (uint hash = 0; hash < maxHashCount; hash++)
283 {
284 uint index = indices[hash];
285 if (index != -1)
286 {
287 uint lastHash = index;
288 while (entries[lastHash].next != -1)
289 lastHash = entries[lastHash].next;
290
291 entries[lastHash].next = unusedEntryIndex;
292 unusedEntryIndex = index;
293 indices[hash] = -1;
294 }
295 }
296 }
297
298
299
300 uint Get_Size() const
301 {
302 uint result = 0;
303
304 for (uint hash = 0; hash < maxHashCount; hash++)
305 {
306 uint index = indices[hash];
307 while (index != -1)
308 {
309 ++result;
310 index = entries[index].next;
311 }
312 }
313
314 return result;
315 }
316
317 const Value getValueByIndex(int index) const
318 {
319 Value value = entries[index].value;
320 return value;
321 }
322
323 void _validate()
324 {
325 for (uint hash = 0; hash < maxHashCount; hash++)
326 {
327 uint index = indices[hash];
328 while (index != -1)
329 {
330 TT_ASSERT(computeHash(entries[index].key) == hash);
331 index = entries[index].next;
332 }
333 }
334 }
335
336
337
338 static void _test()
339 {
340 HashTemplateClass<uint, uint> table;
341
342 for (uint run = 0; run < 10; run++)
343 {
344 bool bits[1234];
345 for (uint i = 0; i < 1234; i++)
346 {
347 bits[i] = rand() > (RAND_MAX & 1);
348 if (bits[i])
349 table.Insert(i*45, i*2+5678);
350 }
351
352 for (uint i = 0; i < 1234; i++)
353 {
354 TT_ASSERT(bits[i] == table.Exists(i*45));
355 if (bits[i])
356 TT_ASSERT(*table.Get(i*45) == i*2+5678);
357 }
358
359 for (uint i = 0; i < 1234/2; i++)
360 {
361 if (rand() > (RAND_MAX & 1))
362 {
363 bits[i] = !bits[i];
364 if (bits[i])
365 table.Insert(i*45, i*2+5678);
366 else
367 table.Remove(i*45);
368 }
369 }
370
371 for (uint i = 0; i < 1234; i++)
372 {
373 TT_ASSERT(bits[i] == table.Exists(i*45));
374 if (bits[i])
375 TT_ASSERT(*table.Get(i*45) == i*2+5678);
376 }
377
378 table.Remove_All();
379
380 for (uint i = 0; i < 1234; i++)
381 TT_ASSERT(table.Exists(i*45) == false);
382 }
383
384 TT_INTERRUPT; // Test success.
385 }
386
387}; // 0010
388
389
390
391#endif