Browse Source

htable: add htable_copy.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 9 years ago
parent
commit
f359fde1b7
3 changed files with 86 additions and 5 deletions
  1. 23 5
      ccan/htable/htable.c
  2. 19 0
      ccan/htable/htable.h
  3. 44 0
      ccan/htable/test/run-copy.c

+ 23 - 5
ccan/htable/htable.c

@@ -5,6 +5,7 @@
 #include <limits.h>
 #include <stdbool.h>
 #include <assert.h>
+#include <string.h>
 
 /* We use 0x1 as deleted marker. */
 #define HTABLE_DELETED (0x1)
@@ -52,6 +53,13 @@ void htable_init(struct htable *ht,
 	ht->table = &ht->perfect_bit;
 }
 
+/* We've changed ht->bits, update ht->max and ht->max_with_deleted */
+static void htable_adjust_capacity(struct htable *ht)
+{
+	ht->max = ((size_t)3 << ht->bits) / 4;
+	ht->max_with_deleted = ((size_t)9 << ht->bits) / 10;
+}
+
 bool htable_init_sized(struct htable *ht,
 		       size_t (*rehash)(const void *, void *),
 		       void *priv, size_t expect)
@@ -69,9 +77,7 @@ bool htable_init_sized(struct htable *ht,
 		ht->table = &ht->perfect_bit;
 		return false;
 	}
-	ht->max = ((size_t)3 << ht->bits) / 4;
-	ht->max_with_deleted = ((size_t)9 << ht->bits) / 10;
-
+	htable_adjust_capacity(ht);
 	return true;
 }
 	
@@ -82,6 +88,19 @@ void htable_clear(struct htable *ht)
 	htable_init(ht, ht->rehash, ht->priv);
 }
 
+bool htable_copy(struct htable *dst, const struct htable *src)
+{
+	uintptr_t *htable = malloc(sizeof(size_t) << src->bits);
+
+	if (!htable)
+		return false;
+
+	*dst = *src;
+	dst->table = htable;
+	memcpy(dst->table, src->table, sizeof(size_t) << src->bits);
+	return true;
+}
+
 static size_t hash_bucket(const struct htable *ht, size_t h)
 {
 	return h & ((1 << ht->bits)-1);
@@ -174,8 +193,7 @@ static COLD bool double_table(struct htable *ht)
 		return false;
 	}
 	ht->bits++;
-	ht->max = ((size_t)3 << ht->bits) / 4;
-	ht->max_with_deleted = ((size_t)9 << ht->bits) / 10;
+	htable_adjust_capacity(ht);
 
 	/* If we lost our "perfect bit", get it back now. */
 	if (!ht->perfect_bit && ht->common_mask) {

+ 19 - 0
ccan/htable/htable.h

@@ -74,6 +74,25 @@ bool htable_init_sized(struct htable *ht,
  */
 void htable_clear(struct htable *ht);
 
+/**
+ * htable_copy - duplicate a hash table.
+ * @dst: the hash table to overwrite
+ * @src: the hash table to copy
+ *
+ * Only fails on out-of-memory.
+ *
+ * Equivalent to (but faster than):
+ *    if (!htable_init_sized(dst, src->rehash, src->priv, 1U << src->bits))
+ *	   return false;
+ *    v = htable_first(src, &i);
+ *    while (v) {
+ *		htable_add(dst, v);
+ *		v = htable_next(src, i);
+ *    }
+ *    return true;
+ */
+bool htable_copy(struct htable *dst, const struct htable *src);
+
 /**
  * htable_rehash - use a hashtree's rehash function
  * @elem: the argument to rehash()

+ 44 - 0
ccan/htable/test/run-copy.c

@@ -0,0 +1,44 @@
+#include <ccan/htable/htable.h>
+#include <ccan/htable/htable.c>
+#include <ccan/tap/tap.h>
+#include <stdbool.h>
+#include <string.h>
+
+#define NUM_VALS 512
+
+static size_t hash(const void *elem, void *unused)
+{
+	size_t h = *(uint64_t *)elem / 2;
+	return h;
+}
+
+static bool cmp(const void *candidate, void *ptr)
+{
+	return *(const uint64_t *)candidate == *(const uint64_t *)ptr;
+}
+
+int main(int argc, char *argv[])
+{
+	struct htable ht, ht2;
+	uint64_t val[NUM_VALS], i;
+
+	plan_tests((NUM_VALS) * 3);
+	for (i = 0; i < NUM_VALS; i++)
+		val[i] = i;
+
+	htable_init(&ht, hash, NULL);
+	for (i = 0; i < NUM_VALS; i++) {
+		ok1(ht.max >= i);
+		ok1(ht.max <= i * 2);
+		htable_add(&ht, hash(&val[i], NULL), &val[i]);
+	}
+
+	htable_copy(&ht2, &ht);
+	htable_clear(&ht);
+
+	for (i = 0; i < NUM_VALS; i++)
+		ok1(htable_get(&ht2, hash(&i, NULL), cmp, &i) == &val[i]);
+	htable_clear(&ht2);
+
+	return exit_status();
+}