| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : WWLib *
- * *
- * $Archive:: /Commando/Code/wwlib/multilist.h $*
- * *
- * Original Author:: Greg Hjelstrom *
- * *
- * $Author:: Jani_p $*
- * *
- * $Modtime:: 4/09/01 8:26p $*
- * *
- * $Revision:: 16 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #if defined(_MSC_VER)
- #pragma once
- #endif
- #ifndef MULTILIST_H
- #define MULTILIST_H
- #include "always.h"
- #include "mempool.h"
- #include <assert.h>
- class MultiListNodeClass;
- class GenericMultiListClass;
- /******************************************************************************
-
- MultiLists
- MultiLists solve the problem of needing to have objects that can be placed
- into multiple lists at the same time. MultiListNodes are all allocated from
- a pool which grows in chunks to avoid overhead from calling new and delete.
- All operations such as insertion, removal, checking if a list contains an
- object, are ether immediate or O(numlists) where numlists is the number of
- different lists that the object in question currently occupies.
- ******************************************************************************/
- /**
- ** MultiListObjectClass
- ** This is an object that can be linked into a MultiList. The only overhead
- ** for this is a single pointer to a MultiListNode.
- ** Objects that are linked into MulitLists must derive from this class.
- ** If you delete an instance of one of these objects while it is in one or more
- ** Multi-Lists, it will automatically remove itself from the lists.
- */
- class MultiListObjectClass
- {
- public:
- MultiListObjectClass(void) : ListNode(NULL) { }
- virtual ~MultiListObjectClass(void);
- MultiListNodeClass * Get_List_Node() const { return ListNode; }
- void Set_List_Node(MultiListNodeClass *node) { ListNode = node; }
- private:
- MultiListNodeClass * ListNode;
- };
- /**
- ** MultiListNodeClass
- ** These nodes allow objects to be linked in multiple lists. It is
- ** like a 2-D linked list where one dimension is the list of objects in a
- ** given list and the other dimension is the list of lists that a given object
- ** is in.
- */
- class MultiListNodeClass : public AutoPoolClass<MultiListNodeClass, 256>
- {
- public:
- MultiListNodeClass(void) { Prev = Next = NextList = 0; Object = 0; List = 0; }
- MultiListNodeClass *Prev; // prev object in list
- MultiListNodeClass *Next; // next object in list
- MultiListNodeClass *NextList; // next list this object is in
- MultiListObjectClass *Object; // pointer back to the object
- GenericMultiListClass *List; // pointer to list for this node
- };
- /**
- ** GenericMultiListClass
- ** This is an internal implementation class for Multi List. It is not meant to be used as-is
- ** Instead use the MultiListClass template which performs type-casting and reference counting
- ** on the objects that you add to the list.
- ** This simply contains the head node for a list. This is a doubly circularly linked list where
- ** our head node is a sentry. To easily iterate the list use the iterator defined below.
- */
- class GenericMultiListClass
- {
- public:
- GenericMultiListClass(void) { Head.Next = Head.Prev = &Head; Head.Object = 0; Head.NextList = 0; }
- virtual ~GenericMultiListClass(void);
-
- bool Is_In_List(MultiListObjectClass *obj);
- bool Contains(MultiListObjectClass * obj);
- bool Is_Empty(void);
- int Count(void);
- protected:
-
- bool Internal_Add(MultiListObjectClass *obj,bool onlyonce = true);
- bool Internal_Add_Tail(MultiListObjectClass * obj,bool onlyonce = true);
- bool Internal_Add_After(MultiListObjectClass * obj,const MultiListObjectClass * existing_list_member,bool onlyonce = true);
- bool Internal_Remove(MultiListObjectClass *obj);
- MultiListObjectClass * Internal_Get_List_Head(void);
- MultiListObjectClass * Internal_Remove_List_Head(void);
- private:
- MultiListNodeClass Head;
- friend class GenericMultiListIterator;
- friend class MultiListObjectClass;
- };
- inline bool GenericMultiListClass::Is_In_List(MultiListObjectClass * obj)
- {
- return Contains(obj);
- }
- inline bool GenericMultiListClass::Is_Empty(void)
- {
- return (Head.Next == &Head);
- }
- inline MultiListObjectClass * GenericMultiListClass::Internal_Get_List_Head(void)
- {
- if (Head.Next == &Head) {
- return 0; // no more objects
- } else {
- assert(Head.Next->Object != 0);
- return Head.Next->Object;
- }
- }
- /**
- ** GenericMultiListIterator
- ** This is the internal implementation of an iterator for a MultiList. The user should
- ** use the templated MultiListIterator which will do typecasting and proper reference
- ** counting rather than this class.
- */
- class GenericMultiListIterator
- {
- public:
- GenericMultiListIterator(GenericMultiListClass *list) { assert(list); First(list); }
- void First(GenericMultiListClass *list) { List = list; CurNode = List->Head.Next; }
- void First(void) { CurNode = List->Head.Next; }
- void Next(void) { CurNode = CurNode->Next; }
- void Prev(void) { CurNode = CurNode->Prev; }
- bool Is_Done(void) { return (CurNode == &(List->Head)); }
-
- protected:
-
- MultiListObjectClass * Current_Object(void) { return CurNode->Object; }
- GenericMultiListClass * List; // list we're working in
- MultiListNodeClass * CurNode; // node we're currently at.
- };
- /**************************************************************************************
- MultiListClass, MultiListIterator
- These templates inherits from GenericMultiListClass and GenericMultiListIterator
- and handle all typecasting to your object type. These classes require that
- your 'ObjectType' be derived from MultiListObjectClass.
- **************************************************************************************/
- /**
- ** MultiListClass
- ** This is a template derived from GenericMultiListClass which allows you
- ** to create specialized lists. All this template does is perform type-checking
- ** and internal type-casting of all pointers to your object type. Your
- ** object must be derived from MultiListObjectClass in order to be used
- ** with this template.
- */
- template <class ObjectType>
- class MultiListClass : public GenericMultiListClass
- {
- public:
- MultiListClass(void) { }
-
- virtual ~MultiListClass(void)
- {
- while (!Is_Empty()) {
- Remove_Head();
- }
- }
- bool Add(ObjectType * obj,bool onlyonce = true)
- {
- return Internal_Add(obj,onlyonce);
- }
- bool Add_Tail(ObjectType * obj,bool onlyonce = true)
- {
- return Internal_Add_Tail(obj,onlyonce);
- }
- bool Add_After(ObjectType * obj,const ObjectType * existing_list_member,bool onlyonce = true)
- {
- return Internal_Add_After(obj,existing_list_member,onlyonce);
- }
- bool Remove(ObjectType *obj)
- {
- return Internal_Remove(obj);
- }
- ObjectType * Get_Head()
- {
- return ((ObjectType*)Internal_Get_List_Head());
- }
- ObjectType * Peek_Head()
- {
- return ((ObjectType*)Internal_Get_List_Head());
- }
- ObjectType * Remove_Head()
- {
- return ((ObjectType*)Internal_Remove_List_Head());
- }
- void Reset_List()
- {
- while (Get_Head() != NULL) {
- Remove_Head();
- }
- }
- private:
- // not implemented
- MultiListClass(const MultiListClass & that);
- MultiListClass & operator = (const MultiListClass & that);
-
- };
- /**
- ** MultiListIterator
- ** This is a template derived from GenericMultiListIterator which allows you
- ** to iterate through specialized MultiListClass's. Again, it basically
- ** just type-casts all of the pointers for you (hopefully compiles away to
- ** nothing...)
- **
- ** WARNING: If you need to remove an object from a MultiList while you are iterating, use the
- ** Remove_Current_Object function (don't modify the list directly while iterating it).
- */
- template <class ObjectType>
- class MultiListIterator : public GenericMultiListIterator
- {
- public:
- MultiListIterator(MultiListClass<ObjectType> *list) : GenericMultiListIterator(list) {}
- ObjectType * Get_Obj(void)
- {
- return (ObjectType*)Current_Object();
- }
- ObjectType * Peek_Obj(void)
- {
- return (ObjectType*)Current_Object();
- }
- void Remove_Current_Object(void)
- {
- ObjectType * obj = Peek_Obj();
- if (obj != NULL) {
- Next();
- ((MultiListClass<ObjectType> *)List)->Remove(obj);
- }
- }
- };
- /**************************************************************************************
- RefMultiListClass, RefMultiListIterator
- These templates inherits from GenericMultiListClass and GenericMultiListIterator
- and handle all typecasting to your object type and also do proper reference tracking.
- These classes require that your 'ObjectType' be derived from MultiListObjectClass and
- RefCountClass.
- **************************************************************************************/
- /**
- ** RefMultiListClass
- ** This is a template derived from GenericMultiListClass which handles ref-counted
- ** objects. It assumes that 'ObjectType' is derived from MultiListObjectClass and
- ** RefCountClass. It adds type-checking and reference counting to
- ** GenericMultiListClass.
- */
- template <class ObjectType>
- class RefMultiListClass : public GenericMultiListClass
- {
- public:
- virtual ~RefMultiListClass(void)
- {
- while (!Is_Empty()) {
- Release_Head();
- }
- }
- bool Add(ObjectType * obj,bool onlyonce = true)
- {
- // if we add the object from our list, add a reference to it
- bool result = Internal_Add(obj,onlyonce);
- if (result == true) {
- obj->Add_Ref();
- }
- return result;
- }
- bool Add_Tail(ObjectType * obj,bool onlyonce = true)
- {
- // if we add the object from our list, add a reference to it
- bool result = Internal_Add_Tail(obj,onlyonce);
- if (result == true) {
- obj->Add_Ref();
- }
- return result;
- }
- bool Add_After(ObjectType * obj,const ObjectType * existing_list_member,bool onlyonce = true)
- {
- // if we add the object from our list, add a reference to it
- bool result = Internal_Add_After(obj,existing_list_member,onlyonce);
- if (result == true) {
- obj->Add_Ref();
- }
- return result;
- }
- bool Remove(ObjectType *obj)
- {
- // if we remove the object from our list, release our reference to it
- bool result = Internal_Remove(obj);
- if (result) {
- obj->Release_Ref();
- }
- return result;
- }
- bool Release_Head(void)
- {
- // remove the head from the list and release our reference to it
- ObjectType * obj = ((ObjectType*)Internal_Remove_List_Head());
- if (obj) {
- obj->Release_Ref();
- return true;
- } else {
- return false;
- }
- }
- ObjectType * Get_Head()
- {
- // if we have a head, add a reference for the caller of this function
- ObjectType * obj = ((ObjectType*)Internal_Get_List_Head());
- if (obj) {
- obj->Add_Ref();
- }
- return obj;
- }
- ObjectType * Peek_Head()
- {
- // no need to add-ref since the caller is 'peek'ing
- return ((ObjectType*)Internal_Get_List_Head());
- }
- ObjectType * Remove_Head()
- {
- // our reference is transferred to the caller of this function
- return ((ObjectType*)Internal_Remove_List_Head());
- }
- void Reset_List()
- {
- while (Peek_Head() != NULL) {
- Release_Head();
- }
- }
- };
- /**
- ** RefMultiListIterator
- ** This is a template derived from GenericMultiListIterator which can iterate
- ** through RefMultiListClass's. It adds type-checking and reference counting
- ** to GenericMultiListIterator.
- **
- ** WARNING: If you need to remove an object from a MultiList while you are iterating, use the
- ** Remove_Current_Object function (don't modify the list directly while iterating it). Also
- ** note that this function will cause the list to release its reference to the object.
- */
- template <class ObjectType>
- class RefMultiListIterator : public GenericMultiListIterator
- {
- public:
- RefMultiListIterator(RefMultiListClass<ObjectType> *list) : GenericMultiListIterator(list) {}
- ObjectType * Get_Obj(void)
- {
- ObjectType * obj = (ObjectType*)Current_Object();
- if (obj != NULL) {
- obj->Add_Ref();
- }
- return obj;
- }
- ObjectType * Peek_Obj(void)
- {
- return ((ObjectType*)Current_Object());
- }
- void Remove_Current_Object(void)
- {
- ObjectType * obj = Peek_Obj();
- if (obj != NULL) {
- Next();
- ((RefMultiListClass<ObjectType> *)List)->Remove(obj);
- }
- }
- };
- /**************************************************************************************
- PriorityMultiListIterator
- This template inherits from MultiListIterator and is used to implement a simple
- priority queue where nodes are popped off the head of the list and added to the tail.
- **************************************************************************************/
- template <class ObjectType>
- class PriorityMultiListIterator : public MultiListIterator<ObjectType>
- {
- public:
- PriorityMultiListIterator(MultiListClass<ObjectType> *list)
- : OriginalHead (NULL),
- MultiListIterator<ObjectType>(list) { First (); }
- bool
- Process_Head (ObjectType **object)
- {
- bool retval = false;
- // Check to ensure we don't wrap around the list (stop after iterating
- // the list once).
- if (CurNode != NULL && CurNode->Object != NULL && OriginalHead != CurNode) {
- OriginalHead = (OriginalHead == NULL) ? CurNode : OriginalHead;
- (*object) = (ObjectType *)CurNode->Object;
- // Remove the node from the head of the list and
- // add it to the tail of the list
- Remove_Current_Object();
- ((MultiListClass<ObjectType> *)PriorityMultiListIterator::List)->Add_Tail ((*object));
- retval = true;
- }
- return retval;
- }
-
- protected:
-
- MultiListNodeClass * OriginalHead;
- };
- #endif //LIST_CLASS_H
|