Mercurial > cgi-bin > hgwebdir.cgi > VMS > C_Libraries > Hash_impl
changeset 23:ac99f4a8ce22 MC_shared
First working version
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Wed, 06 Jun 2012 18:00:58 -0700 |
| parents | f5972b1ddb29 |
| children | b032601956bb |
| files | PrivateHash.c PrivateHash.h |
| diffstat | 2 files changed, 317 insertions(+), 28 deletions(-) [+] |
line diff
1.1 --- a/PrivateHash.c Tue Mar 13 18:31:05 2012 -0700 1.2 +++ b/PrivateHash.c Wed Jun 06 18:00:58 2012 -0700 1.3 @@ -9,7 +9,7 @@ 1.4 #include "PrivateHash.h" 1.5 1.6 1.7 - HashTable * 1.8 +HashTable * 1.9 makeHashTable( int numHashSlots, FreeEntryContentFnPtr freeFn ) 1.10 { HashTable * retTable; 1.11 retTable = VMS_int__malloc( sizeof( HashTable ) ); 1.12 @@ -25,7 +25,23 @@ 1.13 return retTable; 1.14 } 1.15 1.16 - void 1.17 +HashTable * 1.18 +makeHashTable_WL( int numHashSlots, FreeEntryContentFnPtr freeFn ) 1.19 + { HashTable * retTable; 1.20 + retTable = VMS_WL__malloc( sizeof( HashTable ) ); 1.21 + 1.22 + retTable->freeEntryContentFn = freeFn; 1.23 + 1.24 + retTable->entries = VMS_int__malloc( numHashSlots * sizeof(HashEntry *) ); 1.25 + retTable->numEntries = 0; 1.26 + retTable->tableSz = numHashSlots; 1.27 + 1.28 + nullOutTablesArray( retTable ); 1.29 + 1.30 + return retTable; 1.31 + } 1.32 + 1.33 +void 1.34 doubleTableSize( HashTable *table ) 1.35 { int i, oldTableSz, newTableSz; 1.36 HashEntry *entry, *nextEntry, **oldEntries, **newEntries; 1.37 @@ -33,7 +49,7 @@ 1.38 oldTableSz = table->tableSz; 1.39 oldEntries = table->entries; 1.40 1.41 - newTableSz = 2 * oldTableSz + 1; 1.42 + newTableSz = 2 * oldTableSz; 1.43 newEntries = VMS_int__malloc( newTableSz * sizeof(HashEntry *) ); 1.44 1.45 table->tableSz = newTableSz; 1.46 @@ -45,7 +61,7 @@ 1.47 { if( oldEntries[i] != NULL ) 1.48 { entry = oldEntries[i]; 1.49 while( entry != NULL ) 1.50 - { nextEntry = entry->next; 1.51 + { nextEntry = entry->next; //save for later 1.52 entry->next = NULL; 1.53 putEntryIntoTable( entry, table ); //does not allocate anything 1.54 entry = nextEntry; 1.55 @@ -74,17 +90,36 @@ 1.56 return h % hashSz; 1.57 } 1.58 1.59 +/*Copies the string that is the key*/ 1.60 +inline HashEntry * 1.61 +makeHashEntry( char * key ) 1.62 + { HashEntry *hashEntry; 1.63 + 1.64 + int32 len = strlen(key); 1.65 + 1.66 + hashEntry = (HashEntry*) VMS_int__malloc( sizeof( HashEntry ) ); 1.67 + if( hashEntry == NULL ) return NULL; 1.68 + 1.69 + hashEntry->key = VMS_int__malloc( len + 1 ); 1.70 + if( hashEntry->key == NULL ) return NULL; 1.71 + memcpy( hashEntry->key, key, len + 1 ); 1.72 + hashEntry->next = NULL; 1.73 + 1.74 + return hashEntry; 1.75 + } 1.76 + 1.77 + 1.78 /*Need this to be separated out, for use in both getParam and putParam 1.79 */ 1.80 HashEntry * 1.81 getEntryFromTable( char *key, HashTable * table ) 1.82 - { unsigned int 1.83 + { uint32 1.84 hashIndex = hashThisKey( key, table->tableSz ); 1.85 HashEntry* 1.86 hashEntry = table->entries[ hashIndex ]; 1.87 for( ; hashEntry != NULL; hashEntry = hashEntry->next ) 1.88 { 1.89 - if( memcmp( hashEntry->key, key, sizeof(hashkey_t) ) == 0 ) 1.90 + if( strcmp( hashEntry->key, key ) == 0 ) 1.91 return hashEntry; 1.92 } 1.93 return NULL; 1.94 @@ -99,7 +134,6 @@ 1.95 return entry->content; 1.96 } 1.97 1.98 - 1.99 /*If key already has a value, clobber the old one and replace it 1.100 */ 1.101 int 1.102 @@ -110,11 +144,7 @@ 1.103 hashEntry = getEntryFromTable( key, table ); 1.104 if( hashEntry == NULL ) 1.105 { hashIdx = hashThisKey( key, table->tableSz ); 1.106 - hashEntry = (HashEntry*) VMS_int__malloc( sizeof( HashEntry ) ); 1.107 - if( hashEntry == NULL ) return 0; 1.108 - hashEntry->key = VMS_int__malloc( sizeof(hashkey_t) ); 1.109 - if( hashEntry->key == NULL ) return 0; 1.110 - memcpy( hashEntry->key, key, sizeof(hashkey_t) ); 1.111 + hashEntry = makeHashEntry( key ); 1.112 hashEntry->next = (table->entries)[hashIdx]; 1.113 (table->entries)[hashIdx] = hashEntry; 1.114 table->numEntries += 1; 1.115 @@ -127,6 +157,7 @@ 1.116 return 1; 1.117 } 1.118 1.119 + 1.120 int 1.121 putEntryIntoTable( HashEntry *entry, HashTable *table ) 1.122 { unsigned int hashIdx; 1.123 @@ -142,8 +173,8 @@ 1.124 } 1.125 else 1.126 { (*(table->freeEntryContentFn))( testEntry->content ); 1.127 - //being lazy -- will create bug in code that relies on having ptr to 1.128 - // elem given to insert into table! 1.129 + //being lazy -- will create bug in code that relies on having ptr 1.130 + // to elem given to insert into table! 1.131 testEntry->content = entry->content; 1.132 entry->content = NULL; 1.133 freeHashEntryButNotContent( entry ); 1.134 @@ -161,7 +192,7 @@ 1.135 1.136 testEntry = table->entries[ hashIndex ]; 1.137 for( ; testEntry != NULL; testEntry = testEntry->next ) 1.138 - { if( memcmp( testEntry->key, entry->key, sizeof(hashkey_t)) == 0 ) 1.139 + { if( strcmp( testEntry->key, entry->key ) == 0 ) 1.140 { if( prevEntry == NULL ) 1.141 { table->entries[hashIndex] = entry; 1.142 entry->next = testEntry->next; 1.143 @@ -180,27 +211,26 @@ 1.144 } 1.145 1.146 1.147 - 1.148 - bool8 1.149 +bool8 1.150 deleteEntryFromTable( char *key, HashTable *table ) 1.151 { HashEntry *hashEntry; 1.152 - HashEntry **addrOfHashEntryPtr; 1.153 + HashEntry **addrOfPrevPtr; 1.154 unsigned int hashIndex; 1.155 1.156 hashIndex = hashThisKey( key, table->tableSz ); 1.157 - addrOfHashEntryPtr = &( table->entries[ hashIndex ] ); 1.158 - hashEntry = *addrOfHashEntryPtr; 1.159 + addrOfPrevPtr = &( table->entries[ hashIndex ] );//for removing node 1.160 + hashEntry = *addrOfPrevPtr; //already did work, might as well use it 1.161 while( hashEntry != NULL ) 1.162 - { if( memcmp( hashEntry->key, key, sizeof(hashkey_t) ) == 0 ) 1.163 + { if( strcmp( hashEntry->key, key ) == 0 ) 1.164 { 1.165 - *addrOfHashEntryPtr = hashEntry->next; 1.166 + *addrOfPrevPtr = hashEntry->next; //remove node from list 1.167 //TODO: Free the contents of entry? 1.168 freeHashEntryButNotContent( hashEntry ); 1.169 table->numEntries -= 1; 1.170 return TRUE; 1.171 } 1.172 - addrOfHashEntryPtr = &( hashEntry->next ); 1.173 - hashEntry = *addrOfHashEntryPtr; 1.174 + addrOfPrevPtr = &( hashEntry->next ); 1.175 + hashEntry = *addrOfPrevPtr; 1.176 } 1.177 return FALSE; 1.178 } 1.179 @@ -234,9 +264,247 @@ 1.180 } 1.181 1.182 void 1.183 +freeHashEntryUsing_WL( HashEntry *entry, HashTable *table ) 1.184 + { 1.185 + if( entry->content != NULL ) 1.186 + (*(table->freeEntryContentFn))( entry->content ); 1.187 + VMS_WL__free( entry->key ); //was VMS_int__malloc'd above, so free it 1.188 + VMS_WL__free( entry ); 1.189 + } 1.190 + 1.191 +void 1.192 +freeHashTable_WL( HashTable *table ) 1.193 + { int i; 1.194 + HashEntry *hashEntry, *temp, **entries; 1.195 + 1.196 + entries = table->entries; 1.197 + for( i=0; i < table->tableSz; i++ ) 1.198 + { if( entries[i] != NULL ) 1.199 + { hashEntry = entries[i]; 1.200 + while( hashEntry != NULL ) 1.201 + { 1.202 + temp = hashEntry->next; 1.203 + freeHashEntryUsing_WL( hashEntry, table ); 1.204 + hashEntry = temp; 1.205 + } 1.206 + } 1.207 + } 1.208 + } 1.209 + 1.210 + 1.211 +void 1.212 freeHashEntryButNotContent( HashEntry *entry ) 1.213 { 1.214 VMS_int__free( entry->key ); //was VMS_int__malloc'd above, so free it 1.215 VMS_int__free( entry ); 1.216 } 1.217 1.218 +void 1.219 +freeHashEntryButNotContent_WL( HashEntry *entry ) 1.220 + { 1.221 + VMS_WL__free( entry->key ); //was VMS_int__malloc'd above, so free it 1.222 + VMS_WL__free( entry ); 1.223 + } 1.224 + 1.225 + 1.226 + 1.227 + 1.228 +//======================= 32 bit integer key version ====================== 1.229 + 1.230 +/*key is array of uint32, with first entry being the num ints in key. 1.231 + * that means size of key is content of first entry times 4, plus the 1.232 + * size of first entry itself, which is another 4*/ 1.233 +#define sizeOfKey(key) key[0]*4 + 4 1.234 + 1.235 + 1.236 +HashTable * 1.237 +makeHashTable32( int powerOf2OfSz, FreeEntryContentFnPtr freeFn ) 1.238 + { HashTable * retTable; 1.239 + int32 numHashSlots; 1.240 + 1.241 + retTable = VMS_int__malloc( sizeof( HashTable ) ); 1.242 + 1.243 + numHashSlots = 1 << powerOf2OfSz; 1.244 + retTable->hashMask = 0xffffffff >> 32 - powerOf2OfSz; 1.245 + retTable->prevHash = (int32)rand(); 1.246 + 1.247 + retTable->freeEntryContentFn = freeFn; 1.248 + 1.249 + retTable->entries = VMS_int__malloc( numHashSlots * sizeof(HashEntry *)); 1.250 + retTable->numEntries = 0; 1.251 + retTable->tableSz = numHashSlots; 1.252 + 1.253 + nullOutTablesArray( retTable ); 1.254 + 1.255 + return retTable; 1.256 + } 1.257 + 1.258 +HashTable * 1.259 +makeDefaultSizeHashTable32( FreeEntryContentFnPtr freeFn ) 1.260 + { 1.261 + return makeHashTable32( DEFAULT_POWER_OF_2_TABLE_SIZE, freeFn ); 1.262 + } 1.263 + 1.264 +HashEntry * 1.265 +makeHashEntry32( uint32 * key ) 1.266 + { HashEntry *hashEntry; 1.267 + 1.268 + hashEntry = (HashEntry*) VMS_int__malloc( sizeof( HashEntry ) ); 1.269 + if( hashEntry == NULL ) return NULL; 1.270 + hashEntry->key = VMS_int__malloc( sizeOfKey(key) ); 1.271 + if( hashEntry->key == NULL ) return NULL; 1.272 + memcpy( hashEntry->key, key, sizeOfKey(key) ); 1.273 + hashEntry->next = NULL; 1.274 + 1.275 + return hashEntry; 1.276 + } 1.277 + 1.278 + 1.279 + 1.280 +int32 1.281 +putEntryIntoTable32( HashEntry *entry, HashTable *table ) 1.282 + { unsigned int hashIdx; 1.283 + HashEntry* testEntry; 1.284 + 1.285 + testEntry = getEntryFromTable32( (uint32 *)entry->key, table ); 1.286 + if( testEntry == NULL ) //no entry w/key, so add passed-in as list-head 1.287 + { hashIdx = hashThisKey32( entry->key, table->tableSz ); 1.288 + entry->next = (table->entries)[hashIdx]; 1.289 + (table->entries)[hashIdx] = entry; 1.290 + table->numEntries += 1; 1.291 + //keep num entries less than half the num indexes in table 1.292 + if( table->numEntries > (table->tableSz >>1) ) doubleTableSize(table); 1.293 + } 1.294 + else //entry w/key already exists, so free content, then replace then 1.295 + // free the passed-in entry, leaving the entry already in table 1.296 + { (*(table->freeEntryContentFn))( testEntry->content ); 1.297 + //being lazy -- will create bug in code that relies on having ptr 1.298 + // to elem given to insert into table! 1.299 + testEntry->content = entry->content; 1.300 + entry->content = NULL; 1.301 + freeHashEntryButNotContent( entry ); 1.302 + } 1.303 + return 1; 1.304 + } 1.305 + 1.306 + 1.307 +void 1.308 +doubleTableSize32( HashTable *table ) 1.309 + { int i, oldTableSz, newTableSz; 1.310 + HashEntry *entry, *nextEntry, **oldEntries, **newEntries; 1.311 + 1.312 + oldTableSz = table->tableSz; 1.313 + oldEntries = table->entries; 1.314 + 1.315 + newTableSz = 2 * oldTableSz; 1.316 + newEntries = VMS_int__malloc( newTableSz * sizeof(HashEntry *) ); 1.317 + 1.318 + table->tableSz = newTableSz; 1.319 + table->entries = newEntries; 1.320 + table->numEntries = 0; //about to add them all back! 1.321 + 1.322 + // move all the entries from old to new 1.323 + for( i=0; i < oldTableSz; i++ ) 1.324 + { if( oldEntries[i] != NULL ) 1.325 + { entry = oldEntries[i]; 1.326 + while( entry != NULL ) 1.327 + { nextEntry = entry->next; //save for later 1.328 + entry->next = NULL; //null before, so can chain in new 1.329 + putEntryIntoTable32( entry, table ); //doesn't allocate anything 1.330 + entry = nextEntry; 1.331 + } 1.332 + } 1.333 + } 1.334 + } 1.335 + 1.336 +/*The key is a self-sized array of 32 bit unsigned ints, with the first 1.337 + * entry being the number of ints in the key, which makes up the rest of 1.338 + * the array.*/ 1.339 +int32 1.340 +hashThisKey32( uint32 *key, HashTable *hashTable ) 1.341 + { int32 hashOfKey; 1.342 + 1.343 + //the hash function takes addr of start of key array, plus num int32s, 1.344 + hashOfKey = jenkHash32( &key[1], *key ); 1.345 + hashTable->prevHash = hashOfKey; 1.346 + 1.347 + /*The hash is a full 32 bits, but only want hashes that fall within 1.348 + * the size of the table. So, mask off the higher bits. */ 1.349 + return ( hashTable->hashMask & hashOfKey ); //reduce to size of table 1.350 + } 1.351 + 1.352 + 1.353 +/*The first entry of key says the size of the key, while key itself is the 1.354 + * rest of the integers in the array 1.355 + */ 1.356 +HashEntry * 1.357 +getEntryFromTable32( uint32 *key, HashTable * table ) 1.358 + { unsigned int 1.359 + hashIndex = hashThisKey32( key, table ); 1.360 + HashEntry* 1.361 + hashEntry = table->entries[ hashIndex ]; 1.362 + for( ; hashEntry != NULL; hashEntry = hashEntry->next ) 1.363 + { 1.364 + if( memcmp( hashEntry->key, key, sizeOfKey(key) ) == 0 ) 1.365 + return hashEntry; 1.366 + } 1.367 + return NULL; 1.368 + } 1.369 + 1.370 +void * 1.371 +getValueFromTable32( uint32 *key, HashTable * table ) 1.372 + { HashEntry *entry; 1.373 + entry = getEntryFromTable32( key, table ); 1.374 + if( entry == NULL ) return NULL; 1.375 + 1.376 + return entry->content; 1.377 + } 1.378 + 1.379 +/*Returns NULL if failed to insert, else returns ptr to hash entry */ 1.380 +HashEntry * 1.381 +addValueIntoTable32( uint32* key, void *content, HashTable *table ) 1.382 + { unsigned int hashIdx; 1.383 + HashEntry* hashEntry; 1.384 + 1.385 + hashEntry = getEntryFromTable32( key, table ); 1.386 + if( hashEntry == NULL ) 1.387 + { hashIdx = hashThisKey32( key, table ); 1.388 + hashEntry = makeHashEntry32( key ); 1.389 + hashEntry->next = (table->entries)[hashIdx]; 1.390 + (table->entries)[hashIdx] = hashEntry; 1.391 + table->numEntries += 1; 1.392 + //Check if need to make bigger -- keep half-full (hence ">> 1") 1.393 + if( table->numEntries > table->tableSz >>1 ) doubleTableSize( table ); 1.394 + } 1.395 + else 1.396 + { (*(table->freeEntryContentFn))( hashEntry->content ); 1.397 + } 1.398 + hashEntry->content = content; 1.399 + return hashEntry; 1.400 + } 1.401 + 1.402 + 1.403 +bool32 1.404 +deleteEntryFromTable32( uint32 *key, HashTable *table ) 1.405 + { HashEntry *hashEntry; 1.406 + HashEntry **addrOfPrevPtr; 1.407 + unsigned int hashIndex; 1.408 + 1.409 + hashIndex = hashThisKey32( key, table ); 1.410 + hashEntry = table->entries[ hashIndex ]; 1.411 + //go down the chained list, checking all with this hash value 1.412 + addrOfPrevPtr = &( table->entries[hashIndex] ); //for removing a node 1.413 + hashEntry = *addrOfPrevPtr; //did ptr chasing, might as well use it 1.414 + while( hashEntry != NULL ) 1.415 + { if( memcmp( hashEntry->key, key, sizeOfKey(key) ) == 0 ) 1.416 + { *addrOfPrevPtr = hashEntry->next; //remove node from list 1.417 + freeHashEntryButNotContent( hashEntry ); 1.418 + table->numEntries -= 1; 1.419 + return TRUE; 1.420 + } 1.421 + addrOfPrevPtr = &(hashEntry->next); //chg content of *this* to remove 1.422 + hashEntry = *addrOfPrevPtr; //cheaper than hashEntry->next 1.423 + } 1.424 + return FALSE; 1.425 + } 1.426 +
2.1 --- a/PrivateHash.h Tue Mar 13 18:31:05 2012 -0700 2.2 +++ b/PrivateHash.h Wed Jun 06 18:00:58 2012 -0700 2.3 @@ -16,9 +16,15 @@ 2.4 #include "VMS_impl/VMS_primitive_data_types.h" 2.5 #include "VMS_impl/Services_Offered_by_VMS/Memory_Handling/vmalloc.h" 2.6 2.7 +//===================== defines ===================== 2.8 #define TRUE 1 2.9 #define FALSE 0 2.10 2.11 +#define DEFAULT_HASH_TABLE_SIZE 1 << 10 2.12 +#define DEFAULT_POWER_OF_2_TABLE_SIZE 10 2.13 + 2.14 + 2.15 +//===================== structs ===================== 2.16 union hashkey_t{ 2.17 char hashable[8]; 2.18 int parts[2]; 2.19 @@ -26,8 +32,6 @@ 2.20 2.21 typedef union hashkey_t hashkey_t; 2.22 2.23 -#define DEFAULT_HASHSIZE 1 << 10 2.24 - 2.25 typedef struct _HashEntry HashEntry; 2.26 2.27 struct _HashEntry 2.28 @@ -40,9 +44,11 @@ 2.29 typedef void (*FreeEntryContentFnPtr) ( void * ); 2.30 2.31 typedef struct 2.32 - { int tableSz; 2.33 - int numEntries; 2.34 + { int tableSz; 2.35 + int numEntries; 2.36 HashEntry* *entries; 2.37 + int32 hashMask; 2.38 + int32 prevHash; 2.39 FreeEntryContentFnPtr freeEntryContentFn; 2.40 } 2.41 HashTable; 2.42 @@ -64,6 +70,17 @@ 2.43 void freeHashTable( HashTable *table ); 2.44 //char *paramBagToString( ParamBag * bag ) 2.45 2.46 +//================= Same Fns, but for 32b array key hash fn ================ 2.47 +HashTable *makeHashTable32(int32 powerOf2OfSz, FreeEntryContentFnPtr freeFn); 2.48 +HashTable *makeDefaultSizeHashTable32( FreeEntryContentFnPtr freeFn ); 2.49 + 2.50 +int putEntryIntoTable32( HashEntry *entry, HashTable *table); 2.51 +HashEntry *addValueIntoTable32( uint32 key[], void *value, HashTable *table); 2.52 +HashEntry *getEntryFromTable32( uint32 key[], HashTable *table ); 2.53 +void *getValueFromTable32( uint32 key[], HashTable *table ); 2.54 + 2.55 +bool32 deleteEntryFromTable32( uint32 key[], HashTable *table ); 2.56 + 2.57 //=========================================================================== 2.58 // Internal functions 2.59 void freeHashEntryUsing( HashEntry *entry, HashTable *table ); 2.60 @@ -72,5 +89,9 @@ 2.61 void doubleTableSize( HashTable *table ); 2.62 void freeHashEntryButNotContent( HashEntry *entry ); 2.63 2.64 +uint32 2.65 +jenkHash32( const uint32 *key, /* array of uint32 values */ 2.66 + int32 length); /* num uint32 in the key */ 2.67 + 2.68 #endif /* _PRIVATE_HASH_H */ 2.69
