btHashMap.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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 = *(unsigned char *)src - *(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(int uid) :m_uid(uid)
  63. {
  64. }
  65. int getUid1() const
  66. {
  67. return m_uid;
  68. }
  69. void setUid1(int uid)
  70. {
  71. m_uid = uid;
  72. }
  73. bool equals(const btHashInt& other) const
  74. {
  75. return getUid1() == other.getUid1();
  76. }
  77. //to our success
  78. SIMD_FORCE_INLINE unsigned int getHash()const
  79. {
  80. int key = m_uid;
  81. // Thomas Wang's hash
  82. key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16);
  83. return key;
  84. }
  85. };
  86. class btHashPtr
  87. {
  88. union
  89. {
  90. const void* m_pointer;
  91. int m_hashValues[2];
  92. };
  93. public:
  94. btHashPtr(const void* ptr)
  95. :m_pointer(ptr)
  96. {
  97. }
  98. const void* getPointer() const
  99. {
  100. return m_pointer;
  101. }
  102. bool equals(const btHashPtr& other) const
  103. {
  104. return getPointer() == other.getPointer();
  105. }
  106. //to our success
  107. SIMD_FORCE_INLINE unsigned int getHash()const
  108. {
  109. const bool VOID_IS_8 = ((sizeof(void*)==8));
  110. int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0];
  111. // Thomas Wang's hash
  112. key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16);
  113. return key;
  114. }
  115. };
  116. template <class Value>
  117. class btHashKeyPtr
  118. {
  119. int m_uid;
  120. public:
  121. btHashKeyPtr(int uid) :m_uid(uid)
  122. {
  123. }
  124. int getUid1() const
  125. {
  126. return m_uid;
  127. }
  128. bool equals(const btHashKeyPtr<Value>& other) const
  129. {
  130. return getUid1() == other.getUid1();
  131. }
  132. //to our success
  133. SIMD_FORCE_INLINE unsigned int getHash()const
  134. {
  135. int key = m_uid;
  136. // Thomas Wang's hash
  137. key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16);
  138. return key;
  139. }
  140. };
  141. template <class Value>
  142. class btHashKey
  143. {
  144. int m_uid;
  145. public:
  146. btHashKey(int uid) :m_uid(uid)
  147. {
  148. }
  149. int getUid1() const
  150. {
  151. return m_uid;
  152. }
  153. bool equals(const btHashKey<Value>& other) const
  154. {
  155. return getUid1() == other.getUid1();
  156. }
  157. //to our success
  158. SIMD_FORCE_INLINE unsigned int getHash()const
  159. {
  160. int key = m_uid;
  161. // Thomas Wang's hash
  162. key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16);
  163. return key;
  164. }
  165. };
  166. ///The btHashMap template class implements a generic and lightweight hashmap.
  167. ///A basic sample of how to use btHashMap is located in Demos\BasicDemo\main.cpp
  168. template <class Key, class Value>
  169. class btHashMap
  170. {
  171. protected:
  172. btAlignedObjectArray<int> m_hashTable;
  173. btAlignedObjectArray<int> m_next;
  174. btAlignedObjectArray<Value> m_valueArray;
  175. btAlignedObjectArray<Key> m_keyArray;
  176. void growTables(const Key& /*key*/)
  177. {
  178. int newCapacity = m_valueArray.capacity();
  179. if (m_hashTable.size() < newCapacity)
  180. {
  181. //grow hashtable and next table
  182. int curHashtableSize = m_hashTable.size();
  183. m_hashTable.resize(newCapacity);
  184. m_next.resize(newCapacity);
  185. int i;
  186. for (i= 0; i < newCapacity; ++i)
  187. {
  188. m_hashTable[i] = BT_HASH_NULL;
  189. }
  190. for (i = 0; i < newCapacity; ++i)
  191. {
  192. m_next[i] = BT_HASH_NULL;
  193. }
  194. for(i=0;i<curHashtableSize;i++)
  195. {
  196. //const Value& value = m_valueArray[i];
  197. //const Key& key = m_keyArray[i];
  198. int hashValue = m_keyArray[i].getHash() & (m_valueArray.capacity()-1); // New hash value with new mask
  199. m_next[i] = m_hashTable[hashValue];
  200. m_hashTable[hashValue] = i;
  201. }
  202. }
  203. }
  204. public:
  205. void insert(const Key& key, const Value& value) {
  206. int hash = key.getHash() & (m_valueArray.capacity()-1);
  207. //replace value if the key is already there
  208. int index = findIndex(key);
  209. if (index != BT_HASH_NULL)
  210. {
  211. m_valueArray[index]=value;
  212. return;
  213. }
  214. int count = m_valueArray.size();
  215. int oldCapacity = m_valueArray.capacity();
  216. m_valueArray.push_back(value);
  217. m_keyArray.push_back(key);
  218. int newCapacity = m_valueArray.capacity();
  219. if (oldCapacity < newCapacity)
  220. {
  221. growTables(key);
  222. //hash with new capacity
  223. hash = key.getHash() & (m_valueArray.capacity()-1);
  224. }
  225. m_next[count] = m_hashTable[hash];
  226. m_hashTable[hash] = count;
  227. }
  228. void remove(const Key& key) {
  229. int hash = key.getHash() & (m_valueArray.capacity()-1);
  230. int pairIndex = findIndex(key);
  231. if (pairIndex ==BT_HASH_NULL)
  232. {
  233. return;
  234. }
  235. // Remove the pair from the hash table.
  236. int index = m_hashTable[hash];
  237. btAssert(index != BT_HASH_NULL);
  238. int previous = BT_HASH_NULL;
  239. while (index != pairIndex)
  240. {
  241. previous = index;
  242. index = m_next[index];
  243. }
  244. if (previous != BT_HASH_NULL)
  245. {
  246. btAssert(m_next[previous] == pairIndex);
  247. m_next[previous] = m_next[pairIndex];
  248. }
  249. else
  250. {
  251. m_hashTable[hash] = m_next[pairIndex];
  252. }
  253. // We now move the last pair into spot of the
  254. // pair being removed. We need to fix the hash
  255. // table indices to support the move.
  256. int lastPairIndex = m_valueArray.size() - 1;
  257. // If the removed pair is the last pair, we are done.
  258. if (lastPairIndex == pairIndex)
  259. {
  260. m_valueArray.pop_back();
  261. m_keyArray.pop_back();
  262. return;
  263. }
  264. // Remove the last pair from the hash table.
  265. int lastHash = m_keyArray[lastPairIndex].getHash() & (m_valueArray.capacity()-1);
  266. index = m_hashTable[lastHash];
  267. btAssert(index != BT_HASH_NULL);
  268. previous = BT_HASH_NULL;
  269. while (index != lastPairIndex)
  270. {
  271. previous = index;
  272. index = m_next[index];
  273. }
  274. if (previous != BT_HASH_NULL)
  275. {
  276. btAssert(m_next[previous] == lastPairIndex);
  277. m_next[previous] = m_next[lastPairIndex];
  278. }
  279. else
  280. {
  281. m_hashTable[lastHash] = m_next[lastPairIndex];
  282. }
  283. // Copy the last pair into the remove pair's spot.
  284. m_valueArray[pairIndex] = m_valueArray[lastPairIndex];
  285. m_keyArray[pairIndex] = m_keyArray[lastPairIndex];
  286. // Insert the last pair into the hash table
  287. m_next[pairIndex] = m_hashTable[lastHash];
  288. m_hashTable[lastHash] = pairIndex;
  289. m_valueArray.pop_back();
  290. m_keyArray.pop_back();
  291. }
  292. int size() const
  293. {
  294. return m_valueArray.size();
  295. }
  296. const Value* getAtIndex(int index) const
  297. {
  298. btAssert(index < m_valueArray.size());
  299. return &m_valueArray[index];
  300. }
  301. Value* getAtIndex(int index)
  302. {
  303. btAssert(index < m_valueArray.size());
  304. return &m_valueArray[index];
  305. }
  306. Value* operator[](const Key& key) {
  307. return find(key);
  308. }
  309. const Value* find(const Key& key) const
  310. {
  311. int index = findIndex(key);
  312. if (index == BT_HASH_NULL)
  313. {
  314. return NULL;
  315. }
  316. return &m_valueArray[index];
  317. }
  318. Value* find(const Key& key)
  319. {
  320. int index = findIndex(key);
  321. if (index == BT_HASH_NULL)
  322. {
  323. return NULL;
  324. }
  325. return &m_valueArray[index];
  326. }
  327. int findIndex(const Key& key) const
  328. {
  329. unsigned int hash = key.getHash() & (m_valueArray.capacity()-1);
  330. if (hash >= (unsigned int)m_hashTable.size())
  331. {
  332. return BT_HASH_NULL;
  333. }
  334. int index = m_hashTable[hash];
  335. while ((index != BT_HASH_NULL) && key.equals(m_keyArray[index]) == false)
  336. {
  337. index = m_next[index];
  338. }
  339. return index;
  340. }
  341. void clear()
  342. {
  343. m_hashTable.clear();
  344. m_next.clear();
  345. m_valueArray.clear();
  346. m_keyArray.clear();
  347. }
  348. };
  349. #endif //BT_HASH_MAP_H