/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include #include #include #include #include #include #include #include namespace OpenVulkano { /** * Heap allocated array. For all these times you need a fixed size data structure, but don't know the size at compile time. * @tparam T The type to be used */ template class Array { size_t size; T* data; void ClearData() { if constexpr (!std::is_trivially_destructible_v) { // Call the destructor on all the members in reverse order for (size_t i = size; i > 0;) { data[--i].~T(); } } } static T* MakeBuffer(size_t count) { return static_cast(::operator new(sizeof(T) * count)); } public: using iterator = T*; using const_iterator = const T*; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; Array() noexcept: size(0), data(nullptr) {} explicit Array(size_t size) : size(size), data(MakeBuffer(size)) { for(size_t i = 0; i < size; i++) { new (&data[i]) T(); } } Array(const std::initializer_list& list) : size(list.size()), data(MakeBuffer(list.size())) { int i = 0; for(const T& e : list) { new (&data[i++]) T(e); } } Array(const Array& other) : size(other.Size()), data(MakeBuffer(other.Size())) { for(size_t i = 0; i < size; i++) { new (&data[i]) T(other[i]); } } Array(Array&& other) noexcept: size(other.size), data(other.data) { other.data = nullptr; other.size = 0; } explicit Array(const std::vector& vector) : size(vector.size()), data(MakeBuffer(size)) { int i = 0; for (const auto& e : vector) { new (&data[i++]) T(e); } } Array(size_t size, const T& defaultValue) : size(size), data(MakeBuffer(size)) { Fill(defaultValue); } template Array(size_t size, ARGS... args) : size(size), data(MakeBuffer(size)) { for(size_t i = 0; i < size; i++) { new (&data[i]) T(args...); } } template::value_type, void> && !std::is_convertible_v, int> = 0> Array(InputIt first, InputIt last) : size(std::distance(first, last)), data(MakeBuffer(size)) { size_t i = 0; while (first != last) { new (&data[i++]) T(*first); ++first; } } ~Array() noexcept { ClearData(); ::operator delete(data); } Array& operator=(const Array& rhs) { if (this == &rhs) return *this; Resize(rhs.Size()); for(size_t i = 0; i < size; i++) { new (&data[i]) T(rhs[i]); } return *this; } Array& operator=(const std::initializer_list& list) { Resize(list.size()); int i = 0; for(const T& e : list) { new (&data[i++]) T(e); } return *this; } Array& operator=(Array&& rhs) noexcept { if (this != &rhs) { Array(std::move(rhs)).Swap(*this); } return *this; } T& operator[](size_t n) { return data[n]; } const T& operator[](size_t n) const { return data[n]; } operator bool() const noexcept { return data; } operator std::span() const noexcept { return { data, size }; } iterator Begin() noexcept { return data; } const_iterator Begin() const noexcept { return data; } iterator begin() noexcept { return data; } const_iterator begin() const noexcept { return data; } iterator End() noexcept { return Begin() + Size(); } const_iterator End() const noexcept { return Begin() + Size(); } iterator end() noexcept { return Begin() + Size(); } const_iterator end() const noexcept { return Begin() + Size(); } reverse_iterator ReverseBegin() noexcept { return reverse_iterator(End()); } const_reverse_iterator ReverseBegin() const noexcept { return const_reverse_iterator(End()); } reverse_iterator ReverseEnd() noexcept { return reverse_iterator(Begin()); } const_reverse_iterator ReverseEnd() const noexcept { return const_reverse_iterator(Begin()); } const_iterator ConstBegin() const noexcept { return Begin(); } const_iterator ConstEnd() const noexcept { return End(); } const_reverse_iterator ConstReverseBegin() const noexcept { return ReverseBegin(); } const_reverse_iterator ConstReverseEnd() const noexcept { return ReverseEnd(); } [[nodiscard]] size_t Size() const noexcept { return size; } [[nodiscard]] size_t MaxSize() const noexcept { return size; } [[nodiscard]] bool Empty() const noexcept { return Size() == 0; } T& At(size_t n) { if (n >= Size()) throw std::out_of_range("Index " + std::to_string(n) + " is out of bounds."); return data[n]; } const T& At(size_t n) const { return const_cast(this)->At(n); } T& Front() noexcept { return *Begin(); } const T& Front() const noexcept { return *ConstBegin(); } T& Back() noexcept { return *(End() - 1); } const T& Back() const noexcept { return *(ConstEnd() - 1); } T* Data() noexcept { return data; } const T* Data() const noexcept { return data; } void Fill(const T& value) noexcept(noexcept(std::fill(Begin(), End(), value))) { std::fill(Begin(), End(), value); } void Swap(Array& other) noexcept { std::swap(data, other.data); std::swap(size, other.size); } private: void Resize(size_t newSize) { ClearData(); if (Size() != newSize) { ::operator delete(data); data = MakeBuffer(newSize); size = newSize; } } }; template inline bool operator==(const Array& lhs, const Array& rhs) { return lhs.Size() == rhs.Size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); } template inline bool operator!=(const Array& lhs, const Array& rhs) { return !(lhs == rhs); } template inline bool operator<(const Array& lhs, const Array& rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template inline bool operator>(const Array& lhs, const Array& rhs) { return rhs < lhs; } template inline bool operator>=(const Array& lhs, const Array& rhs) { return !(lhs < rhs); } template inline bool operator<=(const Array& lhs, const Array& rhs) { return !(rhs < lhs); } template Array(InputIt first, InputIt last) -> Array::value_type>; }