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 
35 #include <new>
36 
38 template<class TYPE>
39 inline void dcConstructElements(TYPE *pElements, int32 nCount) {
40  // first do bit-wise zero initialization
41  memset((void *)pElements, 0, nCount * sizeof(TYPE));
42 
43  // then call the constructor(s)
44  for (; nCount--; pElements++)
45  ::new((void *)pElements) TYPE;
46 }
47 
49 template<class TYPE>
50 inline void dcDestructElements(TYPE *pElements, int32 nCount) {
51  // call the destructor(s)
52  for (; nCount--; pElements++)
53  pElements->~TYPE();
54 }
55 
57 template<class TYPE>
58 inline void dcCopyElements(TYPE *pDest, const TYPE *pSrc, int32 nCount) {
59  // default is element-copy using assignment
60  while (nCount--)
61  *pDest++ = *pSrc++;
62 }
63 
65 // BaseArray<TYPE>
67 template<class TYPE>
69 public:
70  // Construction
71  BaseArrayBase();
72 
73  // Attributes
74  int32 getSize() const;
75  int32 getUpperBound() const;
76  void setSize(int32 nNewSize, int32 nGrowBy = -1);
77 
78  // Operations
79  // Clean up
80  void freeExtra();
81  void removeAll();
82 
83  // Accessing elements
84  TYPE getAt(int32 nIndex) const;
85  void setAt(int32 nIndex, TYPE newElement);
86  TYPE& elementAt(int32 nIndex);
87 
88  // Direct Access to the element data (may return NULL)
89  const TYPE *getData() const;
90  TYPE *getData();
91 
92  // Potentially growing the array
93  void setAtGrow(int32 nIndex, TYPE newElement);
94  int32 add(TYPE newElement);
95  int32 append(const BaseArrayBase &src);
96  void copy(const BaseArrayBase &src);
97 
98  // overloaded operator helpers
99  TYPE operator[](int32 nIndex) const;
100  TYPE &operator[](int32 nIndex);
101 
102  // Operations that move elements around
103  void insertAt(int32 nIndex, TYPE newElement, int32 nCount = 1);
104  void removeAt(int32 nIndex, int32 nCount = 1);
105  void insertAt(int32 nStartIndex, BaseArrayBase *pNewArray);
106 
107  // Implementation
108 protected:
109  TYPE *_pData; // the actual array of data
110  int32 _nSize; // # of elements (upperBound - 1)
111  int32 _nMaxSize; // max allocated
112  int32 _nGrowBy; // grow amount
113 
114 public:
115  ~BaseArrayBase();
116 };
117 
119 // CBArray<TYPE> inline functions
121 template<class TYPE>
122 inline int32 BaseArrayBase<TYPE>::getSize() const {
123  return _nSize;
124 }
125 
126 template<class TYPE>
127 inline int32 BaseArrayBase<TYPE>::getUpperBound() const {
128  return _nSize - 1;
129 }
130 
131 template<class TYPE>
132 inline void BaseArrayBase<TYPE>::removeAll() {
133  setSize(0, -1);
134 }
135 
136 template<class TYPE>
137 inline TYPE BaseArrayBase<TYPE>::getAt(int32 nIndex) const {
138  return _pData[nIndex];
139 }
140 
141 template<class TYPE>
142 inline void BaseArrayBase<TYPE>::setAt(int32 nIndex, TYPE newElement) {
143  _pData[nIndex] = newElement;
144 }
145 
146 template<class TYPE>
147 inline TYPE &BaseArrayBase<TYPE>::elementAt(int32 nIndex) {
148  return _pData[nIndex];
149 }
150 
151 template<class TYPE>
152 inline const TYPE *BaseArrayBase<TYPE>::getData() const {
153  return (const TYPE *)_pData;
154 }
155 
156 template<class TYPE>
157 inline TYPE *BaseArrayBase<TYPE>::getData() {
158  return (TYPE *)_pData;
159 }
160 
161 template<class TYPE>
162 inline int32 BaseArrayBase<TYPE>::add(TYPE newElement) {
163  int32 nIndex = _nSize;
164  setAtGrow(nIndex, newElement);
165  return nIndex;
166 }
167 
168 template<class TYPE>
169 inline TYPE BaseArrayBase<TYPE>::operator[](int32 nIndex) const {
170  return getAt(nIndex);
171 }
172 
173 template<class TYPE>
174 inline TYPE &BaseArrayBase<TYPE>::operator[](int32 nIndex) {
175  return elementAt(nIndex);
176 }
177 
179 // BaseArray<TYPE, ARG_TYPE> out-of-line functions
181 template<class TYPE>
183  _pData = nullptr;
184  _nSize = _nMaxSize = _nGrowBy = 0;
185 }
186 
188 template<class TYPE>
190  if (_pData != nullptr) {
191  dcDestructElements<TYPE>(_pData, _nSize);
192  delete[] (byte *)_pData;
193  }
194 }
195 
197 template<class TYPE>
198 void BaseArrayBase<TYPE>::setSize(int32 nNewSize, int32 nGrowBy) {
199  if (nGrowBy != -1)
200  _nGrowBy = nGrowBy; // set new size
201 
202  if (nNewSize == 0) {
203  // shrink to nothing
204  if (_pData != nullptr) {
205  dcDestructElements<TYPE>(_pData, _nSize);
206  delete[] (byte *)_pData;
207  _pData = nullptr;
208  }
209  _nSize = _nMaxSize = 0;
210  } else if (_pData == nullptr) {
211  // create one with exact size
212  _pData = (TYPE *) new byte[nNewSize * sizeof(TYPE)];
213  dcConstructElements<TYPE>(_pData, nNewSize);
214  _nSize = _nMaxSize = nNewSize;
215  } else if (nNewSize <= _nMaxSize) {
216  // it fits
217  if (nNewSize > _nSize) {
218  // initialize the new elements
219  dcConstructElements<TYPE>(&_pData[_nSize], nNewSize - _nSize);
220  } else if (_nSize > nNewSize) {
221  // destroy the old elements
222  dcDestructElements<TYPE>(&_pData[nNewSize], _nSize - nNewSize);
223  }
224  _nSize = nNewSize;
225  } else {
226  // otherwise, grow array
227  int32 numGrowBy = _nGrowBy;
228  if (numGrowBy == 0) {
229  // heuristically determine growth when nGrowBy == 0
230  // (this avoids heap fragmentation in many situations)
231  numGrowBy = _nSize / 8;
232  numGrowBy = (numGrowBy < 4) ? 4 : ((numGrowBy > 1024) ? 1024 : numGrowBy);
233  }
234  int nNewMax;
235  if (nNewSize < _nMaxSize + numGrowBy)
236  nNewMax = _nMaxSize + numGrowBy; // granularity
237  else
238  nNewMax = nNewSize; // no slush
239 
240  TYPE *pNewData = (TYPE *) new byte[nNewMax * sizeof(TYPE)];
241 
242  // copy new data from old
243  memcpy(pNewData, _pData, _nSize * sizeof(TYPE));
244 
245  // construct remaining elements
246  dcConstructElements<TYPE>(&pNewData[_nSize], nNewSize - _nSize);
247 
248  // get rid of old stuff (note: no destructors called)
249  delete[] (byte *)_pData;
250  _pData = pNewData;
251  _nSize = nNewSize;
252  _nMaxSize = nNewMax;
253  }
254 }
255 
257 template<class TYPE>
258 int32 BaseArrayBase<TYPE>::append(const BaseArrayBase &src) {
259  int32 nOldSize = _nSize;
260  setSize(_nSize + src._nSize);
261  dcCopyElements<TYPE>(_pData + nOldSize, src._pData, src._nSize);
262  return nOldSize;
263 }
264 
266 template<class TYPE>
267 void BaseArrayBase<TYPE>::copy(const BaseArrayBase &src) {
268  setSize(src._nSize);
269  dcCopyElements<TYPE>(_pData, src._pData, src._nSize);
270 }
271 
273 template<class TYPE>
275  if (_nSize != _nMaxSize) {
276  // shrink to desired size
277  TYPE *pNewData = nullptr;
278  if (_nSize != 0) {
279  pNewData = (TYPE *) new byte[_nSize * sizeof(TYPE)];
280  // copy new data from old
281  memcpy(pNewData, _pData, _nSize * sizeof(TYPE));
282  }
283 
284  // get rid of old stuff (note: no destructors called)
285  delete[] (byte *)_pData;
286  _pData = pNewData;
287  _nMaxSize = _nSize;
288  }
289 }
290 
292 template<class TYPE>
293 void BaseArrayBase<TYPE>::setAtGrow(int32 nIndex, TYPE newElement) {
294  if (nIndex >= _nSize)
295  setSize(nIndex + 1, -1);
296  _pData[nIndex] = newElement;
297 }
298 
300 template<class TYPE>
301 void BaseArrayBase<TYPE>::insertAt(int32 nIndex, TYPE newElement, int32 nCount /*=1*/) {
302  if (nIndex >= _nSize) {
303  // adding after the end of the array
304  setSize(nIndex + nCount, -1); // grow so nIndex is valid
305  } else {
306  // inserting in the middle of the array
307  int32 nOldSize = _nSize;
308  setSize(_nSize + nCount, -1); // grow it to new size
309  // destroy intial data before copying over it
310  dcDestructElements<TYPE>(&_pData[nOldSize], nCount);
311  // shift old data up to fill gap
312  memmove(&_pData[nIndex + nCount], &_pData[nIndex],
313  (nOldSize - nIndex) * sizeof(TYPE));
314 
315  // re-init slots we copied from
316  dcConstructElements<TYPE>(&_pData[nIndex], nCount);
317  }
318 
319  // insert new value in the gap
320  while (nCount--)
321  _pData[nIndex++] = newElement;
322 }
323 
325 template<class TYPE>
326 void BaseArrayBase<TYPE>::removeAt(int32 nIndex, int32 nCount) {
327  // just remove a range
328  int32 nMoveCount = _nSize - (nIndex + nCount);
329  dcDestructElements<TYPE>(&_pData[nIndex], nCount);
330  if (nMoveCount)
331  memmove(&_pData[nIndex], &_pData[nIndex + nCount], nMoveCount * sizeof(TYPE));
332  _nSize -= nCount;
333 }
334 
336 template<class TYPE>
337 void BaseArrayBase<TYPE>::insertAt(int32 nStartIndex, BaseArrayBase *pNewArray) {
338  if (pNewArray->getSize() > 0) {
339  InsertAt(nStartIndex, pNewArray->getAt(0), pNewArray->getSize());
340  for (int32 i = 0; i < pNewArray->getSize(); i++)
341  setAt(nStartIndex + i, pNewArray->getAt(i));
342  }
343 }
344 
346 template<class TYPE>
347 class BaseArray : public BaseArrayBase<TYPE> {
348 public:
349  bool persist(BasePersistenceManager *persistMgr) {
350  int32 i, j;
351  if (persistMgr->getIsSaving()) {
352  j = BaseArray::getSize();
353  persistMgr->transferSint32("ArraySize", &j);
354  for (i = 0; i < j; i++) {
355  TYPE obj = BaseArray::getAt(i);
356  persistMgr->transferPtr("", &obj);
357  }
358  } else {
359  BaseArray::setSize(0, -1);
360  persistMgr->transferSint32("ArraySize", &j);
361  for (i = 0; i < j; i++) {
362  TYPE obj = nullptr;
363  persistMgr->transferPtr("", &obj);
364  BaseArray::add(obj);
365  }
366  }
367  return true;
368  }
369 };
370 
372 template <>
373 class BaseArray<char *> : public BaseArrayBase<char *> {
374 public:
375  bool persist(BasePersistenceManager *persistMgr) {
376  int32 i, j;
377  if (persistMgr->getIsSaving()) {
378  j = getSize();
379  persistMgr->transferSint32("ArraySize", &j);
380  for (i = 0; i < j; i++) {
381  char *obj = getAt(i);
382  persistMgr->transferCharPtr("", &obj);
383  }
384  } else {
385  setSize(0, -1);
386  persistMgr->transferSint32("ArraySize", &j);
387  for (i = 0; i < j; i++) {
388  char *obj = nullptr;
389  persistMgr->transferCharPtr("", &obj);
390  add(obj);
391  }
392  }
393  return true;
394  }
395 };
396 
398 template <>
399 class BaseArray<const char *> : public BaseArrayBase<const char *> {
400 public:
401  bool persist(BasePersistenceManager *persistMgr) {
402  int32 i, j;
403  if (persistMgr->getIsSaving()) {
404  j = getSize();
405  persistMgr->transferSint32("ArraySize", &j);
406  for (i = 0; i < j; i++) {
407  const char * obj = getAt(i);
408  persistMgr->transferConstChar("", &obj);
409  }
410  } else {
411  setSize(0, -1);
412  persistMgr->transferSint32("ArraySize", &j);
413  for (i = 0; i < j; i++) {
414  const char * obj;
415  persistMgr->transferConstChar("", &obj);
416  add(obj);
417  }
418  }
419  return true;
420  }
421 };
422 
423 } // End of namespace Wintermute
424 
425 #endif
Definition: base_persistence_manager.h:55
Definition: coll_templ.h:68
Definition: coll_templ.h:347
Definition: achievements_tables.h:27