Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1299 lines
41 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. // Serialization/unserialization buffer
  8. //=============================================================================//
  9. #ifndef UTLHASH_H
  10. #define UTLHASH_H
  11. #pragma once
  12. #include <limits.h>
  13. #include "utlmemory.h"
  14. #include "utlvector.h"
  15. #include "utllinkedlist.h"
  16. #include "utllinkedlist.h"
  17. #include "commonmacros.h"
  18. #include "generichash.h"
  19. typedef unsigned int UtlHashHandle_t;
  20. template<class Data, typename C = bool (*)( Data const&, Data const& ), typename K = unsigned int (*)( Data const& ) >
  21. class CUtlHash
  22. {
  23. public:
  24. // compare and key functions - implemented by the
  25. typedef C CompareFunc_t;
  26. typedef K KeyFunc_t;
  27. // constructor/deconstructor
  28. explicit CUtlHash( int bucketCount = 0, int growCount = 0, int initCount = 0,
  29. CompareFunc_t compareFunc = 0, KeyFunc_t keyFunc = 0 );
  30. ~CUtlHash();
  31. // invalid handle
  32. static UtlHashHandle_t InvalidHandle( void ) { return ( UtlHashHandle_t )~0; }
  33. bool IsValidHandle( UtlHashHandle_t handle ) const;
  34. // size
  35. int Count( void ) const;
  36. // memory
  37. void Purge( void );
  38. // insertion methods
  39. UtlHashHandle_t Insert( Data const &src );
  40. UtlHashHandle_t Insert( Data const &src, bool *pDidInsert );
  41. UtlHashHandle_t AllocEntryFromKey( Data const &src );
  42. // removal methods
  43. void Remove( UtlHashHandle_t handle );
  44. void RemoveAll();
  45. // retrieval methods
  46. UtlHashHandle_t Find( Data const &src ) const;
  47. Data &Element( UtlHashHandle_t handle );
  48. Data const &Element( UtlHashHandle_t handle ) const;
  49. Data &operator[]( UtlHashHandle_t handle );
  50. Data const &operator[]( UtlHashHandle_t handle ) const;
  51. UtlHashHandle_t GetFirstHandle() const;
  52. UtlHashHandle_t GetNextHandle( UtlHashHandle_t h ) const;
  53. // debugging!!
  54. void Log( const char *filename );
  55. void Dump();
  56. protected:
  57. int GetBucketIndex( UtlHashHandle_t handle ) const;
  58. int GetKeyDataIndex( UtlHashHandle_t handle ) const;
  59. UtlHashHandle_t BuildHandle( int ndxBucket, int ndxKeyData ) const;
  60. bool DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const;
  61. protected:
  62. // handle upper 16 bits = bucket index (bucket heads)
  63. // handle lower 16 bits = key index (bucket list)
  64. typedef CUtlVector<Data> HashBucketList_t;
  65. CUtlVector<HashBucketList_t> m_Buckets;
  66. CompareFunc_t m_CompareFunc; // function used to handle unique compares on data
  67. KeyFunc_t m_KeyFunc; // function used to generate the key value
  68. bool m_bPowerOfTwo; // if the bucket value is a power of two,
  69. unsigned int m_ModMask; // use the mod mask to "mod"
  70. };
  71. //-----------------------------------------------------------------------------
  72. //-----------------------------------------------------------------------------
  73. template<class Data, typename C, typename K>
  74. CUtlHash<Data, C, K>::CUtlHash( int bucketCount, int growCount, int initCount,
  75. CompareFunc_t compareFunc, KeyFunc_t keyFunc ) :
  76. m_CompareFunc( compareFunc ),
  77. m_KeyFunc( keyFunc )
  78. {
  79. bucketCount = MIN(bucketCount, 65536);
  80. m_Buckets.SetSize( bucketCount );
  81. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  82. {
  83. m_Buckets[ndxBucket].SetSize( initCount );
  84. m_Buckets[ndxBucket].SetGrowSize( growCount );
  85. }
  86. // check to see if the bucket count is a power of 2 and set up
  87. // optimizations appropriately
  88. m_bPowerOfTwo = IsPowerOfTwo( bucketCount );
  89. m_ModMask = m_bPowerOfTwo ? (bucketCount-1) : 0;
  90. }
  91. //-----------------------------------------------------------------------------
  92. //-----------------------------------------------------------------------------
  93. template<class Data, typename C, typename K>
  94. CUtlHash<Data, C, K>::~CUtlHash()
  95. {
  96. Purge();
  97. }
  98. //-----------------------------------------------------------------------------
  99. //-----------------------------------------------------------------------------
  100. template<class Data, typename C, typename K>
  101. inline bool CUtlHash<Data, C, K>::IsValidHandle( UtlHashHandle_t handle ) const
  102. {
  103. int ndxBucket = GetBucketIndex( handle );
  104. int ndxKeyData = GetKeyDataIndex( handle );
  105. // ndxBucket and ndxKeyData can't possibly be less than zero -- take a
  106. // look at the definition of the Get..Index functions for why. However,
  107. // if you override those functions, you will need to override this one
  108. // as well.
  109. if( /*( ndxBucket >= 0 ) && */ ( ndxBucket < m_Buckets.Count() ) )
  110. {
  111. if( /*( ndxKeyData >= 0 ) && */ ( ndxKeyData < m_Buckets[ndxBucket].Count() ) )
  112. return true;
  113. }
  114. return false;
  115. }
  116. //-----------------------------------------------------------------------------
  117. //-----------------------------------------------------------------------------
  118. template<class Data, typename C, typename K>
  119. inline int CUtlHash<Data, C, K>::Count( void ) const
  120. {
  121. int count = 0;
  122. int bucketCount = m_Buckets.Count();
  123. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  124. {
  125. count += m_Buckets[ndxBucket].Count();
  126. }
  127. return count;
  128. }
  129. //-----------------------------------------------------------------------------
  130. //-----------------------------------------------------------------------------
  131. template<class Data, typename C, typename K>
  132. inline int CUtlHash<Data, C, K>::GetBucketIndex( UtlHashHandle_t handle ) const
  133. {
  134. return ( ( ( handle >> 16 ) & 0x0000ffff ) );
  135. }
  136. //-----------------------------------------------------------------------------
  137. //-----------------------------------------------------------------------------
  138. template<class Data, typename C, typename K>
  139. inline int CUtlHash<Data, C, K>::GetKeyDataIndex( UtlHashHandle_t handle ) const
  140. {
  141. return ( handle & 0x0000ffff );
  142. }
  143. //-----------------------------------------------------------------------------
  144. //-----------------------------------------------------------------------------
  145. template<class Data, typename C, typename K>
  146. inline UtlHashHandle_t CUtlHash<Data, C, K>::BuildHandle( int ndxBucket, int ndxKeyData ) const
  147. {
  148. Assert( ( ndxBucket >= 0 ) && ( ndxBucket < 65536 ) );
  149. Assert( ( ndxKeyData >= 0 ) && ( ndxKeyData < 65536 ) );
  150. UtlHashHandle_t handle = ndxKeyData;
  151. handle |= ( ndxBucket << 16 );
  152. return handle;
  153. }
  154. //-----------------------------------------------------------------------------
  155. //-----------------------------------------------------------------------------
  156. template<class Data, typename C, typename K>
  157. inline void CUtlHash<Data, C, K>::Purge( void )
  158. {
  159. int bucketCount = m_Buckets.Count();
  160. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  161. {
  162. m_Buckets[ndxBucket].Purge();
  163. }
  164. }
  165. //-----------------------------------------------------------------------------
  166. //-----------------------------------------------------------------------------
  167. template<class Data, typename C, typename K>
  168. inline bool CUtlHash<Data, C, K>::DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const
  169. {
  170. // generate the data "key"
  171. unsigned int key = m_KeyFunc( src );
  172. // hash the "key" - get the correct hash table "bucket"
  173. unsigned int ndxBucket;
  174. if( m_bPowerOfTwo )
  175. {
  176. *pBucket = ndxBucket = ( key & m_ModMask );
  177. }
  178. else
  179. {
  180. int bucketCount = m_Buckets.Count();
  181. *pBucket = ndxBucket = key % bucketCount;
  182. }
  183. int ndxKeyData = 0;
  184. const CUtlVector<Data> &bucket = m_Buckets[ndxBucket];
  185. int keyDataCount = bucket.Count();
  186. for( ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++ )
  187. {
  188. if( m_CompareFunc( bucket.Element( ndxKeyData ), src ) )
  189. break;
  190. }
  191. if( ndxKeyData == keyDataCount )
  192. return false;
  193. *pIndex = ndxKeyData;
  194. return true;
  195. }
  196. //-----------------------------------------------------------------------------
  197. //-----------------------------------------------------------------------------
  198. template<class Data, typename C, typename K>
  199. inline UtlHashHandle_t CUtlHash<Data, C, K>::Find( Data const &src ) const
  200. {
  201. unsigned int ndxBucket;
  202. int ndxKeyData = 0;
  203. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  204. {
  205. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  206. }
  207. return ( InvalidHandle() );
  208. }
  209. //-----------------------------------------------------------------------------
  210. //-----------------------------------------------------------------------------
  211. template<class Data, typename C, typename K>
  212. inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src )
  213. {
  214. unsigned int ndxBucket;
  215. int ndxKeyData = 0;
  216. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  217. {
  218. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  219. }
  220. ndxKeyData = m_Buckets[ndxBucket].AddToTail( src );
  221. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  222. }
  223. //-----------------------------------------------------------------------------
  224. //-----------------------------------------------------------------------------
  225. template<class Data, typename C, typename K>
  226. inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src, bool *pDidInsert )
  227. {
  228. unsigned int ndxBucket;
  229. int ndxKeyData = 0;
  230. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  231. {
  232. *pDidInsert = false;
  233. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  234. }
  235. *pDidInsert = true;
  236. ndxKeyData = m_Buckets[ndxBucket].AddToTail( src );
  237. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  238. }
  239. //-----------------------------------------------------------------------------
  240. //-----------------------------------------------------------------------------
  241. template<class Data, typename C, typename K>
  242. inline UtlHashHandle_t CUtlHash<Data, C, K>::AllocEntryFromKey( Data const &src )
  243. {
  244. unsigned int ndxBucket;
  245. int ndxKeyData = 0;
  246. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  247. {
  248. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  249. }
  250. ndxKeyData = m_Buckets[ndxBucket].AddToTail();
  251. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  252. }
  253. //-----------------------------------------------------------------------------
  254. //-----------------------------------------------------------------------------
  255. template<class Data, typename C, typename K>
  256. inline void CUtlHash<Data, C, K>::Remove( UtlHashHandle_t handle )
  257. {
  258. Assert( IsValidHandle( handle ) );
  259. // check to see if the bucket exists
  260. int ndxBucket = GetBucketIndex( handle );
  261. int ndxKeyData = GetKeyDataIndex( handle );
  262. if( m_Buckets[ndxBucket].IsValidIndex( ndxKeyData ) )
  263. {
  264. m_Buckets[ndxBucket].FastRemove( ndxKeyData );
  265. }
  266. }
  267. //-----------------------------------------------------------------------------
  268. //-----------------------------------------------------------------------------
  269. template<class Data, typename C, typename K>
  270. inline void CUtlHash<Data, C, K>::RemoveAll()
  271. {
  272. int bucketCount = m_Buckets.Count();
  273. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  274. {
  275. m_Buckets[ndxBucket].RemoveAll();
  276. }
  277. }
  278. //-----------------------------------------------------------------------------
  279. //-----------------------------------------------------------------------------
  280. template<class Data, typename C, typename K>
  281. inline Data &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle )
  282. {
  283. int ndxBucket = GetBucketIndex( handle );
  284. int ndxKeyData = GetKeyDataIndex( handle );
  285. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  286. }
  287. //-----------------------------------------------------------------------------
  288. //-----------------------------------------------------------------------------
  289. template<class Data, typename C, typename K>
  290. inline Data const &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle ) const
  291. {
  292. int ndxBucket = GetBucketIndex( handle );
  293. int ndxKeyData = GetKeyDataIndex( handle );
  294. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  295. }
  296. //-----------------------------------------------------------------------------
  297. //-----------------------------------------------------------------------------
  298. template<class Data, typename C, typename K>
  299. inline Data &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle )
  300. {
  301. int ndxBucket = GetBucketIndex( handle );
  302. int ndxKeyData = GetKeyDataIndex( handle );
  303. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  304. }
  305. //-----------------------------------------------------------------------------
  306. //-----------------------------------------------------------------------------
  307. template<class Data, typename C, typename K>
  308. inline Data const &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle ) const
  309. {
  310. int ndxBucket = GetBucketIndex( handle );
  311. int ndxKeyData = GetKeyDataIndex( handle );
  312. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  313. }
  314. //-----------------------------------------------------------------------------
  315. //-----------------------------------------------------------------------------
  316. template<class Data, typename C, typename K>
  317. inline UtlHashHandle_t CUtlHash<Data, C, K>::GetFirstHandle() const
  318. {
  319. return GetNextHandle( ( UtlHashHandle_t )-1 );
  320. }
  321. template<class Data, typename C, typename K>
  322. inline UtlHashHandle_t CUtlHash<Data, C, K>::GetNextHandle( UtlHashHandle_t handle ) const
  323. {
  324. ++handle; // start at the first possible handle after the one given
  325. int bi = GetBucketIndex( handle );
  326. int ki = GetKeyDataIndex( handle );
  327. int nBuckets = m_Buckets.Count();
  328. for ( ; bi < nBuckets; ++bi )
  329. {
  330. if ( ki < m_Buckets[ bi ].Count() )
  331. return BuildHandle( bi, ki );
  332. ki = 0;
  333. }
  334. return InvalidHandle();
  335. }
  336. //-----------------------------------------------------------------------------
  337. //-----------------------------------------------------------------------------
  338. template<class Data, typename C, typename K>
  339. inline void CUtlHash<Data, C, K>::Log( const char *filename )
  340. {
  341. FILE *pDebugFp;
  342. pDebugFp = fopen( filename, "w" );
  343. if( !pDebugFp )
  344. return;
  345. int maxBucketSize = 0;
  346. int numBucketsEmpty = 0;
  347. int bucketCount = m_Buckets.Count();
  348. fprintf( pDebugFp, "\n%d Buckets\n", bucketCount );
  349. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  350. {
  351. int count = m_Buckets[ndxBucket].Count();
  352. if( count > maxBucketSize ) { maxBucketSize = count; }
  353. if( count == 0 )
  354. numBucketsEmpty++;
  355. fprintf( pDebugFp, "Bucket %d: %d\n", ndxBucket, count );
  356. }
  357. fprintf( pDebugFp, "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty );
  358. fprintf( pDebugFp, "Max Bucket Size: %d\n", maxBucketSize );
  359. fclose( pDebugFp );
  360. }
  361. //-----------------------------------------------------------------------------
  362. //-----------------------------------------------------------------------------
  363. template<class Data, typename C, typename K>
  364. inline void CUtlHash<Data, C, K>::Dump( )
  365. {
  366. int maxBucketSize = 0;
  367. int numBucketsEmpty = 0;
  368. int bucketCount = m_Buckets.Count();
  369. Msg( "\n%d Buckets\n", bucketCount );
  370. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  371. {
  372. int count = m_Buckets[ndxBucket].Count();
  373. if( count > maxBucketSize ) { maxBucketSize = count; }
  374. if( count == 0 )
  375. numBucketsEmpty++;
  376. Msg( "Bucket %d: %d\n", ndxBucket, count );
  377. }
  378. Msg( "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty );
  379. Msg( "Max Bucket Size: %d\n", maxBucketSize );
  380. }
  381. //=============================================================================
  382. //
  383. // Fast Hash
  384. //
  385. // Number of buckets must be a power of 2.
  386. // Key must be 32-bits (unsigned int).
  387. //
  388. typedef intp UtlHashFastHandle_t;
  389. #define UTLHASH_POOL_SCALAR 2
  390. class CUtlHashFastNoHash
  391. {
  392. public:
  393. static int Hash( int key, int bucketMask )
  394. {
  395. return ( key & bucketMask );
  396. }
  397. };
  398. class CUtlHashFastGenericHash
  399. {
  400. public:
  401. static int Hash( int key, int bucketMask )
  402. {
  403. return ( HashIntConventional( key ) & bucketMask );
  404. }
  405. };
  406. template<class Data, class HashFuncs = CUtlHashFastNoHash >
  407. class CUtlHashFast
  408. {
  409. public:
  410. // Constructor/Deconstructor.
  411. CUtlHashFast();
  412. ~CUtlHashFast();
  413. // Memory.
  414. void Purge( void );
  415. // Invalid handle.
  416. static UtlHashFastHandle_t InvalidHandle( void ) { return ( UtlHashFastHandle_t )~0; }
  417. inline bool IsValidHandle( UtlHashFastHandle_t hHash ) const;
  418. // Initialize.
  419. bool Init( int nBucketCount );
  420. // Size not available; count is meaningless for multilists.
  421. // int Count( void ) const;
  422. // Insertion.
  423. UtlHashFastHandle_t Insert( uintp uiKey, const Data &data );
  424. UtlHashFastHandle_t FastInsert( uintp uiKey, const Data &data );
  425. // Removal.
  426. void Remove( UtlHashFastHandle_t hHash );
  427. void RemoveAll( void );
  428. // Retrieval.
  429. UtlHashFastHandle_t Find( uintp uiKey ) const;
  430. Data &Element( UtlHashFastHandle_t hHash );
  431. Data const &Element( UtlHashFastHandle_t hHash ) const;
  432. Data &operator[]( UtlHashFastHandle_t hHash );
  433. Data const &operator[]( UtlHashFastHandle_t hHash ) const;
  434. // Iteration
  435. struct UtlHashFastIterator_t
  436. {
  437. int bucket;
  438. UtlHashFastHandle_t handle;
  439. UtlHashFastIterator_t(int _bucket, const UtlHashFastHandle_t &_handle)
  440. : bucket(_bucket), handle(_handle) {};
  441. // inline operator UtlHashFastHandle_t() const { return handle; };
  442. };
  443. inline UtlHashFastIterator_t First() const;
  444. inline UtlHashFastIterator_t Next( const UtlHashFastIterator_t &hHash ) const;
  445. inline bool IsValidIterator( const UtlHashFastIterator_t &iter ) const;
  446. inline Data &operator[]( const UtlHashFastIterator_t &iter ) { return (*this)[iter.handle]; }
  447. inline Data const &operator[]( const UtlHashFastIterator_t &iter ) const { return (*this)[iter.handle]; }
  448. //protected:
  449. // Templatized for memory tracking purposes
  450. template <typename HashData>
  451. struct HashFastData_t_
  452. {
  453. uintp m_uiKey;
  454. HashData m_Data;
  455. };
  456. typedef HashFastData_t_<Data> HashFastData_t;
  457. uintp m_uiBucketMask;
  458. CUtlVector<UtlHashFastHandle_t> m_aBuckets;
  459. CUtlFixedLinkedList<HashFastData_t> m_aDataPool;
  460. };
  461. //-----------------------------------------------------------------------------
  462. // Purpose: Constructor
  463. //-----------------------------------------------------------------------------
  464. template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::CUtlHashFast()
  465. {
  466. Purge();
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Purpose: Deconstructor
  470. //-----------------------------------------------------------------------------
  471. template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::~CUtlHashFast()
  472. {
  473. Purge();
  474. }
  475. //-----------------------------------------------------------------------------
  476. // Purpose: Destroy dynamically allocated hash data.
  477. //-----------------------------------------------------------------------------
  478. template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Purge( void )
  479. {
  480. m_aBuckets.Purge();
  481. m_aDataPool.Purge();
  482. }
  483. //-----------------------------------------------------------------------------
  484. // Purpose: Initialize the hash - set bucket count and hash grow amount.
  485. //-----------------------------------------------------------------------------
  486. template<class Data, class HashFuncs> bool CUtlHashFast<Data,HashFuncs>::Init( int nBucketCount )
  487. {
  488. // Verify the bucket count is power of 2.
  489. if ( !IsPowerOfTwo( nBucketCount ) )
  490. return false;
  491. // Set the bucket size.
  492. m_aBuckets.SetSize( nBucketCount );
  493. for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket )
  494. {
  495. m_aBuckets[iBucket] = m_aDataPool.InvalidIndex();
  496. }
  497. // Set the mod mask.
  498. m_uiBucketMask = nBucketCount - 1;
  499. // Calculate the grow size.
  500. int nGrowSize = UTLHASH_POOL_SCALAR * nBucketCount;
  501. m_aDataPool.SetGrowSize( nGrowSize );
  502. return true;
  503. }
  504. //-----------------------------------------------------------------------------
  505. // Purpose: Return the number of elements in the hash.
  506. // Not available because count isn't accurately maintained for multilists.
  507. //-----------------------------------------------------------------------------
  508. /*
  509. template<class Data, class HashFuncs> inline int CUtlHashFast<Data,HashFuncs>::Count( void ) const
  510. {
  511. return m_aDataPool.Count();
  512. }
  513. */
  514. //-----------------------------------------------------------------------------
  515. // Purpose: Insert data into the hash table given its key (uintp), with
  516. // a check to see if the element already exists within the tree.
  517. //-----------------------------------------------------------------------------
  518. template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Insert( uintp uiKey, const Data &data )
  519. {
  520. // Check to see if that key already exists in the buckets (should be unique).
  521. UtlHashFastHandle_t hHash = Find( uiKey );
  522. if( hHash != InvalidHandle() )
  523. return hHash;
  524. return FastInsert( uiKey, data );
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Purpose: Insert data into the hash table given its key (uintp),
  528. // without a check to see if the element already exists within the tree.
  529. //-----------------------------------------------------------------------------
  530. template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::FastInsert( uintp uiKey, const Data &data )
  531. {
  532. // Get a new element from the pool.
  533. intp iHashData = m_aDataPool.Alloc( true );
  534. HashFastData_t *pHashData = &m_aDataPool[iHashData];
  535. if ( !pHashData )
  536. return InvalidHandle();
  537. // Add data to new element.
  538. pHashData->m_uiKey = uiKey;
  539. pHashData->m_Data = data;
  540. // Link element.
  541. int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask );
  542. m_aDataPool.LinkBefore( m_aBuckets[iBucket], iHashData );
  543. m_aBuckets[iBucket] = iHashData;
  544. return iHashData;
  545. }
  546. //-----------------------------------------------------------------------------
  547. // Purpose: Remove a given element from the hash.
  548. //-----------------------------------------------------------------------------
  549. template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Remove( UtlHashFastHandle_t hHash )
  550. {
  551. int iBucket = HashFuncs::Hash( m_aDataPool[hHash].m_uiKey, m_uiBucketMask );
  552. if ( m_aBuckets[iBucket] == hHash )
  553. {
  554. // It is a bucket head.
  555. m_aBuckets[iBucket] = m_aDataPool.Next( hHash );
  556. }
  557. else
  558. {
  559. // Not a bucket head.
  560. m_aDataPool.Unlink( hHash );
  561. }
  562. // Remove the element.
  563. m_aDataPool.Remove( hHash );
  564. }
  565. //-----------------------------------------------------------------------------
  566. // Purpose: Remove all elements from the hash
  567. //-----------------------------------------------------------------------------
  568. template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::RemoveAll( void )
  569. {
  570. m_aBuckets.RemoveAll();
  571. m_aDataPool.RemoveAll();
  572. }
  573. //-----------------------------------------------------------------------------
  574. //-----------------------------------------------------------------------------
  575. template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Find( uintp uiKey ) const
  576. {
  577. // hash the "key" - get the correct hash table "bucket"
  578. int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask );
  579. for ( intp iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next( iElement ) )
  580. {
  581. if ( m_aDataPool[iElement].m_uiKey == uiKey )
  582. return iElement;
  583. }
  584. return InvalidHandle();
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Purpose: Return data given a hash handle.
  588. //-----------------------------------------------------------------------------
  589. template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash )
  590. {
  591. return ( m_aDataPool[hHash].m_Data );
  592. }
  593. //-----------------------------------------------------------------------------
  594. // Purpose: Return data given a hash handle.
  595. //-----------------------------------------------------------------------------
  596. template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash ) const
  597. {
  598. return ( m_aDataPool[hHash].m_Data );
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Purpose: Return data given a hash handle.
  602. //-----------------------------------------------------------------------------
  603. template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash )
  604. {
  605. return ( m_aDataPool[hHash].m_Data );
  606. }
  607. //-----------------------------------------------------------------------------
  608. // Purpose: Return data given a hash handle.
  609. //-----------------------------------------------------------------------------
  610. template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash ) const
  611. {
  612. return ( m_aDataPool[hHash].m_Data );
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Purpose: For iterating over the whole hash, return the index of the first element
  616. //-----------------------------------------------------------------------------
  617. template<class Data, class HashFuncs>
  618. typename CUtlHashFast<Data,HashFuncs>::UtlHashFastIterator_t
  619. CUtlHashFast<Data,HashFuncs>::First() const
  620. {
  621. // walk through the buckets to find the first one that has some data
  622. int bucketCount = m_aBuckets.Count();
  623. const UtlHashFastHandle_t invalidIndex = m_aDataPool.InvalidIndex();
  624. for ( int bucket = 0 ; bucket < bucketCount ; ++bucket )
  625. {
  626. UtlHashFastHandle_t iElement = m_aBuckets[bucket]; // get the head of the bucket
  627. if (iElement != invalidIndex)
  628. return UtlHashFastIterator_t(bucket,iElement);
  629. }
  630. // if we are down here, the list is empty
  631. return UtlHashFastIterator_t(-1, invalidIndex);
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Purpose: For iterating over the whole hash, return the next element after
  635. // the param one. Or an invalid iterator.
  636. //-----------------------------------------------------------------------------
  637. template<class Data, class HashFuncs>
  638. typename CUtlHashFast<Data,HashFuncs>::UtlHashFastIterator_t
  639. CUtlHashFast<Data,HashFuncs>::Next( const typename CUtlHashFast<Data,HashFuncs>::UtlHashFastIterator_t &iter ) const
  640. {
  641. // look for the next entry in the current bucket
  642. UtlHashFastHandle_t next = m_aDataPool.Next(iter.handle);
  643. const UtlHashFastHandle_t invalidIndex = m_aDataPool.InvalidIndex();
  644. if (next != invalidIndex)
  645. {
  646. // this bucket still has more elements in it
  647. return UtlHashFastIterator_t(iter.bucket, next);
  648. }
  649. // otherwise look for the next bucket with data
  650. int bucketCount = m_aBuckets.Count();
  651. for ( int bucket = iter.bucket+1 ; bucket < bucketCount ; ++bucket )
  652. {
  653. UtlHashFastHandle_t next = m_aBuckets[bucket]; // get the head of the bucket
  654. if (next != invalidIndex)
  655. return UtlHashFastIterator_t( bucket, next );
  656. }
  657. // if we're here, there's no more data to be had
  658. return UtlHashFastIterator_t(-1, invalidIndex);
  659. }
  660. template<class Data, class HashFuncs>
  661. bool CUtlHashFast<Data,HashFuncs>::IsValidIterator( const typename CUtlHashFast::UtlHashFastIterator_t &iter ) const
  662. {
  663. return ( (iter.bucket >= 0) && (m_aDataPool.IsValidIndex(iter.handle)) );
  664. }
  665. template<class Data, class HashFuncs> inline bool CUtlHashFast<Data,HashFuncs>::IsValidHandle( UtlHashFastHandle_t hHash ) const
  666. {
  667. return m_aDataPool.IsValidIndex(hHash);
  668. }
  669. //=============================================================================
  670. //
  671. // Fixed Hash
  672. //
  673. // Number of buckets must be a power of 2.
  674. // Key must be pointer-size (uintp).
  675. //
  676. typedef intp UtlHashFixedHandle_t;
  677. template <int NUM_BUCKETS>
  678. class CUtlHashFixedGenericHash
  679. {
  680. public:
  681. static int Hash( int key, int bucketMask )
  682. {
  683. int hash = HashIntConventional( key );
  684. if ( NUM_BUCKETS <= USHRT_MAX )
  685. {
  686. hash ^= ( hash >> 16 );
  687. }
  688. if ( NUM_BUCKETS <= UCHAR_MAX )
  689. {
  690. hash ^= ( hash >> 8 );
  691. }
  692. return ( hash & bucketMask );
  693. }
  694. };
  695. template<class Data, int NUM_BUCKETS, class CHashFuncs = CUtlHashFastNoHash >
  696. class CUtlHashFixed
  697. {
  698. public:
  699. // Constructor/Deconstructor.
  700. CUtlHashFixed();
  701. ~CUtlHashFixed();
  702. // Memory.
  703. void Purge( void );
  704. // Invalid handle.
  705. static UtlHashFixedHandle_t InvalidHandle( void ) { return ( UtlHashFixedHandle_t )~0; }
  706. // Size.
  707. int Count( void );
  708. // Insertion.
  709. UtlHashFixedHandle_t Insert( unsigned int uiKey, const Data &data );
  710. UtlHashFixedHandle_t FastInsert( unsigned int uiKey, const Data &data );
  711. // Removal.
  712. void Remove( UtlHashFixedHandle_t hHash );
  713. void RemoveAll( void );
  714. // Retrieval.
  715. UtlHashFixedHandle_t Find( unsigned int uiKey );
  716. Data &Element( UtlHashFixedHandle_t hHash );
  717. Data const &Element( UtlHashFixedHandle_t hHash ) const;
  718. Data &operator[]( UtlHashFixedHandle_t hHash );
  719. Data const &operator[]( UtlHashFixedHandle_t hHash ) const;
  720. //protected:
  721. // Templatized for memory tracking purposes
  722. template <typename Data_t>
  723. struct HashFixedData_t_
  724. {
  725. unsigned int m_uiKey;
  726. Data_t m_Data;
  727. };
  728. typedef HashFixedData_t_<Data> HashFixedData_t;
  729. enum
  730. {
  731. BUCKET_MASK = NUM_BUCKETS - 1
  732. };
  733. CUtlPtrLinkedList<HashFixedData_t> m_aBuckets[NUM_BUCKETS];
  734. int m_nElements;
  735. };
  736. //-----------------------------------------------------------------------------
  737. // Purpose: Constructor
  738. //-----------------------------------------------------------------------------
  739. template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::CUtlHashFixed()
  740. {
  741. Purge();
  742. }
  743. //-----------------------------------------------------------------------------
  744. // Purpose: Deconstructor
  745. //-----------------------------------------------------------------------------
  746. template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::~CUtlHashFixed()
  747. {
  748. Purge();
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Purpose: Destroy dynamically allocated hash data.
  752. //-----------------------------------------------------------------------------
  753. template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Purge( void )
  754. {
  755. RemoveAll();
  756. }
  757. //-----------------------------------------------------------------------------
  758. // Purpose: Return the number of elements in the hash.
  759. //-----------------------------------------------------------------------------
  760. template<class Data, int NUM_BUCKETS, class HashFuncs> inline int CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Count( void )
  761. {
  762. return m_nElements;
  763. }
  764. //-----------------------------------------------------------------------------
  765. // Purpose: Insert data into the hash table given its key (unsigned int), with
  766. // a check to see if the element already exists within the tree.
  767. //-----------------------------------------------------------------------------
  768. template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Insert( unsigned int uiKey, const Data &data )
  769. {
  770. // Check to see if that key already exists in the buckets (should be unique).
  771. UtlHashFixedHandle_t hHash = Find( uiKey );
  772. if( hHash != InvalidHandle() )
  773. return hHash;
  774. return FastInsert( uiKey, data );
  775. }
  776. //-----------------------------------------------------------------------------
  777. // Purpose: Insert data into the hash table given its key (unsigned int),
  778. // without a check to see if the element already exists within the tree.
  779. //-----------------------------------------------------------------------------
  780. template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::FastInsert( unsigned int uiKey, const Data &data )
  781. {
  782. int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 );
  783. UtlPtrLinkedListIndex_t iElem = m_aBuckets[iBucket].AddToHead();
  784. HashFixedData_t *pHashData = &m_aBuckets[iBucket][iElem];
  785. Assert( (UtlPtrLinkedListIndex_t)pHashData == iElem );
  786. // Add data to new element.
  787. pHashData->m_uiKey = uiKey;
  788. pHashData->m_Data = data;
  789. m_nElements++;
  790. return (UtlHashFixedHandle_t)pHashData;
  791. }
  792. //-----------------------------------------------------------------------------
  793. // Purpose: Remove a given element from the hash.
  794. //-----------------------------------------------------------------------------
  795. template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Remove( UtlHashFixedHandle_t hHash )
  796. {
  797. HashFixedData_t *pHashData = (HashFixedData_t *)hHash;
  798. Assert( Find(pHashData->m_uiKey) != InvalidHandle() );
  799. int iBucket = HashFuncs::Hash( pHashData->m_uiKey, NUM_BUCKETS - 1 );
  800. m_aBuckets[iBucket].Remove( (UtlPtrLinkedListIndex_t)pHashData );
  801. m_nElements--;
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Purpose: Remove all elements from the hash
  805. //-----------------------------------------------------------------------------
  806. template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::RemoveAll( void )
  807. {
  808. for ( int i = 0; i < NUM_BUCKETS; i++ )
  809. {
  810. m_aBuckets[i].RemoveAll();
  811. }
  812. m_nElements = 0;
  813. }
  814. //-----------------------------------------------------------------------------
  815. //-----------------------------------------------------------------------------
  816. template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Find( unsigned int uiKey )
  817. {
  818. int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 );
  819. CUtlPtrLinkedList<HashFixedData_t> &bucket = m_aBuckets[iBucket];
  820. for ( UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next( iElement ) )
  821. {
  822. if ( bucket[iElement].m_uiKey == uiKey )
  823. return (UtlHashFixedHandle_t)iElement;
  824. }
  825. return InvalidHandle();
  826. }
  827. //-----------------------------------------------------------------------------
  828. // Purpose: Return data given a hash handle.
  829. //-----------------------------------------------------------------------------
  830. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash )
  831. {
  832. return ((HashFixedData_t *)hHash)->m_Data;
  833. }
  834. //-----------------------------------------------------------------------------
  835. // Purpose: Return data given a hash handle.
  836. //-----------------------------------------------------------------------------
  837. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash ) const
  838. {
  839. return ((HashFixedData_t *)hHash)->m_Data;
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Purpose: Return data given a hash handle.
  843. //-----------------------------------------------------------------------------
  844. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash )
  845. {
  846. return ((HashFixedData_t *)hHash)->m_Data;
  847. }
  848. //-----------------------------------------------------------------------------
  849. // Purpose: Return data given a hash handle.
  850. //-----------------------------------------------------------------------------
  851. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash ) const
  852. {
  853. return ((HashFixedData_t *)hHash)->m_Data;
  854. }
  855. class CDefaultHash32
  856. {
  857. public:
  858. static inline uint32 HashKey32( uint32 nKey ) { return HashIntConventional(nKey); }
  859. };
  860. class CPassthroughHash32
  861. {
  862. public:
  863. static inline uint32 HashKey32( uint32 nKey ) { return nKey; }
  864. };
  865. // This is a simpler hash for scalar types that stores the entire hash + buckets in a single linear array
  866. // This is much more cache friendly for small (e.g. 32-bit) types stored in the hash
  867. template<class Data, class CHashFunction = CDefaultHash32>
  868. class CUtlScalarHash
  869. {
  870. public:
  871. // Constructor/Destructor.
  872. CUtlScalarHash();
  873. ~CUtlScalarHash();
  874. // Memory.
  875. // void Purge( void );
  876. // Invalid handle.
  877. static const UtlHashFastHandle_t InvalidHandle( void ) { return (unsigned int)~0; }
  878. // Initialize.
  879. bool Init( int nBucketCount );
  880. // Size.
  881. int Count( void ) const { return m_dataCount; }
  882. // Insertion.
  883. UtlHashFastHandle_t Insert( unsigned int uiKey, const Data &data );
  884. // Removal.
  885. void FindAndRemove( unsigned int uiKey, const Data &dataRecord );
  886. void Remove( UtlHashFastHandle_t hHash );
  887. void RemoveAll( void );
  888. void Grow();
  889. // Retrieval. Finds by uiKey and then by comparing dataRecord
  890. UtlHashFastHandle_t Find( unsigned int uiKey, const Data &dataRecord ) const;
  891. UtlHashFastHandle_t FindByUniqueKey( unsigned int uiKey ) const;
  892. Data &Element( UtlHashFastHandle_t hHash ) { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; }
  893. Data const &Element( UtlHashFastHandle_t hHash ) const { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; }
  894. Data &operator[]( UtlHashFastHandle_t hHash ) { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; }
  895. Data const &operator[]( UtlHashFastHandle_t hHash ) const { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; }
  896. unsigned int Key( UtlHashFastHandle_t hHash ) const { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_uiKey; }
  897. UtlHashFastHandle_t FirstInorder() const
  898. {
  899. return NextInorder(-1);
  900. }
  901. UtlHashFastHandle_t NextInorder( UtlHashFastHandle_t nStart ) const
  902. {
  903. int nElementCount = m_maxData * 2;
  904. unsigned int nUnusedListElement = (unsigned int)InvalidHandle();
  905. for ( int i = nStart+1; i < nElementCount; i++ )
  906. {
  907. if ( m_pData[i].m_uiKey != nUnusedListElement )
  908. return i;
  909. }
  910. return nUnusedListElement;
  911. }
  912. //protected:
  913. struct HashScalarData_t
  914. {
  915. unsigned int m_uiKey;
  916. Data m_Data;
  917. };
  918. unsigned int m_uiBucketMask;
  919. HashScalarData_t *m_pData;
  920. int m_maxData;
  921. int m_dataCount;
  922. };
  923. template<class Data, class CHashFunction> CUtlScalarHash<Data, CHashFunction>::CUtlScalarHash()
  924. {
  925. m_pData = NULL;
  926. m_uiBucketMask = 0;
  927. m_maxData = 0;
  928. m_dataCount = 0;
  929. }
  930. template<class Data, class CHashFunction> CUtlScalarHash<Data, CHashFunction>::~CUtlScalarHash()
  931. {
  932. delete[] m_pData;
  933. }
  934. template<class Data, class CHashFunction> bool CUtlScalarHash<Data, CHashFunction>::Init( int nBucketCount )
  935. {
  936. Assert(m_dataCount==0);
  937. m_maxData = SmallestPowerOfTwoGreaterOrEqual(nBucketCount);
  938. int elementCount = m_maxData * 2;
  939. m_pData = new HashScalarData_t[elementCount];
  940. m_uiBucketMask = elementCount - 1;
  941. RemoveAll();
  942. return true;
  943. }
  944. template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::Grow()
  945. {
  946. ASSERT_NO_REENTRY();
  947. int oldElementCount = m_maxData * 2;
  948. HashScalarData_t *pOldData = m_pData;
  949. // Grow to a minimum size of 16
  950. m_maxData = MAX( oldElementCount, 16 );
  951. int elementCount = m_maxData * 2;
  952. m_pData = new HashScalarData_t[elementCount];
  953. m_uiBucketMask = elementCount-1;
  954. m_dataCount = 0;
  955. for ( int i = 0; i < elementCount; i++ )
  956. {
  957. m_pData[i].m_uiKey = InvalidHandle();
  958. }
  959. for ( int i = 0; i < oldElementCount; i++ )
  960. {
  961. if ( pOldData[i].m_uiKey != (unsigned)InvalidHandle() )
  962. {
  963. Insert( pOldData[i].m_uiKey, pOldData[i].m_Data );
  964. }
  965. }
  966. delete[] pOldData;
  967. }
  968. template<class Data, class CHashFunction> UtlHashFastHandle_t CUtlScalarHash<Data, CHashFunction>::Insert( unsigned int uiKey, const Data &data )
  969. {
  970. if ( m_dataCount >= m_maxData )
  971. {
  972. Grow();
  973. }
  974. m_dataCount++;
  975. Assert(uiKey != (uint)InvalidHandle()); // This hash stores less data by assuming uiKey != ~0
  976. int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask;
  977. unsigned int endOfList = (unsigned int)InvalidHandle();
  978. while ( m_pData[index].m_uiKey != endOfList )
  979. {
  980. index = (index+1) & m_uiBucketMask;
  981. }
  982. m_pData[index].m_uiKey = uiKey;
  983. m_pData[index].m_Data = data;
  984. return index;
  985. }
  986. // Removal.
  987. template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::Remove( UtlHashFastHandle_t hHash )
  988. {
  989. int mid = (m_uiBucketMask+1) / 2;
  990. int lastRemoveIndex = hHash;
  991. // remove the item
  992. m_pData[lastRemoveIndex].m_uiKey = InvalidHandle();
  993. m_dataCount--;
  994. // now search for any items needing to be swapped down
  995. unsigned int endOfList = (unsigned int)InvalidHandle();
  996. for ( int index = (hHash+1) & m_uiBucketMask; m_pData[index].m_uiKey != endOfList; index = (index+1) & m_uiBucketMask )
  997. {
  998. int ideal = CHashFunction::HashKey32(m_pData[index].m_uiKey) & m_uiBucketMask;
  999. // is the ideal index for this element <= (in a wrapped buffer sense) the ideal index of the removed element?
  1000. // if so, swap
  1001. int diff = ideal - lastRemoveIndex;
  1002. if ( diff > mid )
  1003. {
  1004. diff -= (m_uiBucketMask+1);
  1005. }
  1006. if ( diff < -mid )
  1007. {
  1008. diff += (m_uiBucketMask+1);
  1009. }
  1010. // should I swap this?
  1011. if ( diff <= 0 )
  1012. {
  1013. m_pData[lastRemoveIndex] = m_pData[index];
  1014. lastRemoveIndex = index;
  1015. m_pData[index].m_uiKey = InvalidHandle();
  1016. }
  1017. }
  1018. }
  1019. template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::FindAndRemove( unsigned int uiKey, const Data &dataRecord )
  1020. {
  1021. int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask;
  1022. unsigned int endOfList = (unsigned int)InvalidHandle();
  1023. while ( m_pData[index].m_uiKey != endOfList )
  1024. {
  1025. if ( m_pData[index].m_uiKey == uiKey && m_pData[index].m_Data == dataRecord )
  1026. {
  1027. Remove(index);
  1028. return;
  1029. }
  1030. index = (index+1) & m_uiBucketMask;
  1031. }
  1032. }
  1033. template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::RemoveAll( void )
  1034. {
  1035. int elementCount = m_maxData * 2;
  1036. for ( int i = 0; i < elementCount; i++ )
  1037. {
  1038. m_pData[i].m_uiKey = (unsigned)InvalidHandle();
  1039. }
  1040. m_dataCount = 0;
  1041. }
  1042. // Retrieval.
  1043. template<class Data, class CHashFunction> UtlHashFastHandle_t CUtlScalarHash<Data, CHashFunction>::Find( unsigned int uiKey, const Data &dataRecord ) const
  1044. {
  1045. if ( m_pData == NULL )
  1046. return InvalidHandle();
  1047. int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask;
  1048. unsigned int endOfList = (unsigned int)InvalidHandle();
  1049. while ( m_pData[index].m_uiKey != endOfList )
  1050. {
  1051. if ( m_pData[index].m_uiKey == uiKey && m_pData[index].m_Data == dataRecord )
  1052. return index;
  1053. index = (index+1) & m_uiBucketMask;
  1054. }
  1055. return InvalidHandle();
  1056. }
  1057. template<class Data, class CHashFunction> UtlHashFastHandle_t CUtlScalarHash<Data, CHashFunction>::FindByUniqueKey( unsigned int uiKey ) const
  1058. {
  1059. if ( m_pData == NULL )
  1060. return InvalidHandle();
  1061. int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask;
  1062. unsigned int endOfList = (unsigned int)InvalidHandle();
  1063. while ( m_pData[index].m_uiKey != endOfList )
  1064. {
  1065. if ( m_pData[index].m_uiKey == uiKey )
  1066. return index;
  1067. index = (index+1) & m_uiBucketMask;
  1068. }
  1069. return InvalidHandle();
  1070. }
  1071. #endif // UTLHASH_H