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.

561 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation, 1992 - 1997.
  4. //
  5. // File: DBLINK.HXX
  6. //
  7. // Contents: Parametrized doubly linked list and iterators
  8. //
  9. // History: 15-Jun-92 BartoszM Created.
  10. //
  11. //----------------------------------------------------------------------------
  12. #pragma once
  13. //+---------------------------------------------------------------------------
  14. //
  15. // Class: CDoubleLink
  16. //
  17. // Purpose: Linked element
  18. //
  19. // History: 15-Jun-92 BartoszM Created.
  20. //
  21. // Notes: Use as base for your class. No need to override anything.
  22. //
  23. // class CFoo: public CDoubleLink
  24. // {
  25. // // your data and code goes here
  26. // };
  27. //
  28. //----------------------------------------------------------------------------
  29. class CDoubleLink
  30. {
  31. public:
  32. CDoubleLink* Next() { return _next; }
  33. CDoubleLink* Prev() { return _prev; }
  34. void Close() { _next = this; _prev = this; }
  35. BOOL IsSingle() const { return _next == this; }
  36. void Unlink()
  37. {
  38. _next->_prev = _prev;
  39. _prev->_next = _next;
  40. }
  41. void InsertBefore ( CDoubleLink* pAfter )
  42. {
  43. CDoubleLink* pBefore = pAfter->_prev;
  44. _next = pAfter;
  45. _prev = pBefore;
  46. pAfter->_prev = this;
  47. pBefore->_next = this;
  48. }
  49. void InsertAfter ( CDoubleLink* pBefore )
  50. {
  51. CDoubleLink* pAfter = pBefore->_next;
  52. _next = pAfter;
  53. _prev = pBefore;
  54. pAfter->_prev = this;
  55. pBefore->_next = this;
  56. }
  57. #ifdef CIEXTMODE
  58. void CiExtDump(void *ciExtSelf);
  59. #endif
  60. protected:
  61. CDoubleLink* _next;
  62. CDoubleLink* _prev;
  63. };
  64. //+---------------------------------------------------------------------------
  65. //
  66. // Class: CDoubleList
  67. //
  68. // Purpose: Linked list of indexes
  69. //
  70. // History: 15-Jun-92 BartoszM Created.
  71. //
  72. // Notes: Use as base for your own class.
  73. // Add methods as needed.
  74. // To implement searches use forward and backward
  75. // iterators described below. For instance, if you implement
  76. // a SORTED list:
  77. //
  78. // Foo* CFooList::Insert ( CFoo* pFoo )
  79. // {
  80. // for ( CBackFooIter it(*this); !AtEnd(it); BackUp(it) )
  81. // {
  82. // if ( it->Size() <= pFoo->Size() ) // overloaded operator ->
  83. // {
  84. // pFoo->InsertAfter(it.GetFoo());
  85. // return;
  86. // }
  87. // }
  88. // // end of list
  89. // Push(pFoo);
  90. // }
  91. //
  92. //----------------------------------------------------------------------------
  93. class CDoubleList
  94. {
  95. friend class CForwardIter;
  96. friend class CBackwardIter;
  97. friend class CDoubleIter;
  98. public:
  99. class CDoubleIter
  100. {
  101. friend class CDoubleList;
  102. protected:
  103. CDoubleIter ( CDoubleLink* pLink ) : _pLinkCur(pLink) {}
  104. CDoubleIter ( CDoubleIter& iter ) : _pLinkCur(iter._pLinkCur) {}
  105. CDoubleLink* _pLinkCur;
  106. };
  107. CDoubleList()
  108. {
  109. _root.Close();
  110. }
  111. BOOL IsEmpty() const { return _root.IsSingle(); }
  112. void Advance ( CDoubleIter& it );
  113. void BackUp ( CDoubleIter& it );
  114. BOOL AtEnd ( CDoubleIter& it);
  115. void SetToEnd( CDoubleIter& it )
  116. {
  117. Win4Assert( !IsEmpty() );
  118. it._pLinkCur = _root.Prev();
  119. }
  120. void SetToBeginning( CDoubleIter& it )
  121. {
  122. Win4Assert( !IsEmpty() );
  123. it._pLinkCur = _root.Next();
  124. }
  125. BOOL IsFirst( CDoubleLink & link )
  126. {
  127. return _root.Next() == &link;
  128. }
  129. BOOL IsLast( CDoubleLink & link )
  130. {
  131. return _root.Prev() == &link;
  132. }
  133. BOOL IsFirst( CDoubleIter & it )
  134. {
  135. Win4Assert( !AtEnd( it ) );
  136. return _root.Next() == it._pLinkCur;
  137. }
  138. BOOL IsLast( CDoubleIter & it )
  139. {
  140. Win4Assert( !AtEnd(it) );
  141. return _root.Prev() == it._pLinkCur;
  142. }
  143. // In derived class you can add your own Pop(), Top(), etc.
  144. // that will cast the results of _Pop(), _Top(), etc...
  145. #ifdef CIEXTMODE
  146. void CiExtDump(void *ciExtSelf);
  147. #endif
  148. protected:
  149. CDoubleLink* _Top() { return IsEmpty()? 0: _root.Next(); }
  150. BOOL _IsRoot ( CDoubleLink* pLink ) const
  151. { return pLink == &_root; }
  152. void _Push ( CDoubleLink* pLink );
  153. void _Queue ( CDoubleLink* pLink );
  154. CDoubleLink* _Pop ( void );
  155. CDoubleLink * _Replace( CDoubleIter & it, CDoubleLink * pNew )
  156. {
  157. Win4Assert( !AtEnd(it) );
  158. Win4Assert( 0 != pNew );
  159. CDoubleLink * pCurr = it._pLinkCur;
  160. pNew->InsertAfter( pCurr );
  161. pCurr->Unlink();
  162. it._pLinkCur = pNew;
  163. return pCurr;
  164. }
  165. CDoubleLink _root;
  166. };
  167. //+---------------------------------------------------------------------------
  168. //
  169. // Class: CDoubleIter
  170. //
  171. // Purpose: Linked list iterator
  172. //
  173. // History: 17-Jun-92 BartoszM Created.
  174. //
  175. // Notes: Auxiliary class. See iterators below.
  176. //
  177. //----------------------------------------------------------------------------
  178. //+---------------------------------------------------------------------------
  179. //
  180. // Class: CForwardIter
  181. //
  182. // Purpose: Linked list iterator
  183. //
  184. // History: 17-Jun-92 BartoszM Created.
  185. //
  186. // Notes: Use as base for your own forward iterator.
  187. // Notice the overloading of operator ->
  188. // -------------------------------------
  189. // It lets you use iterator like a pointer to Foo.
  190. //
  191. // class CForFooIter : public CForwardIter
  192. // {
  193. // public:
  194. //
  195. // CForFooIter ( CFooList& list ) : CForwardIter(list) {}
  196. //
  197. // CFoo* operator->() { return (CFoo*) _pLinkCur; }
  198. // CFoo* GetFoo() { return (CFoo*) _pLinkCur; }
  199. // };
  200. //
  201. // Example of usage:
  202. // ----------------
  203. //
  204. // for ( CForFooIter it(fooList); !fooList.AtEnd(it); fooList.Advance(it))
  205. // {
  206. // it->FooMethod(); // operator ->
  207. // }
  208. //
  209. //----------------------------------------------------------------------------
  210. class CForwardIter: public CDoubleList::CDoubleIter
  211. {
  212. public:
  213. CForwardIter ( CDoubleList& list ): CDoubleIter(list._root.Next()) {}
  214. };
  215. //+---------------------------------------------------------------------------
  216. //
  217. // Class: CBackwardIter
  218. //
  219. // Purpose: Linked list iterator
  220. //
  221. // History: 17-Jun-92 BartoszM Created.
  222. //
  223. // Notes: See above.
  224. //
  225. //----------------------------------------------------------------------------
  226. class CBackwardIter: public CDoubleList::CDoubleIter
  227. {
  228. public:
  229. CBackwardIter ( CDoubleList& list ): CDoubleIter(list._root.Prev()) {}
  230. };
  231. //+---------------------------------------------------------------------------
  232. //
  233. // Member: CDoubleList::AtEnd, public
  234. //
  235. // Arguments: [it] -- iterator
  236. //
  237. // Returns: TRUE if iterator at end of list
  238. //
  239. // History: 17-Jun-92 BartoszM Created.
  240. //
  241. // Notes: Works for both iterators (forward and backward)
  242. //
  243. //----------------------------------------------------------------------------
  244. inline BOOL CDoubleList::AtEnd ( CDoubleIter& it)
  245. {
  246. return _IsRoot( it._pLinkCur );
  247. }
  248. //+---------------------------------------------------------------------------
  249. //
  250. // Member: CDoubleList::Advance, public
  251. //
  252. // Synopsis: Advances an iterator
  253. //
  254. // Arguments: [it] -- iterator
  255. //
  256. // History: 17-Jun-92 BartoszM Created.
  257. //
  258. //----------------------------------------------------------------------------
  259. inline void CDoubleList::Advance ( CDoubleIter& it )
  260. {
  261. Win4Assert ( !_IsRoot(it._pLinkCur) );
  262. it._pLinkCur = it._pLinkCur->Next();
  263. }
  264. //+---------------------------------------------------------------------------
  265. //
  266. // Member: CDoubleList::BackUp, public
  267. //
  268. // Synopsis: Backs up an iterator
  269. //
  270. // Arguments: [it] -- iterator
  271. //
  272. // History: 17-Jun-92 BartoszM Created.
  273. //
  274. //----------------------------------------------------------------------------
  275. inline void CDoubleList::BackUp ( CDoubleIter& it )
  276. {
  277. Win4Assert ( !_IsRoot(it._pLinkCur) );
  278. it._pLinkCur = it._pLinkCur->Prev();
  279. }
  280. //+---------------------------------------------------------------------------
  281. //
  282. // Member: CDoubleList::Queue, private
  283. //
  284. // Arguments: [pLink] -- link to be queued
  285. //
  286. // History: 17-Mar-93 WadeR Created. (based on Push, below)
  287. //
  288. // Notest: Override, accept only derived class (type safety!), e.g.
  289. //
  290. // void CFooList::Queue ( CFoo* pFoo )
  291. // {
  292. // _Queue ( pFoo );
  293. // }
  294. //
  295. //----------------------------------------------------------------------------
  296. inline void CDoubleList::_Queue ( CDoubleLink* pLink )
  297. {
  298. pLink->InsertBefore ( &_root );
  299. }
  300. //+---------------------------------------------------------------------------
  301. //
  302. // Member: CDoubleList::Push, private
  303. //
  304. // Arguments: [pLink] -- link to be pushed
  305. //
  306. // History: 17-Jun-92 BartoszM Created.
  307. //
  308. // Notest: Override, accept only derived class (type safety!), e.g.
  309. //
  310. // void CFooList::Push ( CFoo* pFoo )
  311. // {
  312. // _Push ( pFoo );
  313. // }
  314. //
  315. //----------------------------------------------------------------------------
  316. inline void CDoubleList::_Push ( CDoubleLink* pLink )
  317. {
  318. pLink->InsertAfter ( &_root );
  319. }
  320. //+---------------------------------------------------------------------------
  321. //
  322. // Member: CDoubleList::_Pop, private
  323. //
  324. // History: 17-Jun-92 BartoszM Created.
  325. //
  326. // Notes: Override: cast the result
  327. //
  328. // CFoo* CFooList::Pop()
  329. // {
  330. // return (CFoo*) _Pop();
  331. // }
  332. //
  333. //----------------------------------------------------------------------------
  334. inline CDoubleLink* CDoubleList::_Pop ( void )
  335. {
  336. CDoubleLink* pLink = 0;
  337. if ( !IsEmpty() )
  338. {
  339. pLink = _root.Next();
  340. pLink->Unlink();
  341. }
  342. return pLink;
  343. }
  344. template <class T>
  345. class TDoubleList : public CDoubleList
  346. {
  347. public:
  348. TDoubleList() : _cEntries(0) {}
  349. ~TDoubleList()
  350. {
  351. Clear();
  352. }
  353. T * Top()
  354. {
  355. return (T *) _Top();
  356. }
  357. BOOL IsRoot(T * pLink)
  358. {
  359. return _IsRoot( pLink );
  360. }
  361. void Push( T * pLink )
  362. {
  363. Win4Assert( 0 != pLink );
  364. _Push( pLink );
  365. _cEntries++;
  366. }
  367. void Queue( T * pLink )
  368. {
  369. Win4Assert( 0 != pLink );
  370. _Queue( pLink );
  371. _cEntries++;
  372. }
  373. T * Pop()
  374. {
  375. if ( _cEntries )
  376. {
  377. _cEntries--;
  378. }
  379. return (T *) _Pop();
  380. }
  381. T * GetFirst()
  382. {
  383. return !IsEmpty() ? (T * ) _root.Next() : 0 ;
  384. }
  385. T * GetLast()
  386. {
  387. if ( IsEmpty() )
  388. return 0;
  389. else
  390. return (T *) _root.Prev();
  391. }
  392. T * GetIth( ULONG i )
  393. {
  394. //
  395. // Return ith entry
  396. //
  397. Win4Assert( i < _cEntries );
  398. CDoubleLink *pLink = _root.Next();
  399. while ( i != 0 )
  400. {
  401. pLink = pLink->Next();
  402. i--;
  403. }
  404. return (T *) pLink;
  405. }
  406. T * RemoveLast()
  407. {
  408. T * pEntry = 0;
  409. if ( !IsEmpty() )
  410. {
  411. pEntry = (T *) _root.Prev();
  412. pEntry->Unlink();
  413. Win4Assert( _cEntries > 0 );
  414. _cEntries--;
  415. }
  416. else
  417. {
  418. //
  419. // NOTE: Some clients of this class may increment, but never decrement
  420. // this count. This could happen by directly invoking the Unlink
  421. // method on a list element instead of using the RemoveFromList
  422. // method which maintains the entry count.
  423. //
  424. Win4Assert( _cEntries == 0 );
  425. }
  426. return pEntry;
  427. }
  428. void RemoveFromList( T * pEntry )
  429. {
  430. pEntry->Unlink();
  431. Win4Assert( _cEntries > 0 );
  432. _cEntries--;
  433. }
  434. void MoveToFront( T * pLink )
  435. {
  436. pLink->Unlink();
  437. _Push( pLink );
  438. }
  439. void Clear()
  440. {
  441. while ( Count() > 0 )
  442. {
  443. T *pLink = Pop();
  444. delete pLink;
  445. }
  446. }
  447. unsigned Count() const { return _cEntries; }
  448. private:
  449. unsigned _cEntries;
  450. };
  451. template <class T, class TList>
  452. class TFwdListIter : public CForwardIter
  453. {
  454. public:
  455. TFwdListIter ( TList & list ) : CForwardIter(list) {}
  456. T* operator->() { return (T*) _pLinkCur; }
  457. T* GetEntry() { return (T*) _pLinkCur; }
  458. };
  459. template <class T, class TList>
  460. class TBackListIter : public CBackwardIter
  461. {
  462. public:
  463. TBackListIter ( TList & list ) : CBackwardIter(list) {}
  464. T* operator->() { return (T*) _pLinkCur; }
  465. T* GetEntry() { return (T*) _pLinkCur; }
  466. };