Fixed bugs in the Knight shared files (not that these are used in SM).
2 #include <KeHashTable.h>
4 using namespace Knight;
23 KeHashGenerator key_gen;
26 ke_allocator_t *node_alloc;
31 KeHashNode *free_list;
36 void *ke_DefHashMalloc(ke_allocator_t *alloc, size_t amt)
41 void ke_DefHashFree(ke_allocator_t *alloc, void *addr)
46 ke_allocator_t s_DefHashAllocator =
53 KeHashTable *Knight::KE_CreateHashTable(
55 KeHashGenerator key_gen,
56 const KeHashMarshal *key_marshal,
57 const KeHashMarshal *val_marshal,
58 ke_allocator_t *nodeAlloc,
72 /* Validate marshals. */
73 if ((key_marshal->bytes != 0
74 && key_marshal->ctor == NULL)
75 || (val_marshal->bytes != 0
76 && val_marshal->ctor == NULL))
81 table = new KeHashTable;
82 table->key_gen = key_gen;
83 table->key_m = *key_marshal;
84 table->val_m = *val_marshal;
85 table->num_entries = 0;
86 table->shift = 32 - bits;
87 table->node_alloc = nodeAlloc == NULL ? &s_DefHashAllocator : nodeAlloc;
88 table->num_buckets = (1 << bits);
89 table->grow_limit = (uint32_t)(0.9f * table->num_buckets);
90 table->keep_free_list = keep_free_list;
91 table->free_list = NULL;
92 table->buckets = (KeHashNode **)malloc(sizeof(KeHashNode *) * table->num_buckets);
93 memset(table->buckets, 0, sizeof(KeHashNode *) * table->num_buckets);
95 table->key_offs = sizeof(KeHashNode);
96 if (table->key_m.bytes != 0 && table->key_m.bytes % 8 != 0)
98 table->key_m.bytes += 8;
99 table->key_m.bytes -= (table->key_m.bytes % 8);
102 table->val_offs = table->key_offs + table->key_m.bytes;
103 table->node_size = table->val_offs + table->val_m.bytes;
108 #define KE_GET_BUCKET(tbl, hsh) (&(tbl)->buckets[((hsh) * 0x9E3779B9) >> (tbl)->shift])
110 KeHashNode **ke_HashInternalFind(KeHashTable *table, uint32_t key_hash, const void *key)
115 bucket = KE_GET_BUCKET(table, key_hash);
117 /* :TODO: move to the front once found? */
119 while ((node = *bucket) != NULL)
121 if (node->key_hash == key_hash
122 && ((table->key_m.cmp != NULL && table->key_m.cmp(node->key, key))
123 || node->key == key))
127 bucket = &node->next;
133 void ke_ResizeHashTable(KeHashTable *table, uint32_t new_shift)
138 KeHashNode **rbucket;
139 KeHashNode **old_buckets;
140 uint32_t old_num_buckets;
143 old_num_buckets = table->num_buckets;
144 old_buckets = table->buckets;
145 entries = table->num_entries;
148 table->num_buckets = (1 << new_shift);
149 table->shift = 32 - new_shift;
150 table->grow_limit = (uint32_t)(0.9f * table->num_buckets);
152 table->buckets = (KeHashNode **)malloc(sizeof(KeHashNode *) * table->num_buckets);
153 memset(table->buckets, 0, sizeof(KeHashNode *) * table->num_buckets);
155 /* For each old bucket... */
157 i < old_num_buckets && entries != 0;
160 node = old_buckets[i];
161 /* Get each item in its list... */
166 /* Find the new replacement bucket it needs to go in. */
167 rbucket = KE_GET_BUCKET(table, node->key_hash);
169 /* Link this node to the next node in the new bucket. */
170 if (*rbucket == NULL)
176 node->next = *rbucket;
179 /* Add us to the front of that bucket's list. */
189 void Knight::KE_AddToHashTable(KeHashTable *table, const void *key, void *val)
195 key_hash = table->key_gen(key);
196 bucket = ke_HashInternalFind(table, key_hash, key);
198 if ((node = *bucket) != NULL)
200 /* Already in the table */
201 if ((table->val_m.cmp != NULL && table->val_m.cmp(node->value, val))
202 || node->value == val)
207 /* Destroy old value if it's set. */
208 if (node->value != NULL && table->val_m.dtor != NULL)
210 table->val_m.dtor(node->value);
213 /* Construct or set the new value. */
214 if (table->val_m.bytes != 0)
216 table->val_m.ctor(node->value, val);
226 /* If we're overloaded, we may need to resize.
227 * Right now, we do this if we hit a .9 entry:buckets ratio.
229 if (table->num_entries >= table->grow_limit)
231 ke_ResizeHashTable(table, table->shift << 1);
232 bucket = ke_HashInternalFind(table, key_hash, key);
235 if (table->free_list != NULL)
237 node = table->free_list;
238 table->free_list = node->next;
242 node = (KeHashNode *)table->node_alloc->alloc(table->node_alloc, table->node_size);
245 if (table->key_m.bytes == 0)
251 node->key = (char *)node + table->key_offs;
252 table->key_m.ctor((void *)node->key, key);
255 if (table->val_m.bytes == 0)
261 node->value = (char *)node + table->val_offs;
262 table->val_m.ctor(node->value, val);
265 node->next = *bucket;
266 node->key_hash = key_hash;
270 inline void ke_CleanUpHashNode(KeHashTable *table, KeHashNode *node)
272 /* Destroy old value if it's set. */
273 if (node->value != NULL && table->val_m.dtor != NULL)
275 table->val_m.dtor(node->value);
278 /* Destroy the key. */
279 if (table->key_m.dtor != NULL)
281 table->key_m.dtor(node->key);
284 /* Deallocate us as appropriate. */
285 if (table->keep_free_list)
287 node->next = table->free_list;
288 table->free_list = node;
292 table->node_alloc->dealloc(table->node_alloc, node);
296 void Knight::KE_RemoveFromHashTable(KeHashTable *table, const void *key)
302 key_hash = table->key_gen(key);
303 bucket = ke_HashInternalFind(table, key_hash, key);
305 if ((node = *bucket) == NULL)
310 /* Link the bucket to its next (removing us). */
311 *bucket = node->next;
313 ke_CleanUpHashNode(table, node);
316 bool Knight::KE_FindInHashTable(KeHashTable *table, const void *key, void **value)
322 key_hash = table->key_gen(key);
323 bucket = ke_HashInternalFind(table, key_hash, key);
325 if ((node = *bucket) == NULL)
332 *value = node->value;
338 void Knight::KE_DestroyHashTable(KeHashTable *table)
340 KeHashNode *node, *next;
342 /* Turn off this caching! */
343 table->keep_free_list = false;
345 /* Find entries in buckets that need to be freed. */
346 for (uint32_t i = 0; i < table->num_buckets; i++)
348 node = table->buckets[i];
353 ke_CleanUpHashNode(table, node);
358 /* Free the free list */
359 while (table->free_list != NULL)
361 next = table->free_list->next;
362 ke_CleanUpHashNode(table, table->free_list);
363 table->free_list = next;
366 /* Destroy everything now. */
367 free(table->buckets);
371 void Knight::KE_ClearHashTable(KeHashTable *table)
373 KeHashNode *node, *next;
375 /* Free every entry in the table. */
376 for (uint32_t i = 0; i < table->num_buckets; i++)
378 node = table->buckets[i];
383 ke_CleanUpHashNode(table, node);
389 #if defined _MSC_VER && (defined _M_IX86 || defined _M_AMD64 || defined _M_X64)
390 #pragma intrinsic(_rotl)
393 uint32_t Knight::KE_HashString(const void *str)
396 const unsigned char *us;
400 for (us = (const unsigned char *)str; *us != 0; us++)
402 #if defined _MSC_VER && (defined _M_IX86 || defined _M_AMD64 || defined _M_X64)
403 h = _rotl(h, 4) ^ *us;
405 h = ((h << 4) | (h >> 28)) ^ *us;
412 bool Knight::KE_AreStringsEqual(const void* str1, const void* str2)
414 return (strcmp((const char*)str1, (const char*)str2) == 0) ? true : false;