X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fhtable%2Fhtable.c;h=e1d13699ea85811fe2f61adbb1ce4eca942406c8;hb=5ff76d983c62c8fc489672a1f89927ee3ba58e5d;hp=f3e529211d5b2456bad5165d3baa848de4314d3d;hpb=0c3590dc33d644f73bb8587db454c491830aaf26;p=ccan diff --git a/ccan/htable/htable.c b/ccan/htable/htable.c index f3e52921..e1d13699 100644 --- a/ccan/htable/htable.c +++ b/ccan/htable/htable.c @@ -5,6 +5,7 @@ #include #include #include +#include /* We use 0x1 as deleted marker. */ #define HTABLE_DELETED (0x1) @@ -45,21 +46,41 @@ static inline uintptr_t get_hash_ptr_bits(const struct htable *ht, void htable_init(struct htable *ht, size_t (*rehash)(const void *elem, void *priv), void *priv) { - ht->bits = 0; + struct htable empty = HTABLE_INITIALIZER(empty, NULL, NULL); + *ht = empty; ht->rehash = rehash; ht->priv = priv; - ht->elems = 0; - ht->deleted = 0; - ht->max = 0; - ht->max_with_deleted = 0; - /* This guarantees we enter update_common first add. */ - ht->common_mask = -1; - ht->common_bits = 0; - ht->perfect_bit = 0; - /* Dummy table until first insert. */ 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) +{ + htable_init(ht, rehash, priv); + + /* Don't go insane with sizing. */ + for (ht->bits = 1; ((size_t)3 << ht->bits) / 4 < expect; ht->bits++) { + if (ht->bits == 30) + break; + } + + ht->table = calloc(1 << ht->bits, sizeof(size_t)); + if (!ht->table) { + ht->table = &ht->perfect_bit; + return false; + } + htable_adjust_capacity(ht); + return true; +} + void htable_clear(struct htable *ht) { if (ht->table != &ht->perfect_bit) @@ -67,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); @@ -120,6 +154,17 @@ void *htable_next(const struct htable *ht, struct htable_iter *i) return NULL; } +void *htable_prev(const struct htable *ht, struct htable_iter *i) +{ + for (;;) { + if (!i->off) + return NULL; + i->off --; + if (entry_is_valid(ht->table[i->off])) + return get_raw_ptr(ht, ht->table[i->off]); + } +} + /* This does not expand the hash table, that's up to caller. */ static void ht_add(struct htable *ht, const void *new, size_t h) { @@ -148,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) { @@ -205,8 +249,17 @@ static COLD void update_common(struct htable *ht, const void *p) uintptr_t maskdiff, bitsdiff; if (ht->elems == 0) { - ht->common_mask = -1; - ht->common_bits = (uintptr_t)p; + /* Always reveal one bit of the pointer in the bucket, + * so it's not zero or HTABLE_DELETED (1), even if + * hash happens to be 0. Assumes (void *)1 is not a + * valid pointer. */ + for (i = sizeof(uintptr_t)*CHAR_BIT - 1; i > 0; i--) { + if ((uintptr_t)p & ((uintptr_t)1 << i)) + break; + } + + ht->common_mask = ~((uintptr_t)1 << i); + ht->common_bits = ((uintptr_t)p & ht->common_mask); ht->perfect_bit = 1; return; }