summary refs log tree commit diff
diff options
context:
space:
mode:
authorWormHeamer2025-03-01 21:40:24 -0500
committerWormHeamer2025-03-01 21:40:24 -0500
commit20cbe7ee472c416b243541e661e7eb11621a881f (patch)
tree62a6a6d4565fc964554aeaec2ce8a6783aff6305
parent9c4420e3ef42a553ded82286988d3cf5d6570ca0 (diff)
add ihash
-rw-r--r--ihash.h109
-rw-r--r--stdwrm.h1
2 files changed, 110 insertions, 0 deletions
diff --git a/ihash.h b/ihash.h
new file mode 100644
index 0000000..242e97c
--- /dev/null
+++ b/ihash.h
@@ -0,0 +1,109 @@
+#ifndef IHASH_H
+#define IHASH_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <ctype.h>
+
+#include "dynarr.h"
+#include "str.h"
+
+#ifndef IHASH_SLOTS
+#define IHASH_SLOTS 8192
+#endif
+
+typedef uint64_t hash_t;
+
+typedef struct {
+	intptr_t key;
+	void *value;
+	hash_t hash;
+} IntHashEntry;
+
+typedef struct {
+	DYNARR(IntHashEntry) entries;
+} IntHashSlot;
+
+typedef struct {
+	IntHashSlot slots[IHASH_SLOTS];
+} IntHashTable;
+
+hash_t ihash(intptr_t s);
+void ihash_init(IntHashTable *h);
+void ihash_free(IntHashTable *h);
+void *ihash_get(IntHashTable *h, intptr_t key);
+void ihash_put(IntHashTable *h, intptr_t key, void *value);
+IntHashEntry *ihash_find(IntHashTable *h, intptr_t key);
+
+#ifdef IHASH_IMPL
+
+/* murmur64 integer hash */
+
+hash_t ihash(intptr_t h) {
+	h *= h >> 33;
+	h *= 0xff51afd7ed558ccdL;
+	h *= h >> 33;
+	h *= 0xc4ceb9fe1a85ec53L;
+	h *= h >> 33;
+	return h;
+}
+
+/* hash table */
+
+void ihash_init(IntHashTable *h) {
+	*h = (IntHashTable) { 0 };
+}
+
+void ihash_free(IntHashTable *h) {
+	for (unsigned i = 0; i < IHASH_SLOTS; i++) {
+		IntHashSlot *s = &h->slots[i];
+		if (!s->entries) continue;
+		DA_FREE(s->entries);
+	}
+}
+
+static inline int ihash_entry_match(IntHashEntry *h, intptr_t s, hash_t ihash) {
+	return s == ihash;
+}
+
+static inline IntHashEntry *ihash_find_hashed(IntHashTable *h, intptr_t key, hash_t k) {
+	size_t i = k & (IHASH_SLOTS - 1);
+	if (h->slots[i].entries) {
+		DA_FOR(h->slots[i].entries, e) {
+			if (ihash_entry_match(e, key, k)) {
+				return e;
+			}
+		}
+	}
+	return NULL;
+}
+
+IntHashEntry *ihash_find(IntHashTable *h, intptr_t key) {
+	return ihash_find_hashed(h, key, ihash(key));
+}
+
+void *ihash_get(IntHashTable *h, intptr_t key) {
+	IntHashEntry *e = ihash_find(h, key);
+	return e ? e->value : NULL;
+}
+
+void ihash_put(IntHashTable *h, intptr_t key, void *value) {
+	hash_t keyh = ihash(key);
+	IntHashEntry *e = ihash_find_hashed(h, key, keyh);
+	if (e) {
+		e->value = value;
+	} else {
+		hash_t keyi = keyh & (IHASH_SLOTS - 1);
+		if (!h->slots[keyi].entries) {
+			DA_INIT(h->slots[keyi].entries);
+		}
+		DA_PUSH(h->slots[keyi].entries, (IntHashEntry) {
+			.key = key,
+			.value = value,
+			.hash = keyh
+		});
+	}
+}
+
+#endif
+#endif
diff --git a/stdwrm.h b/stdwrm.h
index a1f9d0d..46992c3 100644
--- a/stdwrm.h
+++ b/stdwrm.h
@@ -3,6 +3,7 @@
 
 #ifdef STDWRM_IMPL
 #define SHASH_IMPL
+#define IHASH_IMPL
 #define ZONE_IMPL
 #define STR_IMPL
 #endif