]> git.ozlabs.org Git - ccan/blobdiff - ccan/htable/htable.c
mem: add memends_str() helper for symmetry
[ccan] / ccan / htable / htable.c
index f3e529211d5b2456bad5165d3baa848de4314d3d..59048dc0ada0df95b23583e0dfbba65d3c96768c 100644 (file)
@@ -45,21 +45,36 @@ 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;
 }
 
+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)
@@ -205,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;
        }