Source code of Windows XP (NT5)
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.

1089 lines
20 KiB

  1. /*++
  2. fdlhash.inl
  3. This file contains the template implementation of the class TFDLHash
  4. --*/
  5. #ifdef METER
  6. template< class Data,
  7. class KEYREF,
  8. Data::PFNDLIST s_Offset,
  9. BOOL fOrdered
  10. >
  11. long
  12. TFDLHash< Data, KEYREF, s_Offset >::BucketDepth(
  13. DWORD index
  14. ) {
  15. /*++
  16. Routine Description :
  17. computes how deep the specified bucket is !
  18. Arguments :
  19. index - the hash bucket thats changed length !
  20. Return Value :
  21. Depth of the bucket !
  22. --*/
  23. _ASSERT( IsValid( FALSE ) ) ;
  24. long l = 0 ;
  25. ITER i = m_pBucket[index] ;
  26. while( !i.AtEnd() ) {
  27. i.Next() ;
  28. l ++ ;
  29. }
  30. return l ;
  31. }
  32. template< class Data,
  33. class KEYREF,
  34. Data::PFNDLIST s_Offset
  35. >
  36. void
  37. TFDLHash< Data, KEYREF, s_Offset >::MaxBucket(
  38. DWORD index
  39. ) {
  40. /*++
  41. Routine Description :
  42. Sets our statistics for what the deepest bucket is !
  43. Arguments :
  44. index - the hash bucket that was touched !
  45. Return Value :
  46. None.
  47. --*/
  48. if( m_pStat ) {
  49. long l = BucketDepth( index ) ;
  50. m_pStat->m_cHashCounters[CHashStats::DEEPBUCKET] =
  51. max( m_pStat->m_cHashCounters[CHashStats::DEEPBUCKET], l ) ;
  52. }
  53. }
  54. template< class Data,
  55. class KEYREF,
  56. Data::PFNDLIST s_Offset,
  57. BOOL fOrdered
  58. >
  59. void
  60. TFDLHash< Data, KEYREF, s_Offset >::AverageBucket() {
  61. /*++
  62. Routine Description :
  63. Sets out statistics for what the average bucket depth is !
  64. Arguments :
  65. index - the hash bucket that was touched !
  66. Return Value :
  67. None.
  68. --*/
  69. if( m_pStat ) {
  70. BOOL fReMax = (m_pStat->m_cHashCounters[CHashStats::INSERTS] % 1000) == 0 ;
  71. if( fReMax ) {
  72. m_pStat->m_cHashCounters[CHashStats::DEEPBUCKET] = 0 ;
  73. }
  74. if( (m_pStat->m_cHashCounters[CHashStats::INSERTS] % 200) == 0 ) {
  75. long l = m_pStat->m_cHashCounters[CHashStats::HASHITEMS] ;
  76. long cNonEmpty = 0 ;
  77. for( int i=0; i < m_cActiveBuckets ; i++ ) {
  78. if( !m_pBucket[i].IsEmpty() ) {
  79. cNonEmpty ++ ;
  80. if( fReMax )
  81. MaxBucket( DWORD(i) ) ;
  82. }
  83. }
  84. m_pStat->m_cHashCounters[CHashStats::AVERAGEBUCKET] =
  85. l / cNonEmpty ;
  86. m_pStat->m_cHashCounters[CHashStats::EMPTYBUCKET] = m_cActiveBuckets - cNonEmpty ;
  87. }
  88. }
  89. }
  90. template< class Data,
  91. class KEYREF,
  92. Data::PFNDLIST s_Offset,
  93. BOOL fOrdered
  94. >
  95. void
  96. TFDLHash< Data, KEYREF, s_Offset >::AverageSearch(
  97. BOOL fHit,
  98. long depthSearch
  99. ) {
  100. /*++
  101. Routine Description :
  102. Computes the average Search depth !
  103. Arguments :
  104. depthSearch - how long the search went !
  105. Return Value :
  106. none
  107. --*/
  108. if( m_pStat ) {
  109. if( (m_pStat->m_cHashCounters[CHashStats::SEARCHHITS] % 500) == 0 ) {
  110. m_pStat->m_cHashCounters[CHashStats::DEEPSEARCH] = 0 ;
  111. }
  112. if( depthSearch != 0 ) {
  113. long searches = m_pStat->m_cHashCounters[CHashStats::SEARCHHITS] ;
  114. searches = min( searches, 100 ) ; // Average over the last 100 hits !
  115. __int64 sum = m_pStat->m_cHashCounters[CHashStats::AVERAGESEARCH] *
  116. (searches) ;
  117. __int64 average = (sum + ((__int64)depthSearch)) / ((__int64)searches+1) ;
  118. m_pStat->m_cHashCounters[CHashStats::AVERAGESEARCH] = (long)average ;
  119. }
  120. if( fHit ) {
  121. INCREMENTSTAT( SEARCHHITS ) ;
  122. ADDSTAT( SEARCHCOST, depthSearch ) ;
  123. } else {
  124. ADDSTAT( SEARCHCOSTMISS, depthSearch ) ;
  125. }
  126. m_pStat->m_cHashCounters[CHashStats::DEEPSEARCH] =
  127. max( m_pStat->m_cHashCounters[CHashStats::DEEPSEARCH], depthSearch ) ;
  128. }
  129. }
  130. #endif // METER
  131. //---------------------------------------------
  132. template< class Data,
  133. class KEYREF, /* This is the type used to point or reference items in the cache*/
  134. Data::PFNDLIST s_Offset,
  135. BOOL fOrdered
  136. >
  137. TFDLHash< Data, KEYREF, s_Offset >::TFDLHash( ) :
  138. m_cBuckets( 0 ),
  139. m_cActiveBuckets( 0 ),
  140. m_cNumAlloced( 0 ),
  141. m_cIncrement( 0 ),
  142. m_pBucket( 0 ),
  143. m_pfnHash( 0 ),
  144. m_pGetKey( 0 ),
  145. m_pMatchKey( 0 ),
  146. m_load( 0 ) {
  147. //
  148. // Very basic constructor
  149. //
  150. }
  151. //---------------------------------------------
  152. template< class Data,
  153. class KEYREF,
  154. Data::PFNDLIST s_Offset,
  155. BOOL fOrdered
  156. >
  157. BOOL
  158. TFDLHash< Data, KEYREF, s_Offset >::Init(
  159. int cInitial,
  160. int cIncrement,
  161. int load,
  162. PFNHASH pfnHash,
  163. GETKEY pGetKey,
  164. MATCHKEY pMatchKey,
  165. PFNREHASH pfnReHash,
  166. CHashStats* pStats
  167. ) {
  168. /*++
  169. Routine Description :
  170. Initialize the hash table
  171. Arguments :
  172. pNext - A pointer to Member with class Data where we can hold
  173. our bucket pointers !
  174. cInitial - Initial size of the hash table
  175. cIncrement - Amount to grow the hash table by !
  176. pfnHash - Hash Function -
  177. load - Average bucket length before growing the table !
  178. Return Value :
  179. TRUE if successfull FALSE otherwise
  180. --*/
  181. #ifdef METER
  182. m_pStat = pStats ;
  183. #endif
  184. m_pGetKey = pGetKey ;
  185. m_pMatchKey = pMatchKey ;
  186. //
  187. // Compute nearest power of 2
  188. //
  189. int power = cInitial ;
  190. while( power & (power-1) )
  191. power = power & (power-1) ;
  192. power<<= 1 ;
  193. cInitial = power;
  194. m_load = load ;
  195. m_pfnHash = pfnHash ;
  196. m_pfnReHash = pfnReHash ;
  197. //
  198. // Number of ActiveBuckets is initially half that of the number of buckets.
  199. //
  200. m_cActiveBuckets = power/2 ;
  201. m_cBuckets = power ;
  202. m_cInserts = m_cActiveBuckets * m_load ;
  203. m_cIncrement = m_cActiveBuckets / 4;
  204. m_cNumAlloced = cInitial + 5 * m_cIncrement ;
  205. //
  206. // Allocate bucket pointers and zero initialize
  207. //
  208. m_pBucket = new DLIST[m_cNumAlloced] ;
  209. SETSTAT( ALLOCBUCKETS, m_cNumAlloced ) ;
  210. SETSTAT( ACTIVEBUCKETS, m_cActiveBuckets ) ;
  211. SETSTAT( SPLITINSERTS, m_cInserts ) ;
  212. if( m_pBucket ) {
  213. _ASSERT( IsValid( TRUE ) ) ;
  214. return TRUE ;
  215. }
  216. return FALSE ;
  217. }
  218. //------------------------------------------------
  219. template< class Data,
  220. class KEYREF,
  221. Data::PFNDLIST s_Offset,
  222. BOOL fOrdered
  223. >
  224. BOOL
  225. TFDLHash< Data, KEYREF, s_Offset >::IsValidBucket( int i ) {
  226. /*++
  227. Routine Description :
  228. Chech that the hash bucket is valid !
  229. Arguments :
  230. i - the bucket to check !
  231. Return Value :
  232. TRUE if successfull FALSE otherwise
  233. --*/
  234. if( i>=m_cActiveBuckets ) {
  235. if( !m_pBucket[i].IsEmpty() ) {
  236. _ASSERT(1==0) ;
  237. return FALSE ;
  238. }
  239. } else {
  240. ITER iterNext = m_pBucket[i] ;
  241. if( !iterNext.AtEnd() )
  242. iterNext.Next() ;
  243. for( ITER iter = m_pBucket[i]; !iter.AtEnd(); iter.Next()) {
  244. Data *p = iter.Current() ;
  245. KEYREF keyref = (p->*m_pGetKey)();
  246. DWORD dwHash = m_pfnHash( keyref ) ;
  247. DWORD index = ComputeIndex(dwHash) ;
  248. if( index != unsigned(i) ) {
  249. _ASSERT(1==0);
  250. return FALSE ;
  251. }
  252. if( fOrdered ) {
  253. if( !iterNext.AtEnd() ) {
  254. Data *pNext = iterNext.Current() ;
  255. KEYREF keyrefNext = (pNext->*m_pGetKey)() ;
  256. int iCompare = (*m_pMatchKey)( keyref, keyrefNext ) ;
  257. _ASSERT( iCompare < 0 ) ;
  258. if( iCompare >= 0 )
  259. return FALSE ;
  260. iterNext.Next() ;
  261. }
  262. }
  263. }
  264. }
  265. return TRUE ;
  266. }
  267. //------------------------------------------------
  268. template< class Data,
  269. class KEYREF,
  270. Data::PFNDLIST s_Offset,
  271. BOOL fOrdered
  272. >
  273. BOOL
  274. TFDLHash< Data, KEYREF, s_Offset >::IsValid( BOOL fCheckHash ) {
  275. /*++
  276. Routine Description :
  277. Check that the hash table is valid
  278. Arguments :
  279. fCheckHash - verify that all the buckets contain the correct hash values !
  280. Return Value :
  281. TRUE if successfull FALSE otherwise
  282. --*/
  283. //
  284. // This function checks that all member variables are consistent and correct.
  285. // Do not call this function until AFTER calling the Init() function.
  286. //
  287. if( m_cBuckets <= 0 ||
  288. m_cActiveBuckets <= 0 ||
  289. m_cNumAlloced <= 0 ||
  290. m_cIncrement <= 0 ||
  291. m_load <= 0 ) {
  292. _ASSERT(1==0) ;
  293. return FALSE ;
  294. }
  295. if( m_cActiveBuckets < (m_cBuckets / 2) || m_cActiveBuckets > m_cBuckets ) {
  296. _ASSERT(1==0) ;
  297. return FALSE ;
  298. }
  299. if( m_cActiveBuckets > m_cNumAlloced ) {
  300. _ASSERT(1==0) ;
  301. return FALSE ;
  302. }
  303. if( m_cInserts > (m_load * m_cActiveBuckets) ) {
  304. _ASSERT(1==0) ;
  305. return FALSE ;
  306. }
  307. if( m_pBucket == 0 ) {
  308. _ASSERT(1==0) ;
  309. return FALSE ;
  310. }
  311. if( fCheckHash ) {
  312. //
  313. // Examine every bucket chain to ensure that elements are in correct slots.
  314. //
  315. for( int i=0; i<m_cNumAlloced; i++ ) {
  316. if( i>=m_cActiveBuckets ) {
  317. if( !m_pBucket[i].IsEmpty() ) {
  318. _ASSERT(1==0) ;
  319. return FALSE ;
  320. }
  321. } else {
  322. for( ITER iter = m_pBucket[i]; !iter.AtEnd(); iter.Next() ) {
  323. Data *p = iter.Current() ;
  324. KEYREF keyref = (p->*m_pGetKey)();
  325. DWORD dwHash = m_pfnHash( keyref ) ;
  326. DWORD index = ComputeIndex(dwHash) ;
  327. if( index != unsigned(i) ) {
  328. _ASSERT(1==0);
  329. return FALSE ;
  330. }
  331. }
  332. }
  333. _ASSERT( IsValidBucket( i ) ) ;
  334. }
  335. }
  336. return TRUE ;
  337. }
  338. //-------------------------------------------------
  339. template< class Data,
  340. class KEYREF,
  341. Data::PFNDLIST s_Offset,
  342. BOOL fOrdered
  343. >
  344. TFDLHash< Data, KEYREF, s_Offset >::~TFDLHash() {
  345. /*++
  346. Routine Description :
  347. Destroy the hash table !
  348. Arguments :
  349. None
  350. Return Value :
  351. None
  352. --*/
  353. //
  354. // The destructor discards any memory we have allocated.
  355. //
  356. Clear();
  357. }
  358. //-------------------------------------------------
  359. template< class Data,
  360. class KEYREF,
  361. Data::PFNDLIST s_Offset,
  362. BOOL fOrdered
  363. >
  364. void
  365. TFDLHash< Data, KEYREF, s_Offset >::Clear() {
  366. /*++
  367. Routine Description :
  368. Delete all entries in the table, and reset all member variables !
  369. User must call Init() again before the table is usable !
  370. Arguments :
  371. None.
  372. Return Value :
  373. None
  374. --*/
  375. //
  376. // Discards any memory we have allocated - after this, you must
  377. // call Init() again!
  378. //
  379. if( m_pBucket ) {
  380. _ASSERT( IsValid( TRUE ) ) ;
  381. for( int i=0; i<m_cNumAlloced; i++ ) {
  382. for( ITER iter=m_pBucket[i]; !iter.AtEnd(); ) {
  383. Data* p = iter.RemoveItem() ;
  384. delete p ;
  385. }
  386. }
  387. delete[] m_pBucket;
  388. }
  389. m_cBuckets = 0;
  390. m_cActiveBuckets = 0;
  391. m_cNumAlloced = 0;
  392. m_cIncrement = 0;
  393. m_pBucket = 0;
  394. m_pfnHash = 0;
  395. m_load = 0;
  396. }
  397. //-------------------------------------------------
  398. template< class Data,
  399. class KEYREF,
  400. Data::PFNDLIST s_Offset,
  401. BOOL fOrdered
  402. >
  403. void
  404. TFDLHash< Data, KEYREF, s_Offset >::Empty() {
  405. /*++
  406. Routine Description :
  407. Remove all entries in the table, and reset all member variables !
  408. User must call Init() again before the table is usable !
  409. This is just like Clear() but it does do a "delete".
  410. Arguments :
  411. None.
  412. Return Value :
  413. None
  414. --*/
  415. //
  416. // Discards any memory we have allocated - after this, you must
  417. // call Init() again!
  418. //
  419. if( m_pBucket ) {
  420. _ASSERT( IsValid( TRUE ) ) ;
  421. delete[] m_pBucket;
  422. }
  423. m_cBuckets = 0;
  424. m_cActiveBuckets = 0;
  425. m_cNumAlloced = 0;
  426. m_cIncrement = 0;
  427. m_ppBucket = 0;
  428. m_pfnHash = 0;
  429. m_load = 0;
  430. }
  431. //-------------------------------------------------
  432. template< class Data,
  433. class KEYREF,
  434. Data::PFNDLIST s_Offset,
  435. BOOL fOrdered
  436. >
  437. DWORD
  438. TFDLHash< Data, KEYREF, s_Offset >::ComputeIndex( DWORD dw ) {
  439. /*++
  440. Routine Description :
  441. Compute which bucket an element should be in
  442. This function tells us where we should store elements. To do this we mod with
  443. m_cBuckets. Since we only have m_cActiveBuckets in reality, we check the result
  444. of the mod and subtract m_cBuckets over 2 if necessary.
  445. Arguments :
  446. dw - the hash value of the entry we are adding to the table
  447. Return Value :
  448. Index to the bucket to use !
  449. --*/
  450. DWORD dwTemp = dw % m_cBuckets ;
  451. return (dwTemp >= (unsigned)m_cActiveBuckets) ? dwTemp - (m_cBuckets/2) : dwTemp ;
  452. }
  453. //-----------------------------------------------
  454. template< class Data,
  455. class KEYREF,
  456. Data::PFNDLIST s_Offset,
  457. BOOL fOrdered
  458. >
  459. void
  460. TFDLHash< Data, KEYREF, s_Offset >::SearchKeyHash(
  461. DWORD dwHash,
  462. KEYREF k,
  463. Data* &pd
  464. ) {
  465. /*++
  466. Routine Description :
  467. Search for an element in the Hash Table,
  468. Arguments :
  469. dwHash - the hash value of the entry we are adding to the table
  470. k - reference to the key we are to compare against
  471. Return Value :
  472. Pointer to the Data Item in its final resting place !
  473. --*/
  474. _ASSERT( IsValid( FALSE ) ) ;
  475. _ASSERT( dwHash == (m_pfnHash)(k) ) ;
  476. INCREMENTSTAT( SEARCHES ) ;
  477. #ifdef METER
  478. long lSearchDepth = 0 ;
  479. #endif
  480. pd = 0 ;
  481. DWORD index = ComputeIndex( dwHash ) ;
  482. ITER i = m_pBucket[index] ;
  483. Data* p = 0 ;
  484. while( !i.AtEnd() ) {
  485. #ifdef METER
  486. lSearchDepth ++ ;
  487. #endif
  488. p = i.Current() ;
  489. int iSign = (*m_pMatchKey)( (p->*m_pGetKey)(), k ) ;
  490. if( iSign == 0 ) {
  491. pd = p ;
  492. break ;
  493. } else if( fOrdered && iSign > 0 ) {
  494. break ;
  495. }
  496. i.Next() ;
  497. }
  498. #ifdef METER
  499. AverageSearch( pd != 0, lSearchDepth ) ;
  500. #endif
  501. }
  502. //-----------------------------------------------
  503. template< class Data,
  504. class KEYREF,
  505. Data::PFNDLIST s_Offset,
  506. BOOL fOrdered
  507. >
  508. TFDLHash< Data, KEYREF, s_Offset, fOrdered >::ITER
  509. TFDLHash< Data, KEYREF, s_Offset, fOrdered >::SearchKeyHashIter(
  510. DWORD dwHash,
  511. KEYREF k,
  512. Data* &pd
  513. ) {
  514. /*++
  515. Routine Description :
  516. Search for an element in the Hash Table,
  517. Arguments :
  518. dwHash - the hash value of the entry we are adding to the table
  519. k - reference to the key we are to compare against
  520. Return Value :
  521. Pointer to the Data Item in its final resting place !
  522. --*/
  523. _ASSERT( IsValid( FALSE ) ) ;
  524. _ASSERT( dwHash == (m_pfnHash)(k) ) ;
  525. INCREMENTSTAT( SEARCHES ) ;
  526. #ifdef METER
  527. long lSearchDepth = 0 ;
  528. #endif
  529. pd = 0 ;
  530. DWORD index = ComputeIndex( dwHash ) ;
  531. ITER i = m_pBucket[index] ;
  532. Data* p = 0 ;
  533. while( !i.AtEnd() ) {
  534. #ifdef METER
  535. lSearchDepth ++ ;
  536. #endif
  537. p = i.Current() ;
  538. int iSign = (*m_pMatchKey)( (p->*m_pGetKey)(), k ) ;
  539. if( iSign == 0 ) {
  540. pd = p ;
  541. break ;
  542. } else if( fOrdered && iSign > 0 ) {
  543. break ;
  544. }
  545. i.Next() ;
  546. }
  547. #ifdef METER
  548. AverageSearch( pd != 0, lSearchDepth ) ;
  549. #endif
  550. return i ;
  551. }
  552. //-------------------------------------------------
  553. template< class Data,
  554. class KEYREF,
  555. Data::PFNDLIST s_Offset,
  556. BOOL fOrdered
  557. >
  558. BOOL
  559. TFDLHash< Data, KEYREF, s_Offset >::InsertDataHashIter(
  560. ITER& iter,
  561. DWORD dwHash,
  562. KEYREF k,
  563. Data* pd
  564. ) {
  565. /*++
  566. Routine Description :
  567. Insert an element into the hash table.
  568. We will use member's of Data to hold the bucket chain.
  569. Arguments :
  570. dw - the hash value of the entry we are adding to the table
  571. pd - Pointer to the item we are adding to the table !
  572. Return Value :
  573. Pointer to the Data Item in its final resting place !
  574. --*/
  575. _ASSERT( IsValid( FALSE ) ) ;
  576. INCREMENTSTAT( INSERTS ) ;
  577. #if defined(DEBUG) || defined( METER )
  578. KEYREF keyref = (pd->*m_pGetKey)();
  579. _ASSERT( dwHash == m_pfnHash( keyref ) ) ;
  580. DWORD index = ComputeIndex( dwHash ) ;
  581. _ASSERT( index < unsigned(m_cActiveBuckets) ) ;
  582. _ASSERT( iter.GetHead() == &m_pBucket[index] ) ;
  583. #endif
  584. //
  585. // This is no longer smaller than the current guy - so insert in front
  586. //
  587. iter.InsertBefore( pd ) ;
  588. #if defined(DEBUG) || defined( METER )
  589. _ASSERT( IsValidBucket( index ) ) ;
  590. //
  591. // Update our statistics !
  592. //
  593. //MAXBUCKET( index ) ;
  594. #endif
  595. INCREMENTSTAT( HASHITEMS ) ;
  596. //AVERAGEBUCKET() ;
  597. _ASSERT( IsValid( FALSE ) ) ;
  598. //
  599. // First check whether it is time to grow the hash table.
  600. //
  601. if( --m_cInserts == 0 ) {
  602. Split() ;
  603. }
  604. SETSTAT( SPLITINSERTS, m_cInserts ) ;
  605. return TRUE ;
  606. }
  607. template< class Data,
  608. class KEYREF,
  609. Data::PFNDLIST s_Offset,
  610. BOOL fOrdered
  611. >
  612. BOOL
  613. TFDLHash< Data, KEYREF, s_Offset >::Split( ) {
  614. /*++
  615. Routine Description :
  616. This function grows the hash table so that our average bucket depth remains constant !
  617. Arguments :
  618. None.
  619. Return Value :
  620. Index to the bucket to use !
  621. --*/
  622. _ASSERT( IsValid( TRUE ) ) ;
  623. INCREMENTSTAT( SPLITS ) ;
  624. //
  625. // Check whether we need to reallocate the array of Bucket pointers.
  626. //
  627. if( m_cIncrement + m_cActiveBuckets > m_cNumAlloced ) {
  628. INCREMENTSTAT( REALLOCS ) ;
  629. DLIST* pTemp = new DLIST[m_cNumAlloced + 10 * m_cIncrement ] ;
  630. if( pTemp == 0 ) {
  631. //
  632. // bugbug ... need to handles this error better !?
  633. //
  634. return FALSE ;
  635. } else {
  636. for( int i=0; i<m_cNumAlloced; i++ ) {
  637. pTemp[i].Join( m_pBucket[i] ) ;
  638. }
  639. delete[] m_pBucket ;
  640. m_cNumAlloced += 10 * m_cIncrement ;
  641. m_pBucket = pTemp ;
  642. SETSTAT( ALLOCBUCKETS, m_cNumAlloced ) ;
  643. }
  644. }
  645. _ASSERT( IsValid( TRUE ) ) ;
  646. //
  647. // Okay grow the array by m_cIncrement.
  648. //
  649. m_cActiveBuckets += m_cIncrement ;
  650. if( m_cActiveBuckets > m_cBuckets )
  651. m_cBuckets *= 2 ;
  652. m_cInserts = m_cIncrement * m_load ;
  653. SETSTAT( ACTIVEBUCKETS, m_cActiveBuckets ) ;
  654. //
  655. // Now do some rehashing of elements.
  656. //
  657. for( int i = -m_cIncrement; i < 0; i++ ) {
  658. int iCurrent = (m_cActiveBuckets + i) - (m_cBuckets / 2) ;
  659. ITER iter = m_pBucket[iCurrent] ;
  660. while( !iter.AtEnd() ) {
  661. Data* p = iter.Current() ;
  662. int index = ComputeIndex( ReHash( p ) ) ;
  663. if( index != iCurrent ) {
  664. Data* pTemp = iter.RemoveItem() ;
  665. _ASSERT( pTemp == p ) ;
  666. m_pBucket[index].PushBack( p ) ;
  667. } else {
  668. iter.Next() ;
  669. }
  670. }
  671. _ASSERT( IsValidBucket( iCurrent ) ) ;
  672. }
  673. _ASSERT( IsValid( TRUE ) ) ;
  674. return TRUE ;
  675. }
  676. //-------------------------------------------------
  677. template< class Data,
  678. class KEYREF,
  679. Data::PFNDLIST s_Offset,
  680. BOOL fOrdered
  681. >
  682. BOOL
  683. TFDLHash< Data, KEYREF, s_Offset >::InsertDataHash(
  684. DWORD dwHash,
  685. KEYREF k,
  686. Data* pd
  687. ) {
  688. /*++
  689. Routine Description :
  690. Insert an element into the hash table.
  691. We will use member's of Data to hold the bucket chain.
  692. Arguments :
  693. dw - the hash value of the entry we are adding to the table
  694. pd - Pointer to the item we are adding to the table !
  695. Return Value :
  696. Pointer to the Data Item in its final resting place !
  697. --*/
  698. _ASSERT( IsValid( FALSE ) ) ;
  699. INCREMENTSTAT( INSERTS ) ;
  700. //
  701. // First check whether it is time to grow the hash table.
  702. //
  703. if( --m_cInserts == 0 ) {
  704. if( !Split() ) {
  705. return FALSE ;
  706. }
  707. }
  708. SETSTAT( SPLITINSERTS, m_cInserts ) ;
  709. //
  710. // Finally, insert into the Hash Table.
  711. //
  712. //DWORD index = ComputeIndex( m_pfnHash( d.GetKey() ) ) ;
  713. KEYREF keyref = (pd->*m_pGetKey)();
  714. _ASSERT( dwHash == m_pfnHash( keyref ) ) ;
  715. DWORD index = ComputeIndex( dwHash ) ;
  716. _ASSERT( index < unsigned(m_cActiveBuckets) ) ;
  717. if( !fOrdered ) {
  718. m_pBucket[index].PushFront( pd ) ;
  719. } else {
  720. //
  721. // Build the hash buckets in order !
  722. //
  723. ITER iter = m_pBucket[index] ;
  724. Data* p = 0 ;
  725. while( !iter.AtEnd() ) {
  726. p = iter.Current() ;
  727. int i = (*m_pMatchKey)( (p->*m_pGetKey)(), k ) ;
  728. _ASSERT( i != 0 ) ;
  729. if( i > 0 )
  730. break ;
  731. iter.Next() ;
  732. }
  733. //
  734. // This is no longer smaller than the current guy - so insert in front
  735. //
  736. iter.InsertBefore( pd ) ;
  737. }
  738. _ASSERT( IsValidBucket( index ) ) ;
  739. //
  740. // Update our statistics !
  741. //
  742. //MAXBUCKET( index ) ;
  743. INCREMENTSTAT( HASHITEMS ) ;
  744. //AVERAGEBUCKET() ;
  745. _ASSERT( IsValid( FALSE ) ) ;
  746. return TRUE ;
  747. }
  748. //-----------------------------------------------
  749. template< class Data,
  750. class KEYREF,
  751. Data::PFNDLIST s_Offset,
  752. BOOL fOrdered
  753. >
  754. void
  755. TFDLHash< Data, KEYREF, s_Offset >::Delete( Data* pd ) {
  756. //
  757. // Remove an element from the Hash Table. We only need the
  758. // Key to find the element we wish to remove.
  759. //
  760. _ASSERT( IsValid( FALSE ) ) ;
  761. INCREMENTSTAT( DELETES ) ;
  762. if( pd ) {
  763. DECREMENTSTAT(HASHITEMS) ;
  764. m_cInserts ++ ;
  765. DLIST::Remove( pd ) ;
  766. }
  767. SETSTAT( SPLITINSERTS, m_cInserts ) ;
  768. _ASSERT( IsValid( FALSE ) ) ;
  769. }
  770. template< class Data,
  771. class KEYREF,
  772. Data::PFNDLIST s_Offset,
  773. BOOL fOrdered
  774. >
  775. void
  776. TFDLHash< Data, KEYREF, s_Offset >::NotifyOfRemoval( ) {
  777. //
  778. // Notify us that an item has been removed from the hash table !
  779. //
  780. _ASSERT( IsValid( FALSE ) ) ;
  781. INCREMENTSTAT( DELETES ) ;
  782. DECREMENTSTAT( HASHITEMS ) ;
  783. m_cInserts ++ ;
  784. SETSTAT( SPLITINSERTS, m_cInserts ) ;
  785. _ASSERT( IsValid( FALSE ) ) ;
  786. }
  787. //-----------------------------------------------
  788. template< class Data,
  789. class KEYREF,
  790. Data::PFNDLIST s_Offset,
  791. BOOL fOrdered
  792. >
  793. void
  794. TFDLHash< Data, KEYREF, s_Offset >::DeleteData( KEYREF k,
  795. Data* pd
  796. ) {
  797. //
  798. // Remove an element from the Hash Table. We only need the
  799. // Key to find the element we wish to remove.
  800. //
  801. _ASSERT( IsValid( FALSE ) ) ;
  802. if( !pd ) {
  803. pd = SearchKey( k ) ;
  804. }
  805. if( pd ) {
  806. INCREMENTSTAT(DELETES) ;
  807. DECREMENTSTAT(HASHITEMS) ;
  808. _ASSERT( (*m_pMatchKey)( pd->GetKey(), k ) ) ;
  809. _ASSERT( SearchKey( k ) == pd ) ;
  810. m_cInserts ++ ;
  811. DLIST::Remove( pd ) ;
  812. }
  813. SETSTAT( SPLITINSERTS, m_cInserts ) ;
  814. _ASSERT( IsValid( FALSE ) ) ;
  815. }
  816. template< class Data,
  817. class KEYREF,
  818. Data::PFNDLIST s_Offset,
  819. BOOL fOrdered
  820. >
  821. DWORD
  822. TFDLHash< Data, KEYREF, s_Offset >::ComputeHash( KEYREF k ) {
  823. return m_pfnHash( k ) ;
  824. }