shithub: hmap

Download patch

ref: 03f72f7bc34e43a767cf3686ac3c0f55cf7c64d5
parent: 9ae12fa984b9bc0eb0a33f9c0cf5b4ebd47ecd6d
author: Jacob Moody <moody@posixcafe.org>
date: Sun May 22 17:52:11 EDT 2022

fifth pass

--- a/hash.c
+++ b/hash.c
@@ -14,7 +14,7 @@
 };
 
 Hmap*
-allochmap(uvlong (*hash)(void*), int (*cmp)(void*,void*), int nbuckets, int size)
+hmapalloc(uvlong (*hash)(void*), int (*cmp)(void*,void*), int nbuckets, int size)
 {
 	void *store;
 	Hmap *h;
@@ -37,15 +37,17 @@
 	return store;
 }
 
-void
-hmapset(Hmap **store, void *key, void *new)
+int
+hmapset(Hmap **store, void *key, void *new, void *old)
 {
 	Hnode *n;
 	uchar *v;
+	uchar *oldv;
 	Hmap *h;
 	int next;
 
 	h = *store;
+	oldv = nil;
 	v = h->nodes + (h->hash(key)%h->nbs) * h->nsz;
 
 	for(;;){
@@ -54,8 +56,10 @@
 
 		if(n->filled == 0)
 			goto replace;
-		if(h->cmp(n->key, key) == 0)
+		if(h->cmp(n->key, key) == 0){
+			oldv = v + Tagsize;
 			goto replace;
+		}
 		if(next == 0)
 			break;
 		v = h->nodes + next*h->nsz;
@@ -79,10 +83,15 @@
 	n->filled++;
 	n->key = key;
 	n->next = next;
+	if(old != nil && oldv != nil){
+		memmove(old, oldv, h->nsz - Tagsize);
+		return 1;
+	}
+	return 0;
 }
 
 void*
-hmapget(Hmap *h, void *key)
+_hmapget(Hmap *h, void *key)
 {
 	Hnode *n;
 	uchar *v;
@@ -91,7 +100,7 @@
 	for(;;){
 		n = (Hnode*)v;
 		if(n->filled != 0 && h->cmp(n->key, key) == 0)
-			return v + Tagsize;
+			return v;
 		if(n->next == 0)
 			break;
 		v = h->nodes + n->next*h->nsz;
@@ -99,20 +108,34 @@
 	return nil;
 }
 
+int
+hmapget(Hmap *h, void *key, void *dst)
+{
+	uchar *v;
 
-void*
-hmapdel(Hmap *h, void *key)
+	v = _hmapget(h, key);
+	if(v == nil)
+		return -1;
+	if(dst != nil)
+		memmove(dst, v + Tagsize, h->nsz - Tagsize);
+	return 0;
+}
+
+int
+hmapdel(Hmap *h, void *key, void *dst)
 {
 	uchar *v;
 	Hnode *n;
 
-	v = hmapget(h, key);
+	v = _hmapget(h, key);
 	if(v == nil)
-		return nil;
+		return -1;
 
-	n = (Hnode*)(v - Tagsize);
+	n = (Hnode*)v;
 	n->filled = 0;
-	return v;
+	if(dst != nil)
+		memmove(dst, v + Tagsize, h->nsz - Tagsize);
+	return 0;
 }
 
 Hmap*
@@ -126,11 +149,11 @@
 	if(buckets == 0)
 		buckets = old->len;
 
-	new = allochmap(old->hash, old->cmp, buckets, old->nsz - Tagsize);
+	new = hmapalloc(old->hash, old->cmp, buckets, old->nsz - Tagsize);
 	for(i=0 ; i < old->len; i++){
 		v = old->nodes + i*old->nsz;
 		n = (Hnode*)v;
-		hmapset(&new, n->key, v + Tagsize);
+		hmapset(&new, n->key, v + Tagsize, nil);
 	}
 	free(old);
 	return new;
--- a/test.c
+++ b/test.c
@@ -16,6 +16,7 @@
 {
 	int i;
 	Hmap *h;
+	char *p;
 	char **v;
 
 	struct {
@@ -30,15 +31,15 @@
 		{.key "key6", .value "value6" },
 	};
 
-	h = allochmap(thash, strcmp, 1, sizeof(char*));
+	h = hmapalloc(thash, strcmp, 1, sizeof(char*));
 
 	for(i=0; i < nelem(tab); i++)
-		hmapset(&h, tab[i].key, &tab[i].value);
+		hmapset(&h, tab[i].key, &tab[i].value, nil);
 
 	for(i=0; i < nelem(tab); i++){
-		v = hmapget(h, tab[i].key);
-		assert(v);
-		assert(strcmp(*v, tab[i].value) == 0);
+		hmapget(h, tab[i].key, &p);
+		assert(p);
+		assert(strcmp(p, tab[i].value) == 0);
 	}
 
 	print("len, cap: %d %d\n", h->len, h->cap);
@@ -45,15 +46,14 @@
 
 	v = mallocz(nelem(tab)*sizeof(char*), 1);
 	assert(hmapvals(h, v, nelem(tab)) == nelem(tab));
-	for(i=0; i < nelem(tab); i++){
+	for(i=0; i < nelem(tab); i++)
 		print("%s\n", v[i]);
-	}
 
 	h = hmaprehash(h, 0);
 	for(i=0; i < nelem(tab); i++){
-		v = hmapget(h, tab[i].key);
-		assert(v);
-		assert(strcmp(*v, tab[i].value) == 0);
+		hmapget(h, tab[i].key, &p);
+		assert(p);
+		assert(strcmp(p, tab[i].value) == 0);
 	}
 	print("len, cap: %d %d\n", h->len, h->cap);
 	free(h);
@@ -64,7 +64,7 @@
 {
 	Hkey k;
 	k.p = p;
-	return k.v * 0xdeece66d + 0xb;
+	return k.v;
 }
 
 int
@@ -81,18 +81,20 @@
 	Hkey k;
 	Hmap *h;
 	char *v;
-	char **p;
+	char *p, *p2;
 
-	h = allochmap(runehash, runecmp, 16, sizeof(char*));
+	h = hmapalloc(runehash, runecmp, 16, sizeof(char*));
 
 	k.v = 'p';
 	v = "hello";
-	hmapset(&h, k.p, &v);
-	hmapset(&h, k.p, &v);
+	assert(hmapset(&h, k.p, &v, nil) == 0);
+	assert(hmapset(&h, k.p, &v, &p2) == 1);
+	assert(p2 == v);
 
-	p = hmapget(h, k.p);
+	assert(hmapget(h, k.p, &p) == 0);
 	assert(p && *p);
-	assert(*p == v);
+	assert(p == v);
+	free(h);
 }
 
 void