Leaked source code of windows server 2003
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.

861 lines
17 KiB

  1. /*++
  2. FHashEx.inl
  3. This file contains the template implementation of the class TFHashEx.
  4. --*/
  5. //---------------------------------------------
  6. template< class Data,
  7. class Key,
  8. class KEYREF /* This is the type used to point or reference items in the cache*/
  9. >
  10. TFHashEx< Data, Key, KEYREF >::TFHashEx( ) :
  11. m_cBuckets( 0 ),
  12. m_cActiveBuckets( 0 ),
  13. m_cNumAlloced( 0 ),
  14. m_cIncrement( 0 ),
  15. m_ppBucket( 0 ),
  16. m_pfnHash( 0 ),
  17. m_pGetKey( 0 ),
  18. m_pMatchKey( 0 ),
  19. m_load( 0 ) {
  20. //
  21. // Very basic constructor
  22. //
  23. }
  24. //---------------------------------------------
  25. template< class Data,
  26. class Key,
  27. class KEYREF
  28. >
  29. BOOL
  30. TFHashEx< Data, Key, KEYREF >::Init(
  31. NEXTPTR pNext,
  32. int cInitial,
  33. int cIncrement,
  34. DWORD (*pfnHash)(KEYREF),
  35. int load,
  36. GETKEY pGetKey,
  37. MATCHKEY pMatchKey
  38. ) {
  39. /*++
  40. Routine Description :
  41. Initialize the hash table
  42. Arguments :
  43. pNext - A pointer to Member with class Data where we can hold
  44. our bucket pointers !
  45. cInitial - Initial size of the hash table
  46. cIncrement - Amount to grow the hash table by !
  47. pfnHash - Hash Function -
  48. load - Average bucket length before growing the table !
  49. Return Value :
  50. TRUE if successfull FALSE otherwise
  51. --*/
  52. m_pGetKey = pGetKey ;
  53. m_pMatchKey = pMatchKey ;
  54. //
  55. // Compute nearest power of 2
  56. //
  57. m_pNext = pNext ;
  58. int power = cInitial ;
  59. while( power & (power-1) )
  60. power = power & (power-1) ;
  61. power<<= 1 ;
  62. cInitial = power;
  63. m_load = load ;
  64. m_pfnHash = pfnHash ;
  65. //
  66. // Number of ActiveBuckets is initially half that of the number of buckets.
  67. //
  68. m_cActiveBuckets = power/2 ;
  69. m_cBuckets = power ;
  70. m_cInserts = m_cActiveBuckets * m_load ;
  71. m_cIncrement = m_cActiveBuckets / 4;
  72. m_cNumAlloced = cInitial + 5 * m_cIncrement ;
  73. //
  74. // Allocate bucket pointers and zero initialize
  75. //
  76. m_ppBucket = new Data*[m_cNumAlloced] ;
  77. if( m_ppBucket ) {
  78. ZeroMemory( m_ppBucket, m_cNumAlloced * sizeof( Data*) ) ;
  79. _ASSERT( IsValid( FALSE ) ) ;
  80. return TRUE ;
  81. }
  82. return FALSE ;
  83. }
  84. //------------------------------------------------
  85. template< class Data,
  86. class Key,
  87. class KEYREF
  88. >
  89. BOOL
  90. TFHashEx< Data, Key, KEYREF >::IsValid( BOOL fCheckHash ) {
  91. /*++
  92. Routine Description :
  93. Check that the hash table is valid
  94. Arguments :
  95. fCheckHash - verify that all the buckets contain the correct hash values !
  96. Return Value :
  97. TRUE if successfull FALSE otherwise
  98. --*/
  99. //
  100. // This function checks that all member variables are consistent and correct.
  101. // Do not call this function until AFTER calling the Init() function.
  102. //
  103. if( m_cBuckets <= 0 ||
  104. m_cActiveBuckets <= 0 ||
  105. m_cNumAlloced <= 0 ||
  106. m_cIncrement <= 0 ||
  107. m_load <= 0 )
  108. return FALSE ;
  109. if( m_cActiveBuckets < (m_cBuckets / 2) || m_cActiveBuckets > m_cBuckets )
  110. return FALSE ;
  111. if( m_cActiveBuckets > m_cNumAlloced )
  112. return FALSE ;
  113. if( m_cInserts > (m_load * m_cActiveBuckets) )
  114. return FALSE ;
  115. if( m_ppBucket == 0 )
  116. return FALSE ;
  117. if( fCheckHash ) {
  118. //
  119. // Examine every bucket chain to ensure that elements are in correct slots.
  120. //
  121. for( int i=0; i<m_cNumAlloced; i++ ) {
  122. if( i>=m_cActiveBuckets ) {
  123. if( m_ppBucket[i] != 0 ) {
  124. return FALSE ;
  125. }
  126. } else {
  127. for( Data *p = m_ppBucket[i]; p != 0; p = p->*m_pNext ) {
  128. KEYREF keyref = (p->*m_pGetKey)();
  129. if( ComputeIndex( m_pfnHash( keyref ) ) != unsigned(i) ) {
  130. return FALSE ;
  131. }
  132. }
  133. }
  134. }
  135. }
  136. return TRUE ;
  137. }
  138. //-------------------------------------------------
  139. template< class Data,
  140. class Key,
  141. class KEYREF
  142. >
  143. TFHashEx< Data, Key, KEYREF >::~TFHashEx() {
  144. /*++
  145. Routine Description :
  146. Destroy the hash table !
  147. Arguments :
  148. None
  149. Return Value :
  150. None
  151. --*/
  152. //
  153. // The destructor discards any memory we have allocated.
  154. //
  155. Clear();
  156. }
  157. //-------------------------------------------------
  158. template< class Data,
  159. class Key,
  160. class KEYREF
  161. >
  162. void
  163. TFHashEx< Data, Key, KEYREF >::Clear() {
  164. /*++
  165. Routine Description :
  166. Delete all entries in the table, and reset all member variables !
  167. User must call Init() again before the table is usable !
  168. Arguments :
  169. None.
  170. Return Value :
  171. None
  172. --*/
  173. //
  174. // Discards any memory we have allocated - after this, you must
  175. // call Init() again!
  176. //
  177. if( m_ppBucket ) {
  178. _ASSERT( IsValid( TRUE ) ) ;
  179. for( int i=0; i<m_cNumAlloced; i++ ) {
  180. Data *p, *pNext ;
  181. for( p = m_ppBucket[i], pNext = p ? p->*m_pNext : 0;
  182. p!=0; p=pNext, pNext= p ? p->*m_pNext : 0 ) {
  183. delete p ;
  184. }
  185. }
  186. delete[] m_ppBucket;
  187. }
  188. m_cBuckets = 0;
  189. m_cActiveBuckets = 0;
  190. m_cNumAlloced = 0;
  191. m_cIncrement = 0;
  192. m_ppBucket = 0;
  193. m_pfnHash = 0;
  194. m_load = 0;
  195. }
  196. //-------------------------------------------------
  197. template< class Data,
  198. class Key,
  199. class KEYREF
  200. >
  201. void
  202. TFHashEx< Data, Key, KEYREF >::Empty() {
  203. /*++
  204. Routine Description :
  205. Remove all entries in the table, and reset all member variables !
  206. User must call Init() again before the table is usable !
  207. This is just like Clear() but it does do a "delete".
  208. Arguments :
  209. None.
  210. Return Value :
  211. None
  212. --*/
  213. //
  214. // Discards any memory we have allocated - after this, you must
  215. // call Init() again!
  216. //
  217. if( m_ppBucket ) {
  218. _ASSERT( IsValid( TRUE ) ) ;
  219. delete[] m_ppBucket;
  220. }
  221. m_cBuckets = 0;
  222. m_cActiveBuckets = 0;
  223. m_cNumAlloced = 0;
  224. m_cIncrement = 0;
  225. m_ppBucket = 0;
  226. m_pfnHash = 0;
  227. m_load = 0;
  228. }
  229. //-------------------------------------------------
  230. template< class Data,
  231. class Key,
  232. class KEYREF
  233. >
  234. DWORD
  235. TFHashEx< Data, Key, KEYREF >::ComputeIndex( DWORD dw ) {
  236. /*++
  237. Routine Description :
  238. Compute which bucket an element should be in
  239. This function tells us where we should store elements. To do this we mod with
  240. m_cBuckets. Since we only have m_cActiveBuckets in reality, we check the result
  241. of the mod and subtract m_cBuckets over 2 if necessary.
  242. Arguments :
  243. dw - the hash value of the entry we are adding to the table
  244. Return Value :
  245. Index to the bucket to use !
  246. --*/
  247. DWORD dwTemp = dw % m_cBuckets ;
  248. return (dwTemp >= (unsigned)m_cActiveBuckets) ? dwTemp - (m_cBuckets/2) : dwTemp ;
  249. }
  250. template< class Data,
  251. class Key,
  252. class KEYREF
  253. >
  254. BOOL
  255. TFHashEx< Data, Key, KEYREF >::Insert( Data& d ) {
  256. /*++
  257. Routine Description :
  258. Insert a Data element into the hash table
  259. Arguments :
  260. d - reference to the item to be inserted into the table
  261. Return Value :
  262. TRUE if successfull - FALSE otherwise !
  263. --*/
  264. _ASSERT( d.*m_pNext == 0 ) ;
  265. _ASSERT( IsValid( FALSE ) ) ;
  266. if( InsertData( d ) )
  267. return TRUE ;
  268. return FALSE ;
  269. }
  270. template< class Data,
  271. class Key,
  272. class KEYREF
  273. >
  274. BOOL
  275. TFHashEx< Data, Key, KEYREF >::Insert( Data* pd ) {
  276. /*++
  277. Routine Description :
  278. Insert a Data element into the hash table
  279. Arguments :
  280. pd - pointer to the item to be inserted into the table
  281. Return Value :
  282. TRUE if successfull - FALSE otherwise !
  283. --*/
  284. _ASSERT( pd->*m_pNext == 0 ) ;
  285. _ASSERT( IsValid( FALSE ) ) ;
  286. KEYREF keyref = (pd->*m_pGetKey)() ;
  287. if( InsertDataHash( m_pfnHash( keyref ), pd ) )
  288. return TRUE ;
  289. return FALSE ;
  290. }
  291. //-------------------------------------------------
  292. template< class Data,
  293. class Key,
  294. class KEYREF
  295. >
  296. Data*
  297. TFHashEx< Data, Key, KEYREF >::InsertDataHash(
  298. DWORD dwHash,
  299. Data& d
  300. ) {
  301. /*++
  302. Routine Description :
  303. Insert an element into the hash table.
  304. We will use member's of Data to hold the bucket chain.
  305. Arguments :
  306. dw - the hash value of the entry we are adding to the table
  307. d - The item we are adding to the table !
  308. Return Value :
  309. Pointer to the Data Item in its final resting place !
  310. --*/
  311. _ASSERT( IsValid( FALSE ) ) ;
  312. _ASSERT( d.*m_pNext == 0 ) ;
  313. //
  314. // First check whether it is time to grow the hash table.
  315. //
  316. if( --m_cInserts == 0 ) {
  317. //
  318. // Check whether we need to reallocate the array of Bucket pointers.
  319. //
  320. if( m_cIncrement + m_cActiveBuckets > m_cNumAlloced ) {
  321. Data** pTemp = new Data*[m_cNumAlloced + 10 * m_cIncrement ] ;
  322. if( pTemp == 0 ) {
  323. //
  324. // bugbug ... need to handles this error better !?
  325. //
  326. return 0 ;
  327. } else {
  328. ZeroMemory( pTemp, (m_cNumAlloced + 10 *m_cIncrement)* sizeof( Data*) ) ;
  329. CopyMemory( pTemp, m_ppBucket, m_cNumAlloced * sizeof( Data* ) ) ;
  330. delete[] m_ppBucket;
  331. m_cNumAlloced += 10 * m_cIncrement ;
  332. m_ppBucket = pTemp ;
  333. }
  334. }
  335. //
  336. // Okay grow the array by m_cIncrement.
  337. //
  338. m_cActiveBuckets += m_cIncrement ;
  339. if( m_cActiveBuckets > m_cBuckets )
  340. m_cBuckets *= 2 ;
  341. m_cInserts = m_cIncrement * m_load ;
  342. //
  343. // Now do some rehashing of elements.
  344. //
  345. for( int i = -m_cIncrement; i < 0; i++ ) {
  346. int iCurrent = (m_cActiveBuckets + i) - (m_cBuckets / 2) ;
  347. Data** ppNext = &m_ppBucket[ iCurrent ] ;
  348. Data* p = *ppNext ;
  349. while( p ) {
  350. KEYREF keyref = (p->*m_pGetKey)();
  351. int index = ComputeIndex( m_pfnHash( keyref ) ) ;
  352. Data* pNext = p->*m_pNext ;
  353. if( index != iCurrent) {
  354. *ppNext = pNext ;
  355. p->*m_pNext = m_ppBucket[index] ;
  356. m_ppBucket[index] = p ;
  357. } else {
  358. ppNext = &(p->*m_pNext) ;
  359. }
  360. p = pNext ;
  361. }
  362. }
  363. _ASSERT( IsValid( TRUE ) ) ;
  364. }
  365. //
  366. // Finally, insert into the Hash Table.
  367. //
  368. //DWORD index = ComputeIndex( m_pfnHash( d.GetKey() ) ) ;
  369. KEYREF keyref = (d.*m_pGetKey)();
  370. _ASSERT( dwHash == m_pfnHash( keyref ) ) ;
  371. DWORD index = ComputeIndex( dwHash ) ;
  372. _ASSERT( index < unsigned(m_cActiveBuckets) ) ;
  373. d.*m_pNext = m_ppBucket[index] ;
  374. m_ppBucket[index] = &d ;
  375. _ASSERT( IsValid( FALSE ) ) ;
  376. return &d ;
  377. }
  378. //-------------------------------------------------
  379. template< class Data,
  380. class Key,
  381. class KEYREF
  382. >
  383. Data*
  384. TFHashEx< Data, Key, KEYREF >::InsertDataHash(
  385. DWORD dwHash,
  386. Data* pd
  387. ) {
  388. /*++
  389. Routine Description :
  390. Insert an element into the hash table.
  391. We will use member's of Data to hold the bucket chain.
  392. Arguments :
  393. dw - the hash value of the entry we are adding to the table
  394. pd - Pointer to the item we are adding to the table !
  395. Return Value :
  396. Pointer to the Data Item in its final resting place !
  397. --*/
  398. _ASSERT( IsValid( FALSE ) ) ;
  399. _ASSERT( pd->*m_pNext == 0 ) ;
  400. //
  401. // First check whether it is time to grow the hash table.
  402. //
  403. if( --m_cInserts == 0 ) {
  404. //
  405. // Check whether we need to reallocate the array of Bucket pointers.
  406. //
  407. if( m_cIncrement + m_cActiveBuckets > m_cNumAlloced ) {
  408. Data** pTemp = new Data*[m_cNumAlloced + 10 * m_cIncrement ] ;
  409. if( pTemp == 0 ) {
  410. //
  411. // bugbug ... need to handles this error better !?
  412. //
  413. return 0 ;
  414. } else {
  415. ZeroMemory( pTemp, (m_cNumAlloced + 10 *m_cIncrement)* sizeof( Data*) ) ;
  416. CopyMemory( pTemp, m_ppBucket, m_cNumAlloced * sizeof( Data* ) ) ;
  417. delete[] m_ppBucket;
  418. m_cNumAlloced += 10 * m_cIncrement ;
  419. m_ppBucket = pTemp ;
  420. }
  421. }
  422. //
  423. // Okay grow the array by m_cIncrement.
  424. //
  425. m_cActiveBuckets += m_cIncrement ;
  426. if( m_cActiveBuckets > m_cBuckets )
  427. m_cBuckets *= 2 ;
  428. m_cInserts = m_cIncrement * m_load ;
  429. //
  430. // Now do some rehashing of elements.
  431. //
  432. for( int i = -m_cIncrement; i < 0; i++ ) {
  433. int iCurrent = (m_cActiveBuckets + i) - (m_cBuckets / 2) ;
  434. Data** ppNext = &m_ppBucket[ iCurrent ] ;
  435. Data* p = *ppNext ;
  436. while( p ) {
  437. KEYREF keyref = (p->*m_pGetKey)();
  438. int index = ComputeIndex( m_pfnHash( keyref ) ) ;
  439. Data* pNext = p->*m_pNext ;
  440. if( index != iCurrent) {
  441. *ppNext = pNext ;
  442. p->*m_pNext = m_ppBucket[index] ;
  443. m_ppBucket[index] = p ;
  444. } else {
  445. ppNext = &(p->*m_pNext) ;
  446. }
  447. p = pNext ;
  448. }
  449. }
  450. _ASSERT( IsValid( TRUE ) ) ;
  451. }
  452. //
  453. // Finally, insert into the Hash Table.
  454. //
  455. //DWORD index = ComputeIndex( m_pfnHash( d.GetKey() ) ) ;
  456. KEYREF keyref = (pd->*m_pGetKey)();
  457. _ASSERT( dwHash == m_pfnHash( keyref ) ) ;
  458. DWORD index = ComputeIndex( dwHash ) ;
  459. _ASSERT( index < unsigned(m_cActiveBuckets) ) ;
  460. pd->*m_pNext = m_ppBucket[index] ;
  461. m_ppBucket[index] = pd ;
  462. _ASSERT( IsValid( FALSE ) ) ;
  463. return pd ;
  464. }
  465. //-------------------------------------------------
  466. template< class Data,
  467. class Key,
  468. class KEYREF
  469. >
  470. inline Data*
  471. TFHashEx< Data, Key, KEYREF >::InsertData( Data& d ) {
  472. /*++
  473. Routine Description :
  474. Insert an element into the hash table.
  475. We will use member's of Data to hold the bucket chain,
  476. and we will also compute the hash of the key !
  477. Arguments :
  478. d - The item we are adding to the table !
  479. Return Value :
  480. Pointer to the Data Item in its final resting place !
  481. --*/
  482. _ASSERT( IsValid( FALSE ) ) ;
  483. KEYREF keyref = (d.*m_pGetKey)() ;
  484. return InsertDataHash( m_pfnHash( keyref ), d ) ;
  485. }
  486. //-----------------------------------------------
  487. template< class Data,
  488. class Key,
  489. class KEYREF
  490. >
  491. BOOL
  492. TFHashEx< Data, Key, KEYREF >::Search( KEYREF k,
  493. Data &dOut
  494. ) {
  495. /*++
  496. Routine Description :
  497. Search for an element in the hashtable.
  498. Arguments :
  499. k - key of the item to find
  500. dOut - A reference that we will set to the
  501. located data item
  502. Return Value :
  503. TRUE if found, FALSE otherwise
  504. --*/
  505. const Data* pData = SearchKey( k ) ;
  506. if( pData ) {
  507. dOut = *pData ;
  508. return TRUE ;
  509. }
  510. return FALSE ;
  511. }
  512. //-----------------------------------------------
  513. template< class Data,
  514. class Key,
  515. class KEYREF
  516. >
  517. Data*
  518. TFHashEx< Data, Key, KEYREF >::SearchKeyHash(
  519. DWORD dwHash,
  520. KEYREF k
  521. ) {
  522. /*++
  523. Routine Description :
  524. Search for an element in the Hash Table,
  525. Arguments :
  526. dwHash - the hash value of the entry we are adding to the table
  527. k - reference to the key we are to compare against
  528. Return Value :
  529. Pointer to the Data Item in its final resting place !
  530. --*/
  531. _ASSERT( IsValid( FALSE ) ) ;
  532. _ASSERT( dwHash == (m_pfnHash)(k) ) ;
  533. DWORD index = ComputeIndex( dwHash ) ;
  534. Data* p = m_ppBucket[index] ;
  535. while( p ) {
  536. if( (p->*m_pMatchKey)( k ) )
  537. break ;
  538. p = p->*m_pNext ;
  539. }
  540. return p ;
  541. }
  542. //-----------------------------------------------
  543. template< class Data,
  544. class Key,
  545. class KEYREF
  546. >
  547. inline Data*
  548. TFHashEx< Data, Key, KEYREF >::SearchKey( KEYREF k ) {
  549. /*++
  550. Routine Description :
  551. Search for an element in the Hash Table,
  552. We will compute the hash of the key.
  553. Arguments :
  554. k - reference to the key we are to compare against
  555. Return Value :
  556. Pointer to the Data Item in its final resting place !
  557. --*/
  558. _ASSERT( IsValid( FALSE ) ) ;
  559. return SearchKeyHash( m_pfnHash( k ), k ) ;
  560. }
  561. //-----------------------------------------------
  562. template< class Data,
  563. class Key,
  564. class KEYREF
  565. >
  566. BOOL
  567. TFHashEx< Data, Key, KEYREF >::Delete( KEYREF k ) {
  568. /*++
  569. Routine Description :
  570. Find an element in the hash table, remove it from
  571. the table and then destroy it !
  572. Arguments :
  573. k - reference to the key we are to compare against
  574. Return Value :
  575. TRUE if an item is found and destroyed, FALSE otherwise !
  576. --*/
  577. Data* p = DeleteData( k, 0 ) ;
  578. if( p ) {
  579. delete p ;
  580. return TRUE ;
  581. }
  582. return FALSE ;
  583. }
  584. //-----------------------------------------------
  585. template< class Data,
  586. class Key,
  587. class KEYREF
  588. >
  589. Data*
  590. TFHashEx< Data, Key, KEYREF >::DeleteData( KEYREF k,
  591. Data* pd
  592. ) {
  593. //
  594. // Remove an element from the Hash Table. We only need the
  595. // Key to find the element we wish to remove.
  596. //
  597. _ASSERT( IsValid( FALSE ) ) ;
  598. DWORD dwHash = (m_pfnHash)( k ) ;
  599. DWORD index = ComputeIndex( dwHash ) ;
  600. Data** ppNext = &m_ppBucket[index] ;
  601. Data* p = *ppNext ;
  602. while( p ) {
  603. if( (p->*m_pMatchKey)( k ) )
  604. break ;
  605. ppNext = &(p->*m_pNext) ;
  606. p = *ppNext ;
  607. }
  608. if( p ) {
  609. //
  610. // If we were given a pointer to a data block, than the client
  611. // wants us to check to make sure that we are deleting the correct
  612. // instance !!
  613. //
  614. if( !pd || pd == p ) {
  615. *ppNext = p->*m_pNext ;
  616. p->*m_pNext = 0 ;
  617. //
  618. // Finally - since we removed something from the hash table
  619. // increment the number of inserts so that we don't keep splitting
  620. // the table unnecessarily !
  621. //
  622. m_cInserts++ ;
  623. _ASSERT( IsValid( FALSE ) ) ;
  624. } else {
  625. p = 0 ;
  626. }
  627. }
  628. _ASSERT( IsValid( FALSE ) ) ;
  629. return p ;
  630. }
  631. template< class Data,
  632. class Key,
  633. class KEYREF
  634. >
  635. DWORD
  636. TFHashEx< Data, Key, KEYREF >::ComputeHash( KEYREF k ) {
  637. return m_pfnHash( k ) ;
  638. }