btHashMap.h 8.2 KB

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