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.

335 lines
7.4 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: ptrlist.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #define ASSERT_VALID(ptr) /*ptr*/
  12. MMC::CPtrList::CPtrList(int nBlockSize)
  13. {
  14. ASSERT(nBlockSize > 0);
  15. m_nCount = 0;
  16. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  17. m_pBlocks = NULL;
  18. m_nBlockSize = nBlockSize;
  19. }
  20. void MMC::CPtrList::RemoveAll()
  21. {
  22. ASSERT_VALID(this);
  23. // destroy elements
  24. m_nCount = 0;
  25. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  26. m_pBlocks->FreeDataChain();
  27. m_pBlocks = NULL;
  28. }
  29. MMC::CPtrList::~CPtrList()
  30. {
  31. RemoveAll();
  32. ASSERT(m_nCount == 0);
  33. }
  34. /////////////////////////////////////////////////////////////////////////////
  35. // Node helpers
  36. /*
  37. * Implementation note: CNode's are stored in CPlex blocks and
  38. * chained together. Free blocks are maintained in a singly linked list
  39. * using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
  40. * Used blocks are maintained in a doubly linked list using both 'pNext'
  41. * and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
  42. * as the head/tail.
  43. *
  44. * We never free a CPlex block unless the List is destroyed or RemoveAll()
  45. * is used - so the total number of CPlex blocks may grow large depending
  46. * on the maximum past size of the list.
  47. */
  48. MMC::CPtrList::CNode*
  49. MMC::CPtrList::NewNode(MMC::CPtrList::CNode* pPrev, MMC::CPtrList::CNode* pNext)
  50. {
  51. if (m_pNodeFree == NULL)
  52. {
  53. // add another block
  54. CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize,
  55. sizeof(CNode));
  56. // chain them into free list
  57. CNode* pNode = (CNode*) pNewBlock->data();
  58. // free in reverse order to make it easier to debug
  59. pNode += m_nBlockSize - 1;
  60. for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
  61. {
  62. pNode->pNext = m_pNodeFree;
  63. m_pNodeFree = pNode;
  64. }
  65. }
  66. ASSERT(m_pNodeFree != NULL); // we must have something
  67. MMC::CPtrList::CNode* pNode = m_pNodeFree;
  68. m_pNodeFree = m_pNodeFree->pNext;
  69. pNode->pPrev = pPrev;
  70. pNode->pNext = pNext;
  71. m_nCount++;
  72. ASSERT(m_nCount > 0); // make sure we don't overflow
  73. memset(&pNode->data, 0, sizeof(void*)); // zero fill
  74. return pNode;
  75. }
  76. void MMC::CPtrList::FreeNode(MMC::CPtrList::CNode* pNode)
  77. {
  78. pNode->pNext = m_pNodeFree;
  79. m_pNodeFree = pNode;
  80. m_nCount--;
  81. ASSERT(m_nCount >= 0); // make sure we don't underflow
  82. }
  83. /////////////////////////////////////////////////////////////////////////////
  84. POSITION MMC::CPtrList::AddHead(void* newElement)
  85. {
  86. ASSERT_VALID(this);
  87. CNode* pNewNode = NewNode(NULL, m_pNodeHead);
  88. pNewNode->data = newElement;
  89. if (m_pNodeHead != NULL)
  90. m_pNodeHead->pPrev = pNewNode;
  91. else
  92. m_pNodeTail = pNewNode;
  93. m_pNodeHead = pNewNode;
  94. return (POSITION) pNewNode;
  95. }
  96. POSITION MMC::CPtrList::AddTail(void* newElement)
  97. {
  98. ASSERT_VALID(this);
  99. CNode* pNewNode = NewNode(m_pNodeTail, NULL);
  100. pNewNode->data = newElement;
  101. if (m_pNodeTail != NULL)
  102. m_pNodeTail->pNext = pNewNode;
  103. else
  104. m_pNodeHead = pNewNode;
  105. m_pNodeTail = pNewNode;
  106. return (POSITION) pNewNode;
  107. }
  108. void MMC::CPtrList::AddHead(CPtrList* pNewList)
  109. {
  110. ASSERT_VALID(this);
  111. ASSERT(pNewList != NULL);
  112. ASSERT_VALID(pNewList);
  113. // add a list of same elements to head (maintain order)
  114. POSITION pos = pNewList->GetTailPosition();
  115. while (pos != NULL)
  116. AddHead(pNewList->GetPrev(pos));
  117. }
  118. void MMC::CPtrList::AddTail(CPtrList* pNewList)
  119. {
  120. ASSERT_VALID(this);
  121. ASSERT(pNewList != NULL);
  122. ASSERT_VALID(pNewList);
  123. // add a list of same elements
  124. POSITION pos = pNewList->GetHeadPosition();
  125. while (pos != NULL)
  126. AddTail(pNewList->GetNext(pos));
  127. }
  128. void* MMC::CPtrList::RemoveHead()
  129. {
  130. ASSERT_VALID(this);
  131. ASSERT(m_pNodeHead != NULL); // don't call on empty list !!!
  132. ASSERT(_IsValidAddress(m_pNodeHead, sizeof(CNode)));
  133. CNode* pOldNode = m_pNodeHead;
  134. void* returnValue = pOldNode->data;
  135. m_pNodeHead = pOldNode->pNext;
  136. if (m_pNodeHead != NULL)
  137. m_pNodeHead->pPrev = NULL;
  138. else
  139. m_pNodeTail = NULL;
  140. FreeNode(pOldNode);
  141. return returnValue;
  142. }
  143. void* MMC::CPtrList::RemoveTail()
  144. {
  145. ASSERT_VALID(this);
  146. ASSERT(m_pNodeTail != NULL); // don't call on empty list !!!
  147. ASSERT(_IsValidAddress(m_pNodeTail, sizeof(CNode)));
  148. CNode* pOldNode = m_pNodeTail;
  149. void* returnValue = pOldNode->data;
  150. m_pNodeTail = pOldNode->pPrev;
  151. if (m_pNodeTail != NULL)
  152. m_pNodeTail->pNext = NULL;
  153. else
  154. m_pNodeHead = NULL;
  155. FreeNode(pOldNode);
  156. return returnValue;
  157. }
  158. POSITION MMC::CPtrList::InsertBefore(POSITION position, void* newElement)
  159. {
  160. ASSERT_VALID(this);
  161. if (position == NULL)
  162. return AddHead(newElement); // insert before nothing -> head of the list
  163. // Insert it before position
  164. CNode* pOldNode = (CNode*) position;
  165. CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
  166. pNewNode->data = newElement;
  167. if (pOldNode->pPrev != NULL)
  168. {
  169. ASSERT(_IsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  170. pOldNode->pPrev->pNext = pNewNode;
  171. }
  172. else
  173. {
  174. ASSERT(pOldNode == m_pNodeHead);
  175. m_pNodeHead = pNewNode;
  176. }
  177. pOldNode->pPrev = pNewNode;
  178. return (POSITION) pNewNode;
  179. }
  180. POSITION MMC::CPtrList::InsertAfter(POSITION position, void* newElement)
  181. {
  182. ASSERT_VALID(this);
  183. if (position == NULL)
  184. return AddTail(newElement); // insert after nothing -> tail of the list
  185. // Insert it before position
  186. CNode* pOldNode = (CNode*) position;
  187. ASSERT(_IsValidAddress(pOldNode, sizeof(CNode)));
  188. CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
  189. pNewNode->data = newElement;
  190. if (pOldNode->pNext != NULL)
  191. {
  192. ASSERT(_IsValidAddress(pOldNode->pNext, sizeof(CNode)));
  193. pOldNode->pNext->pPrev = pNewNode;
  194. }
  195. else
  196. {
  197. ASSERT(pOldNode == m_pNodeTail);
  198. m_pNodeTail = pNewNode;
  199. }
  200. pOldNode->pNext = pNewNode;
  201. return (POSITION) pNewNode;
  202. }
  203. void MMC::CPtrList::RemoveAt(POSITION position)
  204. {
  205. ASSERT_VALID(this);
  206. CNode* pOldNode = (CNode*) position;
  207. ASSERT(_IsValidAddress(pOldNode, sizeof(CNode)));
  208. // remove pOldNode from list
  209. if (pOldNode == m_pNodeHead)
  210. {
  211. m_pNodeHead = pOldNode->pNext;
  212. }
  213. else
  214. {
  215. ASSERT(_IsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  216. pOldNode->pPrev->pNext = pOldNode->pNext;
  217. }
  218. if (pOldNode == m_pNodeTail)
  219. {
  220. m_pNodeTail = pOldNode->pPrev;
  221. }
  222. else
  223. {
  224. ASSERT(_IsValidAddress(pOldNode->pNext, sizeof(CNode)));
  225. pOldNode->pNext->pPrev = pOldNode->pPrev;
  226. }
  227. FreeNode(pOldNode);
  228. }
  229. /////////////////////////////////////////////////////////////////////////////
  230. // slow operations
  231. POSITION MMC::CPtrList::FindIndex(int nIndex) const
  232. {
  233. ASSERT_VALID(this);
  234. ASSERT(nIndex >= 0);
  235. if (nIndex >= m_nCount)
  236. return NULL; // went too far
  237. CNode* pNode = m_pNodeHead;
  238. while (nIndex--)
  239. {
  240. ASSERT(_IsValidAddress(pNode, sizeof(CNode)));
  241. pNode = pNode->pNext;
  242. }
  243. return (POSITION) pNode;
  244. }
  245. POSITION MMC::CPtrList::Find(void* searchValue, POSITION startAfter) const
  246. {
  247. ASSERT_VALID(this);
  248. CNode* pNode = (CNode*) startAfter;
  249. if (pNode == NULL)
  250. {
  251. pNode = m_pNodeHead; // start at head
  252. }
  253. else
  254. {
  255. ASSERT(_IsValidAddress(pNode, sizeof(CNode)));
  256. pNode = pNode->pNext; // start after the one specified
  257. }
  258. for (; pNode != NULL; pNode = pNode->pNext)
  259. if (pNode->data == searchValue)
  260. return (POSITION) pNode;
  261. return NULL;
  262. }
  263. #ifdef _DBG
  264. void MMC::CPtrList::AssertValid() const
  265. {
  266. if (m_nCount == 0)
  267. {
  268. // empty list
  269. ASSERT(m_pNodeHead == NULL);
  270. ASSERT(m_pNodeTail == NULL);
  271. }
  272. else
  273. {
  274. // non-empty list
  275. ASSERT(_IsValidAddress(m_pNodeHead, sizeof(CNode)));
  276. ASSERT(_IsValidAddress(m_pNodeTail, sizeof(CNode)));
  277. }
  278. }
  279. #endif