[PATCH 4/4] Add resize_hash() function.
"Kevin J. McCarthy" <[email protected]> Mon, 20 Jul 2026 13:00:40 +0800
| Newsgroups | gmane.mail.mutt.devel |
|---|---|
| Message-ID | <[email protected]> |
Some of mutt's hashes are based on the size of the mailbox, with room
to grow. Generally they perform okay.
However, some of the hash tables are based on "Hmmmm... I think this
should be enough in general" guesstimates, such as the label hash, or
the auto_subscribe hash. When those guesses are wrong, it can degrade
performance. So this commit allows the hash table to resize itself.
Note, there are a couple functions that allow callers to work directly
with buckets or to walk the hash table. None of the callers currently
do anything silly like try to insert/delete entries while walking the
internals. So for now, I've let them be.
If later callers want to do crazy things, we could always introduce a
resize-lock, but since we're not a library I'd rather keep it simple
for now.
---
hash.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/hash.c b/hash.c
index 8b50b244..fd2e06d4 100644
--- a/hash.c
+++ b/hash.c
@@ -117,16 +117,47 @@ HASH *int_hash_create(int bucket_count, int flags)
return table;
}
+static void resize_hash(HASH *table)
+{
+ struct hash_elem **old_buckets = table->table;
+ int old_bucket_count = table->bucket_count;
+ int bucket, hash;
+ struct hash_elem *elem, *next_elem;
+
+ while (table->elem_count > table->bucket_count * 1.2)
+ table->bucket_count *= 2;
+ table->table = safe_calloc(table->bucket_count, sizeof(struct hash_elem *));
+
+ for (bucket = 0; bucket < old_bucket_count; bucket++)
+ {
+ elem = old_buckets[bucket];
+ while (elem)
+ {
+ next_elem = elem->next;
+
+ hash = table->gen_hash(elem->key, table->bucket_count);
+ elem->next = table->table[hash];
+ table->table[hash] = elem;
+
+ elem = next_elem;
+ }
+ }
+ FREE(&old_buckets);
+}
+
/* table hash table to update
* key key to hash on
* data data to associate with `key'
* allow_dup if nonzero, duplicate keys are allowed in the table
*/
-static int union_hash_insert(HASH * table, union hash_key key, void *data)
+static int union_hash_insert(HASH *table, union hash_key key, void *data)
{
struct hash_elem *ptr;
unsigned int h;
+ if (table->elem_count > table->bucket_count * 1.2)
+ resize_hash(table);
+
ptr = (struct hash_elem *) safe_malloc(sizeof(struct hash_elem));
h = table->gen_hash(key, table->bucket_count);
ptr->key = key;
--
2.55.0