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.

1019 lines
26 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Link list and Hash table
  6. File: Hashing.cpp
  7. Owner: PramodD
  8. This is the Link list and Hash table source file.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "memchk.h"
  13. /*===================================================================
  14. ::DefaultHash
  15. this is a hash algorithm that is highly recommended by Aho,
  16. Seth, and Ulman from the dragon book. (THE compiler reference)
  17. Parameters:
  18. BYTE * pbKey
  19. int cbKey
  20. Returns:
  21. Hashed DWORD value.
  22. ===================================================================*/
  23. DWORD DefaultHash(const BYTE *pbKey, int cbKey)
  24. {
  25. const unsigned WORD_BITS = CHAR_BIT * sizeof(unsigned);
  26. const unsigned SEVENTY_FIVE_PERCENT = WORD_BITS * 3 / 4;
  27. const unsigned ONE_EIGHTH = WORD_BITS / 8;
  28. const unsigned HIGH_BITS = ~(unsigned(~0) >> ONE_EIGHTH);
  29. register unsigned uT, uResult = 0;
  30. register const BYTE *pb = pbKey;
  31. while (cbKey-- > 0)
  32. {
  33. uResult = (uResult << ONE_EIGHTH) + *pb++;
  34. if ((uT = uResult & HIGH_BITS) != 0)
  35. uResult = (uResult ^ (uT >> SEVENTY_FIVE_PERCENT)) & ~HIGH_BITS;
  36. }
  37. return uResult;
  38. }
  39. /*===================================================================
  40. ::UnicodeUpcaseHash
  41. This is Aho, Seth, and Ulman's hash algorithm adapted for wide
  42. character strings. Their algorithm was not designed for cases
  43. where every other character is 0 (which is how a unicode string
  44. looks if you pretend it's ascii) Therefore, performance
  45. qualities are unknown for that case.
  46. NOTE: for real Unicode, (not unicode that is merely ANSI converted)
  47. I have no idea how good a distribution this algorithm will
  48. produce. (since we are shifting in values > 8 bits now)
  49. Parameters:
  50. BYTE * pbKey
  51. int cbKey
  52. Returns:
  53. Hashed DWORD value.
  54. ===================================================================*/
  55. #define toupper(x) WORD(CharUpper(LPSTR(WORD(x))))
  56. DWORD UnicodeUpcaseHash(const BYTE *pbKey, int cbKey)
  57. {
  58. // PERF hash on last CCH_HASH chars only
  59. const unsigned WORD_BITS = CHAR_BIT * sizeof(unsigned);
  60. const unsigned SEVENTY_FIVE_PERCENT = WORD_BITS * 3 / 4;
  61. const unsigned ONE_EIGHTH = WORD_BITS / 8;
  62. const unsigned HIGH_BITS = ~(unsigned(~0) >> ONE_EIGHTH);
  63. const unsigned CCH_HASH = 8;
  64. register unsigned uT, uResult = 0;
  65. Assert ((cbKey & 1) == 0); // cbKey better be even!
  66. int cwKey = unsigned(cbKey) >> 1;
  67. register const WORD *pw = reinterpret_cast<const WORD *>(pbKey) + cwKey;
  68. cwKey = min(cwKey, CCH_HASH);
  69. WCHAR awcTemp[CCH_HASH];
  70. // copy last cwKey WCHARs of pbKey to last cwKey WCHARs of awcTemp
  71. wcsncpy(awcTemp + CCH_HASH - cwKey, pw - cwKey, cwKey);
  72. CharUpperBuffW(awcTemp + CCH_HASH - cwKey, cwKey);
  73. pw = awcTemp + CCH_HASH;
  74. while (cwKey-- > 0)
  75. {
  76. uResult = (uResult << ONE_EIGHTH) + *--pw;
  77. if ((uT = uResult & HIGH_BITS) != 0)
  78. uResult = (uResult ^ (uT >> SEVENTY_FIVE_PERCENT)) & ~HIGH_BITS;
  79. }
  80. return uResult;
  81. }
  82. DWORD MultiByteUpcaseHash(const BYTE *pbKey, int cbKey)
  83. {
  84. // PERF hash on first CCH_HASH chars only
  85. const unsigned WORD_BITS = CHAR_BIT * sizeof(unsigned);
  86. const unsigned SEVENTY_FIVE_PERCENT = WORD_BITS * 3 / 4;
  87. const unsigned ONE_EIGHTH = WORD_BITS / 8;
  88. const unsigned HIGH_BITS = ~(unsigned(~0) >> ONE_EIGHTH);
  89. const unsigned CCH_HASH = 8;
  90. register unsigned uT, uResult = 0;
  91. unsigned char achTemp[CCH_HASH + 1];
  92. // For performance we only HASH on at most CCH_HASH characters.
  93. cbKey = min(cbKey, CCH_HASH);
  94. // Copy cbKey chacters into temporary buffer
  95. memcpy(achTemp, pbKey, cbKey);
  96. // Add terminating null character
  97. achTemp[cbKey] = 0;
  98. // Convert to upper case
  99. _mbsupr(achTemp);
  100. while (cbKey-- > 0)
  101. {
  102. uResult = (uResult << ONE_EIGHTH) + achTemp[cbKey];
  103. if ((uT = uResult & HIGH_BITS) != 0)
  104. uResult = (uResult ^ (uT >> SEVENTY_FIVE_PERCENT)) & ~HIGH_BITS;
  105. }
  106. return uResult;
  107. }
  108. /*===================================================================
  109. ::PtrHash
  110. Hash function that returns the pointer itself as the
  111. DWORD hash value
  112. Parameters:
  113. BYTE * pbKey
  114. int cbKey (not used)
  115. Returns:
  116. Hashed DWORD value.
  117. ===================================================================*/
  118. DWORD PtrHash
  119. (
  120. const BYTE *pbKey,
  121. int /* cbKey */
  122. )
  123. {
  124. return *(reinterpret_cast<DWORD *>(&pbKey));
  125. }
  126. /*===================================================================
  127. CLSIDHash
  128. CLSID hash. Uses xor of the first and last DWORD
  129. Parameters:
  130. BYTE * pbKey
  131. int cbKey
  132. Returns:
  133. Hashed DWORD value.
  134. ===================================================================*/
  135. DWORD CLSIDHash
  136. (
  137. const BYTE *pbKey,
  138. int cbKey
  139. )
  140. {
  141. Assert(cbKey == 16);
  142. DWORD *pdwKey = (DWORD *)pbKey;
  143. return (pdwKey[0] ^ pdwKey[3]);
  144. }
  145. /*===================================================================
  146. CLinkElem::CLinkElem
  147. The Constructor.
  148. Parameters:
  149. NONE
  150. Returns:
  151. NONE
  152. ===================================================================*/
  153. CLinkElem::CLinkElem(void)
  154. : m_pKey(NULL),
  155. m_cbKey(0),
  156. m_Info(0),
  157. m_pPrev(NULL),
  158. m_pNext(NULL)
  159. {
  160. }
  161. /*===================================================================
  162. HRESULT CLinkElem::Init
  163. Initializes class members
  164. Parameters:
  165. void * pKey
  166. int cbKey
  167. Returns:
  168. S_OK Success
  169. E_FAIL Error
  170. ===================================================================*/
  171. HRESULT CLinkElem::Init( void *pKey, int cbKey )
  172. {
  173. m_pPrev = NULL;
  174. m_pNext = NULL;
  175. m_Info = 0;
  176. if ( pKey == NULL || cbKey == 0 )
  177. return E_FAIL;
  178. m_pKey = static_cast<BYTE *>(pKey);
  179. m_cbKey = (short)cbKey;
  180. return S_OK;
  181. }
  182. /*===================================================================
  183. CHashTable::CHashTable
  184. Constructor for CHashTable
  185. Parameters:
  186. NONE
  187. Returns:
  188. NONE
  189. ===================================================================*/
  190. CHashTable::CHashTable( HashFunction pfnHash )
  191. : m_fInited(FALSE),
  192. m_fBucketsAllocated(FALSE),
  193. m_pHead(NULL),
  194. m_pTail(NULL),
  195. m_rgpBuckets(NULL),
  196. m_pfnHash(pfnHash),
  197. m_cBuckets(0),
  198. m_Count(0)
  199. {
  200. }
  201. /*===================================================================
  202. CHashTable::~CHashTable
  203. Destructor for CHashTable. Frees allocated bucket array.
  204. Parameters:
  205. NONE
  206. Returns:
  207. NONE
  208. ===================================================================*/
  209. CHashTable::~CHashTable( void )
  210. {
  211. if (m_fBucketsAllocated)
  212. {
  213. Assert(m_rgpBuckets);
  214. delete [] m_rgpBuckets;
  215. }
  216. }
  217. /*===================================================================
  218. HRESULT CHashTable::UnInit
  219. Frees allocated bucket array.
  220. Parameters:
  221. NONE
  222. Returns:
  223. S_OK Always
  224. ===================================================================*/
  225. HRESULT CHashTable::UnInit( void )
  226. {
  227. if (m_fBucketsAllocated)
  228. {
  229. Assert(m_rgpBuckets);
  230. delete [] m_rgpBuckets;
  231. m_fBucketsAllocated = FALSE;
  232. }
  233. m_rgpBuckets = NULL;
  234. m_pHead = NULL;
  235. m_pTail = NULL;
  236. m_cBuckets = 0;
  237. m_Count = 0;
  238. m_fInited = FALSE;
  239. return S_OK;
  240. }
  241. /*===================================================================
  242. void CHashTable::AssertValid
  243. Verify integrity of the data structure.
  244. NOTE: This function does very deep integrity checks and thus is
  245. very slow.
  246. Checks performed:
  247. verify that m_Count is valid
  248. verify that each element is in the right bucket
  249. verify prev, next links and info fields
  250. ===================================================================*/
  251. #ifdef DBG
  252. void CHashTable::AssertValid() const
  253. {
  254. CLinkElem *pElem; // pointer to current link element
  255. unsigned i; // index into current bucket
  256. unsigned cItems = 0; // actual number of items in the table
  257. Assert(m_fInited);
  258. if (m_Count == 0)
  259. {
  260. if (m_rgpBuckets)
  261. {
  262. BOOL fAllNulls = TRUE;
  263. // empty hash table - make sure that everything reflects this
  264. Assert(m_pHead == NULL);
  265. Assert (m_pTail == NULL);
  266. for (i = 0; i < m_cBuckets; i++)
  267. {
  268. if (m_rgpBuckets[i] != NULL)
  269. {
  270. fAllNulls = FALSE;
  271. break;
  272. }
  273. }
  274. Assert(fAllNulls);
  275. }
  276. return;
  277. }
  278. // If m_Count > 0
  279. Assert(m_pHead);
  280. Assert(m_pHead->m_pPrev == NULL);
  281. Assert(m_pTail != NULL && m_pTail->m_pNext == NULL);
  282. Assert(m_rgpBuckets);
  283. // Now verify each entry
  284. for (i = 0; i < m_cBuckets; ++i)
  285. {
  286. pElem = m_rgpBuckets[i];
  287. while (pElem != NULL)
  288. {
  289. // Verify hashing
  290. Assert ((m_pfnHash(pElem->m_pKey, pElem->m_cbKey) % m_cBuckets) == i);
  291. // Verify links
  292. if (pElem->m_pPrev)
  293. {
  294. Assert (pElem->m_pPrev->m_pNext == pElem);
  295. }
  296. else
  297. {
  298. Assert (m_pHead == pElem);
  299. }
  300. if (pElem->m_pNext)
  301. {
  302. Assert (pElem->m_pNext->m_pPrev == pElem);
  303. }
  304. else
  305. {
  306. Assert (m_pTail == pElem);
  307. }
  308. // Verify info fields
  309. Assert (pElem->m_Info >= 0);
  310. if (pElem != m_rgpBuckets[i])
  311. {
  312. Assert (pElem->m_Info == pElem->m_pPrev->m_Info - 1);
  313. }
  314. // Prepare for next iteration, stopping when m_Info is zero.
  315. ++cItems;
  316. if (pElem->m_Info == 0)
  317. break;
  318. pElem = pElem->m_pNext;
  319. }
  320. }
  321. // Verify count
  322. Assert (m_Count == cItems);
  323. }
  324. #endif
  325. /*===================================================================
  326. HRESULT CHashTable::Init
  327. Initialize CHashTable by allocating the bucket array and
  328. and initializing the bucket link lists.
  329. Parameters:
  330. UINT cBuckets Number of buckets
  331. Returns:
  332. HRESULT S_OK
  333. E_OUTOFMEMORY
  334. ===================================================================*/
  335. HRESULT CHashTable::Init( UINT cBuckets )
  336. {
  337. m_cBuckets = cBuckets;
  338. m_Count = 0;
  339. m_rgpBuckets = NULL; // created on demand
  340. m_fInited = TRUE;
  341. return S_OK;
  342. }
  343. /*===================================================================
  344. HRESULT CHashTable::ReInit
  345. Reinitialize CHashTable by deleting everything in it. - client
  346. is responsible for making the hashtable empty first
  347. Parameters:
  348. None
  349. Returns:
  350. None
  351. ===================================================================*/
  352. void CHashTable::ReInit()
  353. {
  354. Assert( m_fInited );
  355. if (m_rgpBuckets)
  356. memset(m_rgpBuckets, 0, m_cBuckets * sizeof(CLinkElem *));
  357. m_Count = 0;
  358. m_pHead = NULL;
  359. m_pTail = NULL;
  360. }
  361. /*===================================================================
  362. HRESULT CHashTable::AllocateBuckets()
  363. Allocates hash table buckets on demand
  364. Parameters:
  365. Returns:
  366. HRESULT
  367. ===================================================================*/
  368. HRESULT CHashTable::AllocateBuckets()
  369. {
  370. Assert(m_rgpBuckets == NULL);
  371. Assert(m_fInited);
  372. Assert(m_cBuckets > 0);
  373. if (m_cBuckets <= PREALLOCATED_BUCKETS_MAX)
  374. {
  375. m_rgpBuckets = m_rgpBucketsBuffer;
  376. }
  377. else
  378. {
  379. m_rgpBuckets = new CLinkElem * [m_cBuckets];
  380. if (m_rgpBuckets == NULL)
  381. return E_OUTOFMEMORY;
  382. m_fBucketsAllocated = TRUE;
  383. }
  384. memset(m_rgpBuckets, 0, m_cBuckets * sizeof(CLinkElem *));
  385. return S_OK;
  386. }
  387. /*===================================================================
  388. BOOL CHashTable::FIsEqual
  389. compare two keys using their lengths and memcmp()
  390. Parameters:
  391. const void *pKey1 first key
  392. int cbKey1 length of the first key
  393. const void *pKey2 second key
  394. int cbKey2 length of second key
  395. Returns:
  396. Pointer to element added/found.
  397. ===================================================================*/
  398. BOOL CHashTable::FIsEqual( const void * pKey1,
  399. int cbKey1,
  400. const void * pKey2,
  401. int cbKey2 )
  402. {
  403. if (cbKey1 != cbKey2)
  404. return FALSE;
  405. return memcmp(pKey1, pKey2, cbKey1) == 0;
  406. }
  407. #pragma optimize("g", off)
  408. /*===================================================================
  409. CHashTable::AddElem
  410. Adds a CLinkElem to Hash table.
  411. User is responsible for allocating the Element to be added.
  412. Parameters:
  413. CLinkElem * pElem Object to be added
  414. BOOL fTestDups Look for duplicates if true
  415. Returns:
  416. Pointer to element added/found.
  417. ===================================================================*/
  418. CLinkElem *CHashTable::AddElem( CLinkElem *pElem, BOOL fTestDups )
  419. {
  420. if (m_rgpBuckets == NULL)
  421. {
  422. if (FAILED(AllocateBuckets()))
  423. return NULL;
  424. }
  425. if (pElem == NULL)
  426. return NULL;
  427. BOOL fNew = TRUE;
  428. DWORD iT = m_pfnHash( pElem->m_pKey, pElem->m_cbKey ) % m_cBuckets;
  429. CLinkElem * pT = m_rgpBuckets[iT];
  430. BOOL fDebugTestDups = FALSE;
  431. #ifdef DBG
  432. // In retail, if fTestDups is false, it means that
  433. // there shouldnt be any dups, so dont bother testing. Under debug, however
  434. // we want to be able to assert that there isnt a dup (since there isnt supposed to be one).
  435. fDebugTestDups = !fTestDups;
  436. #endif
  437. if (fTestDups || fDebugTestDups)
  438. {
  439. while ( pT && fNew )
  440. {
  441. if ( FIsEqual( pT->m_pKey, pT->m_cbKey, pElem->m_pKey, pElem->m_cbKey ) )
  442. fNew = FALSE;
  443. else if ( pT->m_Info > 0 )
  444. pT = pT->m_pNext;
  445. else
  446. break;
  447. }
  448. }
  449. #ifdef DBG
  450. // If there arent supposed to be any dups, then make sure this element is seen as "new"
  451. if (fDebugTestDups)
  452. Assert(fNew);
  453. #endif
  454. #ifdef DUMP_HASHING_INFO
  455. static DWORD cAdds = 0;
  456. FILE *logfile = NULL;
  457. if (cAdds++ > 1000000 && m_Count > 100)
  458. {
  459. cAdds = 0;
  460. if (logfile = fopen("C:\\Temp\\hashdump.Log", "a+"))
  461. {
  462. DWORD cZero = 0;
  463. short iMax = 0;
  464. DWORD cGte3 = 0;
  465. DWORD cGte5 = 0;
  466. DWORD cGte10 = 0;
  467. fprintf(logfile, "Hash dump: # elements = %d\n", m_Count);
  468. for (UINT iBucket = 0; iBucket < m_cBuckets; iBucket++)
  469. {
  470. if (m_rgpBuckets[iBucket] == NULL)
  471. cZero++;
  472. else
  473. {
  474. short Info = m_rgpBuckets[iBucket]->m_Info;
  475. if (Info > iMax)
  476. iMax = Info;
  477. if (Info >= 10) cGte10++;
  478. else if (Info >= 5) cGte5++;
  479. else if (Info >= 3) cGte3++;
  480. }
  481. }
  482. fprintf(logfile, "Max chain = %d, # 0 chains = %d, # >= 3 = %d, # >= 5 = %d, # >= 10 = %d\n",
  483. (DWORD)iMax, cZero, cGte3, cGte5, cGte10);
  484. fflush(logfile);
  485. fclose(logfile);
  486. }
  487. }
  488. #endif
  489. if ( fNew )
  490. {
  491. if ( pT )
  492. {
  493. // There are other elements in bucket
  494. pT = m_rgpBuckets[iT];
  495. m_rgpBuckets[iT] = pElem;
  496. pElem->m_Info = pT->m_Info + 1;
  497. pElem->m_pNext = pT;
  498. pElem->m_pPrev = pT->m_pPrev;
  499. pT->m_pPrev = pElem;
  500. if ( pElem->m_pPrev == NULL )
  501. m_pHead = pElem;
  502. else
  503. pElem->m_pPrev->m_pNext = pElem;
  504. }
  505. else
  506. {
  507. // This is the first element in the bucket
  508. m_rgpBuckets[iT] = pElem;
  509. pElem->m_pPrev = NULL;
  510. pElem->m_pNext = m_pHead;
  511. pElem->m_Info = 0;
  512. if ( m_pHead )
  513. m_pHead->m_pPrev = pElem;
  514. else
  515. m_pTail = pElem;
  516. m_pHead = pElem;
  517. }
  518. m_Count++;
  519. AssertValid();
  520. return pElem;
  521. }
  522. AssertValid();
  523. return pT;
  524. }
  525. #pragma optimize("g", on)
  526. #pragma optimize("g", off)
  527. /*===================================================================
  528. CLinkElem * CHashTable::FindElem
  529. Finds an object in the hash table based on the name.
  530. Parameters:
  531. void * pKey
  532. int cbKey
  533. Returns:
  534. Pointer to CLinkElem if found, otherwise NULL.
  535. ===================================================================*/
  536. CLinkElem * CHashTable::FindElem( const void *pKey, int cbKey )
  537. {
  538. AssertValid();
  539. if ( m_rgpBuckets == NULL || pKey == NULL )
  540. return NULL;
  541. DWORD iT = m_pfnHash( static_cast<const BYTE *>(pKey), cbKey ) % m_cBuckets;
  542. CLinkElem * pT = m_rgpBuckets[iT];
  543. CLinkElem * pRet = NULL;
  544. while ( pT && pRet == NULL )
  545. {
  546. if ( FIsEqual( pT->m_pKey, pT->m_cbKey, pKey, cbKey ) )
  547. pRet = pT;
  548. else if ( pT->m_Info > 0 )
  549. pT = pT->m_pNext;
  550. else
  551. break;
  552. }
  553. return pRet;
  554. }
  555. #pragma optimize("g", on)
  556. #pragma optimize("g", off)
  557. /*===================================================================
  558. CHashTable::DeleteElem
  559. Removes a CLinkElem from Hash table.
  560. The user should delete the freed link list element.
  561. Parameters:
  562. void * pbKey key
  563. int cbKey length of key
  564. Returns:
  565. Pointer to element removed, NULL if not found
  566. ===================================================================*/
  567. CLinkElem * CHashTable::DeleteElem( const void *pKey, int cbKey )
  568. {
  569. if ( m_rgpBuckets == NULL || pKey == NULL )
  570. return NULL;
  571. CLinkElem * pRet = NULL;
  572. DWORD iT = m_pfnHash( static_cast<const BYTE *>(pKey), cbKey ) % m_cBuckets;
  573. CLinkElem * pT = m_rgpBuckets[iT];
  574. while ( pT && pRet == NULL )// Find it !
  575. {
  576. if ( FIsEqual( pT->m_pKey, pT->m_cbKey, pKey, cbKey ) )
  577. pRet = pT;
  578. else if ( pT->m_Info > 0 )
  579. pT = pT->m_pNext;
  580. else
  581. break;
  582. }
  583. if ( pRet )
  584. {
  585. pT = m_rgpBuckets[iT];
  586. if ( pRet == pT )
  587. {
  588. // Update bucket head
  589. if ( pRet->m_Info > 0 )
  590. m_rgpBuckets[iT] = pRet->m_pNext;
  591. else
  592. m_rgpBuckets[iT] = NULL;
  593. }
  594. // Update counts in bucket link list
  595. while ( pT != pRet )
  596. {
  597. pT->m_Info--;
  598. pT = pT->m_pNext;
  599. }
  600. // Update link list
  601. if ( pT = pRet->m_pPrev )
  602. {
  603. // Not the Head of the link list
  604. if ( pT->m_pNext = pRet->m_pNext )
  605. pT->m_pNext->m_pPrev = pT;
  606. else
  607. m_pTail = pT;
  608. }
  609. else
  610. {
  611. // Head of the link list
  612. if ( m_pHead = pRet->m_pNext )
  613. m_pHead->m_pPrev = NULL;
  614. else
  615. m_pTail = NULL;
  616. }
  617. m_Count--;
  618. }
  619. AssertValid();
  620. return pRet;
  621. }
  622. #pragma optimize("g", on)
  623. /*===================================================================
  624. CHashTable::RemoveElem
  625. Removes a given CLinkElem from Hash table.
  626. The user should delete the freed link list element.
  627. Parameters:
  628. CLinkElem * pLE Element to remove
  629. Returns:
  630. Pointer to element removed
  631. ===================================================================*/
  632. CLinkElem * CHashTable::RemoveElem( CLinkElem *pLE )
  633. {
  634. CLinkElem *pLET;
  635. if ( m_rgpBuckets == NULL || pLE == NULL )
  636. return NULL;
  637. // Remove this item from the linked list
  638. pLET = pLE->m_pPrev;
  639. if (pLET)
  640. pLET->m_pNext = pLE->m_pNext;
  641. pLET = pLE->m_pNext;
  642. if (pLET)
  643. pLET->m_pPrev = pLE->m_pPrev;
  644. if (m_pHead == pLE)
  645. m_pHead = pLE->m_pNext;
  646. if (m_pTail == pLE)
  647. m_pTail = pLE->m_pPrev;
  648. /*
  649. * If this was the first item in a bucket, then fix up the bucket.
  650. * Otherwise, decrement the count of items in the bucket for each item
  651. * in the bucket prior to this item
  652. */
  653. if (pLE->m_pPrev == NULL || pLE->m_pPrev->m_Info == 0)
  654. {
  655. UINT iBucket;
  656. // This item is head of a bucket. Need to find out which bucket!
  657. for (iBucket = 0; iBucket < m_cBuckets; iBucket++)
  658. if (m_rgpBuckets[iBucket] == pLE)
  659. break;
  660. Assert(iBucket < m_cBuckets && m_rgpBuckets[iBucket] == pLE);
  661. if (pLE->m_Info == 0)
  662. m_rgpBuckets[iBucket] = NULL;
  663. else
  664. m_rgpBuckets[iBucket] = pLE->m_pNext;
  665. }
  666. else
  667. {
  668. // This item is in the middle of a bucket chain. Update counts in preceeding items
  669. pLET = pLE->m_pPrev;
  670. while (pLET != NULL && pLET->m_Info != 0)
  671. {
  672. pLET->m_Info--;
  673. pLET = pLET->m_pPrev;
  674. }
  675. }
  676. // Decrement count of total number of items
  677. m_Count--;
  678. AssertValid();
  679. return pLE;
  680. }
  681. /*===================================================================
  682. CHashTableStr::CHashTableStr
  683. Constructor for CHashTableStr
  684. Parameters:
  685. NONE
  686. Returns:
  687. NONE
  688. ===================================================================*/
  689. CHashTableStr::CHashTableStr( HashFunction pfnHash )
  690. : CHashTable( pfnHash )
  691. {
  692. }
  693. /*===================================================================
  694. BOOL CHashTableStr::FIsEqual
  695. compare two keys using their lengths, treating the keys
  696. as Unicode and doing case insensitive compare.
  697. Parameters:
  698. const void *pKey1 first key
  699. int cbKey1 length of the first key
  700. const void *pKey2 second key
  701. int cbKey2 length of second key
  702. Returns:
  703. Pointer to element added/found.
  704. ===================================================================*/
  705. BOOL CHashTableStr::FIsEqual( const void * pKey1,
  706. int cbKey1,
  707. const void * pKey2,
  708. int cbKey2 )
  709. {
  710. if ( cbKey1 != cbKey2 )
  711. return FALSE;
  712. return _wcsnicmp(static_cast<const wchar_t *>(pKey1), static_cast<const wchar_t *>(pKey2), cbKey1) == 0;
  713. }
  714. /*===================================================================
  715. CHashTableMBStr::CHashTableMBStr
  716. Constructor for CHashTableMBStr
  717. Parameters:
  718. NONE
  719. Returns:
  720. NONE
  721. ===================================================================*/
  722. CHashTableMBStr::CHashTableMBStr( HashFunction pfnHash )
  723. : CHashTable( pfnHash )
  724. {
  725. }
  726. /*===================================================================
  727. BOOL CHashTableMBStr::FIsEqual
  728. compare two keys using their lengths, treating the keys
  729. as multi-byte strings and doing case insensitive compare.
  730. Parameters:
  731. const void *pKey1 first key
  732. int cbKey1 length of the first key
  733. const void *pKey2 second key
  734. int cbKey2 length of second key
  735. Returns:
  736. Pointer to element added/found.
  737. ===================================================================*/
  738. BOOL CHashTableMBStr::FIsEqual( const void * pKey1,
  739. int cbKey1,
  740. const void * pKey2,
  741. int cbKey2 )
  742. {
  743. if ( cbKey1 != cbKey2 )
  744. return FALSE;
  745. return _mbsnicmp(static_cast<const unsigned char *>(pKey1), static_cast<const unsigned char *>(pKey2), cbKey1) == 0;
  746. }
  747. /*===================================================================
  748. CHashTablePtr::CHashTablePtr
  749. Constructor for CHashTableStr
  750. Parameters:
  751. HashFunction pfnHash has function (PtrHash is default)
  752. Returns:
  753. NONE
  754. ===================================================================*/
  755. CHashTablePtr::CHashTablePtr
  756. (
  757. HashFunction pfnHash
  758. )
  759. : CHashTable(pfnHash)
  760. {
  761. }
  762. /*===================================================================
  763. BOOL CHashTablePtr::FIsEqual
  764. Compare two pointers.
  765. Used by CHashTable to find elements
  766. Parameters:
  767. const void *pKey1 first key
  768. int cbKey1 length of the first key (unused)
  769. const void *pKey2 second key
  770. int cbKey2 length of second key (unused)
  771. Returns:
  772. BOOL (true when equal)
  773. ===================================================================*/
  774. BOOL CHashTablePtr::FIsEqual
  775. (
  776. const void *pKey1,
  777. int /* cbKey1 */,
  778. const void *pKey2,
  779. int /* cbKey2 */
  780. )
  781. {
  782. return (pKey1 == pKey2);
  783. }
  784. /*===================================================================
  785. CHashTableCLSID::CHashTableCLSID
  786. Constructor for CHashTableCLSID
  787. Parameters:
  788. HashFunction pfnHash has function (CLSIDHash is default)
  789. Returns:
  790. NONE
  791. ===================================================================*/
  792. CHashTableCLSID::CHashTableCLSID
  793. (
  794. HashFunction pfnHash
  795. )
  796. : CHashTable(pfnHash)
  797. {
  798. }
  799. /*===================================================================
  800. BOOL CHashTableCLSID::FIsEqual
  801. Compare two CLSIDs.
  802. Parameters:
  803. const void *pKey1 first key
  804. int cbKey1 length of the first key
  805. const void *pKey2 second key
  806. int cbKey2 length of second key
  807. Returns:
  808. BOOL (true when equal)
  809. ===================================================================*/
  810. BOOL CHashTableCLSID::FIsEqual
  811. (
  812. const void *pKey1,
  813. int cbKey1,
  814. const void *pKey2,
  815. int cbKey2
  816. )
  817. {
  818. Assert(cbKey1 == sizeof(CLSID) && cbKey2 == sizeof(CLSID));
  819. return IsEqualCLSID(*((CLSID *)pKey1), *((CLSID *)pKey2));
  820. }