Initial commit
This commit is contained in:
425
engines/wintermute/coll_templ.h
Normal file
425
engines/wintermute/coll_templ.h
Normal file
@@ -0,0 +1,425 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on WME Lite.
|
||||
* http://dead-code.org/redir.php?target=wmelite
|
||||
* Copyright (c) 2011 Jan Nedoma
|
||||
*/
|
||||
|
||||
#ifndef WINTERMUTE_COLL_TEMPL_H
|
||||
#define WINTERMUTE_COLL_TEMPL_H
|
||||
|
||||
#include "engines/wintermute/base/base_persistence_manager.h"
|
||||
|
||||
namespace Wintermute {
|
||||
|
||||
#include <new>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
inline void dcConstructElements(TYPE *pElements, int32 nCount) {
|
||||
// first do bit-wise zero initialization
|
||||
memset((void *)pElements, 0, nCount * sizeof(TYPE));
|
||||
|
||||
// then call the constructor(s)
|
||||
for (; nCount--; pElements++)
|
||||
::new((void *)pElements) TYPE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
inline void dcDestructElements(TYPE *pElements, int32 nCount) {
|
||||
// call the destructor(s)
|
||||
for (; nCount--; pElements++)
|
||||
pElements->~TYPE();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
inline void dcCopyElements(TYPE *pDest, const TYPE *pSrc, int32 nCount) {
|
||||
// default is element-copy using assignment
|
||||
while (nCount--)
|
||||
*pDest++ = *pSrc++;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// BaseArray<TYPE>
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
class BaseArrayBase {
|
||||
public:
|
||||
// Construction
|
||||
BaseArrayBase();
|
||||
|
||||
// Attributes
|
||||
int32 getSize() const;
|
||||
int32 getUpperBound() const;
|
||||
void setSize(int32 nNewSize, int32 nGrowBy = -1);
|
||||
|
||||
// Operations
|
||||
// Clean up
|
||||
void freeExtra();
|
||||
void removeAll();
|
||||
|
||||
// Accessing elements
|
||||
TYPE getAt(int32 nIndex) const;
|
||||
void setAt(int32 nIndex, TYPE newElement);
|
||||
TYPE &elementAt(int32 nIndex);
|
||||
|
||||
// Direct Access to the element data (may return NULL)
|
||||
const TYPE *getData() const;
|
||||
TYPE *getData();
|
||||
|
||||
// Potentially growing the array
|
||||
void setAtGrow(int32 nIndex, TYPE newElement);
|
||||
int32 add(TYPE newElement);
|
||||
int32 append(const BaseArrayBase &src);
|
||||
void copy(const BaseArrayBase &src);
|
||||
|
||||
// overloaded operator helpers
|
||||
TYPE operator[](int32 nIndex) const;
|
||||
TYPE &operator[](int32 nIndex);
|
||||
|
||||
// Operations that move elements around
|
||||
void insertAt(int32 nIndex, TYPE newElement, int32 nCount = 1);
|
||||
void removeAt(int32 nIndex, int32 nCount = 1);
|
||||
void insertAt(int32 nStartIndex, BaseArrayBase *pNewArray);
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
TYPE *_pData; // the actual array of data
|
||||
int32 _nSize; // # of elements (upperBound - 1)
|
||||
int32 _nMaxSize; // max allocated
|
||||
int32 _nGrowBy; // grow amount
|
||||
|
||||
public:
|
||||
~BaseArrayBase();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CBArray<TYPE> inline functions
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
inline int32 BaseArrayBase<TYPE>::getSize() const {
|
||||
return _nSize;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline int32 BaseArrayBase<TYPE>::getUpperBound() const {
|
||||
return _nSize - 1;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline void BaseArrayBase<TYPE>::removeAll() {
|
||||
setSize(0, -1);
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline TYPE BaseArrayBase<TYPE>::getAt(int32 nIndex) const {
|
||||
return _pData[nIndex];
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline void BaseArrayBase<TYPE>::setAt(int32 nIndex, TYPE newElement) {
|
||||
_pData[nIndex] = newElement;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline TYPE &BaseArrayBase<TYPE>::elementAt(int32 nIndex) {
|
||||
return _pData[nIndex];
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline const TYPE *BaseArrayBase<TYPE>::getData() const {
|
||||
return (const TYPE *)_pData;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline TYPE *BaseArrayBase<TYPE>::getData() {
|
||||
return (TYPE *)_pData;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline int32 BaseArrayBase<TYPE>::add(TYPE newElement) {
|
||||
int32 nIndex = _nSize;
|
||||
setAtGrow(nIndex, newElement);
|
||||
return nIndex;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline TYPE BaseArrayBase<TYPE>::operator[](int32 nIndex) const {
|
||||
return getAt(nIndex);
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
inline TYPE &BaseArrayBase<TYPE>::operator[](int32 nIndex) {
|
||||
return elementAt(nIndex);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// BaseArray<TYPE> out-of-line functions
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
BaseArrayBase<TYPE>::BaseArrayBase() {
|
||||
_pData = nullptr;
|
||||
_nSize = _nMaxSize = _nGrowBy = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
BaseArrayBase<TYPE>::~BaseArrayBase() {
|
||||
if (_pData != nullptr) {
|
||||
dcDestructElements<TYPE>(_pData, _nSize);
|
||||
delete[] (byte *)_pData;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
void BaseArrayBase<TYPE>::setSize(int32 nNewSize, int32 nGrowBy) {
|
||||
if (nGrowBy != -1)
|
||||
_nGrowBy = nGrowBy; // set new size
|
||||
|
||||
if (nNewSize == 0) {
|
||||
// shrink to nothing
|
||||
if (_pData != nullptr) {
|
||||
dcDestructElements<TYPE>(_pData, _nSize);
|
||||
delete[] (byte *)_pData;
|
||||
_pData = nullptr;
|
||||
}
|
||||
_nSize = _nMaxSize = 0;
|
||||
} else if (_pData == nullptr) {
|
||||
// create one with exact size
|
||||
_pData = (TYPE *) new byte[nNewSize * sizeof(TYPE)];
|
||||
dcConstructElements<TYPE>(_pData, nNewSize);
|
||||
_nSize = _nMaxSize = nNewSize;
|
||||
} else if (nNewSize <= _nMaxSize) {
|
||||
// it fits
|
||||
if (nNewSize > _nSize) {
|
||||
// initialize the new elements
|
||||
dcConstructElements<TYPE>(&_pData[_nSize], nNewSize - _nSize);
|
||||
} else if (_nSize > nNewSize) {
|
||||
// destroy the old elements
|
||||
dcDestructElements<TYPE>(&_pData[nNewSize], _nSize - nNewSize);
|
||||
}
|
||||
_nSize = nNewSize;
|
||||
} else {
|
||||
// otherwise, grow array
|
||||
int32 numGrowBy = _nGrowBy;
|
||||
if (numGrowBy == 0) {
|
||||
// heuristically determine growth when nGrowBy == 0
|
||||
// (this avoids heap fragmentation in many situations)
|
||||
numGrowBy = _nSize / 8;
|
||||
numGrowBy = (numGrowBy < 4) ? 4 : ((numGrowBy > 1024) ? 1024 : numGrowBy);
|
||||
}
|
||||
int nNewMax;
|
||||
if (nNewSize < _nMaxSize + numGrowBy)
|
||||
nNewMax = _nMaxSize + numGrowBy; // granularity
|
||||
else
|
||||
nNewMax = nNewSize; // no slush
|
||||
|
||||
TYPE *pNewData = (TYPE *) new byte[nNewMax * sizeof(TYPE)];
|
||||
|
||||
// copy new data from old
|
||||
memcpy(pNewData, _pData, _nSize * sizeof(TYPE));
|
||||
|
||||
// construct remaining elements
|
||||
dcConstructElements<TYPE>(&pNewData[_nSize], nNewSize - _nSize);
|
||||
|
||||
// get rid of old stuff (note: no destructors called)
|
||||
delete[] (byte *)_pData;
|
||||
_pData = pNewData;
|
||||
_nSize = nNewSize;
|
||||
_nMaxSize = nNewMax;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
int32 BaseArrayBase<TYPE>::append(const BaseArrayBase &src) {
|
||||
int32 nOldSize = _nSize;
|
||||
setSize(_nSize + src._nSize);
|
||||
dcCopyElements<TYPE>(_pData + nOldSize, src._pData, src._nSize);
|
||||
return nOldSize;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
void BaseArrayBase<TYPE>::copy(const BaseArrayBase &src) {
|
||||
setSize(src._nSize);
|
||||
dcCopyElements<TYPE>(_pData, src._pData, src._nSize);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
void BaseArrayBase<TYPE>::freeExtra() {
|
||||
if (_nSize != _nMaxSize) {
|
||||
// shrink to desired size
|
||||
TYPE *pNewData = nullptr;
|
||||
if (_nSize != 0) {
|
||||
pNewData = (TYPE *) new byte[_nSize * sizeof(TYPE)];
|
||||
// copy new data from old
|
||||
memcpy(pNewData, _pData, _nSize * sizeof(TYPE));
|
||||
}
|
||||
|
||||
// get rid of old stuff (note: no destructors called)
|
||||
delete[] (byte *)_pData;
|
||||
_pData = pNewData;
|
||||
_nMaxSize = _nSize;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
void BaseArrayBase<TYPE>::setAtGrow(int32 nIndex, TYPE newElement) {
|
||||
if (nIndex >= _nSize)
|
||||
setSize(nIndex + 1, -1);
|
||||
_pData[nIndex] = newElement;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
void BaseArrayBase<TYPE>::insertAt(int32 nIndex, TYPE newElement, int32 nCount /*=1*/) {
|
||||
if (nIndex >= _nSize) {
|
||||
// adding after the end of the array
|
||||
setSize(nIndex + nCount, -1); // grow so nIndex is valid
|
||||
} else {
|
||||
// inserting in the middle of the array
|
||||
int32 nOldSize = _nSize;
|
||||
setSize(_nSize + nCount, -1); // grow it to new size
|
||||
// destroy intial data before copying over it
|
||||
dcDestructElements<TYPE>(&_pData[nOldSize], nCount);
|
||||
// shift old data up to fill gap
|
||||
memmove(&_pData[nIndex + nCount], &_pData[nIndex],
|
||||
(nOldSize - nIndex) * sizeof(TYPE));
|
||||
|
||||
// re-init slots we copied from
|
||||
dcConstructElements<TYPE>(&_pData[nIndex], nCount);
|
||||
}
|
||||
|
||||
// insert new value in the gap
|
||||
while (nCount--)
|
||||
_pData[nIndex++] = newElement;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
void BaseArrayBase<TYPE>::removeAt(int32 nIndex, int32 nCount) {
|
||||
// just remove a range
|
||||
int32 nMoveCount = _nSize - (nIndex + nCount);
|
||||
dcDestructElements<TYPE>(&_pData[nIndex], nCount);
|
||||
if (nMoveCount)
|
||||
memmove(&_pData[nIndex], &_pData[nIndex + nCount], nMoveCount * sizeof(TYPE));
|
||||
_nSize -= nCount;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
void BaseArrayBase<TYPE>::insertAt(int32 nStartIndex, BaseArrayBase *pNewArray) {
|
||||
if (pNewArray->getSize() > 0) {
|
||||
insertAt(nStartIndex, pNewArray->getAt(0), pNewArray->getSize());
|
||||
for (int32 i = 0; i < pNewArray->getSize(); i++)
|
||||
setAt(nStartIndex + i, pNewArray->getAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template<class TYPE>
|
||||
class BaseArray : public BaseArrayBase<TYPE> {
|
||||
public:
|
||||
bool persist(BasePersistenceManager *persistMgr) {
|
||||
int32 i, j;
|
||||
if (persistMgr->getIsSaving()) {
|
||||
j = BaseArray::getSize();
|
||||
persistMgr->transferSint32("ArraySize", &j);
|
||||
for (i = 0; i < j; i++) {
|
||||
TYPE obj = BaseArray::getAt(i);
|
||||
persistMgr->transferPtr("", &obj);
|
||||
}
|
||||
} else {
|
||||
BaseArray::setSize(0, -1);
|
||||
persistMgr->transferSint32("ArraySize", &j);
|
||||
for (i = 0; i < j; i++) {
|
||||
TYPE obj = nullptr;
|
||||
persistMgr->transferPtr("", &obj);
|
||||
BaseArray::add(obj);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template <>
|
||||
class BaseArray<char *> : public BaseArrayBase<char *> {
|
||||
public:
|
||||
bool persist(BasePersistenceManager *persistMgr) {
|
||||
int32 i, j;
|
||||
if (persistMgr->getIsSaving()) {
|
||||
j = BaseArray::getSize();
|
||||
persistMgr->transferSint32("ArraySize", &j);
|
||||
for (i = 0; i < j; i++) {
|
||||
char *obj = BaseArray::getAt(i);
|
||||
persistMgr->transferCharPtr("", &obj);
|
||||
}
|
||||
} else {
|
||||
setSize(0, -1);
|
||||
persistMgr->transferSint32("ArraySize", &j);
|
||||
for (i = 0; i < j; i++) {
|
||||
char *obj = nullptr;
|
||||
persistMgr->transferCharPtr("", &obj);
|
||||
add(obj);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template <>
|
||||
class BaseArray<const char *> : public BaseArrayBase<const char *> {
|
||||
public:
|
||||
bool persist(BasePersistenceManager *persistMgr) {
|
||||
int32 i, j;
|
||||
if (persistMgr->getIsSaving()) {
|
||||
j = BaseArray::getSize();
|
||||
persistMgr->transferSint32("ArraySize", &j);
|
||||
for (i = 0; i < j; i++) {
|
||||
const char * obj = BaseArray::getAt(i);
|
||||
persistMgr->transferConstChar("", &obj);
|
||||
}
|
||||
} else {
|
||||
BaseArray::setSize(0, -1);
|
||||
persistMgr->transferSint32("ArraySize", &j);
|
||||
for (i = 0; i < j; i++) {
|
||||
const char * obj;
|
||||
persistMgr->transferConstChar("", &obj);
|
||||
BaseArray::add(obj);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Wintermute
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user