From 12035d66a1dab59ae3b5178674f2481f67ccfc4a Mon Sep 17 00:00:00 2001 From: Dan Hirsch <thequux@thequux.com> Date: Mon, 8 Oct 2012 19:20:36 +0200 Subject: [PATCH] Added hashtable implementation --- src/datastructures.c | 114 +++++++++++++++++++++++++++++++++++++++++++ src/internal.h | 27 ++++++++++ 2 files changed, 141 insertions(+) diff --git a/src/datastructures.c b/src/datastructures.c index e7552e57..00db7448 100644 --- a/src/datastructures.c +++ b/src/datastructures.c @@ -63,3 +63,117 @@ void h_slist_free(HSlist *slist) { h_slist_pop(slist); h_arena_free(slist->arena, slist); } + +//////////////////////////////////////////////////////////////// + +HHashTable* h_hashtable_new(HArena *arena) { + HHashTable *ht = h_arena_malloc(arena, sizeof(HHashTable*)); + ht->hashFunc = hashFunc; + ht->equalFunc = equalFunc; + ht->capacity = 64; // to start; should be tuned later... + ht->used = 0; + ht->contents = h_arena_malloc(arena, sizeof(HHashTableEntry) * ht->capacity); + memset(ht->contents, sizeof(HHashTableEntry) * ht->capacity); + return ht; +} + +void* h_hashtable_get(HHashTable* ht, void* key) { + HHashValue hashval = ht->hashFunc(key); +#ifdef CONSISTENCY_CHECK + assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2 +#endif + + for (HHashTableEntry *hte = &ht->contents[hashval & (ht->capacity - 1)]; + hte != NULL; + hte = hte->next) { + if (hte->hashval != hashval) + continue; + if (ht->equalFunc(key, hte->key)) + return hte->value; + } + return NULL; +} + +void h_hashtable_put(HHashTable* ht, void* key, void* value) { + // # Start with a rebalancing + h_hashtable_ensure_capacity(ht, ht->used + 1); + + HHashValue hashval = ht->hashFunc(key); +#ifdef CONSISTENCY_CHECK + assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2 +#endif + + hte = &ht->contents[hashval & (ht->capacity - 1)]; + if (hte->key != NULL) { + do { + if (hte->hashval == hashval && ht->equalFunc(key, hte->key)) + goto insert_here; + } while (hte->next); + // Add a new link... + assert (hte->next == NULL); + hte->next = h_arena_malloc(ht->arena, sizeof(HHashTableEntry)); + hte = hte->next; + hte->next = NULL; + } + + insert_here: + hte->key = key; + hte->value = value; + hte->hashval = hashval; +} + +int h_hashtable_present(HHashTable* ht, void* key) { + HHashValue hashval = ht->hashFunc(key); +#ifdef CONSISTENCY_CHECK + assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2 +#endif + + for (HHashTableEntry *hte = &ht->contents[hashval & (ht->capacity - 1)]; + hte != NULL; + hte = hte->next) { + if (hte->hashval != hashval) + continue; + if (ht->equalFunc(key, hte->key)) + return true; + } + return false; +} +void h_hashtable_del(HHashTable* ht, void* key) { + HHashValue hashval = ht->hashFunc(key); +#ifdef CONSISTENCY_CHECK + assert((ht->capacity & (ht->capacity - 1)) == 0); // capacity is a power of 2 +#endif + + for (HHashTableEntry *hte = &ht->contents[hashval & (ht->capacity - 1)]; + hte != NULL; + hte = hte->next) { + if (hte->hashval != hashval) + continue; + if (ht->equalFunc(key, hte->key)) { + // FIXME: Leaks keys and values. + HHashTableEntry* hten = hte->next; + if (hten != NULL) { + *hte = *hten; + h_arena_free(ht->arena, hten); + } else { + hte->key = hte->value = NULL; + hte->hashval = 0; + } + return; + } + } +} +void h_hashtable_free(HHashTable* ht) { + for (i = 0; i < ht->capacity; i++) { + HHashTableEntry *hten, *hte = &ht->contents[i]; + // FIXME: Free key and value + hte = hte->next; + while (hte != NULL) { + // FIXME: leaks keys and values. + hten = hte->next; + h_arena_free(ht->arena, hte); + hte = hten; + } + } + h_arena_free(ht->arena, ht->contents); +} diff --git a/src/internal.h b/src/internal.h index b59f8240..cde861f6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -170,6 +170,33 @@ void* h_slist_pop(HSlist *slist); void h_slist_push(HSlist *slist, void* item); void h_slist_free(HSlist *slist); +typedef unsigned int HHashValue; +typedef HHashValue (*HHashFunc)(const void* key); +typedef bool (*HEqualFunc)(const void* key1, const void* key2); + +typedef struct HHashTableEntry_ { + struct HHashTableEntry_ *next; + void* key; + void* value; + HHashValue hashval; +} HHashTableEntry; + +typedef struct HHashTable_ { + HHashTableEntry *contents; + HHashFunc hashFunc; + HEqualFunc equalFunc; + int capacity; + int used; +} HHashTable; + +HHashTable* h_hashtable_new(HArena *arena, ); +void* h_hashtable_get(HHashTable* ht, void* key); +void h_hashtable_put(HHashTable* ht, void* key, void* value); +int h_hashtable_present(HHashTable* ht, void* key); +void h_hashtable_del(HHashTable* ht, void* key); +void h_hashtable_free(HHashTable* ht); + + #if 0 #include <malloc.h> #define arena_malloc(a, s) malloc(s) -- GitLab