00001 #ifndef BT_HASH_MAP_H 00002 #define BT_HASH_MAP_H 00003 00004 #include "btAlignedObjectArray.h" 00005 00007 struct btHashString 00008 { 00009 const char* m_string; 00010 unsigned int m_hash; 00011 00012 SIMD_FORCE_INLINE unsigned int getHash()const 00013 { 00014 return m_hash; 00015 } 00016 00017 btHashString(const char* name) 00018 :m_string(name) 00019 { 00020 /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */ 00021 static const unsigned int InitialFNV = 2166136261u; 00022 static const unsigned int FNVMultiple = 16777619u; 00023 00024 /* Fowler / Noll / Vo (FNV) Hash */ 00025 unsigned int hash = InitialFNV; 00026 00027 for(int i = 0; m_string[i]; i++) 00028 { 00029 hash = hash ^ (m_string[i]); /* xor the low 8 bits */ 00030 hash = hash * FNVMultiple; /* multiply by the magic number */ 00031 } 00032 m_hash = hash; 00033 } 00034 00035 int portableStringCompare(const char* src, const char* dst) const 00036 { 00037 int ret = 0 ; 00038 00039 while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) 00040 ++src, ++dst; 00041 00042 if ( ret < 0 ) 00043 ret = -1 ; 00044 else if ( ret > 0 ) 00045 ret = 1 ; 00046 00047 return( ret ); 00048 } 00049 00050 bool equals(const btHashString& other) const 00051 { 00052 return (m_string == other.m_string) || 00053 (0==portableStringCompare(m_string,other.m_string)); 00054 00055 } 00056 00057 }; 00058 00059 const int BT_HASH_NULL=0xffffffff; 00060 00061 00062 class btHashInt 00063 { 00064 int m_uid; 00065 public: 00066 btHashInt(int uid) :m_uid(uid) 00067 { 00068 } 00069 00070 int getUid1() const 00071 { 00072 return m_uid; 00073 } 00074 00075 bool equals(const btHashInt& other) const 00076 { 00077 return getUid1() == other.getUid1(); 00078 } 00079 //to our success 00080 SIMD_FORCE_INLINE unsigned int getHash()const 00081 { 00082 int key = m_uid; 00083 // Thomas Wang's hash 00084 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 00085 return key; 00086 } 00087 }; 00088 00089 00090 00091 class btHashPtr 00092 { 00093 00094 union 00095 { 00096 const void* m_pointer; 00097 int m_hashValues[2]; 00098 }; 00099 00100 public: 00101 00102 btHashPtr(const void* ptr) 00103 :m_pointer(ptr) 00104 { 00105 } 00106 00107 const void* getPointer() const 00108 { 00109 return m_pointer; 00110 } 00111 00112 bool equals(const btHashPtr& other) const 00113 { 00114 return getPointer() == other.getPointer(); 00115 } 00116 00117 //to our success 00118 SIMD_FORCE_INLINE unsigned int getHash()const 00119 { 00120 const bool VOID_IS_8 = ((sizeof(void*)==8)); 00121 00122 int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; 00123 00124 // Thomas Wang's hash 00125 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 00126 return key; 00127 } 00128 00129 00130 }; 00131 00132 00133 template <class Value> 00134 class btHashKeyPtr 00135 { 00136 int m_uid; 00137 public: 00138 00139 btHashKeyPtr(int uid) :m_uid(uid) 00140 { 00141 } 00142 00143 int getUid1() const 00144 { 00145 return m_uid; 00146 } 00147 00148 bool equals(const btHashKeyPtr<Value>& other) const 00149 { 00150 return getUid1() == other.getUid1(); 00151 } 00152 00153 //to our success 00154 SIMD_FORCE_INLINE unsigned int getHash()const 00155 { 00156 int key = m_uid; 00157 // Thomas Wang's hash 00158 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 00159 return key; 00160 } 00161 00162 00163 }; 00164 00165 00166 template <class Value> 00167 class btHashKey 00168 { 00169 int m_uid; 00170 public: 00171 00172 btHashKey(int uid) :m_uid(uid) 00173 { 00174 } 00175 00176 int getUid1() const 00177 { 00178 return m_uid; 00179 } 00180 00181 bool equals(const btHashKey<Value>& other) const 00182 { 00183 return getUid1() == other.getUid1(); 00184 } 00185 //to our success 00186 SIMD_FORCE_INLINE unsigned int getHash()const 00187 { 00188 int key = m_uid; 00189 // Thomas Wang's hash 00190 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 00191 return key; 00192 } 00193 }; 00194 00195 00198 template <class Key, class Value> 00199 class btHashMap 00200 { 00201 00202 btAlignedObjectArray<int> m_hashTable; 00203 btAlignedObjectArray<int> m_next; 00204 00205 btAlignedObjectArray<Value> m_valueArray; 00206 btAlignedObjectArray<Key> m_keyArray; 00207 00208 void growTables(const Key& key) 00209 { 00210 int newCapacity = m_valueArray.capacity(); 00211 00212 if (m_hashTable.size() < newCapacity) 00213 { 00214 //grow hashtable and next table 00215 int curHashtableSize = m_hashTable.size(); 00216 00217 m_hashTable.resize(newCapacity); 00218 m_next.resize(newCapacity); 00219 00220 int i; 00221 00222 for (i= 0; i < newCapacity; ++i) 00223 { 00224 m_hashTable[i] = BT_HASH_NULL; 00225 } 00226 for (i = 0; i < newCapacity; ++i) 00227 { 00228 m_next[i] = BT_HASH_NULL; 00229 } 00230 00231 for(i=0;i<curHashtableSize;i++) 00232 { 00233 //const Value& value = m_valueArray[i]; 00234 //const Key& key = m_keyArray[i]; 00235 00236 int hashValue = m_keyArray[i].getHash() & (m_valueArray.capacity()-1); // New hash value with new mask 00237 m_next[i] = m_hashTable[hashValue]; 00238 m_hashTable[hashValue] = i; 00239 } 00240 00241 00242 } 00243 } 00244 00245 public: 00246 00247 void insert(const Key& key, const Value& value) { 00248 int hash = key.getHash() & (m_valueArray.capacity()-1); 00249 00250 //replace value if the key is already there 00251 int index = findIndex(key); 00252 if (index != BT_HASH_NULL) 00253 { 00254 m_valueArray[index]=value; 00255 return; 00256 } 00257 00258 int count = m_valueArray.size(); 00259 int oldCapacity = m_valueArray.capacity(); 00260 m_valueArray.push_back(value); 00261 m_keyArray.push_back(key); 00262 00263 int newCapacity = m_valueArray.capacity(); 00264 if (oldCapacity < newCapacity) 00265 { 00266 growTables(key); 00267 //hash with new capacity 00268 hash = key.getHash() & (m_valueArray.capacity()-1); 00269 } 00270 m_next[count] = m_hashTable[hash]; 00271 m_hashTable[hash] = count; 00272 } 00273 00274 void remove(const Key& key) { 00275 00276 int hash = key.getHash() & (m_valueArray.capacity()-1); 00277 00278 int pairIndex = findIndex(key); 00279 00280 if (pairIndex ==BT_HASH_NULL) 00281 { 00282 return; 00283 } 00284 00285 // Remove the pair from the hash table. 00286 int index = m_hashTable[hash]; 00287 btAssert(index != BT_HASH_NULL); 00288 00289 int previous = BT_HASH_NULL; 00290 while (index != pairIndex) 00291 { 00292 previous = index; 00293 index = m_next[index]; 00294 } 00295 00296 if (previous != BT_HASH_NULL) 00297 { 00298 btAssert(m_next[previous] == pairIndex); 00299 m_next[previous] = m_next[pairIndex]; 00300 } 00301 else 00302 { 00303 m_hashTable[hash] = m_next[pairIndex]; 00304 } 00305 00306 // We now move the last pair into spot of the 00307 // pair being removed. We need to fix the hash 00308 // table indices to support the move. 00309 00310 int lastPairIndex = m_valueArray.size() - 1; 00311 00312 // If the removed pair is the last pair, we are done. 00313 if (lastPairIndex == pairIndex) 00314 { 00315 m_valueArray.pop_back(); 00316 m_keyArray.pop_back(); 00317 return; 00318 } 00319 00320 // Remove the last pair from the hash table. 00321 int lastHash = m_keyArray[lastPairIndex].getHash() & (m_valueArray.capacity()-1); 00322 00323 index = m_hashTable[lastHash]; 00324 btAssert(index != BT_HASH_NULL); 00325 00326 previous = BT_HASH_NULL; 00327 while (index != lastPairIndex) 00328 { 00329 previous = index; 00330 index = m_next[index]; 00331 } 00332 00333 if (previous != BT_HASH_NULL) 00334 { 00335 btAssert(m_next[previous] == lastPairIndex); 00336 m_next[previous] = m_next[lastPairIndex]; 00337 } 00338 else 00339 { 00340 m_hashTable[lastHash] = m_next[lastPairIndex]; 00341 } 00342 00343 // Copy the last pair into the remove pair's spot. 00344 m_valueArray[pairIndex] = m_valueArray[lastPairIndex]; 00345 m_keyArray[pairIndex] = m_keyArray[lastPairIndex]; 00346 00347 // Insert the last pair into the hash table 00348 m_next[pairIndex] = m_hashTable[lastHash]; 00349 m_hashTable[lastHash] = pairIndex; 00350 00351 m_valueArray.pop_back(); 00352 m_keyArray.pop_back(); 00353 00354 } 00355 00356 00357 int size() const 00358 { 00359 return m_valueArray.size(); 00360 } 00361 00362 const Value* getAtIndex(int index) const 00363 { 00364 btAssert(index < m_valueArray.size()); 00365 00366 return &m_valueArray[index]; 00367 } 00368 00369 Value* getAtIndex(int index) 00370 { 00371 btAssert(index < m_valueArray.size()); 00372 00373 return &m_valueArray[index]; 00374 } 00375 00376 Value* operator[](const Key& key) { 00377 return find(key); 00378 } 00379 00380 const Value* find(const Key& key) const 00381 { 00382 int index = findIndex(key); 00383 if (index == BT_HASH_NULL) 00384 { 00385 return NULL; 00386 } 00387 return &m_valueArray[index]; 00388 } 00389 00390 Value* find(const Key& key) 00391 { 00392 int index = findIndex(key); 00393 if (index == BT_HASH_NULL) 00394 { 00395 return NULL; 00396 } 00397 return &m_valueArray[index]; 00398 } 00399 00400 00401 int findIndex(const Key& key) const 00402 { 00403 unsigned int hash = key.getHash() & (m_valueArray.capacity()-1); 00404 00405 if (hash >= (unsigned int)m_hashTable.size()) 00406 { 00407 return BT_HASH_NULL; 00408 } 00409 00410 int index = m_hashTable[hash]; 00411 while ((index != BT_HASH_NULL) && key.equals(m_keyArray[index]) == false) 00412 { 00413 index = m_next[index]; 00414 } 00415 return index; 00416 } 00417 00418 void clear() 00419 { 00420 m_hashTable.clear(); 00421 m_next.clear(); 00422 m_valueArray.clear(); 00423 m_keyArray.clear(); 00424 } 00425 00426 }; 00427 00428 #endif //BT_HASH_MAP_H
1.6.1