ScummVM API documentation
array.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 #ifndef COMMON_ARRAY_H
23 #define COMMON_ARRAY_H
24 
25 #include "common/scummsys.h"
26 #include "common/algorithm.h"
27 #include "common/textconsole.h" // For error()
28 #include "common/memory.h"
29 
30 namespace Common {
31 
51 template<class T>
52 class Array {
53 public:
54  typedef T *iterator;
55  typedef const T *const_iterator;
57  typedef T value_type;
59  typedef value_type &reference;
60  typedef const value_type &const_reference;
61 
62  typedef uint size_type;
64 protected:
65  size_type _capacity;
66  size_type _size;
67  T *_storage;
69 public:
70  constexpr Array() : _capacity(0), _size(0), _storage(nullptr) {}
71 
76  explicit Array(size_type count) : _size(count) {
77  allocCapacity(count);
78 
79  T *storage = _storage;
80 
81  for (size_type i = 0; i < count; ++i)
82  new ((void *)&storage[i]) T();
83  }
84 
88  Array(size_type count, const T &value) : _size(count) {
89  allocCapacity(count);
90  uninitialized_fill_n(_storage, count, value);
91  }
92 
96  Array(const Array<T> &array) : _capacity(array._size), _size(array._size), _storage(nullptr) {
97  if (array._storage) {
98  allocCapacity(_size);
99  uninitialized_copy(array._storage, array._storage + _size, _storage);
100  }
101  }
102 
106  Array(Array<T> &&old) : _capacity(old._capacity), _size(old._size), _storage(old._storage) {
107  old._storage = nullptr;
108  old._capacity = 0;
109  old._size = 0;
110  }
111 
120  Array(std::initializer_list<T> list) : _size(list.size()) {
121  allocCapacity(list.size());
122  if (_storage)
123  Common::uninitialized_copy(list.begin(), list.end(), _storage);
124  }
125 
129  template<class T2>
130  Array(const T2 *array, size_type n) {
131  _size = n;
132  allocCapacity(n);
133  uninitialized_copy(array, array + _size, _storage);
134  }
135 
136  ~Array() {
137  freeStorage(_storage, _size);
138  _storage = nullptr;
139  _capacity = _size = 0;
140  }
141 
143  template<class... TArgs>
144  void emplace(const_iterator pos, TArgs&&... args) {
145  assert(pos >= _storage && pos <= _storage + _size);
146 
147  const size_type index = static_cast<size_type>(pos - _storage);
148 
149  if (_size != _capacity && index == _size) {
150  // Added at the end in the existing storage
151  new (_storage + index) T(Common::forward<TArgs>(args)...);
152  } else {
153  // Either added in the middle, or ran out of space
154  // In the added-in-the-middle case, the copy is required because the parameters
155  // may contain a const ref to the original storage.
156  T *oldStorage = _storage;
157 
158  allocCapacity(roundUpCapacity(_size + 1));
159 
160  // Construct the new element first, since it may copy-construct from
161  // the original array
162  new (_storage + index) T(Common::forward<TArgs>(args)...);
163 
164  // Move the original data
165  uninitialized_move(oldStorage, oldStorage + index, _storage);
166  uninitialized_move(oldStorage + index, oldStorage + _size, _storage + index + 1);
167 
168  freeStorage(oldStorage, _size);
169  }
170 
171  _size++;
172  }
173 
175  template<class... TArgs>
176  void emplace_back(TArgs &&...args) {
177  emplace(begin() + _size, Common::forward<TArgs>(args)...);
178  }
179 
181  void push_back(const T &element) {
182  emplace_back(element);
183  }
184 
186  void push_back(T &&element) {
187  emplace_back(Common::move(element));
188  }
189 
191  void push_back(const Array<T> &array) {
192  if (_size + array.size() <= _capacity) {
193  uninitialized_copy(array.begin(), array.end(), end());
194  _size += array.size();
195  } else
196  insert_aux(end(), array.begin(), array.end());
197  }
198 
200  void pop_back() {
201  assert(_size > 0);
202  _size--;
203  // We also need to destroy the last object properly here.
204  _storage[_size].~T();
205  }
206 
208  const T *data() const {
209  return _storage;
210  }
211 
213  T *data() {
214  return _storage;
215  }
216 
218  T &front() {
219  assert(_size > 0);
220  return _storage[0];
221  }
222 
224  const T &front() const {
225  assert(_size > 0);
226  return _storage[0];
227  }
228 
230  T &back() {
231  assert(_size > 0);
232  return _storage[_size-1];
233  }
234 
236  const T &back() const {
237  assert(_size > 0);
238  return _storage[_size-1];
239  }
240 
242  void insert_at(size_type idx, const T &element) {
243  assert(idx <= _size);
244  insert_aux(_storage + idx, &element, &element + 1);
245  }
246 
248  void insert_at(size_type idx, const Array<T> &array) {
249  assert(idx <= _size);
250  insert_aux(_storage + idx, array.begin(), array.end());
251  }
252 
256  void insert(iterator pos, const T &element) {
257  insert_aux(pos, &element, &element + 1);
258  }
259 
261  T remove_at(size_type idx) {
262  assert(idx < _size);
263  T tmp = Common::move(_storage[idx]);
264  move(_storage + idx + 1, _storage + _size, _storage + idx);
265  _size--;
266  // We also need to destroy the last object properly here.
267  _storage[_size].~T();
268  return tmp;
269  }
270 
271  // TODO: insert, remove, ...
272 
274  T &operator[](size_type idx) {
275  assert(idx < _size);
276  return _storage[idx];
277  }
278 
280  const T &operator[](size_type idx) const {
281  assert(idx < _size);
282  return _storage[idx];
283  }
284 
286  Array<T> &operator=(const Array<T> &array) {
287  if (this == &array)
288  return *this;
289 
290  freeStorage(_storage, _size);
291  _size = array._size;
292  allocCapacity(_size);
293  uninitialized_copy(array._storage, array._storage + _size, _storage);
294 
295  return *this;
296  }
297 
300  if (this == &old)
301  return *this;
302 
303  freeStorage(_storage, _size);
304  _capacity = old._capacity;
305  _size = old._size;
306  _storage = old._storage;
307 
308  old._storage = nullptr;
309  old._capacity = 0;
310  old._size = 0;
311 
312  return *this;
313  }
314 
316  size_type size() const {
317  return _size;
318  }
319 
321  void clear() {
322  freeStorage(_storage, _size);
323  _storage = nullptr;
324  _size = 0;
325  _capacity = 0;
326  }
327 
329  iterator erase(iterator pos) {
330  move(pos + 1, _storage + _size, pos);
331  _size--;
332  // We also need to destroy the last object properly here.
333  _storage[_size].~T();
334  return pos;
335  }
336 
338  iterator erase(iterator first, iterator last) {
339  move(last, _storage + _size, first);
340 
341  int count = (last - first);
342  _size -= count;
343 
344  // We also need to destroy the objects beyond the new size
345  for (uint idx = _size; idx < (_size + count); ++idx)
346  _storage[idx].~T();
347 
348  return first;
349  }
350 
352  bool empty() const {
353  return (_size == 0);
354  }
355 
357  bool operator==(const Array<T> &other) const {
358  if (this == &other)
359  return true;
360  if (_size != other._size)
361  return false;
362  for (size_type i = 0; i < _size; ++i) {
363  if (_storage[i] != other._storage[i])
364  return false;
365  }
366  return true;
367  }
368 
370  bool operator!=(const Array<T> &other) const {
371  return !(*this == other);
372  }
373 
375  iterator begin() {
376  return _storage;
377  }
378 
380  iterator end() {
381  return _storage + _size;
382  }
383 
385  const_iterator begin() const {
386  return _storage;
387  }
388 
390  const_iterator end() const {
391  return _storage + _size;
392  }
393 
397  void reserve(size_type newCapacity) {
398  if (newCapacity <= _capacity)
399  return;
400 
401  T *oldStorage = _storage;
402  allocCapacity(newCapacity);
403 
404  if (oldStorage) {
405  // Move old data
406  uninitialized_move(oldStorage, oldStorage + _size, _storage);
407  freeStorage(oldStorage, _size);
408  }
409  }
410 
412  void resize(size_type newSize) {
413  reserve(newSize);
414 
415  T *storage = _storage;
416 
417  for (size_type i = newSize; i < _size; ++i)
418  storage[i].~T();
419  for (size_type i = _size; i < newSize; ++i)
420  new ((void *)&storage[i]) T();
421 
422  _size = newSize;
423  }
424 
427  void resize(size_type newSize, const T value) {
428  reserve(newSize);
429 
430  T *storage = _storage;
431 
432  for (size_type i = newSize; i < _size; ++i)
433  storage[i].~T();
434  if (newSize > _size)
435  uninitialized_fill_n(storage + _size, newSize - _size, value);
436 
437  _size = newSize;
438  }
439 
443  void assign(const_iterator first, const_iterator last) {
444  resize(distance(first, last)); // FIXME: ineffective?
445  T *dst = _storage;
446  while (first != last)
447  *dst++ = *first++;
448  }
449 
450  void swap(Array &arr) {
451  SWAP(this->_capacity, arr._capacity);
452  SWAP(this->_size, arr._size);
453  SWAP(this->_storage, arr._storage);
454  }
455 
456 protected:
460  static size_type roundUpCapacity(size_type capacity) {
461  size_type capa = 8;
462  while (capa < capacity)
463  capa <<= 1;
464  return capa;
465  }
466 
468  void allocCapacity(size_type capacity) {
469  _capacity = capacity;
470  if (capacity) {
471  _storage = (T *)malloc(sizeof(T) * capacity);
472  if (!_storage)
473  ::error("Common::Array: failure to allocate %u bytes", capacity * (size_type)sizeof(T));
474  } else {
475  _storage = nullptr;
476  }
477  }
478 
480  void freeStorage(T *storage, const size_type elements) {
481  for (size_type i = 0; i < elements; ++i)
482  storage[i].~T();
483  free(storage);
484  }
485 
499  iterator insert_aux(iterator pos, const_iterator first, const_iterator last) {
500  assert(_storage <= pos && pos <= _storage + _size);
501  assert(first <= last);
502  const size_type n = last - first;
503  if (n) {
504  const size_type idx = pos - _storage;
505  if (_size + n > _capacity || (_storage <= first && first <= _storage + _size)) {
506  T *const oldStorage = _storage;
507 
508  // If there is not enough space, allocate more.
509  // Likewise, if this is a self-insert, we allocate new
510  // storage to avoid conflicts.
511  allocCapacity(roundUpCapacity(_size + n));
512 
513  // Move the data from the old storage till the position where
514  // we insert new data
515  uninitialized_move(oldStorage, oldStorage + idx, _storage);
516  // Copy the data we insert
517  uninitialized_copy(first, last, _storage + idx);
518  // Afterwards, move the old data from the position where we
519  // insert.
520  uninitialized_move(oldStorage + idx, oldStorage + _size, _storage + idx + n);
521 
522  freeStorage(oldStorage, _size);
523  } else if (idx + n <= _size) {
524  // Make room for the new elements by shifting back
525  // existing ones.
526  // 1. Move a part of the data to the uninitialized area
527  uninitialized_move(_storage + _size - n, _storage + _size, _storage + _size);
528  // 2. Move a part of the data to the initialized area
529  move_backward(pos, _storage + _size - n, _storage + _size);
530 
531  // Insert the new elements.
532  copy(first, last, pos);
533  } else {
534  // Move the old data from the position till the end to the new
535  // place.
536  uninitialized_move(pos, _storage + _size, _storage + idx + n);
537 
538  // Copy a part of the new data to the position inside the
539  // initialized space.
540  copy(first, first + (_size - idx), pos);
541 
542  // Copy a part of the new data to the position inside the
543  // uninitialized space.
544  uninitialized_copy(first + (_size - idx), last, _storage + _size);
545  }
546 
547  // Finally, update the internal state
548  _size += n;
549  }
550  return pos;
551  }
552 
553 };
554 
558 template<class T, typename CompareArgType = const void *>
559 class SortedArray : public Array<T> {
560 public:
561  typedef int (*Comparator)(CompareArgType, CompareArgType);
562  typedef T *iterator;
563  typedef uint size_type;
564 
565  SortedArray(Comparator comparator) {
566  _comparator = comparator;
567  }
568 
572  void insert(const T &element) {
573  if (!this->_size) {
574  this->insert_aux(this->_storage, &element, &element + 1);
575  return;
576  }
577 
578  T *where = bsearchMin(element);
579 
580  if (where > this->_storage + this->_size)
581  Array<T>::push_back(element);
582  else
583  Array<T>::insert(where, element);
584  }
585 
586 private:
587  T &operator[](size_type idx);
588 
589  void insert_at(size_type idx, const T &element);
590 
591  void insert_at(size_type idx, const Array<T> &array);
592 
593  void insert(iterator pos, const T &element);
594 
595  void push_back(const T &element);
596 
597  void push_back(const Array<T> &array);
598 
599  // Based on code Copyright (C) 2008-2009 Ksplice, Inc.
600  // Author: Tim Abbott <tabbott@ksplice.com>
601  // Licensed under GPLv2+
602  T *bsearchMin(CompareArgType key) {
603  uint start_ = 0, end_ = this->_size;
604  int result;
605 
606  while (start_ < end_) {
607  uint mid = start_ + (end_ - start_) / 2;
608 
609  result = this->_comparator(key, this->_storage[mid]);
610  if (result < 0)
611  end_ = mid;
612  else
613  start_ = mid + 1;
614  }
615 
616  return &this->_storage[start_];
617  }
618 
619  Comparator _comparator;
620 };
621 
624 } // End of namespace Common
625 
626 #endif
void push_back(const Array< T > &array)
Definition: array.h:191
bool operator==(const Array< T > &other) const
Definition: array.h:357
T * _storage
Definition: array.h:67
bool operator!=(const Array< T > &other) const
Definition: array.h:370
void insert_at(size_type idx, const T &element)
Definition: array.h:242
const_iterator begin() const
Definition: array.h:385
iterator insert_aux(iterator pos, const_iterator first, const_iterator last)
Definition: array.h:499
T * data()
Definition: array.h:213
const T * data() const
Definition: array.h:208
void insert_at(size_type idx, const Array< T > &array)
Definition: array.h:248
Definition: array.h:52
const T & operator[](size_type idx) const
Definition: array.h:280
void clear()
Definition: array.h:321
iterator end()
Definition: array.h:380
iterator begin()
Definition: array.h:375
T & operator[](size_type idx)
Definition: array.h:274
T * iterator
Definition: array.h:54
Array< T > & operator=(const Array< T > &array)
Definition: array.h:286
void SWAP(T &a, T &b)
Definition: util.h:84
T & front()
Definition: array.h:218
Array(size_type count)
Definition: array.h:76
Array & operator=(Array< T > &&old)
Definition: array.h:299
static size_type roundUpCapacity(size_type capacity)
Definition: array.h:460
Type * uninitialized_move(In first, In last, Type *dst)
Definition: memory.h:71
const T & front() const
Definition: array.h:224
const_iterator end() const
Definition: array.h:390
Out copy(In first, In last, Out dst)
Definition: algorithm.h:52
bool empty() const
Definition: array.h:352
void push_back(const T &element)
Definition: array.h:181
size_type _size
Definition: array.h:66
const T * const_iterator
Definition: array.h:55
void reserve(size_type newCapacity)
Definition: array.h:397
Type * uninitialized_copy(In first, In last, Type *dst)
Definition: memory.h:59
Definition: algorithm.h:29
Definition: array.h:559
void pop_back()
Definition: array.h:200
Array(size_type count, const T &value)
Definition: array.h:88
void resize(size_type newSize, const T value)
Definition: array.h:427
void freeStorage(T *storage, const size_type elements)
Definition: array.h:480
size_type size() const
Definition: array.h:316
Out move(In first, In last, Out dst)
Definition: algorithm.h:109
Out move_backward(In first, In last, Out dst)
Definition: algorithm.h:124
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
void push_back(T &&element)
Definition: array.h:186
iterator erase(iterator first, iterator last)
Definition: array.h:338
void resize(size_type newSize)
Definition: array.h:412
T remove_at(size_type idx)
Definition: array.h:261
Array(const Array< T > &array)
Definition: array.h:96
size_type _capacity
Definition: array.h:65
uint size_type
Definition: array.h:62
void allocCapacity(size_type capacity)
Definition: array.h:468
void assign(const_iterator first, const_iterator last)
Definition: array.h:443
void emplace_back(TArgs &&...args)
Definition: array.h:176
T value_type
Definition: array.h:57
const T & back() const
Definition: array.h:236
Array(const T2 *array, size_type n)
Definition: array.h:130
void insert(const T &element)
Definition: array.h:572
void insert(iterator pos, const T &element)
Definition: array.h:256
Array(std::initializer_list< T > list)
Definition: array.h:120
Array(Array< T > &&old)
Definition: array.h:106
void emplace(const_iterator pos, TArgs &&... args)
Definition: array.h:144
iterator erase(iterator pos)
Definition: array.h:329
T & back()
Definition: array.h:230
void uninitialized_fill_n(Type *dst, size_t n, const Value &x)
Definition: memory.h:94