File indexing completed on 2025-10-22 08:23:35
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #ifndef BOOST_OUTCOME_VALUE_STORAGE_HPP
0032 #define BOOST_OUTCOME_VALUE_STORAGE_HPP
0033
0034 #include "../config.hpp"
0035
0036 BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN
0037
0038 namespace detail
0039 {
0040
0041 template <class T, bool isCopyOrMoveConstructible = std::is_copy_constructible<T>::value || std::is_move_constructible<T>::value,
0042 bool isDefaultConstructibleAndCopyOrMoveAssignable =
0043 std::is_default_constructible<T>::value && (std::is_copy_assignable<T>::value || std::is_move_assignable<T>::value)>
0044 struct move_assign_to_empty;
0045
0046 template <class T> struct move_assign_to_empty<T, true, false>
0047 {
0048 move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
0049 };
0050 template <class T> struct move_assign_to_empty<T, true, true>
0051 {
0052 move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
0053 };
0054
0055 template <class T> struct move_assign_to_empty<T, false, true>
0056 {
0057 move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_default_constructible<T>::value && std::is_nothrow_move_assignable<T>::value)
0058 {
0059 new(dest) T;
0060 *dest = static_cast<T &&>(*o);
0061 }
0062 };
0063
0064 template <> struct move_assign_to_empty<void, false, false>
0065 {
0066 move_assign_to_empty(void *, void *) noexcept { }
0067 };
0068 template <> struct move_assign_to_empty<const void, false, false>
0069 {
0070 move_assign_to_empty(const void *, const void *) noexcept { }
0071 };
0072
0073 template <class T, bool isCopyConstructible = std::is_copy_constructible<T>::value,
0074 bool isDefaultConstructibleAndCopyAssignable = std::is_default_constructible<T>::value && std::is_copy_assignable<T>::value>
0075 struct copy_assign_to_empty;
0076
0077 template <class T> struct copy_assign_to_empty<T, true, false>
0078 {
0079 copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
0080 };
0081 template <class T> struct copy_assign_to_empty<T, true, true>
0082 {
0083 copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
0084 };
0085
0086 template <class T> struct copy_assign_to_empty<T, false, true>
0087 {
0088 copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_default_constructible<T>::value && std::is_nothrow_copy_assignable<T>::value)
0089 {
0090 new(dest) T;
0091 *dest = *o;
0092 }
0093 };
0094
0095 template <> struct copy_assign_to_empty<void, false, false>
0096 {
0097 copy_assign_to_empty(void *, void *) noexcept { }
0098 };
0099 template <> struct copy_assign_to_empty<const void, false, false>
0100 {
0101 copy_assign_to_empty(const void *, const void *) noexcept { }
0102 };
0103
0104 template <class T, bool nothrow> struct strong_swap_impl
0105 {
0106 constexpr strong_swap_impl(bool &allgood, T &a, T &b)
0107 {
0108 allgood = true;
0109 using std::swap;
0110 swap(a, b);
0111 }
0112 };
0113 template <class T, bool nothrow> struct strong_placement_impl
0114 {
0115 template <class F> constexpr strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
0116 {
0117 allgood = true;
0118 new(a) T(static_cast<T &&>(*b));
0119 b->~T();
0120 f();
0121 }
0122 };
0123 #ifndef BOOST_NO_EXCEPTIONS
0124 template <class T> struct strong_swap_impl<T, false>
0125 {
0126 strong_swap_impl(bool &allgood, T &a, T &b)
0127 {
0128 allgood = true;
0129 T v(static_cast<T &&>(a));
0130 try
0131 {
0132 a = static_cast<T &&>(b);
0133 }
0134 catch(...)
0135 {
0136
0137 try
0138 {
0139 a = static_cast<T &&>(v);
0140
0141 }
0142 catch(...)
0143 {
0144
0145 allgood = false;
0146
0147 }
0148 throw;
0149 }
0150
0151 try
0152 {
0153 b = static_cast<T &&>(v);
0154 }
0155 catch(...)
0156 {
0157
0158 try
0159 {
0160 b = static_cast<T &&>(a);
0161 a = static_cast<T &&>(v);
0162
0163 }
0164 catch(...)
0165 {
0166
0167 allgood = false;
0168
0169 }
0170 throw;
0171 }
0172 }
0173 };
0174 template <class T> struct strong_placement_impl<T, false>
0175 {
0176 template <class F> strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
0177 {
0178 new(a) T(static_cast<T &&>(*b));
0179 try
0180 {
0181 b->~T();
0182 f();
0183 }
0184 catch(...)
0185 {
0186
0187 if(allgood)
0188 {
0189 try
0190 {
0191 new(b) T(static_cast<T &&>(*a));
0192
0193 }
0194 catch(...)
0195 {
0196
0197 allgood = false;
0198
0199 }
0200 throw;
0201 }
0202 }
0203 }
0204 };
0205 #endif
0206 }
0207
0208
0209
0210 BOOST_OUTCOME_TEMPLATE(class T)
0211 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
0212 constexpr inline void strong_swap(bool &allgood, T &a, T &b) noexcept(detail::is_nothrow_swappable<T>::value)
0213 {
0214 detail::strong_swap_impl<T, detail::is_nothrow_swappable<T>::value>(allgood, a, b);
0215 }
0216
0217
0218 BOOST_OUTCOME_TEMPLATE(class T, class F)
0219 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
0220 constexpr inline void strong_placement(bool &allgood, T *a, T *b, F &&f) noexcept(std::is_nothrow_move_constructible<T>::value)
0221 {
0222 detail::strong_placement_impl<T, std::is_nothrow_move_constructible<T>::value>(allgood, a, b, static_cast<F &&>(f));
0223 }
0224
0225 namespace detail
0226 {
0227 template <class T>
0228 constexpr
0229 #ifdef _MSC_VER
0230 __declspec(noreturn)
0231 #elif defined(__GNUC__) || defined(__clang__)
0232 __attribute__((noreturn))
0233 #endif
0234 void
0235 make_ub(T && )
0236 {
0237 BOOST_OUTCOME_ASSERT(false);
0238 #if defined(__GNUC__) || defined(__clang__)
0239 __builtin_unreachable();
0240 #elif defined(_MSC_VER)
0241 __assume(0);
0242 #endif
0243 }
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257 enum class status : uint16_t
0258 {
0259
0260
0261 none = 0,
0262
0263 have_value = (1U << 0U),
0264 have_error = (1U << 1U),
0265 have_exception = (2U << 1U),
0266 have_error_exception = (3U << 1U),
0267
0268
0269 have_lost_consistency = (1U << 3U),
0270
0271 have_value_lost_consistency = (1U << 0U) | (1U << 3U),
0272 have_error_lost_consistency = (1U << 1U) | (1U << 3U),
0273 have_exception_lost_consistency = (2U << 1U) | (1U << 3U),
0274 have_error_exception_lost_consistency = (3U << 1U) | (1U << 3U),
0275
0276
0277 have_error_is_errno = (1U << 4U),
0278
0279 have_error_error_is_errno = (1U << 1U) | (1U << 4U),
0280 have_error_exception_error_is_errno = (3U << 1U) | (1U << 4U),
0281
0282 have_error_lost_consistency_error_is_errno = (1U << 1U) | (1U << 3U) | (1U << 4U),
0283 have_error_exception_lost_consistency_error_is_errno = (3U << 1U) | (1U << 3U) | (1U << 4U),
0284
0285
0286 have_moved_from = (1U << 5U),
0287
0288 have_value_moved_from = (1U << 0U) | (1U << 5U),
0289 have_error_moved_from = (1U << 1U) | (1U << 5U),
0290 have_exception_moved_from = (2U << 1U) | (1U << 5U),
0291 have_error_exception_moved_from = (3U << 1U) | (1U << 5U),
0292
0293 have_value_lost_consistency_moved_from = (1U << 0U) | (1U << 3U) | (1U << 5U),
0294 have_error_lost_consistency_moved_from = (1U << 1U) | (1U << 3U) | (1U << 5U),
0295 have_exception_lost_consistency_moved_from = (2U << 1U) | (1U << 3U) | (1U << 5U),
0296 have_error_exception_lost_consistency_moved_from = (3U << 1U) | (1U << 3U) | (1U << 5U),
0297
0298 have_error_is_errno_moved_from = (1U << 4U) | (1U << 5U),
0299 have_error_error_is_errno_moved_from = (1U << 1U) | (1U << 4U) | (1U << 5U),
0300 have_error_exception_error_is_errno_moved_from = (3U << 1U) | (1U << 4U) | (1U << 5U),
0301
0302 have_error_lost_consistency_error_is_errno_moved_from = (1U << 1U) | (1U << 3U) | (1U << 4U) | (1U << 5U),
0303 have_error_exception_lost_consistency_error_is_errno_moved_from = (3U << 1U) | (1U << 3U) | (1U << 4U) | (1U << 5U),
0304 };
0305 struct status_bitfield_type
0306 {
0307 status status_value{status::none};
0308 uint16_t spare_storage_value{0};
0309
0310 constexpr status_bitfield_type() = default;
0311 constexpr status_bitfield_type(status v) noexcept
0312 : status_value(v)
0313 {
0314 }
0315 constexpr status_bitfield_type(status v, uint16_t s) noexcept
0316 : status_value(v)
0317 , spare_storage_value(s)
0318 {
0319 }
0320 constexpr status_bitfield_type(const status_bitfield_type &) = default;
0321 constexpr status_bitfield_type(status_bitfield_type &&) = default;
0322 constexpr status_bitfield_type &operator=(const status_bitfield_type &) = default;
0323 constexpr status_bitfield_type &operator=(status_bitfield_type &&) = default;
0324
0325
0326 constexpr bool have_value() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_value)) != 0; }
0327 constexpr bool have_error() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error)) != 0; }
0328 constexpr bool have_exception() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_exception)) != 0; }
0329 constexpr bool have_lost_consistency() const noexcept
0330 {
0331 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_lost_consistency)) != 0;
0332 }
0333 constexpr bool have_error_is_errno() const noexcept
0334 {
0335 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error_is_errno)) != 0;
0336 }
0337 constexpr bool have_moved_from() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_moved_from)) != 0; }
0338
0339 constexpr status_bitfield_type &set_have_value(bool v) noexcept
0340 {
0341 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_value)) :
0342 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_value)));
0343 return *this;
0344 }
0345 constexpr status_bitfield_type &set_have_error(bool v) noexcept
0346 {
0347 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error)) :
0348 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error)));
0349 return *this;
0350 }
0351 constexpr status_bitfield_type &set_have_exception(bool v) noexcept
0352 {
0353 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_exception)) :
0354 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_exception)));
0355 return *this;
0356 }
0357 constexpr status_bitfield_type &set_have_error_is_errno(bool v) noexcept
0358 {
0359 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error_is_errno)) :
0360 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error_is_errno)));
0361 return *this;
0362 }
0363 constexpr status_bitfield_type &set_have_lost_consistency(bool v) noexcept
0364 {
0365 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_lost_consistency)) :
0366 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_lost_consistency)));
0367 return *this;
0368 }
0369 constexpr status_bitfield_type &set_have_moved_from(bool v) noexcept
0370 {
0371 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_moved_from)) :
0372 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_moved_from)));
0373 return *this;
0374 }
0375 };
0376 #if !defined(NDEBUG)
0377
0378 static_assert(sizeof(status_bitfield_type) == 4, "status_bitfield_type is not sized 4 bytes!");
0379 static_assert(std::is_trivially_copyable<status_bitfield_type>::value, "status_bitfield_type is not trivially copyable!");
0380 static_assert(std::is_trivially_assignable<status_bitfield_type, status_bitfield_type>::value, "status_bitfield_type is not trivially assignable!");
0381 static_assert(std::is_trivially_destructible<status_bitfield_type>::value, "status_bitfield_type is not trivially destructible!");
0382 static_assert(std::is_trivially_copy_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially copy constructible!");
0383 static_assert(std::is_trivially_move_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially move constructible!");
0384 static_assert(std::is_trivially_copy_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially copy assignable!");
0385 static_assert(std::is_trivially_move_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially move assignable!");
0386
0387 static_assert(std::is_standard_layout<status_bitfield_type>::value, "status_bitfield_type is not a standard layout type!");
0388 #endif
0389
0390 template <class State> constexpr inline void _set_error_is_errno(State & ) {}
0391
0392 #ifdef _MSC_VER
0393 #pragma warning(push)
0394 #pragma warning(disable : 4127)
0395 #pragma warning(disable : 4624)
0396 #endif
0397
0398 template <class T, class E> struct value_storage_trivial
0399 {
0400 using value_type = T;
0401 using error_type = E;
0402
0403
0404 struct disable_in_place_value_type
0405 {
0406 };
0407 struct disable_in_place_error_type
0408 {
0409 };
0410 using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
0411 using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
0412 using _value_type_ = devoid<value_type>;
0413 using _error_type_ = devoid<error_type>;
0414
0415 union
0416 {
0417 empty_type _empty;
0418 _value_type_ _value;
0419 _error_type_ _error;
0420 };
0421 status_bitfield_type _status;
0422 constexpr value_storage_trivial() noexcept
0423 : _empty{}
0424 {
0425 }
0426 value_storage_trivial(const value_storage_trivial &) = default;
0427 value_storage_trivial(value_storage_trivial &&) = default;
0428 value_storage_trivial &operator=(const value_storage_trivial &) = default;
0429 value_storage_trivial &operator=(value_storage_trivial &&) = default;
0430 ~value_storage_trivial() = default;
0431 constexpr explicit value_storage_trivial(status_bitfield_type status)
0432 : _empty()
0433 , _status(status)
0434 {
0435 }
0436 template <class... Args>
0437 constexpr explicit value_storage_trivial(in_place_type_t<_value_type> ,
0438 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
0439 : _value(static_cast<Args &&>(args)...)
0440 , _status(status::have_value)
0441 {
0442 }
0443 template <class U, class... Args>
0444 constexpr value_storage_trivial(in_place_type_t<_value_type> , std::initializer_list<U> il,
0445 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
0446 : _value(il, static_cast<Args &&>(args)...)
0447 , _status(status::have_value)
0448 {
0449 }
0450 template <class... Args>
0451 constexpr explicit value_storage_trivial(in_place_type_t<_error_type> ,
0452 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
0453 : _error(static_cast<Args &&>(args)...)
0454 , _status(status::have_error)
0455 {
0456 _set_error_is_errno(*this);
0457 }
0458 template <class U, class... Args>
0459 constexpr value_storage_trivial(in_place_type_t<_error_type> , std::initializer_list<U> il,
0460 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
0461 : _error(il, static_cast<Args &&>(args)...)
0462 , _status(status::have_error)
0463 {
0464 _set_error_is_errno(*this);
0465 }
0466
0467 struct nonvoid_converting_constructor_tag
0468 {
0469 };
0470 template <class U, class V>
0471 static constexpr bool enable_nonvoid_converting_constructor =
0472 !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value)
0473 && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
0474 BOOST_OUTCOME_TEMPLATE(class U, class V)
0475 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0476 constexpr explicit value_storage_trivial(const value_storage_trivial<U, V> &o,
0477 nonvoid_converting_constructor_tag = {}) noexcept(detail::is_nothrow_constructible<_value_type_, U> &&
0478 detail::is_nothrow_constructible<_error_type_, V>)
0479 : value_storage_trivial(o._status.have_value() ?
0480 value_storage_trivial(in_place_type<value_type>, o._value) :
0481 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial()))
0482 {
0483 _status = o._status;
0484 }
0485 BOOST_OUTCOME_TEMPLATE(class U, class V)
0486 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0487 constexpr explicit value_storage_trivial(value_storage_trivial<U, V> &&o,
0488 nonvoid_converting_constructor_tag = {}) noexcept(detail::is_nothrow_constructible<_value_type_, U> &&
0489 detail::is_nothrow_constructible<_error_type_, V>)
0490 : value_storage_trivial(
0491 o._status.have_value() ?
0492 value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
0493 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial()))
0494 {
0495 _status = o._status;
0496 }
0497
0498 struct void_value_converting_constructor_tag
0499 {
0500 };
0501 template <class V>
0502 static constexpr bool enable_void_value_converting_constructor =
0503 std::is_default_constructible<value_type>::value && detail::is_constructible<error_type, V>;
0504 BOOST_OUTCOME_TEMPLATE(class V)
0505 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
0506 constexpr explicit value_storage_trivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag = {}) noexcept(
0507 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
0508 : value_storage_trivial(o._status.have_value() ?
0509 value_storage_trivial(in_place_type<value_type>) :
0510 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial()))
0511 {
0512 _status = o._status;
0513 }
0514 BOOST_OUTCOME_TEMPLATE(class V)
0515 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
0516 constexpr explicit value_storage_trivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag = {}) noexcept(
0517 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
0518 : value_storage_trivial(
0519 o._status.have_value() ?
0520 value_storage_trivial(in_place_type<value_type>) :
0521 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial()))
0522 {
0523 _status = o._status;
0524 }
0525
0526 struct void_error_converting_constructor_tag
0527 {
0528 };
0529 template <class U>
0530 static constexpr bool enable_void_error_converting_constructor =
0531 std::is_default_constructible<error_type>::value && detail::is_constructible<value_type, U>;
0532 BOOST_OUTCOME_TEMPLATE(class U)
0533 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
0534 constexpr explicit value_storage_trivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag = {}) noexcept(
0535 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
0536 : value_storage_trivial(o._status.have_value() ?
0537 value_storage_trivial(in_place_type<value_type>, o._value) :
0538 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial()))
0539 {
0540 _status = o._status;
0541 }
0542 BOOST_OUTCOME_TEMPLATE(class U)
0543 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
0544 constexpr explicit value_storage_trivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag = {}) noexcept(
0545 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
0546 : value_storage_trivial(o._status.have_value() ?
0547 value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
0548 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial()))
0549 {
0550 _status = o._status;
0551 }
0552 constexpr void swap(value_storage_trivial &o) noexcept
0553 {
0554
0555 auto temp = static_cast<value_storage_trivial &&>(*this);
0556 *this = static_cast<value_storage_trivial &&>(o);
0557 o = static_cast<value_storage_trivial &&>(temp);
0558 }
0559 };
0560
0561
0562
0563
0564 template <class T, class E> struct value_storage_nontrivial
0565 {
0566 using value_type = T;
0567 using error_type = E;
0568 struct disable_in_place_value_type
0569 {
0570 };
0571 struct disable_in_place_error_type
0572 {
0573 };
0574 using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
0575 using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
0576 using _value_type_ = devoid<value_type>;
0577 using _error_type_ = devoid<error_type>;
0578
0579 union
0580 {
0581 empty_type _empty1;
0582 _value_type_ _value;
0583 };
0584 status_bitfield_type _status;
0585 union
0586 {
0587 empty_type _empty2;
0588 _error_type_ _error;
0589 };
0590 #if __cplusplus >= 202000L || _HAS_CXX20
0591 constexpr
0592 #endif
0593 value_storage_nontrivial() noexcept
0594 : _empty1{}
0595 , _empty2{}
0596 {
0597 }
0598 value_storage_nontrivial &operator=(const value_storage_nontrivial &) = default;
0599 value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default;
0600 #if __cplusplus >= 202000L || _HAS_CXX20
0601 constexpr
0602 #endif
0603 value_storage_nontrivial(value_storage_nontrivial &&o) noexcept(std::is_nothrow_move_constructible<_value_type_>::value &&
0604 std::is_nothrow_move_constructible<_error_type_>::value)
0605 {
0606 if(o._status.have_value())
0607 {
0608 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));
0609 }
0610 else if(o._status.have_error())
0611 {
0612 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));
0613 }
0614 _status = o._status;
0615 o._status.set_have_moved_from(true);
0616 }
0617 #if __cplusplus >= 202000L || _HAS_CXX20
0618 constexpr
0619 #endif
0620 value_storage_nontrivial(const value_storage_nontrivial &o) noexcept(std::is_nothrow_copy_constructible<_value_type_>::value &&
0621 std::is_nothrow_copy_constructible<_error_type_>::value)
0622 {
0623 if(o._status.have_value())
0624 {
0625 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value);
0626 }
0627 else if(o._status.have_error())
0628 {
0629 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error);
0630 }
0631 _status = o._status;
0632 }
0633 #if __cplusplus >= 202000L || _HAS_CXX20
0634 constexpr
0635 #endif
0636 explicit value_storage_nontrivial(status_bitfield_type status)
0637 : _empty1()
0638 , _status(status)
0639 , _empty2()
0640 {
0641 }
0642 template <class... Args>
0643 constexpr explicit value_storage_nontrivial(in_place_type_t<_value_type> ,
0644 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
0645 : _value(static_cast<Args &&>(args)...)
0646 , _status(status::have_value)
0647 {
0648 }
0649 template <class U, class... Args>
0650 constexpr value_storage_nontrivial(in_place_type_t<_value_type> , std::initializer_list<U> il,
0651 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
0652 : _value(il, static_cast<Args &&>(args)...)
0653 , _status(status::have_value)
0654 {
0655 }
0656 template <class... Args>
0657 constexpr explicit value_storage_nontrivial(in_place_type_t<_error_type> ,
0658 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
0659 : _status(status::have_error)
0660 , _error(static_cast<Args &&>(args)...)
0661 {
0662 _set_error_is_errno(*this);
0663 }
0664 template <class U, class... Args>
0665 constexpr value_storage_nontrivial(in_place_type_t<_error_type> , std::initializer_list<U> il,
0666 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
0667 : _status(status::have_error)
0668 , _error(il, static_cast<Args &&>(args)...)
0669 {
0670 _set_error_is_errno(*this);
0671 }
0672
0673 struct nonvoid_converting_constructor_tag
0674 {
0675 };
0676 template <class U, class V>
0677 static constexpr bool enable_nonvoid_converting_constructor =
0678 !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value)
0679 && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
0680 BOOST_OUTCOME_TEMPLATE(class U, class V)
0681 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0682 constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, V> &o, nonvoid_converting_constructor_tag = {}) noexcept(
0683 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
0684 : value_storage_nontrivial(o._status.have_value() ?
0685 value_storage_nontrivial(in_place_type<value_type>, o._value) :
0686 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
0687 {
0688 _status = o._status;
0689 }
0690 BOOST_OUTCOME_TEMPLATE(class U, class V)
0691 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0692 constexpr explicit value_storage_nontrivial(value_storage_trivial<U, V> &&o, nonvoid_converting_constructor_tag = {}) noexcept(
0693 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
0694 : value_storage_nontrivial(
0695 o._status.have_value() ?
0696 value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
0697 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
0698 {
0699 _status = o._status;
0700 }
0701 BOOST_OUTCOME_TEMPLATE(class U, class V)
0702 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0703 constexpr explicit value_storage_nontrivial(const value_storage_nontrivial<U, V> &o, nonvoid_converting_constructor_tag = {}) noexcept(
0704 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
0705 : value_storage_nontrivial(o._status.have_value() ?
0706 value_storage_nontrivial(in_place_type<value_type>, o._value) :
0707 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
0708 {
0709 _status = o._status;
0710 }
0711 BOOST_OUTCOME_TEMPLATE(class U, class V)
0712 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0713 constexpr explicit value_storage_nontrivial(value_storage_nontrivial<U, V> &&o, nonvoid_converting_constructor_tag = {}) noexcept(
0714 detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
0715 : value_storage_nontrivial(
0716 o._status.have_value() ?
0717 value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
0718 (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
0719 {
0720 _status = o._status;
0721 }
0722
0723 struct void_value_converting_constructor_tag
0724 {
0725 };
0726 template <class V>
0727 static constexpr bool enable_void_value_converting_constructor =
0728 std::is_default_constructible<value_type>::value && detail::is_constructible<error_type, V>;
0729 BOOST_OUTCOME_TEMPLATE(class V)
0730 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
0731 constexpr explicit value_storage_nontrivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag = {}) noexcept(
0732 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
0733 {
0734 if(o._status.have_value())
0735 {
0736 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_();
0737 }
0738 else if(o._status.have_error())
0739 {
0740 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error);
0741 }
0742 _status = o._status;
0743 }
0744 BOOST_OUTCOME_TEMPLATE(class V)
0745 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
0746 constexpr explicit value_storage_nontrivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag = {}) noexcept(
0747 std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
0748 {
0749 if(o._status.have_value())
0750 {
0751 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_();
0752 }
0753 else if(o._status.have_error())
0754 {
0755 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));
0756 }
0757 _status = o._status;
0758 o._status.set_have_moved_from(true);
0759 }
0760
0761 struct void_error_converting_constructor_tag
0762 {
0763 };
0764 template <class U>
0765 static constexpr bool enable_void_error_converting_constructor =
0766 std::is_default_constructible<error_type>::value && detail::is_constructible<value_type, U>;
0767 BOOST_OUTCOME_TEMPLATE(class U)
0768 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
0769 constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag = {}) noexcept(
0770 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
0771 {
0772 if(o._status.have_value())
0773 {
0774 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value);
0775 }
0776 else if(o._status.have_error())
0777 {
0778 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_();
0779 }
0780 _status = o._status;
0781 }
0782 BOOST_OUTCOME_TEMPLATE(class U)
0783 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
0784 constexpr explicit value_storage_nontrivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag = {}) noexcept(
0785 detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
0786 {
0787 if(o._status.have_value())
0788 {
0789 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));
0790 }
0791 else if(o._status.have_error())
0792 {
0793 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_();
0794 }
0795 _status = o._status;
0796 o._status.set_have_moved_from(true);
0797 }
0798
0799 #if __cplusplus >= 202000L || _HAS_CXX20
0800 constexpr
0801 #endif
0802 ~value_storage_nontrivial() noexcept(std::is_nothrow_destructible<_value_type_>::value && std::is_nothrow_destructible<_error_type_>::value)
0803 {
0804 if(this->_status.have_value())
0805 {
0806 if(!trait::is_move_bitcopying<value_type>::value || !this->_status.have_moved_from())
0807 {
0808 this->_value.~_value_type_();
0809 }
0810 this->_status.set_have_value(false);
0811 }
0812 else if(this->_status.have_error())
0813 {
0814 if(!trait::is_move_bitcopying<error_type>::value || !this->_status.have_moved_from())
0815 {
0816 this->_error.~_error_type_();
0817 }
0818 this->_status.set_have_error(false);
0819 }
0820 }
0821 #if __cplusplus >= 202000L || _HAS_CXX20
0822 constexpr
0823 #endif
0824 void
0825 swap(value_storage_nontrivial &o) noexcept(detail::is_nothrow_swappable<_value_type_>::value && detail::is_nothrow_swappable<_error_type_>::value)
0826 {
0827 using std::swap;
0828
0829 if(!_status.have_value() && !o._status.have_value() && !_status.have_error() && !o._status.have_error())
0830 {
0831 swap(_status, o._status);
0832 return;
0833 }
0834
0835 if(_status.have_value() && o._status.have_value())
0836 {
0837 struct some_type
0838 {
0839 status_bitfield_type &a, &b;
0840 bool all_good{false};
0841 ~some_type()
0842 {
0843 if(!this->all_good)
0844 {
0845
0846 this->a.set_have_lost_consistency(true);
0847 this->b.set_have_lost_consistency(true);
0848 }
0849 }
0850 } some_type_value{_status, o._status};
0851 strong_swap(some_type_value.all_good, _value, o._value);
0852 swap(_status, o._status);
0853 return;
0854 }
0855
0856 if(_status.have_error() && o._status.have_error())
0857 {
0858 struct some_type
0859 {
0860 status_bitfield_type &a, &b;
0861 bool all_good{false};
0862 ~some_type()
0863 {
0864 if(!this->all_good)
0865 {
0866
0867 this->a.set_have_lost_consistency(true);
0868 this->b.set_have_lost_consistency(true);
0869 }
0870 }
0871 } some_type_value{_status, o._status};
0872 strong_swap(some_type_value.all_good, _error, o._error);
0873 swap(_status, o._status);
0874 return;
0875 }
0876
0877 if(_status.have_value() && !o._status.have_error())
0878 {
0879
0880 new(BOOST_OUTCOME_ADDRESS_OF(o._value)) _value_type_(static_cast<_value_type_ &&>(_value));
0881 if(!trait::is_move_bitcopying<value_type>::value)
0882 {
0883 this->_value.~value_type();
0884 }
0885 swap(_status, o._status);
0886 return;
0887 }
0888 if(o._status.have_value() && !_status.have_error())
0889 {
0890
0891 new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));
0892 if(!trait::is_move_bitcopying<value_type>::value)
0893 {
0894 o._value.~value_type();
0895 }
0896 swap(_status, o._status);
0897 return;
0898 }
0899 if(_status.have_error() && !o._status.have_value())
0900 {
0901
0902 new(BOOST_OUTCOME_ADDRESS_OF(o._error)) _error_type_(static_cast<_error_type_ &&>(_error));
0903 if(!trait::is_move_bitcopying<error_type>::value)
0904 {
0905 this->_error.~error_type();
0906 }
0907 swap(_status, o._status);
0908 return;
0909 }
0910 if(o._status.have_error() && !_status.have_value())
0911 {
0912
0913 new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));
0914 if(!trait::is_move_bitcopying<error_type>::value)
0915 {
0916 o._error.~error_type();
0917 }
0918 swap(_status, o._status);
0919 return;
0920 }
0921
0922 struct some_type
0923 {
0924 status_bitfield_type &a, &b;
0925 _value_type_ *value, *o_value;
0926 _error_type_ *error, *o_error;
0927 bool all_good{true};
0928 ~some_type()
0929 {
0930 if(!this->all_good)
0931 {
0932
0933 this->a.set_have_lost_consistency(true);
0934 this->b.set_have_lost_consistency(true);
0935 }
0936 }
0937 } some_type_value{_status, o._status, BOOST_OUTCOME_ADDRESS_OF(_value), BOOST_OUTCOME_ADDRESS_OF(o._value), BOOST_OUTCOME_ADDRESS_OF(_error), BOOST_OUTCOME_ADDRESS_OF(o._error)};
0938 if(_status.have_value() && o._status.have_error())
0939 {
0940 strong_placement(some_type_value.all_good, some_type_value.o_value, some_type_value.value, [&some_type_value] {
0941 strong_placement(some_type_value.all_good, some_type_value.error, some_type_value.o_error, [&some_type_value] {
0942 swap(some_type_value.a, some_type_value.b);
0943 });
0944 });
0945 return;
0946 }
0947 if(_status.have_error() && o._status.have_value())
0948 {
0949 strong_placement(some_type_value.all_good, some_type_value.o_error, some_type_value.error, [&some_type_value] {
0950 strong_placement(some_type_value.all_good, some_type_value.value, some_type_value.o_value, [&some_type_value] {
0951 swap(some_type_value.a, some_type_value.b);
0952 });
0953 });
0954 return;
0955 }
0956
0957 make_ub(_value);
0958 }
0959 };
0960 template <class Base> struct value_storage_delete_copy_constructor : Base
0961 {
0962 using Base::Base;
0963 using value_type = typename Base::value_type;
0964 using error_type = typename Base::error_type;
0965 value_storage_delete_copy_constructor() = default;
0966 value_storage_delete_copy_constructor(const value_storage_delete_copy_constructor &) = delete;
0967 value_storage_delete_copy_constructor(value_storage_delete_copy_constructor &&) = default;
0968 value_storage_delete_copy_constructor &operator=(const value_storage_delete_copy_constructor &o) = default;
0969 value_storage_delete_copy_constructor &operator=(value_storage_delete_copy_constructor &&o) = default;
0970 ~value_storage_delete_copy_constructor() = default;
0971 };
0972 template <class Base> struct value_storage_delete_copy_assignment : Base
0973 {
0974 using Base::Base;
0975 using value_type = typename Base::value_type;
0976 using error_type = typename Base::error_type;
0977 value_storage_delete_copy_assignment() = default;
0978 value_storage_delete_copy_assignment(const value_storage_delete_copy_assignment &) = default;
0979 value_storage_delete_copy_assignment(value_storage_delete_copy_assignment &&) = default;
0980 value_storage_delete_copy_assignment &operator=(const value_storage_delete_copy_assignment &o) = delete;
0981 value_storage_delete_copy_assignment &operator=(value_storage_delete_copy_assignment &&o) = default;
0982 ~value_storage_delete_copy_assignment() = default;
0983 };
0984 template <class Base> struct value_storage_delete_move_assignment : Base
0985 {
0986 using Base::Base;
0987 using value_type = typename Base::value_type;
0988 using error_type = typename Base::error_type;
0989 value_storage_delete_move_assignment() = default;
0990 value_storage_delete_move_assignment(const value_storage_delete_move_assignment &) = default;
0991 value_storage_delete_move_assignment(value_storage_delete_move_assignment &&) = default;
0992 value_storage_delete_move_assignment &operator=(const value_storage_delete_move_assignment &o) = default;
0993 value_storage_delete_move_assignment &operator=(value_storage_delete_move_assignment &&o) = delete;
0994 ~value_storage_delete_move_assignment() = default;
0995 };
0996 template <class Base> struct value_storage_delete_move_constructor : Base
0997 {
0998 using Base::Base;
0999 using value_type = typename Base::value_type;
1000 using error_type = typename Base::error_type;
1001 value_storage_delete_move_constructor() = default;
1002 value_storage_delete_move_constructor(const value_storage_delete_move_constructor &) = default;
1003 value_storage_delete_move_constructor(value_storage_delete_move_constructor &&) = delete;
1004 value_storage_delete_move_constructor &operator=(const value_storage_delete_move_constructor &o) = default;
1005 value_storage_delete_move_constructor &operator=(value_storage_delete_move_constructor &&o) = default;
1006 ~value_storage_delete_move_constructor() = default;
1007 };
1008 template <class Base> struct value_storage_nontrivial_move_assignment : Base
1009 {
1010 using Base::Base;
1011 using value_type = typename Base::value_type;
1012 using error_type = typename Base::error_type;
1013 value_storage_nontrivial_move_assignment() = default;
1014 value_storage_nontrivial_move_assignment(const value_storage_nontrivial_move_assignment &) = default;
1015 value_storage_nontrivial_move_assignment(value_storage_nontrivial_move_assignment &&) = default;
1016 value_storage_nontrivial_move_assignment &operator=(const value_storage_nontrivial_move_assignment &o) = default;
1017 ~value_storage_nontrivial_move_assignment() = default;
1018 #if __cplusplus >= 202000L || _HAS_CXX20
1019 constexpr
1020 #endif
1021 value_storage_nontrivial_move_assignment &
1022 operator=(value_storage_nontrivial_move_assignment &&o) noexcept(std::is_nothrow_move_assignable<value_type>::value &&
1023 std::is_nothrow_move_assignable<error_type>::value &&
1024 noexcept(move_assign_to_empty<value_type>(static_cast<value_type *>(nullptr),
1025 static_cast<value_type *>(nullptr))) &&
1026 noexcept(move_assign_to_empty<error_type>(static_cast<error_type *>(nullptr),
1027 static_cast<error_type *>(nullptr))))
1028 {
1029 using _value_type_ = typename Base::_value_type_;
1030 using _error_type_ = typename Base::_error_type_;
1031 if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1032 {
1033 this->_status = o._status;
1034 o._status.set_have_moved_from(true);
1035 return *this;
1036 }
1037 if(this->_status.have_value() && o._status.have_value())
1038 {
1039 this->_value = static_cast<_value_type_ &&>(o._value);
1040 this->_status = o._status;
1041 o._status.set_have_moved_from(true);
1042 return *this;
1043 }
1044 if(this->_status.have_error() && o._status.have_error())
1045 {
1046 this->_error = static_cast<_error_type_ &&>(o._error);
1047 this->_status = o._status;
1048 o._status.set_have_moved_from(true);
1049 return *this;
1050 }
1051 if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
1052 {
1053 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1054 {
1055 this->_value.~_value_type_();
1056 }
1057 this->_status = o._status;
1058 o._status.set_have_moved_from(true);
1059 return *this;
1060 }
1061 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
1062 {
1063 move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1064 this->_status = o._status;
1065 o._status.set_have_moved_from(true);
1066 return *this;
1067 }
1068 if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1069 {
1070 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1071 {
1072 this->_error.~_error_type_();
1073 }
1074 this->_status = o._status;
1075 o._status.set_have_moved_from(true);
1076 return *this;
1077 }
1078 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
1079 {
1080 move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1081 this->_status = o._status;
1082 o._status.set_have_moved_from(true);
1083 return *this;
1084 }
1085 if(this->_status.have_value() && o._status.have_error())
1086 {
1087 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1088 {
1089 this->_value.~_value_type_();
1090 }
1091 move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1092 this->_status = o._status;
1093 o._status.set_have_moved_from(true);
1094 return *this;
1095 }
1096 if(this->_status.have_error() && o._status.have_value())
1097 {
1098 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1099 {
1100 this->_error.~_error_type_();
1101 }
1102 move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1103 this->_status = o._status;
1104 o._status.set_have_moved_from(true);
1105 return *this;
1106 }
1107
1108 make_ub(this->_value);
1109 }
1110 };
1111 template <class Base> struct value_storage_nontrivial_copy_assignment : Base
1112 {
1113 using Base::Base;
1114 using value_type = typename Base::value_type;
1115 using error_type = typename Base::error_type;
1116 value_storage_nontrivial_copy_assignment() = default;
1117 value_storage_nontrivial_copy_assignment(const value_storage_nontrivial_copy_assignment &) = default;
1118 value_storage_nontrivial_copy_assignment(value_storage_nontrivial_copy_assignment &&) = default;
1119 value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default;
1120 ~value_storage_nontrivial_copy_assignment() = default;
1121 #if __cplusplus >= 202000L || _HAS_CXX20
1122 constexpr
1123 #endif
1124 value_storage_nontrivial_copy_assignment &
1125 operator=(const value_storage_nontrivial_copy_assignment &o) noexcept(
1126 std::is_nothrow_copy_assignable<value_type>::value && std::is_nothrow_copy_assignable<error_type>::value &&
1127 noexcept(copy_assign_to_empty<value_type>(static_cast<value_type *>(nullptr), static_cast<value_type *>(nullptr))) &&
1128 noexcept(copy_assign_to_empty<error_type>(static_cast<error_type *>(nullptr), static_cast<error_type *>(nullptr))))
1129 {
1130 using _value_type_ = typename Base::_value_type_;
1131 using _error_type_ = typename Base::_error_type_;
1132 if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1133 {
1134 this->_status = o._status;
1135 return *this;
1136 }
1137 if(this->_status.have_value() && o._status.have_value())
1138 {
1139 this->_value = o._value;
1140 this->_status = o._status;
1141 return *this;
1142 }
1143 if(this->_status.have_error() && o._status.have_error())
1144 {
1145 this->_error = o._error;
1146 this->_status = o._status;
1147 return *this;
1148 }
1149 if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
1150 {
1151 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1152 {
1153 this->_value.~_value_type_();
1154 }
1155 this->_status = o._status;
1156 return *this;
1157 }
1158 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
1159 {
1160 copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1161 this->_status = o._status;
1162 return *this;
1163 }
1164 if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1165 {
1166 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1167 {
1168 this->_error.~_error_type_();
1169 }
1170 this->_status = o._status;
1171 return *this;
1172 }
1173 if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
1174 {
1175 copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1176 this->_status = o._status;
1177 return *this;
1178 }
1179 if(this->_status.have_value() && o._status.have_error())
1180 {
1181 if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1182 {
1183 this->_value.~_value_type_();
1184 }
1185 copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1186 this->_status = o._status;
1187 return *this;
1188 }
1189 if(this->_status.have_error() && o._status.have_value())
1190 {
1191 if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1192 {
1193 this->_error.~_error_type_();
1194 }
1195 copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1196 this->_status = o._status;
1197 return *this;
1198 }
1199
1200 make_ub(this->_value);
1201 }
1202 };
1203 #ifdef _MSC_VER
1204 #pragma warning(pop)
1205 #endif
1206
1207
1208 template <class T> struct is_storage_trivial
1209 {
1210 static constexpr bool value = std::is_void<T>::value || (std::is_trivially_copy_constructible<T>::value && std::is_trivially_copyable<T>::value);
1211 };
1212
1213 template <> struct is_storage_trivial<void>
1214 {
1215 static constexpr bool value = true;
1216 };
1217 template <> struct is_storage_trivial<const void>
1218 {
1219 static constexpr bool value = true;
1220 };
1221
1222 template <class T> struct is_copy_assignable
1223 {
1224 static constexpr bool value = std::is_copy_assignable<T>::value && (std::is_copy_constructible<T>::value || std::is_default_constructible<T>::value);
1225 };
1226
1227 template <class T> struct is_move_assignable
1228 {
1229 static constexpr bool value = std::is_move_assignable<T>::value && (std::is_move_constructible<T>::value || std::is_default_constructible<T>::value);
1230 };
1231
1232 template <class T, class E>
1233 using value_storage_select_trivality =
1234 std::conditional_t<is_storage_trivial<T>::value && is_storage_trivial<E>::value, value_storage_trivial<T, E>, value_storage_nontrivial<T, E>>;
1235 template <class T, class E>
1236 using value_storage_select_move_constructor =
1237 std::conditional_t<std::is_move_constructible<devoid<T>>::value && std::is_move_constructible<devoid<E>>::value, value_storage_select_trivality<T, E>,
1238 value_storage_delete_move_constructor<value_storage_select_trivality<T, E>>>;
1239 template <class T, class E>
1240 using value_storage_select_copy_constructor =
1241 std::conditional_t<std::is_copy_constructible<devoid<T>>::value && std::is_copy_constructible<devoid<E>>::value, value_storage_select_move_constructor<T, E>,
1242 value_storage_delete_copy_constructor<value_storage_select_move_constructor<T, E>>>;
1243 template <class T, class E>
1244 using value_storage_select_move_assignment =
1245 std::conditional_t<std::is_trivially_move_assignable<devoid<T>>::value && std::is_trivially_move_assignable<devoid<E>>::value,
1246 value_storage_select_copy_constructor<T, E>,
1247 std::conditional_t<is_move_assignable<devoid<T>>::value && is_move_assignable<devoid<E>>::value,
1248 value_storage_nontrivial_move_assignment<value_storage_select_copy_constructor<T, E>>,
1249 value_storage_delete_move_assignment<value_storage_select_copy_constructor<T, E>>>>;
1250 template <class T, class E>
1251 using value_storage_select_copy_assignment =
1252 std::conditional_t<std::is_trivially_copy_assignable<devoid<T>>::value && std::is_trivially_copy_assignable<devoid<E>>::value,
1253 value_storage_select_move_assignment<T, E>,
1254 std::conditional_t<is_copy_assignable<devoid<T>>::value && is_copy_assignable<devoid<E>>::value,
1255 value_storage_nontrivial_copy_assignment<value_storage_select_move_assignment<T, E>>,
1256 value_storage_delete_copy_assignment<value_storage_select_move_assignment<T, E>>>>;
1257 template <class T, class E> using value_storage_select_impl = value_storage_select_copy_assignment<T, E>;
1258 #ifndef NDEBUG
1259
1260
1261
1262
1263 static_assert(std::is_trivially_copyable<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivially copyable!");
1264 static_assert(std::is_trivially_assignable<value_storage_select_impl<int, long>, value_storage_select_impl<int, long>>::value,
1265 "value_storage_select_impl<int, long> is not trivially assignable!");
1266 static_assert(std::is_trivially_destructible<value_storage_select_impl<int, long>>::value,
1267 "value_storage_select_impl<int, long> is not trivially destructible!");
1268 static_assert(std::is_trivially_copy_constructible<value_storage_select_impl<int, long>>::value,
1269 "value_storage_select_impl<int, long> is not trivially copy constructible!");
1270 static_assert(std::is_trivially_move_constructible<value_storage_select_impl<int, long>>::value,
1271 "value_storage_select_impl<int, long> is not trivially move constructible!");
1272 static_assert(std::is_trivially_copy_assignable<value_storage_select_impl<int, long>>::value,
1273 "value_storage_select_impl<int, long> is not trivially copy assignable!");
1274 static_assert(std::is_trivially_move_assignable<value_storage_select_impl<int, long>>::value,
1275 "value_storage_select_impl<int, long> is not trivially move assignable!");
1276
1277 static_assert(std::is_standard_layout<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not a standard layout type!");
1278 #endif
1279 }
1280
1281 BOOST_OUTCOME_V2_NAMESPACE_END
1282
1283 #endif