| rev |
line source |
|
Me@14
|
1 /*
|
|
seanhalle@31
|
2 * Copyright 2009 OpenSourceResearchInstitute.org
|
|
Me@14
|
3 * Licensed under GNU General Public License version 2
|
|
Me@14
|
4 *
|
|
Me@14
|
5 *
|
|
Me@14
|
6 * Author: seanhalle@yahoo.com
|
|
Me@14
|
7 */
|
|
Me@14
|
8
|
|
seanhalle@35
|
9 #include <PR__include/prhash.h>
|
|
seanhalle@35
|
10 #include <PR__include/prmalloc.h>
|
|
Me@14
|
11
|
|
seanhalle@23
|
12 HashTable *
|
|
Me@14
|
13 makeHashTable( int numHashSlots, FreeEntryContentFnPtr freeFn )
|
|
Me@14
|
14 { HashTable * retTable;
|
|
seanhalle@34
|
15 retTable = PR__malloc( sizeof( HashTable ) );
|
|
Me@14
|
16
|
|
Me@14
|
17 retTable->freeEntryContentFn = freeFn;
|
|
Me@14
|
18
|
|
seanhalle@34
|
19 retTable->entries = PR__malloc( numHashSlots * sizeof(HashEntry *) );
|
|
seanhalle@23
|
20 retTable->numEntries = 0;
|
|
seanhalle@23
|
21 retTable->tableSz = numHashSlots;
|
|
seanhalle@23
|
22
|
|
seanhalle@23
|
23 nullOutTablesArray( retTable );
|
|
seanhalle@23
|
24
|
|
seanhalle@23
|
25 return retTable;
|
|
seanhalle@23
|
26 }
|
|
seanhalle@23
|
27
|
|
seanhalle@23
|
28 void
|
|
Me@14
|
29 doubleTableSize( HashTable *table )
|
|
Me@14
|
30 { int i, oldTableSz, newTableSz;
|
|
Me@14
|
31 HashEntry *entry, *nextEntry, **oldEntries, **newEntries;
|
|
Me@14
|
32
|
|
Me@14
|
33 oldTableSz = table->tableSz;
|
|
Me@14
|
34 oldEntries = table->entries;
|
|
Me@14
|
35
|
|
seanhalle@23
|
36 newTableSz = 2 * oldTableSz;
|
|
seanhalle@34
|
37 newEntries = PR__malloc( newTableSz * sizeof(HashEntry *) );
|
|
Me@14
|
38
|
|
Me@14
|
39 table->tableSz = newTableSz;
|
|
Me@14
|
40 table->entries = newEntries;
|
|
Me@14
|
41 table->numEntries = 0; //about to add them all back!
|
|
Me@14
|
42
|
|
Me@14
|
43 // move all the entries from old to new
|
|
Me@14
|
44 for( i=0; i < oldTableSz; i++ )
|
|
Me@14
|
45 { if( oldEntries[i] != NULL )
|
|
Me@14
|
46 { entry = oldEntries[i];
|
|
Me@14
|
47 while( entry != NULL )
|
|
seanhalle@23
|
48 { nextEntry = entry->next; //save for later
|
|
Me@14
|
49 entry->next = NULL;
|
|
Me@14
|
50 putEntryIntoTable( entry, table ); //does not allocate anything
|
|
Me@14
|
51 entry = nextEntry;
|
|
Me@14
|
52 }
|
|
Me@14
|
53 }
|
|
Me@14
|
54 }
|
|
Me@14
|
55 }
|
|
Me@14
|
56
|
|
Me@14
|
57 void
|
|
Me@14
|
58 nullOutTablesArray( HashTable *table )
|
|
Me@14
|
59 { int i, tableSz;
|
|
Me@14
|
60 tableSz = table->tableSz;
|
|
Me@14
|
61 HashEntry ** entries = table->entries;
|
|
Me@14
|
62 for( i = 0; i < tableSz; i++ )
|
|
Me@14
|
63 entries[ i ] = NULL;
|
|
Me@14
|
64 }
|
|
Me@14
|
65
|
|
Me@14
|
66 unsigned int
|
|
Me@14
|
67 hashThisKey( char* s, int hashSz )
|
|
Me@14
|
68 { unsigned int h = 0;
|
|
Me@14
|
69 unsigned int i;
|
|
Me@14
|
70 hashkey_t* key = (hashkey_t*)s;
|
|
Me@14
|
71
|
|
Me@14
|
72 for(i=0 ; i<sizeof(hashkey_t); i++ )
|
|
Me@14
|
73 h = key->hashable[i] + h*31;
|
|
Me@14
|
74 return h % hashSz;
|
|
Me@14
|
75 }
|
|
Me@14
|
76
|
|
seanhalle@23
|
77 /*Copies the string that is the key*/
|
|
seanhalle@23
|
78 inline HashEntry *
|
|
seanhalle@23
|
79 makeHashEntry( char * key )
|
|
seanhalle@23
|
80 { HashEntry *hashEntry;
|
|
seanhalle@23
|
81
|
|
seanhalle@23
|
82 int32 len = strlen(key);
|
|
seanhalle@23
|
83
|
|
seanhalle@34
|
84 hashEntry = (HashEntry*) PR__malloc( sizeof( HashEntry ) );
|
|
seanhalle@23
|
85 if( hashEntry == NULL ) return NULL;
|
|
seanhalle@23
|
86
|
|
seanhalle@34
|
87 hashEntry->key = PR__malloc( len + 1 );
|
|
seanhalle@23
|
88 if( hashEntry->key == NULL ) return NULL;
|
|
seanhalle@23
|
89 memcpy( hashEntry->key, key, len + 1 );
|
|
seanhalle@23
|
90 hashEntry->next = NULL;
|
|
seanhalle@23
|
91
|
|
seanhalle@23
|
92 return hashEntry;
|
|
seanhalle@23
|
93 }
|
|
seanhalle@23
|
94
|
|
seanhalle@23
|
95
|
|
Me@14
|
96 /*Need this to be separated out, for use in both getParam and putParam
|
|
Me@14
|
97 */
|
|
Me@14
|
98 HashEntry *
|
|
Me@14
|
99 getEntryFromTable( char *key, HashTable * table )
|
|
seanhalle@23
|
100 { uint32
|
|
Me@14
|
101 hashIndex = hashThisKey( key, table->tableSz );
|
|
Me@14
|
102 HashEntry*
|
|
Me@14
|
103 hashEntry = table->entries[ hashIndex ];
|
|
Me@14
|
104 for( ; hashEntry != NULL; hashEntry = hashEntry->next )
|
|
Me@14
|
105 {
|
|
seanhalle@23
|
106 if( strcmp( hashEntry->key, key ) == 0 )
|
|
Me@14
|
107 return hashEntry;
|
|
Me@14
|
108 }
|
|
Me@14
|
109 return NULL;
|
|
Me@14
|
110 }
|
|
Me@14
|
111
|
|
Me@14
|
112 void *
|
|
Me@14
|
113 getValueFromTable( char *key, HashTable * table )
|
|
Me@14
|
114 { HashEntry *entry;
|
|
Me@14
|
115 entry = getEntryFromTable( key, table );
|
|
Me@14
|
116 if( entry == NULL ) return NULL;
|
|
Me@14
|
117
|
|
Me@14
|
118 return entry->content;
|
|
Me@14
|
119 }
|
|
Me@14
|
120
|
|
Me@14
|
121 /*If key already has a value, clobber the old one and replace it
|
|
Me@14
|
122 */
|
|
Me@14
|
123 int
|
|
Me@14
|
124 addValueIntoTable( char* key, void *content, HashTable *table )
|
|
Me@14
|
125 { unsigned int hashIdx;
|
|
Me@14
|
126 HashEntry* hashEntry;
|
|
Me@14
|
127
|
|
Me@14
|
128 hashEntry = getEntryFromTable( key, table );
|
|
Me@14
|
129 if( hashEntry == NULL )
|
|
Me@14
|
130 { hashIdx = hashThisKey( key, table->tableSz );
|
|
seanhalle@23
|
131 hashEntry = makeHashEntry( key );
|
|
Me@14
|
132 hashEntry->next = (table->entries)[hashIdx];
|
|
Me@14
|
133 (table->entries)[hashIdx] = hashEntry;
|
|
Me@14
|
134 table->numEntries += 1;
|
|
Me@14
|
135 if( table->tableSz < table->numEntries ) doubleTableSize( table );
|
|
Me@14
|
136 }
|
|
Me@14
|
137 else
|
|
Me@14
|
138 { (*(table->freeEntryContentFn))( hashEntry->content );
|
|
Me@14
|
139 }
|
|
Me@14
|
140 hashEntry->content = content;
|
|
Me@14
|
141 return 1;
|
|
Me@14
|
142 }
|
|
Me@14
|
143
|
|
seanhalle@23
|
144
|
|
Me@14
|
145 int
|
|
Me@14
|
146 putEntryIntoTable( HashEntry *entry, HashTable *table )
|
|
Me@14
|
147 { unsigned int hashIdx;
|
|
Me@14
|
148 HashEntry* testEntry;
|
|
Me@14
|
149
|
|
Me@14
|
150 testEntry = getEntryFromTable( entry->key, table );
|
|
Me@14
|
151 if( testEntry == NULL )
|
|
Me@14
|
152 { hashIdx = hashThisKey( entry->key, table->tableSz );
|
|
Me@14
|
153 entry->next = (table->entries)[hashIdx];
|
|
Me@14
|
154 (table->entries)[hashIdx] = entry;
|
|
Me@14
|
155 table->numEntries += 1;
|
|
Me@14
|
156 if( table->tableSz < table->numEntries ) doubleTableSize( table );
|
|
Me@14
|
157 }
|
|
Me@14
|
158 else
|
|
Me@14
|
159 { (*(table->freeEntryContentFn))( testEntry->content );
|
|
seanhalle@23
|
160 //being lazy -- will create bug in code that relies on having ptr
|
|
seanhalle@23
|
161 // to elem given to insert into table!
|
|
Me@14
|
162 testEntry->content = entry->content;
|
|
Me@14
|
163 entry->content = NULL;
|
|
Me@14
|
164 freeHashEntryButNotContent( entry );
|
|
Me@14
|
165 }
|
|
Me@14
|
166 return 1;
|
|
Me@14
|
167 }
|
|
Me@14
|
168
|
|
Me@14
|
169 /*Better version
|
|
Me@14
|
170 */
|
|
Me@14
|
171 void
|
|
Me@14
|
172 untested_putEntryIntoTable( HashEntry *entry, HashTable * table )
|
|
Me@14
|
173 { HashEntry *testEntry, *prevEntry = NULL;
|
|
Me@14
|
174 unsigned int
|
|
Me@14
|
175 hashIndex = hashThisKey( entry->key, table->tableSz );
|
|
Me@14
|
176
|
|
Me@14
|
177 testEntry = table->entries[ hashIndex ];
|
|
Me@14
|
178 for( ; testEntry != NULL; testEntry = testEntry->next )
|
|
seanhalle@23
|
179 { if( strcmp( testEntry->key, entry->key ) == 0 )
|
|
Me@14
|
180 { if( prevEntry == NULL )
|
|
Me@14
|
181 { table->entries[hashIndex] = entry;
|
|
Me@14
|
182 entry->next = testEntry->next;
|
|
Me@14
|
183 }
|
|
Me@14
|
184 else
|
|
Me@14
|
185 { prevEntry->next = entry;
|
|
Me@14
|
186 entry->next = testEntry->next;
|
|
Me@14
|
187 }
|
|
Me@14
|
188 freeHashEntryUsing( testEntry, table ); //frees content too!
|
|
Me@14
|
189 return;
|
|
Me@14
|
190 }
|
|
Me@14
|
191 }
|
|
Me@14
|
192 //wasn't found, so insert
|
|
Me@14
|
193 entry->next = table->entries[hashIndex];
|
|
Me@14
|
194 table->entries[hashIndex] = entry;
|
|
Me@14
|
195 }
|
|
Me@14
|
196
|
|
Me@14
|
197
|
|
seanhalle@23
|
198 bool8
|
|
Me@14
|
199 deleteEntryFromTable( char *key, HashTable *table )
|
|
Me@14
|
200 { HashEntry *hashEntry;
|
|
seanhalle@23
|
201 HashEntry **addrOfPrevPtr;
|
|
Me@14
|
202 unsigned int hashIndex;
|
|
Me@14
|
203
|
|
Me@14
|
204 hashIndex = hashThisKey( key, table->tableSz );
|
|
seanhalle@23
|
205 addrOfPrevPtr = &( table->entries[ hashIndex ] );//for removing node
|
|
seanhalle@23
|
206 hashEntry = *addrOfPrevPtr; //already did work, might as well use it
|
|
Me@14
|
207 while( hashEntry != NULL )
|
|
seanhalle@23
|
208 { if( strcmp( hashEntry->key, key ) == 0 )
|
|
Me@14
|
209 {
|
|
seanhalle@23
|
210 *addrOfPrevPtr = hashEntry->next; //remove node from list
|
|
Me@14
|
211 //TODO: Free the contents of entry?
|
|
Me@14
|
212 freeHashEntryButNotContent( hashEntry );
|
|
Me@14
|
213 table->numEntries -= 1;
|
|
Me@14
|
214 return TRUE;
|
|
Me@14
|
215 }
|
|
seanhalle@23
|
216 addrOfPrevPtr = &( hashEntry->next );
|
|
seanhalle@23
|
217 hashEntry = *addrOfPrevPtr;
|
|
Me@14
|
218 }
|
|
Me@14
|
219 return FALSE;
|
|
Me@14
|
220 }
|
|
Me@14
|
221
|
|
seanhalle@31
|
222 /*Frees hash table struct, all entry strucs, and even the contents of each
|
|
seanhalle@31
|
223 * entry.
|
|
seanhalle@31
|
224 */
|
|
Me@14
|
225 void
|
|
Me@14
|
226 freeHashTable( HashTable *table )
|
|
Me@14
|
227 { int i;
|
|
Me@14
|
228 HashEntry *hashEntry, *temp, **entries;
|
|
Me@14
|
229
|
|
Me@14
|
230 entries = table->entries;
|
|
Me@14
|
231 for( i=0; i < table->tableSz; i++ )
|
|
Me@14
|
232 { if( entries[i] != NULL )
|
|
Me@14
|
233 { hashEntry = entries[i];
|
|
Me@14
|
234 while( hashEntry != NULL )
|
|
Me@14
|
235 {
|
|
Me@14
|
236 temp = hashEntry->next;
|
|
Me@14
|
237 freeHashEntryUsing( hashEntry, table );
|
|
Me@14
|
238 hashEntry = temp;
|
|
Me@14
|
239 }
|
|
Me@14
|
240 }
|
|
Me@14
|
241 }
|
|
Me@14
|
242 }
|
|
Me@14
|
243
|
|
Me@14
|
244 void
|
|
Me@14
|
245 freeHashEntryUsing( HashEntry *entry, HashTable *table )
|
|
Me@14
|
246 {
|
|
Me@14
|
247 if( entry->content != NULL )
|
|
Me@14
|
248 (*(table->freeEntryContentFn))( entry->content );
|
|
seanhalle@34
|
249 PR__free( entry->key ); //was PR__malloc'd above, so free it
|
|
seanhalle@34
|
250 PR__free( entry );
|
|
seanhalle@34
|
251 }
|
|
seanhalle@34
|
252
|
|
seanhalle@34
|
253 /* obsolete -- delete
|
|
seanhalle@34
|
254
|
|
seanhalle@34
|
255 HashTable *
|
|
seanhalle@34
|
256 makeHashTable_WL( int numHashSlots, FreeEntryContentFnPtr freeFn )
|
|
seanhalle@34
|
257 { HashTable * retTable;
|
|
seanhalle@34
|
258 retTable = PR__malloc( sizeof( HashTable ) );
|
|
seanhalle@34
|
259
|
|
seanhalle@34
|
260 retTable->freeEntryContentFn = freeFn;
|
|
seanhalle@34
|
261
|
|
seanhalle@34
|
262 retTable->entries = PR__malloc( numHashSlots * sizeof(HashEntry *) );
|
|
seanhalle@34
|
263 retTable->numEntries = 0;
|
|
seanhalle@34
|
264 retTable->tableSz = numHashSlots;
|
|
seanhalle@34
|
265
|
|
seanhalle@34
|
266 nullOutTablesArray( retTable );
|
|
seanhalle@34
|
267
|
|
seanhalle@34
|
268 return retTable;
|
|
Me@14
|
269 }
|
|
Me@14
|
270
|
|
Me@14
|
271 void
|
|
seanhalle@23
|
272 freeHashEntryUsing_WL( HashEntry *entry, HashTable *table )
|
|
seanhalle@23
|
273 {
|
|
seanhalle@23
|
274 if( entry->content != NULL )
|
|
seanhalle@23
|
275 (*(table->freeEntryContentFn))( entry->content );
|
|
seanhalle@34
|
276 PR__free( entry->key ); //was PR__malloc'd above, so free it
|
|
seanhalle@34
|
277 PR__free( entry );
|
|
seanhalle@23
|
278 }
|
|
seanhalle@23
|
279 void
|
|
seanhalle@23
|
280 freeHashTable_WL( HashTable *table )
|
|
seanhalle@23
|
281 { int i;
|
|
seanhalle@23
|
282 HashEntry *hashEntry, *temp, **entries;
|
|
seanhalle@23
|
283
|
|
seanhalle@23
|
284 entries = table->entries;
|
|
seanhalle@23
|
285 for( i=0; i < table->tableSz; i++ )
|
|
seanhalle@23
|
286 { if( entries[i] != NULL )
|
|
seanhalle@23
|
287 { hashEntry = entries[i];
|
|
seanhalle@23
|
288 while( hashEntry != NULL )
|
|
seanhalle@23
|
289 {
|
|
seanhalle@23
|
290 temp = hashEntry->next;
|
|
seanhalle@23
|
291 freeHashEntryUsing_WL( hashEntry, table );
|
|
seanhalle@23
|
292 hashEntry = temp;
|
|
seanhalle@23
|
293 }
|
|
seanhalle@23
|
294 }
|
|
seanhalle@23
|
295 }
|
|
seanhalle@23
|
296 }
|
|
seanhalle@34
|
297 */
|
|
seanhalle@23
|
298
|
|
seanhalle@23
|
299 void
|
|
Me@14
|
300 freeHashEntryButNotContent( HashEntry *entry )
|
|
Me@14
|
301 {
|
|
seanhalle@34
|
302 PR__free( entry->key ); //was PR__malloc'd above, so free it
|
|
seanhalle@34
|
303 PR__free( entry );
|
|
seanhalle@23
|
304 }
|
|
seanhalle@23
|
305
|
|
seanhalle@23
|
306
|
|
seanhalle@23
|
307
|
|
seanhalle@23
|
308
|
|
seanhalle@23
|
309 //======================= 32 bit integer key version ======================
|
|
seanhalle@23
|
310
|
|
seanhalle@23
|
311 /*key is array of uint32, with first entry being the num ints in key.
|
|
seanhalle@23
|
312 * that means size of key is content of first entry times 4, plus the
|
|
seanhalle@23
|
313 * size of first entry itself, which is another 4*/
|
|
seanhalle@23
|
314 #define sizeOfKey(key) key[0]*4 + 4
|
|
seanhalle@23
|
315
|
|
seanhalle@23
|
316
|
|
seanhalle@23
|
317 HashTable *
|
|
seanhalle@23
|
318 makeHashTable32( int powerOf2OfSz, FreeEntryContentFnPtr freeFn )
|
|
seanhalle@23
|
319 { HashTable * retTable;
|
|
seanhalle@23
|
320 int32 numHashSlots;
|
|
seanhalle@23
|
321
|
|
seanhalle@34
|
322 retTable = PR__malloc( sizeof( HashTable ) );
|
|
seanhalle@23
|
323
|
|
seanhalle@23
|
324 numHashSlots = 1 << powerOf2OfSz;
|
|
seanhalle@23
|
325 retTable->hashMask = 0xffffffff >> 32 - powerOf2OfSz;
|
|
seanhalle@23
|
326 retTable->prevHash = (int32)rand();
|
|
seanhalle@23
|
327
|
|
seanhalle@23
|
328 retTable->freeEntryContentFn = freeFn;
|
|
seanhalle@23
|
329
|
|
seanhalle@34
|
330 retTable->entries = PR__malloc( numHashSlots * sizeof(HashEntry *));
|
|
seanhalle@23
|
331 retTable->numEntries = 0;
|
|
seanhalle@23
|
332 retTable->tableSz = numHashSlots;
|
|
seanhalle@23
|
333
|
|
seanhalle@23
|
334 nullOutTablesArray( retTable );
|
|
seanhalle@23
|
335
|
|
seanhalle@23
|
336 return retTable;
|
|
seanhalle@23
|
337 }
|
|
seanhalle@23
|
338
|
|
seanhalle@23
|
339 HashTable *
|
|
seanhalle@23
|
340 makeDefaultSizeHashTable32( FreeEntryContentFnPtr freeFn )
|
|
seanhalle@23
|
341 {
|
|
seanhalle@23
|
342 return makeHashTable32( DEFAULT_POWER_OF_2_TABLE_SIZE, freeFn );
|
|
seanhalle@23
|
343 }
|
|
seanhalle@23
|
344
|
|
seanhalle@23
|
345 HashEntry *
|
|
seanhalle@23
|
346 makeHashEntry32( uint32 * key )
|
|
seanhalle@23
|
347 { HashEntry *hashEntry;
|
|
seanhalle@23
|
348
|
|
seanhalle@34
|
349 hashEntry = (HashEntry*) PR__malloc( sizeof( HashEntry ) );
|
|
seanhalle@23
|
350 if( hashEntry == NULL ) return NULL;
|
|
seanhalle@34
|
351 hashEntry->key = PR__malloc( sizeOfKey(key) );
|
|
seanhalle@23
|
352 if( hashEntry->key == NULL ) return NULL;
|
|
seanhalle@23
|
353 memcpy( hashEntry->key, key, sizeOfKey(key) );
|
|
seanhalle@23
|
354 hashEntry->next = NULL;
|
|
seanhalle@23
|
355
|
|
seanhalle@23
|
356 return hashEntry;
|
|
seanhalle@23
|
357 }
|
|
seanhalle@23
|
358
|
|
seanhalle@23
|
359
|
|
seanhalle@23
|
360
|
|
seanhalle@23
|
361 int32
|
|
seanhalle@23
|
362 putEntryIntoTable32( HashEntry *entry, HashTable *table )
|
|
seanhalle@23
|
363 { unsigned int hashIdx;
|
|
seanhalle@23
|
364 HashEntry* testEntry;
|
|
seanhalle@23
|
365
|
|
seanhalle@23
|
366 testEntry = getEntryFromTable32( (uint32 *)entry->key, table );
|
|
seanhalle@23
|
367 if( testEntry == NULL ) //no entry w/key, so add passed-in as list-head
|
|
seanhalle@23
|
368 { hashIdx = hashThisKey32( entry->key, table->tableSz );
|
|
seanhalle@23
|
369 entry->next = (table->entries)[hashIdx];
|
|
seanhalle@23
|
370 (table->entries)[hashIdx] = entry;
|
|
seanhalle@23
|
371 table->numEntries += 1;
|
|
seanhalle@23
|
372 //keep num entries less than half the num indexes in table
|
|
seanhalle@23
|
373 if( table->numEntries > (table->tableSz >>1) ) doubleTableSize(table);
|
|
seanhalle@23
|
374 }
|
|
seanhalle@23
|
375 else //entry w/key already exists, so free content, then replace then
|
|
seanhalle@23
|
376 // free the passed-in entry, leaving the entry already in table
|
|
seanhalle@23
|
377 { (*(table->freeEntryContentFn))( testEntry->content );
|
|
seanhalle@23
|
378 //being lazy -- will create bug in code that relies on having ptr
|
|
seanhalle@23
|
379 // to elem given to insert into table!
|
|
seanhalle@23
|
380 testEntry->content = entry->content;
|
|
seanhalle@23
|
381 entry->content = NULL;
|
|
seanhalle@23
|
382 freeHashEntryButNotContent( entry );
|
|
seanhalle@23
|
383 }
|
|
seanhalle@23
|
384 return 1;
|
|
seanhalle@23
|
385 }
|
|
seanhalle@23
|
386
|
|
seanhalle@23
|
387
|
|
seanhalle@23
|
388 void
|
|
seanhalle@23
|
389 doubleTableSize32( HashTable *table )
|
|
seanhalle@23
|
390 { int i, oldTableSz, newTableSz;
|
|
seanhalle@23
|
391 HashEntry *entry, *nextEntry, **oldEntries, **newEntries;
|
|
seanhalle@23
|
392
|
|
seanhalle@23
|
393 oldTableSz = table->tableSz;
|
|
seanhalle@23
|
394 oldEntries = table->entries;
|
|
seanhalle@23
|
395
|
|
seanhalle@23
|
396 newTableSz = 2 * oldTableSz;
|
|
seanhalle@34
|
397 newEntries = PR__malloc( newTableSz * sizeof(HashEntry *) );
|
|
seanhalle@23
|
398
|
|
seanhalle@23
|
399 table->tableSz = newTableSz;
|
|
seanhalle@23
|
400 table->entries = newEntries;
|
|
seanhalle@23
|
401 table->numEntries = 0; //about to add them all back!
|
|
seanhalle@23
|
402
|
|
seanhalle@23
|
403 // move all the entries from old to new
|
|
seanhalle@23
|
404 for( i=0; i < oldTableSz; i++ )
|
|
seanhalle@23
|
405 { if( oldEntries[i] != NULL )
|
|
seanhalle@23
|
406 { entry = oldEntries[i];
|
|
seanhalle@23
|
407 while( entry != NULL )
|
|
seanhalle@23
|
408 { nextEntry = entry->next; //save for later
|
|
seanhalle@23
|
409 entry->next = NULL; //null before, so can chain in new
|
|
seanhalle@23
|
410 putEntryIntoTable32( entry, table ); //doesn't allocate anything
|
|
seanhalle@23
|
411 entry = nextEntry;
|
|
seanhalle@23
|
412 }
|
|
seanhalle@23
|
413 }
|
|
seanhalle@23
|
414 }
|
|
seanhalle@23
|
415 }
|
|
seanhalle@23
|
416
|
|
seanhalle@23
|
417 /*The key is a self-sized array of 32 bit unsigned ints, with the first
|
|
seanhalle@23
|
418 * entry being the number of ints in the key, which makes up the rest of
|
|
seanhalle@23
|
419 * the array.*/
|
|
seanhalle@23
|
420 int32
|
|
seanhalle@23
|
421 hashThisKey32( uint32 *key, HashTable *hashTable )
|
|
seanhalle@23
|
422 { int32 hashOfKey;
|
|
seanhalle@23
|
423
|
|
seanhalle@23
|
424 //the hash function takes addr of start of key array, plus num int32s,
|
|
seanhalle@23
|
425 hashOfKey = jenkHash32( &key[1], *key );
|
|
seanhalle@23
|
426 hashTable->prevHash = hashOfKey;
|
|
seanhalle@23
|
427
|
|
seanhalle@23
|
428 /*The hash is a full 32 bits, but only want hashes that fall within
|
|
seanhalle@23
|
429 * the size of the table. So, mask off the higher bits. */
|
|
seanhalle@23
|
430 return ( hashTable->hashMask & hashOfKey ); //reduce to size of table
|
|
seanhalle@23
|
431 }
|
|
seanhalle@23
|
432
|
|
seanhalle@23
|
433
|
|
seanhalle@23
|
434 /*The first entry of key says the size of the key, while key itself is the
|
|
seanhalle@23
|
435 * rest of the integers in the array
|
|
seanhalle@23
|
436 */
|
|
seanhalle@23
|
437 HashEntry *
|
|
seanhalle@23
|
438 getEntryFromTable32( uint32 *key, HashTable * table )
|
|
seanhalle@23
|
439 { unsigned int
|
|
seanhalle@23
|
440 hashIndex = hashThisKey32( key, table );
|
|
seanhalle@23
|
441 HashEntry*
|
|
seanhalle@23
|
442 hashEntry = table->entries[ hashIndex ];
|
|
seanhalle@23
|
443 for( ; hashEntry != NULL; hashEntry = hashEntry->next )
|
|
seanhalle@23
|
444 {
|
|
seanhalle@23
|
445 if( memcmp( hashEntry->key, key, sizeOfKey(key) ) == 0 )
|
|
seanhalle@23
|
446 return hashEntry;
|
|
seanhalle@23
|
447 }
|
|
seanhalle@23
|
448 return NULL;
|
|
seanhalle@23
|
449 }
|
|
seanhalle@23
|
450
|
|
seanhalle@23
|
451 void *
|
|
seanhalle@23
|
452 getValueFromTable32( uint32 *key, HashTable * table )
|
|
seanhalle@23
|
453 { HashEntry *entry;
|
|
seanhalle@23
|
454 entry = getEntryFromTable32( key, table );
|
|
seanhalle@23
|
455 if( entry == NULL ) return NULL;
|
|
seanhalle@23
|
456
|
|
seanhalle@23
|
457 return entry->content;
|
|
seanhalle@23
|
458 }
|
|
seanhalle@23
|
459
|
|
seanhalle@24
|
460 /*Returns NULL if failed to insert, else returns ptr to hash entry
|
|
seanhalle@24
|
461 * NOTE: does a copy of the key, so key can be alloc'd on stack */
|
|
seanhalle@23
|
462 HashEntry *
|
|
seanhalle@23
|
463 addValueIntoTable32( uint32* key, void *content, HashTable *table )
|
|
seanhalle@23
|
464 { unsigned int hashIdx;
|
|
seanhalle@23
|
465 HashEntry* hashEntry;
|
|
seanhalle@23
|
466
|
|
seanhalle@23
|
467 hashEntry = getEntryFromTable32( key, table );
|
|
seanhalle@23
|
468 if( hashEntry == NULL )
|
|
seanhalle@23
|
469 { hashIdx = hashThisKey32( key, table );
|
|
seanhalle@23
|
470 hashEntry = makeHashEntry32( key );
|
|
seanhalle@23
|
471 hashEntry->next = (table->entries)[hashIdx];
|
|
seanhalle@23
|
472 (table->entries)[hashIdx] = hashEntry;
|
|
seanhalle@23
|
473 table->numEntries += 1;
|
|
seanhalle@23
|
474 //Check if need to make bigger -- keep half-full (hence ">> 1")
|
|
seanhalle@23
|
475 if( table->numEntries > table->tableSz >>1 ) doubleTableSize( table );
|
|
seanhalle@23
|
476 }
|
|
seanhalle@23
|
477 else
|
|
seanhalle@23
|
478 { (*(table->freeEntryContentFn))( hashEntry->content );
|
|
seanhalle@23
|
479 }
|
|
seanhalle@23
|
480 hashEntry->content = content;
|
|
seanhalle@23
|
481 return hashEntry;
|
|
seanhalle@23
|
482 }
|
|
seanhalle@23
|
483
|
|
seanhalle@23
|
484
|
|
seanhalle@23
|
485 bool32
|
|
seanhalle@23
|
486 deleteEntryFromTable32( uint32 *key, HashTable *table )
|
|
seanhalle@23
|
487 { HashEntry *hashEntry;
|
|
seanhalle@23
|
488 HashEntry **addrOfPrevPtr;
|
|
seanhalle@23
|
489 unsigned int hashIndex;
|
|
seanhalle@23
|
490
|
|
seanhalle@23
|
491 hashIndex = hashThisKey32( key, table );
|
|
seanhalle@23
|
492 hashEntry = table->entries[ hashIndex ];
|
|
seanhalle@23
|
493 //go down the chained list, checking all with this hash value
|
|
seanhalle@23
|
494 addrOfPrevPtr = &( table->entries[hashIndex] ); //for removing a node
|
|
seanhalle@23
|
495 hashEntry = *addrOfPrevPtr; //did ptr chasing, might as well use it
|
|
seanhalle@23
|
496 while( hashEntry != NULL )
|
|
seanhalle@23
|
497 { if( memcmp( hashEntry->key, key, sizeOfKey(key) ) == 0 )
|
|
seanhalle@23
|
498 { *addrOfPrevPtr = hashEntry->next; //remove node from list
|
|
seanhalle@23
|
499 freeHashEntryButNotContent( hashEntry );
|
|
seanhalle@23
|
500 table->numEntries -= 1;
|
|
seanhalle@23
|
501 return TRUE;
|
|
seanhalle@23
|
502 }
|
|
seanhalle@23
|
503 addrOfPrevPtr = &(hashEntry->next); //chg content of *this* to remove
|
|
seanhalle@23
|
504 hashEntry = *addrOfPrevPtr; //cheaper than hashEntry->next
|
|
seanhalle@23
|
505 }
|
|
seanhalle@23
|
506 return FALSE;
|
|
seanhalle@23
|
507 }
|
|
seanhalle@23
|
508
|