#ifndef ELIST_H #define ELIST_H #pragma warning( disable : 4211 ) #include #include "heap.h" //-------------------------------------------------------------------------------------- // // Mech Commander 2 // // standard linked list // //---------------------------------------------------------------------------// // Copyright (C) Microsoft Corporation. All rights reserved. // //===========================================================================// //************************************************************************************************* #define ELIST_TPL_DEF template #define ELIST_TPL_ARG T, T_ARG //************************************************************************************************* /************************************************************************************************** CLASS DESCRIPTION EList: This template class is a doubly linked list. The list is implemented using a fixed memory pool, which ensures proximity of all the elements, in order to increase the cacheability of the list. Two template parameters are required to declare a list. The first is the type of the object, that is intended to be stored in the list. The second is the type by which we intend to pass the object. The user needs to pass the initial element count and the amount of elements to grow the memory pool by, if required to accomodate all elements, to the constructor. Optionally a name can be supplied, however this will only be used during debug builds. Example: EList m_List(10, 5, "SomeList"); EList m_List(100, 10); Note: The second template argument is const to provide for const safety. It is syntacticly legal to use a non-const version, however, it will not provide const safty. Unfortunately there is no way to prevent this. Classes used with the list need to define a copy constructor, an assignment operator, and an equality operator in order to work properly (of course only if the default versions are not sufficient). **************************************************************************************************/ #ifndef __PLACEMENT_NEW_INLINE #define __PLACEMENT_NEW_INLINE inline void *__cdecl operator new(size_t, void *_P) {return (_P); } // placement new #endif ELIST_TPL_DEF class EList { protected: // // The node is used to chain the elements of the list together, it contains pointers // to the elements preceeding or following it, in addition to the element itself. // If no preceeding or following element are present the value is NULL // struct ENode { ENode(T_ARG New_Element) : m_Data(New_Element) {}; ENode* m_pNext; ENode* m_pPrev; T m_Data; private: ENode& operator=(const ENode& rNode); }; enum { MAX_NAME_LENGTH = 64 }; public: /************************************************************************************************** CLASS DESCRIPTION EList::EConstIterator This class is used to iterate through the List. You can read objects with this iterator but you can't change them. Use class !!(EIterator) for changing objects. **************************************************************************************************/ class EConstIterator { public: // Note: Code needs to be implemented in class decleration, due // to MSVC bug with nested template classes inline EConstIterator() { m_pCur_Node = NULL; } inline EConstIterator(const EConstIterator& rIter) { m_pCur_Node = rIter.m_pCur_Node; } inline EConstIterator& operator=(const EConstIterator& rIter) { m_pCur_Node = rIter.m_pCur_Node; return(*this); } // // NOTE: Postfix operators require "int" to be passed as parameter, // else compiler error C2807 will occur when used // inline EConstIterator& operator++(int) // postfix increment { #ifdef DEBUG if(!(IsValid())) { gosASSERT("EList::EIterator: Attempt to increment invalid iterator\n"); } #endif m_pCur_Node = m_pCur_Node->m_pNext; return(*this); } inline EConstIterator& operator--(int) // postfix decrement { #ifdef KTL_DEBUG if(!(IsValid())) { Assert("EList::EIterator: Attempt to decrement invalid iterator\n"); } #endif m_pCur_Node = m_pCur_Node->m_pPrev; return(*this); } inline EConstIterator& operator+=(unsigned long Increment) { while(Increment) { #ifdef KTL_DEBUG if(!(IsValid())) { Assert("EList::EIterator: Attempt to increment invalid iterator\n"); } #endif m_pCur_Node = m_pCur_Node->m_pNext; Increment--; } return(*this); } inline EConstIterator& operator-=(unsigned long Decrement) { while(Decrement) { #ifdef KTL_DEBUG if(!(IsValid())) { Assert("EList::EIterator: Attempt to increment invalid iterator\n"); } #endif m_pCur_Node = m_pCur_Node->m_pPrev; Decrement--; } return(*this); } inline bool operator==(const EConstIterator& rIter) const { return(m_pCur_Node == rIter.m_pCur_Node); } inline bool operator!=(const EConstIterator& rIter) const { return(m_pCur_Node != rIter.m_pCur_Node); } inline T_ARG operator*() const { return Item(); } inline T_ARG Item() const { return(m_pCur_Node->m_Data); } inline bool IsValid() const { return(m_pCur_Node ? true : false); } inline bool IsDone() const { return(m_pCur_Node ? false : true); } friend class EList; protected: ENode* m_pCur_Node; #ifdef KTL_DEBUG char m_Name[64]; #endif }; // END CLASS EConstIterator /************************************************************************************************** CLASS DESCRIPTION EList::EIterator This class is used for non constant iteration through a list. **************************************************************************************************/ class EIterator : public EConstIterator { public: inline EIterator() : EConstIterator() {} inline EIterator(const EIterator& rIter) : EConstIterator(rIter) {} inline T& Item() { return(m_pCur_Node->m_Data); } inline T& operator*() { return Item(); } }; // END CLASS EIterator //===== ENUMERATIONS & CONSTANTS ===== typename static const EIterator INVALID_ITERATOR; //===== CREATORS ===== inline EList(); EList(const EList& rList); ~EList(); //===== OPERATORS ===== EList& operator=(const EList& rList); inline T& operator[](unsigned long Pos); inline T& operator[](const typename EList::EIterator& rIter); inline T_ARG operator[](unsigned long Pos) const; inline T_ARG operator[](const typename EList::EIterator& rIter) const; inline bool operator==(const EList& rList) const; inline bool operator!=(const EList& rList) const; //===== MANIPULATORS ===== bool Clear(); inline bool Prepend(T_ARG New_Element); // Add an element to the start of the list inline bool Append(T_ARG New_Element); // Add an element to the end of the list inline bool Insert(T_ARG New_Element, const typename EList::EIterator& rIter); // Insert an element bofore the specified position inline bool Insert(T_ARG New_Element, unsigned long Pos); // Insert an element bofore the specified position bool Prepend(const EList& rList); // Prepend a list to this one bool Append(const EList& rList); // Append a list to this one bool Insert(const EList& rList, const typename EList::EIterator& rIter); // Insert a list at the specified position bool Insert(const EList& rList, unsigned long Pos); // Insert a list at the specified position inline bool DeleteHead(); // Remove the element at the beginning of the list inline bool DeleteTail(); // Remove the element at the end of the list inline bool Delete(const typename EList::EIterator& rIter); // Remove the element at the specified position inline bool Delete(unsigned long Pos); // Remove the element at the specified position inline bool Delete(const typename EList::EIterator& rStart_Iter, const typename EList::EIterator& rEnd_Iter); // Remove the element at the specified position inline bool Delete(unsigned long Start_Pos, unsigned long End_Pos); // Remove the element at the specified position inline bool Replace(T_ARG Element, const typename EList::EIterator& rIter); // Replace an element at the specified position inline bool Replace(T_ARG Element, unsigned long Pos); // Replace an element at the specified position inline typename EList::EIterator Iterator(unsigned long Pos); inline const typename EList::EConstIterator Iterator(unsigned long Pos) const; inline typename EList::EIterator Begin(); inline const typename EList::EConstIterator Begin() const; inline typename EList::EIterator End(); inline const typename EList::EConstIterator End() const; inline T& Get(const typename EList::EIterator& rIter); // Retrieve the element at the specified position inline T& Get(unsigned long Pos); // Retrieve the element at the specified position inline T& GetHead(); // Retrieve the element at the start of the list inline T& GetTail(); // Retrieve the element at the end of the list //===== ACCESSORS ===== inline T_ARG Get(const typename EList::EConstIterator& rIter) const; // Retrieve the element at the specified position inline T_ARG Get(unsigned long Pos) const; // Retrieve the element at the specified position inline T_ARG GetHead() const; // Retrieve the element at the start of the list inline T_ARG GetTail() const; // Retrieve the element at the end of the list inline unsigned long Count() const; // Get the number of elements in the list inline bool IsEmpty() const; // Check if the list is empty inline bool Exists(unsigned long Pos) const;// Check if an element at that position exists inline typename EList::EConstIterator Find(T_ARG Item, unsigned long Start_Index = 0) const; inline typename EList::EIterator Find(T_ARG Item, unsigned long Start_Index = 0); inline typename EList::EConstIterator Find(T_ARG Item, const typename EList::EConstIterator& rStart_Iterator) const; inline typename EList::EIterator Find(T_ARG Item, const typename EList::EIterator& rStart_Iterator); inline unsigned long GrowSize() const; // Get the growsize of list private: //===== DATA ===== unsigned long m_Count; // number of elements currently in list ENode* m_pHead; // pointer to first node in list ENode* m_pTail; // pointer to last node in list //===== HELPER FUNCTIONS ===== inline bool AddFirstElement(T_ARG New_Element); inline typename EList::ENode* CreateElement(T_ARG New_Element); inline void KillElement(ENode* pElement); void DestroyList(); bool CopyData(const EList& rSrc); }; // END CLASS EList //************************************************************************************************* // Constants //************************************************************************************************* ELIST_TPL_DEF const typename EList::EIterator EList::INVALID_ITERATOR = EList::EIterator(); //************************************************************************************************* // Inline Functions //************************************************************************************************* //------------------------------------------------------------------------------------------------- // CREATORS //------------------------------------------------------------------------------------------------- /************************************************************************************************** FUNCTION DESCRIPTION: EList Standard constructor used to instantiate a list INPUT PARAMETERS: Size: Initial size of the memory pool in number of elements Grow: The size in elements to grow the pool when required pName: The name of the list (optional) ***************************************************************************************************/ ELIST_TPL_DEF inline EList::EList() : m_Count(0), m_pHead(NULL), m_pTail(NULL) { } /************************************************************************************************** FUNCTION DESCRIPTION: EList Copy constructor of the list INPUT PARAMETERS: rList: The list to be made a copy of ***************************************************************************************************/ ELIST_TPL_DEF EList::EList(const EList& rList) { CopyData(rList); } /************************************************************************************************** FUNCTION DESCRIPTION: ~EList List Destructor, deletes all the elements in the list and then frees the memory pool ***************************************************************************************************/ ELIST_TPL_DEF EList::~EList() { DestroyList(); } //------------------------------------------------------------------------------------------------- // OPERATORS //------------------------------------------------------------------------------------------------- /************************************************************************************************** FUNCTION DESCRIPTION: operator= Assignment operator, destroys the current elements and creates copies of all the elements in the source list and adds them to this list. INPUT PARAMETERS: rList: The list to be assigned to this one RETURN VALUE: A reference to this list ***************************************************************************************************/ ELIST_TPL_DEF EList& EList::operator=(const EList& rList) { // // Get rid of any list entries that might be used // DestroyList(); CopyData(rList); return(*this); } /************************************************************************************************** FUNCTION DESCRIPTION: operator[] Retrieve a reference to an element in the list. Const versions of these functions are also supplied INPUT PARAMETERS: rIter: An iterator that points at the element for which we want a reference Pos: Position of the element in the list for which we want a reference RETURN VALUE: A reference to the desired element ***************************************************************************************************/ ELIST_TPL_DEF inline T& EList::operator[](const typename EList::EIterator& rIter) { gosASSERT(rIter.IsValid() && m_Count); // Make sure we are using a valid iterator and have something in the list return(rIter.m_pCur_Node->m_Data); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline T& EList::operator[](unsigned long Pos) { gosASSERT(Pos < m_Count); // Need to stay within range of number of elements return operator[](Iterator((unsigned long)Pos)); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline T_ARG EList::operator[](const typename EList::EIterator& rIter) const { gosASSERT(rIter.IsValid() && m_Count); // Make sure we are using a valid iterator and have something in the list return(rIter.m_pCur_Node->m_Data); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline T_ARG EList::operator[](unsigned long Pos) const { gosASSERT(Pos < m_Count); // Need to stay within range of number of elements return(Get(Iterator(Pos))); } /************************************************************************************************** FUNCTION DESCRIPTION: operator== Equality operator, tests if this and another list are equal INPUT PARAMETERS: rList: Reference to the list we want to compare this one with RETURN VALUE: TRUE if equal, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::operator==(const EList& rList) const { // // If the count of elements is different in each list, // they're not equal // if(m_Count != rList.m_Count) { return(false); } // // In case both lists are empty, they're equal, however, we don't // want to iterate if there is nothing to iterate // if(m_Count == 0 && rList.m_Count == 0) { return(true); } EConstIterator List_Iter = rList.Begin(); EConstIterator This_Iter = Begin(); // // Iterate through both lists and check if they're equal // for(unsigned long i = 0; i < m_Count; i++) { if(List_Iter.Item() != This_Iter.Item()) { return(false); } } return(true); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline bool EList::operator!=(const EList& rList) const { return(!(rList == *this)); } //------------------------------------------------------------------------------------------------- // MANIPULATORS //------------------------------------------------------------------------------------------------- /************************************************************************************************** FUNCTION DESCRIPTION: Iterator Get an iterator that points at the element corresponding with the Position passed INPUT PARAMETERS: Pos: The position of the element we want an iterator for RETURN VALUE: An iterator that points at the element at the position we passed ***************************************************************************************************/ ELIST_TPL_DEF inline typename EList::EIterator EList::Iterator(unsigned long Pos) { gosASSERT(Pos < m_Count && m_Count); // Need to stay within range of number of elements if(!m_Count) { return(INVALID_ITERATOR); } // // Iterate through the list until we get to the element we desire // ENode *pNode = m_pHead; for(unsigned long i = 0; i < Pos; i++) { pNode = pNode->m_pNext; } EIterator Iter; Iter.m_pCur_Node = pNode; return(Iter); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline const typename EList::EConstIterator EList::Iterator(unsigned long Pos) const { gosASSERT(Pos < m_Count && m_Count); // Need to stay within range of number of elements if(!m_Count) { return(INVALID_ITERATOR); } // // Iterate through the list until we get to the element we desire // ENode *pNode = m_pHead; for(unsigned long i = 0; i < Pos; i++) { pNode = pNode->m_pNext; } EIterator Iter; Iter.m_pCur_Node = pNode; return(Iter); } /************************************************************************************************** FUNCTION DESCRIPTION: Begin Get an iterator that points at the head element of the list. Also available as const version RETURN VALUE: An iterator that points at the head element ***************************************************************************************************/ ELIST_TPL_DEF inline typename EList::EIterator EList::Begin() { if(!m_Count) { return(INVALID_ITERATOR); } EIterator Iter; Iter.m_pCur_Node = m_pHead; return(Iter); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline const typename EList::EConstIterator EList::Begin() const { if(!m_Count) { return(INVALID_ITERATOR); } EIterator Iter; Iter.m_pCur_Node = m_pHead; return(Iter); } /************************************************************************************************** FUNCTION DESCRIPTION: End Get an iterator that points at the tail element of the list Also available as const version RETURN VALUE: An iterator that points at the tail element ***************************************************************************************************/ ELIST_TPL_DEF inline typename EList::EIterator EList::End() { gosASSERT(m_Count); // Don't try to get an iterator if list is empty if(!m_Count) { return(INVALID_ITERATOR); } EIterator Iter; Iter.m_pCur_Node = m_pTail; return(Iter); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline const typename EList::EConstIterator EList::End() const { gosASSERT(m_Count); // Don't try to get an iterator if list is empty if(!m_Count) { return(INVALID_ITERATOR); } EIterator Iter; Iter.m_pCur_Node = m_pTail; return(Iter); } /************************************************************************************************** FUNCTION DESCRIPTION: Clear Deletes all elements from the list RETURN VALUE: TRUE if success ***************************************************************************************************/ ELIST_TPL_DEF bool EList::Clear() { DestroyList(); return(true); // <> BR - need to do checking } /************************************************************************************************** FUNCTION DESCRIPTION: Prepend Prepend an element to the list, this element will be the new head element INPUT PARAMETERS: New_Element: The element we want to prepend to the list RETURN VALUE: TRUE if success ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Prepend(T_ARG New_Element) { // // If the list is empty, let's create the first element // if(IsEmpty()) { return(AddFirstElement(New_Element)); } // // Otherwise create a new element and prepend to to the list // ENode* pNode = CreateElement(New_Element); if(pNode) { m_pHead->m_pPrev = pNode; pNode->m_pNext = m_pHead; pNode->m_pPrev = NULL; m_pHead = pNode; m_Count++; return(true); } return(false); // <> BR } /************************************************************************************************** FUNCTION DESCRIPTION: Append Append an element to the list, this element will be the new tail element INPUT PARAMETERS: New_Element: The element we want to append to the list RETURN VALUE: TRUE if success ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Append(T_ARG New_Element) { // // If the list is empty, let's create the first element // if(IsEmpty()) { return(AddFirstElement(New_Element)); } // // Otherwise create a new element and append to to the list // ENode* pNode = CreateElement(New_Element); if(pNode) { m_pTail->m_pNext = pNode; pNode->m_pPrev = m_pTail; pNode->m_pNext = NULL; m_pTail = pNode; m_Count++; return(true); } return(false); } /************************************************************************************************** FUNCTION DESCRIPTION: Insert Insert an element into the list at the given position INPUT PARAMETERS: New_Element: The element to be added Pos: The position at which to insert the element rIter: An iterator the points to the location where we want to insert the element RETURN VALUE: TRUE if success ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Insert(T_ARG New_Element, const typename EList::EIterator& rIter) { // // Make sure we have a valid iterator before we continue // gosASSERT(rIter.m_pCur_Node); // // Attempt to create a new element // ENode* pNode = CreateElement(New_Element); if(!pNode) { return(false); } // // Connect the newly created node // pNode->m_pNext = rIter.m_pCur_Node; pNode->m_pPrev = rIter.m_pCur_Node->m_pPrev; // // Make sure to connect the previous node only if we are not the first in the list // if(pNode->m_pPrev) { pNode->m_pPrev->m_pNext = pNode; } else { // if we are, set the haed pointer m_pHead = pNode; } // // Last thing to do is to connect the next node to oursef // pNode->m_pNext->m_pPrev = pNode; m_Count++; return(true); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline bool EList::Insert(T_ARG New_Element, unsigned long Pos) { gosASSERT(m_Count > Pos && m_Count); // // We can't INSERT after the end of the list, so fail here // if(m_Count <= Pos) { return(false); } // // In case list is empty, simply prepend the element, Prepend() handles this case // if(IsEmpty()) { return(Prepend(New_Element)); } return(Insert(New_Element, Iterator(Pos))); } /************************************************************************************************** FUNCTION DESCRIPTION: DeleteHead Delete the head element from the list. This will call the destructor of the element to assure that any memory allocated by the element can be freed. RETURN VALUE: TRUE is success, FALSE if list is empty ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::DeleteHead() { // // can't delete anything if there is nothing... // gosASSERT(m_Count); if(!m_Count) { return(false); } // // In case it's the only element in the list // if(m_Count == 1) { KillElement(m_pHead); m_pHead = m_pTail = NULL; // make sure haed and tail pointers are set to NULL // if the list is empty m_Count = 0; return(true); } else { ENode* pElement_To_Kill = m_pHead; // Get the element we want to kill m_pHead = m_pHead->m_pNext; // Second element becomes head of the list m_pHead->m_pPrev = NULL; KillElement(pElement_To_Kill); m_Count--; return(true); } } /************************************************************************************************** FUNCTION DESCRIPTION: DeleteTail Delete the tail element from the list. This will call the destructor of the element to assure that any memory allocated by the element can be freed. RETURN VALUE: TRUE is success, FALSE if list is empty ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::DeleteTail() { // // Make sure we're not trying to delete from an empty list // gosASSERT(m_Count); if(!m_Count) { return(false); } if(m_Count == 1) { KillElement(m_pHead); m_pHead = m_pTail = NULL; // make sure haed and tail pointers are set to NULL // if the list is empty m_Count = 0; return(true); } else { ENode* pElement_To_Kill = m_pTail; m_pTail = m_pTail->m_pPrev; m_pTail->m_pNext = NULL; KillElement(pElement_To_Kill); m_Count--; return(true); } } /************************************************************************************************** FUNCTION DESCRIPTION: Delete Delete an element from the list INPUT PARAMETERS: rIter: An iterator that points at the element we want to delete RETURN VALUE: TRUE if success ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Delete(const typename EList::EIterator& rIter) { // // Verify that we have a valid iterator // gosASSERT(rIter.IsValid()); if(m_Count == 1) { KillElement(m_pHead); m_pHead = m_pTail = NULL; m_Count = 0; return(true); } else { ENode* pElement_To_Kill = rIter.m_pCur_Node; if(m_pTail == pElement_To_Kill) { m_pTail = pElement_To_Kill->m_pPrev; m_pTail->m_pNext = NULL; } else if(m_pHead == pElement_To_Kill) { m_pHead = pElement_To_Kill->m_pNext; m_pHead->m_pPrev = NULL; } else { pElement_To_Kill->m_pPrev->m_pNext = pElement_To_Kill->m_pNext; pElement_To_Kill->m_pNext->m_pPrev = pElement_To_Kill->m_pPrev; } KillElement(pElement_To_Kill); m_Count--; return(true); } } /************************************************************************************************** FUNCTION DESCRIPTION: Delete Delete an element from the list INPUT PARAMETERS: Pos: Position of the element we want to delete RETURN VALUE: TRUE if success ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Delete(unsigned long Pos) { gosASSERT(m_Count > Pos && m_Count); // // We can't DELETE after the end of the list or if empty, so fail here // if(m_Count <= Pos || (!m_Count)) { return(false); } return(Delete(Iterator(Pos))); } /************************************************************************************************** FUNCTION DESCRIPTION: Delete Delete a range of elements in the list INPUT PARAMETERS: Start_Pos: First element in the list to delete End_Pos: Last element in the list to delete rStart_Iter:First element in the list to delete rEnd_Iter: Last element in the list to delete RETURN VALUE: TRUE if successfull ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Delete(const typename EList::EIterator& rStart_Iter, const typename EList::EIterator& rEnd_Iter) { gosASSERT(rStart_Iter.IsValid() && rEnd_Iter.IsValid()); gosASSERT((rStart_Iter != rEnd_Iter)); if( (!(rStart_Iter.IsValid())) || (!(rEnd_Iter.IsValid())) ) { return(false); } EIterator Iter; EIterator Next_Iter = rStart_Iter; while(Next_Iter != rEnd_Iter) { Iter = Next_Iter; Next_Iter++; Delete(Iter); } return(true); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline bool EList::Delete(unsigned long Start_Pos, unsigned long End_Pos) { gosASSERT(Start_Pos < End_Pos); return(Delete(Iterator(Start_Pos), Iterator(End_Pos))); } /************************************************************************************************** FUNCTION DESCRIPTION: Get Gets a reference to the element that is at the position we passed to the function INPUT PARAMETERS: Pos: The position of the element we want to get rIter: The iterator of the element we want to get RETURN VALUE: Reference to the element at the position we passed ***************************************************************************************************/ ELIST_TPL_DEF inline T& EList::Get(const typename EList::EIterator& rIter) { gosASSERT(m_Count && rIter.IsValid()); return(rIter.m_pCur_Node->m_Data); } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline T& EList::Get(unsigned long Pos) { gosASSERT(m_Count > Pos && m_Count); return(Get(Iterator(Pos))); } /************************************************************************************************** FUNCTION DESCRIPTION: GetHead Get a reference to the element that is at the head of the list RETURN VALUE: Reference to the element at the head of the list ***************************************************************************************************/ ELIST_TPL_DEF inline T& EList::GetHead() { gosASSERT(m_Count); return(m_pHead->m_Data); } /************************************************************************************************** FUNCTION DESCRIPTION: GetTail Get a reference to the element that is at the tail of the list RETURN VALUE: Reference to the element at the tail of the list ***************************************************************************************************/ ELIST_TPL_DEF inline T& EList::GetTail() { gosASSERT(m_Count); return(m_pTail->m_Data); } /************************************************************************************************** FUNCTION DESCRIPTION: Replace Replace an element in the list with a new one INPUT PARAMETERS: Element: The new element we want to replace the old one with rIter: An iterator to the element we want to replace RETURN VALUE: TRUE if success, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Replace(T_ARG Element, const typename EList::EIterator& rIter) { gosASSERT(rIter.IsValid()); if(!(rIter.IsValid())) { return(false); } rIter.m_pCur_Node->m_Data = Element; return(true); } /************************************************************************************************** FUNCTION DESCRIPTION: Replace Replace an element in the list with a new one INPUT PARAMETERS: Element: The new element we want to replace the old one with Pos: An index to the element we want to replace RETURN VALUE: TRUE if success, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Replace(T_ARG Element, unsigned long Pos) { return(Replace(Element, Iterator(Pos))); } /************************************************************************************************** FUNCTION DESCRIPTION: Append Appends the given list to this one INPUT PARAMETERS: rList: A reference to the list that is to be prepended RETURN VALUE: TRUE if success, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF bool EList::Append(const EList& rList) { gosASSERT(&rList != this); // // Iterate through the source list and add any element to this one // const ENode* pNode = rList.m_pHead; for(unsigned long i = 0; i < rList.m_Count; i++) { Append(pNode->m_Data); // <> BR - This needs to be optimized pNode = pNode->m_pNext; } return(true); } /************************************************************************************************** FUNCTION DESCRIPTION: Prepend Prepends the given list to this one INPUT PARAMETERS: rList: A reference to the list that is to be prepended RETURN VALUE: TRUE if success, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF bool EList::Prepend(const EList& rList) { gosASSERT(&rList != this); // // Iterate through the source list and add any element to this one // const ENode* pNode = rList.m_pTail; for(unsigned long i = 0; i < rList.m_Count; i++) { Prepend(pNode->m_Data); // <> BR - This needs to be optimized pNode = pNode->m_pPrev; } return(true); } /************************************************************************************************** FUNCTION DESCRIPTION: Insert Insert all elements from the list given into this list INPUT PARAMETERS: rList: A reference to the list to be inserted rIter: An iterator into the list at which to start the insert RETURN VALUE: TRUE if success, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF bool EList::Insert(const EList& rList, const typename EList::EIterator& rIter) { gosASSERT(&rList != this); gosASSERT(rIter.IsValid()); EConstIterator Src_Iter = rList.Begin(); for(unsigned long i = 0; i < rList.m_Count; i++) { Insert(Src_Iter.Item(), rIter); Src_Iter++; } return(true); } /************************************************************************************************** FUNCTION DESCRIPTION: Insert Insert all elements from the list given into this list INPUT PARAMETERS: rList: A reference to the list to be inserted Pos: An index to the position at which to start the insert RETURN VALUE: TRUE if success, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF bool EList::Insert(const EList& rList, unsigned long Pos) { gosASSERT( &rList != this); return(Insert(rList, Iterator(Pos))); } //------------------------------------------------------------------------------------------------- // ACCESSORS //------------------------------------------------------------------------------------------------- /************************************************************************************************** FUNCTION DESCRIPTION: Get Get an element from the list using an iterator to determine it's location INPUT PARAMETERS: rIter: The iterator of the element we want to get RETURN VALUE: The element referenced by the iterator ***************************************************************************************************/ ELIST_TPL_DEF inline T_ARG EList::Get(const typename EList::EConstIterator& rIter) const { gosASSERT(m_Count && rIter.IsValid()); return(rIter.m_pCur_Node->m_Data); } /************************************************************************************************** FUNCTION DESCRIPTION: Get Get the element that is at the position we passed to the function INPUT PARAMETERS: Pos: The position of the element we want to get RETURN VALUE: The element at the position we passed ***************************************************************************************************/ ELIST_TPL_DEF inline T_ARG EList::Get(unsigned long Pos) const { gosASSERT(m_Count > Pos && m_Count); return(Get(Iterator(Pos))); } /************************************************************************************************** FUNCTION DESCRIPTION: GetHead Get the element that is at the head of the list RETURN VALUE: The element at the head of the list ***************************************************************************************************/ ELIST_TPL_DEF inline T_ARG EList::GetHead() const { gosASSERT(m_Count); return(m_pHead->m_Data); } /************************************************************************************************** FUNCTION DESCRIPTION: GetTail Get the element that is at the tail of the list RETURN VALUE: The element at the tail of the list ***************************************************************************************************/ ELIST_TPL_DEF inline T_ARG EList::GetTail() const { gosASSERT(m_Count); return(m_pTail->m_Data); } /************************************************************************************************** FUNCTION DESCRIPTION: Find Search through the list for the item corresponding to "Item" INPUT PARAMETERS: Item: The item to search for Start_Index: The element at which to start the search RETURN VALUE: The iterator that corresponds with the element in the list we searched for, or INVALID_ITERATOR if the element could not be found ***************************************************************************************************/ ELIST_TPL_DEF inline typename EList::EConstIterator EList::Find(T_ARG Item, unsigned long Start_Index) const { gosASSERT(Start_Index < m_Count && (!(IsEmpty()))); return(Find(Item, Iterator(Start_Index))); } /************************************************************************************************** FUNCTION DESCRIPTION: Find Search through the list for the item corresponding to "Item" INPUT PARAMETERS: Item: The item to search for Start_Index: The element at which to start the search RETURN VALUE: The iterator that corresponds with the element in the list we searched for, or INVALID_ITERATOR if the element could not be found ***************************************************************************************************/ ELIST_TPL_DEF inline typename EList::EIterator EList::Find(T_ARG Item, unsigned long Start_Index) { gosASSERT(Start_Index < m_Count && (!(IsEmpty()))); return(Find(Item, Iterator(Start_Index))); } /************************************************************************************************** FUNCTION DESCRIPTION: Find Search through the list for the item corresponding to "Item" INPUT PARAMETERS: Item: The item to search for rStart_Iterator: The element at which to start the search RETURN VALUE: The iterator that corresponds with the element in the list we searched for, or INVALID_ITERATOR if the element could not be found ***************************************************************************************************/ ELIST_TPL_DEF inline typename EList::EConstIterator EList::Find(T_ARG Item, const typename EList::EConstIterator& rStart_Iterator) const { gosASSERT(rStart_Iterator.IsValid()); EConstIterator Iter = rStart_Iterator; while(!(Iter.IsDone())) { if(Iter.Item() == Item) { return(Iter); } Iter++; } return(INVALID_ITERATOR); } /************************************************************************************************** FUNCTION DESCRIPTION: Find Search through the list for the item corresponding to "Item" INPUT PARAMETERS: Item: The item to search for rStart_Iterator: The element at which to start the search RETURN VALUE: The iterator that corresponds with the element in the list we searched for, or INVALID_ITERATOR if the element could not be found ***************************************************************************************************/ ELIST_TPL_DEF inline typename EList::EIterator EList::Find(T_ARG Item, const typename EList::EIterator& rStart_Iterator) { gosASSERT(rStart_Iterator.IsValid()); EIterator Iter = rStart_Iterator; while(!(Iter.IsDone())) { if(Iter.Item() == Item) { return(Iter); } Iter++; } return(INVALID_ITERATOR); } /************************************************************************************************** FUNCTION DESCRIPTION: Count Retrieve the number of elements currently in the list RETURN VALUE: The number of elements in the list ***************************************************************************************************/ ELIST_TPL_DEF inline unsigned long EList::Count() const { return(m_Count); } /************************************************************************************************** FUNCTION DESCRIPTION: IsEmpty Test the list for emptyness RETURN VALUE: TRUE if list is empty, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::IsEmpty() const { return(m_Count ? false : true); } /************************************************************************************************** FUNCTION DESCRIPTION: GrowSize Retrieve the current Growsize of the list RETURN VALUE: Current Growsize ***************************************************************************************************/ ELIST_TPL_DEF inline unsigned long EList::GrowSize() const { return(m_List_Pool.PageSize()); } /************************************************************************************************** FUNCTION DESCRIPTION: Exists Determine whether an entry exists in the list INPUT PARAMETERS: Pos: The position of the element we want to check for existance RETURN VALUE: TRUE if exist, FALSE if not ***************************************************************************************************/ ELIST_TPL_DEF inline bool EList::Exists(unsigned long Pos) const { if(Pos < m_Count) { return(true); } return(false); } //------------------------------------------------------------------------------------------------- // HELPER FUNCTIONS //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline bool EList::AddFirstElement(T_ARG New_Element) { ENode* pElement = CreateElement(New_Element); if(!pElement) { return(false); } m_pHead = m_pTail = pElement; // Setup List head and tail pointers pElement->m_pNext = pElement->m_pPrev = NULL; m_Count = 1; return(true); } //------------------------------------------------------------------------------------------------- // Note: m_pNext and m_pPrev are not initialized ELIST_TPL_DEF inline typename EList::ENode* EList::CreateElement(T_ARG New_Element) { ENode* pNode = (ENode*)systemHeap->Malloc( sizeof( ENode ) ); // Allocate memory for the node and data if(!pNode) { return(NULL); // return NULL if it fails } pNode = new(pNode) ENode(New_Element); // and construct the data object explicitly gosASSERT(pNode); return(pNode); // return the pointer to the Node of the element we created } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline void EList::KillElement(ENode* pElement) { gosASSERT(pElement); pElement->m_Data.~T(); // Destruct the data component of the element systemHeap->Free(pElement); // Now free the element } //------------------------------------------------------------------------------------------------- ELIST_TPL_DEF inline void EList::DestroyList() { // // simply return if list is empty // if(IsEmpty()) { return; } // // Otherwise remove the head element until none are left // while(m_Count) { DeleteHead(); } } /************************************************************************************************** FUNCTION DESCRIPTION: CopyData Copies data from the source list into this one NOTE: The function assumes the list to be empty at when it is called INPUT PARAMETERS: rSrc: Reference to the source list RETURN VALUE: TRUE is success ***************************************************************************************************/ ELIST_TPL_DEF bool EList::CopyData(const EList& rSrc) { // // Iterate through the source list and add any element to this one // m_Count = rSrc.m_Count; if(!m_Count) { m_pHead = m_pTail = NULL; return(true); } ENode* pSrc_Node = rSrc.m_pHead; ENode* pNode = CreateElement(pSrc_Node->m_Data); gosASSERT(pNode && pSrc_Node); // Should never be NULL m_pHead = m_pTail = pNode; m_pHead->m_pPrev = NULL; for(unsigned long i = 1; im_pNext; gosASSERT(pSrc_Node); // Should never be NULL m_pTail = CreateElement(pSrc_Node->m_Data); gosASSERT(m_pTail); m_pTail->m_pPrev = pNode; pNode->m_pNext = m_pTail; pNode = m_pTail; } m_pTail->m_pNext = NULL; return(true); } //************************************************************************************************* #endif // end of file ( ELIST.h )