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.

587 lines
16 KiB

  1. #pragma once
  2. #include "fusiontrace.h"
  3. #include "fusiondequelinkage.h"
  4. class CDequeBase
  5. {
  6. protected:
  7. inline CDequeBase() : m_EntryCount(0) { m_Head.InitializeHead(this); }
  8. inline ~CDequeBase()
  9. {
  10. // Derived class should have cleaned up
  11. ASSERT_NTC(m_EntryCount == 0);
  12. }
  13. inline VOID VerifyLinkageFromThisDeque(const CDequeLinkage &r)
  14. {
  15. ASSERT_NTC(r.GetDequeBase() == this);
  16. }
  17. #if DBG
  18. inline bool Valid() const { return (m_Head.GetFlink() != NULL) && (m_Head.GetBlink() != NULL); }
  19. #endif // DBG
  20. void ResetHead() { FN_TRACE(); m_Head.InitializeHead(this); }
  21. inline VOID InsertAfter(CDequeLinkage *pExistingLinkage, CDequeLinkage *pNewLinkage, bool fUpdateEntryCount = true)
  22. {
  23. ASSERT_NTC(this->Valid());
  24. this->VerifyLinkageFromThisDeque(m_Head);
  25. pNewLinkage->SetFlink(pExistingLinkage->GetFlink());
  26. pNewLinkage->SetBlink(pExistingLinkage);
  27. pExistingLinkage->GetFlink()->SetBlink(pNewLinkage);
  28. pExistingLinkage->SetFlink(pNewLinkage);
  29. pNewLinkage->SetDeque(this);
  30. if (fUpdateEntryCount)
  31. m_EntryCount++;
  32. }
  33. VOID InsertBefore(CDequeLinkage *pExistingLinkage, CDequeLinkage *pNewLinkage, bool fUpdateEntryCount = true)
  34. {
  35. ASSERT_NTC(this->Valid());
  36. this->VerifyLinkageFromThisDeque(m_Head);
  37. pNewLinkage->SetBlink(pExistingLinkage->GetBlink());
  38. pNewLinkage->SetFlink(pExistingLinkage);
  39. pExistingLinkage->GetBlink()->SetFlink(pNewLinkage);
  40. pExistingLinkage->SetBlink(pNewLinkage);
  41. pNewLinkage->SetDeque(this);
  42. if (fUpdateEntryCount)
  43. m_EntryCount++;
  44. }
  45. VOID Remove(CDequeLinkage *pLinkage, bool fUpdateEntryCount = true)
  46. {
  47. ASSERT_NTC(this->Valid());
  48. this->VerifyLinkageFromThisDeque(m_Head);
  49. // You can't remove the head...
  50. ASSERT_NTC(pLinkage->GetDequeBase() == this);
  51. ASSERT_NTC(pLinkage != &m_Head);
  52. ASSERT_NTC(pLinkage->m_ulLockCount == 0);
  53. if ((pLinkage != NULL) &&
  54. (pLinkage->GetDequeBase() == this) &&
  55. (pLinkage != &m_Head))
  56. {
  57. pLinkage->GetBlink()->SetFlink(pLinkage->GetFlink());
  58. pLinkage->GetFlink()->SetBlink(pLinkage->GetBlink());
  59. if (fUpdateEntryCount)
  60. m_EntryCount--;
  61. }
  62. }
  63. VOID SetDeque(CDequeLinkage *pLinkage) { pLinkage->SetDeque(this); }
  64. static CDequeLinkage *GetFlink(const CDequeLinkage *pLinkage) { return pLinkage->GetFlink(); }
  65. static CDequeLinkage *GetFlink(const CDequeLinkage &rLinkage) { return rLinkage.GetFlink(); }
  66. static CDequeLinkage *GetBlink(const CDequeLinkage *pLinkage) { return pLinkage->GetBlink(); }
  67. static CDequeLinkage *GetBlink(const CDequeLinkage &rLinkage) { return rLinkage.GetBlink(); }
  68. static VOID SetFlink(CDequeLinkage *pLinkage, CDequeLinkage *pFlink) { pLinkage->SetFlink(pFlink); }
  69. static VOID SetFlink(CDequeLinkage &rLinkage, CDequeLinkage *pFlink) { rLinkage.SetFlink(pFlink); }
  70. static VOID SetBlink(CDequeLinkage *pLinkage, CDequeLinkage *pBlink) { pLinkage->SetBlink(pBlink); }
  71. static VOID SetBlink(CDequeLinkage &rLinkage, CDequeLinkage *pBlink) { rLinkage.SetBlink(pBlink); }
  72. CDequeLinkage m_Head;
  73. SIZE_T m_EntryCount;
  74. private:
  75. CDequeBase(const CDequeBase &r); // intentionally not implemented
  76. void operator =(const CDequeBase &r); // intentionally not implemented
  77. };
  78. template <typename TEntry, size_t LinkageMemberOffset> class CConstDequeIterator;
  79. template <typename TEntry, size_t LinkageMemberOffset> class CDeque : protected CDequeBase
  80. {
  81. friend CConstDequeIterator<TEntry, LinkageMemberOffset>;
  82. public:
  83. CDeque() { }
  84. ~CDeque()
  85. {
  86. CSxsPreserveLastError ple;
  87. ASSERT_NTC(this->Valid());
  88. this->VerifyLinkageFromThisDeque(m_Head);
  89. // You should have cleaned up this deque beforehand...
  90. ASSERT_NTC(m_EntryCount == 0);
  91. m_EntryCount = 0;
  92. ple.Restore();
  93. }
  94. VOID TakeValue(CDeque &rThat)
  95. {
  96. FN_TRACE();
  97. ASSERT(this->Valid());
  98. // Since we don't manage the storage of the entries, "this" deque
  99. // must be empty.
  100. ASSERT(m_EntryCount == 0);
  101. // with regards to linkages, we only need to change the pseudo-head flink
  102. // and blink, the actual head blink and the actual tail flink. However,
  103. // for debugging purposes, we keep the identity of the deque that contains
  104. // the linkage in the linkage, so we also have to fix those.
  105. ASSERT(rThat.Valid());
  106. CDequeLinkage *pLinkage = rThat.GetFlink(rThat.m_Head);
  107. if (pLinkage != NULL)
  108. {
  109. while (pLinkage != &rThat.m_Head)
  110. {
  111. ASSERT(pLinkage->IsNotLocked());
  112. this->SetDeque(pLinkage);
  113. pLinkage = rThat.GetFlink(pLinkage);
  114. }
  115. }
  116. // Now munge the pointers...
  117. this->SetFlink(m_Head, rThat.GetFlink(rThat.m_Head));
  118. this->SetBlink(m_Head, rThat.GetBlink(rThat.m_Head));
  119. this->SetBlink(rThat.GetFlink(rThat.m_Head), &m_Head);
  120. this->SetFlink(rThat.GetBlink(rThat.m_Head), &m_Head);
  121. rThat.SetFlink(rThat.m_Head, &rThat.m_Head);
  122. rThat.SetBlink(rThat.m_Head, &rThat.m_Head);
  123. m_EntryCount = rThat.m_EntryCount;
  124. rThat.m_EntryCount = 0;
  125. }
  126. VOID AddToHead(TEntry *pEntry)
  127. {
  128. FN_TRACE();
  129. ASSERT(this->Valid());
  130. this->InsertAfter(&m_Head, this->MapEntryToLinkage(pEntry), true);
  131. }
  132. VOID AddToTail(TEntry *pEntry)
  133. {
  134. FN_TRACE();
  135. ASSERT(this->Valid());
  136. this->InsertBefore(&m_Head, this->MapEntryToLinkage(pEntry), true);
  137. }
  138. VOID Add(TEntry *pEntry)
  139. {
  140. FN_TRACE();
  141. ASSERT(this->Valid());
  142. AddToTail(pEntry);
  143. }
  144. TEntry *RemoveHead()
  145. {
  146. FN_TRACE();
  147. ASSERT(this->Valid());
  148. TEntry *pEntry = NULL;
  149. if (this->GetFlink(m_Head) != &m_Head)
  150. {
  151. CDequeLinkage *pLinkage = this->GetFlink(m_Head);
  152. this->Remove(pLinkage, true);
  153. pEntry = this->MapLinkageToEntry(pLinkage);
  154. }
  155. return pEntry;
  156. }
  157. TEntry *RemoveTail()
  158. {
  159. FN_TRACE();
  160. ASSERT(this->Valid());
  161. TEntry *pEntry = NULL;
  162. if (this->GetBlink(m_Head) != &m_Head)
  163. {
  164. pEntry = this->GetBlink(m_Head);
  165. this->Remove(pEntry, true);
  166. }
  167. return pEntry;
  168. }
  169. bool IsHead(CDequeLinkage *pLinkage) const { return pLinkage == &m_Head; }
  170. VOID Remove(TEntry *pEntry)
  171. {
  172. FN_TRACE();
  173. ASSERT(this->Valid());
  174. this->Remove(this->MapEntryToLinkage(pEntry), true);
  175. }
  176. template <typename T> VOID ForEach(T *pt, VOID (T::*pmfn)(TEntry *p))
  177. {
  178. FN_TRACE();
  179. ASSERT(this->Valid());
  180. CDequeLinkage *pLinkage = this->GetFlink(m_Head);
  181. if (pLinkage != NULL)
  182. {
  183. while (pLinkage != &m_Head)
  184. {
  185. // You can't remove the element that you're on during a ForEach() call.
  186. pLinkage->Lock();
  187. (pt->*pmfn)(this->MapLinkageToEntry(pLinkage));
  188. pLinkage->Unlock();
  189. pLinkage = this->GetFlink(pLinkage);
  190. }
  191. }
  192. }
  193. template <typename T> VOID ForEach(const T *pt, VOID (T::*pmfn)(TEntry *p) const)
  194. {
  195. FN_TRACE();
  196. ASSERT(this->Valid());
  197. CDequeLinkage *pLinkage = this->GetFlink(m_Head);
  198. while ( pLinkage && (pLinkage != &m_Head) )
  199. {
  200. pLinkage->Lock();
  201. (pt->*pmfn)(this->MapLinkageToEntry(pLinkage));
  202. pLinkage->Unlock();
  203. pLinkage = this->GetFlink(pLinkage);
  204. }
  205. }
  206. template <typename T> VOID Clear(T *pt, VOID (T::*pmfn)(TEntry *p))
  207. {
  208. FN_TRACE();
  209. ASSERT(this->Valid());
  210. CDequeLinkage *pLinkage = this->GetFlink(m_Head);
  211. if (pLinkage != NULL)
  212. {
  213. while (pLinkage != &m_Head)
  214. {
  215. CDequeLinkage *pLinkage_Next = this->GetFlink(pLinkage);
  216. ASSERT(pLinkage->IsNotLocked());
  217. (pt->*pmfn)(this->MapLinkageToEntry(pLinkage));
  218. pLinkage = pLinkage_Next;
  219. }
  220. }
  221. this->ResetHead();
  222. m_EntryCount = 0;
  223. }
  224. template <typename T> VOID Clear(const T *pt, VOID (T::*pmfn)(TEntry *p) const)
  225. {
  226. FN_TRACE();
  227. ASSERT(this->Valid());
  228. CDequeLinkage *pLinkage = this->GetFlink(m_Head);
  229. if (pLinkage != NULL)
  230. {
  231. while (pLinkage != &m_Head)
  232. {
  233. CDequeLinkage *pLinkage_Next = this->GetFlink(pLinkage);
  234. ASSERT(pLinkage->IsNotLocked());
  235. (pt->*pmfn)(this->MapLinkageToEntry(pLinkage));
  236. pLinkage = pLinkage_Next;
  237. }
  238. }
  239. this->ResetHead();
  240. m_EntryCount = 0;
  241. }
  242. VOID Clear(VOID (TEntry::*pmfn)())
  243. {
  244. FN_TRACE();
  245. ASSERT(this->Valid());
  246. CDequeLinkage *pLinkage = this->GetFlink(m_Head);
  247. if (pLinkage != NULL)
  248. {
  249. while (pLinkage != &m_Head)
  250. {
  251. CDequeLinkage *pLinkage_Next = this->GetFlink(pLinkage);
  252. ASSERT(pLinkage->IsNotLocked());
  253. TEntry* pEntry = this->MapLinkageToEntry(pLinkage);
  254. (pEntry->*pmfn)();
  255. pLinkage = pLinkage_Next;
  256. }
  257. }
  258. this->ResetHead();
  259. m_EntryCount = 0;
  260. }
  261. VOID ClearAndDeleteAll()
  262. {
  263. FN_TRACE();
  264. ASSERT(this->Valid());
  265. CDequeLinkage *pLinkage = this->GetFlink(m_Head);
  266. if (pLinkage != NULL)
  267. {
  268. while (pLinkage != &m_Head)
  269. {
  270. CDequeLinkage *pLinkage_Next = this->GetFlink(pLinkage);
  271. ASSERT(pLinkage->IsNotLocked());
  272. TEntry* pEntry = this->MapLinkageToEntry(pLinkage);
  273. FUSION_DELETE_SINGLETON(pEntry);
  274. pLinkage = pLinkage_Next;
  275. }
  276. }
  277. this->ResetHead();
  278. m_EntryCount = 0;
  279. }
  280. void ClearNoCallback()
  281. {
  282. FN_TRACE();
  283. ASSERT(this->Valid());
  284. this->ResetHead();
  285. m_EntryCount = 0;
  286. }
  287. SIZE_T GetEntryCount() const { return m_EntryCount; }
  288. bool IsEmpty() const { return m_EntryCount == 0; }
  289. protected:
  290. using CDequeBase::Remove;
  291. TEntry *MapLinkageToEntry(CDequeLinkage *pLinkage) const
  292. {
  293. ASSERT_NTC(pLinkage != &m_Head);
  294. if (pLinkage == &m_Head)
  295. return NULL;
  296. return (TEntry *) (((LONG_PTR) pLinkage) - LinkageMemberOffset);
  297. }
  298. CDequeLinkage *MapEntryToLinkage(TEntry *pEntry) const
  299. {
  300. ASSERT_NTC(pEntry != NULL);
  301. return (CDequeLinkage *) (((LONG_PTR) pEntry) + LinkageMemberOffset);
  302. }
  303. private:
  304. CDeque(const CDeque &r); // intentionally not implemented
  305. void operator =(const CDeque &r); // intentionally not implemented
  306. };
  307. enum DequeIteratorMovementDirection
  308. {
  309. eDequeIteratorMoveForward,
  310. eDequeIteratorMoveBackward
  311. };
  312. template <typename TEntry, size_t LinkageMemberOffset> class CConstDequeIterator
  313. {
  314. public:
  315. CConstDequeIterator(const CDeque<TEntry, LinkageMemberOffset> *Deque = NULL) : m_Deque(Deque), m_pCurrent(NULL) { }
  316. ~CConstDequeIterator()
  317. {
  318. if (m_pCurrent != NULL)
  319. {
  320. m_pCurrent->Unlock();
  321. m_pCurrent = NULL;
  322. }
  323. }
  324. VOID Rebind(const CDeque<TEntry, LinkageMemberOffset> *NewDeque)
  325. {
  326. FN_TRACE();
  327. if (m_pCurrent != NULL)
  328. {
  329. m_pCurrent->Unlock();
  330. m_pCurrent = NULL;
  331. }
  332. m_Deque = NewDeque;
  333. if (NewDeque != NULL)
  334. {
  335. m_pCurrent = this->GetFirstLinkage();
  336. m_pCurrent->Lock();
  337. }
  338. }
  339. bool IsBound() const { return (m_Deque != NULL); }
  340. VOID Unbind()
  341. {
  342. FN_TRACE();
  343. if (m_Deque != NULL)
  344. {
  345. if (m_pCurrent != NULL)
  346. {
  347. m_pCurrent->Unlock();
  348. m_pCurrent = NULL;
  349. }
  350. m_Deque = NULL;
  351. }
  352. }
  353. // You can't remove an element that the iterator is sitting on; usually you just
  354. // save the current element and move to the next one, but if you found the exact
  355. // element you wanted and don't want to use the iterator any more, you can Close()
  356. // it to release the lock.
  357. VOID Close()
  358. {
  359. FN_TRACE();
  360. if (m_pCurrent != NULL)
  361. {
  362. m_pCurrent->Unlock();
  363. m_pCurrent = NULL;
  364. }
  365. }
  366. inline VOID Reset()
  367. {
  368. if (m_pCurrent != NULL)
  369. {
  370. m_pCurrent->Unlock();
  371. m_pCurrent = NULL;
  372. }
  373. m_pCurrent = this->GetFirstLinkage();
  374. m_pCurrent->Lock();
  375. }
  376. inline VOID Move(DequeIteratorMovementDirection eDirection)
  377. {
  378. ASSERT_NTC(m_pCurrent != NULL);
  379. ASSERT_NTC((eDirection == eDequeIteratorMoveForward) ||
  380. (eDirection == eDequeIteratorMoveBackward));
  381. m_pCurrent->Unlock();
  382. if (eDirection == eDequeIteratorMoveForward)
  383. m_pCurrent = m_Deque->GetFlink(m_pCurrent);
  384. else if (eDirection == eDequeIteratorMoveBackward)
  385. m_pCurrent = m_Deque->GetBlink(m_pCurrent);
  386. m_pCurrent->Lock();
  387. }
  388. VOID Next() { this->Move(eDequeIteratorMoveForward); }
  389. VOID Previous() { this->Move(eDequeIteratorMoveBackward); }
  390. bool More() const { return (m_pCurrent != NULL) && (m_pCurrent != &m_Deque->m_Head); }
  391. TEntry *operator ->() const { ASSERT_NTC(m_pCurrent != NULL); return this->MapLinkageToEntry(m_pCurrent); }
  392. operator TEntry *() const { ASSERT_NTC(m_pCurrent != NULL); return this->MapLinkageToEntry(m_pCurrent); }
  393. TEntry *Current() const { ASSERT_NTC(m_pCurrent != NULL); return this->MapLinkageToEntry(m_pCurrent); }
  394. protected:
  395. CDequeLinkage *GetFirstLinkage() const { return m_Deque->GetFlink(m_Deque->m_Head); }
  396. CDequeLinkage *GetLastLinkage() const { return m_Deque->GetBlink(m_Deque->m_Head); }
  397. TEntry *MapLinkageToEntry(CDequeLinkage *pLinkage) const { return m_Deque->MapLinkageToEntry(pLinkage); }
  398. const CDeque<TEntry, LinkageMemberOffset> *m_Deque;
  399. CDequeLinkage *m_pCurrent;
  400. };
  401. template <typename TEntry, size_t LinkageMemberOffset> class CDequeIterator : public CConstDequeIterator<TEntry, LinkageMemberOffset>
  402. {
  403. typedef CConstDequeIterator<TEntry, LinkageMemberOffset> Base;
  404. public:
  405. CDequeIterator(CDeque<TEntry, LinkageMemberOffset> *Deque = NULL) : Base(Deque) { }
  406. ~CDequeIterator() { }
  407. VOID Rebind(CDeque<TEntry, LinkageMemberOffset> *NewDeque)
  408. {
  409. FN_TRACE();
  410. if (m_pCurrent != NULL)
  411. {
  412. m_pCurrent->Unlock();
  413. m_pCurrent = NULL;
  414. }
  415. m_Deque = NewDeque;
  416. if (NewDeque != NULL)
  417. {
  418. m_pCurrent = this->GetFirstLinkage();
  419. m_pCurrent->Lock();
  420. }
  421. }
  422. TEntry *RemoveCurrent(DequeIteratorMovementDirection eDirection)
  423. {
  424. FN_TRACE();
  425. TEntry *Result = NULL;
  426. ASSERT(m_pCurrent != NULL);
  427. ASSERT(!m_Deque->IsHead(m_pCurrent));
  428. if ((m_pCurrent != NULL) && (!m_Deque->IsHead(m_pCurrent)))
  429. {
  430. Result = this->MapLinkageToEntry(m_pCurrent);
  431. this->Move(eDirection);
  432. const_cast<CDeque<TEntry, LinkageMemberOffset> *>(m_Deque)->Remove(Result);
  433. }
  434. return Result;
  435. }
  436. void DeleteCurrent(DequeIteratorMovementDirection eDirection)
  437. {
  438. FN_TRACE();
  439. TEntry *Result = this->RemoveCurrent(eDirection);
  440. if (Result != NULL)
  441. FUSION_DELETE_SINGLETON(Result);
  442. }
  443. protected:
  444. // All member data is in the parent...
  445. };
  446. #ifdef FN_TRACE_SHOULD_POP
  447. #pragma pop_macro("FN_TRACE")
  448. #undef FN_TRACE_SHOULD_POP
  449. #elif defined(FN_TRACE_SHOULD_DESTROY)
  450. #undef FN_TRACE
  451. #endif
  452. #ifdef FN_TRACE_CONSTRUCTOR_SHOULD_POP
  453. #pragma pop_macro("FN_TRACE_CONSTRUCTOR")
  454. #undef FN_TRACE_CONSTRUCTOR_SHOULD_POP
  455. #elif defined(FN_TRACE_CONSTRUCTOR_SHOULD_DESTROY)
  456. #undef FN_TRACE_CONSTRUCTOR
  457. #endif
  458. #ifdef FN_TRACE_DESTRUCTOR_SHOULD_POP
  459. #pragma pop_macro("FN_TRACE_DESTRUCTOR")
  460. #undef FN_TRACE_DESTRUCTOR_SHOULD_POP
  461. #elif defined(FN_TRACE_DESTRUCTOR_SHOULD_DESTROY)
  462. #undef FN_TRACE_DESTRUCTOR
  463. #endif