/* * Copyright (c) 2012-2014 Daniele Bartolini and individual contributors. * License: https://github.com/taylor001/crown/blob/master/LICENSE */ #pragma once #include "assert.h" #include "macros.h" #include "container_types.h" #include "allocator.h" #include // memcpy namespace crown { /// Functions to manipulate Array. /// /// @ingroup Containers namespace array { /// Returns whether the array @a a is empty. template bool empty(const Array& a); /// Returns the number of items in the array @a a. template uint32_t size(const Array& a); /// Returns the maximum number of items the array @a a can hold. template uint32_t capacity(const Array& a); /// Resizes the array @a a to the given @a size. /// @note /// Old items will be copied to the newly created array. /// If the new capacity is smaller than the previous one, the /// array will be truncated. template void resize(Array& a, uint32_t size); /// Reserves space in the array @a a for at least @a capacity items. template void reserve(uint32_t capacity); /// Sets the capacity of array @a a. template void set_capacity(Array& a, uint32_t capacity); /// Grows the array @a a to contain at least @a min_capacity items. template void grow(Array& a, uint32_t min_capacity); /// Condenses the array @a a so that its capacity matches the actual number /// of items in the array. template void condense(Array& a); /// Appends an item to the array @a a and returns its index. template uint32_t push_back(Array& a, const T& item); /// Removes the last item from the array @a a. template void pop_back(Array& a); /// Appends @a count @a items to the array @a a and returns the number /// of items in the array after the append operation. template uint32_t push(Array& a, const T* items, uint32_t count); /// Clears the content of the array @a a. /// @note /// Does not free memory nor call destructors, it only zeroes /// the number of items in the array. template void clear(Array& a); template T* begin(Array& a); template const T* begin(const Array& a); template T* end(Array& a); template const T* end(const Array& a); template T& front(Array& a); template const T& front(const Array& a); template T& back(Array& a); template const T& back(const Array& a); } // namespace array namespace array { template inline bool empty(const Array& a) { return a._size == 0; } template inline uint32_t size(const Array& a) { return a._size; } template inline uint32_t capacity(const Array& a) { return a._capacity; } template inline void resize(Array& a, uint32_t size) { if (size > a._capacity) { set_capacity(a, size); } a._size = size; } template inline void reserve(Array& a, uint32_t capacity) { if (capacity > a._capacity) { grow(a, capacity); } } template inline void set_capacity(Array& a, uint32_t capacity) { if (capacity == a._capacity) { return; } if (capacity < a._size) { resize(a, capacity); } if (capacity > 0) { T* tmp = a._array; a._capacity = capacity; a._array = (T*)a._allocator->allocate(capacity * sizeof(T), CE_ALIGNOF(T)); memcpy(a._array, tmp, a._size * sizeof(T)); if (tmp) { a._allocator->deallocate(tmp); } } } template inline void grow(Array& a, uint32_t min_capacity) { uint32_t new_capacity = a._capacity * 2 + 1; if (new_capacity < min_capacity) { new_capacity = min_capacity; } set_capacity(a, new_capacity); } template inline void condense(Array& a) { resize(a, a._size); } template inline uint32_t push_back(Array& a, const T& item) { if (a._capacity == a._size) { grow(a, 0); } a._array[a._size] = item; return a._size++; } template inline void pop_back(Array& a) { CE_ASSERT(a._size > 0, "The array is empty"); a._size--; } template inline uint32_t push(Array& a, const T* items, uint32_t count) { if (a._capacity <= a._size + count) { grow(a, a._size + count); } memcpy(&a._array[a._size], items, sizeof(T) * count); a._size += count; return a._size; } template inline void clear(Array& a) { a._size = 0; } template inline const T* begin(const Array& a) { return a._array; } template inline T* begin(Array& a) { return a._array; } template inline const T* end(const Array& a) { return a._array + a._size; } template inline T* end(Array& a) { return a._array + a._size; } template inline T& front(Array& a) { CE_ASSERT(a._size > 0, "The array is empty"); return a._array[0]; } template inline const T& front(const Array& a) { CE_ASSERT(a._size > 0, "The array is empty"); return a._array[0]; } template inline T& back(Array& a) { CE_ASSERT(a._size > 0, "The array is empty"); return a._array[a._size - 1]; } template inline const T& back(const Array& a) { CE_ASSERT(a._size > 0, "The array is empty"); return a._array[a._size - 1]; } } // namespace array template inline Array::Array(Allocator& allocator) : _allocator(&allocator), _capacity(0), _size(0), _array(NULL) { } template inline Array::Array(Allocator& allocator, uint32_t capacity) : _allocator(&allocator), _capacity(0), _size(0), _array(NULL) { array::resize(*this, capacity); } template inline Array::Array(const Array& other) : _allocator(other._allocator), _capacity(0), _size(0), _array(NULL) { *this = other; } template inline Array::~Array() { if (_array) { _allocator->deallocate(_array); } } template inline T& Array::operator[](uint32_t index) { CE_ASSERT(index < _size, "Index out of bounds"); return _array[index]; } template inline const T& Array::operator[](uint32_t index) const { CE_ASSERT(index < _size, "Index out of bounds"); return _array[index]; } template inline Array& Array::operator=(const Array& other) { const uint32_t size = other._size; array::resize(*this, size); memcpy(_array, other._array, sizeof(T) * size); return *this; } } // namespace crown