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.

1625 lines
56 KiB

  1. #if !defined(_FUSION_INC_FUSIONHASH_H_INCLUDED_)
  2. #define _FUSION_INC_FUSIONHASH_H_INCLUDED_
  3. #pragma once
  4. #include "fusionheap.h"
  5. #include "fusionbuffer.h"
  6. #include "fusionchartraits.h"
  7. #include "fusiondeque.h"
  8. #define T2P(x, y) < x , y >
  9. #pragma warning(disable:4327) // indirection alignment of LHS (16) is greater than RHS (8)
  10. #pragma warning(disable:4328) // indirection alignment of formal parameter 2 (16) is greater than the actual argument alignment (8)
  11. enum InsertOrUpdateIfDisposition
  12. {
  13. eUpdateValue,
  14. eLeaveValueAlone,
  15. };
  16. template <typename TPassed, class TStored> inline BOOL HashTableCompareKey(TPassed tpassed, const TStored &rtstored, bool &rfMatch)
  17. {
  18. return rtstored.Compare(tpassed, rfMatch);
  19. }
  20. template<> inline BOOL HashTableCompareKey<REFGUID, GUID>(REFGUID rguid, const GUID &rguidstored, bool &rfMatch)
  21. {
  22. rfMatch = ((rguid == rguidstored) != 0);
  23. return TRUE;
  24. }
  25. template <typename TPassed> inline BOOL HashTableHashKey(TPassed tpassed, ULONG &rulPseudoKey);
  26. // common override for GUID-indexed tables
  27. template<> inline BOOL HashTableHashKey<REFGUID>(REFGUID rguid, ULONG &rulPseudoKey)
  28. {
  29. rulPseudoKey = rguid.Data1;
  30. return TRUE;
  31. }
  32. template <typename TPassed, class TStored> inline BOOL HashTableInitializeKey(TPassed tpassed, TStored &rtstored)
  33. {
  34. return rtstored.Initialize(tpassed);
  35. }
  36. // common override for GUID-indexed tables
  37. template<> inline BOOL HashTableInitializeKey<REFGUID, GUID>(REFGUID rguidIn, GUID &rguidOut)
  38. {
  39. rguidOut = rguidIn;
  40. return TRUE;
  41. }
  42. template <typename TPassed, class TStored> inline BOOL HashTableInitializeValue(TPassed tpassed, TStored &rtstored)
  43. {
  44. return rtstored.Initialize(tpassed);
  45. }
  46. template <typename TPassed, class TStored> inline BOOL HashTableUpdateValue(TPassed tpassed, TStored &rtstored)
  47. {
  48. return rtstored.Assign(tpassed);
  49. }
  50. template <typename TStored> inline VOID HashTablePreInitializeKey(TStored &rtstored) { }
  51. template <typename TStored> inline VOID HashTablePreInitializeValue(TStored &rtstored) { }
  52. template <typename TStored> inline VOID HashTableFinalizeKey(TStored &rtstored) { }
  53. template <typename TStored> inline VOID HashTableFinalizeValue(TStored &rtstored) { }
  54. template <typename TCharTraits>
  55. class CCountedStringHolder
  56. {
  57. public:
  58. CCountedStringHolder() : m_psz(NULL), m_cch(0) { }
  59. CCountedStringHolder(TCharTraits::TConstantString sz) : m_psz(sz), m_cch(TCharTraits::Cch(sz)) { }
  60. CCountedStringHolder(const CGenericBaseStringBuffer<TCharTraits> &rBuffer) : m_psz(rBuffer), m_cch(TCharTraits::Cch(rBuffer)) { }
  61. ~CCountedStringHolder() { }
  62. TCharTraits::TConstantString m_psz;
  63. SIZE_T m_cch;
  64. };
  65. //
  66. // You want to create a class derived from CHashTableHelper, and
  67. // use it as THashHelper for CHashTable.
  68. //
  69. template <typename TKPassed, class TKStored, typename TVPassed, typename TVStored> class CHashTableHelper
  70. {
  71. public:
  72. static BOOL HashKey(TKPassed keyin, ULONG &rulPseudoKey) { return ::HashTableHashKey<TKPassed>(keyin, rulPseudoKey); }
  73. static BOOL CompareKey(TKPassed keyin, const TKStored &rtkeystored, bool &rfMatch) { return ::HashTableCompareKey<TKPassed, TKStored>(keyin, rtkeystored, rfMatch); }
  74. static VOID PreInitializeKey(TKStored &rtkeystored) { return ::HashTablePreInitializeKey<TKStored>(rtkeystored); }
  75. static VOID PreInitializeValue(TVStored &rtvaluestored) { return ::HashTablePreInitializeValue<TVStored>(rtvaluestored); }
  76. static BOOL InitializeKey(TKPassed keyin, TKStored &rtkeystored) { return ::HashTableInitializeKey<TKPassed>(keyin, rtkeystored); }
  77. static BOOL InitializeValue(TVPassed vin, TVStored &rvstored) { return ::HashTableInitializeValue<TVPassed, TVStored>(vin, rvstored); }
  78. static BOOL UpdateValue(TVPassed vin, TVStored &rvstored) { return ::HashTableUpdateValue<TVPassed, TVStored>(vin, rvstored); }
  79. static VOID FinalizeKey(TKStored &rtkeystored) { return ::HashTableFinalizeKey<TKStored>(rtkeystored); }
  80. static VOID FinalizeValue(TVStored &rtvstored) { return ::HashTableFinalizeValue<TVStored>(rtvstored); }
  81. };
  82. template <typename TKPassed, typename TKStored, typename TVPassed, typename TVStored, class THashHelper = CHashTableHelper<TKPassed, TKStored, TVPassed, TVStored>, ULONG nInlineBucketChains = 7, bool fAllowDups = false> class CHashTableIter;
  83. template <typename TKPassed, typename TKStored, typename TVPassed, typename TVStored, class THashHelper = CHashTableHelper<TKPassed, TKStored, TVPassed, TVStored>, ULONG nInlineBucketChains = 7, bool fAllowDups = false> class CHashTable
  84. {
  85. friend CHashTableIter<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups>;
  86. typedef CHashTable<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups> TThisHashTable;
  87. public:
  88. CHashTable() :
  89. m_cBucketChains(nInlineBucketChains),
  90. m_prgBucketChains(m_rgInlineBucketChains),
  91. m_ulLockCount(0),
  92. m_cEntries(0)
  93. {
  94. }
  95. ~CHashTable()
  96. {
  97. // This denotes a programming error.
  98. ASSERT_NTC(m_ulLockCount == 0);
  99. ULONG i;
  100. SIZE_T cFound = 0;
  101. for (i=0; i<m_cBucketChains; i++)
  102. {
  103. SIZE_T cThisBucket = 0;
  104. m_prgBucketChains[i].ClearNoCallback(this, cThisBucket);
  105. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "Destroying hash table %p; found %Id buckets at index %d\n", this, cThisBucket, i);
  106. cFound += cThisBucket;
  107. }
  108. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "After loop, destroying hash table %p; found total of %Id buckets; m_cEntries == %Id\n", this, cFound, m_cEntries);
  109. ASSERT_NTC(cFound == m_cEntries);
  110. if ((m_prgBucketChains != m_rgInlineBucketChains) &&
  111. (m_prgBucketChains != NULL))
  112. {
  113. ASSERT_NTC(m_cBucketChains != 0);
  114. FUSION_DELETE_ARRAY(m_prgBucketChains);
  115. m_cBucketChains = 0;
  116. m_prgBucketChains = NULL;
  117. }
  118. else
  119. {
  120. // Better safe than sorry
  121. ASSERT_NTC((m_prgBucketChains == m_rgInlineBucketChains) || (m_cBucketChains == 0));
  122. m_cBucketChains = 0;
  123. }
  124. m_prgBucketChains = NULL;
  125. }
  126. BOOL Initialize(ULONG cBucketChains = nInlineBucketChains)
  127. {
  128. BOOL fSuccess = FALSE;
  129. FN_TRACE_WIN32(fSuccess);
  130. PARAMETER_CHECK(cBucketChains != 0);
  131. // If you hit this assertion, it either means that you're calling Initialize
  132. // twice on the same hash table, the hash table has been corrupted since it was
  133. // constructed, or someone messed up the constructor.
  134. INTERNAL_ERROR_CHECK(m_prgBucketChains == m_rgInlineBucketChains);
  135. // Since we already have nInlineBucketChains allocated, there's no point
  136. // in going lower. However, do perform the dynamic allocation if necessary.
  137. if (cBucketChains > nInlineBucketChains)
  138. {
  139. IFALLOCFAILED_EXIT(m_prgBucketChains = FUSION_NEW_ARRAY(CBucketChain, cBucketChains));
  140. m_cBucketChains = cBucketChains;
  141. }
  142. fSuccess = TRUE;
  143. Exit:
  144. return fSuccess;
  145. }
  146. void Lock(bool fAllowInsertions)
  147. {
  148. FN_TRACE();
  149. if (m_ulLockCount++ == 0)
  150. {
  151. m_fInsertionsPermitted = fAllowInsertions;
  152. m_fRemovalsPermitted = false;
  153. }
  154. }
  155. void Unlock()
  156. {
  157. FN_TRACE();
  158. m_ulLockCount--;
  159. }
  160. BOOL Insert(TKPassed keyin, TVPassed valuein, DWORD DuplicateKeyErrorCode)
  161. {
  162. BOOL fSuccess = FALSE;
  163. FN_TRACE_WIN32(fSuccess);
  164. ULONG ulPseudoKey = 0;
  165. ULONG iBucket = 0;
  166. PARAMETER_CHECK(DuplicateKeyErrorCode != ERROR_SUCCESS);
  167. INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fInsertionsPermitted));
  168. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  169. iBucket = ulPseudoKey % m_cBucketChains;
  170. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Insert(this, keyin, valuein, ulPseudoKey, DuplicateKeyErrorCode));
  171. fSuccess = TRUE;
  172. Exit:
  173. return fSuccess;
  174. }
  175. BOOL Insert(TKPassed keyin, TVPassed valuein)
  176. {
  177. return this->Insert(keyin, valuein, ERROR_ALREADY_EXISTS);
  178. }
  179. BOOL FindOrInsertIfNotPresent(TKPassed keyin, TVPassed valuein, TVStored **ppvaluestored = NULL, BOOL *pfFound = NULL)
  180. {
  181. BOOL fSuccess = FALSE;
  182. FN_TRACE_WIN32(fSuccess);
  183. ULONG ulPseudoKey = 0;
  184. ULONG iBucket = 0;
  185. if (ppvaluestored != NULL)
  186. *ppvaluestored = NULL;
  187. if (pfFound != NULL)
  188. *pfFound = FALSE;
  189. INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fInsertionsPermitted));
  190. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  191. iBucket = ulPseudoKey % m_cBucketChains;
  192. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].FindOrInsertIfNotPresent(this, keyin, valuein, ulPseudoKey, ppvaluestored, pfFound));
  193. fSuccess = TRUE;
  194. Exit:
  195. return fSuccess;
  196. }
  197. // U is always as indicated, but the compiler would rather
  198. // deduce that seperately than deduce types dependent on each other
  199. template <typename T>
  200. BOOL InsertOrUpdateIf(
  201. TKPassed keyin,
  202. TVPassed valuein,
  203. T *pt,
  204. BOOL (T::*pmfn)(
  205. TVPassed,
  206. const TVStored &,
  207. InsertOrUpdateIfDisposition &)
  208. )
  209. {
  210. BOOL fSuccess = FALSE;
  211. FN_TRACE_WIN32(fSuccess);
  212. ULONG ulPseudoKey = 0;
  213. ULONG iBucket = 0;
  214. INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fInsertionsPermitted));
  215. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  216. iBucket = ulPseudoKey % m_cBucketChains;
  217. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].InsertOrUpdateIf T2P(TThisHashTable, T)(this, keyin, valuein, ulPseudoKey, pt, pmfn));
  218. fSuccess = TRUE;
  219. Exit:
  220. return fSuccess;
  221. }
  222. inline VOID ClearNoCallback()
  223. {
  224. FN_TRACE();
  225. ULONG i;
  226. SIZE_T cFound = 0;
  227. for (i=0; i<m_cBucketChains; i++)
  228. {
  229. SIZE_T cThisBucket = 0;
  230. m_prgBucketChains[i].ClearNoCallback(this, cThisBucket);
  231. cFound += cThisBucket;
  232. }
  233. if (m_prgBucketChains != m_rgInlineBucketChains)
  234. {
  235. FUSION_DELETE_ARRAY(m_prgBucketChains);
  236. m_prgBucketChains = m_rgInlineBucketChains;
  237. m_cBucketChains = nInlineBucketChains;
  238. }
  239. m_cEntries = 0;
  240. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Cleared hash table %p entries to 0\n", __FILE__, __LINE__, this);
  241. }
  242. template <typename T> inline VOID Clear(T *pt = NULL, VOID (T::*pmfn)(TKStored &, TVStored &) = NULL)
  243. {
  244. FN_TRACE();
  245. ULONG i;
  246. // Either both have to be NULL or neither.
  247. ASSERT((pt == NULL) == (pmfn == NULL));
  248. if ((pt != NULL) && (pmfn != NULL))
  249. {
  250. for (i=0; i<m_cBucketChains; i++)
  251. m_prgBucketChains[i].Clear(this, pt, pmfn);
  252. }
  253. if (m_prgBucketChains != m_rgInlineBucketChains)
  254. {
  255. FUSION_DELETE_ARRAY(m_prgBucketChains);
  256. m_prgBucketChains = m_rgInlineBucketChains;
  257. m_cBucketChains = nInlineBucketChains;
  258. }
  259. m_cEntries = 0;
  260. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Cleared hash table %p entries to 0\n", __FILE__, __LINE__, this);
  261. }
  262. BOOL Remove(TKPassed keyin, bool fRemoveFirstFoundOnly = false)
  263. {
  264. BOOL fSuccess = FALSE;
  265. FN_TRACE_WIN32(fSuccess);
  266. ULONG ulPseudoKey = 0;
  267. ULONG iBucket = 0;
  268. INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fRemovalsPermitted));
  269. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  270. iBucket = ulPseudoKey % m_cBucketChains;
  271. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Remove(this, keyin, ulPseudoKey, fRemoveFirstFoundOnly));
  272. fSuccess = TRUE;
  273. Exit:
  274. return fSuccess;
  275. }
  276. BOOL Find(TKPassed keyin, TVStored const *&rpvaluestored) const
  277. {
  278. BOOL fSuccess = FALSE;
  279. FN_TRACE_WIN32(fSuccess);
  280. ULONG ulPseudoKey = 0;
  281. ULONG iBucket = 0;
  282. rpvaluestored = NULL;
  283. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  284. iBucket = ulPseudoKey % m_cBucketChains;
  285. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, rpvaluestored));
  286. fSuccess = TRUE;
  287. Exit:
  288. return fSuccess;
  289. }
  290. BOOL Find(TKPassed keyin, TVStored *&rpvaluestored)
  291. {
  292. BOOL fSuccess = FALSE;
  293. FN_TRACE_WIN32(fSuccess);
  294. ULONG ulPseudoKey = 0;
  295. ULONG iBucket = 0;
  296. rpvaluestored = NULL;
  297. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  298. iBucket = ulPseudoKey % m_cBucketChains;
  299. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, rpvaluestored));
  300. fSuccess = TRUE;
  301. Exit:
  302. return fSuccess;
  303. }
  304. BOOL Assign(CHashTable &TableToCopy) { return FALSE; }
  305. VOID TakeValue(CHashTable &That)
  306. {
  307. FN_TRACE();
  308. ULONG i;
  309. // Nothing can fail in this function, so we're theoretically safe to preemptively clean up our own storage.
  310. if (m_prgBucketChains != m_rgInlineBucketChains)
  311. {
  312. FUSION_DELETE_ARRAY(m_prgBucketChains);
  313. m_prgBucketChains = m_rgInlineBucketChains;
  314. m_cBucketChains = nInlineBucketChains;
  315. }
  316. // Just steal any storage from the other table.
  317. if (That.m_prgBucketChains != That.m_rgInlineBucketChains)
  318. {
  319. // It's a dynamically allocated array in the source; just move the pointer over
  320. // and clean up its state to be somewhat consistent.
  321. m_prgBucketChains = That.m_prgBucketChains;
  322. m_cBucketChains = That.m_cBucketChains;
  323. That.m_prgBucketChains = That.m_rgInlineBucketChains;
  324. That.m_cBucketChains = nInlineBucketChains;
  325. }
  326. else
  327. {
  328. // The inline chain of the other table is being used; we have to copy the
  329. // chains over one by one.
  330. for (i=0; i<nInlineBucketChains; i++)
  331. m_rgInlineBucketChains[i].TakeValue(this, That.m_rgInlineBucketChains[i]);
  332. }
  333. m_cEntries = That.m_cEntries;
  334. That.m_cEntries = 0;
  335. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Hash table %p took over hash table %p's %Id entries\n", __FILE__, __LINE__, this, &That, m_cEntries);
  336. }
  337. SIZE_T GetEntryCount() const { return m_cEntries; }
  338. //protected:
  339. class CBucketChain;
  340. class CBucket
  341. {
  342. public:
  343. CBucket(ULONG ulPseudoKey) : m_ulPseudoKey(ulPseudoKey) { THashHelper::PreInitializeKey(m_tkey); THashHelper::PreInitializeValue(m_tvalue); }
  344. ~CBucket() { THashHelper::FinalizeKey(m_tkey); THashHelper::FinalizeValue(m_tvalue); }
  345. BOOL Initialize(CHashTable const * pTable, TKPassed keyin, TVPassed valuein)
  346. {
  347. BOOL fSuccess = FALSE;
  348. FN_TRACE_WIN32(fSuccess);
  349. IFW32FALSE_EXIT(THashHelper::InitializeKey(keyin, m_tkey));
  350. IFW32FALSE_EXIT(THashHelper::InitializeValue(valuein, m_tvalue));
  351. fSuccess = TRUE;
  352. Exit:
  353. return fSuccess;
  354. }
  355. BOOL Matches(TKPassed keyin, ULONG ulPseudoKey, bool &rfMatches) const
  356. {
  357. BOOL fSuccess = FALSE;
  358. FN_TRACE_WIN32(fSuccess);
  359. bool fMatches = false;
  360. if (m_ulPseudoKey == ulPseudoKey)
  361. IFW32FALSE_EXIT(THashHelper::CompareKey(keyin, m_tkey, fMatches));
  362. rfMatches = fMatches;
  363. fSuccess = TRUE;
  364. Exit:
  365. return fSuccess;
  366. }
  367. template <typename T> VOID Clear(TThisHashTable const * pTable, T *pt, VOID (T::*pmfn)(TKStored &keystored, TVStored &rvaluestored))
  368. {
  369. FN_TRACE();
  370. (pt->*pmfn)(m_tkey, m_tvalue);
  371. }
  372. template <typename T> VOID Clear(TThisHashTable const * pTable, T *pt, VOID (T::*pmfn)(TKStored &keystored, TVStored &rvaluestored) const)
  373. {
  374. FN_TRACE();
  375. (pt->*pmfn)(m_tkey, m_tvalue);
  376. }
  377. VOID Remove()
  378. {
  379. FN_TRACE();
  380. m_Linkage.Remove();
  381. }
  382. BOOL Update(TVPassed valuein)
  383. {
  384. BOOL fSuccess = FALSE;
  385. FN_TRACE_WIN32(fSuccess);
  386. IFW32FALSE_EXIT(THashHelper::UpdateValue(m_tvalue, valuein));
  387. fSuccess = TRUE;
  388. Exit:
  389. return fSuccess;
  390. }
  391. TKStored m_tkey;
  392. TVStored m_tvalue;
  393. ULONG m_ulPseudoKey;
  394. CDequeLinkage m_Linkage;
  395. private:
  396. CBucket(const CBucket &);
  397. void operator =(const CBucket &);
  398. };
  399. typedef CDequeIterator<CBucket, FIELD_OFFSET(CBucket, m_Linkage)> CBucketIterator;
  400. typedef CConstDequeIterator<CBucket, FIELD_OFFSET(CBucket, m_Linkage)> CConstBucketIterator;
  401. class CBucketChain
  402. {
  403. public:
  404. CBucketChain() { }
  405. ~CBucketChain() { }
  406. inline void DeallocateBuckets(CHashTable const *pTable, SIZE_T &rcFound)
  407. {
  408. rcFound = m_Buckets.GetEntryCount();
  409. m_Buckets.Clear(pTable, &CHashTable::DeallocateBucket);
  410. }
  411. BOOL Insert(
  412. CHashTable *pTable,
  413. TKPassed keyin,
  414. TVPassed valuein,
  415. ULONG ulPseudoKey,
  416. DWORD DuplicateKeyErrorCode)
  417. {
  418. BOOL fSuccess = FALSE;
  419. FN_TRACE_WIN32(fSuccess);
  420. bool fMatches = false;
  421. CBucket *pCBucket = NULL;
  422. if (!fAllowDups)
  423. {
  424. CBucketIterator Iter(&m_Buckets);
  425. for (Iter.Reset(); Iter.More(); Iter.Next())
  426. {
  427. IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
  428. if (fMatches)
  429. ORIGINATE_WIN32_FAILURE_AND_EXIT(DuplicateKey, DuplicateKeyErrorCode);
  430. }
  431. }
  432. IFW32FALSE_EXIT(pTable->AllocateAndInitializeBucket(ulPseudoKey, keyin, valuein, pCBucket));
  433. m_Buckets.AddToTail(pCBucket);
  434. pTable->m_cEntries++;
  435. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Incremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
  436. fSuccess = TRUE;
  437. Exit:
  438. return fSuccess;
  439. }
  440. BOOL FindOrInsertIfNotPresent(
  441. CHashTable *pTable,
  442. TKPassed keyin,
  443. TVPassed valuein,
  444. ULONG ulPseudoKey,
  445. TVStored **ppvaluestored,
  446. BOOL *pfFound
  447. )
  448. {
  449. BOOL fSuccess = FALSE;
  450. FN_TRACE_WIN32(fSuccess);
  451. bool fMatches = false;
  452. CBucketIterator Iter(&m_Buckets);
  453. for (Iter.Reset(); Iter.More(); Iter.Next())
  454. {
  455. IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
  456. if (fMatches)
  457. {
  458. *ppvaluestored = &Iter->m_tvalue;
  459. break;
  460. }
  461. }
  462. if (!fMatches)
  463. {
  464. CBucket *pCBucket = NULL;
  465. IFW32FALSE_EXIT(pTable->AllocateAndInitializeBucket(ulPseudoKey, keyin, valuein, pCBucket));
  466. m_Buckets.AddToTail(pCBucket);
  467. pTable->m_cEntries++;
  468. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Incremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
  469. if (ppvaluestored != NULL)
  470. *ppvaluestored = &pCBucket->m_tvalue;
  471. }
  472. if (pfFound != NULL)
  473. *pfFound = fMatches;
  474. fSuccess = TRUE;
  475. Exit:
  476. return fSuccess;
  477. }
  478. template <typename THashTable, typename T>
  479. BOOL InsertOrUpdateIf(
  480. THashTable *pTable,
  481. TKPassed keyin,
  482. TVPassed valuein,
  483. ULONG ulPseudoKey,
  484. T *pt,
  485. BOOL (T::*pmfn)(
  486. TVPassed,
  487. const TVStored &,
  488. InsertOrUpdateIfDisposition &)
  489. )
  490. {
  491. BOOL fSuccess = FALSE;
  492. FN_TRACE_WIN32(fSuccess);
  493. bool fMatches = false;
  494. CBucketIterator Iter(&m_Buckets);
  495. for (Iter.Reset(); Iter.More(); Iter.Next())
  496. {
  497. IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
  498. if (fMatches)
  499. {
  500. InsertOrUpdateIfDisposition Disposition;
  501. IFW32FALSE_EXIT((pt->*pmfn)(valuein, Iter->m_tvalue, Disposition));
  502. if (Disposition == eUpdateValue)
  503. {
  504. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Updating value in hash table %p\n", __FILE__, __LINE__, pTable);
  505. IFW32FALSE_EXIT(THashHelper::UpdateValue(valuein, Iter->m_tvalue));
  506. }
  507. break;
  508. }
  509. }
  510. // If we didn't find one, we want to insert.
  511. if (!fMatches)
  512. {
  513. CBucket *pCBucket = NULL;
  514. IFW32FALSE_EXIT(pTable->AllocateAndInitializeBucket(ulPseudoKey, keyin, valuein, pCBucket));
  515. m_Buckets.AddToTail(pCBucket);
  516. pTable->m_cEntries++;
  517. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Incremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
  518. }
  519. fSuccess = TRUE;
  520. Exit:
  521. return fSuccess;
  522. }
  523. inline VOID ClearNoCallback(TThisHashTable const *pTable, SIZE_T &rcFound)
  524. {
  525. FN_TRACE();
  526. this->DeallocateBuckets(pTable, rcFound);
  527. }
  528. template <typename T> class CLEAR_CALLBACK_BLOCK
  529. {
  530. public:
  531. VOID DoClear(CBucket *pCBucket) { pCBucket->Clear(pTable, pt, pmfn); pTable->DeallocateBucket(pCBucket); }
  532. TThisHashTable const *pTable;
  533. T *pt;
  534. VOID (T::*pmfn)(TKStored &, TVStored &);
  535. };
  536. template <typename T> VOID Clear(TThisHashTable const *pTable, T *pt, VOID (T::*pmfn)(TKStored &keystored, TVStored &valuestored))
  537. {
  538. FN_TRACE();
  539. SIZE_T cFound = 0;
  540. ASSERT((pt != NULL) && (pmfn != NULL));
  541. CLEAR_CALLBACK_BLOCK<T> CallbackBlock;
  542. CallbackBlock.pTable = pTable;
  543. CallbackBlock.pt = pt;
  544. CallbackBlock.pmfn = pmfn;
  545. m_Buckets.Clear<CLEAR_CALLBACK_BLOCK<T> >(&CallbackBlock, &CLEAR_CALLBACK_BLOCK<T>::DoClear);
  546. this->DeallocateBuckets(pTable, cFound);
  547. }
  548. // BOOL Remove(CHashTable const *pTable, TKPassed keyin, ULONG ulPseudoKey, bool fFirstOnly = false)
  549. BOOL Remove(CHashTable *pTable, TKPassed keyin, ULONG ulPseudoKey, bool fFirstOnly = false)
  550. {
  551. BOOL fSuccess = FALSE;
  552. FN_TRACE_WIN32(fSuccess);
  553. bool fFoundOne = false;
  554. bool fMatches = false;
  555. CBucketIterator Iter(&m_Buckets);
  556. Iter.Reset();
  557. while (Iter.More())
  558. {
  559. IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
  560. if (fMatches)
  561. {
  562. CBucket *pCBucket = Iter.RemoveCurrent(eDequeIteratorMoveForward);
  563. pTable->DeallocateBucket(pCBucket);
  564. fFoundOne = true;
  565. pTable->m_cEntries--;
  566. FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Decremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
  567. // If we don't allow duplicates, our job is done and there's no point
  568. // in searching the remainder of the list. Also, if we're only interested
  569. // in removing the first match we find (and not necessarily all of them),
  570. // then also bail out.
  571. if ((!fAllowDups) || (fFirstOnly))
  572. break;
  573. }
  574. else
  575. Iter.Next();
  576. }
  577. // If we didn't at least find one, then tell the caller.
  578. if (!fFoundOne)
  579. ORIGINATE_WIN32_FAILURE_AND_EXIT(HashTableEntryNotFound, ERROR_FILE_NOT_FOUND);
  580. fSuccess = TRUE;
  581. Exit:
  582. return fSuccess;
  583. }
  584. BOOL Find(TKPassed keyin, ULONG ulPseudoKey, TVStored const *&rpvaluestored) const
  585. {
  586. BOOL fSuccess = FALSE;
  587. FN_TRACE_WIN32(fSuccess);
  588. bool fMatches = false;
  589. CConstBucketIterator Iter(&m_Buckets);
  590. rpvaluestored = NULL;
  591. for (Iter.Reset(); Iter.More(); Iter.Next())
  592. {
  593. IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
  594. if (fMatches)
  595. {
  596. rpvaluestored = &Iter->m_tvalue;
  597. break;
  598. }
  599. }
  600. fSuccess = TRUE;
  601. Exit:
  602. return fSuccess;
  603. }
  604. BOOL Find(TKPassed keyin, ULONG ulPseudoKey, TVStored *&rpvaluestored)
  605. {
  606. BOOL fSuccess = FALSE;
  607. FN_TRACE_WIN32(fSuccess);
  608. bool fMatches = false;
  609. CBucketIterator Iter(&m_Buckets);
  610. rpvaluestored = NULL;
  611. for (Iter.Reset(); Iter.More(); Iter.Next())
  612. {
  613. IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
  614. if (fMatches)
  615. {
  616. rpvaluestored = &Iter->m_tvalue;
  617. break;
  618. }
  619. }
  620. fSuccess = TRUE;
  621. Exit:
  622. return fSuccess;
  623. }
  624. VOID TakeValue(CHashTable *pTable, CBucketChain &That)
  625. {
  626. SIZE_T cFound = 0;
  627. this->DeallocateBuckets(pTable, cFound);
  628. m_Buckets.TakeValue(That.m_Buckets);
  629. }
  630. CDeque<CBucket, FIELD_OFFSET(CBucket, m_Linkage)> m_Buckets;
  631. private:
  632. CBucketChain(const CBucketChain &);
  633. void operator =(const CBucketChain &);
  634. };
  635. inline BOOL AllocateAndInitializeBucket(
  636. ULONG ulPseudoKey,
  637. TKPassed keyin,
  638. TVPassed valuein,
  639. CBucket *&rpBucket
  640. ) const
  641. {
  642. BOOL fSuccess = FALSE;
  643. FN_TRACE_WIN32(fSuccess);
  644. rpBucket = NULL;
  645. CBucket *pBucket = NULL;
  646. IFALLOCFAILED_EXIT(pBucket = new CBucket(ulPseudoKey));
  647. IFW32FALSE_EXIT(pBucket->Initialize(this, keyin, valuein));
  648. rpBucket = pBucket;
  649. pBucket = NULL;
  650. fSuccess = TRUE;
  651. Exit:
  652. if (pBucket != NULL)
  653. this->DeallocateBucket(pBucket);
  654. return fSuccess;
  655. }
  656. inline void DeallocateBucket(CBucket *pCBucket) const { FUSION_DELETE_SINGLETON(pCBucket); }
  657. friend CBucket;
  658. friend CBucketChain;
  659. ULONG m_cBucketChains;
  660. CBucketChain *m_prgBucketChains;
  661. CBucketChain m_rgInlineBucketChains[nInlineBucketChains];
  662. SIZE_T m_ulLockCount;
  663. SIZE_T m_cEntries;
  664. bool m_fInsertionsPermitted;
  665. bool m_fRemovalsPermitted;
  666. private:
  667. CHashTable(const CHashTable &r); // intentionally not implmented
  668. void operator =(const CHashTable &r); // intentionally not implemented
  669. };
  670. template <typename TKPassed, typename TKStored, typename TVPassed, typename TVStored, class THashHelper = CHashTableHelper<TKPassed, TKStored, TVPassed, TVStored>, ULONG nInlineBucketChains = 7, bool fAllowDups = false> class CHashTableIter
  671. {
  672. typedef CHashTable<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups> THashTable;
  673. public:
  674. inline CHashTableIter(CHashTable<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups> &r) : m_rTable(r), m_iBucketChain(0),
  675. m_fAlreadyAdvanced(false) { }
  676. inline ~CHashTableIter() { }
  677. inline void Reset()
  678. {
  679. FN_TRACE();
  680. m_iBucketChain = 0;
  681. m_fAlreadyAdvanced = false;
  682. // Move the bucket iterator across the bucket chains looking for one with some
  683. // buckets
  684. for (m_iBucketChain = 0; m_iBucketChain < m_rTable.m_cBucketChains; m_iBucketChain++)
  685. {
  686. m_Iter.Rebind(&m_rTable.m_prgBucketChains[m_iBucketChain].m_Buckets);
  687. m_Iter.Reset();
  688. if (m_Iter.More())
  689. break;
  690. }
  691. if (m_iBucketChain == m_rTable.m_cBucketChains)
  692. {
  693. // There wasn't anything. Unbind the iterator to signal that we're
  694. // totally done.
  695. m_Iter.Unbind();
  696. }
  697. }
  698. inline void Delete()
  699. {
  700. FN_TRACE();
  701. CSxsPreserveLastError ple;
  702. ASSERT(m_Iter.IsBound());
  703. if (m_Iter.IsBound())
  704. {
  705. THashTable::CBucket *pCBucket = m_Iter.RemoveCurrent(eDequeIteratorMoveForward);
  706. FUSION_DELETE_SINGLETON(pCBucket);
  707. m_fAlreadyAdvanced = true;
  708. m_rTable.m_cEntries--;
  709. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Decremented hash table %p entries to %Id\n", __FILE__, __LINE__, &m_rTable, m_rTable.m_cEntries);
  710. }
  711. ple.Restore();
  712. }
  713. inline BOOL Update(TVPassed valuein) const
  714. {
  715. BOOL fSuccess = FALSE;
  716. FN_TRACE_WIN32(fSuccess);
  717. INTERNAL_ERROR_CHECK(m_Iter.IsBound());
  718. INTERNAL_ERROR_CHECK(!m_fAlreadyAdvanced);
  719. IFW32FALSE_EXIT(m_Iter->Update(valuein));
  720. fSuccess = TRUE;
  721. Exit:
  722. return fSuccess;
  723. }
  724. inline bool More() const { return m_Iter.IsBound(); }
  725. inline void Next()
  726. {
  727. FN_TRACE();
  728. if (m_Iter.IsBound())
  729. {
  730. // If someone deleted the current element, the iterator has already been
  731. // advanced. Otherwise, move on.
  732. if (!m_fAlreadyAdvanced)
  733. m_Iter.Next();
  734. // We've taken it into account, now forget about it.
  735. m_fAlreadyAdvanced = false;
  736. // If there aren't any more elements in this deque, try the next bucket chain
  737. if (!m_Iter.More())
  738. {
  739. m_iBucketChain++;
  740. while (m_iBucketChain < m_rTable.m_cBucketChains)
  741. {
  742. m_Iter.Rebind(&m_rTable.m_prgBucketChains[m_iBucketChain].m_Buckets);
  743. m_Iter.Reset();
  744. if (m_Iter.More())
  745. break;
  746. m_iBucketChain++;
  747. }
  748. if (m_iBucketChain == m_rTable.m_cBucketChains)
  749. m_Iter.Unbind();
  750. }
  751. }
  752. }
  753. inline const TKStored &GetKey() const
  754. {
  755. FN_TRACE();
  756. // Should not call this if More() returns false
  757. ASSERT(m_Iter.IsBound());
  758. if (m_Iter.IsBound() && m_Iter.More())
  759. {
  760. return m_Iter->m_tkey;
  761. }
  762. return NULL;
  763. }
  764. inline TVStored &GetValue() const
  765. {
  766. FN_TRACE();
  767. // Should not call this function if More() returns false
  768. ASSERT(m_Iter.IsBound());
  769. return m_Iter->m_tvalue;
  770. }
  771. inline TVStored &operator ->() const
  772. {
  773. FN_TRACE();
  774. // Should not call this function if More() returns false
  775. ASSERT(m_Iter.IsBound());
  776. return m_Iter->m_tvalue;
  777. }
  778. protected:
  779. THashTable &m_rTable;
  780. THashTable::CBucketIterator m_Iter;
  781. ULONG m_iBucketChain;
  782. bool m_fAlreadyAdvanced;
  783. private:
  784. CHashTableIter(const CHashTableIter &);
  785. void operator =(const CHashTableIter &);
  786. };
  787. //
  788. // Helper class for hash tables of filenames:
  789. //
  790. template <typename TVPassed, typename TVStored> class CFusionFilenameHashTableHelper : public CHashTableHelper<LPCWSTR, CUnicodeStringBuffer, TVPassed, TVStored>
  791. {
  792. public:
  793. inline static BOOL HashKey(LPCWSTR sz, ULONG &rulPseudoKey)
  794. {
  795. BOOL fSuccess = FALSE;
  796. FN_TRACE_WIN32(fSuccess);
  797. ULONG ulPK = 0;
  798. LPCWSTR pszTemp;
  799. WCHAR wch;
  800. if (sz != NULL)
  801. {
  802. SIZE_T cch = ::wcslen(sz);
  803. IFW32FALSE_EXIT(::FusionpHashUnicodeString(sz, cch, &ulPK, true));
  804. }
  805. rulPseudoKey = ulPK;
  806. fSuccess = TRUE;
  807. Exit:
  808. return fSuccess;
  809. }
  810. static BOOL CompareKey(LPCWSTR szKey, CUnicodeBaseStringBuffer *pbuff, bool &rfMatch)
  811. {
  812. BOOL fSuccess = FALSE;
  813. FN_TRACE_WIN32(fSuccess);
  814. int iResult;
  815. rfMatch = false;
  816. PARAMETER_CHECK(pbuff != NULL);
  817. iResult = ::FusionpCompareStrings(
  818. szKey, (szKey == NULL) ? 0 : ::wcslen(szKey),
  819. static_cast<LPCWSTR>(*pbuff), pbuff->Cch(),
  820. true);
  821. rfMatch = (iResult == 2); // In SDK DOCS, 2 == CSTR_EQUAL; there is no constant defined. -mgrier 12/6/1999
  822. fSuccess = TRUE;
  823. Exit:
  824. return fSuccess;
  825. }
  826. };
  827. //
  828. // CSimpleKeyedTable
  829. //
  830. // A simplification of the CHashTable class template which assumes that
  831. // keys are passed as const references.
  832. //
  833. template <typename TKey, typename TVPassed, typename TVStored, typename THashHelper> class CSimpleKeyedTable : public CHashTable<const TKey &, TKey, TVPassed, TVStored, THashHelper>
  834. {
  835. public:
  836. CSimpleKeyedTable() : CHashTable<const TKey &, TKey, TVPassed, TVStored, THashHelper>() { }
  837. };
  838. template <typename TKey, typename TVPassed, typename TVStored, typename THashHelper> class CSimpleKeyedTableIter : public CHashTableIter<const TKey &, TKey, TVPassed, TVStored, THashHelper>
  839. {
  840. typedef CHashTableIter<const TKey &, TKey, TVPassed, TVStored, THashHelper> Base;
  841. public:
  842. CSimpleKeyedTableIter(CSimpleKeyedTable<TKey, TVPassed, TVStored, THashHelper> &Table) : Base(Table) { }
  843. };
  844. template <typename TKPassed, typename TKStored, typename TValue> class CPtrTableHelper : public CHashTableHelper<TKPassed, TKStored, TValue *, TValue *>
  845. {
  846. typedef TValue *TValuePtr;
  847. public:
  848. static VOID PreInitializeValue(TValue *&rvstored) { rvstored = NULL; }
  849. static BOOL InitializeValue(const TValuePtr &vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
  850. static BOOL UpdateValue(const TValuePtr &vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
  851. static VOID FinalizeValue(TValuePtr &rvstored) { if (rvstored != NULL) { FUSION_DELETE_SINGLETON(rvstored); rvstored = NULL; } }
  852. };
  853. template <typename TKPassed, typename TKStored, typename TValue, typename THashHelper = CPtrTableHelper<TKPassed, TKStored, TValue> > class CPtrTable : public CHashTable<TKPassed, TKStored, TValue *, TValue *, THashHelper>
  854. {
  855. public:
  856. CPtrTable() : CHashTable<TKPassed, TKStored, TValue *, TValue *, THashHelper>() { }
  857. BOOL Find(TKPassed keyin, TValue *&rpvaluestored)
  858. {
  859. BOOL fSuccess = FALSE;
  860. FN_TRACE_WIN32(fSuccess);
  861. ULONG ulPseudoKey = 0;
  862. ULONG iBucket = 0;
  863. TValue **ppValue = NULL;
  864. rpvaluestored = NULL;
  865. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  866. iBucket = ulPseudoKey % m_cBucketChains;
  867. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, ppValue));
  868. if (ppValue != NULL)
  869. rpvaluestored = *ppValue;
  870. fSuccess = TRUE;
  871. Exit:
  872. return fSuccess;
  873. }
  874. private:
  875. CPtrTable(const CPtrTable &);
  876. void operator =(const CPtrTable &);
  877. };
  878. template <typename TKPassed, typename TKStored, typename TValue, typename THashHelper = CPtrTableHelper<TKPassed, TKStored, TValue> > class CPtrTableIter : public CHashTableIter<TKPassed, TKStored, TValue *, TValue *, THashHelper>
  879. {
  880. public:
  881. CPtrTableIter(CPtrTable<TKPassed, TKStored, TValue, THashHelper> &Table) : CHashTableIter<TKPassed, TKStored, TValue *, TValue *, THashHelper>(Table) { }
  882. private:
  883. CPtrTableIter(const CPtrTableIter &);
  884. void operator =(const CPtrTableIter &);
  885. };
  886. template <typename TKey, typename TValue> class CSimplePtrTableHelper : public CPtrTableHelper<const TKey &, TKey, TValue>
  887. {
  888. public:
  889. };
  890. //
  891. // CSimplePtrTable
  892. //
  893. // A simplification of CHashTable class template which assumes
  894. // that keys are passed as const references and values are pointers.
  895. //
  896. // Note that the table does NOT own allocating or deallocating the storage
  897. // to which the pointers refer. If the table is destroyed, the
  898. // storage is not released.
  899. //
  900. template <typename TKey, typename TValue, typename THashHelper = CSimplePtrTableHelper<TKey, TValue> > class CSimplePtrTable : public CSimpleKeyedTable<TKey, TValue *, TValue *, THashHelper>
  901. {
  902. public:
  903. CSimplePtrTable() : CSimpleKeyedTable<TKey, TValue *, TValue *, THashHelper>(hHeap) { }
  904. BOOL Find(const TKey &keyin, TValue *&rpvaluestored)
  905. {
  906. BOOL fSuccess = FALSE;
  907. FN_TRACE_WIN32(fSuccess);
  908. ULONG ulPseudoKey = 0;
  909. ULONG iBucket = 0;
  910. TValue **ppValue = NULL;
  911. rpvaluestored = NULL;
  912. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  913. iBucket = ulPseudoKey % m_cBucketChains;
  914. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, ppValue));
  915. if (ppValue != NULL)
  916. rpvaluestored = *ppValue;
  917. fSuccess = TRUE;
  918. Exit:
  919. return fSuccess;
  920. }
  921. private:
  922. CSimplePtrTable(const CSimplePtrTable &);
  923. void operator =(const CSimplePtrTable &);
  924. };
  925. template <typename TKey, typename TValue, typename THashHelper = CSimplePtrTableHelper<TKey, TValue> > class CSimplePtrTableIter : public CSimpleKeyedTableIter<TKey, TValue *, TValue *, THashHelper>
  926. {
  927. typedef CSimpleKeyedTableIter<TKey, TValue *, TValue *, THashHelper> Base;
  928. public:
  929. CSimplePtrTableIter(CSimplePtrTable<TKey, TValue, THashHelper> &Table)
  930. : Base(Table) { }
  931. private:
  932. CSimplePtrTableIter(const CSimplePtrTableIter &);
  933. void operator =(const CSimplePtrTableIter &);
  934. };
  935. template <typename TVPassed, typename TVStored> class CGuidTableHelper : public CHashTableHelper<GUID, GUID, TVPassed, TVStored>
  936. {
  937. typedef CHashTableHelper<REFGUID, GUID, TVPassed, TVStored> Base;
  938. public:
  939. static BOOL InitializeKey(REFGUID keyin, GUID &rtkeystored) { rtkeystored = keyin; return TRUE; }
  940. };
  941. template <typename TVPassed, typename TVStored, typename THashHelper = CGuidTableHelper<TVPassed, TVStored> > class CGuidTable : public CHashTable<REFGUID, GUID, TVPassed, TVStored, THashHelper >
  942. {
  943. public:
  944. CGuidTable() : CHashTable<REFGUID, GUID, TVPassed, TVStored, THashHelper >() { }
  945. private:
  946. CGuidTable(const CGuidTable &);
  947. void operator =(const CGuidTable &);
  948. };
  949. template <typename TVPassed, typename TVStored, typename THashHelper = CGuidTableHelper<TVPassed, TVStored> > class CGuidTableIter : public CHashTableIter<REFGUID, GUID, TVPassed, TVStored, THashHelper >
  950. {
  951. typedef CHashTableIter<REFGUID, GUID, TVPassed, TVStored, THashHelper > Base;
  952. public:
  953. CGuidTableIter(CGuidTable<TVPassed, TVStored, THashHelper> &Table) : Base(Table) { }
  954. private:
  955. CGuidTableIter(const CGuidTableIter &);
  956. void operator =(const CGuidTableIter &);
  957. };
  958. template <typename TValue> class CGuidPtrTableHelper : public CHashTableHelper<REFGUID, GUID, TValue *, TValue *>
  959. {
  960. public:
  961. static BOOL InitializeKey(REFGUID keyin, GUID &rtkeystored) { rtkeystored = keyin; return TRUE; }
  962. static BOOL InitializeValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
  963. static BOOL UpdateValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
  964. };
  965. template <typename TValue, typename THashHelper = CGuidPtrTableHelper<TValue> > class CGuidPtrTable : public CGuidTable<TValue *, TValue *, THashHelper>
  966. {
  967. public:
  968. CGuidPtrTable() : CGuidTable<TValue *, TValue *, THashHelper>() { }
  969. private:
  970. CGuidPtrTable(const CGuidPtrTable &);
  971. void operator =(const CGuidPtrTable &);
  972. };
  973. template <typename TValue, typename THashHelper = CGuidPtrTableHelper<TValue> > class CGuidPtrTableIter : public CGuidTableIter<TValue *, TValue *, THashHelper>
  974. {
  975. typedef CGuidTableIter<TValue *, TValue *, THashHelper> Base;
  976. public:
  977. CGuidPtrTableIter(CGuidPtrTable<TValue, THashHelper> &Table) : Base(Table) { }
  978. private:
  979. CGuidPtrTableIter(const CGuidPtrTableIter &);
  980. void operator =(const CGuidPtrTableIter &);
  981. };
  982. template <typename TVPassed, typename TVStored, typename TCharTraits, bool fCaseInsensitive = false> class CStringTableHelper : public CHashTableHelper<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored>
  983. {
  984. public:
  985. typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
  986. static BOOL HashKey(const TCountedStringHolder &keyin, ULONG &rulPseudoKey) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFW32FALSE_EXIT(TCharTraits::Win32HashString(keyin.m_psz, keyin.m_cch, rulPseudoKey, fCaseInsensitive)); fSuccess = TRUE; Exit: return fSuccess; }
  987. static BOOL InitializeKey(const TCountedStringHolder &keyin, CBaseStringBuffer &rtkeystored) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFW32FALSE_EXIT(rtkeystored.Win32Assign(keyin.m_psz, keyin.m_cch)); fSuccess = TRUE; Exit: return fSuccess; }
  988. static BOOL CompareKey(const TCountedStringHolder &keyin, const CBaseStringBuffer &rtkeystored, bool &rfMatch) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFW32FALSE_EXIT(rtkeystored.Win32Equals(keyin.m_psz, keyin.m_cch, rfMatch, fCaseInsensitive)); fSuccess = TRUE; Exit: return fSuccess; }
  989. };
  990. class STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE
  991. {
  992. public:
  993. virtual VOID DoClear(PVOID) = 0;
  994. };
  995. template <typename TVPassed, typename TVStored, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringTableHelper<TVPassed, TVStored, TCharTraits, dwCmpFlags> > class CStringTable : public CHashTable<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored, THashHelper>
  996. {
  997. typedef CHashTable<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored, THashHelper> Base;
  998. public:
  999. typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
  1000. protected:
  1001. VOID ClearCallbackWrapper(CStringBuffer &key, TVStored &valuestored)
  1002. {
  1003. FN_TRACE();
  1004. key.Clear();
  1005. m_pActiveClearCallbackBlock->DoClear(valuestored);
  1006. }
  1007. STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE *m_pActiveClearCallbackBlock;
  1008. template <typename T> class STRING_TABLE_CLEAR_CALLBACK_BLOCK : public STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE
  1009. {
  1010. public:
  1011. T *pt;
  1012. VOID (T::*pmfn)(TVStored &valuestored);
  1013. VOID DoClear(PVOID pv) { TVStored *pvstored = (TVStored *) pv; (pt->*pmfn)(*pvstored); }
  1014. };
  1015. // Introduce name that derived classes will not override to work around compiler bugs
  1016. inline VOID ClearStringTable(STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE *pCallbackBlock)
  1017. {
  1018. FN_TRACE();
  1019. ASSERT(m_pActiveClearCallbackBlock == NULL);
  1020. m_pActiveClearCallbackBlock = pCallbackBlock;
  1021. ULONG i;
  1022. for (i=0; i<m_cBucketChains; i++)
  1023. m_prgBucketChains[i].Clear<CStringTable>(this, this, &CStringTable::ClearCallbackWrapper);
  1024. this->ClearNoCallback();
  1025. m_pActiveClearCallbackBlock = NULL;
  1026. }
  1027. public:
  1028. typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
  1029. CStringTable() : CHashTable<const TCountedStringHolder &, CStringBuffer, TVPassed, TVStored, THashHelper>(), m_pActiveClearCallbackBlock(NULL) { }
  1030. template <typename T> inline VOID Clear(T *pt, VOID (T::*pmfn)(TVStored &valuestored))
  1031. {
  1032. FN_TRACE();
  1033. STRING_TABLE_CLEAR_CALLBACK_BLOCK<T> CallbackBlock;
  1034. CallbackBlock.pt = pt;
  1035. CallbackBlock.pmfn = pmfn;
  1036. this->ClearStringTable(&CallbackBlock);
  1037. }
  1038. private:
  1039. CStringTable(const CStringTable &);
  1040. void operator =(const CStringTable &);
  1041. };
  1042. template <typename TVPassed, typename TVStored, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringTableHelper<TVPassed, TVStored, TCharTraits, dwCmpFlags> > class CStringTableIter : public CHashTableIter<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored, THashHelper>
  1043. {
  1044. public:
  1045. typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
  1046. protected:
  1047. typedef CHashTableIter<const TCountedStringHolder &, CStringBuffer, TVPassed, TVStored, THashHelper> Base;
  1048. public:
  1049. CStringTableIter(CStringTable<TVPassed, TVStored, TCharTraits, dwCmpFlags, THashHelper> &rTable) : Base(rTable) { }
  1050. inline TCharTraits::TConstantString GetKey() const
  1051. {
  1052. FN_TRACE();
  1053. // Should not call this if More() returns false
  1054. ASSERT(m_Iter != NULL);
  1055. //
  1056. // m_ulLockCount doesn't exist. I'm wondering if perhaps this entire function
  1057. // could be axed in favor of using the default one, which does something
  1058. // very similar. (jonwis 8/24/00)
  1059. //
  1060. // ASSERT(m_ulLockCount != 0);
  1061. if (m_Iter != NULL)
  1062. return m_Iter->m_tkey;
  1063. return NULL;
  1064. }
  1065. private:
  1066. CStringTableIter(const CStringTableIter &);
  1067. void operator =(const CStringTableIter &);
  1068. };
  1069. template <typename TValue, typename TCharTraits, bool fCaseInsensitive = false> class CStringPtrTableHelper : public CStringTableHelper<TValue *, TValue *, TCharTraits, fCaseInsensitive>
  1070. {
  1071. public:
  1072. static VOID PreInitializeValue(TValue *&rvstored) { rvstored = NULL; }
  1073. static BOOL InitializeValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
  1074. static BOOL UpdateValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
  1075. static VOID FinalizeValue(TValue *&rvstored) { if (rvstored != NULL) { FUSION_DELETE_SINGLETON(rvstored); rvstored = NULL; } }
  1076. };
  1077. template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringPtrTableHelper<TValue, TCharTraits, dwCmpFlags> > class CStringPtrTable : public CStringTable<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper>
  1078. {
  1079. typedef CStringTable<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper> Base;
  1080. protected:
  1081. template <typename T> class STRING_PTR_TABLE_CLEAR_CALLBACK_BLOCK : public STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE
  1082. {
  1083. public:
  1084. T *pt;
  1085. VOID (T::*pmfn)(TValue *pvaluestored);
  1086. VOID DoClear(PVOID pv) { /* TValue **ppvstored = (TValue **) pv; */ (pt->*pmfn)((TValue *) pv); }
  1087. };
  1088. public:
  1089. CStringPtrTable() : CStringTable<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper>() { }
  1090. template <typename T> VOID Clear(T *pt, VOID (T::*pmfn)(TValue *valuestored))
  1091. {
  1092. FN_TRACE();
  1093. STRING_PTR_TABLE_CLEAR_CALLBACK_BLOCK<T> CallbackBlock;
  1094. CallbackBlock.pt = pt;
  1095. CallbackBlock.pmfn = pmfn;
  1096. this->ClearStringTable(&CallbackBlock);
  1097. }
  1098. BOOL Find(const TCountedStringHolder &keyin, TValue const *&rpvaluestored) const
  1099. {
  1100. BOOL fSuccess = FALSE;
  1101. FN_TRACE_WIN32(fSuccess);
  1102. ULONG ulPseudoKey = 0;
  1103. ULONG iBucket = 0;
  1104. rpvaluestored = NULL;
  1105. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  1106. iBucket = ulPseudoKey % m_cBucketChains;
  1107. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, rpvaluestored));
  1108. fSuccess = TRUE;
  1109. Exit:
  1110. return fSuccess;
  1111. }
  1112. BOOL Find(const TCountedStringHolder &keyin, TValue *&rpvaluestored)
  1113. {
  1114. BOOL fSuccess = FALSE;
  1115. FN_TRACE_WIN32(fSuccess);
  1116. ULONG ulPseudoKey = 0;
  1117. ULONG iBucket = 0;
  1118. TValue **ppvaluestored = NULL;
  1119. rpvaluestored = NULL;
  1120. IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
  1121. iBucket = ulPseudoKey % m_cBucketChains;
  1122. IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, ppvaluestored));
  1123. if (ppvaluestored != NULL)
  1124. rpvaluestored = *ppvaluestored;
  1125. fSuccess = TRUE;
  1126. Exit:
  1127. return fSuccess;
  1128. }
  1129. private:
  1130. CStringPtrTable(const CStringPtrTable &);
  1131. void operator =(const CStringPtrTable &);
  1132. };
  1133. template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringPtrTableHelper<TValue, TCharTraits, dwCmpFlags> > class CStringPtrTableIter : public CStringTableIter<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper>
  1134. {
  1135. typedef CStringTableIter<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper> Base;
  1136. public:
  1137. CStringPtrTableIter(CStringPtrTable<TValue, TCharTraits, dwCmpFlags, THashHelper> &rTable) : Base(rTable) { }
  1138. operator TValue *() const { return this->GetValue(); }
  1139. TValue *operator ->() const { return this->GetValue(); }
  1140. private:
  1141. CStringPtrTableIter(const CStringPtrTableIter &);
  1142. void operator =(const CStringPtrTableIter &);
  1143. };
  1144. template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0> class CSimpleStringTableHelper : public CStringTableHelper<const TValue &, TValue, TCharTraits, dwCmpFlags>
  1145. {
  1146. public:
  1147. static BOOL InitializeValue(const TValue &vin, TValue &rvstored) { rvstored = vin; return TRUE; }
  1148. static BOOL UpdateValue(const TValue &vin, TValue &rvstored) { rvstored = vin; return TRUE; }
  1149. };
  1150. template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleStringTableHelper<TValue, TCharTraits, dwCmpFlags> > class CSimpleStringTable : public CStringTable<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper>
  1151. {
  1152. public:
  1153. CSimpleStringTable() : CStringTable<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper>() { }
  1154. private:
  1155. CSimpleStringTable(const CSimpleStringTable &);
  1156. void operator =(const CSimpleStringTable &);
  1157. };
  1158. template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleStringTableHelper<TValue, TCharTraits, dwCmpFlags> > class CSimpleStringTableIter : public CStringTableIter<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper>
  1159. {
  1160. typedef CStringTableIter<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper> Base;
  1161. public:
  1162. CSimpleStringTableIter(CSimpleStringTable<TValue, TCharTraits, dwCmpFlags, THashHelper> &rTable) : Base(rTable) { }
  1163. private:
  1164. CSimpleStringTableIter(const CSimpleStringTableIter &);
  1165. void operator =(const CSimpleStringTableIter &);
  1166. };
  1167. // CSimpleUnicodeStringTable et al:
  1168. template <typename TValue, DWORD dwCmpFlags = 0> class CSimpleUnicodeStringTableHelper : public CSimpleStringTableHelper<TValue, CUnicodeCharTraits, dwCmpFlags>
  1169. {
  1170. };
  1171. template <typename TValue, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleUnicodeStringTableHelper<TValue, dwCmpFlags> > class CSimpleUnicodeStringTable : public CSimpleStringTable<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper>
  1172. {
  1173. typedef CSimpleStringTable<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper> Base;
  1174. public:
  1175. CSimpleUnicodeStringTable() : Base() { }
  1176. private:
  1177. CSimpleUnicodeStringTable(const CSimpleUnicodeStringTable &);
  1178. void operator =(const CSimpleUnicodeStringTable &);
  1179. };
  1180. template <typename TValue, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleUnicodeStringTableHelper<TValue, dwCmpFlags> > class CSimpleUnicodeStringTableIter : public CSimpleStringTableIter<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper>
  1181. {
  1182. typedef CSimpleStringTableIter<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper> Base;
  1183. typedef CSimpleUnicodeStringTable<TValue, dwCmpFlags, THashHelper> TTable;
  1184. public:
  1185. CSimpleUnicodeStringTableIter(TTable &rTable) : Base(rTable) { }
  1186. private:
  1187. CSimpleUnicodeStringTableIter(const CSimpleUnicodeStringTableIter &);
  1188. void operator =(const CSimpleUnicodeStringTableIter &);
  1189. };
  1190. // CCaseInsensitiveSimpleStringTable et al:
  1191. template <typename TValue, typename TCharTraits> class CCaseInsensitiveSimpleStringTableHelper : public CSimpleStringTableHelper<TValue, TCharTraits, true>
  1192. {
  1193. };
  1194. template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveSimpleStringTableHelper<TValue, TCharTraits> > class CCaseInsensitiveSimpleStringTable : public CSimpleStringTable<TValue, TCharTraits, true, THashHelper>
  1195. {
  1196. typedef CSimpleStringTable<TValue, TCharTraits, true, THashHelper> Base;
  1197. public:
  1198. CCaseInsensitiveSimpleStringTable() : Base() { }
  1199. };
  1200. template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveSimpleStringTableHelper<TValue, TCharTraits> > class CCaseInsensitiveSimpleStringTableIter : public CSimpleStringTableIter<TValue, TCharTraits, true, THashHelper>
  1201. {
  1202. typedef CSimpleStringTableIter<TValue, TCharTraits, true, THashHelper> Base;
  1203. public:
  1204. CCaseInsensitiveSimpleStringTableIter(CCaseInsensitiveSimpleStringTable<TValue, TCharTraits, THashHelper> &rTable) : Base(rTable) { }
  1205. };
  1206. // CCaseInsensitiveSimpleUnicodeStringTable et al:
  1207. template <typename TValue> class CCaseInsensitiveSimpleUnicodeStringTableHelper : public CSimpleUnicodeStringTableHelper<TValue, true>
  1208. {
  1209. };
  1210. template <typename TValue, typename THashHelper = CCaseInsensitiveSimpleUnicodeStringTableHelper<TValue> > class CCaseInsensitiveSimpleUnicodeStringTable : public CSimpleUnicodeStringTable<TValue, true, THashHelper>
  1211. {
  1212. typedef CSimpleUnicodeStringTable<TValue, true, THashHelper> Base;
  1213. public:
  1214. CCaseInsensitiveSimpleUnicodeStringTable() : Base() { }
  1215. private:
  1216. CCaseInsensitiveSimpleUnicodeStringTable(const CCaseInsensitiveSimpleUnicodeStringTable &);
  1217. void operator =(const CCaseInsensitiveSimpleUnicodeStringTable &);
  1218. };
  1219. template <typename TValue, typename THashHelper = CCaseInsensitiveSimpleUnicodeStringTableHelper<TValue> > class CCaseInsensitiveSimpleUnicodeStringTableIter : public CSimpleUnicodeStringTableIter<TValue, true, THashHelper>
  1220. {
  1221. typedef CSimpleUnicodeStringTableIter<TValue, true, THashHelper> Base;
  1222. public:
  1223. CCaseInsensitiveSimpleUnicodeStringTableIter(CCaseInsensitiveSimpleUnicodeStringTable<TValue, THashHelper> &rTable) : Base(rTable) { }
  1224. private:
  1225. CCaseInsensitiveSimpleUnicodeStringTableIter(const CCaseInsensitiveSimpleUnicodeStringTableIter &);
  1226. void operator =(const CCaseInsensitiveSimpleUnicodeStringTableIter &);
  1227. };
  1228. // CCaseInsensitiveStringPtrTable et al:
  1229. template <typename TValue, typename TCharTraits> class CCaseInsensitiveStringPtrTableHelper : public CStringPtrTableHelper<TValue, TCharTraits, true>
  1230. {
  1231. };
  1232. template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveStringPtrTableHelper<TValue, TCharTraits> > class CCaseInsensitiveStringPtrTable : public CStringPtrTable<TValue, TCharTraits, true, THashHelper>
  1233. {
  1234. typedef CStringPtrTable<TValue, TCharTraits, true, THashHelper> Base;
  1235. public:
  1236. CCaseInsensitiveStringPtrTable() : Base() { }
  1237. };
  1238. template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveStringPtrTableHelper<TValue, TCharTraits> > class CCaseInsensitiveStringPtrTableIter : public CStringPtrTableIter<TValue, TCharTraits, true, THashHelper>
  1239. {
  1240. typedef CStringPtrTableIter<TValue, TCharTraits, true, THashHelper> Base;
  1241. public:
  1242. CCaseInsensitiveStringPtrTableIter(CCaseInsensitiveStringPtrTable<TValue, TCharTraits, THashHelper> &rTable) : Base(rTable) { }
  1243. };
  1244. // CCaseInsensitiveUnicodeStringPtrTable et al:
  1245. template <typename TValue> class CCaseInsensitiveUnicodeStringPtrTableHelper : public CStringPtrTableHelper<TValue, CUnicodeCharTraits, true>
  1246. {
  1247. };
  1248. template <typename TValue, typename THashHelper = CCaseInsensitiveUnicodeStringPtrTableHelper<TValue> > class CCaseInsensitiveUnicodeStringPtrTable : public CStringPtrTable<TValue, CUnicodeCharTraits, true, THashHelper>
  1249. {
  1250. typedef CStringPtrTable<TValue, CUnicodeCharTraits, true, THashHelper> Base;
  1251. public:
  1252. CCaseInsensitiveUnicodeStringPtrTable() { }
  1253. private:
  1254. CCaseInsensitiveUnicodeStringPtrTable(const CCaseInsensitiveUnicodeStringPtrTable &r);
  1255. void operator =(const CCaseInsensitiveUnicodeStringPtrTable &r);
  1256. };
  1257. template <typename TValue, typename THashHelper = CCaseInsensitiveUnicodeStringPtrTableHelper<TValue> > class CCaseInsensitiveUnicodeStringPtrTableIter : public CStringPtrTableIter<TValue, CUnicodeCharTraits, true, THashHelper>
  1258. {
  1259. typedef CStringPtrTableIter<TValue, CUnicodeCharTraits, true, THashHelper> Base;
  1260. public:
  1261. CCaseInsensitiveUnicodeStringPtrTableIter(CCaseInsensitiveUnicodeStringPtrTable<TValue, THashHelper> &rTable) : Base(rTable) { }
  1262. private:
  1263. CCaseInsensitiveUnicodeStringPtrTableIter(const CCaseInsensitiveUnicodeStringPtrTableIter &);
  1264. void operator =(const CCaseInsensitiveUnicodeStringPtrTableIter &);
  1265. };
  1266. #endif