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.

326 lines
7.2 KiB

  1. //
  2. // Lists have internal serialization so that most functions operate as atomic
  3. // operations. However, the results of some functions are transient (i.e.
  4. // immediately out-of-date) unless the caller explicitly locks the list using
  5. // the Lock/Unlock methods. These functions are GetCount, GetHeadPosition,
  6. // GetNext. Also, it is the caller's responsibility to serialize access to a
  7. // POSITION. The internal serialization only ensures that two simultaneus
  8. // AddTail calls will not make the list internally inconsistent, and nor will
  9. // two simultaneous RemoveAt calls on _different_ POSITIONs.
  10. //
  11. // List elements with NULL object pointers are skipped by list iteration
  12. // functions GetHeadPosition and GetNext.
  13. //
  14. typedef struct _CListElement {
  15. struct _CListElement *Next;
  16. struct _CListElement *Prev;
  17. const void *Object;
  18. } CListElement, *POSITION;
  19. template <class TYPE, class ARG_TYPE> class CList {
  20. public:
  21. CList();
  22. ~CList();
  23. POSITION AddHead(ARG_TYPE newElement);
  24. POSITION AddTail(ARG_TYPE newElement);
  25. TYPE GetAt(POSITION position);
  26. int GetCount(void) const;
  27. POSITION GetHeadPosition(void) const;
  28. TYPE GetNext(POSITION& rPosition); // return *Position++
  29. LONG Initialize(void);
  30. POSITION InsertAfter(POSITION position, ARG_TYPE newElement);
  31. POSITION InsertBefore(POSITION position, ARG_TYPE newElement);
  32. BOOL IsEmpty(void) const;
  33. void Lock(void);
  34. void MoveBefore(POSITION posTarget, POSITION posMove);
  35. void RemoveAll(void);
  36. void RemoveAt(POSITION position);
  37. void SetAt(POSITION pos, ARG_TYPE newElement);
  38. void Unlock(void);
  39. private:
  40. BOOL m_Initialized;
  41. CRITICAL_SECTION m_CriticalSection;
  42. int m_Count;
  43. CListElement m_Sentinel;
  44. };
  45. template<class TYPE, class ARG_TYPE>
  46. CList<TYPE, ARG_TYPE>::CList(void)
  47. {
  48. m_Initialized = FALSE;
  49. m_Count = 0;
  50. m_Sentinel.Next = &m_Sentinel;
  51. m_Sentinel.Prev = &m_Sentinel;
  52. m_Sentinel.Object = &m_Sentinel;
  53. }
  54. template<class TYPE, class ARG_TYPE>
  55. CList<TYPE, ARG_TYPE>::~CList(void)
  56. {
  57. if (m_Initialized) {
  58. RemoveAll();
  59. ASSERT(m_Sentinel.Next = &m_Sentinel);
  60. ASSERT(m_Sentinel.Prev = &m_Sentinel);
  61. DeleteCriticalSection(&m_CriticalSection);
  62. m_Initialized = FALSE;
  63. }
  64. }
  65. template<class TYPE, class ARG_TYPE>
  66. POSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
  67. {
  68. POSITION pos;
  69. ASSERT(m_Initialized);
  70. pos = new CListElement;
  71. if (pos) {
  72. Lock();
  73. pos->Next = m_Sentinel.Next;
  74. pos->Prev = &m_Sentinel;
  75. pos->Prev->Next = pos;
  76. pos->Next->Prev = pos;
  77. pos->Object = newElement;
  78. m_Count++;
  79. Unlock();
  80. }
  81. return pos;
  82. }
  83. template<class TYPE, class ARG_TYPE>
  84. POSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
  85. {
  86. POSITION pos;
  87. ASSERT(m_Initialized);
  88. pos = new CListElement;
  89. if (pos) {
  90. Lock();
  91. pos->Next = &m_Sentinel;
  92. pos->Prev = m_Sentinel.Prev;
  93. pos->Prev->Next = pos;
  94. pos->Next->Prev = pos;
  95. pos->Object = newElement;
  96. m_Count++;
  97. Unlock();
  98. }
  99. return pos;
  100. }
  101. template<class TYPE, class ARG_TYPE>
  102. TYPE CList<TYPE, ARG_TYPE>::GetAt(POSITION pos)
  103. {
  104. ASSERT(m_Initialized);
  105. return (TYPE)pos->Object;
  106. }
  107. template<class TYPE, class ARG_TYPE>
  108. int CList<TYPE, ARG_TYPE>::GetCount(void) const
  109. {
  110. ASSERT(m_Initialized);
  111. return m_Count;
  112. }
  113. template<class TYPE, class ARG_TYPE>
  114. POSITION CList<TYPE, ARG_TYPE>::GetHeadPosition(void) const
  115. {
  116. POSITION pos;
  117. ASSERT(m_Initialized);
  118. pos = m_Sentinel.Next;
  119. // Skip NULL elements
  120. while (NULL == pos->Object) pos = pos->Next;
  121. if (pos == &m_Sentinel) return NULL;
  122. return pos;
  123. }
  124. template<class TYPE, class ARG_TYPE>
  125. TYPE CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPos)
  126. {
  127. ASSERT(m_Initialized);
  128. TYPE Object = (TYPE)rPos->Object;
  129. rPos = rPos->Next;
  130. // Skip NULL elements.
  131. while (NULL == rPos->Object) rPos = rPos->Next;
  132. if (rPos == &m_Sentinel) rPos = NULL;
  133. return Object;
  134. }
  135. template<class TYPE, class ARG_TYPE>
  136. LONG CList<TYPE, ARG_TYPE>::Initialize(void)
  137. {
  138. LONG result;
  139. ASSERT(!m_Initialized);
  140. __try {
  141. InitializeCriticalSection(&m_CriticalSection);
  142. result = NO_ERROR;
  143. } __except(EXCEPTION_EXECUTE_HANDLER) {
  144. result = ERROR_OUTOFMEMORY;
  145. }
  146. m_Initialized = (NO_ERROR == result);
  147. return result;
  148. }
  149. template<class TYPE, class ARG_TYPE>
  150. POSITION CList<TYPE, ARG_TYPE>::InsertAfter(POSITION position, ARG_TYPE newElement)
  151. {
  152. ASSERT(m_Initialized);
  153. if (position == NULL)
  154. {
  155. // insert after nothing -> head of the list
  156. position = &m_Sentinel;
  157. }
  158. // Insert it after position
  159. CListElement* newPos = new CListElement;
  160. if (newPos)
  161. {
  162. Lock();
  163. newPos->Next = position->Next;
  164. newPos->Prev = position;
  165. newPos->Next->Prev = newPos;
  166. newPos->Prev->Next = newPos;
  167. newPos->Object = newElement;
  168. m_Count++;
  169. Unlock();
  170. }
  171. return newPos;
  172. }
  173. template<class TYPE, class ARG_TYPE>
  174. POSITION CList<TYPE, ARG_TYPE>::InsertBefore(POSITION position, ARG_TYPE newElement)
  175. {
  176. ASSERT(m_Initialized);
  177. if (position == NULL)
  178. {
  179. // insert before nothing -> tail of list
  180. position = &m_Sentinel;
  181. }
  182. // Insert it before position
  183. CListElement* newPos = new CListElement;
  184. if (newPos)
  185. {
  186. Lock();
  187. newPos->Next = position;
  188. newPos->Prev = position->Prev;
  189. newPos->Next->Prev = newPos;
  190. newPos->Prev->Next = newPos;
  191. newPos->Object = newElement;
  192. m_Count++;
  193. Unlock();
  194. }
  195. return newPos;
  196. }
  197. template<class TYPE, class ARG_TYPE>
  198. BOOL CList<TYPE, ARG_TYPE>::IsEmpty(void) const
  199. {
  200. ASSERT(m_Initialized);
  201. return (0 == m_Count);
  202. }
  203. template<class TYPE, class ARG_TYPE>
  204. void CList<TYPE, ARG_TYPE>::Lock(void)
  205. {
  206. EnterCriticalSection(&m_CriticalSection);
  207. }
  208. template<class TYPE, class ARG_TYPE>
  209. void CList<TYPE, ARG_TYPE>::MoveBefore(POSITION posTarget, POSITION posMove)
  210. {
  211. ASSERT(m_Initialized);
  212. if (posTarget == posMove) return;
  213. if (posTarget == NULL)
  214. {
  215. // Move before nothing -> tail of list
  216. posTarget = &m_Sentinel;
  217. }
  218. // first remove from list
  219. posMove->Prev->Next = posMove->Next;
  220. posMove->Next->Prev = posMove->Prev;
  221. // Move it before posTarget
  222. posMove->Next = posTarget;
  223. posMove->Prev = posTarget->Prev;
  224. posMove->Next->Prev = posMove;
  225. posMove->Prev->Next = posMove;
  226. return;
  227. }
  228. template<class TYPE, class ARG_TYPE>
  229. void CList<TYPE, ARG_TYPE>::RemoveAll(void)
  230. {
  231. POSITION pos;
  232. ASSERT(m_Initialized);
  233. while (pos = GetHeadPosition()) RemoveAt(pos);
  234. return;
  235. }
  236. template<class TYPE, class ARG_TYPE>
  237. void CList<TYPE, ARG_TYPE>::RemoveAt(POSITION pos)
  238. {
  239. ASSERT(m_Initialized);
  240. ASSERT(m_Count > 0);
  241. Lock();
  242. pos->Prev->Next = pos->Next;
  243. pos->Next->Prev = pos->Prev;
  244. m_Count--;
  245. Unlock();
  246. delete pos;
  247. }
  248. template<class TYPE, class ARG_TYPE>
  249. void CList<TYPE, ARG_TYPE>::SetAt(POSITION pos, ARG_TYPE newElement)
  250. {
  251. ASSERT(m_Initialized);
  252. ASSERT(m_Count > 0);
  253. Lock();
  254. pos->Object = newElement;
  255. Unlock();
  256. return;
  257. }
  258. template<class TYPE, class ARG_TYPE>
  259. void CList<TYPE, ARG_TYPE>::Unlock(void)
  260. {
  261. LeaveCriticalSection(&m_CriticalSection);
  262. }