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