00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "BasicHashTable.hh"
00021 #include "strDup.hh"
00022
00023 #if defined(__WIN32__) || defined(_WIN32)
00024 #else
00025 #include <stddef.h>
00026 #endif
00027 #include <string.h>
00028 #include <stdio.h>
00029
00030
00031
00032 #define REBUILD_MULTIPLIER 3
00033
00034 BasicHashTable::BasicHashTable(int keyType)
00035 : fBuckets(fStaticBuckets), fNumBuckets(SMALL_HASH_TABLE_SIZE),
00036 fNumEntries(0), fRebuildSize(SMALL_HASH_TABLE_SIZE*REBUILD_MULTIPLIER),
00037 fDownShift(28), fMask(0x3), fKeyType(keyType) {
00038 for (unsigned i = 0; i < SMALL_HASH_TABLE_SIZE; ++i) {
00039 fStaticBuckets[i] = NULL;
00040 }
00041 }
00042
00043 BasicHashTable::~BasicHashTable() {
00044
00045 for (unsigned i = 0; i < fNumBuckets; ++i) {
00046 TableEntry* entry;
00047 while ((entry = fBuckets[i]) != NULL) {
00048 deleteEntry(i, entry);
00049 }
00050 }
00051
00052
00053 if (fBuckets != fStaticBuckets) delete[] fBuckets;
00054 }
00055
00056 void* BasicHashTable::Add(char const* key, void* value) {
00057 void* oldValue;
00058 unsigned index;
00059 TableEntry* entry = lookupKey(key, index);
00060 if (entry != NULL) {
00061
00062 oldValue = entry->value;
00063 } else {
00064
00065 entry = insertNewEntry(index, key);
00066 oldValue = NULL;
00067 }
00068 entry->value = value;
00069
00070
00071 if (fNumEntries >= fRebuildSize) rebuild();
00072
00073 return oldValue;
00074 }
00075
00076 Boolean BasicHashTable::Remove(char const* key) {
00077 unsigned index;
00078 TableEntry* entry = lookupKey(key, index);
00079 if (entry == NULL) return False;
00080
00081 deleteEntry(index, entry);
00082
00083 return True;
00084 }
00085
00086 void* BasicHashTable::Lookup(char const* key) const {
00087 unsigned index;
00088 TableEntry* entry = lookupKey(key, index);
00089 if (entry == NULL) return NULL;
00090
00091 return entry->value;
00092 }
00093
00094 unsigned BasicHashTable::numEntries() const {
00095 return fNumEntries;
00096 }
00097
00098 BasicHashTable::Iterator::Iterator(BasicHashTable& table)
00099 : fTable(table), fNextIndex(0), fNextEntry(NULL) {
00100 }
00101
00102 void* BasicHashTable::Iterator::next(char const*& key) {
00103 while (fNextEntry == NULL) {
00104 if (fNextIndex >= fTable.fNumBuckets) return NULL;
00105
00106 fNextEntry = fTable.fBuckets[fNextIndex++];
00107 }
00108
00109 BasicHashTable::TableEntry* entry = fNextEntry;
00110 fNextEntry = entry->fNext;
00111
00112 key = entry->key;
00113 return entry->value;
00114 }
00115
00117
00118 HashTable* HashTable::create(int keyType) {
00119 return new BasicHashTable(keyType);
00120 }
00121
00122 HashTable::Iterator* HashTable::Iterator::create(HashTable& hashTable) {
00123
00124 return new BasicHashTable::Iterator((BasicHashTable&)hashTable);
00125 }
00126
00128
00129 BasicHashTable::TableEntry* BasicHashTable
00130 ::lookupKey(char const* key, unsigned& index) const {
00131 TableEntry* entry;
00132 index = hashIndexFromKey(key);
00133
00134 for (entry = fBuckets[index]; entry != NULL; entry = entry->fNext) {
00135 if (keyMatches(key, entry->key)) break;
00136 }
00137
00138 return entry;
00139 }
00140
00141 Boolean BasicHashTable
00142 ::keyMatches(char const* key1, char const* key2) const {
00143
00144 if (fKeyType == STRING_HASH_KEYS) {
00145 return (strcmp(key1, key2) == 0);
00146 } else if (fKeyType == ONE_WORD_HASH_KEYS) {
00147 return (key1 == key2);
00148 } else {
00149 unsigned* k1 = (unsigned*)key1;
00150 unsigned* k2 = (unsigned*)key2;
00151
00152 for (int i = 0; i < fKeyType; ++i) {
00153 if (k1[i] != k2[i]) return False;
00154 }
00155 return True;
00156 }
00157 }
00158
00159 BasicHashTable::TableEntry* BasicHashTable
00160 ::insertNewEntry(unsigned index, char const* key) {
00161 TableEntry* entry = new TableEntry();
00162 entry->fNext = fBuckets[index];
00163 fBuckets[index] = entry;
00164
00165 ++fNumEntries;
00166 assignKey(entry, key);
00167
00168 return entry;
00169 }
00170
00171 void BasicHashTable::assignKey(TableEntry* entry, char const* key) {
00172
00173 if (fKeyType == STRING_HASH_KEYS) {
00174 entry->key = strDup(key);
00175 } else if (fKeyType == ONE_WORD_HASH_KEYS) {
00176 entry->key = key;
00177 } else if (fKeyType > 0) {
00178 unsigned* keyFrom = (unsigned*)key;
00179 unsigned* keyTo = new unsigned[fKeyType];
00180 for (int i = 0; i < fKeyType; ++i) keyTo[i] = keyFrom[i];
00181
00182 entry->key = (char const*)keyTo;
00183 }
00184 }
00185
00186 void BasicHashTable::deleteEntry(unsigned index, TableEntry* entry) {
00187 TableEntry** ep = &fBuckets[index];
00188
00189 Boolean foundIt = False;
00190 while (*ep != NULL) {
00191 if (*ep == entry) {
00192 foundIt = True;
00193 *ep = entry->fNext;
00194 break;
00195 }
00196 ep = &((*ep)->fNext);
00197 }
00198
00199 if (!foundIt) {
00200 #ifdef DEBUG
00201 fprintf(stderr, "BasicHashTable[%p]::deleteEntry(%d,%p): internal error - not found (first entry %p", this, index, entry, fBuckets[index]);
00202 if (fBuckets[index] != NULL) fprintf(stderr, ", next entry %p", fBuckets[index]->fNext);
00203 fprintf(stderr, ")\n");
00204 #endif
00205 }
00206
00207 --fNumEntries;
00208 deleteKey(entry);
00209 delete entry;
00210 }
00211
00212 void BasicHashTable::deleteKey(TableEntry* entry) {
00213
00214 if (fKeyType == ONE_WORD_HASH_KEYS) {
00215 entry->key = NULL;
00216 } else {
00217 delete[] (char*)entry->key;
00218 entry->key = NULL;
00219 }
00220 }
00221
00222 void BasicHashTable::rebuild() {
00223
00224 unsigned oldSize = fNumBuckets;
00225 TableEntry** oldBuckets = fBuckets;
00226
00227
00228 fNumBuckets *= 4;
00229 fBuckets = new TableEntry*[fNumBuckets];
00230 for (unsigned i = 0; i < fNumBuckets; ++i) {
00231 fBuckets[i] = NULL;
00232 }
00233 fRebuildSize *= 4;
00234 fDownShift -= 2;
00235 fMask = (fMask<<2)|0x3;
00236
00237
00238 for (TableEntry** oldChainPtr = oldBuckets; oldSize > 0;
00239 --oldSize, ++oldChainPtr) {
00240 for (TableEntry* hPtr = *oldChainPtr; hPtr != NULL;
00241 hPtr = *oldChainPtr) {
00242 *oldChainPtr = hPtr->fNext;
00243
00244 unsigned index = hashIndexFromKey(hPtr->key);
00245
00246 hPtr->fNext = fBuckets[index];
00247 fBuckets[index] = hPtr;
00248 }
00249 }
00250
00251
00252 if (oldBuckets != fStaticBuckets) delete[] oldBuckets;
00253 }
00254
00255 unsigned BasicHashTable::hashIndexFromKey(char const* key) const {
00256 unsigned result = 0;
00257
00258 if (fKeyType == STRING_HASH_KEYS) {
00259 while (1) {
00260 char c = *key++;
00261 if (c == 0) break;
00262 result += (result<<3) + (unsigned)c;
00263 }
00264 result &= fMask;
00265 } else if (fKeyType == ONE_WORD_HASH_KEYS) {
00266 result = randomIndex((unsigned long)key);
00267 } else {
00268 unsigned* k = (unsigned*)key;
00269 unsigned long sum = 0;
00270 for (int i = 0; i < fKeyType; ++i) {
00271 sum += k[i];
00272 }
00273 result = randomIndex(sum);
00274 }
00275
00276 return result;
00277 }
00278