exip  Alpha 0.5.4
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hashtable.c
Go to the documentation of this file.
1 /* Copyright (C) 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
2 /* @par[Revision] $Id: hashtable.c 310 2013-08-05 09:43:03Z kjussakov $
3  **/
4 
5 #include "hashtable.h"
6 #include "hashtable_private.h"
7 #include "procTypes.h"
8 
9 #define CEIL(VARIABLE) ( ((VARIABLE) - (unsigned int)(VARIABLE))==0 ? (unsigned int)(VARIABLE) : (unsigned int) (VARIABLE)+1 )
10 
11 /*
12 Credit for primes table: Aaron Krowne
13  http://br.endernet.org/~akrowne/
14  http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
15 */
16 static const uint32_t primes[] = {
17 53, 97, 193, 389,
18 769, 1543, 3079, 6151,
19 12289, 24593, 49157, 98317,
20 196613, 393241, 786433, 1572869,
21 3145739, 6291469, 12582917, 25165843,
22 50331653, 100663319, 201326611, 402653189,
23 805306457, 1610612741
24 };
25 const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
26 const float max_load_factor = 0.65F;
27 
29 {
30  char* tmp = (char*) str.str;
31  uint32_t hash = 5381;
32  unsigned int i = 0;
33 
34  for(i = 0; i < sizeof(CharType)*str.length; tmp++, i++)
35  {
36  hash = ((hash << 5) + hash) + (*tmp);
37  }
38 
39  return hash;
40 }
41 
42 /*****************************************************************************/
43 
44 struct hashtable * create_hashtable(unsigned int minsize,
45  uint32_t (*hashfn) (String key),
46  boolean (*eqfn) (const String str1, const String str2))
47 {
48  struct hashtable *h;
49  unsigned int pindex, size = primes[0];
50  /* Check requested hashtable isn't too large */
51  if (minsize > MAX_HASH_TABLE_SIZE) return NULL;
52  /* Enforce size as prime */
53  for (pindex=0; pindex < prime_table_length; pindex++) {
54  if (primes[pindex] >= minsize) { size = primes[pindex]; break; }
55  }
56  h = (struct hashtable *)EXIP_MALLOC(sizeof(struct hashtable));
57  if (NULL == h) return NULL; /*oom*/
58  h->table = (struct entry **)EXIP_MALLOC(sizeof(struct entry*) * size);
59  if (NULL == h->table) { EXIP_MFREE(h); return NULL; } /*oom*/
60  memset(h->table, 0, size * sizeof(struct entry *));
61  h->tablelength = size;
62  h->primeindex = pindex;
63  h->entrycount = 0;
64  h->hashfn = hashfn;
65  h->eqfn = eqfn;
66  h->loadlimit = CEIL(size * max_load_factor);
67  return h;
68 }
69 
70 /*****************************************************************************/
71 
72 // Currently this function is not used. Some performance tests must be written
73 // and performed to show if it is better when it is used
74 //uint32_t hash(struct hashtable *h, void *k, unsigned int len)
75 //{
76 // /* Aim to protect against poor hash functions by adding logic here
77 // * - logic taken from java 1.4 hashtable source */
78 // uint32_t i = h->hashfn(k, len);
79 // i += ~(i << 9);
80 // i ^= ((i >> 14) | (i << 18)); /* >>> */
81 // i += (i << 4);
82 // i ^= ((i >> 10) | (i << 22)); /* >>> */
83 // return i;
84 //}
85 
86 /*****************************************************************************/
87 static int hashtable_expand(struct hashtable *h)
88 {
89  /* Double the size of the table to accommodate more entries */
90  struct entry **newtable;
91  struct entry *e;
92  struct entry **pE;
93  unsigned int newsize, i, index;
94  /* Check we're not hitting max capacity */
95  if (h->primeindex == (prime_table_length - 1) || primes[h->primeindex + 1] > MAX_HASH_TABLE_SIZE) return 0;
96  newsize = primes[++(h->primeindex)];
97 
98  newtable = (struct entry **)EXIP_MALLOC(sizeof(struct entry*) * newsize);
99  if (NULL != newtable)
100  {
101  memset(newtable, 0, newsize * sizeof(struct entry *));
102  /* This algorithm is not 'stable'. ie. it reverses the list
103  * when it transfers entries between the tables */
104  for (i = 0; i < h->tablelength; i++) {
105  while (NULL != (e = h->table[i])) {
106  h->table[i] = e->next;
107  index = indexFor(newsize,e->hash);
108  e->next = newtable[index];
109  newtable[index] = e;
110  }
111  }
112  EXIP_MFREE(h->table);
113  h->table = newtable;
114  }
115  /* Plan B: realloc instead */
116  else
117  {
118  newtable = (struct entry **) EXIP_REALLOC(h->table, newsize * sizeof(struct entry *));
119  if (NULL == newtable) { (h->primeindex)--; return 0; }
120  h->table = newtable;
121  memset(newtable[h->tablelength], 0, newsize - h->tablelength);
122  for (i = 0; i < h->tablelength; i++) {
123  for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
124  index = indexFor(newsize,e->hash);
125  if (index == i)
126  {
127  pE = &(e->next);
128  }
129  else
130  {
131  *pE = e->next;
132  e->next = newtable[index];
133  newtable[index] = e;
134  }
135  }
136  }
137  }
138  h->tablelength = newsize;
139  h->loadlimit = CEIL(newsize * max_load_factor);
140  return -1;
141 }
142 
143 /*****************************************************************************/
144 unsigned int hashtable_count(struct hashtable *h)
145 {
146  return h->entrycount;
147 }
148 
149 /*****************************************************************************/
151 {
152  /* This method allows duplicate keys - but they shouldn't be used */
153  unsigned int index;
154  struct entry *e;
155  if (++(h->entrycount) > h->loadlimit)
156  {
157  /* Ignore the return value. If expand fails, we should
158  * still try cramming just this value into the existing table
159  * -- we may not have memory for a larger table, but one more
160  * element may be ok. Next time we insert, we'll try expanding again.*/
161  hashtable_expand(h);
162  }
163  e = (struct entry *)EXIP_MALLOC(sizeof(struct entry));
164  if (NULL == e) { --(h->entrycount); return EXIP_MEMORY_ALLOCATION_ERROR; } /*oom*/
165  e->hash = h->hashfn(key); // hash(h,k, len);
166  index = indexFor(h->tablelength,e->hash);
167  e->key = key;
168  e->value = value;
169  e->next = h->table[index];
170  h->table[index] = e;
171  return EXIP_OK;
172 }
173 
174 /*****************************************************************************/
176 {
177  struct entry *e;
178  uint32_t hashvalue;
179  unsigned int index;
180  hashvalue = h->hashfn(key); // hash(h,k, len);
181  index = indexFor(h->tablelength,hashvalue);
182  e = h->table[index];
183  while (NULL != e)
184  {
185  /* Check hash value to short circuit heavier comparison */
186  if ((hashvalue == e->hash) && h->eqfn(key, e->key)) return e->value;
187  e = e->next;
188  }
189  return INDEX_MAX;
190 }
191 
192 /*****************************************************************************/
194 {
195  /* TODO: consider compacting the table when the load factor drops enough,
196  * or provide a 'compact' method. */
197 
198  struct entry *e;
199  struct entry **pE;
200  Index value;
201  uint32_t hashvalue;
202  unsigned int index;
203 
204  hashvalue = h->hashfn(key); // hash(h,k, len);
205  index = indexFor(h->tablelength, hashvalue);
206  pE = &(h->table[index]);
207  e = *pE;
208  while (NULL != e)
209  {
210  /* Check hash value to short circuit heavier comparison */
211  if (hashvalue == e->hash && h->eqfn(key, e->key))
212  {
213  *pE = e->next;
214  h->entrycount--;
215  value = e->value;
216  // freekey(e->key);
217  EXIP_MFREE(e);
218  return value;
219  }
220  pE = &(e->next);
221  e = e->next;
222  }
223  return INDEX_MAX;
224 }
225 
226 /*****************************************************************************/
227 /* destroy */
229 {
230  unsigned int i;
231  struct entry *e, *f;
232  struct entry **table = h->table;
233  for (i = 0; i < h->tablelength; i++)
234  {
235  e = table[i];
236  while (NULL != e)
237  { f = e; e = e->next; EXIP_MFREE(f); }
238  }
239  EXIP_MFREE(h->table);
240  EXIP_MFREE(h);
241 }
242 
243 /*
244  * Copyright (c) 2002, Christopher Clark
245  * All rights reserved.
246  *
247  * Redistribution and use in source and binary forms, with or without
248  * modification, are permitted provided that the following conditions
249  * are met:
250  *
251  * * Redistributions of source code must retain the above copyright
252  * notice, this list of conditions and the following disclaimer.
253  *
254  * * Redistributions in binary form must reproduce the above copyright
255  * notice, this list of conditions and the following disclaimer in the
256  * documentation and/or other materials provided with the distribution.
257  *
258  * * Neither the name of the original author; nor the names of any contributors
259  * may be used to endorse or promote products derived from this software
260  * without specific prior written permission.
261  *
262  *
263  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
264  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
265  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
266  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
267  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
268  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
269  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
270  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
271  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
272  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
273  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274 */