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