int main(void) { size_t initcap = 10; HashTable *newht, *ht = hashtable_new(initcap); if (!ht) testfail("Could not create hash table!"); if (ht->items != 0) testfail("New hash table should be empty, instead has size %lu", ht->items); hashtable_put(ht, "Elvis", "Presley"); if (ht->items != 1) testfail("Hash table should have size 1 after put instead has size %lu", ht->items); expect_to_get(ht, "Elvis", "Presley"); hashtable_put(ht, "Elvis", "Costello"); if (ht->items != 1) testfail("Hash table should have remained size 1 after put instead has size %lu", ht->items); expect_to_get(ht, "Elvis", "Costello"); hashtable_put(ht, "Janis", "Joplin"); if (ht->items != 2) testfail("Hash table should have grown to size 2 after put instead has size %lu", ht->items); expect_to_get(ht, "Janis", "Joplin"); newht = hashtable_rehash(ht, 100); if (newht != ht) testfail("Expected hashtable instance to be the same; should not have changed!"); newht = hashtable_rehash(ht, 0); if (newht == ht) testfail("Expected hashtable instance to be the different; should have changed!"); ht = newht; if (newht->capacity <= initcap) testfail("Expected new hashtable to be larger than %lu, instead got %lu", initcap, newht->capacity); if (newht->items != 2) testfail("Expected 2 items in new hash table!"); expect_to_get(ht, "Elvis", "Costello"); expect_to_get(ht, "Janis", "Joplin"); hashtable_destroy(ht); return 0; }
static int _hashtable_pop_entry(_Py_hashtable_t *ht, const void *key, void *data, size_t data_size) { Py_uhash_t key_hash; size_t index; _Py_hashtable_entry_t *entry, *previous; key_hash = ht->hash_func(key); index = key_hash & (ht->num_buckets - 1); previous = NULL; for (entry = TABLE_HEAD(ht, index); entry != NULL; entry = ENTRY_NEXT(entry)) { if (entry->key_hash == key_hash && ht->compare_func(key, entry)) break; previous = entry; } if (entry == NULL) return 0; _Py_slist_remove(&ht->buckets[index], (_Py_slist_item_t *)previous, (_Py_slist_item_t *)entry); ht->entries--; if (data != NULL) _Py_HASHTABLE_ENTRY_READ_DATA(ht, data, data_size, entry); ht->alloc.free(entry); if ((float)ht->entries / (float)ht->num_buckets < HASHTABLE_LOW) hashtable_rehash(ht); return 1; }
/** * Inserts the data with the given hash into the table. * * Note that insertion may rearrange the table on a resize or rehash, * so previously found hash_entries are no longer valid after this function. */ int ht_insert2(ht_t *ht, uint64_t hash, void *data, uint32_t length) { uint64_t hash_address; if(length == 0 || length > ht->data_length) { return -1; } if(ht->entries >= ht->max_entries) { hashtable_rehash(ht, ht->size_index + 1); } else if(ht->deleted_entries + ht->entries >= ht->max_entries) { hashtable_rehash(ht, ht->size_index); } uint32_t element_size = sizeof(*ht->table) + ht->data_length; hash_address = hash % ht->size; do { ht_entry_t *entry = (ht_entry_t *)( (char *) ht->table + hash_address * element_size); if(!entry_is_present(entry)) { if(entry_is_deleted(entry)) { ht->deleted_entries--; } entry->hash = hash; entry->length = length; memcpy(entry->data, data, length); ht->entries++; return 0; } uint64_t double_hash = hash % ht->rehash; if(double_hash == 0) { double_hash = 1; } hash_address = (hash_address + double_hash) % ht->size; } while (hash_address != hash % ht->size); /* We could hit here if a required resize failed. An unchecked-malloc * application could ignore this result. */ return -1; }
void _Py_hashtable_clear(_Py_hashtable_t *ht) { _Py_hashtable_entry_t *entry, *next; size_t i; for (i=0; i < ht->num_buckets; i++) { for (entry = TABLE_HEAD(ht, i); entry != NULL; entry = next) { next = ENTRY_NEXT(entry); if (ht->free_data_func) ht->free_data_func(_Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(entry)); ht->alloc.free(entry); } _Py_slist_init(&ht->buckets[i]); } ht->entries = 0; hashtable_rehash(ht); }
/* Add a new entry to the hash. The key must not be present in the hash table. Return 0 on success, -1 on memory error. */ int _Py_hashtable_set(_Py_hashtable_t *ht, const void *key, void *data, size_t data_size) { Py_uhash_t key_hash; size_t index; _Py_hashtable_entry_t *entry; assert(data != NULL || data_size == 0); #ifndef NDEBUG /* Don't write the assertion on a single line because it is interesting to know the duplicated entry if the assertion failed. The entry can be read using a debugger. */ entry = _Py_hashtable_get_entry(ht, key); assert(entry == NULL); #endif key_hash = ht->hash_func(key); index = key_hash & (ht->num_buckets - 1); entry = ht->alloc.malloc(HASHTABLE_ITEM_SIZE(ht)); if (entry == NULL) { /* memory allocation failed */ return -1; } entry->key = (void *)key; entry->key_hash = key_hash; assert(data_size == ht->data_size); memcpy(_Py_HASHTABLE_ENTRY_DATA(entry), data, data_size); _Py_slist_prepend(&ht->buckets[index], (_Py_slist_item_t*)entry); ht->entries++; if ((float)ht->entries / (float)ht->num_buckets > HASHTABLE_HIGH) hashtable_rehash(ht); return 0; }