From cbcba6f184c8db39a658b205f4ecbd61e3416db6 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 4 Oct 2019 00:08:43 -0400 Subject: [PATCH 1/4] rstl: Organize headers We can also make includes a little nicer for the compiler by only including logvisor headers when performing debug builds. --- Runtime/rstl.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Runtime/rstl.hpp b/Runtime/rstl.hpp index f27c19a38..3fbfcd2ee 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 { From 00a4df5aa67f049f32bb0b9e0878d121d3edd804 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 4 Oct 2019 00:14:10 -0400 Subject: [PATCH 2/4] rstl: Make use of variable templates where applicable While we're at it, we can use if constexpr on some conditional checks. --- Runtime/rstl.hpp | 133 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 92 insertions(+), 41 deletions(-) diff --git a/Runtime/rstl.hpp b/Runtime/rstl.hpp index 3fbfcd2ee..d6a4bb136 100644 --- a/Runtime/rstl.hpp +++ b/Runtime/rstl.hpp @@ -242,12 +242,12 @@ 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: @@ -262,82 +262,107 @@ public: reserved_vector(const T(&l)[LN]) : 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) + 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) { 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) + 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) { 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; } @@ -345,34 +370,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; @@ -389,8 +421,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; @@ -399,59 +432,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; } @@ -482,15 +531,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); } From b2d9283b3c97ca364f384430e24c251710bde619 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 4 Oct 2019 00:28:13 -0400 Subject: [PATCH 3/4] rstl: Provide full set of type aliases in reserved_vector Allows for better integration with standard library facilities and templates, now that types can be queried. --- Runtime/rstl.hpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Runtime/rstl.hpp b/Runtime/rstl.hpp index d6a4bb136..1817ddc45 100644 --- a/Runtime/rstl.hpp +++ b/Runtime/rstl.hpp @@ -229,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; @@ -251,11 +271,6 @@ class reserved_vector : public _reserved_vector_base { } 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) {} template From d4b9124b9fc4a154f11578c5e6ba68415c8ba0c9 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 4 Oct 2019 00:53:12 -0400 Subject: [PATCH 4/4] rstl: Allow move constructors and assignment operators to be conditionally noexcept Makes the constructors and assignment operators for reserved_vector noexcept, allowing them to play nicely with standard facilities and avoid needing to copy construct where avoidable. --- Runtime/rstl.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Runtime/rstl.hpp b/Runtime/rstl.hpp index 1817ddc45..39cd243eb 100644 --- a/Runtime/rstl.hpp +++ b/Runtime/rstl.hpp @@ -271,10 +271,10 @@ private: } public: - 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) { @@ -282,13 +282,14 @@ public: } } - reserved_vector(const reserved_vector& other) : x0_size(other.x0_size) { + 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) { @@ -317,13 +318,14 @@ public: return *this; } - reserved_vector(reserved_vector&& other) : x0_size(other.x0_size) { + 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) {