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
80static void** vt_hashtable2_search(
void* obj,
const void* key) {
return hashtable2_search(obj, key); }
84static size_t vt_hashtable2_count(
const void* obj) {
return hashtable2_count(obj); }
85static bool vt_hashtable2_verify(
const void* obj) {
return hashtable2_verify(obj); }
91static bool vt_hashtable2_itor_nextn(
void* itor,
size_t count) {
return hashtable2_itor_nextn(itor, count); }
92static bool vt_hashtable2_itor_prevn(
void* itor,
size_t count) {
return hashtable2_itor_prevn(itor, count); }
95static void* vt_hashtable2_itor_key(
void* itor) {
return dict_unconst(
hashtable2_itor_key(itor)); }
97static bool vt_hashtable2_itor_search(
void* itor,
const void* key) {
return hashtable2_itor_search(itor, key); }
102 vt_hashtable2_dict_itor_new,
104 vt_hashtable2_insert,
105 vt_hashtable2_search,
110 vt_hashtable2_remove,
112 vt_hashtable2_traverse,
115 vt_hashtable2_verify,
119 vt_hashtable2_itor_free,
120 vt_hashtable2_itor_valid,
121 vt_hashtable2_itor_invalidate,
122 vt_hashtable2_itor_next,
123 vt_hashtable2_itor_prev,
124 vt_hashtable2_itor_nextn,
125 vt_hashtable2_itor_prevn,
126 vt_hashtable2_itor_first,
127 vt_hashtable2_itor_last,
128 vt_hashtable2_itor_key,
129 vt_hashtable2_itor_datum,
130 vt_hashtable2_itor_search,
135 vt_hashtable2_itor_remove,
143 ASSERT(hash_func != NULL);
167 ASSERT(hash_func != NULL);
177 dct->
_vtable = &hashtable2_vtable;
193insert(
hashtable2* table,
void *key,
unsigned hash)
209 if (++node == table_end)
211 }
while (node != first);
216static inline unsigned
219 const unsigned hash = hash_func(key);
220 return hash ? hash : ~(unsigned)0;
237 const unsigned hash = nonzero_hash(table->
hash_func, key);
247 const unsigned hash = nonzero_hash(table->
hash_func, key);
258 if (++node == table_end)
260 }
while (node != first);
269 const unsigned hash = node->
hash;
273 void*
const datum = node->
datum;
283 if (++node == table_end)
285 }
while (node != first);
297 if (++node == table->
table + table->
size)
299 remove_cleanup(table, first, node);
305 const unsigned hash = nonzero_hash(table->
hash_func, key);
315 remove_node(table, first, node);
322 if (++node == table_end)
324 }
while (node != first);
333 for (; node != end; ++node) {
335 if (delete_func) delete_func(node->
key, node->
datum);
341 const size_t count = table->
count;
355 if (!visit(node->
key, node->
datum, user_data))
break;
385 if (table->
size == new_size)
388 if (table->
count > new_size) {
393 const unsigned old_size = table->
size;
394 const size_t old_count = table->
count;
399 table->
table = old_table;
403 table->
size = new_size;
405 for (
unsigned i = 0; i < old_size; ++i) {
406 if (old_table[i].hash) {
408 insert(table, old_table[i].key, old_table[i].hash);
411 table->
table = old_table;
412 table->
size = old_size;
413 table->
count = old_count;
430 for (; node != end; ++node) {
462 itor->
_vtable = &hashtable2_itor_vtable;
485 if (itor->
slot >= 0 && itor_stale(itor))
487 return itor->
slot >= 0;
493 if (itor->
slot < 0 || itor_stale(itor))
509 if (!itor_check(itor))
523 if (!itor_check(itor))
526 while (itor->
slot-- > 0) {
540 return itor_check(itor);
549 return itor_check(itor);
556 for (
unsigned slot = 0; slot < itor->
table->
size; ++slot) {
558 itor->
slot = (int) slot;
570 for (
unsigned slot = itor->
table->
size; slot > 0;) {
572 itor->
slot = (int) slot;
585 const unsigned truncated_hash = hash % itor->
table->
size;
586 unsigned index = truncated_hash;
592 itor->
slot = (int) index;
597 }
while (index != truncated_hash);
617 if (!itor_check(itor))
619 remove_node(itor->
table,
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.
bool hashtable2_verify(const hashtable2 *table)
Check the internal invariants of the table and return true if they hold, or print the first failed ch...
hashtable2_itor * hashtable2_itor_new(hashtable2 *table)
Create an iterator over |table| that is not positioned on any element yet.
dict_itor * hashtable2_dict_itor_new(hashtable2 *table)
Like hashtable2_itor_new(), but wrapped in a generic dict_itor for use with the dict_itor_* macros.
void ** hashtable2_search(hashtable2 *table, const void *key)
Return the address of the datum stored for |key|, or NULL if |key| is not present.
bool hashtable2_itor_nextn(hashtable2_itor *itor, size_t count)
Move |itor| |count| elements forward and return whether it is still positioned.
#define LOADFACTOR_NUMERATOR
size_t hashtable2_free(hashtable2 *table, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL,...
bool hashtable2_itor_valid(const hashtable2_itor *itor)
Return whether |itor| is positioned on an element.
bool hashtable2_itor_prev(hashtable2_itor *itor)
Move |itor| to the previous element in table order (unspecified) and return true, or unposition it an...
void ** hashtable2_itor_datum(hashtable2_itor *itor)
Return the address of the datum |itor| is positioned on, through which it can be read or replaced,...
bool hashtable2_itor_remove(hashtable2_itor *itor)
Remove the element |itor| is positioned on and unposition |itor|; return false if it was not position...
size_t hashtable2_clear(hashtable2 *table, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL.
#define LOADFACTOR_DENOMINATOR
dict_insert_result hashtable2_insert(hashtable2 *table, void *key)
Insert |key| unless an equal key is present.
void hashtable2_itor_invalidate(hashtable2_itor *itor)
Unposition |itor|, so that it is not positioned on any element.
hashtable2 * hashtable2_new(dict_compare_func cmp_func, dict_hash_func hash_func, unsigned initial_size)
Create an empty hash table that compares keys with |cmp_func| and hashes them with |hash_func| (neith...
size_t hashtable2_count(const hashtable2 *table)
Return the number of elements.
size_t hashtable2_slots_used(const hashtable2 *table)
Return the number of occupied slots, which for open addressing equals the number of elements.
size_t hashtable2_size(const hashtable2 *table)
Return the current number of slots in the table.
void hashtable2_itor_free(hashtable2_itor *itor)
Free an iterator.
bool hashtable2_resize(hashtable2 *table, unsigned new_size)
Rehash the table into at least |size| slots, rounded up as in hashtable2_new().
bool hashtable2_itor_prevn(hashtable2_itor *itor, size_t count)
Move |itor| |count| elements back and return whether it is still positioned.
bool hashtable2_itor_first(hashtable2_itor *itor)
Position |itor| on the first element in table order (unspecified) and return true,...
const void * hashtable2_itor_key(const hashtable2_itor *itor)
Return the key |itor| is positioned on, or NULL if it is not positioned.
bool hashtable2_itor_next(hashtable2_itor *itor)
Move |itor| to the next element in table order (unspecified) and return true, or unposition it and re...
dict_remove_result hashtable2_remove(hashtable2 *table, const void *key)
Remove the element with key |key|.
size_t hashtable2_traverse(hashtable2 *table, dict_visit_func visit, void *user_data)
Call |visit|(key, datum, |user_data|) for each element in table order (unspecified),...
bool hashtable2_itor_search(hashtable2_itor *itor, const void *key)
Position |itor| on |key| and return true, or unposition it and return false if |key| is not present.
bool hashtable2_itor_last(hashtable2_itor *itor)
Position |itor| on the last element in table order (unspecified) and return true, or unposition it an...
dict * hashtable2_dict_new(dict_compare_func cmp_func, dict_hash_func hash_func, unsigned initial_size)
Like hashtable2_new(), but wrapped in a generic dict for use with the dict_* macros.
Hash table with open addressing and linear probing.
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