diff --git a/include/outcome/detail/revision.hpp b/include/outcome/detail/revision.hpp index 1664273d..c6738b9e 100644 --- a/include/outcome/detail/revision.hpp +++ b/include/outcome/detail/revision.hpp @@ -22,6 +22,6 @@ Distributed under the Boost Software License, Version 1.0. */ // Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time -#define OUTCOME_PREVIOUS_COMMIT_REF 147ec1e8673c34cb7cf431dfdbf211d8072d7656 -#define OUTCOME_PREVIOUS_COMMIT_DATE "2022-03-17 19:38:05 +00:00" -#define OUTCOME_PREVIOUS_COMMIT_UNIQUE 147ec1e8 +#define OUTCOME_PREVIOUS_COMMIT_REF 5e36246352c1c412813583e446eea0d1a19d08cc +#define OUTCOME_PREVIOUS_COMMIT_DATE "2022-04-05 06:23:15 +00:00" +#define OUTCOME_PREVIOUS_COMMIT_UNIQUE 5e362463 diff --git a/include/outcome/detail/value_storage.hpp b/include/outcome/detail/value_storage.hpp index 9f9b11c1..4e12c6e4 100644 --- a/include/outcome/detail/value_storage.hpp +++ b/include/outcome/detail/value_storage.hpp @@ -41,19 +41,32 @@ namespace detail // Prefer to use move or copy construction template struct move_assign_to_empty { - move_assign_to_empty(T *dest, T &&o) noexcept(std::is_nothrow_move_constructible::value) { new(dest) T(static_cast(o)); } + move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible::value) { new(dest) T(static_cast(*o)); } }; template struct move_assign_to_empty { - move_assign_to_empty(T *dest, T &&o) noexcept(std::is_nothrow_move_constructible::value) { new(dest) T(static_cast(o)); } + move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible::value) { new(dest) T(static_cast(*o)); } }; // But fall back on default construction and move assign if necessary template struct move_assign_to_empty { - move_assign_to_empty(T *dest, T &&o) noexcept(std::is_nothrow_default_constructible::value &&std::is_nothrow_move_assignable::value) + move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_default_constructible::value &&std::is_nothrow_move_assignable::value) { new(dest) T; - *dest = static_cast(o); + *dest = static_cast(*o); + } + }; + // Void does nothing + template <> struct move_assign_to_empty + { + move_assign_to_empty(void *, void *) noexcept + { /* nothing to assign */ + } + }; + template <> struct move_assign_to_empty + { + move_assign_to_empty(const void *, const void *) noexcept + { /* nothing to assign */ } }; // Helpers for copy assigning to empty storage @@ -63,19 +76,32 @@ namespace detail // Prefer to use copy construction template struct copy_assign_to_empty { - copy_assign_to_empty(T *dest, const T &o) noexcept(std::is_nothrow_copy_constructible::value) { new(dest) T(o); } + copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible::value) { new(dest) T(*o); } }; template struct copy_assign_to_empty { - copy_assign_to_empty(T *dest, const T &o) noexcept(std::is_nothrow_copy_constructible::value) { new(dest) T(o); } + copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible::value) { new(dest) T(*o); } }; // But fall back on default construction and copy assign if necessary template struct copy_assign_to_empty { - copy_assign_to_empty(T *dest, const T &o) noexcept(std::is_nothrow_default_constructible::value &&std::is_nothrow_copy_assignable::value) + copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_default_constructible::value &&std::is_nothrow_copy_assignable::value) { new(dest) T; - *dest = o; + *dest = *o; + } + }; + // Void does nothing + template <> struct copy_assign_to_empty + { + copy_assign_to_empty(void *, void *) noexcept + { /* nothing to assign */ + } + }; + template <> struct copy_assign_to_empty + { + copy_assign_to_empty(const void *, const void *) noexcept + { /* nothing to assign */ } }; @@ -1443,8 +1469,9 @@ namespace detail value_storage_nontrivial_move_assignment & operator=(value_storage_nontrivial_move_assignment &&o) noexcept( std::is_nothrow_move_assignable::value &&std::is_nothrow_move_assignable::value &&noexcept(move_assign_to_empty( - static_cast(nullptr), std::declval())) &&noexcept(move_assign_to_empty(static_cast(nullptr), - std::declval()))) // NOLINT + static_cast(nullptr), + static_cast(nullptr))) &&noexcept(move_assign_to_empty(static_cast(nullptr), + static_cast(nullptr)))) // NOLINT { using _value_type_ = typename Base::_value_type_; using _error_type_ = typename Base::_error_type_; @@ -1480,7 +1507,7 @@ namespace detail } if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value()) { - move_assign_to_empty<_value_type_>(&this->_value, static_cast<_value_type_ &&>(o._value)); + move_assign_to_empty<_value_type_>(&this->_value, &o._value); this->_status = o._status; o._status.set_have_moved_from(true); return *this; @@ -1497,7 +1524,7 @@ namespace detail } if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error()) { - move_assign_to_empty<_error_type_>(&this->_error, static_cast<_error_type_ &&>(o._error)); + move_assign_to_empty<_error_type_>(&this->_error, &o._error); this->_status = o._status; o._status.set_have_moved_from(true); return *this; @@ -1508,7 +1535,7 @@ namespace detail { this->_value.~_value_type_(); // NOLINT } - move_assign_to_empty<_error_type_>(&this->_error, static_cast<_error_type_ &&>(o._error)); + move_assign_to_empty<_error_type_>(&this->_error, &o._error); this->_status = o._status; o._status.set_have_moved_from(true); return *this; @@ -1519,7 +1546,7 @@ namespace detail { this->_error.~_error_type_(); // NOLINT } - move_assign_to_empty<_value_type_>(&this->_value, static_cast<_value_type_ &&>(o._value)); + move_assign_to_empty<_value_type_>(&this->_value, &o._value); this->_status = o._status; o._status.set_have_moved_from(true); return *this; @@ -1544,8 +1571,8 @@ namespace detail value_storage_nontrivial_copy_assignment & operator=(const value_storage_nontrivial_copy_assignment &o) noexcept( std::is_nothrow_copy_assignable::value &&std::is_nothrow_copy_assignable::value &&noexcept(copy_assign_to_empty( - static_cast(nullptr), std::declval())) &&noexcept(copy_assign_to_empty(static_cast(nullptr), - std::declval()))) + static_cast(nullptr), static_cast(nullptr))) &&noexcept(copy_assign_to_empty(static_cast(nullptr), + static_cast(nullptr)))) { using _value_type_ = typename Base::_value_type_; using _error_type_ = typename Base::_error_type_; @@ -1577,7 +1604,7 @@ namespace detail } if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value()) { - copy_assign_to_empty<_value_type_>(&this->_value, o._value); + copy_assign_to_empty<_value_type_>(&this->_value, &o._value); this->_status = o._status; return *this; } @@ -1592,7 +1619,7 @@ namespace detail } if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error()) { - copy_assign_to_empty<_error_type_>(&this->_error, o._error); + copy_assign_to_empty<_error_type_>(&this->_error, &o._error); this->_status = o._status; return *this; } @@ -1602,7 +1629,7 @@ namespace detail { this->_value.~_value_type_(); // NOLINT } - copy_assign_to_empty<_error_type_>(&this->_error, o._error); + copy_assign_to_empty<_error_type_>(&this->_error, &o._error); this->_status = o._status; return *this; } @@ -1612,7 +1639,7 @@ namespace detail { this->_error.~_error_type_(); // NOLINT } - copy_assign_to_empty<_value_type_>(&this->_value, o._value); + copy_assign_to_empty<_value_type_>(&this->_value, &o._value); this->_status = o._status; return *this; }