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.

349 lines
9.6 KiB

  1. #ifndef __CLIST_H__
  2. #define __CLIST_H__
  3. //
  4. // TFList - a class for handling templated lists. Lists support adding
  5. // and removing items from the front and back of the list. The item on
  6. // the front or back can be examined. Using iterator the list can
  7. // be traversed easily (see the block comment below).
  8. //
  9. // The objects that this list hold should have this form:
  10. //
  11. // CListObject {
  12. // public:
  13. // CListObject *m_pNext; // for use by TFList<CListObject>
  14. // CListObject *m_pPrev; // for use by TFList<CListObject>
  15. // // other object parameters
  16. // }
  17. //
  18. // The constructor for the object should set m_pNext and m_pPrev to NULL
  19. // in debug builds to avoid hitting _ASSERTs.
  20. //
  21. // To construct the list you need to pass in the offsets for the m_pNext
  22. // and m_pPrev members using C++'s member offset syntax. Here is an
  23. // example:
  24. // TFList<CListObject> list(&CListObject::m_pPrev, &CListObject::m_pNext);
  25. //
  26. template <class Data> class TFList {
  27. public:
  28. typedef Data *Data::*NEXTPTR;
  29. protected:
  30. Data *m_pHead; // the head of the list
  31. Data *m_pTail; // the tail of the list
  32. NEXTPTR m_pNext; // offset to the next pointer
  33. NEXTPTR m_pPrev; // offset to the prev pointer
  34. public:
  35. TFList(NEXTPTR pPrev, NEXTPTR pNext) {
  36. m_pHead = NULL;
  37. m_pTail = NULL;
  38. m_pNext = pNext;
  39. m_pPrev = pPrev;
  40. }
  41. ~TFList() {
  42. // the user should empty the list before deleting it
  43. _ASSERT(m_pHead == NULL);
  44. _ASSERT(m_pTail == NULL);
  45. }
  46. // see if the list is empty
  47. bool IsEmpty() {
  48. bool f = (m_pHead == NULL);
  49. // if the head is null then the tail has to be null
  50. _ASSERT(!f || m_pTail == NULL);
  51. return f;
  52. }
  53. // push an element onto the front of the list
  54. void PushFront(Data *node) {
  55. _ASSERT(node != NULL);
  56. // you can't put an entry into the list that is already in it
  57. _ASSERT(node->*m_pNext == NULL);
  58. _ASSERT(node->*m_pPrev == NULL);
  59. // set the next and prev pointers
  60. node->*m_pPrev = NULL;
  61. node->*m_pNext = m_pHead;
  62. // if the list is empty then this new item is the tail too
  63. if (IsEmpty()) {
  64. _ASSERT(m_pTail == NULL);
  65. m_pTail = node;
  66. } else {
  67. _ASSERT(m_pHead->*m_pPrev == NULL);
  68. m_pHead->*m_pPrev = node;
  69. }
  70. m_pHead = node;
  71. }
  72. // push an element onto the back of the list
  73. void PushBack(Data* node) {
  74. _ASSERT(node != NULL);
  75. // you can't put an entry into the list that is already in it
  76. _ASSERT(node->*m_pNext == NULL);
  77. _ASSERT(node->*m_pPrev == NULL);
  78. // set the next and prev pointers
  79. node->*m_pNext = NULL;
  80. node->*m_pPrev = m_pTail;
  81. // if the list is empty then this new item is the head too
  82. if (IsEmpty()) {
  83. _ASSERT(m_pHead == NULL);
  84. m_pHead = node;
  85. } else {
  86. _ASSERT(m_pTail->*m_pNext == NULL);
  87. m_pTail->*m_pNext = node;
  88. }
  89. m_pTail = node;
  90. }
  91. // remove the item from the front of the list
  92. Data *PopFront() {
  93. if (m_pHead == NULL) return NULL;
  94. Data *node = m_pHead;
  95. m_pHead = node->*m_pNext;
  96. if (m_pHead == NULL) m_pTail = NULL;
  97. else m_pHead->*m_pPrev = NULL;
  98. node->*m_pNext = NULL;
  99. node->*m_pPrev = NULL;
  100. return node;
  101. }
  102. // remove the item from the back of the list
  103. Data *PopBack() {
  104. if (m_pTail == NULL) return NULL;
  105. Data *node = m_pTail;
  106. m_pTail = node->*m_pPrev;
  107. if (m_pTail == NULL) m_pHead = NULL;
  108. else (m_pTail)->*m_pNext = NULL;
  109. node->*m_pNext = NULL;
  110. node->*m_pPrev = NULL;
  111. return node;
  112. }
  113. // get the item on the front of the list
  114. Data* GetFront() { return m_pHead; }
  115. // get the item on the back of the list
  116. Data* GetBack() { return m_pTail; }
  117. public:
  118. //
  119. // The Iterator object is used to walk the list and modify members
  120. // that are in the middle of the list. It is declared using this
  121. // syntax:
  122. // TFList<CListObject>::Iterator it(&list);
  123. //
  124. class Iterator {
  125. protected:
  126. Data *m_pCur; // our cursor
  127. int m_fForward; // TRUE for forward, FALSE for back
  128. TFList<Data> *m_pList; // the list that we are iterating
  129. NEXTPTR m_pPrev, m_pNext;
  130. public:
  131. //
  132. // create a new iterator object
  133. //
  134. // arguments:
  135. // pList - the list to iterate across
  136. // fForward - TRUE to start at the front, and go forward.
  137. // FALSE to start at the back, and go backwards.
  138. //
  139. Iterator(TFList<Data> *pList, BOOL fForward = TRUE) {
  140. _ASSERT(pList != NULL);
  141. m_pList = pList;
  142. m_fForward = fForward;
  143. m_pCur = (fForward) ? pList->m_pHead : pList->m_pTail;
  144. m_pPrev = pList->m_pPrev;
  145. m_pNext = pList->m_pNext;
  146. }
  147. void ResetHeader( TFList<Data> *pList ) {
  148. _ASSERT( pList != NULL );
  149. m_pList = pList;
  150. m_pCur = (m_fForward) ? m_pList->m_pHead : m_pList->m_pTail;
  151. m_pPrev = m_pList->m_pPrev;
  152. m_pNext = m_pList->m_pNext;
  153. }
  154. //
  155. // get a pointer to the current item
  156. //
  157. Data *Current() {
  158. return m_pCur;
  159. }
  160. //
  161. // go to the previous item in the list
  162. //
  163. void Prev() {
  164. if (m_pCur != NULL) {
  165. m_pCur = m_pCur->*m_pPrev;
  166. } else {
  167. // if they switch direction and are at the end of
  168. // the list then they need to get to a legal place
  169. if (m_fForward) m_pCur = m_pList->m_pTail;
  170. }
  171. m_fForward = FALSE;
  172. }
  173. //
  174. // go to the next item in the list
  175. //
  176. void Next() {
  177. if (m_pCur != NULL) {
  178. m_pCur = m_pCur->*m_pNext;
  179. } else {
  180. // if they switch direction and are at the end of
  181. // the list then they need to get to a legal place
  182. if (!m_fForward) m_pCur = m_pList->m_pHead;
  183. }
  184. m_fForward = TRUE;
  185. }
  186. //
  187. // Go to the head of the list
  188. //
  189. void Front() {
  190. m_pCur = m_pList->m_pHead;
  191. m_fForward = TRUE;
  192. }
  193. //
  194. // Go to the tail of the list
  195. //
  196. void Back() {
  197. m_pCur = m_pList->m_pTail;
  198. m_fForward = FALSE;
  199. }
  200. //
  201. // unlinks an item from the linked list
  202. //
  203. // cursor updates:
  204. // if the last movement in this list was forward then the
  205. // iterator will point towards the pPrev item in the list.
  206. // visa-versa if the last movement was backward. this is
  207. // so that a for loop over an iterator still works as
  208. // expected.
  209. //
  210. // returns:
  211. // a pointer to the item that was unlinked.
  212. //
  213. Data *RemoveItem(void) {
  214. Data *pTemp;
  215. if (m_pCur == NULL) return NULL;
  216. pTemp = m_pCur;
  217. // update cur
  218. if (m_fForward) Next(); else Prev();
  219. // fix head and tail pointers if necessary
  220. if (m_pList->m_pHead == pTemp)
  221. m_pList->m_pHead = pTemp->*m_pNext;
  222. if (m_pList->m_pTail == pTemp)
  223. m_pList->m_pTail = pTemp->*m_pPrev;
  224. // fix up the links on the adjacent elements
  225. if (pTemp->*m_pNext != NULL)
  226. pTemp->*m_pNext->*m_pPrev = pTemp->*m_pPrev;
  227. if (pTemp->*m_pPrev != NULL)
  228. pTemp->*m_pPrev->*m_pNext = pTemp->*m_pNext;
  229. // clean up the next and prev pointers
  230. pTemp->*m_pNext = NULL;
  231. pTemp->*m_pPrev = NULL;
  232. // return the item
  233. return pTemp;
  234. }
  235. //
  236. // insert a new item before the current item.
  237. //
  238. // Cursor updates:
  239. // If you use this method to insert an item then it should
  240. // not be visited if the next cursor movement is a Next().
  241. // If the next cursor movement is a Prev() then it should
  242. // be visited.
  243. //
  244. void InsertBefore(Data* pNode) {
  245. // this entry shouldn't be linked into the list
  246. _ASSERT(pNode->*m_pNext == NULL);
  247. _ASSERT(pNode->*m_pPrev == NULL);
  248. if (m_pCur == NULL) {
  249. // if we are at the head of the list then we'll insert
  250. // before the head
  251. if (m_fForward) {
  252. m_pList->PushFront(pNode);
  253. // set the current pointer to this item, so that
  254. // if we iterate forward we dont' see this item
  255. m_pCur = pNode;
  256. } else {
  257. // invalid operation. do nothing
  258. _ASSERT(FALSE);
  259. }
  260. } else {
  261. pNode->*m_pNext = m_pCur;
  262. pNode->*m_pPrev = m_pCur->*m_pPrev;
  263. m_pCur->*m_pPrev = pNode;
  264. if (pNode->*m_pPrev != NULL)
  265. pNode->*m_pPrev->*m_pNext = pNode;
  266. if (m_pList->m_pHead == m_pCur)
  267. m_pList->m_pHead = pNode;
  268. }
  269. }
  270. //
  271. // insert a new item after the current item.
  272. //
  273. // Cursor updates are the opposite of InsertBefore().
  274. //
  275. void InsertAfter(Data *pNode) {
  276. // this entry shouldn't be linked into the list
  277. _ASSERT(pNode->*m_pNext == NULL);
  278. _ASSERT(pNode->*m_pPrev == NULL);
  279. if (m_pCur == NULL) {
  280. // if we are at the tail of the list then we'll insert
  281. // before the tail
  282. if (!m_fForward) {
  283. m_pList->PushBack(pNode);
  284. // set the current pointer to this item, so that
  285. // if we iterate backwards we dont' see this item
  286. m_pCur = pNode;
  287. } else {
  288. // invalid operation. do nothing
  289. _ASSERT(FALSE);
  290. }
  291. } else {
  292. pNode->*m_pPrev = m_pCur;
  293. pNode->*m_pNext = m_pCur->*m_pNext;
  294. m_pCur->*m_pNext = pNode;
  295. if (pNode->*m_pNext != NULL)
  296. pNode->*m_pNext->*m_pPrev = pNode;
  297. if (m_pList->m_pTail == m_pCur)
  298. m_pList->m_pTail = pNode;
  299. }
  300. }
  301. //
  302. // see if we are at either the front or back of the list
  303. //
  304. bool AtEnd() {
  305. return (m_pCur == NULL);
  306. }
  307. };
  308. friend class TFList<Data>::Iterator;
  309. };
  310. #endif