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