shithub: hmap

Download patch

ref: d789157f513b2c3f324e00401f7e72e6010b6211
parent: d3298a0f73f8d45249df6b45b167ae17bea22167
author: Jacob Moody <moody@posixcafe.org>
date: Sat May 21 16:43:43 EDT 2022

second pass

--- a/hash.c
+++ b/hash.c
@@ -3,29 +3,36 @@
 #include "hash.h"
 
 Hmap*
-allochmap(uvlong (*hash)(Hnode*), int (*cmp)(Hnode*,Hnode*), int nbuckets, usize size)
+allochmap(uvlong (*hash)(void*), int (*cmp)(void*,void*), int nbuckets, usize size)
 {
-	Hmap *h = mallocz(sizeof(Hmap), 1);
-	if(h == nil)
+	void *store;
+	Hmap *h;
+
+	store = mallocz(sizeof(*h) + (nbuckets * size), 1);
+	if(store == nil)
 		return nil;
+
+	h = store;
 	h->size = nbuckets;
 	h->nsize = size;
 	h->hash = hash;
 	h->cmp = cmp;
 	h->len = h->cap = nbuckets;
-	h->nodes = mallocz(h->cap*h->nsize, 1);
-	if(h->nodes == nil)
-		return nil;
-	return h;
+
+	h->nodes = store;
+	h->nodes += sizeof(*h);
+	return store;
 }
 
 void
-hmapset(Hmap *h, Hnode *new)
+hmapset(Hmap **store, Hnode *new)
 {
-	Hnode *n, *tmp;
+	Hnode *n;
+	Hmap *h;
+	int tmp;
 
-	tmp = nil;
-	wlock(h);
+	tmp = 0;
+	h = *store;
 	n = (Hnode*)(h->nodes + (h->hash(new)%h->size)*h->nsize);
 
 	for(;;){
@@ -35,42 +42,42 @@
 			tmp = n->next;
 			goto replace;
 		}
-		if(n->next == nil)
+		if(n->next == 0)
 			break;
-		n = n->next;
+		n = (Hnode*)(h->nodes + n->next*h->nsize);
 	}
 
 	if(h->cap == h->len){
 		h->cap *= 2;
-		h->nodes = realloc(h->nodes, h->cap*h->nsize);
+		*store = realloc(*store, sizeof(*h) + h->cap*h->nsize);
+		h = *store;
+		h->nodes = (uchar*)*store + sizeof(*h);
 		memset(h->nodes + h->len*h->nsize, 0, h->nsize);
 	}
-	n->next = (Hnode*)(h->nodes + h->len*h->nsize);
+	n->next = h->len;
 	h->len++;
-	assert(h->len < h->cap);
-	n = n->next;
+	assert(h->len <= h->cap);
+	n = (Hnode*)(h->nodes + n->next*h->nsize);
 
 replace:
 	memmove(n, new, h->nsize);
 	n->filled++;
 	n->next = tmp;
-	wunlock(h);
 }
 
-Hnode*
+void*
 hmapget(Hmap *h, Hnode *q)
 {
 	Hnode *n;
 
-	rlock(h);
 	n = (Hnode*)(h->nodes + (h->hash(q)%h->size)*h->nsize);
-	for(; n!=nil; n=n->next)
-		if(n->filled != 0 && h->cmp(n, q) == 0){
-			runlock(h);
+	for(;;){
+		if(n->filled != 0 && h->cmp(n, q) == 0)
 			return n;
-		}
-
-	runlock(h);
+		if(n->next == 0)
+			break;
+		n = (Hnode*)(h->nodes + n->next*h->nsize);
+	}
 	return nil;
 }
 
@@ -77,12 +84,10 @@
 void
 hmapmark(Hmap *h, Hnode *n)
 {
-	wlock(h);
 	n->filled = 0;
-	wunlock(h);
 }
 
-Hnode*
+void*
 hmapdel(Hmap *h, Hnode *q)
 {
 	Hnode *n;
@@ -90,15 +95,28 @@
 	n = hmapget(h, q);
 	if(n == nil)
 		return nil;
-	hmapmark(h, n);
+
+	n->filled = 0;
 	return n;
 }
 
-void
-hmapfree(Hmap *h)
+Hmap*
+hmaprehash(Hmap *old, int buckets)
 {
-	free(h->nodes);
-	free(h);
+	int i;
+	Hnode *n;
+	Hmap *new;
+
+	if(buckets == 0)
+		buckets = old->len;
+
+	new = allochmap(old->hash, old->cmp, buckets, old->nsize);
+	for(i=0 ; i < old->len; i++){
+		n = (Hnode*)(old->nodes + i*old->nsize);
+		hmapset(&new, n);
+	}
+	free(old);
+	return new;
 }
 
 int
