mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 01:39:57 +00:00
373 lines
12 KiB
C++
373 lines
12 KiB
C++
/* 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 <new>
|
|
#include "BPersistMgr.h"
|
|
|
|
namespace WinterMute {
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE>
|
|
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<class TYPE>
|
|
inline void DCDestructElements(TYPE *pElements, int nCount) {
|
|
// call the destructor(s)
|
|
for (; nCount--; pElements++)
|
|
pElements->~TYPE();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE>
|
|
inline void DCCopyElements(TYPE *pDest, const TYPE *pSrc, int nCount) {
|
|
// default is element-copy using assignment
|
|
while (nCount--)
|
|
*pDest++ = *pSrc++;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
BOOL DCCompareElements(const TYPE *pElement1, const ARG_TYPE *pElement2) {
|
|
return *pElement1 == *pElement2;
|
|
}
|
|
|
|
//class CBPersistMgr;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBArray<TYPE, ARG_TYPE>
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
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<TYPE, ARG_TYPE> inline functions
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline int CBArray<TYPE, ARG_TYPE>::GetSize() const {
|
|
return _nSize;
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline int CBArray<TYPE, ARG_TYPE>::GetUpperBound() const {
|
|
return _nSize - 1;
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline void CBArray<TYPE, ARG_TYPE>::RemoveAll() {
|
|
SetSize(0, -1);
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline TYPE CBArray<TYPE, ARG_TYPE>::GetAt(int nIndex) const {
|
|
return _pData[nIndex];
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline void CBArray<TYPE, ARG_TYPE>::SetAt(int nIndex, ARG_TYPE newElement) {
|
|
_pData[nIndex] = newElement;
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline TYPE &CBArray<TYPE, ARG_TYPE>::ElementAt(int nIndex) {
|
|
return _pData[nIndex];
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline const TYPE *CBArray<TYPE, ARG_TYPE>::GetData() const {
|
|
return (const TYPE *)_pData;
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline TYPE *CBArray<TYPE, ARG_TYPE>::GetData() {
|
|
return (TYPE *)_pData;
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline int CBArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement) {
|
|
int nIndex = _nSize;
|
|
SetAtGrow(nIndex, newElement);
|
|
return nIndex;
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline TYPE CBArray<TYPE, ARG_TYPE>::operator[](int nIndex) const {
|
|
return GetAt(nIndex);
|
|
}
|
|
template<class TYPE, class ARG_TYPE>
|
|
inline TYPE &CBArray<TYPE, ARG_TYPE>::operator[](int nIndex) {
|
|
return ElementAt(nIndex);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBArray<TYPE, ARG_TYPE> out-of-line functions
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
CBArray<TYPE, ARG_TYPE>::CBArray() {
|
|
_pData = NULL;
|
|
_nSize = _nMaxSize = _nGrowBy = 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
CBArray<TYPE, ARG_TYPE>::~CBArray() {
|
|
if (_pData != NULL) {
|
|
DCDestructElements<TYPE>(_pData, _nSize);
|
|
delete[](byte *)_pData;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
void CBArray<TYPE, ARG_TYPE>::SetSize(int nNewSize, int nGrowBy) {
|
|
if (nGrowBy != -1)
|
|
_nGrowBy = nGrowBy; // set new size
|
|
|
|
if (nNewSize == 0) {
|
|
// shrink to nothing
|
|
if (_pData != NULL) {
|
|
DCDestructElements<TYPE>(_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<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
|
|
int 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<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, class ARG_TYPE>
|
|
int CBArray<TYPE, ARG_TYPE>::Append(const CBArray &src) {
|
|
int nOldSize = _nSize;
|
|
SetSize(_nSize + src._nSize);
|
|
DCCopyElements<TYPE>(_pData + nOldSize, src._pData, src._nSize);
|
|
return nOldSize;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
void CBArray<TYPE, ARG_TYPE>::Copy(const CBArray &src) {
|
|
SetSize(src._nSize);
|
|
DCCopyElements<TYPE>(_pData, src._pData, src._nSize);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
void CBArray<TYPE, ARG_TYPE>::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<class TYPE, class ARG_TYPE>
|
|
void CBArray<TYPE, ARG_TYPE>::SetAtGrow(int nIndex, ARG_TYPE newElement) {
|
|
if (nIndex >= _nSize)
|
|
SetSize(nIndex + 1, -1);
|
|
_pData[nIndex] = newElement;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
void CBArray<TYPE, ARG_TYPE>::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<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, class ARG_TYPE>
|
|
void CBArray<TYPE, ARG_TYPE>::RemoveAt(int nIndex, int nCount) {
|
|
// just remove a range
|
|
int nMoveCount = _nSize - (nIndex + nCount);
|
|
DCDestructElements<TYPE>(&_pData[nIndex], nCount);
|
|
if (nMoveCount)
|
|
memcpy(&_pData[nIndex], &_pData[nIndex + nCount],
|
|
nMoveCount * sizeof(TYPE));
|
|
_nSize -= nCount;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class TYPE, class ARG_TYPE>
|
|
void CBArray<TYPE, ARG_TYPE>::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<class TYPE, class ARG_TYPE>
|
|
HRESULT CBArray<TYPE, ARG_TYPE>::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
|