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.

673 lines
19 KiB

  1. #ifndef __CLIST_HPP__
  2. #define __CLIST_HPP__
  3. #include <limits.h>
  4. #include <string.h>
  5. // "Borrowed" from MFC
  6. #ifdef _DEBUG
  7. #define ASSERT_VALID(p) AssertValid()
  8. #else
  9. #define ASSERT_VALID(p) ((void)0)
  10. #endif
  11. #ifndef ASSERT
  12. #define ASSERT(x)
  13. #endif
  14. #ifndef AFXAPI
  15. #define AFXAPI __stdcall
  16. #endif
  17. typedef void* LISTPOSITION; // abstract iteration position
  18. #ifdef __cplusplus
  19. BOOL AFXAPI AfxIsValidAddress(const void* lp,
  20. UINT nBytes, BOOL bReadWrite = TRUE);
  21. struct CPlex // warning variable length structure
  22. {
  23. CPlex* pNext;
  24. UINT nMax;
  25. UINT nCur;
  26. /* BYTE data[maxNum*elementSize]; */
  27. void* data() { return this+1; }
  28. static CPlex* PASCAL Create(CPlex*& head, UINT nMax, UINT cbElement);
  29. // like 'calloc' but no zero fill
  30. // may throw memory exceptions
  31. void FreeDataChain(); // free this one and links
  32. };
  33. #ifdef _global_helper_
  34. /////////////////////////////////////////////////////////////////////////////
  35. // global helpers (can be overridden)
  36. template<class TYPE>
  37. inline void AFXAPI ConstructElements(TYPE* pElements, int nCount)
  38. {
  39. ASSERT(nCount == 0 ||
  40. AfxIsValidAddress(pElements, nCount * sizeof(TYPE)));
  41. // default is bit-wise zero initialization
  42. memset((void*)pElements, 0, nCount * sizeof(TYPE));
  43. }
  44. template<class TYPE>
  45. inline void AFXAPI DestructElements(TYPE* pElements, int nCount)
  46. {
  47. ASSERT(nCount == 0 ||
  48. AfxIsValidAddress(pElements, nCount * sizeof(TYPE)));
  49. pElements;
  50. nCount;
  51. }
  52. /* No need to serialize the list
  53. template<class TYPE>
  54. void AFXAPI SerializeElements(CArchive& ar, TYPE* pElements, int nCount)
  55. {
  56. ASSERT(nCount == 0 ||
  57. AfxIsValidAddress(pElements, nCount * sizeof(TYPE)));
  58. // default is bit-wise read/write
  59. if (ar.IsStoring())
  60. ar.Write((void*)pElements, nCount * sizeof(TYPE));
  61. else
  62. ar.Read((void*)pElements, nCount * sizeof(TYPE));
  63. }
  64. */
  65. /* No need for debug dumping
  66. #ifdef _DEBUG
  67. template<class TYPE>
  68. void AFXAPI DumpElements(CDumpContext& dc, const TYPE* pElements, int nCount)
  69. {
  70. ASSERT(nCount == 0 ||
  71. AfxIsValidAddress(pElements, nCount * sizeof(TYPE)));
  72. dc; // not used
  73. pElements; // not used
  74. nCount; // not used
  75. // default does nothing
  76. }
  77. #endif
  78. */
  79. template<class TYPE, class ARG_TYPE>
  80. BOOL AFXAPI CompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
  81. {
  82. ASSERT(AfxIsValidAddress(pElement1, sizeof(TYPE)));
  83. ASSERT(AfxIsValidAddress(pElement2, sizeof(ARG_TYPE)));
  84. return *pElement1 == *pElement2;
  85. }
  86. template<class ARG_KEY>
  87. inline UINT AFXAPI HashKey(ARG_KEY key)
  88. {
  89. // default identity hash - works for most primitive values
  90. return ((UINT)(void*)(DWORD)key) >> 4;
  91. }
  92. #endif // _global_helper_
  93. /////////////////////////////////////////////////////////////////////////////
  94. // CList<TYPE, ARG_TYPE>
  95. template<class TYPE, class ARG_TYPE>
  96. class CList
  97. {
  98. #ifndef unix
  99. protected:
  100. #else
  101. // If this was not made public we get complier warnings
  102. // that CList<T,A>::CNode is not accessible from file scope
  103. // which means functions cant return CNode pointers
  104. public:
  105. #endif /* unix */
  106. struct CNode
  107. {
  108. CNode* pNext;
  109. CNode* pPrev;
  110. TYPE data;
  111. };
  112. public:
  113. // Construction
  114. CList(int nBlockSize = 10);
  115. // Attributes (head and tail)
  116. // count of elements
  117. int GetCount() const;
  118. BOOL IsEmpty() const;
  119. // peek at head or tail
  120. TYPE& GetHead();
  121. TYPE GetHead() const;
  122. TYPE& GetTail();
  123. TYPE GetTail() const;
  124. // Operations
  125. // get head or tail (and remove it) - don't call on empty list !
  126. TYPE RemoveHead();
  127. TYPE RemoveTail();
  128. // add before head or after tail
  129. LISTPOSITION AddHead(ARG_TYPE newElement);
  130. LISTPOSITION AddTail(ARG_TYPE newElement);
  131. // add another list of elements before head or after tail
  132. void AddHead(CList* pNewList);
  133. void AddTail(CList* pNewList);
  134. // remove all elements
  135. void RemoveAll();
  136. // iteration
  137. LISTPOSITION GetHeadPosition() const;
  138. LISTPOSITION GetTailPosition() const;
  139. TYPE& GetNext(LISTPOSITION& rPosition); // return *Position++
  140. TYPE GetNext(LISTPOSITION& rPosition) const; // return *Position++
  141. TYPE& GetPrev(LISTPOSITION& rPosition); // return *Position--
  142. TYPE GetPrev(LISTPOSITION& rPosition) const; // return *Position--
  143. // getting/modifying an element at a given position
  144. TYPE& GetAt(LISTPOSITION position);
  145. TYPE GetAt(LISTPOSITION position) const;
  146. void SetAt(LISTPOSITION pos, ARG_TYPE newElement);
  147. void RemoveAt(LISTPOSITION position);
  148. // inserting before or after a given position
  149. LISTPOSITION InsertBefore(LISTPOSITION position, ARG_TYPE newElement);
  150. LISTPOSITION InsertAfter(LISTPOSITION position, ARG_TYPE newElement);
  151. // helper functions (note: O(n) speed)
  152. LISTPOSITION Find(ARG_TYPE searchValue, LISTPOSITION startAfter = NULL) const;
  153. // defaults to starting at the HEAD, return NULL if not found
  154. LISTPOSITION FindIndex(int nIndex) const;
  155. // get the 'nIndex'th element (may return NULL)
  156. // Implementation
  157. protected:
  158. CNode* m_pNodeHead;
  159. CNode* m_pNodeTail;
  160. int m_nCount;
  161. CNode* m_pNodeFree;
  162. struct CPlex* m_pBlocks;
  163. int m_nBlockSize;
  164. CNode* NewNode(CNode*, CNode*);
  165. void FreeNode(CNode*);
  166. public:
  167. ~CList();
  168. // void Serialize(CArchive&);
  169. #ifdef _DEBUG
  170. // void Dump(CDumpContext&) const;
  171. void AssertValid() const;
  172. #endif
  173. };
  174. /////////////////////////////////////////////////////////////////////////////
  175. // CList<TYPE, ARG_TYPE> inline functions
  176. template<class TYPE, class ARG_TYPE>
  177. inline int CList<TYPE, ARG_TYPE>::GetCount() const
  178. { return m_nCount; }
  179. template<class TYPE, class ARG_TYPE>
  180. inline BOOL CList<TYPE, ARG_TYPE>::IsEmpty() const
  181. { return m_nCount == 0; }
  182. template<class TYPE, class ARG_TYPE>
  183. inline TYPE& CList<TYPE, ARG_TYPE>::GetHead()
  184. { ASSERT(m_pNodeHead != NULL);
  185. return m_pNodeHead->data; }
  186. template<class TYPE, class ARG_TYPE>
  187. inline TYPE CList<TYPE, ARG_TYPE>::GetHead() const
  188. { ASSERT(m_pNodeHead != NULL);
  189. return m_pNodeHead->data; }
  190. template<class TYPE, class ARG_TYPE>
  191. inline TYPE& CList<TYPE, ARG_TYPE>::GetTail()
  192. { ASSERT(m_pNodeTail != NULL);
  193. return m_pNodeTail->data; }
  194. template<class TYPE, class ARG_TYPE>
  195. inline TYPE CList<TYPE, ARG_TYPE>::GetTail() const
  196. { ASSERT(m_pNodeTail != NULL);
  197. return m_pNodeTail->data; }
  198. template<class TYPE, class ARG_TYPE>
  199. inline LISTPOSITION CList<TYPE, ARG_TYPE>::GetHeadPosition() const
  200. { return (LISTPOSITION) m_pNodeHead; }
  201. template<class TYPE, class ARG_TYPE>
  202. inline LISTPOSITION CList<TYPE, ARG_TYPE>::GetTailPosition() const
  203. { return (LISTPOSITION) m_pNodeTail; }
  204. template<class TYPE, class ARG_TYPE>
  205. inline TYPE& CList<TYPE, ARG_TYPE>::GetNext(LISTPOSITION& rPosition) // return *Position++
  206. { CNode* pNode = (CNode*) rPosition;
  207. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  208. rPosition = (LISTPOSITION) pNode->pNext;
  209. return pNode->data; }
  210. template<class TYPE, class ARG_TYPE>
  211. inline TYPE CList<TYPE, ARG_TYPE>::GetNext(LISTPOSITION& rPosition) const // return *Position++
  212. { CNode* pNode = (CNode*) rPosition;
  213. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  214. rPosition = (LISTPOSITION) pNode->pNext;
  215. return pNode->data; }
  216. template<class TYPE, class ARG_TYPE>
  217. inline TYPE& CList<TYPE, ARG_TYPE>::GetPrev(LISTPOSITION& rPosition) // return *Position--
  218. { CNode* pNode = (CNode*) rPosition;
  219. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  220. rPosition = (LISTPOSITION) pNode->pPrev;
  221. return pNode->data; }
  222. template<class TYPE, class ARG_TYPE>
  223. inline TYPE CList<TYPE, ARG_TYPE>::GetPrev(LISTPOSITION& rPosition) const // return *Position--
  224. { CNode* pNode = (CNode*) rPosition;
  225. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  226. rPosition = (LISTPOSITION) pNode->pPrev;
  227. return pNode->data; }
  228. template<class TYPE, class ARG_TYPE>
  229. inline TYPE& CList<TYPE, ARG_TYPE>::GetAt(LISTPOSITION position)
  230. { CNode* pNode = (CNode*) position;
  231. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  232. return pNode->data; }
  233. template<class TYPE, class ARG_TYPE>
  234. inline TYPE CList<TYPE, ARG_TYPE>::GetAt(LISTPOSITION position) const
  235. { CNode* pNode = (CNode*) position;
  236. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  237. return pNode->data; }
  238. template<class TYPE, class ARG_TYPE>
  239. inline void CList<TYPE, ARG_TYPE>::SetAt(LISTPOSITION pos, ARG_TYPE newElement)
  240. { CNode* pNode = (CNode*) pos;
  241. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  242. pNode->data = newElement; }
  243. template<class TYPE, class ARG_TYPE>
  244. CList<TYPE, ARG_TYPE>::CList(int nBlockSize)
  245. {
  246. ASSERT(nBlockSize > 0);
  247. m_nCount = 0;
  248. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  249. m_pBlocks = NULL;
  250. m_nBlockSize = nBlockSize;
  251. }
  252. template<class TYPE, class ARG_TYPE>
  253. void CList<TYPE, ARG_TYPE>::RemoveAll()
  254. {
  255. ASSERT_VALID(this);
  256. // destroy elements
  257. CNode* pNode;
  258. for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  259. DestructElements(&pNode->data, 1);
  260. m_nCount = 0;
  261. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  262. m_pBlocks->FreeDataChain();
  263. m_pBlocks = NULL;
  264. }
  265. template<class TYPE, class ARG_TYPE>
  266. CList<TYPE, ARG_TYPE>::~CList()
  267. {
  268. RemoveAll();
  269. ASSERT(m_nCount == 0);
  270. }
  271. /////////////////////////////////////////////////////////////////////////////
  272. // Node helpers
  273. //
  274. // Implementation note: CNode's are stored in CPlex blocks and
  275. // chained together. Free blocks are maintained in a singly linked list
  276. // using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
  277. // Used blocks are maintained in a doubly linked list using both 'pNext'
  278. // and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
  279. // as the head/tail.
  280. //
  281. // We never free a CPlex block unless the List is destroyed or RemoveAll()
  282. // is used - so the total number of CPlex blocks may grow large depending
  283. // on the maximum past size of the list.
  284. //
  285. template<class TYPE, class ARG_TYPE>
  286. typename CList<TYPE, ARG_TYPE>::CNode*
  287. CList<TYPE, ARG_TYPE>::NewNode(CNode* pPrev, CNode* pNext)
  288. {
  289. if (m_pNodeFree == NULL)
  290. {
  291. // add another block
  292. CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize,
  293. sizeof(CNode));
  294. // chain them into free list
  295. CNode* pNode = (CNode*) pNewBlock->data();
  296. // free in reverse order to make it easier to debug
  297. pNode += m_nBlockSize - 1;
  298. for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
  299. {
  300. pNode->pNext = m_pNodeFree;
  301. m_pNodeFree = pNode;
  302. }
  303. }
  304. ASSERT(m_pNodeFree != NULL); // we must have something
  305. CList::CNode* pNode = m_pNodeFree;
  306. m_pNodeFree = m_pNodeFree->pNext;
  307. pNode->pPrev = pPrev;
  308. pNode->pNext = pNext;
  309. m_nCount++;
  310. ASSERT(m_nCount > 0); // make sure we don't overflow
  311. ConstructElements(&pNode->data, 1);
  312. return pNode;
  313. }
  314. template<class TYPE, class ARG_TYPE>
  315. void CList<TYPE, ARG_TYPE>::FreeNode(CNode* pNode)
  316. {
  317. DestructElements(&pNode->data, 1);
  318. pNode->pNext = m_pNodeFree;
  319. m_pNodeFree = pNode;
  320. m_nCount--;
  321. ASSERT(m_nCount >= 0); // make sure we don't underflow
  322. }
  323. template<class TYPE, class ARG_TYPE>
  324. LISTPOSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
  325. {
  326. ASSERT_VALID(this);
  327. CNode* pNewNode = NewNode(NULL, m_pNodeHead);
  328. pNewNode->data = newElement;
  329. if (m_pNodeHead != NULL)
  330. m_pNodeHead->pPrev = pNewNode;
  331. else
  332. m_pNodeTail = pNewNode;
  333. m_pNodeHead = pNewNode;
  334. return (LISTPOSITION) pNewNode;
  335. }
  336. template<class TYPE, class ARG_TYPE>
  337. LISTPOSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
  338. {
  339. ASSERT_VALID(this);
  340. CNode* pNewNode = NewNode(m_pNodeTail, NULL);
  341. pNewNode->data = newElement;
  342. if (m_pNodeTail != NULL)
  343. m_pNodeTail->pNext = pNewNode;
  344. else
  345. m_pNodeHead = pNewNode;
  346. m_pNodeTail = pNewNode;
  347. return (LISTPOSITION) pNewNode;
  348. }
  349. template<class TYPE, class ARG_TYPE>
  350. void CList<TYPE, ARG_TYPE>::AddHead(CList* pNewList)
  351. {
  352. ASSERT_VALID(this);
  353. ASSERT(pNewList != NULL);
  354. ASSERT_VALID(pNewList);
  355. // add a list of same elements to head (maintain order)
  356. LISTPOSITION pos = pNewList->GetTailPosition();
  357. while (pos != NULL)
  358. AddHead(pNewList->GetPrev(pos));
  359. }
  360. template<class TYPE, class ARG_TYPE>
  361. void CList<TYPE, ARG_TYPE>::AddTail(CList* pNewList)
  362. {
  363. ASSERT_VALID(this);
  364. ASSERT(pNewList != NULL);
  365. ASSERT_VALID(pNewList);
  366. // add a list of same elements
  367. LISTPOSITION pos = pNewList->GetHeadPosition();
  368. while (pos != NULL)
  369. AddTail(pNewList->GetNext(pos));
  370. }
  371. template<class TYPE, class ARG_TYPE>
  372. TYPE CList<TYPE, ARG_TYPE>::RemoveHead()
  373. {
  374. ASSERT_VALID(this);
  375. ASSERT(m_pNodeHead != NULL); // don't call on empty list !!!
  376. ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  377. CNode* pOldNode = m_pNodeHead;
  378. TYPE returnValue = pOldNode->data;
  379. m_pNodeHead = pOldNode->pNext;
  380. if (m_pNodeHead != NULL)
  381. m_pNodeHead->pPrev = NULL;
  382. else
  383. m_pNodeTail = NULL;
  384. FreeNode(pOldNode);
  385. return returnValue;
  386. }
  387. template<class TYPE, class ARG_TYPE>
  388. TYPE CList<TYPE, ARG_TYPE>::RemoveTail()
  389. {
  390. ASSERT_VALID(this);
  391. ASSERT(m_pNodeTail != NULL); // don't call on empty list !!!
  392. ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  393. CNode* pOldNode = m_pNodeTail;
  394. TYPE returnValue = pOldNode->data;
  395. m_pNodeTail = pOldNode->pPrev;
  396. if (m_pNodeTail != NULL)
  397. m_pNodeTail->pNext = NULL;
  398. else
  399. m_pNodeHead = NULL;
  400. FreeNode(pOldNode);
  401. return returnValue;
  402. }
  403. template<class TYPE, class ARG_TYPE>
  404. LISTPOSITION CList<TYPE, ARG_TYPE>::InsertBefore(LISTPOSITION position, ARG_TYPE newElement)
  405. {
  406. ASSERT_VALID(this);
  407. if (position == NULL)
  408. return AddHead(newElement); // insert before nothing -> head of the list
  409. // Insert it before position
  410. CNode* pOldNode = (CNode*) position;
  411. CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
  412. pNewNode->data = newElement;
  413. if (pOldNode->pPrev != NULL)
  414. {
  415. ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  416. pOldNode->pPrev->pNext = pNewNode;
  417. }
  418. else
  419. {
  420. ASSERT(pOldNode == m_pNodeHead);
  421. m_pNodeHead = pNewNode;
  422. }
  423. pOldNode->pPrev = pNewNode;
  424. return (LISTPOSITION) pNewNode;
  425. }
  426. template<class TYPE, class ARG_TYPE>
  427. LISTPOSITION CList<TYPE, ARG_TYPE>::InsertAfter(LISTPOSITION position, ARG_TYPE newElement)
  428. {
  429. ASSERT_VALID(this);
  430. if (position == NULL)
  431. return AddTail(newElement); // insert after nothing -> tail of the list
  432. // Insert it before position
  433. CNode* pOldNode = (CNode*) position;
  434. ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  435. CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
  436. pNewNode->data = newElement;
  437. if (pOldNode->pNext != NULL)
  438. {
  439. ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  440. pOldNode->pNext->pPrev = pNewNode;
  441. }
  442. else
  443. {
  444. ASSERT(pOldNode == m_pNodeTail);
  445. m_pNodeTail = pNewNode;
  446. }
  447. pOldNode->pNext = pNewNode;
  448. return (LISTPOSITION) pNewNode;
  449. }
  450. template<class TYPE, class ARG_TYPE>
  451. void CList<TYPE, ARG_TYPE>::RemoveAt(LISTPOSITION position)
  452. {
  453. ASSERT_VALID(this);
  454. CNode* pOldNode = (CNode*) position;
  455. ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  456. // remove pOldNode from list
  457. if (pOldNode == m_pNodeHead)
  458. {
  459. m_pNodeHead = pOldNode->pNext;
  460. }
  461. else
  462. {
  463. ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  464. pOldNode->pPrev->pNext = pOldNode->pNext;
  465. }
  466. if (pOldNode == m_pNodeTail)
  467. {
  468. m_pNodeTail = pOldNode->pPrev;
  469. }
  470. else
  471. {
  472. ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  473. pOldNode->pNext->pPrev = pOldNode->pPrev;
  474. }
  475. FreeNode(pOldNode);
  476. }
  477. template<class TYPE, class ARG_TYPE>
  478. LISTPOSITION CList<TYPE, ARG_TYPE>::FindIndex(int nIndex) const
  479. {
  480. ASSERT_VALID(this);
  481. ASSERT(nIndex >= 0);
  482. if (nIndex >= m_nCount)
  483. return NULL; // went too far
  484. CNode* pNode = m_pNodeHead;
  485. while (nIndex--)
  486. {
  487. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  488. pNode = pNode->pNext;
  489. }
  490. return (LISTPOSITION) pNode;
  491. }
  492. template<class TYPE, class ARG_TYPE>
  493. LISTPOSITION CList<TYPE, ARG_TYPE>::Find(ARG_TYPE searchValue, LISTPOSITION startAfter) const
  494. {
  495. ASSERT_VALID(this);
  496. CNode* pNode = (CNode*) startAfter;
  497. if (pNode == NULL)
  498. {
  499. pNode = m_pNodeHead; // start at head
  500. }
  501. else
  502. {
  503. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  504. pNode = pNode->pNext; // start after the one specified
  505. }
  506. for (; pNode != NULL; pNode = pNode->pNext)
  507. if (CompareElements(&pNode->data, &searchValue))
  508. return (LISTPOSITION)pNode;
  509. return NULL;
  510. }
  511. #if 0 // Member was comment'd out in the class definition
  512. template<class TYPE, class ARG_TYPE>
  513. void CList<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  514. {
  515. ASSERT_VALID(this);
  516. CObject::Serialize(ar);
  517. if (ar.IsStoring())
  518. {
  519. ar << (WORD) m_nCount;
  520. for (CNode* pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  521. {
  522. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  523. SerializeElements(ar, &pNode->data, 1);
  524. }
  525. }
  526. else
  527. {
  528. WORD nNewCount;
  529. ar >> nNewCount;
  530. TYPE newData;
  531. while (nNewCount--)
  532. {
  533. SerializeElements(ar, &newData, 1);
  534. AddTail(newData);
  535. }
  536. }
  537. }
  538. #endif
  539. #ifdef _DEBUG
  540. template<class TYPE, class ARG_TYPE>
  541. void CList<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
  542. {
  543. CObject::Dump(dc);
  544. dc << "with " << m_nCount << " elements";
  545. if (dc.GetDepth() > 0)
  546. {
  547. LISTPOSITION pos = GetHeadPosition();
  548. while (pos != NULL)
  549. {
  550. dc << "\n";
  551. DumpElements(dc, &((CList*)this)->GetNext(pos), 1);
  552. }
  553. }
  554. dc << "\n";
  555. }
  556. template<class TYPE, class ARG_TYPE>
  557. void CList<TYPE, ARG_TYPE>::AssertValid() const
  558. {
  559. // CObject::AssertValid();
  560. if (m_nCount == 0)
  561. {
  562. // empty list
  563. ASSERT(m_pNodeHead == NULL);
  564. ASSERT(m_pNodeTail == NULL);
  565. }
  566. else
  567. {
  568. // non-empty list
  569. ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  570. ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  571. }
  572. }
  573. #endif //_DEBUG
  574. #endif // __cplusplus
  575. #endif // __CLIST_HPP__