Team Fortress 2 Source Code as on 22/4/2020
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.

936 lines
30 KiB

  1. //========= Copyright 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 <assert.h>
  13. #include <limits.h>
  14. #include "utlmemory.h"
  15. #include "utlvector.h"
  16. #include "utllinkedlist.h"
  17. #include "utllinkedlist.h"
  18. #include "commonmacros.h"
  19. #include "generichash.h"
  20. typedef unsigned int UtlHashHandle_t;
  21. template<class Data, typename C = bool (*)( Data const&, Data const& ), typename K = unsigned int (*)( Data const& ) >
  22. class CUtlHash
  23. {
  24. public:
  25. // compare and key functions - implemented by the
  26. typedef C CompareFunc_t;
  27. typedef K KeyFunc_t;
  28. // constructor/deconstructor
  29. CUtlHash( int bucketCount = 0, int growCount = 0, int initCount = 0,
  30. CompareFunc_t compareFunc = 0, KeyFunc_t keyFunc = 0 );
  31. ~CUtlHash();
  32. // invalid handle
  33. static UtlHashHandle_t InvalidHandle( void ) { return ( UtlHashHandle_t )~0; }
  34. bool IsValidHandle( UtlHashHandle_t handle ) const;
  35. // size
  36. int Count( void ) const;
  37. // memory
  38. void Purge( void );
  39. // insertion methods
  40. UtlHashHandle_t Insert( Data const &src );
  41. UtlHashHandle_t Insert( Data const &src, bool *pDidInsert );
  42. UtlHashHandle_t AllocEntryFromKey( Data const &src );
  43. // removal methods
  44. void Remove( UtlHashHandle_t handle );
  45. void RemoveAll();
  46. // retrieval methods
  47. UtlHashHandle_t Find( Data const &src ) const;
  48. Data &Element( UtlHashHandle_t handle );
  49. Data const &Element( UtlHashHandle_t handle ) const;
  50. Data &operator[]( UtlHashHandle_t handle );
  51. Data const &operator[]( UtlHashHandle_t handle ) const;
  52. UtlHashHandle_t GetFirstHandle() const;
  53. UtlHashHandle_t GetNextHandle( UtlHashHandle_t h ) const;
  54. // debugging!!
  55. void Log( const char *filename );
  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. m_Buckets.SetSize( bucketCount );
  80. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  81. {
  82. m_Buckets[ndxBucket].SetSize( initCount );
  83. m_Buckets[ndxBucket].SetGrowSize( growCount );
  84. }
  85. // check to see if the bucket count is a power of 2 and set up
  86. // optimizations appropriately
  87. m_bPowerOfTwo = IsPowerOfTwo( bucketCount );
  88. m_ModMask = m_bPowerOfTwo ? (bucketCount-1) : 0;
  89. }
  90. //-----------------------------------------------------------------------------
  91. //-----------------------------------------------------------------------------
  92. template<class Data, typename C, typename K>
  93. CUtlHash<Data, C, K>::~CUtlHash()
  94. {
  95. Purge();
  96. }
  97. //-----------------------------------------------------------------------------
  98. //-----------------------------------------------------------------------------
  99. template<class Data, typename C, typename K>
  100. inline bool CUtlHash<Data, C, K>::IsValidHandle( UtlHashHandle_t handle ) const
  101. {
  102. int ndxBucket = GetBucketIndex( handle );
  103. int ndxKeyData = GetKeyDataIndex( handle );
  104. // ndxBucket and ndxKeyData can't possibly be less than zero -- take a
  105. // look at the definition of the Get..Index functions for why. However,
  106. // if you override those functions, you will need to override this one
  107. // as well.
  108. if( /*( ndxBucket >= 0 ) && */ ( ndxBucket < m_Buckets.Count() ) )
  109. {
  110. if( /*( ndxKeyData >= 0 ) && */ ( ndxKeyData < m_Buckets[ndxBucket].Count() ) )
  111. return true;
  112. }
  113. return false;
  114. }
  115. //-----------------------------------------------------------------------------
  116. //-----------------------------------------------------------------------------
  117. template<class Data, typename C, typename K>
  118. inline int CUtlHash<Data, C, K>::Count( void ) const
  119. {
  120. int count = 0;
  121. int bucketCount = m_Buckets.Count();
  122. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  123. {
  124. count += m_Buckets[ndxBucket].Count();
  125. }
  126. return count;
  127. }
  128. //-----------------------------------------------------------------------------
  129. //-----------------------------------------------------------------------------
  130. template<class Data, typename C, typename K>
  131. inline int CUtlHash<Data, C, K>::GetBucketIndex( UtlHashHandle_t handle ) const
  132. {
  133. return ( ( ( handle >> 16 ) & 0x0000ffff ) );
  134. }
  135. //-----------------------------------------------------------------------------
  136. //-----------------------------------------------------------------------------
  137. template<class Data, typename C, typename K>
  138. inline int CUtlHash<Data, C, K>::GetKeyDataIndex( UtlHashHandle_t handle ) const
  139. {
  140. return ( handle & 0x0000ffff );
  141. }
  142. //-----------------------------------------------------------------------------
  143. //-----------------------------------------------------------------------------
  144. template<class Data, typename C, typename K>
  145. inline UtlHashHandle_t CUtlHash<Data, C, K>::BuildHandle( int ndxBucket, int ndxKeyData ) const
  146. {
  147. assert( ( ndxBucket >= 0 ) && ( ndxBucket < 65536 ) );
  148. assert( ( ndxKeyData >= 0 ) && ( ndxKeyData < 65536 ) );
  149. UtlHashHandle_t handle = ndxKeyData;
  150. handle |= ( ndxBucket << 16 );
  151. return handle;
  152. }
  153. //-----------------------------------------------------------------------------
  154. //-----------------------------------------------------------------------------
  155. template<class Data, typename C, typename K>
  156. inline void CUtlHash<Data, C, K>::Purge( void )
  157. {
  158. int bucketCount = m_Buckets.Count();
  159. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  160. {
  161. m_Buckets[ndxBucket].Purge();
  162. }
  163. }
  164. //-----------------------------------------------------------------------------
  165. //-----------------------------------------------------------------------------
  166. template<class Data, typename C, typename K>
  167. inline bool CUtlHash<Data, C, K>::DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const
  168. {
  169. // generate the data "key"
  170. unsigned int key = m_KeyFunc( src );
  171. // hash the "key" - get the correct hash table "bucket"
  172. unsigned int ndxBucket;
  173. if( m_bPowerOfTwo )
  174. {
  175. *pBucket = ndxBucket = ( key & m_ModMask );
  176. }
  177. else
  178. {
  179. int bucketCount = m_Buckets.Count();
  180. *pBucket = ndxBucket = key % bucketCount;
  181. }
  182. int ndxKeyData;
  183. const CUtlVector<Data> &bucket = m_Buckets[ndxBucket];
  184. int keyDataCount = bucket.Count();
  185. for( ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++ )
  186. {
  187. if( m_CompareFunc( bucket.Element( ndxKeyData ), src ) )
  188. break;
  189. }
  190. if( ndxKeyData == keyDataCount )
  191. return false;
  192. *pIndex = ndxKeyData;
  193. return true;
  194. }
  195. //-----------------------------------------------------------------------------
  196. //-----------------------------------------------------------------------------
  197. template<class Data, typename C, typename K>
  198. inline UtlHashHandle_t CUtlHash<Data, C, K>::Find( Data const &src ) const
  199. {
  200. unsigned int ndxBucket;
  201. int ndxKeyData;
  202. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  203. {
  204. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  205. }
  206. return ( InvalidHandle() );
  207. }
  208. //-----------------------------------------------------------------------------
  209. //-----------------------------------------------------------------------------
  210. template<class Data, typename C, typename K>
  211. inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src )
  212. {
  213. unsigned int ndxBucket;
  214. int ndxKeyData;
  215. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  216. {
  217. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  218. }
  219. ndxKeyData = m_Buckets[ndxBucket].AddToTail( src );
  220. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  221. }
  222. //-----------------------------------------------------------------------------
  223. //-----------------------------------------------------------------------------
  224. template<class Data, typename C, typename K>
  225. inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src, bool *pDidInsert )
  226. {
  227. unsigned int ndxBucket;
  228. int ndxKeyData;
  229. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  230. {
  231. *pDidInsert = false;
  232. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  233. }
  234. *pDidInsert = true;
  235. ndxKeyData = m_Buckets[ndxBucket].AddToTail( src );
  236. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  237. }
  238. //-----------------------------------------------------------------------------
  239. //-----------------------------------------------------------------------------
  240. template<class Data, typename C, typename K>
  241. inline UtlHashHandle_t CUtlHash<Data, C, K>::AllocEntryFromKey( Data const &src )
  242. {
  243. unsigned int ndxBucket;
  244. int ndxKeyData;
  245. if ( DoFind( src, &ndxBucket, &ndxKeyData ) )
  246. {
  247. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  248. }
  249. ndxKeyData = m_Buckets[ndxBucket].AddToTail();
  250. return ( BuildHandle( ndxBucket, ndxKeyData ) );
  251. }
  252. //-----------------------------------------------------------------------------
  253. //-----------------------------------------------------------------------------
  254. template<class Data, typename C, typename K>
  255. inline void CUtlHash<Data, C, K>::Remove( UtlHashHandle_t handle )
  256. {
  257. assert( IsValidHandle( handle ) );
  258. // check to see if the bucket exists
  259. int ndxBucket = GetBucketIndex( handle );
  260. int ndxKeyData = GetKeyDataIndex( handle );
  261. if( m_Buckets[ndxBucket].IsValidIndex( ndxKeyData ) )
  262. {
  263. m_Buckets[ndxBucket].FastRemove( ndxKeyData );
  264. }
  265. }
  266. //-----------------------------------------------------------------------------
  267. //-----------------------------------------------------------------------------
  268. template<class Data, typename C, typename K>
  269. inline void CUtlHash<Data, C, K>::RemoveAll()
  270. {
  271. int bucketCount = m_Buckets.Count();
  272. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  273. {
  274. m_Buckets[ndxBucket].RemoveAll();
  275. }
  276. }
  277. //-----------------------------------------------------------------------------
  278. //-----------------------------------------------------------------------------
  279. template<class Data, typename C, typename K>
  280. inline Data &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle )
  281. {
  282. int ndxBucket = GetBucketIndex( handle );
  283. int ndxKeyData = GetKeyDataIndex( handle );
  284. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  285. }
  286. //-----------------------------------------------------------------------------
  287. //-----------------------------------------------------------------------------
  288. template<class Data, typename C, typename K>
  289. inline Data const &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle ) const
  290. {
  291. int ndxBucket = GetBucketIndex( handle );
  292. int ndxKeyData = GetKeyDataIndex( handle );
  293. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  294. }
  295. //-----------------------------------------------------------------------------
  296. //-----------------------------------------------------------------------------
  297. template<class Data, typename C, typename K>
  298. inline Data &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle )
  299. {
  300. int ndxBucket = GetBucketIndex( handle );
  301. int ndxKeyData = GetKeyDataIndex( handle );
  302. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  303. }
  304. //-----------------------------------------------------------------------------
  305. //-----------------------------------------------------------------------------
  306. template<class Data, typename C, typename K>
  307. inline Data const &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle ) const
  308. {
  309. int ndxBucket = GetBucketIndex( handle );
  310. int ndxKeyData = GetKeyDataIndex( handle );
  311. return ( m_Buckets[ndxBucket].Element( ndxKeyData ) );
  312. }
  313. //-----------------------------------------------------------------------------
  314. //-----------------------------------------------------------------------------
  315. template<class Data, typename C, typename K>
  316. inline UtlHashHandle_t CUtlHash<Data, C, K>::GetFirstHandle() const
  317. {
  318. return GetNextHandle( ( UtlHashHandle_t )-1 );
  319. }
  320. template<class Data, typename C, typename K>
  321. inline UtlHashHandle_t CUtlHash<Data, C, K>::GetNextHandle( UtlHashHandle_t handle ) const
  322. {
  323. ++handle; // start at the first possible handle after the one given
  324. int bi = GetBucketIndex( handle );
  325. int ki = GetKeyDataIndex( handle );
  326. int nBuckets = m_Buckets.Count();
  327. for ( ; bi < nBuckets; ++bi )
  328. {
  329. if ( ki < m_Buckets[ bi ].Count() )
  330. return BuildHandle( bi, ki );
  331. ki = 0;
  332. }
  333. return InvalidHandle();
  334. }
  335. //-----------------------------------------------------------------------------
  336. //-----------------------------------------------------------------------------
  337. template<class Data, typename C, typename K>
  338. inline void CUtlHash<Data, C, K>::Log( const char *filename )
  339. {
  340. FILE *pDebugFp;
  341. pDebugFp = fopen( filename, "w" );
  342. if( !pDebugFp )
  343. return;
  344. int maxBucketSize = 0;
  345. int numBucketsEmpty = 0;
  346. int bucketCount = m_Buckets.Count();
  347. fprintf( pDebugFp, "\n%d Buckets\n", bucketCount );
  348. for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ )
  349. {
  350. int count = m_Buckets[ndxBucket].Count();
  351. if( count > maxBucketSize ) { maxBucketSize = count; }
  352. if( count == 0 )
  353. numBucketsEmpty++;
  354. fprintf( pDebugFp, "Bucket %d: %d\n", ndxBucket, count );
  355. }
  356. fprintf( pDebugFp, "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty );
  357. fprintf( pDebugFp, "Max Bucket Size: %d\n", maxBucketSize );
  358. fclose( pDebugFp );
  359. }
  360. //=============================================================================
  361. //
  362. // Fast Hash
  363. //
  364. // Number of buckets must be a power of 2.
  365. // Key must be 32-bits (unsigned int).
  366. //
  367. typedef int UtlHashFastHandle_t;
  368. #define UTLHASH_POOL_SCALAR 2
  369. class CUtlHashFastNoHash
  370. {
  371. public:
  372. static int Hash( int key, int bucketMask )
  373. {
  374. return ( key & bucketMask );
  375. }
  376. };
  377. class CUtlHashFastGenericHash
  378. {
  379. public:
  380. static int Hash( int key, int bucketMask )
  381. {
  382. return ( HashIntConventional( key ) & bucketMask );
  383. }
  384. };
  385. template<class Data, class HashFuncs = CUtlHashFastNoHash >
  386. class CUtlHashFast
  387. {
  388. public:
  389. // Constructor/Deconstructor.
  390. CUtlHashFast();
  391. ~CUtlHashFast();
  392. // Memory.
  393. void Purge( void );
  394. // Invalid handle.
  395. static UtlHashFastHandle_t InvalidHandle( void ) { return ( UtlHashFastHandle_t )~0; }
  396. // Initialize.
  397. bool Init( int nBucketCount );
  398. // Size.
  399. int Count( void );
  400. // Insertion.
  401. UtlHashFastHandle_t Insert( unsigned int uiKey, const Data &data );
  402. UtlHashFastHandle_t FastInsert( unsigned int uiKey, const Data &data );
  403. // Removal.
  404. void Remove( UtlHashFastHandle_t hHash );
  405. void RemoveAll( void );
  406. // Retrieval.
  407. UtlHashFastHandle_t Find( unsigned int uiKey );
  408. Data &Element( UtlHashFastHandle_t hHash );
  409. Data const &Element( UtlHashFastHandle_t hHash ) const;
  410. Data &operator[]( UtlHashFastHandle_t hHash );
  411. Data const &operator[]( UtlHashFastHandle_t hHash ) const;
  412. //protected:
  413. // Templatized for memory tracking purposes
  414. template <typename HashData>
  415. struct HashFastData_t_
  416. {
  417. unsigned int m_uiKey;
  418. HashData m_Data;
  419. };
  420. typedef HashFastData_t_<Data> HashFastData_t;
  421. unsigned int m_uiBucketMask;
  422. CUtlVector<UtlHashFastHandle_t> m_aBuckets;
  423. CUtlFixedLinkedList<HashFastData_t> m_aDataPool;
  424. };
  425. //-----------------------------------------------------------------------------
  426. // Purpose: Constructor
  427. //-----------------------------------------------------------------------------
  428. template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::CUtlHashFast()
  429. {
  430. Purge();
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Purpose: Deconstructor
  434. //-----------------------------------------------------------------------------
  435. template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::~CUtlHashFast()
  436. {
  437. Purge();
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Purpose: Destroy dynamically allocated hash data.
  441. //-----------------------------------------------------------------------------
  442. template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Purge( void )
  443. {
  444. m_aBuckets.Purge();
  445. m_aDataPool.Purge();
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Purpose: Initialize the hash - set bucket count and hash grow amount.
  449. //-----------------------------------------------------------------------------
  450. template<class Data, class HashFuncs> bool CUtlHashFast<Data,HashFuncs>::Init( int nBucketCount )
  451. {
  452. // Verify the bucket count is power of 2.
  453. if ( !IsPowerOfTwo( nBucketCount ) )
  454. return false;
  455. // Set the bucket size.
  456. m_aBuckets.SetSize( nBucketCount );
  457. for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket )
  458. {
  459. m_aBuckets[iBucket] = m_aDataPool.InvalidIndex();
  460. }
  461. // Set the mod mask.
  462. m_uiBucketMask = nBucketCount - 1;
  463. // Calculate the grow size.
  464. int nGrowSize = UTLHASH_POOL_SCALAR * nBucketCount;
  465. m_aDataPool.SetGrowSize( nGrowSize );
  466. return true;
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Purpose: Return the number of elements in the hash.
  470. //-----------------------------------------------------------------------------
  471. template<class Data, class HashFuncs> inline int CUtlHashFast<Data,HashFuncs>::Count( void )
  472. {
  473. return m_aDataPool.Count();
  474. }
  475. //-----------------------------------------------------------------------------
  476. // Purpose: Insert data into the hash table given its key (unsigned int), with
  477. // a check to see if the element already exists within the tree.
  478. //-----------------------------------------------------------------------------
  479. template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Insert( unsigned int uiKey, const Data &data )
  480. {
  481. // Check to see if that key already exists in the buckets (should be unique).
  482. UtlHashFastHandle_t hHash = Find( uiKey );
  483. if( hHash != InvalidHandle() )
  484. return hHash;
  485. return FastInsert( uiKey, data );
  486. }
  487. //-----------------------------------------------------------------------------
  488. // Purpose: Insert data into the hash table given its key (unsigned int),
  489. // without a check to see if the element already exists within the tree.
  490. //-----------------------------------------------------------------------------
  491. template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::FastInsert( unsigned int uiKey, const Data &data )
  492. {
  493. // Get a new element from the pool.
  494. int iHashData = m_aDataPool.Alloc( true );
  495. HashFastData_t *pHashData = &m_aDataPool[iHashData];
  496. if ( !pHashData )
  497. return InvalidHandle();
  498. // Add data to new element.
  499. pHashData->m_uiKey = uiKey;
  500. pHashData->m_Data = data;
  501. // Link element.
  502. int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask );
  503. m_aDataPool.LinkBefore( m_aBuckets[iBucket], iHashData );
  504. m_aBuckets[iBucket] = iHashData;
  505. return iHashData;
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose: Remove a given element from the hash.
  509. //-----------------------------------------------------------------------------
  510. template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Remove( UtlHashFastHandle_t hHash )
  511. {
  512. int iBucket = HashFuncs::Hash( m_aDataPool[hHash].m_uiKey, m_uiBucketMask );
  513. if ( m_aBuckets[iBucket] == hHash )
  514. {
  515. // It is a bucket head.
  516. m_aBuckets[iBucket] = m_aDataPool.Next( hHash );
  517. }
  518. else
  519. {
  520. // Not a bucket head.
  521. m_aDataPool.Unlink( hHash );
  522. }
  523. // Remove the element.
  524. m_aDataPool.Remove( hHash );
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Purpose: Remove all elements from the hash
  528. //-----------------------------------------------------------------------------
  529. template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::RemoveAll( void )
  530. {
  531. m_aBuckets.RemoveAll();
  532. m_aDataPool.RemoveAll();
  533. }
  534. //-----------------------------------------------------------------------------
  535. //-----------------------------------------------------------------------------
  536. template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Find( unsigned int uiKey )
  537. {
  538. // hash the "key" - get the correct hash table "bucket"
  539. int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask );
  540. for ( int iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next( iElement ) )
  541. {
  542. if ( m_aDataPool[iElement].m_uiKey == uiKey )
  543. return iElement;
  544. }
  545. return InvalidHandle();
  546. }
  547. //-----------------------------------------------------------------------------
  548. // Purpose: Return data given a hash handle.
  549. //-----------------------------------------------------------------------------
  550. template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash )
  551. {
  552. return ( m_aDataPool[hHash].m_Data );
  553. }
  554. //-----------------------------------------------------------------------------
  555. // Purpose: Return data given a hash handle.
  556. //-----------------------------------------------------------------------------
  557. template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash ) const
  558. {
  559. return ( m_aDataPool[hHash].m_Data );
  560. }
  561. //-----------------------------------------------------------------------------
  562. // Purpose: Return data given a hash handle.
  563. //-----------------------------------------------------------------------------
  564. template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash )
  565. {
  566. return ( m_aDataPool[hHash].m_Data );
  567. }
  568. //-----------------------------------------------------------------------------
  569. // Purpose: Return data given a hash handle.
  570. //-----------------------------------------------------------------------------
  571. template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash ) const
  572. {
  573. return ( m_aDataPool[hHash].m_Data );
  574. }
  575. //=============================================================================
  576. //
  577. // Fixed Hash
  578. //
  579. // Number of buckets must be a power of 2.
  580. // Key must be 32-bits (unsigned int).
  581. //
  582. typedef int UtlHashFixedHandle_t;
  583. template <int NUM_BUCKETS>
  584. class CUtlHashFixedGenericHash
  585. {
  586. public:
  587. static int Hash( int key, int bucketMask )
  588. {
  589. int hash = HashIntConventional( key );
  590. if ( NUM_BUCKETS <= USHRT_MAX )
  591. {
  592. hash ^= ( hash >> 16 );
  593. }
  594. if ( NUM_BUCKETS <= UCHAR_MAX )
  595. {
  596. hash ^= ( hash >> 8 );
  597. }
  598. return ( hash & bucketMask );
  599. }
  600. };
  601. template<class Data, int NUM_BUCKETS, class CHashFuncs = CUtlHashFastNoHash >
  602. class CUtlHashFixed
  603. {
  604. public:
  605. // Constructor/Deconstructor.
  606. CUtlHashFixed();
  607. ~CUtlHashFixed();
  608. // Memory.
  609. void Purge( void );
  610. // Invalid handle.
  611. static UtlHashFixedHandle_t InvalidHandle( void ) { return ( UtlHashFixedHandle_t )~0; }
  612. // Size.
  613. int Count( void );
  614. // Insertion.
  615. UtlHashFixedHandle_t Insert( unsigned int uiKey, const Data &data );
  616. UtlHashFixedHandle_t FastInsert( unsigned int uiKey, const Data &data );
  617. // Removal.
  618. void Remove( UtlHashFixedHandle_t hHash );
  619. void RemoveAll( void );
  620. // Retrieval.
  621. UtlHashFixedHandle_t Find( unsigned int uiKey );
  622. Data &Element( UtlHashFixedHandle_t hHash );
  623. Data const &Element( UtlHashFixedHandle_t hHash ) const;
  624. Data &operator[]( UtlHashFixedHandle_t hHash );
  625. Data const &operator[]( UtlHashFixedHandle_t hHash ) const;
  626. //protected:
  627. // Templatized for memory tracking purposes
  628. template <typename Data_t>
  629. struct HashFixedData_t_
  630. {
  631. unsigned int m_uiKey;
  632. Data_t m_Data;
  633. };
  634. typedef HashFixedData_t_<Data> HashFixedData_t;
  635. enum
  636. {
  637. BUCKET_MASK = NUM_BUCKETS - 1
  638. };
  639. CUtlPtrLinkedList<HashFixedData_t> m_aBuckets[NUM_BUCKETS];
  640. int m_nElements;
  641. };
  642. //-----------------------------------------------------------------------------
  643. // Purpose: Constructor
  644. //-----------------------------------------------------------------------------
  645. template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::CUtlHashFixed()
  646. {
  647. Purge();
  648. }
  649. //-----------------------------------------------------------------------------
  650. // Purpose: Deconstructor
  651. //-----------------------------------------------------------------------------
  652. template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::~CUtlHashFixed()
  653. {
  654. Purge();
  655. }
  656. //-----------------------------------------------------------------------------
  657. // Purpose: Destroy dynamically allocated hash data.
  658. //-----------------------------------------------------------------------------
  659. template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Purge( void )
  660. {
  661. RemoveAll();
  662. }
  663. //-----------------------------------------------------------------------------
  664. // Purpose: Return the number of elements in the hash.
  665. //-----------------------------------------------------------------------------
  666. template<class Data, int NUM_BUCKETS, class HashFuncs> inline int CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Count( void )
  667. {
  668. return m_nElements;
  669. }
  670. //-----------------------------------------------------------------------------
  671. // Purpose: Insert data into the hash table given its key (unsigned int), with
  672. // a check to see if the element already exists within the tree.
  673. //-----------------------------------------------------------------------------
  674. template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Insert( unsigned int uiKey, const Data &data )
  675. {
  676. // Check to see if that key already exists in the buckets (should be unique).
  677. UtlHashFixedHandle_t hHash = Find( uiKey );
  678. if( hHash != InvalidHandle() )
  679. return hHash;
  680. return FastInsert( uiKey, data );
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Purpose: Insert data into the hash table given its key (unsigned int),
  684. // without a check to see if the element already exists within the tree.
  685. //-----------------------------------------------------------------------------
  686. template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::FastInsert( unsigned int uiKey, const Data &data )
  687. {
  688. int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 );
  689. UtlPtrLinkedListIndex_t iElem = m_aBuckets[iBucket].AddToHead();
  690. HashFixedData_t *pHashData = &m_aBuckets[iBucket][iElem];
  691. Assert( (UtlPtrLinkedListIndex_t)pHashData == iElem );
  692. // Add data to new element.
  693. pHashData->m_uiKey = uiKey;
  694. pHashData->m_Data = data;
  695. m_nElements++;
  696. return (UtlHashFixedHandle_t)pHashData;
  697. }
  698. //-----------------------------------------------------------------------------
  699. // Purpose: Remove a given element from the hash.
  700. //-----------------------------------------------------------------------------
  701. template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Remove( UtlHashFixedHandle_t hHash )
  702. {
  703. HashFixedData_t *pHashData = (HashFixedData_t *)hHash;
  704. Assert( Find(pHashData->m_uiKey) != InvalidHandle() );
  705. int iBucket = HashFuncs::Hash( pHashData->m_uiKey, NUM_BUCKETS - 1 );
  706. m_aBuckets[iBucket].Remove( (UtlPtrLinkedListIndex_t)pHashData );
  707. m_nElements--;
  708. }
  709. //-----------------------------------------------------------------------------
  710. // Purpose: Remove all elements from the hash
  711. //-----------------------------------------------------------------------------
  712. template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::RemoveAll( void )
  713. {
  714. for ( int i = 0; i < NUM_BUCKETS; i++ )
  715. {
  716. m_aBuckets[i].RemoveAll();
  717. }
  718. m_nElements = 0;
  719. }
  720. //-----------------------------------------------------------------------------
  721. //-----------------------------------------------------------------------------
  722. template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Find( unsigned int uiKey )
  723. {
  724. int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 );
  725. CUtlPtrLinkedList<HashFixedData_t> &bucket = m_aBuckets[iBucket];
  726. for ( UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next( iElement ) )
  727. {
  728. if ( bucket[iElement].m_uiKey == uiKey )
  729. return (UtlHashFixedHandle_t)iElement;
  730. }
  731. return InvalidHandle();
  732. }
  733. //-----------------------------------------------------------------------------
  734. // Purpose: Return data given a hash handle.
  735. //-----------------------------------------------------------------------------
  736. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash )
  737. {
  738. return ((HashFixedData_t *)hHash)->m_Data;
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Purpose: Return data given a hash handle.
  742. //-----------------------------------------------------------------------------
  743. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash ) const
  744. {
  745. return ((HashFixedData_t *)hHash)->m_Data;
  746. }
  747. //-----------------------------------------------------------------------------
  748. // Purpose: Return data given a hash handle.
  749. //-----------------------------------------------------------------------------
  750. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash )
  751. {
  752. return ((HashFixedData_t *)hHash)->m_Data;
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Purpose: Return data given a hash handle.
  756. //-----------------------------------------------------------------------------
  757. template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash ) const
  758. {
  759. return ((HashFixedData_t *)hHash)->m_Data;
  760. }
  761. #endif // UTLHASH_H