diff src/ploki/hash.c @ 4223:ac0403686959

<oerjan> rm -rf src/ploki; mv ploki src
author HackBot
date Fri, 20 Dec 2013 22:18:50 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ploki/hash.c	Fri Dec 20 22:18:50 2013 +0000
@@ -0,0 +1,273 @@
+#include "config.h"
+#include "hash.h"
+#include "main.h"
+#include "main_opt.h"
+#include "random.h"
+#include "xmalloc.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <assert.h>
+
+struct h_entry {
+	size_t hash;
+	void *key;
+	void *value;
+};
+
+struct h_node {
+	struct h_entry entry;
+	struct h_node *next;
+};
+
+enum {MAGIC = 112};
+
+void h_init(
+		Hash *h,
+		size_t (*hash)(const void *, size_t),
+		int (*cmp)(const void *, const void *),
+		void (*delk)(void *),
+		void (*delv)(void *)
+		) {
+	size_t i;
+
+	h->entries = 0;
+	h->brk = -1;
+	h->iter = -1;
+	h->iterptr = NULL;
+	h->seed = randval() * (size_t)-1;
+	h->delk = delk;
+	h->delv = delv;
+	assert(hash != NULL);
+	h->hash = hash;
+	assert(cmp != NULL);
+	h->cmp = cmp;
+	h->table = xmalloc(h->newsize = h->size = MAGIC, sizeof *h->table);
+	for (i = 0; i < h->size; ++i) {
+		h->table[i] = NULL;
+	}
+}
+
+#define DELKV(p)                   \
+do {                               \
+	if (h->delk) {                 \
+		h->delk((p)->entry.key);   \
+	}                              \
+	if (h->delv) {                 \
+		h->delv((p)->entry.value); \
+	}                              \
+} while (0)
+
+void h_end(Hash *h) {
+	size_t size, b;
+
+	if (!h->table)
+		return;
+
+	for (b = 0, size = h->newsize; h->newsize; h->newsize--) {
+		struct h_node *p;
+
+		if ((p = h->table[h->newsize - 1])) {
+			++b;
+			for (; p; p = h->table[h->newsize - 1]) {
+				h->table[h->newsize - 1] = p->next;
+				DELKV(p);
+				xfree(p);
+			}
+		}
+	}
+	xfree(h->table);
+	h->table = NULL;
+
+	if (Opt.debug & DBG_HASH) {
+		fprintf(stderr, "%s: hash[%lu/%lu/%lu]\n", Prog, (unsigned long)h->entries, (unsigned long)b, (unsigned long)size);
+	}
+}
+
+ATTR_PURE
+static size_t xclip(const Hash *h, const size_t hash_unc) {
+	size_t hash;
+
+	hash = hash_unc % h->size;
+	if (hash > h->brk) {
+		hash = hash_unc % h->newsize;
+	}
+
+	return hash;
+}
+
+#if 0
+ATTR_PURE
+static size_t xhash(const Hash *h, const void *key) {
+	return xclip(h, h->hash(key, h->seed));
+}
+#endif
+
+#define XRESIZN(h) ((h)->brk + 1u)
+#define XSTEP(h)   do { if (XRESIZN(h)) xstep(h); } while (0)
+
+static void xstep(Hash *h) {
+	struct h_node *rev = NULL;
+	struct h_node *p;
+	struct h_node *tmp;
+
+	assert(h->table != NULL);
+
+	for (p = h->table[h->brk]; p; p = tmp) {
+		tmp = p->next;
+		p->next = rev;
+		rev = p;
+	}
+	h->table[h->brk--] = NULL;
+
+	if (!XRESIZN(h)) {
+		h->size = h->newsize;
+	}
+
+	for (p = rev; p; p = tmp) {
+		const size_t i = xclip(h, p->entry.hash);
+		tmp = p->next;
+		p->next = h->table[i];
+		h->table[i] = p;
+	}
+}
+
+static void xincentries(Hash *h) {
+	h->entries++;
+	if (!(XRESIZN(h)) && h->entries / h->size > 3u) {
+		size_t i;
+		h->table = xrealloc(h->table, h->newsize = h->size * 2u + 1u);
+		for (i = h->size; i < h->newsize; ++i) {
+			h->table[i] = NULL;
+		}
+		h->brk = h->size - 1u;
+		xstep(h);
+	}
+}
+
+int h_get(Hash *h, const void *key, void **res) {
+	XSTEP(h);
+	{
+		const size_t hash_unc = h->hash(key, h->seed);
+		const size_t hash = xclip(h, hash_unc);
+		struct h_node *p;
+
+		for (p = h->table[hash]; p; p = p->next) {
+			if (hash_unc == p->entry.hash && h->cmp(p->entry.key, key) == 0) {
+				if (res) {
+					*res = p->entry.value;
+				}
+				return H_OK;
+			}
+		}
+	}
+	return H_NOENT;
+}
+
+int h_del(Hash *h, const void *key) {
+	XSTEP(h);
+	{
+		const size_t hash_unc = h->hash(key, h->seed);
+		const size_t hash = xclip(h, hash_unc);
+		struct h_node **p;
+
+		for (p = &h->table[hash]; *p; p = &(*p)->next) {
+			if (hash_unc == (*p)->entry.hash && h->cmp((*p)->entry.key, key) == 0) {
+				struct h_node *tmp = *p;
+				*p = (*p)->next;
+				DELKV(tmp);
+				xfree(tmp);
+				h->entries--;
+				return H_OK;
+			}
+		}
+	}
+
+	return H_NOENT;
+}
+
+#if 0
+void h_push(Hash *h, void *key, void *val) {
+	XSTEP(h);
+	{
+		const size_t hash_unc = h->hash(key, h->seed);
+		const size_t hash = xclip(h, hash_unc);
+		struct h_node *p;
+
+		p = xmalloc(1, sizeof *p);
+		p->entry.hash = hash_unc;
+		p->entry.key = key;
+		p->entry.value = val;
+		p->next = h->table[hash];
+		h->table[hash] = p;
+
+		xincentries(h);
+	}
+}
+#endif
+
+int h_put(Hash *h, void *key, void *val, int replace) {
+	XSTEP(h);
+	{
+		const size_t hash_unc = h->hash(key, h->seed);
+		const size_t hash = xclip(h, hash_unc);
+		struct h_node **p;
+
+		for (p = &h->table[hash]; *p; p = &(*p)->next) {
+			if (hash_unc == (*p)->entry.hash && h->cmp((*p)->entry.key, key) == 0) {
+				if (replace) {
+					DELKV(*p);
+					(*p)->entry.key = key;
+					(*p)->entry.value = val;
+					return H_OK;
+				} else {
+					return H_EXIST;
+				}
+			}
+		}
+
+		*p = xmalloc(1, sizeof **p);
+
+		(*p)->entry.hash = hash_unc;
+		(*p)->entry.key = key;
+		(*p)->entry.value = val;
+		(*p)->next = NULL;
+
+		xincentries(h);
+	}
+
+	return H_OK;
+}
+
+void h_reset(Hash *h) {
+	h->iter = -1;
+	h->iterptr = NULL;
+}
+
+int h_nextkv(Hash *h, void **k, void **v) {
+	if (h->iterptr) {
+		*k = h->iterptr->entry.key;
+		*v = h->iterptr->entry.value;
+		h->iterptr = h->iterptr->next;
+		return H_OK;
+	}
+
+	for (h->iter++; h->iter < h->newsize; h->iter++) {
+		if ((h->iterptr = h->table[h->iter])) {
+			*k = h->iterptr->entry.key;
+			*v = h->iterptr->entry.value;
+			h->iterptr = h->iterptr->next;
+			return H_OK;
+		}
+	}
+
+	h->iter = -1;
+	return H_NOENT;
+}
+
+#if 0
+size_t (h_entries)(const Hash *h) {
+	return h_entries(h);
+}
+#endif