39#define LOADFACTOR_NUMERATOR 2
40#define LOADFACTOR_DENOMINATOR 3
41#if LOADFACTOR_NUMERATOR > LOADFACTOR_DENOMINATOR
42# error LOADFACTOR_NUMERATOR must be less than LOADFACTOR_DENOMINATOR
84static void** vt_hashtable_search(
void* obj,
const void* key) {
return hashtable_search(obj, key); }
88static size_t vt_hashtable_count(
const void* obj) {
return hashtable_count(obj); }
89static bool vt_hashtable_verify(
const void* obj) {
return hashtable_verify(obj); }
95static bool vt_hashtable_itor_nextn(
void* itor,
size_t count) {
return hashtable_itor_nextn(itor, count); }
96static bool vt_hashtable_itor_prevn(
void* itor,
size_t count) {
return hashtable_itor_prevn(itor, count); }
99static void* vt_hashtable_itor_key(
void* itor) {
return dict_unconst(
hashtable_itor_key(itor)); }
101static bool vt_hashtable_itor_search(
void* itor,
const void* key) {
return hashtable_itor_search(itor, key); }
106 vt_hashtable_dict_itor_new,
116 vt_hashtable_traverse,
123 vt_hashtable_itor_free,
124 vt_hashtable_itor_valid,
125 vt_hashtable_itor_invalidate,
126 vt_hashtable_itor_next,
127 vt_hashtable_itor_prev,
128 vt_hashtable_itor_nextn,
129 vt_hashtable_itor_prevn,
130 vt_hashtable_itor_first,
131 vt_hashtable_itor_last,
132 vt_hashtable_itor_key,
133 vt_hashtable_itor_datum,
134 vt_hashtable_itor_search,
139 vt_hashtable_itor_remove,
147 ASSERT(hash_func != NULL);
171 ASSERT(hash_func != NULL);
181 dct->
_vtable = &hashtable_vtable;
209 const unsigned hash = table->
hash_func(key);
210 const unsigned mhash = hash % table->
size;
213 while (node && hash >= node->
hash) {
232 table->
table[mhash] = add;
245 const unsigned hash = table->
hash_func(key);
247 while (node && hash >= node->
hash) {
274 const unsigned hash = table->
hash_func(key);
275 const unsigned mhash = hash % table->
size;
278 while (node && hash >= node->
hash) {
281 remove_node(table, node, mhash);
292 for (
unsigned slot = 0; slot < table->
size; slot++) {
294 while (node != NULL) {
296 if (delete_func) delete_func(node->
key, node->
datum);
300 table->
table[slot] = NULL;
303 const size_t count = table->
count;
313 for (
unsigned i = 0; i < table->
size; i++) {
316 if (!visit(node->
key, node->
datum, user_data))
return count;
338 for (
unsigned i = 0; i < table->
size; i++)
350 if (table->
size == new_size)
return true;
354 if (!ntable)
return false;
356 memset(ntable, 0, new_size *
sizeof(
hash_node*));
358 for (
unsigned i = 0; i < table->
size; i++) {
361 const unsigned mhash = node->
hash % new_size;
364 while (search && node->
hash >= search->
hash) {
366 search = search->
next;
368 if ((node->next = search) != NULL)
370 if ((node->prev = prev) != NULL)
373 ntable[mhash] = node;
379 table->
table = ntable;
380 table->
size = new_size;
388 for (
unsigned slot = 0; slot < table->
size; ++slot) {
390 if (n == table->
table[slot]) {
394 VERIFY(n->prev->next == n);
397 VERIFY(n->next->prev == n);
398 VERIFY(n->hash <= n->next->hash);
428 itor->
_vtable = &hashtable_itor_vtable;
451 if (itor->
node && itor_stale(itor)) {
455 return itor->
node != NULL;
461 return itor->
node != NULL && !itor_stale(itor);
474 if (!itor_check(itor))
480 unsigned slot = itor->
slot;
481 while (++slot < itor->table->
size) {
496 if (!itor_check(itor))
502 unsigned slot = itor->
slot;
525 return itor_check(itor);
535 return itor_check(itor);
542 for (
unsigned slot = 0; slot < itor->
table->
size; ++slot) {
558 for (
unsigned slot = itor->
table->
size; slot > 0;) {
578 const unsigned mhash = hash % itor->
table->
size;
580 while (node && hash >= node->
hash) {
602 return itor_check(itor) ? &itor->
node->
datum : NULL;
608 if (!itor_check(itor))
int(* dict_compare_func)(const void *, const void *)
A pointer to a function that compares two keys.
void(* dict_delete_func)(void *, void *)
A pointer to a function that is called when a key-value pair gets removed from a dictionary.
unsigned(* dict_hash_func)(const void *)
A pointer to a function that returns the hash value of a key.
bool(* dict_visit_func)(const void *, void *, void *)
A pointer to a function used for iterating over dictionary contents.
size_t hashtable_free(hashtable *table, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL,...
#define LOADFACTOR_NUMERATOR
bool hashtable_itor_search(hashtable_itor *itor, const void *key)
Position |itor| on |key| and return true, or unposition it and return false if |key| is not present.
dict_remove_result hashtable_remove(hashtable *table, const void *key)
Remove the element with key |key|.
dict_itor * hashtable_dict_itor_new(hashtable *table)
Like hashtable_itor_new(), but wrapped in a generic dict_itor for use with the dict_itor_* macros.
hashtable_itor * hashtable_itor_new(hashtable *table)
Create an iterator over |table| that is not positioned on any element yet.
bool hashtable_verify(const hashtable *table)
Check the internal invariants of the table and return true if they hold, or print the first failed ch...
bool hashtable_itor_last(hashtable_itor *itor)
Position |itor| on the last element in table order (unspecified) and return true, or unposition it an...
bool hashtable_itor_next(hashtable_itor *itor)
Move |itor| to the next element in table order (unspecified) and return true, or unposition it and re...
bool hashtable_itor_first(hashtable_itor *itor)
Position |itor| on the first element in table order (unspecified) and return true,...
size_t hashtable_count(const hashtable *table)
Return the number of elements.
bool hashtable_itor_prevn(hashtable_itor *itor, size_t count)
Move |itor| |count| elements back and return whether it is still positioned.
#define LOADFACTOR_DENOMINATOR
dict_insert_result hashtable_insert(hashtable *table, void *key)
Insert |key| unless an equal key is present.
void ** hashtable_itor_datum(hashtable_itor *itor)
Return the address of the datum |itor| is positioned on, through which it can be read or replaced,...
bool hashtable_itor_remove(hashtable_itor *itor)
Remove the element |itor| is positioned on and unposition |itor|; return false if it was not position...
void hashtable_itor_free(hashtable_itor *itor)
Free an iterator.
bool hashtable_resize(hashtable *table, unsigned new_size)
Rehash the table into at least |size| slots, rounded up as in hashtable_new().
bool hashtable_itor_nextn(hashtable_itor *itor, size_t count)
Move |itor| |count| elements forward and return whether it is still positioned.
size_t hashtable_clear(hashtable *table, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL.
bool hashtable_itor_prev(hashtable_itor *itor)
Move |itor| to the previous element in table order (unspecified) and return true, or unposition it an...
void hashtable_itor_invalidate(hashtable_itor *itor)
Unposition |itor|, so that it is not positioned on any element.
size_t hashtable_traverse(hashtable *table, dict_visit_func visit, void *user_data)
Call |visit|(key, datum, |user_data|) for each element in table order (unspecified),...
dict * hashtable_dict_new(dict_compare_func cmp_func, dict_hash_func hash_func, unsigned size)
Like hashtable_new(), but wrapped in a generic dict for use with the dict_* macros.
bool hashtable_itor_valid(const hashtable_itor *itor)
Return whether |itor| is positioned on an element.
void ** hashtable_search(hashtable *table, const void *key)
Return the address of the datum stored for |key|, or NULL if |key| is not present.
size_t hashtable_size(const hashtable *table)
Return the current number of slots in the table.
size_t hashtable_slots_used(const hashtable *table)
Return the number of slots whose chain is not empty.
const void * hashtable_itor_key(const hashtable_itor *itor)
Return the key |itor| is positioned on, or NULL if it is not positioned.
hashtable * hashtable_new(dict_compare_func cmp_func, dict_hash_func hash_func, unsigned size)
Create an empty hash table that compares keys with |cmp_func| and hashes them with |hash_func| (neith...
Hash table with separate chaining; each chain is kept sorted by hash value.
unsigned dict_prime_geq(unsigned n)
const itor_vtable * _vtable
The operations of one container type.
const dict_vtable * _vtable
dict_compare_func cmp_func