ScummVM API documentation
coll_templ.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 /*
23  * This file is based on WME Lite.
24  * http://dead-code.org/redir.php?target=wmelite
25  * Copyright (c) 2011 Jan Nedoma
26  */
27 
28 #ifndef WINTERMUTE_COLL_TEMPL_H
29 #define WINTERMUTE_COLL_TEMPL_H
30 
31 #include "engines/wintermute/base/base_persistence_manager.h"
32 
33 namespace Wintermute {
34 
36 template<class TYPE>
37 inline void dcConstructElements(TYPE *pElements, int32 nCount) {
38  // first do bit-wise zero initialization
39  memset((void *)pElements, 0, nCount * sizeof(TYPE));
40 
41  // then call the constructor(s)
42  for (; nCount--; pElements++)
43  ::new((void *)pElements) TYPE;
44 }
45 
47 template<class TYPE>
48 inline void dcDestructElements(TYPE *pElements, int32 nCount) {
49  // call the destructor(s)
50  for (; nCount--; pElements++)
51  pElements->~TYPE();
52 }
53 
55 template<class TYPE>
56 inline void dcCopyElements(TYPE *pDest, const TYPE *pSrc, int32 nCount) {
57  // default is element-copy using assignment
58  while (nCount--)
59  *pDest++ = *pSrc++;
60 }
61 
63 // BaseArray<TYPE>
65 template<class TYPE>
67 public:
68  // Construction
69  BaseArrayBase();
70 
71  // Attributes
72  int32 getSize() const;
73  int32 getUpperBound() const;
74  void setSize(int32 nNewSize, int32 nGrowBy = -1);
75 
76  // Operations
77  // Clean up
78  void freeExtra();
79  void removeAll();
80 
81  // Accessing elements
82  TYPE getAt(int32 nIndex) const;
83  void setAt(int32 nIndex, TYPE newElement);
84  TYPE &elementAt(int32 nIndex);
85 
86  // Direct Access to the element data (may return NULL)
87  const TYPE *getData() const;
88  TYPE *getData();
89 
90  // Potentially growing the array
91  void setAtGrow(int32 nIndex, TYPE newElement);
92  int32 add(TYPE newElement);
93  int32 append(const BaseArrayBase &src);
94  void copy(const BaseArrayBase &src);
95 
96  // overloaded operator helpers
97  TYPE operator[](int32 nIndex) const;
98  TYPE &operator[](int32 nIndex);
99 
100  // Operations that move elements around
101  void insertAt(int32 nIndex, TYPE newElement, int32 nCount = 1);
102  void removeAt(int32 nIndex, int32 nCount = 1);
103  void insertAt(int32 nStartIndex, BaseArrayBase *pNewArray);
104 
105  // Implementation
106 protected:
107  TYPE *_pData; // the actual array of data
108  int32 _nSize; // # of elements (upperBound - 1)
109  int32 _nMaxSize; // max allocated
110  int32 _nGrowBy; // grow amount
111 
112 public:
113  ~BaseArrayBase();
114 };
115 
117 // CBArray<TYPE> inline functions
119 template<class TYPE>
120 inline int32 BaseArrayBase<TYPE>::getSize() const {
121  return _nSize;
122 }
123 
124 template<class TYPE>
125 inline int32 BaseArrayBase<TYPE>::getUpperBound() const {
126  return _nSize - 1;
127 }
128 
129 template<class TYPE>
130 inline void BaseArrayBase<TYPE>::removeAll() {
131  setSize(0, -1);
132 }
133 
134 template<class TYPE>
135 inline TYPE BaseArrayBase<TYPE>::getAt(int32 nIndex) const {
136  return _pData[nIndex];
137 }
138 
139 template<class TYPE>
140 inline void BaseArrayBase<TYPE>::setAt(int32 nIndex, TYPE newElement) {
141  _pData[nIndex] = newElement;
142 }
143 
144 template<class TYPE>
145 inline TYPE &BaseArrayBase<TYPE>::elementAt(int32 nIndex) {
146  return _pData[nIndex];
147 }
148 
149 template<class TYPE>
150 inline const TYPE *BaseArrayBase<TYPE>::getData() const {
151  return (const TYPE *)_pData;
152 }
153 
154 template<class TYPE>
155 inline TYPE *BaseArrayBase<TYPE>::getData() {
156  return (TYPE *)_pData;
157 }
158 
159 template<class TYPE>
160 inline int32 BaseArrayBase<TYPE>::add(TYPE newElement) {
161  int32 nIndex = _nSize;
162  setAtGrow(nIndex, newElement);
163  return nIndex;
164 }
165 
166 template<class TYPE>
167 inline TYPE BaseArrayBase<TYPE>::operator[](int32 nIndex) const {
168  return getAt(nIndex);
169 }
170 
171 template<class TYPE>
172 inline TYPE &BaseArrayBase<TYPE>::operator[](int32 nIndex) {
173  return elementAt(nIndex);
174 }
175 
177 // BaseArray<TYPE> out-of-line functions
179 template<class TYPE>
181  _pData = nullptr;
182  _nSize = _nMaxSize = _nGrowBy = 0;
183 }
184 
186 template<class TYPE>
188  if (_pData != nullptr) {
189  dcDestructElements<TYPE>(_pData, _nSize);
190  delete[] (byte *)_pData;
191  }
192 }
193 
195 template<class TYPE>
196 void BaseArrayBase<TYPE>::setSize(int32 nNewSize, int32 nGrowBy) {
197  if (nGrowBy != -1)
198  _nGrowBy = nGrowBy; // set new size
199 
200  if (nNewSize == 0) {
201  // shrink to nothing
202  if (_pData != nullptr) {
203  dcDestructElements<TYPE>(_pData, _nSize);
204  delete[] (byte *)_pData;
205  _pData = nullptr;
206  }
207  _nSize = _nMaxSize = 0;
208  } else if (_pData == nullptr) {
209  // create one with exact size
210  _pData = (TYPE *) new byte[nNewSize * sizeof(TYPE)];
211  dcConstructElements<TYPE>(_pData, nNewSize);
212  _nSize = _nMaxSize = nNewSize;
213  } else if (nNewSize <= _nMaxSize) {
214  // it fits
215  if (nNewSize > _nSize) {
216  // initialize the new elements
217  dcConstructElements<TYPE>(&_pData[_nSize], nNewSize - _nSize);
218  } else if (_nSize > nNewSize) {
219  // destroy the old elements
220  dcDestructElements<TYPE>(&_pData[nNewSize], _nSize - nNewSize);
221  }
222  _nSize = nNewSize;
223  } else {
224  // otherwise, grow array
225  int32 numGrowBy = _nGrowBy;
226  if (numGrowBy == 0) {
227  // heuristically determine growth when nGrowBy == 0
228  // (this avoids heap fragmentation in many situations)
229  numGrowBy = _nSize / 8;
230  numGrowBy = (numGrowBy < 4) ? 4 : ((numGrowBy > 1024) ? 1024 : numGrowBy);
231  }
232  int nNewMax;
233  if (nNewSize < _nMaxSize + numGrowBy)
234  nNewMax = _nMaxSize + numGrowBy; // granularity
235  else
236  nNewMax = nNewSize; // no slush
237 
238  TYPE *pNewData = (TYPE *) new byte[nNewMax * sizeof(TYPE)];
239 
240  // copy new data from old
241  memcpy(pNewData, _pData, _nSize * sizeof(TYPE));
242 
243  // construct remaining elements
244  dcConstructElements<TYPE>(&pNewData[_nSize], nNewSize - _nSize);
245 
246  // get rid of old stuff (note: no destructors called)
247  delete[] (byte *)_pData;
248  _pData = pNewData;
249  _nSize = nNewSize;
250  _nMaxSize = nNewMax;
251  }
252 }
253 
255 template<class TYPE>
256 int32 BaseArrayBase<TYPE>::append(const BaseArrayBase &src) {
257  int32 nOldSize = _nSize;
258  setSize(_nSize + src._nSize);
259  dcCopyElements<TYPE>(_pData + nOldSize, src._pData, src._nSize);
260  return nOldSize;
261 }
262 
264 template<class TYPE>
265 void BaseArrayBase<TYPE>::copy(const BaseArrayBase &src) {
266  setSize(src._nSize);
267  dcCopyElements<TYPE>(_pData, src._pData, src._nSize);
268 }
269 
271 template<class TYPE>
273  if (_nSize != _nMaxSize) {
274  // shrink to desired size
275  TYPE *pNewData = nullptr;
276  if (_nSize != 0) {
277  pNewData = (TYPE *) new byte[_nSize * sizeof(TYPE)];
278  // copy new data from old
279  memcpy(pNewData, _pData, _nSize * sizeof(TYPE));
280  }
281 
282  // get rid of old stuff (note: no destructors called)
283  delete[] (byte *)_pData;
284  _pData = pNewData;
285  _nMaxSize = _nSize;
286  }
287 }
288 
290 template<class TYPE>
291 void BaseArrayBase<TYPE>::setAtGrow(int32 nIndex, TYPE newElement) {
292  if (nIndex >= _nSize)
293  setSize(nIndex + 1, -1);
294  _pData[nIndex] = newElement;
295 }
296 
298 template<class TYPE>
299 void BaseArrayBase<TYPE>::insertAt(int32 nIndex, TYPE newElement, int32 nCount /*=1*/) {
300  if (nIndex >= _nSize) {
301  // adding after the end of the array
302  setSize(nIndex + nCount, -1); // grow so nIndex is valid
303  } else {
304  // inserting in the middle of the array
305  int32 nOldSize = _nSize;
306  setSize(_nSize + nCount, -1); // grow it to new size
307  // destroy intial data before copying over it
308  dcDestructElements<TYPE>(&_pData[nOldSize], nCount);
309  // shift old data up to fill gap
310  memmove(&_pData[nIndex + nCount], &_pData[nIndex],
311  (nOldSize - nIndex) * sizeof(TYPE));
312 
313  // re-init slots we copied from
314  dcConstructElements<TYPE>(&_pData[nIndex], nCount);
315  }
316 
317  // insert new value in the gap
318  while (nCount--)
319  _pData[nIndex++] = newElement;
320 }
321 
323 template<class TYPE>
324 void BaseArrayBase<TYPE>::removeAt(int32 nIndex, int32 nCount) {
325  // just remove a range
326  int32 nMoveCount = _nSize - (nIndex + nCount);
327  dcDestructElements<TYPE>(&_pData[nIndex], nCount);
328  if (nMoveCount)
329  memmove(&_pData[nIndex], &_pData[nIndex + nCount], nMoveCount * sizeof(TYPE));
330  _nSize -= nCount;
331 }
332 
334 template<class TYPE>
335 void BaseArrayBase<TYPE>::insertAt(int32 nStartIndex, BaseArrayBase *pNewArray) {
336  if (pNewArray->getSize() > 0) {
337  insertAt(nStartIndex, pNewArray->getAt(0), pNewArray->getSize());
338  for (int32 i = 0; i < pNewArray->getSize(); i++)
339  setAt(nStartIndex + i, pNewArray->getAt(i));
340  }
341 }
342 
344 template<class TYPE>
345 class BaseArray : public BaseArrayBase<TYPE> {
346 public:
347  bool persist(BasePersistenceManager *persistMgr) {
348  int32 i, j;
349  if (persistMgr->getIsSaving()) {
350  j = BaseArray::getSize();
351  persistMgr->transferSint32("ArraySize", &j);
352  for (i = 0; i < j; i++) {
353  TYPE obj = BaseArray::getAt(i);
354  persistMgr->transferPtr("", &obj);
355  }
356  } else {
357  BaseArray::setSize(0, -1);
358  persistMgr->transferSint32("ArraySize", &j);
359  for (i = 0; i < j; i++) {
360  TYPE obj = nullptr;
361  persistMgr->transferPtr("", &obj);
362  BaseArray::add(obj);
363  }
364  }
365  return true;
366  }
367 };
368 
370 template <>
371 class BaseArray<char *> : public BaseArrayBase<char *> {
372 public:
373  bool persist(BasePersistenceManager *persistMgr) {
374  int32 i, j;
375  if (persistMgr->getIsSaving()) {
376  j = BaseArray::getSize();
377  persistMgr->transferSint32("ArraySize", &j);
378  for (i = 0; i < j; i++) {
379  char *obj = BaseArray::getAt(i);
380  persistMgr->transferCharPtr("", &obj);
381  }
382  } else {
383  setSize(0, -1);
384  persistMgr->transferSint32("ArraySize", &j);
385  for (i = 0; i < j; i++) {
386  char *obj = nullptr;
387  persistMgr->transferCharPtr("", &obj);
388  add(obj);
389  }
390  }
391  return true;
392  }
393 };
394 
396 template <>
397 class BaseArray<const char *> : public BaseArrayBase<const char *> {
398 public:
399  bool persist(BasePersistenceManager *persistMgr) {
400  int32 i, j;
401  if (persistMgr->getIsSaving()) {
402  j = BaseArray::getSize();
403  persistMgr->transferSint32("ArraySize", &j);
404  for (i = 0; i < j; i++) {
405  const char * obj = BaseArray::getAt(i);
406  persistMgr->transferConstChar("", &obj);
407  }
408  } else {
409  BaseArray::setSize(0, -1);
410  persistMgr->transferSint32("ArraySize", &j);
411  for (i = 0; i < j; i++) {
412  const char * obj;
413  persistMgr->transferConstChar("", &obj);
414  BaseArray::add(obj);
415  }
416  }
417  return true;
418  }
419 };
420 
421 } // End of namespace Wintermute
422 
423 #endif
Definition: base_persistence_manager.h:43
Definition: coll_templ.h:66
Definition: coll_templ.h:345
Definition: achievements_tables.h:27