/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ #ifndef SE_INCL_DYNAMICCONTAINER_CPP #define SE_INCL_DYNAMICCONTAINER_CPP #ifdef PRAGMA_ONCE #pragma once #endif #include #include #include /* * Default constructor. */ template CDynamicContainer::CDynamicContainer(void) { #if CHECKARRAYLOCKING // not locked dc_LockCt = 0; #endif } /* * Copy constructor. */ template CDynamicContainer::CDynamicContainer(CDynamicContainer &dcOriginal) { #if CHECKARRAYLOCKING // not locked dc_LockCt = 0; #endif // call assignment operator (*this) = dcOriginal; } /* * Destructor -- removes all objects. */ template CDynamicContainer::~CDynamicContainer(void) { Clear(); } /* * Remove all objects, and reset the array to initial (empty) state. */ template void CDynamicContainer::Clear(void) { ASSERT(this!=NULL); CStaticStackArray::Clear(); } /* * Add a given object to container. */ template void CDynamicContainer::Add(Type *ptNewObject) { // set the new pointer this->Push() = ptNewObject; } /* * Remove a given object from container. */ template void CDynamicContainer::Remove(Type *ptOldObject) { ASSERT(this!=NULL); #if CHECKARRAYLOCKING // check that not locked for indices ASSERT(dc_LockCt == 0); #endif // find its index INDEX iMember=GetIndex(ptOldObject); // move last pointer here this->sa_Array[iMember]=this->sa_Array[this->Count()-1]; this->Pop(); } /* Test if a given object is in the container. */ template BOOL CDynamicContainer::IsMember(Type *ptOldObject) { ASSERT(this!=NULL); // slow !!!! // check all members for (INDEX iMember=0; iMemberCount(); iMember++) { if(this->sa_Array[iMember]==ptOldObject) { return TRUE; } } return FALSE; } /* * Get pointer to a member from it's index. */ template Type *CDynamicContainer::Pointer(INDEX iMember) { ASSERT(this!=NULL); // check that index is currently valid ASSERT(iMember>=0 && iMemberCount()); #if CHECKARRAYLOCKING // check that locked for indices ASSERT(dc_LockCt>0); #endif return this->sa_Array[iMember]; } template const Type *CDynamicContainer::Pointer(INDEX iMember) const { ASSERT(this!=NULL); // check that index is currently valid ASSERT(iMember>=0 && iMemberCount()); #if CHECKARRAYLOCKING // check that locked for indices ASSERT(dc_LockCt>0); #endif return this->sa_Array[iMember]; } /* * Lock for getting indices. */ template void CDynamicContainer::Lock(void) { ASSERT(this!=NULL); #if CHECKARRAYLOCKING ASSERT(dc_LockCt>=0); // increment lock counter dc_LockCt++; #endif } /* * Unlock after getting indices. */ template void CDynamicContainer::Unlock(void) { ASSERT(this!=NULL); #if CHECKARRAYLOCKING dc_LockCt--; ASSERT(dc_LockCt>=0); #endif } /* * Get index of a member from it's pointer. */ template INDEX CDynamicContainer::Index(Type *ptMember) { ASSERT(this!=NULL); // check that locked for indices #if CHECKARRAYLOCKING ASSERT(dc_LockCt>0); #endif return GetIndex(ptMember); } /* * Get index of a member from it's pointer without locking. */ template INDEX CDynamicContainer::GetIndex(Type *ptMember) { ASSERT(this!=NULL); // slow !!!! // check all members for (INDEX iMember=0; iMemberCount(); iMember++) { if(this->sa_Array[iMember]==ptMember) { return iMember; } } ASSERTALWAYS("CDynamicContainer<>::Index(): Not a member of this container!"); return 0; } /* Get first object in container (there must be at least one when calling this). */ template Type &CDynamicContainer::GetFirst(void) { ASSERT(this->Count()>=1); return *this->sa_Array[0]; } /* * Assignment operator. */ template CDynamicContainer &CDynamicContainer::operator=(CDynamicContainer &coOriginal) { CStaticStackArray::operator=(coOriginal); return *this; } /* * Move all elements of another array into this one. */ template void CDynamicContainer::MoveContainer(CDynamicContainer &coOther) { ASSERT(this!=NULL && &coOther!=NULL); // check that not locked for indices #if CHECKARRAYLOCKING ASSERT(dc_LockCt==0 && coOther.dc_LockCt==0); #endif CStaticStackArray::MoveArray(coOther); } ///////////////////////////////////////////////////////////////////// // CDynamicContainerIterator /* * Template class for iterating dynamic array. */ template class CDynamicContainerIterator { private: INDEX dci_Index; // index of current element CDynamicContainer &dci_Array; // reference to array public: /* Constructor for given array. */ inline CDynamicContainerIterator(CDynamicContainer &da); /* Destructor. */ inline ~CDynamicContainerIterator(void); /* Move to next object. */ inline void MoveToNext(void); /* Check if finished. */ inline BOOL IsPastEnd(void); /* Get current element. */ Type &Current(void) { return *dci_Array.Pointer(dci_Index); } Type &operator*(void) { return *dci_Array.Pointer(dci_Index); } operator Type *(void) { return dci_Array.Pointer(dci_Index); } Type *operator->(void) { return dci_Array.Pointer(dci_Index); } }; /* * Constructor for given array. */ template inline CDynamicContainerIterator::CDynamicContainerIterator(CDynamicContainer &da) : dci_Array(da) { // lock indices dci_Array.Lock(); dci_Index = 0; } /* * Destructor. */ template inline CDynamicContainerIterator::~CDynamicContainerIterator(void) { // unlock indices dci_Array.Unlock(); dci_Index = -1; } /* * Move to next object. */ template inline void CDynamicContainerIterator::MoveToNext(void) { ASSERT(this!=NULL); dci_Index++; } /* * Check if finished. */ template inline BOOL CDynamicContainerIterator::IsPastEnd(void) { ASSERT(this!=NULL); return dci_Index>=dci_Array.Count(); } // iterate whole dynamic container /* NOTE: The iterator defined by this macro must be destroyed before adding/removing * elements in the container. To do so, embed the for loop in additional curly braces. */ #define FOREACHINDYNAMICCONTAINER(container, type, iter) \ for(CDynamicContainerIterator iter(container); !iter.IsPastEnd(); iter.MoveToNext() ) #endif /* include-once check. */