The HashElem now contains the type of the data.
Also, the destructor is set once at the creation of the Hash table.
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);
}
}
{
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);
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;
}
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;
}
}
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)
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);
}
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;
/* 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();
/* 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)
}
/* 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)
/* 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)
*
* @authors
* Copyright (C) 1996-2009 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 2017 Richard Russon <rich@flatcap.org>
*
* @copyright
* This program is free software: you can redistribute it and/or modify it under
* 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;
h = table->gen_hash(key, table->nelem);
ptr->key = key;
ptr->data = data;
+ ptr->type = type;
if (table->allow_dups)
{
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;
table->table[h] = ptr;
ptr->next = tmp;
}
- return h;
+ return ptr;
}
/**
* @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;
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);
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)
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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;
{
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);
*
* @authors
* Copyright (C) 1996-2009 Michael R. Elkins <me@mutt.org>
+ * Copyright (C) 2017 Richard Russon <rich@flatcap.org>
*
* @copyright
* This program is free software: you can redistribute it and/or modify it under
#define _MUTT_HASH_H
#include <stdbool.h>
+#include <stdint.h>
/**
* union HashKey - The data item stored in a HashElem
*/
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
*/
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() */
#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
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]);
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()
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
*/
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));
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);
/* 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);
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;
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;
}
}
/* 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);
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)
}
}
+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;
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