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)
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;
}