Commit f359fde1 authored by Rusty Russell's avatar Rusty Russell

htable: add htable_copy.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 7b567629
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
#include <string.h>
/* We use 0x1 as deleted marker. */ /* We use 0x1 as deleted marker. */
#define HTABLE_DELETED (0x1) #define HTABLE_DELETED (0x1)
...@@ -52,6 +53,13 @@ void htable_init(struct htable *ht, ...@@ -52,6 +53,13 @@ void htable_init(struct htable *ht,
ht->table = &ht->perfect_bit; 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, bool htable_init_sized(struct htable *ht,
size_t (*rehash)(const void *, void *), size_t (*rehash)(const void *, void *),
void *priv, size_t expect) void *priv, size_t expect)
...@@ -69,9 +77,7 @@ bool htable_init_sized(struct htable *ht, ...@@ -69,9 +77,7 @@ bool htable_init_sized(struct htable *ht,
ht->table = &ht->perfect_bit; ht->table = &ht->perfect_bit;
return false; return false;
} }
ht->max = ((size_t)3 << ht->bits) / 4; htable_adjust_capacity(ht);
ht->max_with_deleted = ((size_t)9 << ht->bits) / 10;
return true; return true;
} }
...@@ -82,6 +88,19 @@ void htable_clear(struct htable *ht) ...@@ -82,6 +88,19 @@ void htable_clear(struct htable *ht)
htable_init(ht, ht->rehash, ht->priv); 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) static size_t hash_bucket(const struct htable *ht, size_t h)
{ {
return h & ((1 << ht->bits)-1); return h & ((1 << ht->bits)-1);
...@@ -174,8 +193,7 @@ static COLD bool double_table(struct htable *ht) ...@@ -174,8 +193,7 @@ static COLD bool double_table(struct htable *ht)
return false; return false;
} }
ht->bits++; ht->bits++;
ht->max = ((size_t)3 << ht->bits) / 4; htable_adjust_capacity(ht);
ht->max_with_deleted = ((size_t)9 << ht->bits) / 10;
/* If we lost our "perfect bit", get it back now. */ /* If we lost our "perfect bit", get it back now. */
if (!ht->perfect_bit && ht->common_mask) { if (!ht->perfect_bit && ht->common_mask) {
......
...@@ -74,6 +74,25 @@ bool htable_init_sized(struct htable *ht, ...@@ -74,6 +74,25 @@ bool htable_init_sized(struct htable *ht,
*/ */
void htable_clear(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 * htable_rehash - use a hashtree's rehash function
* @elem: the argument to rehash() * @elem: the argument to rehash()
......
#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();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment