X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fhtable%2Fhtable.c;h=59048dc0ada0df95b23583e0dfbba65d3c96768c;hb=c23a40c7f1ac9fad0146b46988a41f196aae933f;hp=0a01ead8978ad4c4e914a37dbe029c2ef1219004;hpb=60cc720d0797fc49325437ea36a9ffd909c75ed0;p=ccan diff --git a/ccan/htable/htable.c b/ccan/htable/htable.c index 0a01ead8..59048dc0 100644 --- a/ccan/htable/htable.c +++ b/ccan/htable/htable.c @@ -52,6 +52,29 @@ void htable_init(struct htable *ht, ht->table = &ht->perfect_bit; } +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; + } + ht->max = ((size_t)3 << ht->bits) / 4; + ht->max_with_deleted = ((size_t)9 << ht->bits) / 10; + + return true; +} + void htable_clear(struct htable *ht) { if (ht->table != &ht->perfect_bit) @@ -197,8 +220,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; }