2 * Copyright (C) 1996-2009 Michael R. Elkins <me@mutt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #define SOMEPRIME 149711
32 static unsigned int gen_string_hash (union hash_key key, unsigned int n)
35 unsigned char *s = (unsigned char *)key.strkey;
39 h = (h * SOMEPRIME) % n;
44 static int cmp_string_key (union hash_key a, union hash_key b)
46 return mutt_strcmp (a.strkey, b.strkey);
49 static unsigned int gen_case_string_hash (union hash_key key, unsigned int n)
52 unsigned char *s = (unsigned char *)key.strkey;
55 h += (h << 7) + tolower (*s++);
56 h = (h * SOMEPRIME) % n;
61 static int cmp_case_string_key (union hash_key a, union hash_key b)
63 return mutt_strcasecmp (a.strkey, b.strkey);
66 static unsigned int gen_int_hash (union hash_key key, unsigned int n)
68 return key.intkey % n;
71 static int cmp_int_key (union hash_key a, union hash_key b)
73 if (a.intkey == b.intkey)
75 if (a.intkey < b.intkey)
80 static HASH *new_hash (int nelem)
82 HASH *table = safe_calloc (1, sizeof (HASH));
86 table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
90 HASH *hash_create (int nelem, int flags)
92 HASH *table = new_hash (nelem);
93 if (flags & MUTT_HASH_STRCASECMP)
95 table->gen_hash = gen_case_string_hash;
96 table->cmp_key = cmp_case_string_key;
100 table->gen_hash = gen_string_hash;
101 table->cmp_key = cmp_string_key;
103 if (flags & MUTT_HASH_STRDUP_KEYS)
104 table->strdup_keys = 1;
105 if (flags & MUTT_HASH_ALLOW_DUPS)
106 table->allow_dups = 1;
110 HASH *int_hash_create (int nelem, int flags)
112 HASH *table = new_hash (nelem);
113 table->gen_hash = gen_int_hash;
114 table->cmp_key = cmp_int_key;
115 if (flags & MUTT_HASH_ALLOW_DUPS)
116 table->allow_dups = 1;
120 /* table hash table to update
122 * data data to associate with `key'
123 * allow_dup if nonzero, duplicate keys are allowed in the table
125 static int union_hash_insert (HASH * table, union hash_key key, void *data)
127 struct hash_elem *ptr;
130 ptr = (struct hash_elem *) safe_malloc (sizeof (struct hash_elem));
131 h = table->gen_hash (key, table->nelem);
135 if (table->allow_dups)
137 ptr->next = table->table[h];
138 table->table[h] = ptr;
142 struct hash_elem *tmp, *last;
145 for (tmp = table->table[h], last = NULL; tmp; last = tmp, tmp = tmp->next)
147 r = table->cmp_key (tmp->key, key);
159 table->table[h] = ptr;
165 int hash_insert (HASH * table, const char *strkey, void *data)
168 key.strkey = table->strdup_keys ? safe_strdup (strkey) : strkey;
169 return union_hash_insert (table, key, data);
172 int int_hash_insert (HASH * table, unsigned int intkey, void *data)
176 return union_hash_insert (table, key, data);
179 static struct hash_elem *union_hash_find_elem (const HASH *table, union hash_key key)
182 struct hash_elem *ptr;
187 hash = table->gen_hash (key, table->nelem);
188 ptr = table->table[hash];
189 for (; ptr; ptr = ptr->next)
191 if (table->cmp_key (key, ptr->key) == 0)
197 static void *union_hash_find (const HASH *table, union hash_key key)
199 struct hash_elem *ptr = union_hash_find_elem (table, key);
206 void *hash_find (const HASH *table, const char *strkey)
210 return union_hash_find (table, key);
213 struct hash_elem *hash_find_elem (const HASH *table, const char *strkey)
217 return union_hash_find_elem (table, key);
220 void *int_hash_find (const HASH *table, unsigned int intkey)
224 return union_hash_find (table, key);
227 struct hash_elem *hash_find_bucket (const HASH *table, const char *strkey)
236 hash = table->gen_hash (key, table->nelem);
237 return table->table[hash];
240 static void union_hash_delete (HASH *table, union hash_key key, const void *data,
241 void (*destroy) (void *))
244 struct hash_elem *ptr, **last;
249 hash = table->gen_hash (key, table->nelem);
250 ptr = table->table[hash];
251 last = &table->table[hash];
255 if ((data == ptr->data || !data)
256 && table->cmp_key (ptr->key, key) == 0)
261 if (table->strdup_keys)
262 FREE (&ptr->key.strkey);
275 void hash_delete (HASH *table, const char *strkey, const void *data,
276 void (*destroy) (void *))
280 union_hash_delete (table, key, data, destroy);
283 void int_hash_delete (HASH *table, unsigned int intkey, const void *data,
284 void (*destroy) (void *))
288 union_hash_delete (table, key, data, destroy);
291 /* ptr pointer to the hash table to be freed
292 * destroy() function to call to free the ->data member (optional)
294 void hash_destroy (HASH **ptr, void (*destroy) (void *))
298 struct hash_elem *elem, *tmp;
304 for (i = 0 ; i < pptr->nelem; i++)
306 for (elem = pptr->table[i]; elem; )
312 if (pptr->strdup_keys)
313 FREE (&tmp->key.strkey);
318 FREE (ptr); /* __FREE_CHECKED__ */
321 struct hash_elem *hash_walk(const HASH *table, struct hash_walk_state *state)
323 if (state->last && state->last->next)
325 state->last = state->last->next;
332 while (state->index < table->nelem)
334 if (table->table[state->index])
336 state->last = table->table[state->index];