2
0

b3HashMap.h 9.2 KB

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