hkCachedHashMap.cxx
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:11k
源码类别:

其他游戏

开发平台:

Visual C++

  1. /* 
  2.  * 
  3.  * Confidential Information of Telekinesys Research Limited (t/a Havok). Not for disclosure or distribution without Havok's
  4.  * prior written consent. This software contains code, techniques and know-how which is confidential and proprietary to Havok.
  5.  * Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2009 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
  6.  * 
  7.  */
  8. #include <Common/Base/hkBase.h>
  9. #include <Common/Base/Container/StringMap/hkStringMapBase.h>
  10. #define HASH_EMPTY hkUlong(-1)
  11. // Quick description:
  12. // The hash table is stored as a linear list. Initially all keys
  13. // are 0xff (empty). When we insert an element, we jump to the items
  14. // hash and scan forwards until we find the key or we come to an empty entry.
  15. // If the hash function is good and the table is not too crowded, we're
  16. // likely to have good performance and be cache friendly.
  17. // The first third of m_elem are the hashes, the second third the string pointers
  18. // and the final third, the value pointers.
  19. #define ELEM_HASH(i) (m_elem[i])
  20. #define ELEM_KEY(i)  (m_elem[i+m_hashMod+1])
  21. #define ELEM_VAL(i)  (m_elem[i+m_hashMod+m_hashMod+2])
  22. #define NOT_EQUAL(i,hash,key,ops) 
  23. ((ELEM_HASH(i) != hash) || (ops.equal( key, ELEM_KEY(i) ) == 0))
  24. #define EQUAL(i,hash,key,ops) 
  25. ((ELEM_HASH(i) == hash) && (ops.equal( key, ELEM_KEY(i) )     ))
  26. template<typename Operations>
  27. hkCachedHashMap<Operations>::hkCachedHashMap(Operations ops)
  28. : m_ops(ops)
  29. {
  30. const int initialCapacity = 16;
  31. m_elem = hkAllocateChunk<hkUlong>(initialCapacity*3, HK_MEMORY_CLASS_ARRAY);
  32. hkString::memSet( m_elem, 0xff, hkSizeOf(hkUlong) * initialCapacity );
  33. m_numElems = 0;
  34. m_hashMod = initialCapacity - 1;
  35. }
  36. template<typename Operations>
  37. hkCachedHashMap<Operations>::~hkCachedHashMap()
  38. {
  39. hkDeallocateChunk<hkUlong>( m_elem, (m_hashMod+1)*3, HK_MEMORY_CLASS_ARRAY );
  40. }
  41. template<typename Operations>
  42. hkCachedHashMap<Operations>* hkCachedHashMap<Operations>::operator=(const hkCachedHashMap* other)
  43. {
  44. // Deallocate our storage
  45. hkDeallocateChunk<hkUlong>( m_elem, (m_hashMod+1)*3, HK_MEMORY_CLASS_ARRAY );
  46. // Copy other storage
  47. this->m_hashMod = other->m_hashMod;
  48. this->m_numElems = other->m_numElems;
  49. m_elem = hkAllocateChunk<hkUlong>( (m_hashMod+1)*3, HK_MEMORY_CLASS_ARRAY);
  50. hkString::memCpy(m_elem, other->m_elem, (m_hashMod+1)*3);
  51. HK_ASSERT( 0x74305156, this->isOk());
  52. return this;
  53. }
  54. template<typename Operations>
  55. typename hkCachedHashMap<Operations>::Iterator hkCachedHashMap<Operations>::getIterator() const
  56. {
  57. int i;
  58. for( i = 0; i <= m_hashMod; ++i )
  59. {
  60. if( ELEM_HASH(i) != HASH_EMPTY )
  61. {
  62. break;
  63. }
  64. }
  65. return reinterpret_cast<Iterator>( hkUlong(i) );
  66. }
  67. template<typename Operations>
  68. hkUlong hkCachedHashMap<Operations>::getKey(Iterator it) const
  69. {
  70. int i = static_cast<int>( reinterpret_cast<hkUlong>(it) );
  71. HK_ASSERT(0x7f305156, i>=0 && i<=m_hashMod);
  72. return ELEM_KEY(i);
  73. }
  74. template<typename Operations>
  75. hkUlong hkCachedHashMap<Operations>::getValue(Iterator it) const
  76. {
  77. int i = static_cast<int>( reinterpret_cast<hkUlong>(it) );
  78. HK_ASSERT(0x7f305156, i>=0 && i<=m_hashMod);
  79. return ELEM_VAL(i);
  80. }
  81. template<typename Operations>
  82. void hkCachedHashMap<Operations>::setValue(Iterator it, hkUlong val)
  83. {
  84. int i = static_cast<int>( reinterpret_cast<hkUlong>(it) );
  85. HK_ASSERT(0x7f305156, i>=0 && i<=m_hashMod);
  86. ELEM_VAL(i) = val;
  87. }
  88. template<typename Operations>
  89. typename hkCachedHashMap<Operations>::Iterator hkCachedHashMap<Operations>::getNext( Iterator it ) const
  90. {
  91. int i = static_cast<int>( reinterpret_cast<hkUlong>(it) );
  92. HK_ASSERT(0x7f305156, i>=0 && i<=m_hashMod);
  93. for( i += 1; i <= m_hashMod; ++i )
  94. {
  95. if( ELEM_HASH(i) != HASH_EMPTY )
  96. {
  97. break;
  98. }
  99. }
  100. return reinterpret_cast<Iterator>( hkUlong(i) );
  101. }
  102. template<typename Operations>
  103. hkBool hkCachedHashMap<Operations>::isValid( Iterator it ) const
  104. {
  105. int i = static_cast<int>( reinterpret_cast<hkUlong>(it) );
  106. HK_ASSERT(0x7f305156, i>=0 && i<=m_hashMod+1);
  107. return i <= m_hashMod;
  108. }
  109. template<typename Operations>
  110. void hkCachedHashMap<Operations>::insert( hkUlong key, hkUlong val )
  111. {
  112. hkUlong hash = m_ops.hash(key);
  113. HK_ASSERT(0x3665dd06, hash != HASH_EMPTY);
  114. // This is quite conservative. We could grow more
  115. // slowly at the cost of potentially longer searches.
  116. if( (m_numElems + m_numElems ) > m_hashMod )
  117. {
  118. resizeTable(m_hashMod + m_hashMod + 2);
  119. }
  120. hkUlong i = hash & m_hashMod;
  121. while(1) // find free slot
  122. {
  123. if(ELEM_HASH(i) == HASH_EMPTY)
  124. {
  125. m_numElems += 1;
  126. break;
  127. }
  128. else if( NOT_EQUAL(i, hash, key, m_ops) )
  129. {
  130. i = (i+1) & m_hashMod;
  131. }
  132. else // overwrite a key
  133. {
  134. break;
  135. }
  136. }
  137. // insert key,value
  138. ELEM_HASH(i) = hash;
  139. ELEM_KEY(i)  = key;
  140. ELEM_VAL(i)  = val;
  141. }
  142. template<typename Operations>
  143. typename hkCachedHashMap<Operations>::Iterator hkCachedHashMap<Operations>::findKey( hkUlong key ) const
  144. {
  145. hkUlong hash = m_ops.hash(key);
  146. for( hkUlong i = hash & m_hashMod;
  147. ELEM_HASH(i) != HASH_EMPTY;
  148. i = (i+1) & m_hashMod )
  149. {
  150. if( EQUAL(i,hash,key,m_ops) )
  151. {
  152. return reinterpret_cast<Iterator>(i);
  153. }
  154. }
  155. return reinterpret_cast<Iterator>( hkUlong(m_hashMod+1) ); // not found
  156. }
  157. template<typename Operations>
  158. hkResult hkCachedHashMap<Operations>::get( hkUlong key, hkUlong* out ) const
  159. {
  160. Iterator it = findKey(key);
  161. if( isValid(it) )
  162. {
  163. *out = getValue(it);
  164. return HK_SUCCESS;
  165. }
  166. return HK_FAILURE;
  167. }
  168. template<typename Operations>
  169. hkUlong hkCachedHashMap<Operations>::getOrInsert( hkUlong key, hkUlong ifNotFound )
  170. {
  171. //TODO: examine table directly - save a lookup
  172. Iterator it = findKey(key);
  173. if( isValid(it) )
  174. {
  175. return getValue(it);
  176. }
  177. insert(key,ifNotFound);
  178. return ifNotFound;
  179. }
  180. template<typename Operations>
  181. hkUlong hkCachedHashMap<Operations>::getWithDefault( hkUlong key, hkUlong def ) const
  182. {
  183. hkUlong ret = def;
  184. get(key, &ret);
  185. return ret;
  186. }
  187. template<typename Operations>
  188. void hkCachedHashMap<Operations>::remove( Iterator it )
  189. {
  190. hkUlong i = reinterpret_cast<hkUlong>(it);
  191. // remove it
  192. --m_numElems;
  193. ELEM_HASH(i) = HASH_EMPTY;
  194. // find lowest element of this unbroken run
  195. hkUlong lo = ( i + m_hashMod ) & m_hashMod;
  196. while( ELEM_HASH(lo) != HASH_EMPTY )
  197. {
  198. lo = ( lo + m_hashMod ) & m_hashMod;
  199. }
  200. lo = ( lo + 1 ) & m_hashMod;
  201. // the slot which has become empty
  202. hkUlong empty = i;
  203. // sift up, closing any gaps we find
  204. for( i = (i + 1) & m_hashMod;
  205. ELEM_HASH(i) != HASH_EMPTY;
  206. i = (i+1) & m_hashMod )
  207. {
  208. hkUlong hmod = ELEM_HASH(i) & m_hashMod;
  209. // Three cases to consider here. 
  210. // a) The normal case where lo <= empty < i.
  211. // b) The case where i has wrapped around.
  212. // c) The case where both i and empty have wrapped around.
  213. // The initial case will be a. (Or b if the last slot is freed).
  214. // and may progress to b, and finally c.
  215. // The algorithm will terminate before 'i' reaches 'lo'
  216. // otherwise the table would have no free slots.
  217. // 'normal'      'i wrapped'   'i and empty wrapped'
  218. // ===== lo      ===== i       ===== empty
  219. // ===== empty   ===== lo      ===== i 
  220. // ===== i       ===== empty   ===== lo     
  221. if( ( i >= lo ) && ( hmod > empty ) )
  222. {
  223. continue;
  224. }
  225. else if( ( i < empty ) && ( hmod > empty || hmod <= i ) )
  226. {
  227. continue;
  228. }
  229. else if( /*i > empty && */ ( hmod > empty && hmod < lo ) )
  230. {
  231. continue;
  232. }
  233. HK_ASSERT(0x3278358f,  i != empty ); // by design
  234. HK_ASSERT(0x7e3aeff8,  i != lo ); // table became full?!
  235. // copy up
  236. ELEM_HASH(empty) = ELEM_HASH(i);
  237. ELEM_KEY(empty)  = ELEM_KEY(i);
  238. ELEM_VAL(empty)  = ELEM_VAL(i);
  239. // source slot is now free
  240. ELEM_HASH(i) = HASH_EMPTY;
  241. empty = i;
  242. }
  243. }
  244. template<typename Operations>
  245. hkResult hkCachedHashMap<Operations>::remove( hkUlong key )
  246. {
  247. Iterator it = findKey(key);
  248. if( isValid(it) )
  249. {
  250. remove(it);
  251. return HK_SUCCESS;
  252. }
  253. return HK_FAILURE;
  254. }
  255. template<typename Operations>
  256. void hkCachedHashMap<Operations>::resizeTable(int newcap)
  257. {
  258. HK_ASSERT2(0x1fdccddd,  m_numElems < newcap, "table size is not big enough" );
  259. HK_ASSERT2(0x18d91741,  HK_NEXT_MULTIPLE_OF(2, newcap) == newcap, "table size should be a power of 2" );
  260. int oldcap = m_hashMod+1;
  261. hkUlong* oldelem = m_elem;
  262. m_elem = hkAllocateChunk<hkUlong>(newcap*3, HK_MEMORY_CLASS_ARRAY); // space for values too
  263. hkString::memSet( m_elem, 0xff, hkSizeOf(hkUlong) * newcap ); // dont bother to zero values
  264. m_numElems = 0;
  265. m_hashMod = newcap - 1;
  266. for( int i = 0; i < oldcap; ++i )
  267. {
  268. if( oldelem[i] != HASH_EMPTY)
  269. {
  270. insert( oldelem[i+oldcap], oldelem[i+oldcap+oldcap] );
  271. }
  272. }
  273. hkDeallocateChunk<hkUlong>( oldelem, oldcap*3, HK_MEMORY_CLASS_ARRAY );
  274. }
  275. template<typename Operations>
  276. hkBool hkCachedHashMap<Operations>::isOk() const
  277. {
  278. // is count consistent?
  279. int count = 0;
  280. int i;
  281. for( i = 0; i <= m_hashMod; ++i )
  282. {
  283. count += ELEM_HASH(i) != HASH_EMPTY;
  284. }
  285. HK_ASSERT(0x11c13481,  count == m_numElems );
  286. // is element reachable from its hash?
  287. for( i = 0; i <= m_hashMod; ++i )
  288. {
  289. if( ELEM_HASH(i) != HASH_EMPTY )
  290. {
  291. hkUlong hash = ELEM_HASH(i);
  292. hkUlong key = ELEM_KEY(i);
  293. hkUlong j = hash & m_hashMod;
  294. while( NOT_EQUAL(j, hash, key, m_ops) )
  295. {
  296. j = (j + 1) & m_hashMod;
  297. HK_ASSERT(0x5ec0df1b,  ELEM_HASH(j) != HASH_EMPTY );
  298. }
  299. }
  300. return true;
  301. }
  302. template<typename Operations>
  303. void hkCachedHashMap<Operations>::clear()
  304. {
  305. for( int i = 0; i < m_hashMod+1; ++i )
  306. {
  307. m_elem[i] = hkUlong(-1);
  308. }
  309. m_numElems = 0;
  310. }
  311. template<typename Operations>
  312. void hkCachedHashMap<Operations>::swap( hkCachedHashMap& other )
  313. {
  314. hkUlong* te = m_elem;
  315. hkUlong tn = m_numElems;
  316. hkUlong th = m_hashMod;
  317. m_elem = other.m_elem;
  318. m_numElems = other.m_numElems;
  319. m_hashMod = other.m_hashMod;
  320. other.m_elem = te;
  321. other.m_numElems = static_cast<int>(tn);
  322. other.m_hashMod = static_cast<int>(th);
  323. }
  324. template<typename Operations>
  325. void hkCachedHashMap<Operations>::merge( const hkCachedHashMap& other )
  326. {
  327. int ohm = other.m_hashMod;
  328. for( int i = 0; i <= ohm; ++i )
  329. {
  330. if( other.m_elem[i] != HASH_EMPTY )
  331. {
  332. hkUlong key = other.m_elem[i+ohm+1];
  333. hkUlong val = other.m_elem[i+ohm+ohm+2];
  334. insert( key, val );
  335. }
  336. }
  337. /*
  338. * Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20090216)
  339. * Confidential Information of Havok.  (C) Copyright 1999-2009
  340. * Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
  341. * Logo, and the Havok buzzsaw logo are trademarks of Havok.  Title, ownership
  342. * rights, and intellectual property rights in the Havok software remain in
  343. * Havok and/or its suppliers.
  344. * Use of this software for evaluation purposes is subject to and indicates
  345. * acceptance of the End User licence Agreement for this product. A copy of
  346. * the license is included with this software and is also available at www.havok.com/tryhavok.
  347. */