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