multilist.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /*
  2. ** Command & Conquer Renegade(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. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWLib *
  23. * *
  24. * $Archive:: /Commando/Code/wwlib/multilist.h $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Jani_p $*
  29. * *
  30. * $Modtime:: 4/09/01 8:26p $*
  31. * *
  32. * $Revision:: 16 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #if defined(_MSC_VER)
  38. #pragma once
  39. #endif
  40. #ifndef MULTILIST_H
  41. #define MULTILIST_H
  42. #include "always.h"
  43. #include "mempool.h"
  44. #include <assert.h>
  45. class MultiListNodeClass;
  46. class GenericMultiListClass;
  47. /******************************************************************************
  48. MultiLists
  49. MultiLists solve the problem of needing to have objects that can be placed
  50. into multiple lists at the same time. MultiListNodes are all allocated from
  51. a pool which grows in chunks to avoid overhead from calling new and delete.
  52. All operations such as insertion, removal, checking if a list contains an
  53. object, are ether immediate or O(numlists) where numlists is the number of
  54. different lists that the object in question currently occupies.
  55. ******************************************************************************/
  56. /**
  57. ** MultiListObjectClass
  58. ** This is an object that can be linked into a MultiList. The only overhead
  59. ** for this is a single pointer to a MultiListNode.
  60. ** Objects that are linked into MulitLists must derive from this class.
  61. ** If you delete an instance of one of these objects while it is in one or more
  62. ** Multi-Lists, it will automatically remove itself from the lists.
  63. */
  64. class MultiListObjectClass
  65. {
  66. public:
  67. MultiListObjectClass(void) : ListNode(NULL) { }
  68. virtual ~MultiListObjectClass(void);
  69. MultiListNodeClass * Get_List_Node() const { return ListNode; }
  70. void Set_List_Node(MultiListNodeClass *node) { ListNode = node; }
  71. private:
  72. MultiListNodeClass * ListNode;
  73. };
  74. /**
  75. ** MultiListNodeClass
  76. ** These nodes allow objects to be linked in multiple lists. It is
  77. ** like a 2-D linked list where one dimension is the list of objects in a
  78. ** given list and the other dimension is the list of lists that a given object
  79. ** is in.
  80. */
  81. class MultiListNodeClass : public AutoPoolClass<MultiListNodeClass, 256>
  82. {
  83. public:
  84. MultiListNodeClass(void) { Prev = Next = NextList = 0; Object = 0; List = 0; }
  85. MultiListNodeClass *Prev; // prev object in list
  86. MultiListNodeClass *Next; // next object in list
  87. MultiListNodeClass *NextList; // next list this object is in
  88. MultiListObjectClass *Object; // pointer back to the object
  89. GenericMultiListClass *List; // pointer to list for this node
  90. };
  91. /**
  92. ** GenericMultiListClass
  93. ** This is an internal implementation class for Multi List. It is not meant to be used as-is
  94. ** Instead use the MultiListClass template which performs type-casting and reference counting
  95. ** on the objects that you add to the list.
  96. ** This simply contains the head node for a list. This is a doubly circularly linked list where
  97. ** our head node is a sentry. To easily iterate the list use the iterator defined below.
  98. */
  99. class GenericMultiListClass
  100. {
  101. public:
  102. GenericMultiListClass(void) { Head.Next = Head.Prev = &Head; Head.Object = 0; Head.NextList = 0; }
  103. virtual ~GenericMultiListClass(void);
  104. bool Is_In_List(MultiListObjectClass *obj);
  105. bool Contains(MultiListObjectClass * obj);
  106. bool Is_Empty(void);
  107. int Count(void);
  108. protected:
  109. bool Internal_Add(MultiListObjectClass *obj,bool onlyonce = true);
  110. bool Internal_Add_Tail(MultiListObjectClass * obj,bool onlyonce = true);
  111. bool Internal_Add_After(MultiListObjectClass * obj,const MultiListObjectClass * existing_list_member,bool onlyonce = true);
  112. bool Internal_Remove(MultiListObjectClass *obj);
  113. MultiListObjectClass * Internal_Get_List_Head(void);
  114. MultiListObjectClass * Internal_Remove_List_Head(void);
  115. private:
  116. MultiListNodeClass Head;
  117. friend class GenericMultiListIterator;
  118. friend class MultiListObjectClass;
  119. };
  120. inline bool GenericMultiListClass::Is_In_List(MultiListObjectClass * obj)
  121. {
  122. return Contains(obj);
  123. }
  124. inline bool GenericMultiListClass::Is_Empty(void)
  125. {
  126. return (Head.Next == &Head);
  127. }
  128. inline MultiListObjectClass * GenericMultiListClass::Internal_Get_List_Head(void)
  129. {
  130. if (Head.Next == &Head) {
  131. return 0; // no more objects
  132. } else {
  133. assert(Head.Next->Object != 0);
  134. return Head.Next->Object;
  135. }
  136. }
  137. /**
  138. ** GenericMultiListIterator
  139. ** This is the internal implementation of an iterator for a MultiList. The user should
  140. ** use the templated MultiListIterator which will do typecasting and proper reference
  141. ** counting rather than this class.
  142. */
  143. class GenericMultiListIterator
  144. {
  145. public:
  146. GenericMultiListIterator(GenericMultiListClass *list) { assert(list); First(list); }
  147. void First(GenericMultiListClass *list) { List = list; CurNode = List->Head.Next; }
  148. void First(void) { CurNode = List->Head.Next; }
  149. void Next(void) { CurNode = CurNode->Next; }
  150. void Prev(void) { CurNode = CurNode->Prev; }
  151. bool Is_Done(void) { return (CurNode == &(List->Head)); }
  152. protected:
  153. MultiListObjectClass * Current_Object(void) { return CurNode->Object; }
  154. GenericMultiListClass * List; // list we're working in
  155. MultiListNodeClass * CurNode; // node we're currently at.
  156. };
  157. /**************************************************************************************
  158. MultiListClass, MultiListIterator
  159. These templates inherits from GenericMultiListClass and GenericMultiListIterator
  160. and handle all typecasting to your object type. These classes require that
  161. your 'ObjectType' be derived from MultiListObjectClass.
  162. **************************************************************************************/
  163. /**
  164. ** MultiListClass
  165. ** This is a template derived from GenericMultiListClass which allows you
  166. ** to create specialized lists. All this template does is perform type-checking
  167. ** and internal type-casting of all pointers to your object type. Your
  168. ** object must be derived from MultiListObjectClass in order to be used
  169. ** with this template.
  170. */
  171. template <class ObjectType>
  172. class MultiListClass : public GenericMultiListClass
  173. {
  174. public:
  175. MultiListClass(void) { }
  176. virtual ~MultiListClass(void)
  177. {
  178. while (!Is_Empty()) {
  179. Remove_Head();
  180. }
  181. }
  182. bool Add(ObjectType * obj,bool onlyonce = true)
  183. {
  184. return Internal_Add(obj,onlyonce);
  185. }
  186. bool Add_Tail(ObjectType * obj,bool onlyonce = true)
  187. {
  188. return Internal_Add_Tail(obj,onlyonce);
  189. }
  190. bool Add_After(ObjectType * obj,const ObjectType * existing_list_member,bool onlyonce = true)
  191. {
  192. return Internal_Add_After(obj,existing_list_member,onlyonce);
  193. }
  194. bool Remove(ObjectType *obj)
  195. {
  196. return Internal_Remove(obj);
  197. }
  198. ObjectType * Get_Head()
  199. {
  200. return ((ObjectType*)Internal_Get_List_Head());
  201. }
  202. ObjectType * Peek_Head()
  203. {
  204. return ((ObjectType*)Internal_Get_List_Head());
  205. }
  206. ObjectType * Remove_Head()
  207. {
  208. return ((ObjectType*)Internal_Remove_List_Head());
  209. }
  210. void Reset_List()
  211. {
  212. while (Get_Head() != NULL) {
  213. Remove_Head();
  214. }
  215. }
  216. private:
  217. // not implemented
  218. MultiListClass(const MultiListClass & that);
  219. MultiListClass & operator = (const MultiListClass & that);
  220. };
  221. /**
  222. ** MultiListIterator
  223. ** This is a template derived from GenericMultiListIterator which allows you
  224. ** to iterate through specialized MultiListClass's. Again, it basically
  225. ** just type-casts all of the pointers for you (hopefully compiles away to
  226. ** nothing...)
  227. **
  228. ** WARNING: If you need to remove an object from a MultiList while you are iterating, use the
  229. ** Remove_Current_Object function (don't modify the list directly while iterating it).
  230. */
  231. template <class ObjectType>
  232. class MultiListIterator : public GenericMultiListIterator
  233. {
  234. public:
  235. MultiListIterator(MultiListClass<ObjectType> *list) : GenericMultiListIterator(list) {}
  236. ObjectType * Get_Obj(void)
  237. {
  238. return (ObjectType*)Current_Object();
  239. }
  240. ObjectType * Peek_Obj(void)
  241. {
  242. return (ObjectType*)Current_Object();
  243. }
  244. void Remove_Current_Object(void)
  245. {
  246. ObjectType * obj = Peek_Obj();
  247. if (obj != NULL) {
  248. Next();
  249. ((MultiListClass<ObjectType> *)List)->Remove(obj);
  250. }
  251. }
  252. };
  253. /**************************************************************************************
  254. RefMultiListClass, RefMultiListIterator
  255. These templates inherits from GenericMultiListClass and GenericMultiListIterator
  256. and handle all typecasting to your object type and also do proper reference tracking.
  257. These classes require that your 'ObjectType' be derived from MultiListObjectClass and
  258. RefCountClass.
  259. **************************************************************************************/
  260. /**
  261. ** RefMultiListClass
  262. ** This is a template derived from GenericMultiListClass which handles ref-counted
  263. ** objects. It assumes that 'ObjectType' is derived from MultiListObjectClass and
  264. ** RefCountClass. It adds type-checking and reference counting to
  265. ** GenericMultiListClass.
  266. */
  267. template <class ObjectType>
  268. class RefMultiListClass : public GenericMultiListClass
  269. {
  270. public:
  271. virtual ~RefMultiListClass(void)
  272. {
  273. while (!Is_Empty()) {
  274. Release_Head();
  275. }
  276. }
  277. bool Add(ObjectType * obj,bool onlyonce = true)
  278. {
  279. // if we add the object from our list, add a reference to it
  280. bool result = Internal_Add(obj,onlyonce);
  281. if (result == true) {
  282. obj->Add_Ref();
  283. }
  284. return result;
  285. }
  286. bool Add_Tail(ObjectType * obj,bool onlyonce = true)
  287. {
  288. // if we add the object from our list, add a reference to it
  289. bool result = Internal_Add_Tail(obj,onlyonce);
  290. if (result == true) {
  291. obj->Add_Ref();
  292. }
  293. return result;
  294. }
  295. bool Add_After(ObjectType * obj,const ObjectType * existing_list_member,bool onlyonce = true)
  296. {
  297. // if we add the object from our list, add a reference to it
  298. bool result = Internal_Add_After(obj,existing_list_member,onlyonce);
  299. if (result == true) {
  300. obj->Add_Ref();
  301. }
  302. return result;
  303. }
  304. bool Remove(ObjectType *obj)
  305. {
  306. // if we remove the object from our list, release our reference to it
  307. bool result = Internal_Remove(obj);
  308. if (result) {
  309. obj->Release_Ref();
  310. }
  311. return result;
  312. }
  313. bool Release_Head(void)
  314. {
  315. // remove the head from the list and release our reference to it
  316. ObjectType * obj = ((ObjectType*)Internal_Remove_List_Head());
  317. if (obj) {
  318. obj->Release_Ref();
  319. return true;
  320. } else {
  321. return false;
  322. }
  323. }
  324. ObjectType * Get_Head()
  325. {
  326. // if we have a head, add a reference for the caller of this function
  327. ObjectType * obj = ((ObjectType*)Internal_Get_List_Head());
  328. if (obj) {
  329. obj->Add_Ref();
  330. }
  331. return obj;
  332. }
  333. ObjectType * Peek_Head()
  334. {
  335. // no need to add-ref since the caller is 'peek'ing
  336. return ((ObjectType*)Internal_Get_List_Head());
  337. }
  338. ObjectType * Remove_Head()
  339. {
  340. // our reference is transferred to the caller of this function
  341. return ((ObjectType*)Internal_Remove_List_Head());
  342. }
  343. void Reset_List()
  344. {
  345. while (Peek_Head() != NULL) {
  346. Release_Head();
  347. }
  348. }
  349. };
  350. /**
  351. ** RefMultiListIterator
  352. ** This is a template derived from GenericMultiListIterator which can iterate
  353. ** through RefMultiListClass's. It adds type-checking and reference counting
  354. ** to GenericMultiListIterator.
  355. **
  356. ** WARNING: If you need to remove an object from a MultiList while you are iterating, use the
  357. ** Remove_Current_Object function (don't modify the list directly while iterating it). Also
  358. ** note that this function will cause the list to release its reference to the object.
  359. */
  360. template <class ObjectType>
  361. class RefMultiListIterator : public GenericMultiListIterator
  362. {
  363. public:
  364. RefMultiListIterator(RefMultiListClass<ObjectType> *list) : GenericMultiListIterator(list) {}
  365. ObjectType * Get_Obj(void)
  366. {
  367. ObjectType * obj = (ObjectType*)Current_Object();
  368. if (obj != NULL) {
  369. obj->Add_Ref();
  370. }
  371. return obj;
  372. }
  373. ObjectType * Peek_Obj(void)
  374. {
  375. return ((ObjectType*)Current_Object());
  376. }
  377. void Remove_Current_Object(void)
  378. {
  379. ObjectType * obj = Peek_Obj();
  380. if (obj != NULL) {
  381. Next();
  382. ((RefMultiListClass<ObjectType> *)List)->Remove(obj);
  383. }
  384. }
  385. };
  386. /**************************************************************************************
  387. PriorityMultiListIterator
  388. This template inherits from MultiListIterator and is used to implement a simple
  389. priority queue where nodes are popped off the head of the list and added to the tail.
  390. **************************************************************************************/
  391. template <class ObjectType>
  392. class PriorityMultiListIterator : public MultiListIterator<ObjectType>
  393. {
  394. public:
  395. PriorityMultiListIterator(MultiListClass<ObjectType> *list)
  396. : OriginalHead (NULL),
  397. MultiListIterator<ObjectType>(list) { First (); }
  398. bool
  399. Process_Head (ObjectType **object)
  400. {
  401. bool retval = false;
  402. // Check to ensure we don't wrap around the list (stop after iterating
  403. // the list once).
  404. if (CurNode != NULL && CurNode->Object != NULL && OriginalHead != CurNode) {
  405. OriginalHead = (OriginalHead == NULL) ? CurNode : OriginalHead;
  406. (*object) = (ObjectType *)CurNode->Object;
  407. // Remove the node from the head of the list and
  408. // add it to the tail of the list
  409. Remove_Current_Object();
  410. ((MultiListClass<ObjectType> *)PriorityMultiListIterator::List)->Add_Tail ((*object));
  411. retval = true;
  412. }
  413. return retval;
  414. }
  415. protected:
  416. MultiListNodeClass * OriginalHead;
  417. };
  418. #endif //LIST_CLASS_H