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.

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