1 /* 2 Bullet Continuous Collision Detection and Physics Library 3 Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 4 5 This software is provided 'as-is', without any express or implied warranty. 6 In no event will the authors be held liable for any damages arising from the use of this software. 7 Permission is granted to anyone to use this software for any purpose, 8 including commercial applications, and to alter it and redistribute it freely, 9 subject to the following restrictions: 10 11 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. 12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 13 3. This notice may not be removed or altered from any source distribution. 14 */ 15 16 17 #ifndef BT_HASH_MAP_H 18 #define BT_HASH_MAP_H 19 20 #include "btAlignedObjectArray.h" 21 22 ///very basic hashable string implementation, compatible with btHashMap 23 struct btHashString 24 { 25 const char* m_string; 26 unsigned int m_hash; 27 28 SIMD_FORCE_INLINE unsigned int getHash()const 29 { 30 return m_hash; 31 } 32 33 btHashString(const char* name) 34 :m_string(name) 35 { 36 /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */ 37 static const unsigned int InitialFNV = 2166136261u; 38 static const unsigned int FNVMultiple = 16777619u; 39 40 /* Fowler / Noll / Vo (FNV) Hash */ 41 unsigned int hash = InitialFNV; 42 43 for(int i = 0; m_string[i]; i++) 44 { 45 hash = hash ^ (m_string[i]); /* xor the low 8 bits */ 46 hash = hash * FNVMultiple; /* multiply by the magic number */ 47 } 48 m_hash = hash; 49 } 50 51 int portableStringCompare(const char* src, const char* dst) const 52 { 53 int ret = 0 ; 54 55 while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) 56 ++src, ++dst; 57 58 if ( ret < 0 ) 59 ret = -1 ; 60 else if ( ret > 0 ) 61 ret = 1 ; 62 63 return( ret ); 64 } 65 66 bool equals(const btHashString& other) const 67 { 68 return (m_string == other.m_string) || 69 (0==portableStringCompare(m_string,other.m_string)); 70 71 } 72 73 }; 74 75 const int BT_HASH_NULL=0xffffffff; 76 77 78 class btHashInt 79 { 80 int m_uid; 81 public: 82 btHashInt(int uid) :m_uid(uid) 83 { 84 } 85 86 int getUid1() const 87 { 88 return m_uid; 89 } 90 91 void setUid1(int uid) 92 { 93 m_uid = uid; 94 } 95 96 bool equals(const btHashInt& other) const 97 { 98 return getUid1() == other.getUid1(); 99 } 100 //to our success 101 SIMD_FORCE_INLINE unsigned int getHash()const 102 { 103 int key = m_uid; 104 // Thomas Wang's hash 105 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 106 return key; 107 } 108 }; 109 110 111 112 class btHashPtr 113 { 114 115 union 116 { 117 const void* m_pointer; 118 int m_hashValues[2]; 119 }; 120 121 public: 122 123 btHashPtr(const void* ptr) 124 :m_pointer(ptr) 125 { 126 } 127 128 const void* getPointer() const 129 { 130 return m_pointer; 131 } 132 133 bool equals(const btHashPtr& other) const 134 { 135 return getPointer() == other.getPointer(); 136 } 137 138 //to our success 139 SIMD_FORCE_INLINE unsigned int getHash()const 140 { 141 const bool VOID_IS_8 = ((sizeof(void*)==8)); 142 143 int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; 144 145 // Thomas Wang's hash 146 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 147 return key; 148 } 149 150 151 }; 152 153 154 template <class Value> 155 class btHashKeyPtr 156 { 157 int m_uid; 158 public: 159 160 btHashKeyPtr(int uid) :m_uid(uid) 161 { 162 } 163 164 int getUid1() const 165 { 166 return m_uid; 167 } 168 169 bool equals(const btHashKeyPtr<Value>& other) const 170 { 171 return getUid1() == other.getUid1(); 172 } 173 174 //to our success 175 SIMD_FORCE_INLINE unsigned int getHash()const 176 { 177 int key = m_uid; 178 // Thomas Wang's hash 179 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 180 return key; 181 } 182 183 184 }; 185 186 187 template <class Value> 188 class btHashKey 189 { 190 int m_uid; 191 public: 192 193 btHashKey(int uid) :m_uid(uid) 194 { 195 } 196 197 int getUid1() const 198 { 199 return m_uid; 200 } 201 202 bool equals(const btHashKey<Value>& other) const 203 { 204 return getUid1() == other.getUid1(); 205 } 206 //to our success 207 SIMD_FORCE_INLINE unsigned int getHash()const 208 { 209 int key = m_uid; 210 // Thomas Wang's hash 211 key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); 212 return key; 213 } 214 }; 215 216 217 ///The btHashMap template class implements a generic and lightweight hashmap. 218 ///A basic sample of how to use btHashMap is located in Demos\BasicDemo\main.cpp 219 template <class Key, class Value> 220 class btHashMap 221 { 222 223 protected: 224 btAlignedObjectArray<int> m_hashTable; 225 btAlignedObjectArray<int> m_next; 226 227 btAlignedObjectArray<Value> m_valueArray; 228 btAlignedObjectArray<Key> m_keyArray; 229 230 void growTables(const Key& /*key*/) 231 { 232 int newCapacity = m_valueArray.capacity(); 233 234 if (m_hashTable.size() < newCapacity) 235 { 236 //grow hashtable and next table 237 int curHashtableSize = m_hashTable.size(); 238 239 m_hashTable.resize(newCapacity); 240 m_next.resize(newCapacity); 241 242 int i; 243 244 for (i= 0; i < newCapacity; ++i) 245 { 246 m_hashTable[i] = BT_HASH_NULL; 247 } 248 for (i = 0; i < newCapacity; ++i) 249 { 250 m_next[i] = BT_HASH_NULL; 251 } 252 253 for(i=0;i<curHashtableSize;i++) 254 { 255 //const Value& value = m_valueArray[i]; 256 //const Key& key = m_keyArray[i]; 257 258 int hashValue = m_keyArray[i].getHash() & (m_valueArray.capacity()-1); // New hash value with new mask 259 m_next[i] = m_hashTable[hashValue]; 260 m_hashTable[hashValue] = i; 261 } 262 263 264 } 265 } 266 267 public: 268 269 void insert(const Key& key, const Value& value) { 270 int hash = key.getHash() & (m_valueArray.capacity()-1); 271 272 //replace value if the key is already there 273 int index = findIndex(key); 274 if (index != BT_HASH_NULL) 275 { 276 m_valueArray[index]=value; 277 return; 278 } 279 280 int count = m_valueArray.size(); 281 int oldCapacity = m_valueArray.capacity(); 282 m_valueArray.push_back(value); 283 m_keyArray.push_back(key); 284 285 int newCapacity = m_valueArray.capacity(); 286 if (oldCapacity < newCapacity) 287 { 288 growTables(key); 289 //hash with new capacity 290 hash = key.getHash() & (m_valueArray.capacity()-1); 291 } 292 m_next[count] = m_hashTable[hash]; 293 m_hashTable[hash] = count; 294 } 295 296 void remove(const Key& key) { 297 298 int hash = key.getHash() & (m_valueArray.capacity()-1); 299 300 int pairIndex = findIndex(key); 301 302 if (pairIndex ==BT_HASH_NULL) 303 { 304 return; 305 } 306 307 // Remove the pair from the hash table. 308 int index = m_hashTable[hash]; 309 btAssert(index != BT_HASH_NULL); 310 311 int previous = BT_HASH_NULL; 312 while (index != pairIndex) 313 { 314 previous = index; 315 index = m_next[index]; 316 } 317 318 if (previous != BT_HASH_NULL) 319 { 320 btAssert(m_next[previous] == pairIndex); 321 m_next[previous] = m_next[pairIndex]; 322 } 323 else 324 { 325 m_hashTable[hash] = m_next[pairIndex]; 326 } 327 328 // We now move the last pair into spot of the 329 // pair being removed. We need to fix the hash 330 // table indices to support the move. 331 332 int lastPairIndex = m_valueArray.size() - 1; 333 334 // If the removed pair is the last pair, we are done. 335 if (lastPairIndex == pairIndex) 336 { 337 m_valueArray.pop_back(); 338 m_keyArray.pop_back(); 339 return; 340 } 341 342 // Remove the last pair from the hash table. 343 int lastHash = m_keyArray[lastPairIndex].getHash() & (m_valueArray.capacity()-1); 344 345 index = m_hashTable[lastHash]; 346 btAssert(index != BT_HASH_NULL); 347 348 previous = BT_HASH_NULL; 349 while (index != lastPairIndex) 350 { 351 previous = index; 352 index = m_next[index]; 353 } 354 355 if (previous != BT_HASH_NULL) 356 { 357 btAssert(m_next[previous] == lastPairIndex); 358 m_next[previous] = m_next[lastPairIndex]; 359 } 360 else 361 { 362 m_hashTable[lastHash] = m_next[lastPairIndex]; 363 } 364 365 // Copy the last pair into the remove pair's spot. 366 m_valueArray[pairIndex] = m_valueArray[lastPairIndex]; 367 m_keyArray[pairIndex] = m_keyArray[lastPairIndex]; 368 369 // Insert the last pair into the hash table 370 m_next[pairIndex] = m_hashTable[lastHash]; 371 m_hashTable[lastHash] = pairIndex; 372 373 m_valueArray.pop_back(); 374 m_keyArray.pop_back(); 375 376 } 377 378 379 int size() const 380 { 381 return m_valueArray.size(); 382 } 383 384 const Value* getAtIndex(int index) const 385 { 386 btAssert(index < m_valueArray.size()); 387 388 return &m_valueArray[index]; 389 } 390 391 Value* getAtIndex(int index) 392 { 393 btAssert(index < m_valueArray.size()); 394 395 return &m_valueArray[index]; 396 } 397 398 Value* operator[](const Key& key) { 399 return find(key); 400 } 401 402 const Value* find(const Key& key) const 403 { 404 int index = findIndex(key); 405 if (index == BT_HASH_NULL) 406 { 407 return NULL; 408 } 409 return &m_valueArray[index]; 410 } 411 412 Value* find(const Key& key) 413 { 414 int index = findIndex(key); 415 if (index == BT_HASH_NULL) 416 { 417 return NULL; 418 } 419 return &m_valueArray[index]; 420 } 421 422 423 int findIndex(const Key& key) const 424 { 425 unsigned int hash = key.getHash() & (m_valueArray.capacity()-1); 426 427 if (hash >= (unsigned int)m_hashTable.size()) 428 { 429 return BT_HASH_NULL; 430 } 431 432 int index = m_hashTable[hash]; 433 while ((index != BT_HASH_NULL) && key.equals(m_keyArray[index]) == false) 434 { 435 index = m_next[index]; 436 } 437 return index; 438 } 439 440 void clear() 441 { 442 m_hashTable.clear(); 443 m_next.clear(); 444 m_valueArray.clear(); 445 m_keyArray.clear(); 446 } 447 448 }; 449 450 #endif //BT_HASH_MAP_H 451