2016-03-12 01:20:51 +01:00
|
|
|
/* 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. */
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
#ifndef SE_INCL_DYNAMICCONTAINER_CPP
|
|
|
|
#define SE_INCL_DYNAMICCONTAINER_CPP
|
|
|
|
#ifdef PRAGMA_ONCE
|
|
|
|
#pragma once
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <Engine/Templates/DynamicContainer.h>
|
|
|
|
#include <Engine/Base/Memory.h>
|
|
|
|
#include <Engine/Templates/StaticStackArray.cpp>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Default constructor.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
CDynamicContainer<Type>::CDynamicContainer(void) {
|
|
|
|
#if CHECKARRAYLOCKING
|
|
|
|
// not locked
|
|
|
|
dc_LockCt = 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy constructor.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
CDynamicContainer<Type>::CDynamicContainer(CDynamicContainer<Type> &dcOriginal)
|
|
|
|
{
|
|
|
|
#if CHECKARRAYLOCKING
|
|
|
|
// not locked
|
|
|
|
dc_LockCt = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// call assignment operator
|
|
|
|
(*this) = dcOriginal;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Destructor -- removes all objects.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
CDynamicContainer<Type>::~CDynamicContainer(void) {
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove all objects, and reset the array to initial (empty) state.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
void CDynamicContainer<Type>::Clear(void) {
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
CStaticStackArray<Type *>::Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add a given object to container.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
void CDynamicContainer<Type>::Add(Type *ptNewObject)
|
|
|
|
{
|
|
|
|
// set the new pointer
|
2016-03-29 03:03:54 +02:00
|
|
|
this->Push() = ptNewObject;
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove a given object from container.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
void CDynamicContainer<Type>::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
|
2016-03-29 03:03:54 +02:00
|
|
|
this->sa_Array[iMember]=this->sa_Array[this->Count()-1];
|
|
|
|
this->Pop();
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Test if a given object is in the container. */
|
|
|
|
template<class Type>
|
|
|
|
BOOL CDynamicContainer<Type>::IsMember(Type *ptOldObject)
|
|
|
|
{
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
// slow !!!!
|
|
|
|
// check all members
|
2016-03-29 03:03:54 +02:00
|
|
|
for (INDEX iMember=0; iMember<this->Count(); iMember++) {
|
|
|
|
if(this->sa_Array[iMember]==ptOldObject) {
|
2016-03-11 14:57:17 +01:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get pointer to a member from it's index.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
Type *CDynamicContainer<Type>::Pointer(INDEX iMember) {
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
// check that index is currently valid
|
2016-03-29 03:03:54 +02:00
|
|
|
ASSERT(iMember>=0 && iMember<this->Count());
|
2016-03-11 14:57:17 +01:00
|
|
|
#if CHECKARRAYLOCKING
|
|
|
|
// check that locked for indices
|
|
|
|
ASSERT(dc_LockCt>0);
|
|
|
|
#endif
|
2016-03-29 03:03:54 +02:00
|
|
|
return this->sa_Array[iMember];
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
template<class Type>
|
|
|
|
const Type *CDynamicContainer<Type>::Pointer(INDEX iMember) const {
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
// check that index is currently valid
|
2016-03-29 03:03:54 +02:00
|
|
|
ASSERT(iMember>=0 && iMember<this->Count());
|
2016-03-11 14:57:17 +01:00
|
|
|
#if CHECKARRAYLOCKING
|
|
|
|
// check that locked for indices
|
|
|
|
ASSERT(dc_LockCt>0);
|
|
|
|
#endif
|
2016-03-29 03:03:54 +02:00
|
|
|
return this->sa_Array[iMember];
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock for getting indices.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
void CDynamicContainer<Type>::Lock(void) {
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
#if CHECKARRAYLOCKING
|
|
|
|
ASSERT(dc_LockCt>=0);
|
|
|
|
// increment lock counter
|
|
|
|
dc_LockCt++;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unlock after getting indices.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
void CDynamicContainer<Type>::Unlock(void) {
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
#if CHECKARRAYLOCKING
|
|
|
|
dc_LockCt--;
|
|
|
|
ASSERT(dc_LockCt>=0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get index of a member from it's pointer.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
INDEX CDynamicContainer<Type>::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<class Type>
|
|
|
|
INDEX CDynamicContainer<Type>::GetIndex(Type *ptMember) {
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
// slow !!!!
|
|
|
|
// check all members
|
2016-03-29 03:03:54 +02:00
|
|
|
for (INDEX iMember=0; iMember<this->Count(); iMember++) {
|
|
|
|
if(this->sa_Array[iMember]==ptMember) {
|
2016-03-11 14:57:17 +01:00
|
|
|
return iMember;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERTALWAYS("CDynamicContainer<Type><>::Index(): Not a member of this container!");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get first object in container (there must be at least one when calling this). */
|
|
|
|
template<class Type>
|
|
|
|
Type &CDynamicContainer<Type>::GetFirst(void)
|
|
|
|
{
|
2016-03-29 03:03:54 +02:00
|
|
|
ASSERT(this->Count()>=1);
|
|
|
|
return *this->sa_Array[0];
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Assignment operator.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
CDynamicContainer<Type> &CDynamicContainer<Type>::operator=(CDynamicContainer<Type> &coOriginal)
|
|
|
|
{
|
|
|
|
CStaticStackArray<Type *>::operator=(coOriginal);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move all elements of another array into this one.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
void CDynamicContainer<Type>::MoveContainer(CDynamicContainer<Type> &coOther)
|
|
|
|
{
|
|
|
|
ASSERT(this!=NULL && &coOther!=NULL);
|
|
|
|
// check that not locked for indices
|
|
|
|
#if CHECKARRAYLOCKING
|
|
|
|
ASSERT(dc_LockCt==0 && coOther.dc_LockCt==0);
|
|
|
|
#endif
|
|
|
|
CStaticStackArray<Type*>::MoveArray(coOther);
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// CDynamicContainerIterator<Type>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Template class for iterating dynamic array.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
class CDynamicContainerIterator {
|
|
|
|
private:
|
|
|
|
INDEX dci_Index; // index of current element
|
|
|
|
CDynamicContainer<Type> &dci_Array; // reference to array
|
|
|
|
public:
|
|
|
|
/* Constructor for given array. */
|
|
|
|
inline CDynamicContainerIterator(CDynamicContainer<Type> &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<class Type>
|
|
|
|
inline CDynamicContainerIterator<Type>::CDynamicContainerIterator(CDynamicContainer<Type> &da) : dci_Array(da) {
|
|
|
|
// lock indices
|
|
|
|
dci_Array.Lock();
|
|
|
|
dci_Index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Destructor.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
inline CDynamicContainerIterator<Type>::~CDynamicContainerIterator(void) {
|
|
|
|
// unlock indices
|
|
|
|
dci_Array.Unlock();
|
|
|
|
dci_Index = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move to next object.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
inline void CDynamicContainerIterator<Type>::MoveToNext(void) {
|
|
|
|
ASSERT(this!=NULL);
|
|
|
|
dci_Index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if finished.
|
|
|
|
*/
|
|
|
|
template<class Type>
|
|
|
|
inline BOOL CDynamicContainerIterator<Type>::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<type> iter(container); !iter.IsPastEnd(); iter.MoveToNext() )
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* include-once check. */
|
|
|
|
|