/* 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* * 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 #include "engines/wintermute/Base/BPersistMgr.h" namespace WinterMute { ///////////////////////////////////////////////////////////////////////////// template inline void DCConstructElements(TYPE *pElements, int 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 inline void DCDestructElements(TYPE *pElements, int nCount) { // call the destructor(s) for (; nCount--; pElements++) pElements->~TYPE(); } ///////////////////////////////////////////////////////////////////////////// template inline void DCCopyElements(TYPE *pDest, const TYPE *pSrc, int nCount) { // default is element-copy using assignment while (nCount--) *pDest++ = *pSrc++; } ///////////////////////////////////////////////////////////////////////////// template bool DCCompareElements(const TYPE *pElement1, const ARG_TYPE *pElement2) { return *pElement1 == *pElement2; } //class CBPersistMgr; ///////////////////////////////////////////////////////////////////////////// // CBArray ///////////////////////////////////////////////////////////////////////////// template class CBArray { public: // Construction CBArray(); // Attributes int GetSize() const; int GetUpperBound() const; void SetSize(int nNewSize, int nGrowBy = -1); // Operations // Clean up void FreeExtra(); void RemoveAll(); HRESULT persist(CBPersistMgr *persistMgr); // Accessing elements TYPE GetAt(int nIndex) const; void SetAt(int nIndex, ARG_TYPE newElement); TYPE &ElementAt(int nIndex); // Direct Access to the element data (may return NULL) const TYPE *GetData() const; TYPE *GetData(); // Potentially growing the array void SetAtGrow(int nIndex, ARG_TYPE newElement); int Add(ARG_TYPE newElement); int Append(const CBArray &src); void Copy(const CBArray &src); // overloaded operator helpers TYPE operator[](int nIndex) const; TYPE &operator[](int nIndex); // Operations that move elements around void InsertAt(int nIndex, ARG_TYPE newElement, int nCount = 1); void RemoveAt(int nIndex, int nCount = 1); void InsertAt(int nStartIndex, CBArray *pNewArray); // Implementation protected: TYPE *_pData; // the actual array of data int _nSize; // # of elements (upperBound - 1) int _nMaxSize; // max allocated int _nGrowBy; // grow amount public: ~CBArray(); }; ///////////////////////////////////////////////////////////////////////////// // CBArray inline functions ///////////////////////////////////////////////////////////////////////////// template inline int CBArray::GetSize() const { return _nSize; } template inline int CBArray::GetUpperBound() const { return _nSize - 1; } template inline void CBArray::RemoveAll() { SetSize(0, -1); } template inline TYPE CBArray::GetAt(int nIndex) const { return _pData[nIndex]; } template inline void CBArray::SetAt(int nIndex, ARG_TYPE newElement) { _pData[nIndex] = newElement; } template inline TYPE &CBArray::ElementAt(int nIndex) { return _pData[nIndex]; } template inline const TYPE *CBArray::GetData() const { return (const TYPE *)_pData; } template inline TYPE *CBArray::GetData() { return (TYPE *)_pData; } template inline int CBArray::Add(ARG_TYPE newElement) { int nIndex = _nSize; SetAtGrow(nIndex, newElement); return nIndex; } template inline TYPE CBArray::operator[](int nIndex) const { return GetAt(nIndex); } template inline TYPE &CBArray::operator[](int nIndex) { return ElementAt(nIndex); } ///////////////////////////////////////////////////////////////////////////// // CBArray out-of-line functions ///////////////////////////////////////////////////////////////////////////// template CBArray::CBArray() { _pData = NULL; _nSize = _nMaxSize = _nGrowBy = 0; } ///////////////////////////////////////////////////////////////////////////// template CBArray::~CBArray() { if (_pData != NULL) { DCDestructElements(_pData, _nSize); delete[](byte *)_pData; } } ///////////////////////////////////////////////////////////////////////////// template void CBArray::SetSize(int nNewSize, int nGrowBy) { if (nGrowBy != -1) _nGrowBy = nGrowBy; // set new size if (nNewSize == 0) { // shrink to nothing if (_pData != NULL) { DCDestructElements(_pData, _nSize); delete[](byte *)_pData; _pData = NULL; } _nSize = _nMaxSize = 0; } else if (_pData == NULL) { // create one with exact size _pData = (TYPE *) new byte[nNewSize * sizeof(TYPE)]; DCConstructElements(_pData, nNewSize); _nSize = _nMaxSize = nNewSize; } else if (nNewSize <= _nMaxSize) { // it fits if (nNewSize > _nSize) { // initialize the new elements DCConstructElements(&_pData[_nSize], nNewSize - _nSize); } else if (_nSize > nNewSize) { // destroy the old elements DCDestructElements(&_pData[nNewSize], _nSize - nNewSize); } _nSize = nNewSize; } else { // otherwise, grow array nGrowBy = _nGrowBy; if (nGrowBy == 0) { // heuristically determine growth when nGrowBy == 0 // (this avoids heap fragmentation in many situations) nGrowBy = _nSize / 8; nGrowBy = (nGrowBy < 4) ? 4 : ((nGrowBy > 1024) ? 1024 : nGrowBy); } int nNewMax; if (nNewSize < _nMaxSize + nGrowBy) nNewMax = _nMaxSize + nGrowBy; // 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(&pNewData[_nSize], nNewSize - _nSize); // get rid of old stuff (note: no destructors called) delete[](byte *)_pData; _pData = pNewData; _nSize = nNewSize; _nMaxSize = nNewMax; } } ///////////////////////////////////////////////////////////////////////////// template int CBArray::Append(const CBArray &src) { int nOldSize = _nSize; SetSize(_nSize + src._nSize); DCCopyElements(_pData + nOldSize, src._pData, src._nSize); return nOldSize; } ///////////////////////////////////////////////////////////////////////////// template void CBArray::Copy(const CBArray &src) { SetSize(src._nSize); DCCopyElements(_pData, src._pData, src._nSize); } ///////////////////////////////////////////////////////////////////////////// template void CBArray::FreeExtra() { if (_nSize != _nMaxSize) { // shrink to desired size TYPE *pNewData = NULL; 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 void CBArray::SetAtGrow(int nIndex, ARG_TYPE newElement) { if (nIndex >= _nSize) SetSize(nIndex + 1, -1); _pData[nIndex] = newElement; } ///////////////////////////////////////////////////////////////////////////// template void CBArray::InsertAt(int nIndex, ARG_TYPE newElement, int 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 int nOldSize = _nSize; SetSize(_nSize + nCount, -1); // grow it to new size // destroy intial data before copying over it DCDestructElements(&_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(&_pData[nIndex], nCount); } // insert new value in the gap while (nCount--) _pData[nIndex++] = newElement; } ///////////////////////////////////////////////////////////////////////////// template void CBArray::RemoveAt(int nIndex, int nCount) { // just remove a range int nMoveCount = _nSize - (nIndex + nCount); DCDestructElements(&_pData[nIndex], nCount); if (nMoveCount) memcpy(&_pData[nIndex], &_pData[nIndex + nCount], nMoveCount * sizeof(TYPE)); _nSize -= nCount; } ///////////////////////////////////////////////////////////////////////////// template void CBArray::InsertAt(int nStartIndex, CBArray *pNewArray) { if (pNewArray->GetSize() > 0) { InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize()); for (int i = 0; i < pNewArray->GetSize(); i++) SetAt(nStartIndex + i, pNewArray->GetAt(i)); } } ///////////////////////////////////////////////////////////////////////////// template HRESULT CBArray::persist(CBPersistMgr *persistMgr) { int i, j; if (persistMgr->_saving) { j = GetSize(); persistMgr->transfer("ArraySize", &j); for (i = 0; i < j; i++) { ARG_TYPE obj = GetAt(i); persistMgr->transfer("", &obj); } } else { SetSize(0, -1); persistMgr->transfer("ArraySize", &j); for (i = 0; i < j; i++) { ARG_TYPE obj; persistMgr->transfer("", &obj); Add(obj); } } return S_OK; } } // end of namespace WinterMute #endif // COLL_TEMPL_H