1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2003 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
15 * Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk>
17 * Permission is hereby granted, free of charge, to any person obtaining a copy
18 * of this software and associated documentation files (the "Software"), to
19 * deal in the Software without restriction, including without limitation the
20 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
21 * sell copies of the Software, and to permit persons to whom the Software is
22 * furnished to do so, subject to the following conditions:
24 * The above copyright notice and this permission notice shall be included in
25 * all copies of the Software and its documentation and acknowledgment shall be
26 * given in the documentation and software packages that this Software was
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
32 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44 /*****************************************************************************/
46 create_hashtable(unsigned int minsize, float maxloadfactor,
47 unsigned int (*hashf) (void*),
48 int (*eqf) (void*,void*))
51 unsigned int i, size = 1u;
52 /* Check requested hashtable isn't too large */
53 if (minsize > (1u << 31)) return NULL;
54 /* Enforce size as power of 2 */
55 while (size < minsize) size <<= 1;
56 h = (struct hashtable *)malloc(sizeof(struct hashtable));
57 if (NULL == h) return NULL; /*oom*/
58 h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
59 if (NULL == h->table) { free(h); return NULL; } /*oom*/
61 for (i=0;i<size;i++) { h->table[i] = NULL; }
62 h->tablelength = size;
66 h->loadlimit = (unsigned int) ((float)size * maxloadfactor);
70 /*****************************************************************************/
72 hash(struct hashtable *h, void *k)
74 /* Aim to protect against poor hash functions by adding logic here
75 * - logic taken from java 1.4 hashtable source */
76 unsigned int i = h->hashfn(k);
78 i ^= ((i >> 14) | (i << 18)); /* >>> */
80 i ^= ((i >> 10) | (i << 22)); /* >>> */
83 /*****************************************************************************/
85 indexFor(unsigned int tablelength, unsigned int hashvalue)
87 /* Only works if tablelength == 2^N */
88 return (hashvalue & (tablelength - 1u));
91 /*****************************************************************************/
93 hashtable_expand(struct hashtable *h)
95 /* Double the size of the table to accomodate more entries */
96 struct entry **newtable;
99 unsigned int newsize, i, index;
100 /* Check we're not hitting max capacity */
101 if (0 == (newsize = (h->tablelength << 1))) return 0;
103 newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
104 if (NULL != newtable)
106 memset(newtable, 0, newsize * sizeof(struct entry *));
107 /* This algorithm is not 'stable'. ie. it reverses the list
108 * when it transfers entries between the tables */
109 for (i = 0; i < h->tablelength; i++) {
110 while (NULL != (e = h->table[i])) {
111 h->table[i] = e->next;
112 index = indexFor(newsize,e->h);
113 e->next = newtable[index];
120 /* Plan B: realloc instead */
123 newtable = (struct entry **)
124 realloc(h->table, newsize * sizeof(struct entry *));
125 if (NULL == newtable) return 0;
127 for (i = h->tablelength; i < newsize; i++) {
130 for (i = 0; i < h->tablelength; i++) {
131 for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
132 index = indexFor(newsize,e->h);
140 e->next = newtable[index];
146 h->tablelength = newsize;
151 /*****************************************************************************/
153 hashtable_count(struct hashtable *h)
155 return h->entrycount;
158 /*****************************************************************************/
160 hashtable_insert(struct hashtable *h, void *k, void *v)
162 /* This method allows duplicate keys - but they shouldn't be used */
165 if (++(h->entrycount) > h->loadlimit)
167 /* Ignore the return value. If expand fails, we should
168 * still try cramming just this value into the existing table
169 * -- we may not have memory for a larger table, but one more
170 * element may be ok. Next time we insert, we'll try expanding again.*/
173 e = (struct entry *)malloc(sizeof(struct entry));
174 if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
176 index = indexFor(h->tablelength,e->h);
179 e->next = h->table[index];
184 /*****************************************************************************/
186 hashtable_change(struct hashtable *h, void *k, void *v)
189 unsigned int hashvalue, index;
190 hashvalue = hash(h,k);
191 index = indexFor(h->tablelength,hashvalue);
195 /* Check hash value to short circuit heavier comparison */
196 if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
207 /*****************************************************************************/
208 void * /* returns value associated with key */
209 hashtable_search(struct hashtable *h, void *k)
212 unsigned int hashvalue, index;
213 hashvalue = hash(h,k);
214 index = indexFor(h->tablelength,hashvalue);
218 /* Check hash value to short circuit heavier comparison */
219 if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
225 /*****************************************************************************/
226 void * /* returns value associated with key */
227 hashtable_remove(struct hashtable *h, void *k)
229 /* TODO: consider compacting the table when the load factor drops enough,
230 * or provide a 'compact' method. */
236 unsigned int index = indexFor(h->tablelength,hash(h,k));
237 pE = &(h->table[index]);
241 if (h->eqfn(k, e->k))
256 /*****************************************************************************/
259 hashtable_destroy(struct hashtable *h, int free_values)
263 struct entry **table = h->table;
265 for (i = 0; i < h->tablelength; i++)
284 /*****************************************************************************/
285 /* hashtable_iterator - iterator constructor */
287 struct hashtable_itr *
288 hashtable_iterator(struct hashtable *h)
290 unsigned int i, tablelength;
291 struct hashtable_itr *itr = (struct hashtable_itr *)
292 malloc(sizeof(struct hashtable_itr));
293 if (NULL == itr) return NULL;
296 tablelength = h->tablelength;
297 itr->index = tablelength;
298 if (0 == h->entrycount) return itr;
300 for (i = 0; i < tablelength; i++)
302 if (NULL != h->table[i])
304 itr->e = h->table[i];
312 /*****************************************************************************/
313 /* key - return the key of the (key,value) pair at the current position */
316 hashtable_iterator_key(struct hashtable_itr *i)
321 /*****************************************************************************/
322 /* value - return the value of the (key,value) pair at the current position */
325 hashtable_iterator_value(struct hashtable_itr *i)
330 /*****************************************************************************/
331 /* advance - advance the iterator to the next element
332 * returns zero if advanced to end of table */
335 hashtable_iterator_advance(struct hashtable_itr *itr)
337 unsigned int j,tablelength;
338 struct entry **table;
340 if (NULL == itr->e) return 0; /* stupidity check */
348 tablelength = itr->h->tablelength;
349 if (tablelength <= (j = ++(itr->index)))
354 table = itr->h->table;
355 while (NULL == (next = table[j]))
357 if (++j >= tablelength)
359 itr->index = tablelength;