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.

708 lines
14 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. File: idhash.h
  6. Owner: DmitryR
  7. Header file for the new hashing stuff
  8. ===================================================================*/
  9. #ifndef ASP_IDHASH_H
  10. #define ASP_IDHASH_H
  11. // forward declarations
  12. class CPtrArray;
  13. class CHashLock;
  14. struct CIdHashElem;
  15. struct CIdHashArray;
  16. class CIdHashTable;
  17. class CIdHashTableWithLock;
  18. struct CObjectListElem;
  19. class CObjectList;
  20. class CObjectListWithLock;
  21. // defines for the iterator callback return codes
  22. #define IteratorCallbackCode DWORD
  23. #define iccContinue 0x00000001 // goto next object
  24. #define iccStop 0x00000002 // stop iterating
  25. #define iccRemoveAndContinue 0x00000004 // remove this, goto next
  26. #define iccRemoveAndStop 0x00000008 // remove this and stop
  27. // typedefs for the iterator callback
  28. typedef IteratorCallbackCode (*PFNIDHASHCB)
  29. (void *pvObj, void *pvArg1, void *pvArg2);
  30. /*===================================================================
  31. C P t r A r r a y
  32. Self-reallocating array of void pointers
  33. ===================================================================*/
  34. class CPtrArray
  35. {
  36. private:
  37. DWORD m_dwSize; // allocated size
  38. DWORD m_dwInc; // allocation increment
  39. void **m_rgpvPtrs; // array of void pointers
  40. DWORD m_cPtrs; // pointers in the array
  41. public:
  42. CPtrArray(DWORD dwInc = 8); // 8 pointers is the default increment
  43. ~CPtrArray();
  44. // # of elements
  45. int Count() const;
  46. // get pointer at position
  47. void *Get(int i) const;
  48. // same as operator []
  49. void *operator[](int i) const;
  50. // append to array
  51. HRESULT Append(void *pv);
  52. // prepend to array
  53. HRESULT Prepend(void *pv);
  54. // insert into given position
  55. HRESULT Insert(int iPos, void *pv);
  56. // find first position of a pointer
  57. HRESULT Find(void *pv, int *piPos) const;
  58. // same as operator []
  59. int operator[](void *pv) const;
  60. // remove by position
  61. HRESULT Remove(int iPos);
  62. // remove by pointer (all occurances)
  63. HRESULT Remove(void *pv);
  64. // remove all
  65. HRESULT Clear();
  66. };
  67. // inlines
  68. inline CPtrArray::CPtrArray(DWORD dwInc)
  69. : m_dwSize(0), m_dwInc(dwInc), m_rgpvPtrs(NULL), m_cPtrs(0)
  70. {
  71. Assert(m_dwInc > 0);
  72. }
  73. inline CPtrArray::~CPtrArray()
  74. {
  75. Clear();
  76. }
  77. inline int CPtrArray::Count() const
  78. {
  79. return m_cPtrs;
  80. }
  81. inline void *CPtrArray::Get(int i) const
  82. {
  83. Assert(i >= 0 && (DWORD)i < m_cPtrs);
  84. Assert(m_rgpvPtrs);
  85. return m_rgpvPtrs[i];
  86. }
  87. inline void *CPtrArray::operator[](int i) const
  88. {
  89. return Get(i);
  90. }
  91. inline HRESULT CPtrArray::Append(void *pv)
  92. {
  93. return Insert(m_cPtrs, pv);
  94. }
  95. inline HRESULT CPtrArray::Prepend(void *pv)
  96. {
  97. return Insert(0, pv);
  98. }
  99. inline int CPtrArray::operator[](void *pv) const
  100. {
  101. int i;
  102. if (Find(pv, &i) == S_OK)
  103. return i;
  104. return -1; // not found
  105. }
  106. /*===================================================================
  107. C H a s h L o c k
  108. A wrapper around CRITICAL_SECTION.
  109. ===================================================================*/
  110. class CHashLock
  111. {
  112. private:
  113. DWORD m_fInited : 1;
  114. CRITICAL_SECTION m_csLock;
  115. public:
  116. CHashLock();
  117. ~CHashLock();
  118. HRESULT Init();
  119. HRESULT UnInit();
  120. void Lock();
  121. void UnLock();
  122. };
  123. // inlines
  124. inline CHashLock::CHashLock()
  125. : m_fInited(FALSE)
  126. {
  127. }
  128. inline CHashLock::~CHashLock()
  129. {
  130. UnInit();
  131. }
  132. inline void CHashLock::Lock()
  133. {
  134. Assert(m_fInited);
  135. EnterCriticalSection(&m_csLock);
  136. }
  137. inline void CHashLock::UnLock()
  138. {
  139. Assert(m_fInited);
  140. LeaveCriticalSection( &m_csLock );
  141. }
  142. /*===================================================================
  143. C I d H a s h U n i t
  144. 8-byte structure -- one element of hash array. Could be:
  145. 1) empty, 2) point to an object, 3) point to sub-array
  146. ===================================================================*/
  147. struct CIdHashElem
  148. {
  149. DWORD_PTR m_dw;
  150. void *m_pv;
  151. BOOL FIsEmpty() const;
  152. BOOL FIsObject() const;
  153. BOOL FIsArray() const;
  154. DWORD_PTR DWId() const;
  155. void *PObject() const;
  156. CIdHashArray *PArray() const;
  157. void SetToEmpty();
  158. void SetToObject(DWORD_PTR dwId, void *pvObj);
  159. void SetToArray(CIdHashArray *pArray);
  160. };
  161. // inlines
  162. inline BOOL CIdHashElem::FIsEmpty() const
  163. {
  164. return (m_pv == NULL);
  165. }
  166. inline BOOL CIdHashElem::FIsObject() const
  167. {
  168. return (m_dw != 0);
  169. }
  170. inline BOOL CIdHashElem::FIsArray() const
  171. {
  172. return (m_pv != NULL && m_dw == 0);
  173. }
  174. inline DWORD_PTR CIdHashElem::DWId() const
  175. {
  176. return m_dw;
  177. }
  178. inline void *CIdHashElem::PObject() const
  179. {
  180. return m_pv;
  181. }
  182. inline CIdHashArray *CIdHashElem::PArray() const
  183. {
  184. return reinterpret_cast<CIdHashArray *>(m_pv);
  185. }
  186. inline void CIdHashElem::SetToEmpty()
  187. {
  188. m_dw = 0;
  189. m_pv = NULL;
  190. }
  191. inline void CIdHashElem::SetToObject
  192. (
  193. DWORD_PTR dwId,
  194. void *pvObj
  195. )
  196. {
  197. m_dw = dwId;
  198. m_pv = pvObj;
  199. }
  200. inline void CIdHashElem::SetToArray
  201. (
  202. CIdHashArray *pArray
  203. )
  204. {
  205. m_dw = 0;
  206. m_pv = pArray;
  207. }
  208. /*===================================================================
  209. C I d H a s h A r r a y
  210. Structure to consisting of DWORD (# of elems) and the array of Elems
  211. ===================================================================*/
  212. struct CIdHashArray
  213. {
  214. USHORT m_cElems; // total number of elements
  215. USHORT m_cNotNulls; // number of not NULL elements
  216. CIdHashElem m_rgElems[1]; // 1 doesn't matter
  217. static CIdHashArray *Alloc(DWORD cElems);
  218. static void Free(CIdHashArray *pArray);
  219. HRESULT Find(DWORD_PTR dwId, void **ppvObj) const;
  220. HRESULT Add(DWORD_PTR dwId, void *pvObj, USHORT *rgusSizes);
  221. HRESULT Remove(DWORD_PTR dwId, void **ppvObj);
  222. IteratorCallbackCode Iterate(PFNIDHASHCB pfnCB, void *pvArg1, void *pvArg2);
  223. #ifdef DBG
  224. void DumpStats(FILE *f, int nVerbose, DWORD iLevel,
  225. DWORD &cElems, DWORD &cSlots, DWORD &cArrays, DWORD &cDepth) const;
  226. #else
  227. inline void DumpStats(FILE *, int, DWORD,
  228. DWORD &, DWORD &, DWORD &, DWORD &) const {}
  229. #endif
  230. };
  231. /*===================================================================
  232. C I d H a s h T a b l e
  233. Remembers sizes of arrays on all levels and has a pointer to the
  234. first level array of CIdHashElem elements.
  235. ===================================================================*/
  236. class CIdHashTable
  237. {
  238. private:
  239. USHORT m_rgusSizes[4]; // Sizes of arrays on first 4 levels
  240. CIdHashArray *m_pArray; // Pointer to first level array
  241. inline BOOL FInited() const { return (m_rgusSizes[0] != 0); }
  242. public:
  243. CIdHashTable();
  244. CIdHashTable(USHORT usSize1, USHORT usSize2 = 0, USHORT usSize3 = 0);
  245. ~CIdHashTable();
  246. HRESULT Init(USHORT usSize1, USHORT usSize2 = 0, USHORT usSize3 = 0);
  247. HRESULT UnInit();
  248. HRESULT FindObject(DWORD_PTR dwId, void **ppvObj = NULL) const;
  249. HRESULT AddObject(DWORD_PTR dwId, void *pvObj);
  250. HRESULT RemoveObject(DWORD_PTR dwId, void **ppvObj = NULL);
  251. HRESULT RemoveAllObjects();
  252. HRESULT IterateObjects
  253. (
  254. PFNIDHASHCB pfnCB,
  255. void *pvArg1 = NULL,
  256. void *pvArg2 = NULL
  257. );
  258. public:
  259. #ifdef DBG
  260. void AssertValid() const;
  261. void Dump(const char *szFile) const;
  262. #else
  263. inline void AssertValid() const {}
  264. inline void Dump(const char *) const {}
  265. #endif
  266. };
  267. // inlines
  268. inline CIdHashTable::CIdHashTable()
  269. {
  270. m_rgusSizes[0] = 0; // mark as UnInited
  271. m_pArray = NULL;
  272. }
  273. inline CIdHashTable::CIdHashTable
  274. (
  275. USHORT usSize1,
  276. USHORT usSize2,
  277. USHORT usSize3
  278. )
  279. {
  280. m_rgusSizes[0] = 0; // mark as UnInited
  281. m_pArray = NULL;
  282. Init(usSize1, usSize2, usSize3); // use Init to initialize
  283. }
  284. inline CIdHashTable::~CIdHashTable()
  285. {
  286. UnInit();
  287. }
  288. inline HRESULT CIdHashTable::FindObject
  289. (
  290. DWORD_PTR dwId,
  291. void **ppvObj
  292. )
  293. const
  294. {
  295. Assert(FInited());
  296. Assert(dwId);
  297. if (!m_pArray)
  298. {
  299. if (ppvObj)
  300. *ppvObj = NULL;
  301. return S_FALSE;
  302. }
  303. return m_pArray->Find(dwId, ppvObj);
  304. }
  305. inline HRESULT CIdHashTable::AddObject
  306. (
  307. DWORD_PTR dwId,
  308. void *pvObj
  309. )
  310. {
  311. Assert(FInited());
  312. Assert(dwId);
  313. Assert(pvObj);
  314. if (!m_pArray)
  315. {
  316. m_pArray = CIdHashArray::Alloc(m_rgusSizes[0]);
  317. if (!m_pArray)
  318. return E_OUTOFMEMORY;
  319. }
  320. return m_pArray->Add(dwId, pvObj, m_rgusSizes);
  321. }
  322. inline HRESULT CIdHashTable::RemoveObject
  323. (
  324. DWORD_PTR dwId,
  325. void **ppvObj
  326. )
  327. {
  328. Assert(FInited());
  329. Assert(dwId);
  330. if (!m_pArray)
  331. {
  332. if (ppvObj)
  333. *ppvObj = NULL;
  334. return S_FALSE;
  335. }
  336. return m_pArray->Remove(dwId, ppvObj);
  337. }
  338. inline HRESULT CIdHashTable::RemoveAllObjects()
  339. {
  340. if (m_pArray)
  341. {
  342. CIdHashArray::Free(m_pArray);
  343. m_pArray = NULL;
  344. }
  345. return S_OK;
  346. }
  347. inline HRESULT CIdHashTable::IterateObjects
  348. (
  349. PFNIDHASHCB pfnCB,
  350. void *pvArg1,
  351. void *pvArg2
  352. )
  353. {
  354. Assert(FInited());
  355. Assert(pfnCB);
  356. if (!m_pArray)
  357. return S_OK;
  358. return m_pArray->Iterate(pfnCB, pvArg1, pvArg2);
  359. }
  360. /*===================================================================
  361. C I d H a s h T a b l e W i t h L o c k
  362. CIdHashTable + CRITICAL_SECTION.
  363. ===================================================================*/
  364. class CIdHashTableWithLock : public CIdHashTable, public CHashLock
  365. {
  366. public:
  367. CIdHashTableWithLock();
  368. ~CIdHashTableWithLock();
  369. HRESULT Init(USHORT usSize1, USHORT usSize2 = 0, USHORT usSize3 = 0);
  370. HRESULT UnInit();
  371. };
  372. // inlines
  373. inline CIdHashTableWithLock::CIdHashTableWithLock()
  374. {
  375. }
  376. inline CIdHashTableWithLock::~CIdHashTableWithLock()
  377. {
  378. UnInit();
  379. }
  380. inline HRESULT CIdHashTableWithLock::Init
  381. (
  382. USHORT usSize1,
  383. USHORT usSize2,
  384. USHORT usSize3
  385. )
  386. {
  387. HRESULT hr = CIdHashTable::Init(usSize1, usSize2, usSize3);
  388. if (SUCCEEDED(hr))
  389. hr = CHashLock::Init();
  390. return hr;
  391. }
  392. inline HRESULT CIdHashTableWithLock::UnInit()
  393. {
  394. CIdHashTable::UnInit();
  395. CHashLock::UnInit();
  396. return S_OK;
  397. }
  398. /*===================================================================
  399. C O b j e c t L i s t E l e m
  400. Double linked list element
  401. ===================================================================*/
  402. struct CObjectListElem
  403. {
  404. CObjectListElem *m_pNext;
  405. CObjectListElem *m_pPrev;
  406. CObjectListElem();
  407. void Insert(CObjectListElem *pPrevElem, CObjectListElem *pNextElem);
  408. void Remove();
  409. void *PObject(DWORD dwFieldOffset);
  410. };
  411. inline CObjectListElem::CObjectListElem()
  412. : m_pNext(NULL), m_pPrev(NULL)
  413. {
  414. }
  415. inline void CObjectListElem::Insert
  416. (
  417. CObjectListElem *pPrevElem,
  418. CObjectListElem *pNextElem
  419. )
  420. {
  421. Assert(!pPrevElem || (pPrevElem->m_pNext == pNextElem));
  422. Assert(!pNextElem || (pNextElem->m_pPrev == pPrevElem));
  423. m_pPrev = pPrevElem;
  424. m_pNext = pNextElem;
  425. if (pPrevElem)
  426. pPrevElem->m_pNext = this;
  427. if (pNextElem)
  428. pNextElem->m_pPrev = this;
  429. }
  430. inline void CObjectListElem::Remove()
  431. {
  432. if (m_pPrev)
  433. m_pPrev->m_pNext = m_pNext;
  434. if (m_pNext)
  435. m_pNext->m_pPrev = m_pPrev;
  436. m_pPrev = m_pNext = NULL;
  437. }
  438. inline void *CObjectListElem::PObject(DWORD dwFieldOffset)
  439. {
  440. return ((BYTE *)this - dwFieldOffset);
  441. }
  442. // Macro to get the byte offset of a field in a class
  443. #define OBJECT_LIST_ELEM_FIELD_OFFSET(type, field) \
  444. (PtrToUlong(&(((type *)0)->field)))
  445. inline CObjectListElem *PListElemField
  446. (
  447. void *pvObj,
  448. DWORD dwFieldOffset
  449. )
  450. {
  451. if (!pvObj)
  452. return NULL;
  453. return (CObjectListElem *)((BYTE *)pvObj + dwFieldOffset);
  454. }
  455. /*===================================================================
  456. C O b j e c t L i s t
  457. Double linked list of objects
  458. ===================================================================*/
  459. class CObjectList
  460. {
  461. private:
  462. CObjectListElem m_Head; // list head
  463. DWORD m_dwFieldOffset; // offset to CObjectListElem member field
  464. public:
  465. CObjectList();
  466. ~CObjectList();
  467. HRESULT Init(DWORD dwFieldOffset = 0);
  468. HRESULT UnInit();
  469. HRESULT AddObject(void *pvObj);
  470. HRESULT RemoveObject(void *pvObj);
  471. HRESULT RemoveAllObjects();
  472. // iteration
  473. void *PFirstObject();
  474. void *PNextObject(void *pvObj);
  475. };
  476. // inlines
  477. inline CObjectList::CObjectList()
  478. : m_dwFieldOffset(0)
  479. {
  480. }
  481. inline CObjectList::~CObjectList()
  482. {
  483. UnInit();
  484. }
  485. inline HRESULT CObjectList::Init(DWORD dwFieldOffset)
  486. {
  487. m_dwFieldOffset = dwFieldOffset;
  488. m_Head.m_pPrev = m_Head.m_pNext = NULL;
  489. return S_OK;
  490. }
  491. inline HRESULT CObjectList::UnInit()
  492. {
  493. RemoveAllObjects();
  494. return S_OK;
  495. }
  496. inline HRESULT CObjectList::AddObject(void *pvObj)
  497. {
  498. Assert(pvObj);
  499. // insert between head and its next
  500. PListElemField(pvObj, m_dwFieldOffset)->Insert(&m_Head, m_Head.m_pNext);
  501. return S_OK;
  502. }
  503. inline HRESULT CObjectList::RemoveObject(void *pvObj)
  504. {
  505. Assert(pvObj);
  506. PListElemField(pvObj, m_dwFieldOffset)->Remove();
  507. return S_OK;
  508. }
  509. inline HRESULT CObjectList::RemoveAllObjects()
  510. {
  511. if (m_Head.m_pNext)
  512. m_Head.m_pNext = NULL;
  513. return S_OK;
  514. }
  515. inline void *CObjectList::PFirstObject()
  516. {
  517. return m_Head.m_pNext ? m_Head.m_pNext->PObject(m_dwFieldOffset) : NULL;
  518. }
  519. inline void *CObjectList::PNextObject(void *pvObj)
  520. {
  521. CObjectListElem *pNextElem =
  522. pvObj ? PListElemField(pvObj, m_dwFieldOffset)->m_pNext : NULL;
  523. return pNextElem ? pNextElem->PObject(m_dwFieldOffset) : NULL;
  524. }
  525. /*===================================================================
  526. C O b j e c t L i s t W i t h L o c k
  527. CObjectList + CRITICAL_SECTION.
  528. ===================================================================*/
  529. class CObjectListWithLock : public CObjectList, public CHashLock
  530. {
  531. public:
  532. CObjectListWithLock();
  533. ~CObjectListWithLock();
  534. HRESULT Init(DWORD dwFieldOffset = 0);
  535. HRESULT UnInit();
  536. };
  537. // inlines
  538. inline CObjectListWithLock::CObjectListWithLock()
  539. {
  540. }
  541. inline CObjectListWithLock::~CObjectListWithLock()
  542. {
  543. UnInit();
  544. }
  545. inline HRESULT CObjectListWithLock::Init(DWORD dwFieldOffset)
  546. {
  547. HRESULT hr = CObjectList::Init(dwFieldOffset);
  548. if (SUCCEEDED(hr))
  549. hr = CHashLock::Init();
  550. return hr;
  551. }
  552. inline HRESULT CObjectListWithLock::UnInit()
  553. {
  554. CObjectList::UnInit();
  555. CHashLock::UnInit();
  556. return S_OK;
  557. }
  558. #endif // ifndef ASP_IDHASH_H