/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #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 Push() = ptNewObject; } /* * Insert a given object to container at specified index. */ template void CDynamicContainer::Insert(Type *ptNewObject, const INDEX iPos/*=0*/) { // get number of member that need moving and add new one const INDEX ctMovees = CStaticStackArray::Count() - iPos; CStaticStackArray::Push(); // move all members after insert position one place up Type **pptInsertAt = this->sa_Array+iPos; Type **pptMoveTo = pptInsertAt +1; memmove( pptMoveTo, pptInsertAt, sizeof(Type*)*ctMovees); // store pointer to newly inserted member at specified position *pptInsertAt = 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 sa_Array[iMember]=sa_Array[Count()-1]; 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; iMember Type *CDynamicContainer::Pointer(INDEX iMember) { ASSERT(this!=NULL); // check that index is currently valid ASSERT(iMember>=0 && iMember0); #endif return sa_Array[iMember]; } template const Type *CDynamicContainer::Pointer(INDEX iMember) const { ASSERT(this!=NULL); // check that index is currently valid ASSERT(iMember>=0 && iMember0); #endif return 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; iMember<>::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(Count()>=1); return *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. */