mirror of https://github.com/AxioDL/metaforce.git
Merge pull request #100 from lioncash/noexcept
rstl: Make constructors/assignment operators of reserved_vector conditionally noexcept
This commit is contained in:
commit
1044b0f1ee
209
Runtime/rstl.hpp
209
Runtime/rstl.hpp
|
@ -1,11 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <type_traits>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "logvisor/logvisor.hpp"
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include <logvisor/logvisor.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace rstl {
|
namespace rstl {
|
||||||
|
|
||||||
|
@ -226,6 +229,26 @@ protected:
|
||||||
*/
|
*/
|
||||||
template <class T, size_t N>
|
template <class T, size_t N>
|
||||||
class reserved_vector : public _reserved_vector_base<T> {
|
class reserved_vector : public _reserved_vector_base<T> {
|
||||||
|
using base = _reserved_vector_base<T>;
|
||||||
|
|
||||||
|
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 {
|
union alignas(T) storage_t {
|
||||||
struct {
|
struct {
|
||||||
} _dummy;
|
} _dummy;
|
||||||
|
@ -239,102 +262,124 @@ class reserved_vector : public _reserved_vector_base<T> {
|
||||||
const T& _value(std::ptrdiff_t idx) const { return x4_data[idx]._value; }
|
const T& _value(std::ptrdiff_t idx) const { return x4_data[idx]._value; }
|
||||||
template <typename Tp>
|
template <typename Tp>
|
||||||
static void
|
static void
|
||||||
destroy(Tp& t, std::enable_if_t<std::is_destructible<Tp>::value && !std::is_trivially_destructible<Tp>::value>* = 0) {
|
destroy(Tp& t, std::enable_if_t<std::is_destructible_v<Tp> && !std::is_trivially_destructible_v<Tp>>* = nullptr) {
|
||||||
t.Tp::~Tp();
|
t.Tp::~Tp();
|
||||||
}
|
}
|
||||||
template <typename Tp>
|
template <typename Tp>
|
||||||
static void
|
static void
|
||||||
destroy(Tp& t, std::enable_if_t<!std::is_destructible<Tp>::value || std::is_trivially_destructible<Tp>::value>* = 0) {
|
destroy(Tp& t, std::enable_if_t<!std::is_destructible_v<Tp> || std::is_trivially_destructible_v<Tp>>* = nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using base = _reserved_vector_base<T>;
|
reserved_vector() noexcept(std::is_nothrow_constructible_v<T>) : x0_size(0) {}
|
||||||
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 <size_t LN>
|
template <size_t LN>
|
||||||
reserved_vector(const T(&l)[LN])
|
reserved_vector(const T (&l)[LN]) noexcept(std::is_nothrow_copy_constructible_v<T>)
|
||||||
: x0_size(LN) {
|
: x0_size(LN) {
|
||||||
static_assert(LN <= N, "initializer array too large for reserved_vector");
|
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<void*>(std::addressof(_value(i)))) T(l[i]);
|
::new (static_cast<void*>(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)
|
|
||||||
::new (static_cast<void*>(std::addressof(_value(i)))) T(other._value(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reserved_vector& operator=(const reserved_vector& other) {
|
reserved_vector(const reserved_vector& other) noexcept(std::is_nothrow_copy_constructible_v<T>)
|
||||||
|
: x0_size(other.x0_size) {
|
||||||
|
for (size_t i = 0; i < x0_size; ++i) {
|
||||||
|
::new (static_cast<void*>(std::addressof(_value(i)))) T(other._value(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reserved_vector& operator=(const reserved_vector& other) noexcept(std::is_nothrow_copy_assignable_v<T>) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
if (other.x0_size > x0_size) {
|
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)
|
|
||||||
::new (static_cast<void*>(std::addressof(_value(i)))) T(other._value(i));
|
|
||||||
} else if (other.x0_size < x0_size) {
|
|
||||||
for (; i < other.x0_size; ++i)
|
|
||||||
_value(i) = other._value(i);
|
|
||||||
if (std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value)
|
|
||||||
for (; i < x0_size; ++i)
|
|
||||||
destroy(_value(i));
|
|
||||||
} else {
|
|
||||||
for (; i < other.x0_size; ++i)
|
|
||||||
_value(i) = other._value(i);
|
_value(i) = other._value(i);
|
||||||
}
|
}
|
||||||
|
for (; i < other.x0_size; ++i) {
|
||||||
|
::new (static_cast<void*>(std::addressof(_value(i)))) T(other._value(i));
|
||||||
|
}
|
||||||
|
} else if (other.x0_size < x0_size) {
|
||||||
|
for (; i < other.x0_size; ++i) {
|
||||||
|
_value(i) = other._value(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_destructible_v<T> && !std::is_trivially_destructible_v<T>) {
|
||||||
|
for (; i < x0_size; ++i) {
|
||||||
|
destroy(_value(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (; i < other.x0_size; ++i) {
|
||||||
|
_value(i) = other._value(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
x0_size = other.x0_size;
|
x0_size = other.x0_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
reserved_vector(reserved_vector&& other) : x0_size(other.x0_size) {
|
reserved_vector(reserved_vector&& other) noexcept(std::is_nothrow_move_constructible_v<T>) : 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<void*>(std::addressof(_value(i)))) T(std::forward<T>(other._value(i)));
|
::new (static_cast<void*>(std::addressof(_value(i)))) T(std::forward<T>(other._value(i)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reserved_vector& operator=(reserved_vector&& other) {
|
reserved_vector& operator=(reserved_vector&& other) noexcept(
|
||||||
|
std::is_nothrow_move_assignable_v<T>&& std::is_nothrow_move_constructible_v<T>) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
if (other.x0_size > x0_size) {
|
if (other.x0_size > x0_size) {
|
||||||
for (; i < x0_size; ++i)
|
for (; i < x0_size; ++i) {
|
||||||
_value(i) = std::forward<T>(other._value(i));
|
|
||||||
for (; i < other.x0_size; ++i)
|
|
||||||
::new (static_cast<void*>(std::addressof(_value(i)))) T(std::forward<T>(other._value(i)));
|
|
||||||
} else if (other.x0_size < x0_size) {
|
|
||||||
for (; i < other.x0_size; ++i)
|
|
||||||
_value(i) = std::forward<T>(other._value(i));
|
|
||||||
if (std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value)
|
|
||||||
for (; i < x0_size; ++i)
|
|
||||||
destroy(_value(i));
|
|
||||||
} else {
|
|
||||||
for (; i < other.x0_size; ++i)
|
|
||||||
_value(i) = std::forward<T>(other._value(i));
|
_value(i) = std::forward<T>(other._value(i));
|
||||||
}
|
}
|
||||||
|
for (; i < other.x0_size; ++i) {
|
||||||
|
::new (static_cast<void*>(std::addressof(_value(i)))) T(std::forward<T>(other._value(i)));
|
||||||
|
}
|
||||||
|
} else if (other.x0_size < x0_size) {
|
||||||
|
for (; i < other.x0_size; ++i) {
|
||||||
|
_value(i) = std::forward<T>(other._value(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_destructible_v<T> && !std::is_trivially_destructible_v<T>) {
|
||||||
|
for (; i < x0_size; ++i) {
|
||||||
|
destroy(_value(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (; i < other.x0_size; ++i) {
|
||||||
|
_value(i) = std::forward<T>(other._value(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
x0_size = other.x0_size;
|
x0_size = other.x0_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~reserved_vector() {
|
~reserved_vector() {
|
||||||
if (std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value)
|
if constexpr (std::is_destructible_v<T> && !std::is_trivially_destructible_v<T>) {
|
||||||
for (size_t i = 0; i < x0_size; ++i)
|
for (size_t i = 0; i < x0_size; ++i) {
|
||||||
destroy(_value(i));
|
destroy(_value(i));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void push_back(const T& d) {
|
void push_back(const T& d) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (x0_size == N)
|
if (x0_size == N) {
|
||||||
Log.report(logvisor::Fatal, fmt("push_back() called on full rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("push_back() called on full rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(d);
|
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(d);
|
||||||
++x0_size;
|
++x0_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(T&& d) {
|
void push_back(T&& d) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (x0_size == N)
|
if (x0_size == N) {
|
||||||
Log.report(logvisor::Fatal, fmt("push_back() called on full rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("push_back() called on full rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(d));
|
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(d));
|
||||||
++x0_size;
|
++x0_size;
|
||||||
}
|
}
|
||||||
|
@ -342,34 +387,41 @@ public:
|
||||||
template <class... _Args>
|
template <class... _Args>
|
||||||
void emplace_back(_Args&&... args) {
|
void emplace_back(_Args&&... args) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (x0_size == N)
|
if (x0_size == N) {
|
||||||
Log.report(logvisor::Fatal, fmt("emplace_back() called on full rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("emplace_back() called on full rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<_Args>(args)...);
|
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<_Args>(args)...);
|
||||||
++x0_size;
|
++x0_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_back() {
|
void pop_back() {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (x0_size == 0)
|
if (x0_size == 0) {
|
||||||
Log.report(logvisor::Fatal, fmt("pop_back() called on empty rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("pop_back() called on empty rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
--x0_size;
|
--x0_size;
|
||||||
destroy(_value(x0_size));
|
destroy(_value(x0_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator insert(const_iterator pos, const T& value) {
|
iterator insert(const_iterator pos, const T& value) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (x0_size == N)
|
if (x0_size == N) {
|
||||||
Log.report(logvisor::Fatal, fmt("insert() called on full rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("insert() called on full rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto target_it = base::_const_cast_iterator(pos);
|
auto target_it = base::_const_cast_iterator(pos);
|
||||||
if (pos == cend()) {
|
if (pos == cend()) {
|
||||||
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(value);
|
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(value);
|
||||||
} else {
|
} else {
|
||||||
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(_value(x0_size - 1)));
|
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(_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<T>(*(it - 1));
|
*it = std::forward<T>(*(it - 1));
|
||||||
|
}
|
||||||
*target_it = value;
|
*target_it = value;
|
||||||
}
|
}
|
||||||
++x0_size;
|
++x0_size;
|
||||||
|
@ -386,8 +438,9 @@ public:
|
||||||
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(value));
|
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(value));
|
||||||
} else {
|
} else {
|
||||||
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(_value(x0_size - 1)));
|
::new (static_cast<void*>(std::addressof(_value(x0_size)))) T(std::forward<T>(_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<T>(*(it - 1));
|
*it = std::forward<T>(*(it - 1));
|
||||||
|
}
|
||||||
*target_it = std::forward<T>(value);
|
*target_it = std::forward<T>(value);
|
||||||
}
|
}
|
||||||
++x0_size;
|
++x0_size;
|
||||||
|
@ -396,59 +449,75 @@ public:
|
||||||
|
|
||||||
void resize(size_t size) {
|
void resize(size_t size) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (size > N)
|
if (size > N) {
|
||||||
Log.report(logvisor::Fatal, fmt("resize() call overflows rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("resize() call overflows rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (size > x0_size) {
|
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<void*>(std::addressof(_value(i)))) T();
|
::new (static_cast<void*>(std::addressof(_value(i)))) T();
|
||||||
|
}
|
||||||
x0_size = size;
|
x0_size = size;
|
||||||
} else if (size < x0_size) {
|
} else if (size < x0_size) {
|
||||||
if (std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value)
|
if constexpr (std::is_destructible_v<T> && !std::is_trivially_destructible_v<T>) {
|
||||||
for (size_t i = size; i < x0_size; ++i)
|
for (size_t i = size; i < x0_size; ++i) {
|
||||||
destroy(_value(i));
|
destroy(_value(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
x0_size = size;
|
x0_size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(size_t size, const T& value) {
|
void resize(size_t size, const T& value) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (size > N)
|
if (size > N) {
|
||||||
Log.report(logvisor::Fatal, fmt("resize() call overflows rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("resize() call overflows rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (size > x0_size) {
|
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<void*>(std::addressof(_value(i)))) T(value);
|
::new (static_cast<void*>(std::addressof(_value(i)))) T(value);
|
||||||
|
}
|
||||||
x0_size = size;
|
x0_size = size;
|
||||||
} else if (size < x0_size) {
|
} else if (size < x0_size) {
|
||||||
if (std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value)
|
if constexpr (std::is_destructible_v<T> && !std::is_trivially_destructible_v<T>) {
|
||||||
for (size_t i = size; i < x0_size; ++i)
|
for (size_t i = size; i < x0_size; ++i) {
|
||||||
destroy(_value(i));
|
destroy(_value(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
x0_size = size;
|
x0_size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator erase(const_iterator pos) {
|
iterator erase(const_iterator pos) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (x0_size == 0)
|
if (x0_size == 0) {
|
||||||
Log.report(logvisor::Fatal, fmt("erase() called on empty rstl::reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("erase() called on empty rstl::reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#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<T>(*it);
|
*(it - 1) = std::forward<T>(*it);
|
||||||
|
}
|
||||||
--x0_size;
|
--x0_size;
|
||||||
destroy(_value(x0_size));
|
destroy(_value(x0_size));
|
||||||
return base::_const_cast_iterator(pos);
|
return base::_const_cast_iterator(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_front() {
|
void pop_front() {
|
||||||
if (x0_size != 0)
|
if (x0_size != 0) {
|
||||||
erase(begin());
|
erase(begin());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
if (std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value)
|
if constexpr (std::is_destructible_v<T> && !std::is_trivially_destructible_v<T>) {
|
||||||
for (auto it = begin(); it != end(); ++it)
|
for (auto it = begin(); it != end(); ++it) {
|
||||||
destroy(*it);
|
destroy(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
x0_size = 0;
|
x0_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,15 +548,17 @@ public:
|
||||||
|
|
||||||
T& operator[](size_t idx) {
|
T& operator[](size_t idx) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (idx >= x0_size)
|
if (idx >= x0_size) {
|
||||||
Log.report(logvisor::Fatal, fmt("out of bounds access on reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("out of bounds access on reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return _value(idx);
|
return _value(idx);
|
||||||
}
|
}
|
||||||
const T& operator[](size_t idx) const {
|
const T& operator[](size_t idx) const {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (idx >= x0_size)
|
if (idx >= x0_size) {
|
||||||
Log.report(logvisor::Fatal, fmt("out of bounds access on reserved_vector."));
|
Log.report(logvisor::Fatal, fmt("out of bounds access on reserved_vector."));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return _value(idx);
|
return _value(idx);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue