123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- /* 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_DYNAMICARRAY_CPP
- #define SE_INCL_DYNAMICARRAY_CPP
- #ifdef PRAGMA_ONCE
- #pragma once
- #endif
- #include <Engine/Base/Memory.h>
- #include <Engine/Base/ListIterator.inl>
- #include <Engine/Templates/DynamicArray.h>
- // iterate whole dynamic array
- /* NOTE: The iterator defined by this macro must be destroyed before adding/removing
- * elements in the array. To do so, embed the for loop in additional curly braces.
- */
- #define FOREACHINDYNAMICARRAY(array, type, iter) \
- for(CDynamicArrayIterator<type> iter(array); !iter.IsPastEnd(); iter.MoveToNext() )
- class CDABlockInfo {
- public:
- CListNode bi_ListNode;
- void *bi_Memory;
- };
- /*
- * Default constructor.
- */
- template<class Type>
- CDynamicArray<Type>::CDynamicArray(void) {
- #if CHECKARRAYLOCKING
- // not locked
- da_LockCt = 0;
- #endif
- // set to empty array of pointers
- da_Pointers = NULL;
- da_Count = 0;
- }
- /*
- * Copy constructor.
- */
- template<class Type>
- CDynamicArray<Type>::CDynamicArray(CDynamicArray<Type> &daOriginal)
- {
- #if CHECKARRAYLOCKING
- // not locked
- da_LockCt = 0;
- #endif
- // set to empty array of pointers
- da_Pointers = NULL;
- da_Count = 0;
- // call assignment operator
- (*this) = daOriginal;
- }
- /*
- * Destructor -- frees all memory.
- */
- template<class Type>
- CDynamicArray<Type>::~CDynamicArray(void) {
- Clear();
- }
- /*
- * Destroy all objects, and reset the array to initial (empty) state.
- */
- template<class Type>
- void CDynamicArray<Type>::Clear(void) {
- ASSERT(this!=NULL);
- // if any pointers are allocated
- if (da_Count!=0) {
- /* NOTE: We must explicitly clear objects here, because array deleting
- * does not call object destructors!
- */
- // for all pointers
- for (INDEX iPointer=0; iPointer<da_Count; iPointer++) {
- // destroy the object that it points to
- ::Clear(*da_Pointers[iPointer]);
- }
- // free the pointers
- FreeMemory(da_Pointers);
- // mark as freed
- da_Pointers = NULL;
- da_Count = 0;
- // otherwise
- } else {
- // check that the pointers are really not allocated
- ASSERT(da_Pointers==NULL);
- // nothing to free
- }
- // for all memory blocks
- FORDELETELIST(CDABlockInfo, bi_ListNode, da_BlocksList, itBlock) {
- // free memory used by block (this doesn't call destructors - see note above!)
- delete[] (Type *)itBlock->bi_Memory;
- // free memory used by block info
- delete &itBlock.Current();
- }
- }
- /* Random access operator. */
- template<class Type>
- Type &CDynamicArray<Type>::operator[](INDEX iObject) {
- return *Pointer(iObject);
- };
- template<class Type>
- const Type &CDynamicArray<Type>::operator[](INDEX iObject) const {
- return *Pointer(iObject);
- };
- /*
- * Grow pointer array by a given number of members.
- */
- template<class Type>
- void CDynamicArray<Type>::GrowPointers(INDEX iCount) {
- ASSERT(this!=NULL && iCount>0);
- // if not yet allocated
- if (da_Count==0) {
- // check that the pointers are really not allocated
- ASSERT(da_Pointers==NULL);
- // allocate
- da_Count=iCount;
- da_Pointers = (Type **)AllocMemory(da_Count*sizeof(Type*));
- // if allocated
- } else {
- // grow to new size
- da_Count+=iCount;
- GrowMemory((void **)&da_Pointers, da_Count*sizeof(Type*));
- }
- }
- /*
- * Shrink pointer array by a given number of members.
- */
- template<class Type>
- void CDynamicArray<Type>::ShrinkPointers(INDEX iCount) {
- ASSERT(this!=NULL && iCount>0);
- // check that the pointers are allocated
- ASSERT(da_Pointers!=NULL);
- // decrement count
- da_Count-=iCount;
- // checked that it has not dropped below zero
- ASSERT(da_Count>=0);
- // if all pointers are freed by this
- if (da_Count==0) {
- // free the array
- FreeMemory(da_Pointers);
- da_Pointers = NULL;
- // if some remain
- } else {
- // shrink to new size
- ShrinkMemory((void **)&da_Pointers, da_Count*sizeof(Type*));
- }
- }
- /*
- * Allocate a new memory block.
- */
- template<class Type>
- Type *CDynamicArray<Type>::AllocBlock(INDEX iCount) {
- ASSERT(this!=NULL && iCount>0);
- Type *ptBlock;
- CDABlockInfo *pbi;
- // allocate the memory and call constructors for all members (+1 for cache-prefetch opt)
- ptBlock = new Type[iCount+1]; // call vector constructor, for better performance
- // allocate the block info
- pbi = new CDABlockInfo;
- // add the block to list
- da_BlocksList.AddTail(pbi->bi_ListNode);
- // remember block memory
- pbi->bi_Memory = ptBlock;
- return ptBlock;
- }
- /*
- * Create a given number of new members.
- */
- template<class Type>
- Type *CDynamicArray<Type>::New(INDEX iCount /*= 1*/) {
- ASSERT(this!=NULL && iCount>=0);
- // if no new members are needed in fact
- if (iCount==0) {
- // do nothing
- return NULL;
- }
- Type *ptBlock;
- INDEX iOldCount = da_Count;
- // grow the pointer table
- GrowPointers(iCount);
- // allocate the memory block
- ptBlock = AllocBlock(iCount);
- // set pointers
- for(INDEX iNewMember=0; iNewMember<iCount; iNewMember++) {
- da_Pointers[iOldCount+iNewMember] = ptBlock+iNewMember;
- }
- return ptBlock;
- }
- /*
- * Delete a given member.
- */
- template<class Type>
- void CDynamicArray<Type>::Delete(Type *ptMember) {
- ASSERT(this!=NULL);
- #if CHECKARRAYLOCKING
- // check that not locked for indices
- ASSERT(da_LockCt == 0);
- #endif
- // clear the object
- ::Clear(*ptMember);
- INDEX iMember=GetIndex(ptMember);
- // move last pointer here
- da_Pointers[iMember]=da_Pointers[da_Count-1];
- // shrink pointers by one
- ShrinkPointers(1);
- // do nothing to free memory
- //!!!!
- }
- /*
- * Get pointer to a member from it's index.
- */
- template<class Type>
- Type *CDynamicArray<Type>::Pointer(INDEX iMember) {
- ASSERT(this!=NULL);
- // check that index is currently valid
- ASSERT(iMember>=0 && iMember<da_Count);
- #if CHECKARRAYLOCKING
- // check that locked for indices
- ASSERT(da_LockCt>0);
- #endif
- return da_Pointers[iMember];
- }
- template<class Type>
- const Type *CDynamicArray<Type>::Pointer(INDEX iMember) const {
- ASSERT(this!=NULL);
- // check that index is currently valid
- ASSERT(iMember>=0 && iMember<da_Count);
- #if CHECKARRAYLOCKING
- // check that locked for indices
- ASSERT(da_LockCt>0);
- #endif
- return da_Pointers[iMember];
- }
- /*
- * Lock for getting indices.
- */
- template<class Type>
- void CDynamicArray<Type>::Lock(void) {
- ASSERT(this!=NULL);
- #if CHECKARRAYLOCKING
- ASSERT(da_LockCt>=0);
- // increment lock counter
- da_LockCt++;
- #endif
- }
- /*
- * Unlock after getting indices.
- */
- template<class Type>
- void CDynamicArray<Type>::Unlock(void) {
- ASSERT(this!=NULL);
- #if CHECKARRAYLOCKING
- da_LockCt--;
- ASSERT(da_LockCt>=0);
- #endif
- }
- /*
- * Get index of a member from it's pointer.
- */
- template<class Type>
- INDEX CDynamicArray<Type>::Index(Type *ptMember) {
- ASSERT(this!=NULL);
- #if CHECKARRAYLOCKING
- // check that locked for indices
- ASSERT(da_LockCt>0);
- #endif
- return GetIndex(ptMember);
- }
- /*
- * Get index of a member from it's pointer without locking.
- */
- template<class Type>
- INDEX CDynamicArray<Type>::GetIndex(Type *ptMember) {
- ASSERT(this!=NULL);
- // slow !!!!
- // check all members
- for (INDEX iMember=0; iMember<da_Count; iMember++) {
- if(da_Pointers[iMember]==ptMember) {
- return iMember;
- }
- }
- ASSERTALWAYS("CDynamicArray<>::Index(): Not a member of this array!");
- return 0;
- }
- /*
- * Get number of elements in array.
- */
- template<class Type>
- INDEX CDynamicArray<Type>::Count(void) const {
- ASSERT(this!=NULL);
- return da_Count;
- }
- /*
- * Assignment operator.
- */
- template<class Type>
- CDynamicArray<Type> &CDynamicArray<Type>::operator=(CDynamicArray<Type> &arOriginal)
- {
- ASSERT(this!=NULL);
- ASSERT(&arOriginal!=NULL);
- ASSERT(this!=&arOriginal);
- // clear previous contents
- Clear();
- // get count of elements in original array
- INDEX ctOriginal = arOriginal.Count();
- // if the other array has no elements
- if (ctOriginal ==0) {
- // no assignment
- return*this;
- }
- // create that much elements
- Type *atNew = New(ctOriginal);
- // copy them all
- arOriginal.Lock();
- for (INDEX iNew=0; iNew<ctOriginal; iNew++) {
- atNew[iNew] = arOriginal[iNew];
- }
- arOriginal.Unlock();
- return *this;
- }
- /*
- * Move all elements of another array into this one.
- */
- template<class Type>
- void CDynamicArray<Type>::MoveArray(CDynamicArray<Type> &arOther)
- {
- ASSERT(this!=NULL && &arOther!=NULL);
- #if CHECKARRAYLOCKING
- // check that not locked for indices
- ASSERT(da_LockCt==0 && arOther.da_LockCt==0);
- #endif
- // if the other array has no elements
- if (arOther.da_Count==0) {
- // no moving
- return;
- }
- // remember number of elements
- INDEX iOldCount = da_Count;
- // grow pointer array to add the pointers to elements of other array
- GrowPointers(arOther.da_Count);
- // for each pointer in other array
- for (INDEX iOtherPointer=0; iOtherPointer<arOther.da_Count; iOtherPointer++) {
- // copy it at the end of this array
- da_Pointers[iOldCount+iOtherPointer] = arOther.da_Pointers[iOtherPointer];
- }
- // remove array of pointers in other array
- arOther.ShrinkPointers(arOther.da_Count);
- // move list of allocated blocks from the other array to the end of this one
- da_BlocksList.MoveList(arOther.da_BlocksList);
- }
- /////////////////////////////////////////////////////////////////////
- // CDynamicArrayIterator
- /*
- * Template class for iterating dynamic array.
- */
- template<class Type>
- class CDynamicArrayIterator {
- private:
- INDEX dai_Index; // index of current element
- CDynamicArray<Type> &dai_Array; // reference to array
- public:
- /* Constructor for given array. */
- inline CDynamicArrayIterator(CDynamicArray<Type> &da);
- /* Destructor. */
- inline ~CDynamicArrayIterator(void);
- /* Move to next object. */
- inline void MoveToNext(void);
- /* Check if finished. */
- inline BOOL IsPastEnd(void);
- /* Get current element. */
- Type &Current(void) { return *dai_Array.Pointer(dai_Index); }
- Type &operator*(void) { return *dai_Array.Pointer(dai_Index); }
- operator Type *(void) { return dai_Array.Pointer(dai_Index); }
- Type *operator->(void) { return dai_Array.Pointer(dai_Index); }
- };
- /*
- * Constructor for given array.
- */
- template<class Type>
- inline CDynamicArrayIterator<Type>::CDynamicArrayIterator(CDynamicArray<Type> &da) : dai_Array(da) {
- // lock indices
- dai_Array.Lock();
- dai_Index = 0;
- }
- /*
- * Destructor.
- */
- template<class Type>
- inline CDynamicArrayIterator<Type>::~CDynamicArrayIterator(void) {
- // unlock indices
- dai_Array.Unlock();
- dai_Index = -1;
- }
- /*
- * Move to next object.
- */
- template<class Type>
- inline void CDynamicArrayIterator<Type>::MoveToNext(void) {
- ASSERT(this!=NULL);
- dai_Index++;
- }
- /*
- * Check if finished.
- */
- template<class Type>
- inline BOOL CDynamicArrayIterator<Type>::IsPastEnd(void) {
- ASSERT(this!=NULL);
- return dai_Index>=dai_Array.Count();
- }
- #endif /* include-once check. */
|