PageRenderTime 25ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/Sources/Engine/Base/Lists.cpp

https://gitlab.com/dahbearz/Serious-Engine
C++ | 290 lines | 156 code | 40 blank | 94 comment | 28 complexity | baa97f5cfda11b1cfc23efe530585652 MD5 | raw file
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Base/Lists.h>
  14. #include <Engine/Base/ListIterator.inl>
  15. /////////////////////////////////////////////////////////////////////
  16. // CListHead implementation
  17. /*
  18. * Initialize a list head.
  19. */
  20. void CListHead::Clear(void)
  21. {
  22. ASSERT(this!=NULL);
  23. lh_Head = (CListNode *) &(lh_NULL);
  24. lh_NULL = (CListNode *) NULL;
  25. lh_Tail = (CListNode *) &(lh_Head);
  26. }
  27. /*
  28. * Check if list head is valid.
  29. */
  30. BOOL CListHead::IsValid(void) const
  31. {
  32. ASSERT(this!=NULL);
  33. ASSERT(lh_NULL == NULL);
  34. ASSERT((lh_Head == (CListNode *) &lh_NULL) && (lh_Tail == (CListNode *) &lh_Head)
  35. || lh_Tail->IsValid() && lh_Head->IsValid() );
  36. return TRUE;
  37. }
  38. /*
  39. * Check if list is empty.
  40. */
  41. BOOL CListHead::IsEmpty(void) const
  42. {
  43. ASSERT(IsValid());
  44. return( lh_Head == (CListNode *) &lh_NULL );
  45. }
  46. /*
  47. * Add a node to head of list.
  48. */
  49. void CListHead::AddHead(CListNode &element)
  50. {
  51. ASSERT(IsValid()&& !element.IsLinked());
  52. CListNode &first = *lh_Head;
  53. lh_Head = &element;
  54. element.ln_Succ = &first;
  55. element.ln_Pred = first.ln_Pred;
  56. first.ln_Pred = &element;
  57. }
  58. /*
  59. * Add a node to tail of list.
  60. */
  61. void CListHead::AddTail(CListNode &element)
  62. {
  63. ASSERT(IsValid()&& !element.IsLinked());
  64. CListNode &last = *lh_Tail;
  65. lh_Tail = &element;
  66. element.ln_Succ = last.ln_Succ;
  67. element.ln_Pred = &last;
  68. last.ln_Succ = &element;
  69. }
  70. /*
  71. * Remove a node from head of list.
  72. */
  73. void CListHead::RemHead(void)
  74. {
  75. ASSERT(!IsEmpty());
  76. lh_Head->Remove();
  77. }
  78. /*
  79. * Remove a node from tail of list.
  80. */
  81. void CListHead::RemTail(void)
  82. {
  83. ASSERT(!IsEmpty());
  84. lh_Tail->Remove();
  85. }
  86. /* Remove all elements from list. */
  87. void CListHead::RemAll(void)
  88. {
  89. // for each element
  90. for ( CListIter<CListNode, 0> iter(*this), iternext;
  91. iternext=iter, iternext.IsPastEnd() || (iternext.MoveToNext(),1), !iter.IsPastEnd();
  92. iter = iternext) {
  93. // remove it
  94. iter->Remove();
  95. }
  96. }
  97. /*
  98. * Move all elements of another list into this one.
  99. */
  100. void CListHead::MoveList(CListHead &lhOther)
  101. {
  102. ASSERT(IsValid() && lhOther.IsValid());
  103. // if the second list is empty
  104. if (lhOther.IsEmpty()) {
  105. // no moving
  106. return;
  107. }
  108. // get first element in other list
  109. CListNode &lnOtherFirst = *lhOther.lh_Head;
  110. // get last element in other list
  111. CListNode &lnOtherLast = *lhOther.lh_Tail;
  112. // get last element in this list
  113. CListNode &lnThisLast = *lh_Tail;
  114. // relink elements
  115. lnOtherLast.ln_Succ = lnThisLast.ln_Succ;
  116. lnThisLast.ln_Succ = &lnOtherFirst;
  117. lnOtherFirst.ln_Pred = &lnThisLast;
  118. lh_Tail = &lnOtherLast;
  119. // clear the other list
  120. lhOther.Clear();
  121. }
  122. /*
  123. * Return the number of elements in list.
  124. */
  125. INDEX CListHead::Count(void) const
  126. {
  127. INDEX slCount = 0;
  128. // walk the list -- modification of FOREACHINLIST that works with base CListNode class
  129. for ( CListIter<CListNode, 0> iter(*this); !iter.IsPastEnd(); iter.MoveToNext() ) {
  130. slCount++;
  131. }
  132. return slCount;
  133. }
  134. /* Sort the list. */
  135. void CListHead::Sort(int (*pCompare)(const void *p0, const void *p1), int iNodeOffset)
  136. {
  137. // get number of elements
  138. INDEX ctCount = Count();
  139. // if none
  140. if (ctCount==0) {
  141. // do not sort
  142. }
  143. // create array of that much integers (the array will hold pointers to the list)
  144. ULONG *aulPointers = new ULONG[ctCount];
  145. // fill it
  146. INDEX i=0;
  147. for ( CListIter<int, 0> iter(*this); !iter.IsPastEnd(); iter.MoveToNext() ) {
  148. aulPointers[i] = ((ULONG)&*iter)-iNodeOffset;
  149. i++;
  150. }
  151. // sort it
  152. qsort(aulPointers, ctCount, sizeof(SLONG), pCompare);
  153. // make temporary list
  154. CListHead lhTmp;
  155. // for each pointer
  156. {for(INDEX i=0; i<ctCount; i++) {
  157. ULONG ul = aulPointers[i];
  158. // get the node
  159. CListNode *pln = (CListNode*)(ul+iNodeOffset);
  160. // remove it from original list
  161. pln->Remove();
  162. // add it to the end of new list
  163. lhTmp.AddTail(*pln);
  164. }}
  165. // free the pointer array
  166. delete[] aulPointers;
  167. // move the sorted list here
  168. MoveList(lhTmp);
  169. }
  170. /////////////////////////////////////////////////////////////////////
  171. // CListNode implementation
  172. /*
  173. * Check if list node is valid.
  174. */
  175. BOOL CListNode::IsValid(void) const
  176. {
  177. ASSERT(this!=NULL);
  178. ASSERT((ln_Pred==NULL && ln_Succ==NULL) || (ln_Pred!=NULL && ln_Succ!=NULL));
  179. // it is valid if it is cleared or if it is linked
  180. return (ln_Pred==NULL && ln_Succ==NULL)
  181. || (ln_Pred->ln_Succ == this) && (ln_Succ->ln_Pred == this);
  182. }
  183. /*
  184. * Check is linked in some list.
  185. */
  186. BOOL CListNode::IsLinked(void) const
  187. {
  188. ASSERT(IsValid());
  189. return ln_Pred != NULL;
  190. }
  191. /*
  192. * Remove a node from list.
  193. */
  194. void CListNode::Remove(void)
  195. {
  196. ASSERT(IsLinked());
  197. CListNode &next = *ln_Succ;
  198. CListNode &prev = *ln_Pred;
  199. ASSERT(next.IsTailMarker() || next.IsLinked());
  200. ASSERT(prev.IsHeadMarker() || prev.IsLinked());
  201. next.ln_Pred = &prev;
  202. prev.ln_Succ = &next;
  203. // make a non-linked node
  204. ln_Succ = NULL;
  205. ln_Pred = NULL;
  206. }
  207. /*
  208. * Add a node after this node.
  209. */
  210. void CListNode::AddAfter(CListNode &lnToAdd)
  211. {
  212. ASSERT(IsLinked() && !lnToAdd.IsLinked());
  213. CListNode &succ = IterationSucc();
  214. CListNode &pred = *this;
  215. succ.ln_Pred = &lnToAdd;
  216. pred.ln_Succ = &lnToAdd;
  217. lnToAdd.ln_Succ = &succ;
  218. lnToAdd.ln_Pred = &pred;
  219. }
  220. /*
  221. * Add a node before this node.
  222. */
  223. void CListNode::AddBefore(CListNode &lnToAdd)
  224. {
  225. ASSERT(IsLinked() && !lnToAdd.IsLinked());
  226. CListNode &succ = *this;
  227. CListNode &pred = IterationPred();
  228. succ.ln_Pred = &lnToAdd;
  229. pred.ln_Succ = &lnToAdd;
  230. lnToAdd.ln_Succ = &succ;
  231. lnToAdd.ln_Pred = &pred;
  232. }
  233. /*
  234. * Find the head of the list that this node is in.
  235. */
  236. CListHead &CListNode::GetHead(void)
  237. {
  238. // start at this node
  239. CListNode *pln = this;
  240. // while current node is not pointer to list.lh_Head
  241. while(pln->ln_Pred != NULL) {
  242. // go backwards
  243. pln = pln->ln_Pred;
  244. }
  245. // return the head pointer
  246. return *(CListHead*)pln;
  247. }