Files
Seele/src/Engine/Containers/Array.h
T

569 lines
22 KiB
C++
Raw Normal View History

#pragma once
2025-01-29 16:15:48 +01:00
#include "Concepts.h"
2025-03-20 20:15:38 +01:00
#include "EngineTypes.h"
#include "MemoryResource.h"
2024-06-09 12:20:04 +02:00
#include <algorithm>
#include <assert.h>
2025-05-16 13:04:43 +02:00
#include <cstring>
2020-04-01 02:17:49 +02:00
#include <initializer_list>
#include <iterator>
#include <memory_resource>
2024-06-09 12:20:04 +02:00
namespace Seele {
2025-03-20 20:15:38 +01:00
template <typename T> struct Array {
2024-06-09 12:20:04 +02:00
public:
template <typename X> class IteratorBase {
public:
2022-01-12 14:40:26 +01:00
using iterator_category = std::random_access_iterator_tag;
using value_type = X;
2021-10-23 00:22:35 +02:00
using difference_type = std::ptrdiff_t;
2022-01-12 14:40:26 +01:00
using reference = X&;
using pointer = X*;
2020-06-08 01:44:47 +02:00
2024-06-09 12:20:04 +02:00
constexpr IteratorBase(X* x = nullptr) : p(x) {}
constexpr reference operator*() const { return *p; }
constexpr pointer operator->() const { return p; }
constexpr bool operator==(const IteratorBase& other) const { return p == other.p; }
constexpr bool operator!=(const IteratorBase& other) const { return p != other.p; }
constexpr std::strong_ordering operator<=>(const IteratorBase& other) const { return p <=> other.p; }
constexpr IteratorBase operator+(size_t other) const {
2022-11-29 16:34:42 +01:00
IteratorBase tmp(*this);
tmp.p += other;
return tmp;
}
2024-06-09 12:20:04 +02:00
constexpr int operator-(const IteratorBase& other) const { return (int)(p - other.p); }
constexpr IteratorBase& operator-=(difference_type other) {
p -= other;
2024-03-18 15:28:56 +01:00
return *this;
}
2024-06-09 12:20:04 +02:00
constexpr IteratorBase& operator+=(difference_type other) {
p += other;
2023-11-06 14:47:21 +01:00
return *this;
}
2024-06-09 12:20:04 +02:00
constexpr IteratorBase operator-(difference_type diff) const { return IteratorBase(p - diff); }
constexpr IteratorBase& operator++() {
2022-01-12 14:40:26 +01:00
p++;
return *this;
}
2024-06-09 12:20:04 +02:00
constexpr IteratorBase& operator--() {
2022-01-12 14:40:26 +01:00
p--;
return *this;
}
2024-06-09 12:20:04 +02:00
constexpr IteratorBase operator++(int) {
2022-01-12 14:40:26 +01:00
IteratorBase tmp(*this);
++*this;
return tmp;
}
2024-06-09 12:20:04 +02:00
constexpr IteratorBase operator--(int) {
2022-01-12 14:40:26 +01:00
IteratorBase tmp(*this);
--*this;
return tmp;
2021-10-23 00:22:35 +02:00
}
2024-06-09 12:20:04 +02:00
private:
X* p;
2022-01-12 14:40:26 +01:00
};
2024-06-09 12:20:04 +02:00
2022-01-12 14:40:26 +01:00
using value_type = T;
2025-03-20 20:15:38 +01:00
using allocator_type = std::pmr::polymorphic_allocator<T>;
2022-01-12 14:40:26 +01:00
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = value_type&;
using const_reference = const value_type&;
using Iterator = IteratorBase<T>;
using ConstIterator = IteratorBase<const T>;
using iterator = Iterator;
using const_iterator = ConstIterator;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
2025-03-26 13:38:48 +01:00
constexpr Array(const allocator_type& alloc = allocator_type()) noexcept
2025-04-11 18:15:39 +02:00
: arraySize(0), allocated(0), _data(nullptr), allocator(alloc) {}
2025-03-26 13:38:48 +01:00
constexpr Array(size_type size, const value_type& value, const allocator_type& alloc = allocator_type())
2024-06-09 12:20:04 +02:00
: arraySize(size), allocated(size), allocator(alloc) {
2022-01-12 14:40:26 +01:00
_data = allocateArray(size);
assert(_data != nullptr);
2024-06-09 12:20:04 +02:00
for (size_type i = 0; i < size; ++i) {
2023-12-03 00:29:02 +01:00
std::allocator_traits<allocator_type>::construct(allocator, &_data[i], value);
2021-10-23 00:22:35 +02:00
}
2022-01-12 14:40:26 +01:00
}
2025-03-26 13:38:48 +01:00
constexpr explicit Array(size_type size, const allocator_type& alloc = allocator_type())
2024-06-09 12:20:04 +02:00
: arraySize(size), allocated(size), allocator(alloc) {
2022-01-12 14:40:26 +01:00
_data = allocateArray(size);
assert(_data != nullptr);
2024-06-09 12:20:04 +02:00
if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
2023-12-03 00:29:02 +01:00
std::memset(_data, 0, size * sizeof(T));
2024-06-09 12:20:04 +02:00
} else {
for (size_type i = 0; i < size; ++i) {
2023-12-03 00:29:02 +01:00
std::allocator_traits<allocator_type>::construct(allocator, &_data[i]);
}
2022-01-12 14:40:26 +01:00
}
}
2025-03-26 13:38:48 +01:00
constexpr Array(std::initializer_list<T> init, const allocator_type& alloc = allocator_type())
2024-06-09 12:20:04 +02:00
: arraySize(init.size()), allocated(init.size()), allocator(alloc) {
2022-01-12 14:40:26 +01:00
_data = allocateArray(init.size());
assert(_data != nullptr);
2025-01-12 11:26:52 +01:00
std::uninitialized_copy(init.begin(), init.end(), begin());
2022-01-12 14:40:26 +01:00
}
2025-01-29 16:15:48 +01:00
template <container_compatible_range<T> Range>
2025-03-26 13:38:48 +01:00
constexpr Array(std::from_range_t, Range&& rg, const allocator_type& alloc = allocator_type())
2025-01-29 16:15:48 +01:00
: arraySize(0), allocated(0), allocator(alloc) {
if constexpr (std::ranges::sized_range<Range> || std::ranges::forward_range<Range>) {
arraySize = std::ranges::size(rg);
allocated = arraySize;
_data = allocateArray(allocated);
2025-02-02 09:39:01 +01:00
std::uninitialized_copy(rg.begin(), rg.end(), begin());
2025-01-29 16:15:48 +01:00
} else {
for (auto it = std::ranges::begin(rg); it != std::ranges::end(rg); it++) {
add(*it);
}
}
}
2024-06-09 12:20:04 +02:00
constexpr Array(const Array& other)
: arraySize(other.arraySize), allocated(other.allocated),
allocator(std::allocator_traits<allocator_type>::select_on_container_copy_construction(other.allocator)) {
2022-01-12 14:40:26 +01:00
_data = allocateArray(other.allocated);
assert(_data != nullptr);
std::uninitialized_copy(other.begin(), other.end(), begin());
}
2025-03-20 20:15:38 +01:00
constexpr Array(const Array& other, const allocator_type& alloc)
: arraySize(other.arraySize), allocated(other.allocated), allocator(alloc) {
2023-01-21 18:43:21 +01:00
_data = allocateArray(other.allocated);
assert(_data != nullptr);
std::uninitialized_copy(other.begin(), other.end(), begin());
}
2024-06-09 12:20:04 +02:00
constexpr Array(Array&& other) noexcept
: arraySize(std::move(other.arraySize)), allocated(std::move(other.allocated)), allocator(std::move(other.allocator)) {
2022-01-12 14:40:26 +01:00
_data = other._data;
other._data = nullptr;
other.allocated = 0;
other.arraySize = 0;
}
2025-03-20 20:15:38 +01:00
constexpr Array(Array&& other, const allocator_type& alloc) noexcept
2024-06-09 12:20:04 +02:00
: arraySize(std::move(other.arraySize)), allocated(std::move(other.allocated)), allocator(alloc) {
2023-01-21 18:43:21 +01:00
_data = allocateArray(other.allocated);
std::uninitialized_move(other.begin(), other.end(), begin());
other.deallocateArray(other._data, other.allocated);
other._data = nullptr;
other.allocated = 0;
other.arraySize = 0;
}
2024-06-09 12:20:04 +02:00
Array& operator=(const Array& other) {
if (this != &other) {
if (other.arraySize > allocated) {
2023-01-21 18:43:21 +01:00
clear();
}
2024-06-09 12:20:04 +02:00
if constexpr (std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value) {
if (!std::allocator_traits<allocator_type>::is_always_equal::value && allocator != other.allocator) {
2022-01-12 14:40:26 +01:00
clear();
}
allocator = other.allocator;
2021-10-23 00:22:35 +02:00
}
2024-06-09 12:20:04 +02:00
if (_data == nullptr) {
2022-01-12 14:40:26 +01:00
_data = allocateArray(other.allocated);
allocated = other.allocated;
}
arraySize = other.arraySize;
2021-10-23 00:22:35 +02:00
std::uninitialized_copy(other.begin(), other.end(), begin());
}
2022-01-12 14:40:26 +01:00
return *this;
}
2025-03-20 20:15:38 +01:00
Array& operator=(Array&& other) noexcept(std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
std::allocator_traits<allocator_type>::is_always_equal::value) {
2024-06-09 12:20:04 +02:00
if (this != &other) {
if (_data != nullptr) {
2022-01-12 14:40:26 +01:00
clear();
}
2024-06-09 12:20:04 +02:00
if constexpr (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value) {
2023-01-21 18:43:21 +01:00
allocator = std::move(other.allocator);
}
2022-01-12 14:40:26 +01:00
allocated = std::move(other.allocated);
arraySize = std::move(other.arraySize);
2021-10-23 00:22:35 +02:00
_data = other._data;
other._data = nullptr;
}
2022-01-12 14:40:26 +01:00
return *this;
}
2024-06-09 12:20:04 +02:00
constexpr ~Array() { clear(); }
2025-01-12 11:26:52 +01:00
[[nodiscard]] constexpr iterator find(const value_type& item) noexcept {
2024-06-09 12:20:04 +02:00
for (size_type i = 0; i < arraySize; ++i) {
if (_data[i] == item) {
2022-01-12 14:40:26 +01:00
return iterator(&_data[i]);
2021-10-23 00:22:35 +02:00
}
}
2022-11-29 16:34:42 +01:00
return end();
2022-01-12 14:40:26 +01:00
}
2025-01-12 11:26:52 +01:00
[[nodiscard]] constexpr iterator find(value_type&& item) noexcept {
2024-06-09 12:20:04 +02:00
for (size_type i = 0; i < arraySize; ++i) {
if (_data[i] == item) {
2022-01-12 14:40:26 +01:00
return iterator(&_data[i]);
2021-10-23 00:22:35 +02:00
}
}
2024-06-09 12:20:04 +02:00
return end();
2022-11-29 16:34:42 +01:00
}
2025-01-12 11:26:52 +01:00
[[nodiscard]] constexpr const_iterator find(const value_type& item) const noexcept {
2024-06-09 12:20:04 +02:00
for (size_type i = 0; i < arraySize; ++i) {
if (_data[i] == item) {
2022-11-29 16:34:42 +01:00
return const_iterator(&_data[i]);
}
}
return end();
}
2025-01-12 11:26:52 +01:00
[[nodiscard]] constexpr const_iterator find(value_type&& item) const noexcept {
2024-06-09 12:20:04 +02:00
for (size_type i = 0; i < arraySize; ++i) {
if (_data[i] == item) {
2022-11-29 16:34:42 +01:00
return const_iterator(&_data[i]);
}
}
2024-06-09 12:20:04 +02:00
return end();
2022-01-12 14:40:26 +01:00
}
2024-06-09 12:20:04 +02:00
template <class Pred>
requires std::predicate<Pred, value_type>
constexpr const_iterator find(Pred pred) const noexcept {
for (size_type i = 0; i < arraySize; ++i) {
if (pred(_data[i])) {
2022-11-29 16:34:42 +01:00
return const_iterator(&_data[i]);
2022-04-13 13:01:35 +02:00
}
}
2022-11-29 16:34:42 +01:00
return end();
2022-04-13 13:01:35 +02:00
}
2023-10-26 18:37:29 +02:00
2024-06-09 12:20:04 +02:00
template <class Pred>
requires std::predicate<Pred, value_type>
2025-03-04 19:38:03 +09:00
constexpr iterator find(Pred&& pred) noexcept {
2024-06-09 12:20:04 +02:00
for (size_type i = 0; i < arraySize; ++i) {
if (pred(_data[i])) {
2023-11-01 23:12:30 +01:00
return iterator(&_data[i]);
2023-10-26 18:37:29 +02:00
}
}
return end();
}
2024-06-09 12:20:04 +02:00
constexpr allocator_type get_allocator() const noexcept { return allocator; }
constexpr iterator begin() noexcept { return iterator(_data); }
constexpr iterator end() noexcept { return iterator(_data + arraySize); }
constexpr const_iterator begin() const noexcept { return const_iterator(_data); }
constexpr const_iterator end() const noexcept { return const_iterator(_data + arraySize); }
constexpr const_iterator cbegin() const noexcept { return const_iterator(_data); }
constexpr const_iterator cend() const noexcept { return const_iterator(_data + arraySize); }
constexpr reference add(const value_type& item = value_type()) { return addInternal(item); }
constexpr reference add(value_type&& item) { return addInternal(std::forward<T>(item)); }
constexpr void addAll(const Array& other) {
for (const auto& value : other) {
2022-01-12 14:40:26 +01:00
addInternal(value);
}
}
2024-06-09 12:20:04 +02:00
constexpr void addAll(Array&& other) {
for (auto&& value : other) {
addInternal(value);
}
2024-04-10 10:23:06 +02:00
}
2024-06-09 12:20:04 +02:00
constexpr reference addUnique(const value_type& item = value_type()) {
2022-01-12 14:40:26 +01:00
iterator it;
2024-06-09 12:20:04 +02:00
if ((it = std::move(find(item))) != end()) {
2022-01-12 14:40:26 +01:00
return *it;
}
return addInternal(item);
}
2024-06-09 12:20:04 +02:00
template <typename... args> constexpr reference emplace(args... arguments) {
if (arraySize == allocated) {
2022-01-12 14:40:26 +01:00
size_type newSize = arraySize + 1;
allocated = calculateGrowth(newSize);
2024-06-09 12:20:04 +02:00
T* tempArray = allocateArray(allocated);
2022-01-12 14:40:26 +01:00
assert(tempArray != nullptr);
2024-06-09 12:20:04 +02:00
2022-01-12 14:40:26 +01:00
std::uninitialized_move(begin(), end(), Iterator(tempArray));
deallocateArray(_data, arraySize);
_data = tempArray;
}
std::allocator_traits<allocator_type>::construct(allocator, &_data[arraySize++], arguments...);
return _data[arraySize - 1];
}
2024-06-09 12:20:04 +02:00
template <class Pred>
requires std::predicate<Pred, value_type>
2025-03-04 19:38:03 +09:00
constexpr void remove_if(Pred&& pred, bool keepOrder = true) {
Iterator it;
2025-03-20 20:15:38 +01:00
while ((it = find(pred)) != end()) {
2025-03-04 19:38:03 +09:00
erase(it, keepOrder);
}
2022-04-13 13:01:35 +02:00
}
2025-02-02 09:39:01 +01:00
constexpr void remove(const value_type& element, bool keepOrder = true) { erase(find(element), keepOrder); }
constexpr void remove(value_type&& element, bool keepOrder = true) { erase(find(element), keepOrder); }
constexpr void erase(iterator it, bool keepOrder = true) { removeAt(it - begin(), keepOrder); }
constexpr void erase(const_iterator it, bool keepOrder = true) { removeAt(it - cbegin(), keepOrder); }
constexpr bool contains(const T& value) const { return find(value) != end(); }
2024-06-09 12:20:04 +02:00
constexpr void removeAt(size_type index, bool keepOrder = true) {
if (keepOrder) {
for (size_type i = index; i < arraySize - 1; ++i) {
_data[i] = std::move(_data[i + 1]);
2022-01-12 14:40:26 +01:00
}
2024-06-09 12:20:04 +02:00
} else {
2022-01-12 14:40:26 +01:00
_data[index] = std::move(_data[arraySize - 1]);
}
2022-02-24 22:38:26 +01:00
std::allocator_traits<allocator_type>::destroy(allocator, &_data[--arraySize]);
2022-01-12 14:40:26 +01:00
}
2024-06-09 12:20:04 +02:00
constexpr void resize(size_type newSize) { resizeInternal(newSize, T()); }
constexpr void resize(size_type newSize, const value_type& value) { resizeInternal(newSize, value); }
2025-04-11 18:15:39 +02:00
constexpr void clear(bool preserveAllocation = false) noexcept {
2024-06-09 12:20:04 +02:00
if (_data == nullptr) {
2022-01-12 14:40:26 +01:00
return;
}
2024-06-09 12:20:04 +02:00
if constexpr (!std::is_trivially_destructible_v<T>) {
for (size_type i = 0; i < arraySize; ++i) {
2023-12-11 14:45:37 +01:00
std::allocator_traits<allocator_type>::destroy(allocator, &_data[i]);
}
2022-01-12 14:40:26 +01:00
}
2025-04-11 18:15:39 +02:00
if (!preserveAllocation) {
deallocateArray(_data, allocated);
_data = nullptr;
allocated = 0;
}
2022-01-12 14:40:26 +01:00
arraySize = 0;
}
2025-03-04 19:38:03 +09:00
[[nodiscard]] constexpr size_type indexOf(iterator iterator) { return iterator - begin(); }
[[nodiscard]] constexpr size_type indexOf(const_iterator iterator) const { return iterator.p - begin().p; }
[[nodiscard]] constexpr size_type indexOf(T& t) { return indexOf(find(t)); }
[[nodiscard]] constexpr size_type indexOf(const T& t) const { return indexOf(find(t)); }
[[nodiscard]] constexpr size_type size() const noexcept { return arraySize; }
2025-01-12 11:26:52 +01:00
[[nodiscard]] constexpr bool empty() const noexcept { return arraySize == 0; }
2024-06-09 12:20:04 +02:00
constexpr void reserve(size_type new_cap) {
if (new_cap > allocated) {
2022-04-13 13:01:35 +02:00
T* temp = allocateArray(new_cap);
2024-06-09 12:20:04 +02:00
if constexpr (std::is_trivially_copyable_v<T>) {
2023-12-11 13:04:58 +01:00
std::memcpy(temp, _data, sizeof(T) * arraySize);
2024-06-09 12:20:04 +02:00
} else {
2023-12-11 13:04:58 +01:00
std::uninitialized_move_n(begin(), arraySize, temp);
}
deallocateArray(_data, allocated);
2022-04-13 13:01:35 +02:00
_data = temp;
}
allocated = new_cap;
}
2024-06-09 12:20:04 +02:00
constexpr size_type capacity() const noexcept { return allocated; }
constexpr pointer data() const noexcept { return _data; }
constexpr reference front() const {
2022-01-12 14:40:26 +01:00
assert(arraySize > 0);
return _data[0];
}
2024-06-09 12:20:04 +02:00
constexpr reference back() const {
2022-01-12 14:40:26 +01:00
assert(arraySize > 0);
return _data[arraySize - 1];
}
2024-06-09 12:20:04 +02:00
constexpr void pop() { std::allocator_traits<allocator_type>::destroy(allocator, &_data[--arraySize]); }
constexpr reference operator[](size_type index) {
2022-01-12 14:40:26 +01:00
assert(index < arraySize);
return _data[index];
}
2024-06-09 12:20:04 +02:00
constexpr const_reference operator[](size_type index) const {
2022-01-12 14:40:26 +01:00
assert(index < arraySize);
return _data[index];
}
2024-06-09 12:20:04 +02:00
private:
size_type calculateGrowth(size_type newSize) const {
2022-01-12 14:40:26 +01:00
const size_type oldCapacity = capacity();
2024-06-09 12:20:04 +02:00
if (oldCapacity > SIZE_MAX - oldCapacity) {
2022-01-12 14:40:26 +01:00
return newSize; // geometric growth would overflow
2021-10-23 00:22:35 +02:00
}
2020-06-08 01:44:47 +02:00
2022-01-12 14:40:26 +01:00
const size_type geometric = oldCapacity + oldCapacity;
2024-06-09 12:20:04 +02:00
if (geometric < newSize) {
2022-01-12 14:40:26 +01:00
return newSize; // geometric growth would be insufficient
2021-10-23 00:22:35 +02:00
}
2020-06-08 01:44:47 +02:00
2022-01-12 14:40:26 +01:00
return geometric; // geometric growth is sufficient
}
2025-01-12 11:26:52 +01:00
[[nodiscard]] T* allocateArray(size_type size) {
2022-01-12 14:40:26 +01:00
T* result = allocator.allocate(size);
assert(result != nullptr);
return result;
}
2025-03-20 20:15:38 +01:00
void deallocateArray(T* ptr, size_type size) {
if (ptr == nullptr)
return;
allocator.deallocate(ptr, size);
}
2024-06-09 12:20:04 +02:00
template <typename Type> T& addInternal(Type&& t) noexcept {
if (arraySize == allocated) {
2022-01-12 14:40:26 +01:00
size_type newSize = arraySize + 1;
allocated = calculateGrowth(newSize);
2024-06-09 12:20:04 +02:00
T* tempArray = allocateArray(allocated);
for (size_type i = 0; i < arraySize; ++i) {
2022-01-12 14:40:26 +01:00
std::allocator_traits<allocator_type>::construct(allocator, &tempArray[i], std::forward<Type>(_data[i]));
}
2025-04-11 18:15:39 +02:00
if (_data != nullptr)
{
deallocateArray(_data, arraySize);
}
2022-01-12 14:40:26 +01:00
_data = tempArray;
}
2023-12-15 18:33:47 +01:00
std::allocator_traits<allocator_type>::construct(allocator, &_data[arraySize], std::forward<Type>(t));
return _data[arraySize++];
2022-01-12 14:40:26 +01:00
}
2024-06-09 12:20:04 +02:00
template <typename Type> void resizeInternal(size_type newSize, const Type& value) noexcept {
if (newSize <= allocated) {
2022-01-12 14:40:26 +01:00
// The array is already big enough
2024-06-09 12:20:04 +02:00
if (newSize < arraySize) {
2022-01-12 14:40:26 +01:00
// But since we are sizing down we destruct some of them
2023-12-11 14:45:37 +01:00
2024-06-09 12:20:04 +02:00
if constexpr (!std::is_trivially_destructible_v<T>) {
for (size_type i = newSize; i < arraySize; ++i) {
2023-12-11 14:45:37 +01:00
std::allocator_traits<allocator_type>::destroy(allocator, &_data[i]);
}
2021-10-23 00:22:35 +02:00
}
2024-06-09 12:20:04 +02:00
} else {
2022-01-12 14:40:26 +01:00
// Or construct the new elements by default
2024-06-09 12:20:04 +02:00
for (size_type i = arraySize; i < newSize; ++i) {
2023-01-21 18:43:21 +01:00
std::allocator_traits<allocator_type>::construct(allocator, &_data[i], value);
2021-10-23 00:22:35 +02:00
}
}
2022-01-12 14:40:26 +01:00
arraySize = newSize;
2024-06-09 12:20:04 +02:00
} else {
2025-05-16 13:04:43 +02:00
size_t oldSize = allocated;
2024-05-01 19:05:48 +02:00
allocated = calculateGrowth(newSize);
2022-01-12 14:40:26 +01:00
// The array is not big enough, so we make a new one
2024-06-09 12:20:04 +02:00
T* newData = allocateArray(allocated);
2022-01-12 14:40:26 +01:00
2024-06-09 12:20:04 +02:00
if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
2023-11-22 13:18:54 +01:00
std::memcpy(newData, _data, sizeof(T) * arraySize);
2024-05-01 19:05:48 +02:00
std::memset(&newData[arraySize], 0, sizeof(T) * (allocated - arraySize));
2024-06-09 12:20:04 +02:00
} else {
2023-11-22 13:18:54 +01:00
// And move the current elements into that one
2024-05-12 19:36:32 +02:00
std::uninitialized_move(begin(), end(), Iterator(newData));
2023-11-13 09:07:23 +01:00
// As well as default initialize the others
2024-06-09 12:20:04 +02:00
for (size_type i = arraySize; i < allocated; ++i) {
2023-11-13 09:07:23 +01:00
std::allocator_traits<allocator_type>::construct(allocator, &newData[i], value);
}
2022-01-12 14:40:26 +01:00
}
2025-05-16 13:04:43 +02:00
deallocateArray(_data, oldSize);
2022-01-12 14:40:26 +01:00
arraySize = newSize;
_data = newData;
2021-10-23 00:22:35 +02:00
}
2022-01-12 14:40:26 +01:00
}
size_type arraySize = 0;
size_type allocated = 0;
2024-06-09 12:20:04 +02:00
T* _data = nullptr;
2022-01-12 14:40:26 +01:00
allocator_type allocator;
};
2021-03-31 12:18:16 +02:00
2025-03-20 20:15:38 +01:00
template <class Type> constexpr bool operator==(const Array<Type>& lhs, const Array<Type>& rhs) {
2024-06-09 12:20:04 +02:00
if (lhs.size() != rhs.size()) {
2022-04-13 13:01:35 +02:00
return false;
}
2024-06-09 12:20:04 +02:00
for (auto it1 = lhs.begin(), it2 = rhs.begin(); it1 != lhs.end() && it2 != rhs.end(); ++it1, ++it2) {
if (*it1 != *it2) {
2022-04-13 13:01:35 +02:00
return false;
}
}
return true;
}
2025-03-20 20:15:38 +01:00
template <class Type> constexpr auto operator<=>(const Array<Type>& lhs, const Array<Type>& rhs) {
2024-01-16 19:24:49 +01:00
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
2022-04-13 13:01:35 +02:00
}
2024-06-09 12:20:04 +02:00
template <typename T, size_t N> struct StaticArray {
public:
template <typename X> class IteratorBase {
public:
2022-01-12 14:40:26 +01:00
using iterator_category = std::random_access_iterator_tag;
using value_type = X;
2021-10-23 00:22:35 +02:00
using difference_type = std::ptrdiff_t;
2022-01-12 14:40:26 +01:00
using reference = X&;
using pointer = X*;
2021-10-23 00:22:35 +02:00
2024-10-07 20:14:00 +02:00
constexpr IteratorBase(X* x = nullptr) : p(x) {}
constexpr reference operator*() const { return *p; }
constexpr pointer operator->() const { return p; }
constexpr bool operator!=(const IteratorBase& other) { return p != other.p; }
constexpr bool operator==(const IteratorBase& other) { return p == other.p; }
constexpr IteratorBase& operator++() {
2022-01-12 14:40:26 +01:00
p++;
return *this;
}
2024-10-07 20:14:00 +02:00
constexpr IteratorBase operator++(int) {
2022-01-12 14:40:26 +01:00
IteratorBase tmp(*this);
++*this;
return tmp;
}
2024-10-07 20:14:00 +02:00
constexpr IteratorBase& operator--() {
2022-01-12 14:40:26 +01:00
p--;
return *this;
}
2024-10-07 20:14:00 +02:00
constexpr IteratorBase operator--(int) {
2022-01-12 14:40:26 +01:00
IteratorBase tmp(*this);
--*this;
return tmp;
2021-10-23 00:22:35 +02:00
}
2022-01-12 14:40:26 +01:00
2024-06-09 12:20:04 +02:00
private:
X* p;
2021-10-23 00:22:35 +02:00
};
2022-01-12 14:40:26 +01:00
using value_type = T;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = IteratorBase<T>;
using const_iterator = IteratorBase<const T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
2024-10-07 20:14:00 +02:00
constexpr StaticArray() {
2022-01-12 14:40:26 +01:00
beginIt = iterator(_data);
endIt = iterator(_data + N);
}
2025-05-16 13:04:43 +02:00
2024-10-07 20:14:00 +02:00
constexpr StaticArray(T value) {
2024-06-09 12:20:04 +02:00
for (size_t i = 0; i < N; ++i) {
2022-01-12 14:40:26 +01:00
_data[i] = value;
}
beginIt = iterator(_data);
endIt = iterator(_data + N);
}
2025-05-16 13:04:43 +02:00
2024-10-07 20:14:00 +02:00
constexpr StaticArray(std::initializer_list<T> init) {
auto beg = init.begin();
2024-06-09 12:20:04 +02:00
for (size_t i = 0; i < N; ++i) {
_data[i] = *beg;
2024-06-09 12:20:04 +02:00
if (init.size() == N) {
2023-11-16 22:58:47 +01:00
beg++;
}
}
}
2024-10-07 20:14:00 +02:00
constexpr ~StaticArray() {}
2024-06-09 12:20:04 +02:00
2024-10-07 20:14:00 +02:00
constexpr size_type size() const { return N; }
constexpr pointer data() { return _data; }
constexpr const_pointer data() const { return _data; }
2024-06-09 12:20:04 +02:00
template <typename I> constexpr reference operator[](I index) noexcept { return operator[](static_cast<size_t>(index)); }
template <typename I> constexpr const_reference operator[](I index) const noexcept { return operator[](static_cast<size_t>(index)); }
constexpr reference operator[](size_type index) noexcept {
2022-01-12 14:40:26 +01:00
assert(index < N);
return _data[index];
}
2024-06-09 12:20:04 +02:00
constexpr const_reference operator[](size_type index) const noexcept {
2022-01-12 14:40:26 +01:00
assert(index < N);
return _data[index];
}
2024-10-07 20:14:00 +02:00
constexpr iterator begin() { return beginIt; }
constexpr iterator end() { return endIt; }
constexpr const_iterator begin() const { return beginIt; }
constexpr const_iterator end() const { return beginIt; }
2024-06-09 12:20:04 +02:00
private:
2024-10-07 20:14:00 +02:00
T _data[N] = {T()};
2022-01-12 14:40:26 +01:00
iterator beginIt;
iterator endIt;
};
2025-02-02 09:39:01 +01:00
} // namespace Seele