comparison PrivateHash.c @ 23:ac99f4a8ce22

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