Serious-Engine/Sources/Engine/Templates/DynamicContainer.cpp
2016-03-11 15:57:17 +02:00

307 lines
7.1 KiB
C++

/* 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 <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
Push() = ptNewObject;
}
/*
* Insert a given object to container at specified index.
*/
template<class Type>
void CDynamicContainer<Type>::Insert(Type *ptNewObject, const INDEX iPos/*=0*/)
{
// get number of member that need moving and add new one
const INDEX ctMovees = CStaticStackArray<Type*>::Count() - iPos;
CStaticStackArray<Type*>::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<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
sa_Array[iMember]=sa_Array[Count()-1];
Pop();
}
/* 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
for (INDEX iMember=0; iMember<Count(); iMember++) {
if(sa_Array[iMember]==ptOldObject) {
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
ASSERT(iMember>=0 && iMember<Count());
#if CHECKARRAYLOCKING
// check that locked for indices
ASSERT(dc_LockCt>0);
#endif
return sa_Array[iMember];
}
template<class Type>
const Type *CDynamicContainer<Type>::Pointer(INDEX iMember) const {
ASSERT(this!=NULL);
// check that index is currently valid
ASSERT(iMember>=0 && iMember<Count());
#if CHECKARRAYLOCKING
// check that locked for indices
ASSERT(dc_LockCt>0);
#endif
return sa_Array[iMember];
}
/*
* 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
for (INDEX iMember=0; iMember<Count(); iMember++) {
if(sa_Array[iMember]==ptMember) {
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)
{
ASSERT(Count()>=1);
return *sa_Array[0];
}
/*
* 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. */