From: Richard Russon Date: Fri, 1 Sep 2017 15:04:04 +0000 (+0100) Subject: refactor the hash types X-Git-Tag: neomutt-20180223~57^2~5 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4d84a79b4c8148f310f8f73fda889dab4c64d2e4;p=neomutt refactor the hash types The HashElem now contains the type of the data. Also, the destructor is set once at the creation of the Hash table. --- diff --git a/alias.c b/alias.c index 6ad6cf76c..d97feb56a 100644 --- a/alias.c +++ b/alias.c @@ -495,7 +495,7 @@ void mutt_alias_delete_reverse(struct Alias *t) for (ap = t->addr; ap; ap = ap->next) { if (!ap->group && ap->mailbox) - mutt_hash_delete(ReverseAliases, ap->mailbox, ap, NULL); + mutt_hash_delete(ReverseAliases, ap->mailbox, ap); } } diff --git a/group.c b/group.c index 159cc2a1e..361822b3d 100644 --- a/group.c +++ b/group.c @@ -53,7 +53,7 @@ static void group_remove(struct Group *g) { if (!g) return; - mutt_hash_delete(Groups, g->name, g, NULL); + mutt_hash_delete(Groups, g->name, g); mutt_addr_free(&g->as); mutt_regexlist_free(&g->rs); FREE(&g->name); diff --git a/header.c b/header.c index 6fe6de40f..e6e737e6c 100644 --- a/header.c +++ b/header.c @@ -237,7 +237,7 @@ static void label_ref_dec(struct Context *ctx, char *label) count = (uintptr_t) elem->data; if (count <= 1) { - mutt_hash_delete(ctx->label_hash, label, NULL, NULL); + mutt_hash_delete(ctx->label_hash, label, NULL); return; } diff --git a/history.c b/history.c index 262bd24ad..0673c7966 100644 --- a/history.c +++ b/history.c @@ -162,7 +162,7 @@ static int dup_hash_dec(struct Hash *dup_hash, char *s) count = (uintptr_t) elem->data; if (count <= 1) { - mutt_hash_delete(dup_hash, s, NULL, NULL); + mutt_hash_delete(dup_hash, s, NULL); return 0; } @@ -292,7 +292,7 @@ cleanup: } if (option(OPT_HISTORY_REMOVE_DUPS)) for (hclass = 0; hclass < HC_LAST; hclass++) - mutt_hash_destroy(&dup_hashes[hclass], NULL); + mutt_hash_destroy(&dup_hashes[hclass]); } static void save_history(enum HistoryClass hclass, const char *s) diff --git a/imap/imap.c b/imap/imap.c index eaba75ca7..fb2141439 100644 --- a/imap/imap.c +++ b/imap/imap.c @@ -903,7 +903,7 @@ void imap_expunge_mailbox(struct ImapData *idata) FREE(&idata->cache[cacheno].path); } - mutt_hash_int_delete(idata->uid_hash, HEADER_DATA(h)->uid, h, NULL); + mutt_hash_int_delete(idata->uid_hash, HEADER_DATA(h)->uid, h); imap_free_header_data((struct ImapHeaderData **) &h->data); } @@ -2329,7 +2329,7 @@ static int imap_close_mailbox(struct Context *ctx) mutt_list_free(&idata->flags); idata->ctx = NULL; - mutt_hash_destroy(&idata->uid_hash, NULL); + mutt_hash_destroy(&idata->uid_hash); FREE(&idata->msn_index); idata->msn_index_size = 0; idata->max_msn = 0; diff --git a/init.c b/init.c index 0fc54dc78..243dad6a1 100644 --- a/init.c +++ b/init.c @@ -3893,7 +3893,7 @@ void mutt_init(int skip_sys_rc, struct ListHead *commands) /* reverse alias keys need to be strdup'ed because of idna conversions */ ReverseAliases = mutt_hash_create( 1031, MUTT_HASH_STRCASECMP | MUTT_HASH_STRDUP_KEYS | MUTT_HASH_ALLOW_DUPS); - TagTransforms = mutt_hash_create(64, 1); + TagTransforms = mutt_hash_create(64, MUTT_HASH_STRCASECMP); TagFormats = mutt_hash_create(64, 0); mutt_menu_init(); diff --git a/mbox.c b/mbox.c index 2a5a06ccc..89dcd29d1 100644 --- a/mbox.c +++ b/mbox.c @@ -621,10 +621,10 @@ static int reopen_mailbox(struct Context *ctx, int *index_hint) /* simulate a close */ if (ctx->id_hash) - mutt_hash_destroy(&ctx->id_hash, NULL); + mutt_hash_destroy(&ctx->id_hash); if (ctx->subj_hash) - mutt_hash_destroy(&ctx->subj_hash, NULL); - mutt_hash_destroy(&ctx->label_hash, NULL); + mutt_hash_destroy(&ctx->subj_hash); + mutt_hash_destroy(&ctx->label_hash); mutt_clear_threads(ctx); FREE(&ctx->v2r); if (ctx->readonly) diff --git a/mh.c b/mh.c index 89d85f6cf..c1c040224 100644 --- a/mh.c +++ b/mh.c @@ -2171,7 +2171,7 @@ static int maildir_check_mailbox(struct Context *ctx, int *index_hint) } /* destroy the file name hash */ - mutt_hash_destroy(&fnames, NULL); + mutt_hash_destroy(&fnames); /* If we didn't just get new mail, update the tables. */ if (occult) @@ -2295,7 +2295,7 @@ static int mh_check_mailbox(struct Context *ctx, int *index_hint) /* destroy the file name hash */ - mutt_hash_destroy(&fnames, NULL); + mutt_hash_destroy(&fnames); /* If we didn't just get new mail, update the tables. */ if (occult) diff --git a/mutt/hash.c b/mutt/hash.c index bbf3501d1..290f9eba9 100644 --- a/mutt/hash.c +++ b/mutt/hash.c @@ -4,6 +4,7 @@ * * @authors * Copyright (C) 1996-2009 Michael R. Elkins + * Copyright (C) 2017 Richard Russon * * @copyright * This program is free software: you can redistribute it and/or modify it under @@ -162,11 +163,13 @@ static struct Hash *new_hash(int nelem) * union_hash_insert - Insert into a hash table using a union as a key * @param table Hash table to update * @param key Key to hash on + * @param type Data type * @param data Data to associate with `key' * @retval -1 on error * @retval >=0 on success, index into the hash table */ -static int union_hash_insert(struct Hash *table, union HashKey key, void *data) +static struct HashElem *union_hash_insert(struct Hash *table, union HashKey key, + int type, void *data) { struct HashElem *ptr = NULL; unsigned int h; @@ -175,6 +178,7 @@ static int union_hash_insert(struct Hash *table, union HashKey key, void *data) h = table->gen_hash(key, table->nelem); ptr->key = key; ptr->data = data; + ptr->type = type; if (table->allow_dups) { @@ -184,14 +188,15 @@ static int union_hash_insert(struct Hash *table, union HashKey key, void *data) else { struct HashElem *tmp = NULL, *last = NULL; + int r; for (tmp = table->table[h], last = NULL; tmp; last = tmp, tmp = tmp->next) { - int r = table->cmp_key(tmp->key, key); + r = table->cmp_key(tmp->key, key); if (r == 0) { FREE(&ptr); - return -1; + return NULL; } if (r > 0) break; @@ -202,7 +207,7 @@ static int union_hash_insert(struct Hash *table, union HashKey key, void *data) table->table[h] = ptr; ptr->next = tmp; } - return h; + return ptr; } /** @@ -249,13 +254,11 @@ static void *union_hash_find(const struct Hash *table, union HashKey key) * @param table Hash table to use * @param key Key (either string or integer) * @param data Private data to match (or NULL for any match) - * @param destroy Callback function to free the HashElem's data */ -static void union_hash_delete(struct Hash *table, union HashKey key, - const void *data, void (*destroy)(void *)) +static void union_hash_delete(struct Hash *table, union HashKey key, const void *data) { int hash; - struct HashElem *ptr = NULL, **last = NULL; + struct HashElem *ptr, **last; if (!table) return; @@ -266,11 +269,11 @@ static void union_hash_delete(struct Hash *table, union HashKey key, while (ptr) { - if (((data == ptr->data) || !data) && table->cmp_key(ptr->key, key) == 0) + if ((data == ptr->data || !data) && table->cmp_key(ptr->key, key) == 0) { *last = ptr->next; - if (destroy) - destroy(ptr->data); + if (table->destroy) + table->destroy(ptr->type, ptr->data, table->dest_data); if (table->strdup_keys) FREE(&ptr->key.strkey); FREE(&ptr); @@ -327,6 +330,20 @@ struct Hash *mutt_hash_int_create(int nelem, int flags) return table; } +void mutt_hash_set_destructor(struct Hash *hash, hash_destructor fn, intptr_t fn_data) +{ + hash->destroy = fn; + hash->dest_data = fn_data; +} + +struct HashElem *mutt_hash_typed_insert(struct Hash *table, const char *strkey, + int type, void *data) +{ + union HashKey key; + key.strkey = table->strdup_keys ? mutt_str_strdup(strkey) : strkey; + return union_hash_insert(table, key, type, data); +} + /** * mutt_hash_insert - Add a new element to the Hash table (with string keys) * @param table Hash table (with string keys) @@ -335,11 +352,9 @@ struct Hash *mutt_hash_int_create(int nelem, int flags) * @retval -1 on error * @retval >=0 on success, index into the hash table */ -int mutt_hash_insert(struct Hash *table, const char *strkey, void *data) +struct HashElem *mutt_hash_insert(struct Hash *table, const char *strkey, void *data) { - union HashKey key; - key.strkey = table->strdup_keys ? mutt_str_strdup(strkey) : strkey; - return union_hash_insert(table, key, data); + return mutt_hash_typed_insert(table, strkey, -1, data); } /** @@ -350,11 +365,11 @@ int mutt_hash_insert(struct Hash *table, const char *strkey, void *data) * @retval -1 on error * @retval >=0 on success, index into the hash table */ -int mutt_hash_int_insert(struct Hash *table, unsigned int intkey, void *data) +struct HashElem *mutt_hash_int_insert(struct Hash *table, unsigned int intkey, void *data) { union HashKey key; key.intkey = intkey; - return union_hash_insert(table, key, data); + return union_hash_insert(table, key, -1, data); } /** @@ -422,14 +437,12 @@ struct HashElem *mutt_hash_find_bucket(const struct Hash *table, const char *str * @param table Hash table to use * @param strkey String key to match * @param data Private data to match (or NULL for any match) - * @param destroy Callback function to free the HashElem's data */ -void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data, - void (*destroy)(void *)) +void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data) { union HashKey key; key.strkey = strkey; - union_hash_delete(table, key, data, destroy); + union_hash_delete(table, key, data); } /** @@ -437,22 +450,19 @@ void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data, * @param table Hash table to use * @param intkey Integer key to match * @param data Private data to match (or NULL for any match) - * @param destroy Callback function to free the HashElem's data */ -void mutt_hash_int_delete(struct Hash *table, unsigned int intkey, - const void *data, void (*destroy)(void *)) +void mutt_hash_int_delete(struct Hash *table, unsigned int intkey, const void *data) { union HashKey key; key.intkey = intkey; - union_hash_delete(table, key, data, destroy); + union_hash_delete(table, key, data); } /** * mutt_hash_destroy - Destroy a hash table * @param ptr Pointer to the hash table to be freed - * @param destroy Function to call to free the ->data member (optional) */ -void mutt_hash_destroy(struct Hash **ptr, void (*destroy)(void *)) +void mutt_hash_destroy(struct Hash **ptr) { struct Hash *pptr = NULL; struct HashElem *elem = NULL, *tmp = NULL; @@ -467,8 +477,8 @@ void mutt_hash_destroy(struct Hash **ptr, void (*destroy)(void *)) { tmp = elem; elem = elem->next; - if (destroy) - destroy(tmp->data); + if (pptr->destroy) + pptr->destroy(tmp->type, tmp->data, pptr->dest_data); if (pptr->strdup_keys) FREE(&tmp->key.strkey); FREE(&tmp); diff --git a/mutt/hash.h b/mutt/hash.h index 40ec698ca..df6d4c4fa 100644 --- a/mutt/hash.h +++ b/mutt/hash.h @@ -4,6 +4,7 @@ * * @authors * Copyright (C) 1996-2009 Michael R. Elkins + * Copyright (C) 2017 Richard Russon * * @copyright * This program is free software: you can redistribute it and/or modify it under @@ -24,6 +25,7 @@ #define _MUTT_HASH_H #include +#include /** * union HashKey - The data item stored in a HashElem @@ -38,11 +40,14 @@ union HashKey { */ struct HashElem { + int type; union HashKey key; void *data; struct HashElem *next; }; +typedef void (*hash_destructor)(int type, void *obj, intptr_t data); + /** * struct Hash - A Hash Table */ @@ -54,6 +59,8 @@ struct Hash struct HashElem **table; unsigned int (*gen_hash)(union HashKey, unsigned int); int (*cmp_key)(union HashKey, union HashKey); + hash_destructor destroy; + intptr_t dest_data; }; /* flags for mutt_hash_create() */ @@ -62,16 +69,18 @@ struct Hash #define MUTT_HASH_ALLOW_DUPS (1 << 2) /**< allow duplicate keys to be inserted */ struct Hash * mutt_hash_create(int nelem, int flags); -void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data, void (*destroy)(void *)); -void mutt_hash_destroy(struct Hash **ptr, void (*destroy)(void *)); +void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data); +void mutt_hash_destroy(struct Hash **ptr); struct HashElem *mutt_hash_find_bucket(const struct Hash *table, const char *strkey); void * mutt_hash_find(const struct Hash *table, const char *strkey); struct HashElem *mutt_hash_find_elem(const struct Hash *table, const char *strkey); -int mutt_hash_insert(struct Hash *table, const char *strkey, void *data); +struct HashElem *mutt_hash_insert(struct Hash *table, const char *strkey, void *data); +void mutt_hash_set_destructor(struct Hash *hash, hash_destructor fn, intptr_t fn_data); +struct HashElem *mutt_hash_typed_insert(struct Hash *table, const char *strkey, int type, void *data); struct Hash * mutt_hash_int_create(int nelem, int flags); -void mutt_hash_int_delete(struct Hash *table, unsigned int intkey, const void *data, void (*destroy)(void *)); +void mutt_hash_int_delete(struct Hash *table, unsigned int intkey, const void *data); void * mutt_hash_int_find(const struct Hash *table, unsigned int intkey); -int mutt_hash_int_insert(struct Hash *table, unsigned int intkey, void *data); +struct HashElem *mutt_hash_int_insert(struct Hash *table, unsigned int intkey, void *data); /** * struct HashWalkState - Cursor to iterate through a Hash Table diff --git a/mx.c b/mx.c index 6554161f8..5eda153a1 100644 --- a/mx.c +++ b/mx.c @@ -535,10 +535,10 @@ void mx_fastclose_mailbox(struct Context *ctx) ctx->mx_ops->close(ctx); if (ctx->subj_hash) - mutt_hash_destroy(&ctx->subj_hash, NULL); + mutt_hash_destroy(&ctx->subj_hash); if (ctx->id_hash) - mutt_hash_destroy(&ctx->id_hash, NULL); - mutt_hash_destroy(&ctx->label_hash, NULL); + mutt_hash_destroy(&ctx->id_hash); + mutt_hash_destroy(&ctx->label_hash); mutt_clear_threads(ctx); for (int i = 0; i < ctx->msgcount; i++) mutt_free_header(&ctx->hdrs[i]); @@ -980,9 +980,9 @@ void mx_update_tables(struct Context *ctx, bool committing) ctx->hdrs[i]->content->hdr_offset); /* remove message from the hash tables */ if (ctx->subj_hash && ctx->hdrs[i]->env->real_subj) - mutt_hash_delete(ctx->subj_hash, ctx->hdrs[i]->env->real_subj, ctx->hdrs[i], NULL); + mutt_hash_delete(ctx->subj_hash, ctx->hdrs[i]->env->real_subj, ctx->hdrs[i]); if (ctx->id_hash && ctx->hdrs[i]->env->message_id) - mutt_hash_delete(ctx->id_hash, ctx->hdrs[i]->env->message_id, ctx->hdrs[i], NULL); + mutt_hash_delete(ctx->id_hash, ctx->hdrs[i]->env->message_id, ctx->hdrs[i]); mutt_label_hash_remove(ctx, ctx->hdrs[i]); /* The path mx_check_mailbox() -> imap_check_mailbox() -> * imap_expunge_mailbox() -> mx_update_tables() diff --git a/newsrc.c b/newsrc.c index ae162cb31..f66ad3c5f 100644 --- a/newsrc.c +++ b/newsrc.c @@ -115,6 +115,11 @@ void nntp_data_free(void *data) FREE(&data); } +void nntp_hash_destructor(int type, void *obj, intptr_t data) +{ + nntp_data_free(obj); +} + /** * nntp_newsrc_close - Unlock and close .newsrc file */ @@ -1026,6 +1031,7 @@ struct NntpServer *nntp_select_server(char *server, bool leave_lock) nserv = mutt_mem_calloc(1, sizeof(struct NntpServer)); nserv->conn = conn; nserv->groups_hash = mutt_hash_create(1009, 0); + mutt_hash_set_destructor(nserv->groups_hash, nntp_hash_destructor, 0); nserv->groups_max = 16; nserv->groups_list = mutt_mem_malloc(nserv->groups_max * sizeof(nntp_data)); @@ -1127,7 +1133,7 @@ struct NntpServer *nntp_select_server(char *server, bool leave_lock) if (rc < 0) { - mutt_hash_destroy(&nserv->groups_hash, nntp_data_free); + mutt_hash_destroy(&nserv->groups_hash); FREE(&nserv->groups_list); FREE(&nserv->newsrc_file); FREE(&nserv->authenticators); diff --git a/nntp.c b/nntp.c index b045870b4..76e510c40 100644 --- a/nntp.c +++ b/nntp.c @@ -1681,9 +1681,9 @@ static int nntp_open_message(struct Context *ctx, struct Message *msg, int msgno /* replace envelope with new one * hash elements must be updated because pointers will be changed */ if (ctx->id_hash && hdr->env->message_id) - mutt_hash_delete(ctx->id_hash, hdr->env->message_id, hdr, NULL); + mutt_hash_delete(ctx->id_hash, hdr->env->message_id, hdr); if (ctx->subj_hash && hdr->env->real_subj) - mutt_hash_delete(ctx->subj_hash, hdr->env->real_subj, hdr, NULL); + mutt_hash_delete(ctx->subj_hash, hdr->env->real_subj, hdr); mutt_env_free(&hdr->env); hdr->env = mutt_read_rfc822_header(msg->fp, hdr, 0, 0); @@ -2015,9 +2015,9 @@ static int check_mailbox(struct Context *ctx) if (ret == MUTT_REOPENED) { if (ctx->subj_hash) - mutt_hash_destroy(&ctx->subj_hash, NULL); + mutt_hash_destroy(&ctx->subj_hash); if (ctx->id_hash) - mutt_hash_destroy(&ctx->id_hash, NULL); + mutt_hash_destroy(&ctx->id_hash); mutt_clear_threads(ctx); ctx->vcount = 0; @@ -2245,7 +2245,7 @@ int nntp_active_fetch(struct NntpServer *nserv, bool new) if (data && data->deleted && !data->newsrc_ent) { nntp_delete_group_cache(data); - mutt_hash_delete(nserv->groups_hash, data->group, NULL, nntp_data_free); + mutt_hash_delete(nserv->groups_hash, data->group, NULL); nserv->groups_list[i] = NULL; } } diff --git a/pop.c b/pop.c index e72f597b1..10dbf6ff4 100644 --- a/pop.c +++ b/pop.c @@ -666,7 +666,7 @@ static int pop_fetch_message(struct Context *ctx, struct Message *msg, int msgno /* we replace envelop, key in subj_hash has to be updated as well */ if (ctx->subj_hash && h->env->real_subj) - mutt_hash_delete(ctx->subj_hash, h->env->real_subj, h, NULL); + mutt_hash_delete(ctx->subj_hash, h->env->real_subj, h); mutt_label_hash_remove(ctx, h); mutt_env_free(&h->env); h->env = mutt_read_rfc822_header(msg->fp, h, 0, 0); diff --git a/thread.c b/thread.c index 673a08437..3e33060a1 100644 --- a/thread.c +++ b/thread.c @@ -604,7 +604,7 @@ void mutt_clear_threads(struct Context *ctx) ctx->tree = NULL; if (ctx->thread_hash) - mutt_hash_destroy(&ctx->thread_hash, *free); + mutt_hash_destroy(&ctx->thread_hash); } static int compare_threads(const void *a, const void *b) @@ -782,6 +782,11 @@ static void check_subjects(struct Context *ctx, int init) } } +void thread_hash_destructor(int type, void *obj, intptr_t data) +{ + FREE(&obj); +} + void mutt_sort_threads(struct Context *ctx, int init) { struct Header *cur = NULL; @@ -801,7 +806,10 @@ void mutt_sort_threads(struct Context *ctx, int init) init = 1; if (init) + { ctx->thread_hash = mutt_hash_create(ctx->msgcount * 2, MUTT_HASH_ALLOW_DUPS); + mutt_hash_set_destructor(ctx->thread_hash, thread_hash_destructor, 0); + } /* we want a quick way to see if things are actually attached to the top of the * thread tree or if they're just dangling, so we attach everything to a top