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.

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