Me@14: /* Me@14: * Copyright 2009 OpenSourceStewardshipFoundation.org Me@14: * Licensed under GNU General Public License version 2 Me@14: * Me@14: * Me@14: * Author: seanhalle@yahoo.com Me@14: */ Me@14: Me@14: #include "PrivateHash.h" Me@14: Me@14: Me@14: HashTable * Me@14: makeHashTable( int numHashSlots, FreeEntryContentFnPtr freeFn ) Me@14: { HashTable * retTable; Me@17: retTable = VMS_int__malloc( sizeof( HashTable ) ); Me@14: Me@14: retTable->freeEntryContentFn = freeFn; Me@14: Me@17: retTable->entries = VMS_int__malloc( numHashSlots * sizeof(HashEntry *) ); Me@14: retTable->numEntries = 0; Me@14: retTable->tableSz = numHashSlots; Me@14: Me@14: nullOutTablesArray( retTable ); Me@14: Me@14: return retTable; Me@14: } Me@14: Me@14: void Me@14: doubleTableSize( HashTable *table ) Me@14: { int i, oldTableSz, newTableSz; Me@14: HashEntry *entry, *nextEntry, **oldEntries, **newEntries; Me@14: Me@14: oldTableSz = table->tableSz; Me@14: oldEntries = table->entries; Me@14: Me@14: newTableSz = 2 * oldTableSz + 1; Me@17: newEntries = VMS_int__malloc( newTableSz * sizeof(HashEntry *) ); Me@14: Me@14: table->tableSz = newTableSz; Me@14: table->entries = newEntries; Me@14: table->numEntries = 0; //about to add them all back! Me@14: Me@14: // move all the entries from old to new Me@14: for( i=0; i < oldTableSz; i++ ) Me@14: { if( oldEntries[i] != NULL ) Me@14: { entry = oldEntries[i]; Me@14: while( entry != NULL ) Me@14: { nextEntry = entry->next; Me@14: entry->next = NULL; Me@14: putEntryIntoTable( entry, table ); //does not allocate anything Me@14: entry = nextEntry; Me@14: } Me@14: } Me@14: } Me@14: } Me@14: Me@14: void Me@14: nullOutTablesArray( HashTable *table ) Me@14: { int i, tableSz; Me@14: tableSz = table->tableSz; Me@14: HashEntry ** entries = table->entries; Me@14: for( i = 0; i < tableSz; i++ ) Me@14: entries[ i ] = NULL; Me@14: } Me@14: Me@14: unsigned int Me@14: hashThisKey( char* s, int hashSz ) Me@14: { unsigned int h = 0; Me@14: unsigned int i; Me@14: hashkey_t* key = (hashkey_t*)s; Me@14: Me@14: for(i=0 ; ihashable[i] + h*31; Me@14: return h % hashSz; Me@14: } Me@14: Me@14: /*Need this to be separated out, for use in both getParam and putParam Me@14: */ Me@14: HashEntry * Me@14: getEntryFromTable( char *key, HashTable * table ) Me@14: { unsigned int Me@14: hashIndex = hashThisKey( key, table->tableSz ); Me@14: HashEntry* Me@14: hashEntry = table->entries[ hashIndex ]; Me@14: for( ; hashEntry != NULL; hashEntry = hashEntry->next ) Me@14: { Me@14: if( memcmp( hashEntry->key, key, sizeof(hashkey_t) ) == 0 ) Me@14: return hashEntry; Me@14: } Me@14: return NULL; Me@14: } Me@14: Me@14: void * Me@14: getValueFromTable( char *key, HashTable * table ) Me@14: { HashEntry *entry; Me@14: entry = getEntryFromTable( key, table ); Me@14: if( entry == NULL ) return NULL; Me@14: Me@14: return entry->content; Me@14: } Me@14: Me@14: Me@14: /*If key already has a value, clobber the old one and replace it Me@14: */ Me@14: int Me@14: addValueIntoTable( char* key, void *content, HashTable *table ) Me@14: { unsigned int hashIdx; Me@14: HashEntry* hashEntry; Me@14: Me@14: hashEntry = getEntryFromTable( key, table ); Me@14: if( hashEntry == NULL ) Me@14: { hashIdx = hashThisKey( key, table->tableSz ); Me@17: hashEntry = (HashEntry*) VMS_int__malloc( sizeof( HashEntry ) ); Me@14: if( hashEntry == NULL ) return 0; Me@17: hashEntry->key = VMS_int__malloc( sizeof(hashkey_t) ); Me@14: if( hashEntry->key == NULL ) return 0; Me@14: memcpy( hashEntry->key, key, sizeof(hashkey_t) ); Me@14: hashEntry->next = (table->entries)[hashIdx]; Me@14: (table->entries)[hashIdx] = hashEntry; Me@14: table->numEntries += 1; Me@14: if( table->tableSz < table->numEntries ) doubleTableSize( table ); Me@14: } Me@14: else Me@14: { (*(table->freeEntryContentFn))( hashEntry->content ); Me@14: } Me@14: hashEntry->content = content; Me@14: return 1; Me@14: } Me@14: Me@14: int Me@14: putEntryIntoTable( HashEntry *entry, HashTable *table ) Me@14: { unsigned int hashIdx; Me@14: HashEntry* testEntry; Me@14: Me@14: testEntry = getEntryFromTable( entry->key, table ); Me@14: if( testEntry == NULL ) Me@14: { hashIdx = hashThisKey( entry->key, table->tableSz ); Me@14: entry->next = (table->entries)[hashIdx]; Me@14: (table->entries)[hashIdx] = entry; Me@14: table->numEntries += 1; Me@14: if( table->tableSz < table->numEntries ) doubleTableSize( table ); Me@14: } Me@14: else Me@14: { (*(table->freeEntryContentFn))( testEntry->content ); Me@14: //being lazy -- will create bug in code that relies on having ptr to Me@14: // elem given to insert into table! Me@14: testEntry->content = entry->content; Me@14: entry->content = NULL; Me@14: freeHashEntryButNotContent( entry ); Me@14: } Me@14: return 1; Me@14: } Me@14: Me@14: /*Better version Me@14: */ Me@14: void Me@14: untested_putEntryIntoTable( HashEntry *entry, HashTable * table ) Me@14: { HashEntry *testEntry, *prevEntry = NULL; Me@14: unsigned int Me@14: hashIndex = hashThisKey( entry->key, table->tableSz ); Me@14: Me@14: testEntry = table->entries[ hashIndex ]; Me@14: for( ; testEntry != NULL; testEntry = testEntry->next ) Me@14: { if( memcmp( testEntry->key, entry->key, sizeof(hashkey_t)) == 0 ) Me@14: { if( prevEntry == NULL ) Me@14: { table->entries[hashIndex] = entry; Me@14: entry->next = testEntry->next; Me@14: } Me@14: else Me@14: { prevEntry->next = entry; Me@14: entry->next = testEntry->next; Me@14: } Me@14: freeHashEntryUsing( testEntry, table ); //frees content too! Me@14: return; Me@14: } Me@14: } Me@14: //wasn't found, so insert Me@14: entry->next = table->entries[hashIndex]; Me@14: table->entries[hashIndex] = entry; Me@14: } Me@14: Me@14: Me@14: Me@14: bool8 Me@14: deleteEntryFromTable( char *key, HashTable *table ) Me@14: { HashEntry *hashEntry; Me@14: HashEntry **addrOfHashEntryPtr; Me@14: unsigned int hashIndex; Me@14: Me@14: hashIndex = hashThisKey( key, table->tableSz ); Me@14: addrOfHashEntryPtr = &( table->entries[ hashIndex ] ); Me@14: hashEntry = *addrOfHashEntryPtr; Me@14: while( hashEntry != NULL ) Me@14: { if( memcmp( hashEntry->key, key, sizeof(hashkey_t) ) == 0 ) Me@14: { Me@14: *addrOfHashEntryPtr = hashEntry->next; Me@14: //TODO: Free the contents of entry? Me@14: freeHashEntryButNotContent( hashEntry ); Me@14: table->numEntries -= 1; Me@14: return TRUE; Me@14: } Me@14: addrOfHashEntryPtr = &( hashEntry->next ); Me@14: hashEntry = *addrOfHashEntryPtr; Me@14: } Me@14: return FALSE; Me@14: } Me@14: Me@14: void Me@14: freeHashTable( HashTable *table ) Me@14: { int i; Me@14: HashEntry *hashEntry, *temp, **entries; Me@14: Me@14: entries = table->entries; Me@14: for( i=0; i < table->tableSz; i++ ) Me@14: { if( entries[i] != NULL ) Me@14: { hashEntry = entries[i]; Me@14: while( hashEntry != NULL ) Me@14: { Me@14: temp = hashEntry->next; Me@14: freeHashEntryUsing( hashEntry, table ); Me@14: hashEntry = temp; Me@14: } Me@14: } Me@14: } Me@14: } Me@14: Me@14: void Me@14: freeHashEntryUsing( HashEntry *entry, HashTable *table ) Me@14: { Me@14: if( entry->content != NULL ) Me@14: (*(table->freeEntryContentFn))( entry->content ); seanhalle@21: VMS_int__free( entry->key ); //was VMS_int__malloc'd above, so free it Me@17: VMS_int__free( entry ); Me@14: } Me@14: Me@14: void Me@14: freeHashEntryButNotContent( HashEntry *entry ) Me@14: { seanhalle@21: VMS_int__free( entry->key ); //was VMS_int__malloc'd above, so free it Me@17: VMS_int__free( entry ); Me@14: } Me@14: