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