btHashMap.h 9.8 KB

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