SimpleObjectIterator.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // SimpleObjectIterator
  24. // Implementation of a simple object iterator
  25. // Author: Steven Johnson, September 2001
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "GameLogic/ObjectIter.h"
  28. #include "Common/ThingTemplate.h"
  29. #include "GameLogic/Object.h"
  30. /// @todo Doxygenize this file
  31. SimpleObjectIterator::ClumpCompareProc SimpleObjectIterator::theClumpCompareProcs[] =
  32. {
  33. NULL, // "fastest" gets no proc
  34. SimpleObjectIterator::sortNearToFar,
  35. SimpleObjectIterator::sortFarToNear,
  36. SimpleObjectIterator::sortCheapToExpensive,
  37. SimpleObjectIterator::sortExpensiveToCheap
  38. };
  39. //=============================================================================
  40. SimpleObjectIterator::Clump::Clump()
  41. {
  42. m_nextClump = NULL;
  43. }
  44. //=============================================================================
  45. SimpleObjectIterator::Clump::~Clump()
  46. {
  47. }
  48. //=============================================================================
  49. SimpleObjectIterator::SimpleObjectIterator()
  50. {
  51. m_firstClump = NULL;
  52. m_curClump = NULL;
  53. m_clumpCount = 0;
  54. }
  55. //=============================================================================
  56. SimpleObjectIterator::~SimpleObjectIterator()
  57. {
  58. makeEmpty();
  59. }
  60. //=============================================================================
  61. void SimpleObjectIterator::insert(Object *obj, Real numeric)
  62. {
  63. DEBUG_ASSERTCRASH(obj, ("sorry, no nulls allowed here"));
  64. Clump *clump = newInstance(Clump)();
  65. clump->m_nextClump = m_firstClump;
  66. m_firstClump = clump;
  67. clump->m_obj = obj;
  68. clump->m_numeric = numeric;
  69. ++m_clumpCount;
  70. }
  71. //=============================================================================
  72. Object *SimpleObjectIterator::nextWithNumeric(Real *num)
  73. {
  74. Object *obj = NULL;
  75. if (num)
  76. *num = 0.0f;
  77. if (m_curClump)
  78. {
  79. obj = m_curClump->m_obj;
  80. if (num)
  81. *num = m_curClump->m_numeric;
  82. m_curClump = m_curClump->m_nextClump;
  83. }
  84. return obj;
  85. }
  86. //=============================================================================
  87. void SimpleObjectIterator::reset()
  88. {
  89. m_curClump = m_firstClump;
  90. }
  91. //=============================================================================
  92. void SimpleObjectIterator::makeEmpty()
  93. {
  94. while (m_firstClump)
  95. {
  96. Clump *next = m_firstClump->m_nextClump;
  97. m_firstClump->deleteInstance();
  98. m_firstClump = next;
  99. --m_clumpCount;
  100. }
  101. DEBUG_ASSERTCRASH(m_clumpCount == 0, ("hmm"));
  102. m_firstClump = NULL;
  103. m_curClump = NULL;
  104. m_clumpCount = 0;
  105. }
  106. //=============================================================================
  107. void SimpleObjectIterator::sort(IterOrderType order)
  108. {
  109. if (m_clumpCount == 0)
  110. return;
  111. #ifdef INTENSE_DEBUG
  112. {
  113. DEBUG_LOG(("\n\n---------- BEFORE sort for %d -----------\n",order));
  114. for (Clump *p = m_firstClump; p; p = p->m_nextClump)
  115. {
  116. DEBUG_LOG((" obj %08lx numeric %f\n",p->m_obj,p->m_numeric));
  117. }
  118. }
  119. #endif
  120. ClumpCompareProc cmpProc = theClumpCompareProcs[order];
  121. if (!cmpProc)
  122. return; // my, that was easy
  123. // do a basic mergesort, which works nicely for linked lists,
  124. // and is reasonably efficient (N log N).
  125. for ( Int n = 1 ; ; n *= 2 )
  126. {
  127. Clump *to_do = m_firstClump;
  128. Clump *tail = NULL;
  129. m_firstClump = NULL;
  130. Int mergeCount = 0;
  131. while (to_do)
  132. {
  133. ++mergeCount;
  134. Int to_do_count = 0;
  135. // make two lists of length 'n' (to_do is one, sub is the other)
  136. Clump *sub = to_do;
  137. for (Int i = 0; i < n; i++)
  138. {
  139. ++to_do_count;
  140. sub = sub->m_nextClump;
  141. if (!sub)
  142. break;
  143. }
  144. Int subCount = sub ? n : 0;
  145. // merge the two lists.
  146. DEBUG_ASSERTCRASH(to_do_count + subCount >= 0, ("uhoh"));
  147. while (to_do_count + subCount > 0) {
  148. DEBUG_ASSERTCRASH(to_do_count + subCount >= 0, ("uhoh"));
  149. Clump *tmp;
  150. // bleah, coalesce into more elegant test case
  151. if (subCount == 0)
  152. {
  153. DEBUG_ASSERTCRASH(to_do_count > 0, ("hmm, expected nonzero to_do_count"));
  154. tmp = to_do;
  155. to_do = to_do->m_nextClump;
  156. --to_do_count;
  157. }
  158. else if (to_do_count == 0)
  159. {
  160. DEBUG_ASSERTCRASH(subCount > 0, ("hmm, expected nonzero subCount"));
  161. tmp = sub;
  162. sub = sub->m_nextClump;
  163. --subCount;
  164. }
  165. else if ((*cmpProc)(to_do, sub) <= 0.0f)
  166. {
  167. DEBUG_ASSERTCRASH(to_do_count > 0, ("hmm, expected nonzero to_do_count"));
  168. tmp = to_do;
  169. to_do = to_do->m_nextClump;
  170. --to_do_count;
  171. }
  172. else
  173. {
  174. DEBUG_ASSERTCRASH(subCount > 0, ("hmm, expected nonzero subCount"));
  175. tmp = sub;
  176. sub = sub->m_nextClump;
  177. --subCount;
  178. }
  179. if (!sub) subCount = 0;
  180. if (!to_do) to_do_count = 0;
  181. if (tail)
  182. tail->m_nextClump = tmp;
  183. else
  184. m_firstClump = tmp;
  185. tail = tmp;
  186. }
  187. to_do = sub;
  188. }
  189. if (tail)
  190. tail->m_nextClump = NULL;
  191. if (mergeCount <= 1) // when we have done just one (or none) swap, we're done
  192. break;
  193. }
  194. #ifdef INTENSE_DEBUG
  195. {
  196. DEBUG_LOG(("\n\n---------- sort for %d -----------\n",order));
  197. for (Clump *p = m_firstClump; p; p = p->m_nextClump)
  198. {
  199. DEBUG_LOG((" obj %08lx numeric %f\n",p->m_obj,p->m_numeric));
  200. }
  201. }
  202. #endif
  203. // always reset after sorting, to prevent weirdness
  204. reset();
  205. }
  206. //-----------------------------------------------------------------------------
  207. Real SimpleObjectIterator::sortNearToFar(Clump *a, Clump *b)
  208. {
  209. return a->m_numeric - b->m_numeric;
  210. }
  211. //-----------------------------------------------------------------------------
  212. Real SimpleObjectIterator::sortFarToNear(Clump *a, Clump *b)
  213. {
  214. return b->m_numeric - a->m_numeric;
  215. }
  216. //-----------------------------------------------------------------------------
  217. Real SimpleObjectIterator::sortCheapToExpensive(Clump *a, Clump *b)
  218. {
  219. return a->m_obj->getTemplate()->friend_getBuildCost() -
  220. b->m_obj->getTemplate()->friend_getBuildCost();
  221. }
  222. //-----------------------------------------------------------------------------
  223. Real SimpleObjectIterator::sortExpensiveToCheap(Clump *a, Clump *b)
  224. {
  225. return b->m_obj->getTemplate()->friend_getBuildCost() -
  226. a->m_obj->getTemplate()->friend_getBuildCost();
  227. }