* free to avoid exponential performance degradation as the hash table fills
*/
-uint32_t deleted_key_value;
-const void *deleted_key = &deleted_key_value;
+static const uint32_t deleted_key_value;
+static const void *deleted_key = &deleted_key_value;
static const struct {
uint32_t max_entries, size, rehash;
set_add(struct set *ht, uint32_t hash, const void *key);
static void
-set_rehash(struct set *ht, int new_size_index)
+set_rehash(struct set *ht, unsigned new_size_index)
{
struct set old_ht;
struct set_entry *table, *entry;
set_add(struct set *ht, uint32_t hash, const void *key)
{
uint32_t hash_address;
+ struct set_entry *available_entry = NULL;
if (ht->entries >= ht->max_entries) {
set_rehash(ht, ht->size_index + 1);
uint32_t double_hash;
if (!entry_is_present(entry)) {
- if (entry_is_deleted(entry))
- ht->deleted_entries--;
- entry->hash = hash;
- entry->key = key;
- ht->entries++;
- return entry;
+ /* Stash the first available entry we find */
+ if (available_entry == NULL)
+ available_entry = entry;
+ if (entry_is_free(entry))
+ break;
}
/* Implement replacement when another insert happens
* If freeing of old keys is required to avoid memory leaks,
* perform a search before inserting.
*/
- if (entry->hash == hash &&
+ if (!entry_is_deleted(entry) &&
+ entry->hash == hash &&
ht->key_equals_function(key, entry->key)) {
entry->key = key;
return entry;
hash_address = (hash_address + double_hash) % ht->size;
} while (hash_address != hash % ht->size);
+ if (available_entry) {
+ if (entry_is_deleted(available_entry))
+ ht->deleted_entries--;
+ available_entry->hash = hash;
+ available_entry->key = key;
+ ht->entries++;
+ return available_entry;
+ }
+
/* We could hit here if a required resize failed. An unchecked-malloc
* application could ignore this result.
*/