@@ -106,22 +124,23 @@
 {
 	Hmap *h;
 	Hnode *n, *o;
-	Rune r[3] = {0, 0, 0};
 	char fmt[16];
 	int i, len;
 
 	h = va_arg(f->args, Hmap*);
-	rlock(h);
-	r[0] = '%';
-	r[1] = h->nodeverb;
-	snprint(fmt, sizeof fmt - 1, "%S", r);
+	fmt[0] = '%';
+	memset(fmt+1, 0, UTFmax+1);
+	runetochar(fmt+1, &h->nodeverb);
 	for(i=len=0; i < h->size; i++){
 		n = (Hnode*)(h->nodes + i*h->nsize);
-		for(o=n; o != nil; o = o->next)
-			if(n->filled != 0)
+		for(o=n;;){
+			if(o->filled != 0)
 				len += fmtprint(f, (char*)fmt, o);
+			if(o->next == 0)
+				break;
+			o = (Hnode*)(h->nodes + o->next*h->nsize);
+		}		
 	}
-	runlock(h);
 	return len;
 }
 
--- a/hash.h
+++ b/hash.h
@@ -1,20 +1,19 @@
 typedef struct Hnode Hnode;
 struct Hnode {
-	Hnode *next;
+	int next;
 	int filled;
 };
 
 typedef struct Hmap Hmap;
 struct Hmap {
-	RWLock;
-	uvlong (*hash)(Hnode*);
-	int (*cmp)(Hnode*,Hnode*);
-	int nodeverb;
+	uvlong (*hash)(void*);
+	int (*cmp)(void*,void*);
+	Rune nodeverb;
 
 	int size;
 	usize nsize;
 
-	uchar *nodes;
 	int len;
 	int cap;
+	uchar *nodes;
 };
--- a/test.c
+++ b/test.c
@@ -16,27 +16,27 @@
 }
 
 uvlong
-thash(Hnode *h)
+thash(void *n)
 {
 	Tnode *t;
 	uvlong hash;
 	char *s;
 
-	t = (Tnode*)h;
+	t = n;
 	hash = 7;
 	s = t->key;
-	for(; *s;s++)
+	for(; *s; s++)
 		hash = hash*31  + *s;
 	return hash;
 }
 
 int
-tcmp(Hnode *ha, Hnode *hb)
+tcmp(void *_a, void *_b)
 {
 	Tnode *a, *b;
 
-	a = (Tnode*)ha;
-	b = (Tnode*)hb;
+	a = _a;
+	b = _b;
 	return strcmp(a->key, b->key);
 }
 
@@ -43,34 +43,45 @@
 void
 main(int argc, char **argv)
 {
+	int i;
 	Hmap *h;
-	Tnode a, b;
-	Tnode *r;
+	Tnode t, *r;
+	Tnode tab[] = {
+		{.key "key1", .value "value1" },
+		{.key "key2", .value "value2" },
+		{.key "key3", .value "value3" },
+		{.key "key4", .value "value4" },
+		{.key "key5", .value "value5" },
+		{.key "key6", .value "value6" },
+	};
 
 	fmtinstall('T', tfmt);
 	fmtinstall('H', hmapfmt);
 	h = allochmap(thash, tcmp, 2, sizeof(Tnode));
 	h->nodeverb = 'T';
-	a.key = "key";
-	a.value = "value";
-	hmapset(h, &a);
-	b.key = "key2";
-	b.value = "value2";
-	hmapset(h, &b);
-	b.key = "key3";
-	b.value = "value3";
-	hmapset(h, &b);
-	a.value = "";
-	r = (Tnode*)hmapget(h, &a);
-	assert(strcmp(r->key, a.key) == 0);
-	if(strcmp(r->value, "value") != 0)
-		sysfatal("fail");
 
-	b.key = "key3";
-	r = (Tnode*)hmapget(h, &b);
-	assert(strcmp(r->key, b.key) == 0);
+	for(i=0; i < nelem(tab); i++)
+		hmapset(&h, &tab[i]);
+
+	for(i=0; i < nelem(tab); i++){
+		t = tab[i];
+		t.value = "";
+		r = hmapget(h, &t);
+		assert(r);
+		assert(strcmp(r->key, tab[i].key) == 0);
+		assert(strcmp(r->value, tab[i].value) == 0);
+	}
+
 	print("%H", h);
-	hmapfree(h);
 	print("len, cap: %d %d\n", h->len, h->cap);
-	print("pass\n");
+	h = hmaprehash(h, 0);
+	for(i=0; i < nelem(tab); i++){
+		t = tab[i];
+		t.value = "";
+		r = hmapget(h, &t);
+		assert(r);
+		assert(strcmp(r->key, tab[i].key) == 0);
+		assert(strcmp(r->value, tab[i].value) == 0);
+	}
+	print("len, cap: %d %d\n", h->len, h->cap);
 }