/* Replace an entry from the hash table. The entry is returned, or NULL if it wasn't found */ void *ght_replace(ght_hash_table_t *p_ht, void *p_entry_data, unsigned int i_key_size, const void *p_key_data) { ght_hash_entry_t *p_e; ght_hash_key_t key; ght_uint32_t l_key; void *p_old; DEBUG_ASSERT(p_ht); hk_fill(&key, i_key_size, p_key_data); l_key = get_hash_value(p_ht, &key) & p_ht->i_size_mask; /* Check that the first element in the list really is the first. */ DEBUG_ASSERT( p_ht->pp_entries[l_key]?p_ht->pp_entries[l_key]->p_prev == NULL:1 ); /* LOCK: p_ht->pp_entries[l_key] */ p_e = search_in_bucket(p_ht, l_key, &key, (unsigned char)p_ht->i_heuristics); /* UNLOCK: p_ht->pp_entries[l_key] */ if ( !p_e ) return NULL; p_old = p_e->p_data; p_e->p_data = p_entry_data; return p_old; }
/* Remove an entry from the hash table. The removed entry, or NULL, is returned (and NOT free'd). */ void *ght_remove(ght_hash_table_t *p_ht, unsigned int i_key_size, const void *p_key_data) { ght_hash_entry_t *p_out; ght_hash_key_t key; ght_uint32_t l_key; void *p_ret=NULL; DEBUG_ASSERT(p_ht); hk_fill(&key, i_key_size, p_key_data); l_key = get_hash_value(p_ht, &key) & p_ht->i_size_mask; /* Check that the first element really is the first */ DEBUG_ASSERT( (p_ht->pp_entries[l_key]?p_ht->pp_entries[l_key]->p_prev == NULL:1) ); /* LOCK: p_ht->pp_entries[l_key] */ p_out = search_in_bucket(p_ht, l_key, &key, 0); /* Link p_out out of the list. */ if (p_out) { remove_from_chain(p_ht, l_key, p_out); /* This should ONLY be done for normal items (for now all items) */ p_ht->i_items--; p_ht->p_nr[l_key]--; /* UNLOCK: p_ht->pp_entries[l_key] */ #if !defined(NDEBUG) p_out->p_next = NULL; p_out->p_prev = NULL; #endif /* NDEBUG */ p_ret = p_out->p_data; he_finalize(p_ht, p_out); } /* else: UNLOCK: p_ht->pp_entries[l_key] */ return p_ret; }
/* Get an entry from the hash table. The entry is returned, or NULL if it wasn't found */ void *ght_get(ght_hash_table_t *p_ht, unsigned int i_key_size, const void *p_key_data) { ght_hash_entry_t *p_e; ght_hash_key_t key; ght_uint32_t l_key; assert(p_ht); hk_fill(&key, i_key_size, p_key_data); l_key = get_hash_value(p_ht, &key) & p_ht->i_size_mask; /* Check that the first element in the list really is the first. */ assert( p_ht->pp_entries[l_key]?p_ht->pp_entries[l_key]->p_prev == NULL:1 ); /* LOCK: p_ht->pp_entries[l_key] */ p_e = search_in_bucket(p_ht, l_key, &key, p_ht->i_heuristics); /* UNLOCK: p_ht->pp_entries[l_key] */ return (p_e?p_e->p_data:NULL); }
/* Insert an entry into the hash table */ int ght_insert(ght_hash_table_t *p_ht, void *p_entry_data, unsigned int i_key_size, const void *p_key_data) { ght_hash_entry_t *p_entry; ght_uint32_t l_key; ght_hash_key_t key; DEBUG_ASSERT(p_ht); hk_fill(&key, i_key_size, p_key_data); l_key = get_hash_value(p_ht, &key) & p_ht->i_size_mask; if (search_in_bucket(p_ht, l_key, &key, 0)) { /* Don't insert if the key is already present. */ return -1; } p_entry = he_create(p_ht, p_entry_data, i_key_size, p_key_data); if (!(p_entry)) { return -2; } /* Rehash if the number of items inserted is too high. */ if (p_ht->i_automatic_rehash && p_ht->i_items > 2*p_ht->i_size) { ght_rehash(p_ht, 2*p_ht->i_size); /* Recalculate l_key after ght_rehash has updated i_size_mask */ l_key = get_hash_value(p_ht, &key) & p_ht->i_size_mask; } /* Place the entry first in the list. */ p_entry->p_next = p_ht->pp_entries[l_key]; p_entry->p_prev = NULL; if (p_ht->pp_entries[l_key]) { p_ht->pp_entries[l_key]->p_prev = p_entry; } p_ht->pp_entries[l_key] = p_entry; /* If this is a limited bucket hash table, potentially remove the last item */ if (p_ht->bucket_limit != 0 && p_ht->p_nr[l_key] >= p_ht->bucket_limit) { ght_hash_entry_t *p; /* Loop through entries until the last * * FIXME: Better with a pointer to the last entry */ for (p = p_ht->pp_entries[l_key]; p->p_next != NULL; p = p->p_next); DEBUG_ASSERT(p && p->p_next == NULL); remove_from_chain(p_ht, l_key, p); /* To allow it to be reinserted in fn_bucket_free */ p_ht->fn_bucket_free(p->p_data, p->key.p_key); he_finalize(p_ht, p); } else { p_ht->p_nr[l_key]++; DEBUG_ASSERT( p_ht->pp_entries[l_key]?p_ht->pp_entries[l_key]->p_prev == NULL:1 ); p_ht->i_items++; } if (p_ht->p_oldest == NULL) { p_ht->p_oldest = p_entry; } p_entry->p_older = p_ht->p_newest; if (p_ht->p_newest != NULL) { p_ht->p_newest->p_newer = p_entry; } p_ht->p_newest = p_entry; return 0; }