diff --git a/Runtime/rstl.hpp b/Runtime/rstl.hpp index f27c19a38..39cd243eb 100644 --- a/Runtime/rstl.hpp +++ b/Runtime/rstl.hpp @@ -1,11 +1,14 @@ #pragma once -#include #include -#include #include #include -#include "logvisor/logvisor.hpp" +#include +#include + +#ifndef NDEBUG +#include +#endif namespace rstl { @@ -226,6 +229,26 @@ protected: */ template class reserved_vector : public _reserved_vector_base { + using base = _reserved_vector_base; + +public: + using value_type = T; + + using pointer = value_type*; + using const_pointer = const value_type*; + + using reference = value_type&; + using const_reference = const value_type&; + + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + + using iterator = typename base::iterator; + using const_iterator = typename base::const_iterator; + using reverse_iterator = typename base::reverse_iterator; + using const_reverse_iterator = typename base::const_reverse_iterator; + +private: union alignas(T) storage_t { struct { } _dummy; @@ -239,102 +262,124 @@ class reserved_vector : public _reserved_vector_base { const T& _value(std::ptrdiff_t idx) const { return x4_data[idx]._value; } template static void - destroy(Tp& t, std::enable_if_t::value && !std::is_trivially_destructible::value>* = 0) { + destroy(Tp& t, std::enable_if_t && !std::is_trivially_destructible_v>* = nullptr) { t.Tp::~Tp(); } template static void - destroy(Tp& t, std::enable_if_t::value || std::is_trivially_destructible::value>* = 0) { + destroy(Tp& t, std::enable_if_t || std::is_trivially_destructible_v>* = nullptr) { } public: - using base = _reserved_vector_base; - using iterator = typename base::iterator; - using const_iterator = typename base::const_iterator; - using reverse_iterator = typename base::reverse_iterator; - using const_reverse_iterator = typename base::const_reverse_iterator; - reserved_vector() : x0_size(0) {} + reserved_vector() noexcept(std::is_nothrow_constructible_v) : x0_size(0) {} template - reserved_vector(const T(&l)[LN]) + reserved_vector(const T (&l)[LN]) noexcept(std::is_nothrow_copy_constructible_v) : x0_size(LN) { static_assert(LN <= N, "initializer array too large for reserved_vector"); - for (size_t i = 0; i < LN; ++i) + for (size_t i = 0; i < LN; ++i) { ::new (static_cast(std::addressof(_value(i)))) T(l[i]); + } } - reserved_vector(const reserved_vector& other) : x0_size(other.x0_size) { - for (size_t i = 0; i < x0_size; ++i) + reserved_vector(const reserved_vector& other) noexcept(std::is_nothrow_copy_constructible_v) + : x0_size(other.x0_size) { + for (size_t i = 0; i < x0_size; ++i) { ::new (static_cast(std::addressof(_value(i)))) T(other._value(i)); + } } - reserved_vector& operator=(const reserved_vector& other) { + reserved_vector& operator=(const reserved_vector& other) noexcept(std::is_nothrow_copy_assignable_v) { size_t i = 0; if (other.x0_size > x0_size) { - for (; i < x0_size; ++i) + for (; i < x0_size; ++i) { _value(i) = other._value(i); - for (; i < other.x0_size; ++i) + } + for (; i < other.x0_size; ++i) { ::new (static_cast(std::addressof(_value(i)))) T(other._value(i)); + } } else if (other.x0_size < x0_size) { - for (; i < other.x0_size; ++i) + for (; i < other.x0_size; ++i) { _value(i) = other._value(i); - if (std::is_destructible::value && !std::is_trivially_destructible::value) - for (; i < x0_size; ++i) + } + + if constexpr (std::is_destructible_v && !std::is_trivially_destructible_v) { + for (; i < x0_size; ++i) { destroy(_value(i)); + } + } } else { - for (; i < other.x0_size; ++i) + for (; i < other.x0_size; ++i) { _value(i) = other._value(i); + } } + x0_size = other.x0_size; return *this; } - reserved_vector(reserved_vector&& other) : x0_size(other.x0_size) { - for (size_t i = 0; i < x0_size; ++i) + reserved_vector(reserved_vector&& other) noexcept(std::is_nothrow_move_constructible_v) : x0_size(other.x0_size) { + for (size_t i = 0; i < x0_size; ++i) { ::new (static_cast(std::addressof(_value(i)))) T(std::forward(other._value(i))); + } } - reserved_vector& operator=(reserved_vector&& other) { + reserved_vector& operator=(reserved_vector&& other) noexcept( + std::is_nothrow_move_assignable_v&& std::is_nothrow_move_constructible_v) { size_t i = 0; if (other.x0_size > x0_size) { - for (; i < x0_size; ++i) + for (; i < x0_size; ++i) { _value(i) = std::forward(other._value(i)); - for (; i < other.x0_size; ++i) + } + for (; i < other.x0_size; ++i) { ::new (static_cast(std::addressof(_value(i)))) T(std::forward(other._value(i))); + } } else if (other.x0_size < x0_size) { - for (; i < other.x0_size; ++i) + for (; i < other.x0_size; ++i) { _value(i) = std::forward(other._value(i)); - if (std::is_destructible::value && !std::is_trivially_destructible::value) - for (; i < x0_size; ++i) + } + + if constexpr (std::is_destructible_v && !std::is_trivially_destructible_v) { + for (; i < x0_size; ++i) { destroy(_value(i)); + } + } } else { - for (; i < other.x0_size; ++i) + for (; i < other.x0_size; ++i) { _value(i) = std::forward(other._value(i)); + } } + x0_size = other.x0_size; return *this; } ~reserved_vector() { - if (std::is_destructible::value && !std::is_trivially_destructible::value) - for (size_t i = 0; i < x0_size; ++i) + if constexpr (std::is_destructible_v && !std::is_trivially_destructible_v) { + for (size_t i = 0; i < x0_size; ++i) { destroy(_value(i)); + } + } } void push_back(const T& d) { #ifndef NDEBUG - if (x0_size == N) + if (x0_size == N) { Log.report(logvisor::Fatal, fmt("push_back() called on full rstl::reserved_vector.")); + } #endif + ::new (static_cast(std::addressof(_value(x0_size)))) T(d); ++x0_size; } void push_back(T&& d) { #ifndef NDEBUG - if (x0_size == N) + if (x0_size == N) { Log.report(logvisor::Fatal, fmt("push_back() called on full rstl::reserved_vector.")); + } #endif + ::new (static_cast(std::addressof(_value(x0_size)))) T(std::forward(d)); ++x0_size; } @@ -342,34 +387,41 @@ public: template void emplace_back(_Args&&... args) { #ifndef NDEBUG - if (x0_size == N) + if (x0_size == N) { Log.report(logvisor::Fatal, fmt("emplace_back() called on full rstl::reserved_vector.")); + } #endif + ::new (static_cast(std::addressof(_value(x0_size)))) T(std::forward<_Args>(args)...); ++x0_size; } void pop_back() { #ifndef NDEBUG - if (x0_size == 0) + if (x0_size == 0) { Log.report(logvisor::Fatal, fmt("pop_back() called on empty rstl::reserved_vector.")); + } #endif + --x0_size; destroy(_value(x0_size)); } iterator insert(const_iterator pos, const T& value) { #ifndef NDEBUG - if (x0_size == N) + if (x0_size == N) { Log.report(logvisor::Fatal, fmt("insert() called on full rstl::reserved_vector.")); + } #endif + auto target_it = base::_const_cast_iterator(pos); if (pos == cend()) { ::new (static_cast(std::addressof(_value(x0_size)))) T(value); } else { ::new (static_cast(std::addressof(_value(x0_size)))) T(std::forward(_value(x0_size - 1))); - for (auto it = end() - 1; it != target_it; --it) + for (auto it = end() - 1; it != target_it; --it) { *it = std::forward(*(it - 1)); + } *target_it = value; } ++x0_size; @@ -386,8 +438,9 @@ public: ::new (static_cast(std::addressof(_value(x0_size)))) T(std::forward(value)); } else { ::new (static_cast(std::addressof(_value(x0_size)))) T(std::forward(_value(x0_size - 1))); - for (auto it = end() - 1; it != target_it; --it) + for (auto it = end() - 1; it != target_it; --it) { *it = std::forward(*(it - 1)); + } *target_it = std::forward(value); } ++x0_size; @@ -396,59 +449,75 @@ public: void resize(size_t size) { #ifndef NDEBUG - if (size > N) + if (size > N) { Log.report(logvisor::Fatal, fmt("resize() call overflows rstl::reserved_vector.")); + } #endif + if (size > x0_size) { - for (size_t i = x0_size; i < size; ++i) + for (size_t i = x0_size; i < size; ++i) { ::new (static_cast(std::addressof(_value(i)))) T(); + } x0_size = size; } else if (size < x0_size) { - if (std::is_destructible::value && !std::is_trivially_destructible::value) - for (size_t i = size; i < x0_size; ++i) + if constexpr (std::is_destructible_v && !std::is_trivially_destructible_v) { + for (size_t i = size; i < x0_size; ++i) { destroy(_value(i)); + } + } x0_size = size; } } void resize(size_t size, const T& value) { #ifndef NDEBUG - if (size > N) + if (size > N) { Log.report(logvisor::Fatal, fmt("resize() call overflows rstl::reserved_vector.")); + } #endif + if (size > x0_size) { - for (size_t i = x0_size; i < size; ++i) + for (size_t i = x0_size; i < size; ++i) { ::new (static_cast(std::addressof(_value(i)))) T(value); + } x0_size = size; } else if (size < x0_size) { - if (std::is_destructible::value && !std::is_trivially_destructible::value) - for (size_t i = size; i < x0_size; ++i) + if constexpr (std::is_destructible_v && !std::is_trivially_destructible_v) { + for (size_t i = size; i < x0_size; ++i) { destroy(_value(i)); + } + } x0_size = size; } } iterator erase(const_iterator pos) { #ifndef NDEBUG - if (x0_size == 0) + if (x0_size == 0) { Log.report(logvisor::Fatal, fmt("erase() called on empty rstl::reserved_vector.")); + } #endif - for (auto it = base::_const_cast_iterator(pos) + 1; it != end(); ++it) + + for (auto it = base::_const_cast_iterator(pos) + 1; it != end(); ++it) { *(it - 1) = std::forward(*it); + } --x0_size; destroy(_value(x0_size)); return base::_const_cast_iterator(pos); } void pop_front() { - if (x0_size != 0) + if (x0_size != 0) { erase(begin()); + } } void clear() { - if (std::is_destructible::value && !std::is_trivially_destructible::value) - for (auto it = begin(); it != end(); ++it) + if constexpr (std::is_destructible_v && !std::is_trivially_destructible_v) { + for (auto it = begin(); it != end(); ++it) { destroy(*it); + } + } x0_size = 0; } @@ -479,15 +548,17 @@ public: T& operator[](size_t idx) { #ifndef NDEBUG - if (idx >= x0_size) + if (idx >= x0_size) { Log.report(logvisor::Fatal, fmt("out of bounds access on reserved_vector.")); + } #endif return _value(idx); } const T& operator[](size_t idx) const { #ifndef NDEBUG - if (idx >= x0_size) + if (idx >= x0_size) { Log.report(logvisor::Fatal, fmt("out of bounds access on reserved_vector.")); + } #endif return _value(idx); }