1 /* Essentially an internal optional implementation :)
2 (C) 2017-2020 Niall Douglas <http://www.nedproductions.biz/> (24 commits)
3 File Created: June 2017
6 Boost Software License - Version 1.0 - August 17th, 2003
8 Permission is hereby granted, free of charge, to any person or organization
9 obtaining a copy of the software and accompanying documentation covered by
10 this license (the "Software") to use, reproduce, display, distribute,
11 execute, and transmit the Software, and to prepare derivative works of the
12 Software, and to permit third-parties to whom the Software is furnished to
13 do so, all subject to the following:
15 The copyright notices in the Software and this entire statement, including
16 the above license grant, this restriction and the following disclaimer,
17 must be included in all copies of the Software, in whole or in part, and
18 all derivative works of the Software, unless such copies or derivative
19 works are solely in the form of machine-executable object code generated by
20 a source language processor.
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
31 #ifndef BOOST_OUTCOME_VALUE_STORAGE_HPP
32 #define BOOST_OUTCOME_VALUE_STORAGE_HPP
34 #include "../config.hpp"
38 BOOST_OUTCOME_V2_NAMESPACE_BEGIN
42 template <class T, bool nothrow> struct strong_swap_impl
44 constexpr strong_swap_impl(bool &allgood, T &a, T &b)
51 #ifndef BOOST_NO_EXCEPTIONS
52 template <class T> struct strong_swap_impl<T, false>
54 strong_swap_impl(bool &allgood, T &a, T &b)
57 T v(static_cast<T &&>(a));
60 a = static_cast<T &&>(b);
67 a = static_cast<T &&>(v);
68 // fall through as all good
72 // failed to completely restore
74 // throw away second exception
76 throw; // rethrow original exception
78 // b has been moved to a, try to move v to b
81 b = static_cast<T &&>(v);
85 // Try to restore a to b, and v to a
88 b = static_cast<T &&>(a);
89 a = static_cast<T &&>(v);
90 // fall through as all good
94 // failed to completely restore
96 // throw away second exception
98 throw; // rethrow original exception
103 } // namespace detail
107 BOOST_OUTCOME_TEMPLATE(class T)
108 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
109 constexpr inline void strong_swap(bool &allgood, T &a, T &b) noexcept(detail::is_nothrow_swappable<T>::value)
111 detail::strong_swap_impl<T, detail::is_nothrow_swappable<T>::value>(allgood, a, b);
120 #elif defined(__GNUC__) || defined(__clang__)
121 __attribute__((noreturn))
123 void make_ub(T && /*unused*/)
125 assert(false); // NOLINT
126 #if defined(__GNUC__) || defined(__clang__)
127 __builtin_unreachable();
128 #elif defined(_MSC_VER)
133 /* Outcome v1 used a C bitfield whose values were tracked by compiler optimisers nicely,
134 but that produces ICEs when used in constexpr.
136 Outcome v2.0-v2.1 used a 32 bit integer and manually set and cleared bits. Unfortunately
137 only GCC's optimiser tracks bit values during constant folding, and only per byte, and
138 even then unreliably. https://wg21.link/P1886 "Error speed benchmarking" showed just how
139 poorly clang and MSVC fails to optimise outcome-using code, if you manually set bits.
141 Outcome v2.2 therefore uses an enum with fixed values, and constexpr manipulation functions
142 to change the value to one of the enum's values. This is stupid to look at in source code,
143 but it make clang's optimiser do the right thing, so it's worth it.
145 #define BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS 0
146 enum class status : uint16_t
148 // WARNING: These bits are not tracked by abi-dumper, but changing them will break ABI!
151 have_value = (1U << 0U),
152 have_error = (1U << 1U),
153 have_exception = (2U << 1U),
154 have_error_exception = (3U << 1U),
156 // failed to complete a strong swap
157 have_lost_consistency = (1U << 3U),
158 have_value_lost_consistency = (1U << 0U) | (1U << 3U),
159 have_error_lost_consistency = (1U << 1U) | (1U << 3U),
160 have_exception_lost_consistency = (2U << 1U) | (1U << 3U),
161 have_error_exception_lost_consistency = (3U << 1U) | (1U << 3U),
163 // can errno be set from this error?
164 have_error_is_errno = (1U << 4U),
165 have_error_error_is_errno = (1U << 1U) | (1U << 4U),
166 have_error_exception_error_is_errno = (3U << 1U) | (1U << 4U),
168 have_error_lost_consistency_error_is_errno = (1U << 1U) | (1U << 3U) | (1U << 4U),
169 have_error_exception_lost_consistency_error_is_errno = (3U << 1U) | (1U << 3U) | (1U << 4U),
171 // value has been moved from
172 have_moved_from = (1U << 5U)
174 struct status_bitfield_type
176 status status_value{status::none};
177 uint16_t spare_storage_value{0}; // hooks::spare_storage()
179 constexpr status_bitfield_type() = default;
180 constexpr status_bitfield_type(status v) noexcept
184 constexpr status_bitfield_type(status v, uint16_t s) noexcept
186 , spare_storage_value(s)
189 constexpr status_bitfield_type(const status_bitfield_type &) = default;
190 constexpr status_bitfield_type(status_bitfield_type &&) = default;
191 constexpr status_bitfield_type &operator=(const status_bitfield_type &) = default;
192 constexpr status_bitfield_type &operator=(status_bitfield_type &&) = default;
193 //~status_bitfield_type() = default; // Do NOT uncomment this, it breaks older clangs!
195 constexpr bool have_value() const noexcept
197 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
198 return (status_value == status::have_value) //
199 || (status_value == status::have_value_lost_consistency) //
202 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_value)) != 0;
205 constexpr bool have_error() const noexcept
207 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
208 return (status_value == status::have_error) //
209 || (status_value == status::have_error_exception) //
210 || (status_value == status::have_error_lost_consistency) //
211 || (status_value == status::have_error_exception_lost_consistency) //
212 || (status_value == status::have_error_error_is_errno) //
213 || (status_value == status::have_error_exception_error_is_errno) //
214 || (status_value == status::have_error_lost_consistency_error_is_errno) //
215 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
218 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error)) != 0;
221 constexpr bool have_exception() const noexcept
223 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
224 return (status_value == status::have_exception) //
225 || (status_value == status::have_error_exception) //
226 || (status_value == status::have_exception_lost_consistency) //
227 || (status_value == status::have_error_exception_lost_consistency) //
228 || (status_value == status::have_error_exception_error_is_errno) //
229 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
232 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_exception)) != 0;
235 constexpr bool have_lost_consistency() const noexcept
237 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
238 return (status_value == status::have_value_lost_consistency) //
239 || (status_value == status::have_error_lost_consistency) //
240 || (status_value == status::have_exception_lost_consistency) //
241 || (status_value == status::have_error_lost_consistency_error_is_errno) //
242 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
245 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_lost_consistency)) != 0;
248 constexpr bool have_error_is_errno() const noexcept
250 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
251 return (status_value == status::have_error_error_is_errno) //
252 || (status_value == status::have_error_exception_error_is_errno) //
253 || (status_value == status::have_error_lost_consistency_error_is_errno) //
254 || (status_value == status::have_error_exception_lost_consistency_error_is_errno) //
257 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error_is_errno)) != 0;
260 constexpr bool have_moved_from() const noexcept
262 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
265 return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_moved_from)) != 0;
269 constexpr status_bitfield_type &set_have_value(bool v) noexcept
271 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
277 status_value = status::have_value;
280 case status::have_value:
283 status_value = status::none;
286 case status::have_error:
292 case status::have_exception:
298 case status::have_error_exception:
304 case status::have_value_lost_consistency:
307 status_value = status::none;
310 case status::have_error_lost_consistency:
316 case status::have_exception_lost_consistency:
322 case status::have_error_exception_lost_consistency:
328 case status::have_error_error_is_errno:
334 case status::have_error_exception_error_is_errno:
340 case status::have_error_lost_consistency_error_is_errno:
346 case status::have_error_exception_lost_consistency_error_is_errno:
354 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_value)) :
355 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_value)));
359 constexpr status_bitfield_type &set_have_error(bool v) noexcept
361 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
367 status_value = status::have_error;
370 case status::have_value:
376 case status::have_error:
379 status_value = status::none;
382 case status::have_exception:
385 status_value = status::have_error_exception;
388 case status::have_error_exception:
391 status_value = status::have_exception;
394 case status::have_value_lost_consistency:
400 case status::have_error_lost_consistency:
403 status_value = status::none;
406 case status::have_exception_lost_consistency:
409 status_value = status::have_error_exception_lost_consistency;
412 case status::have_error_exception_lost_consistency:
415 status_value = status::have_exception_lost_consistency;
418 case status::have_error_error_is_errno:
421 status_value = status::none;
424 case status::have_error_exception_error_is_errno:
427 status_value = status::have_exception;
430 case status::have_error_lost_consistency_error_is_errno:
433 status_value = status::none;
436 case status::have_error_exception_lost_consistency_error_is_errno:
439 status_value = status::have_exception_lost_consistency;
444 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error)) :
445 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error)));
449 constexpr status_bitfield_type &set_have_exception(bool v) noexcept
451 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
457 status_value = status::have_exception;
460 case status::have_value:
466 case status::have_error:
469 status_value = status::have_error_exception;
472 case status::have_exception:
475 status_value = status::none;
478 case status::have_error_exception:
481 status_value = status::have_error;
484 case status::have_value_lost_consistency:
490 case status::have_error_lost_consistency:
493 status_value = status::have_error_exception_lost_consistency;
496 case status::have_exception_lost_consistency:
499 status_value = status::none;
502 case status::have_error_exception_lost_consistency:
505 status_value = status::have_error_lost_consistency;
508 case status::have_error_error_is_errno:
511 status_value = status::have_error_exception_error_is_errno;
514 case status::have_error_exception_error_is_errno:
517 status_value = status::have_error_error_is_errno;
520 case status::have_error_lost_consistency_error_is_errno:
523 status_value = status::have_error_exception_lost_consistency_error_is_errno;
526 case status::have_error_exception_lost_consistency_error_is_errno:
529 status_value = status::have_error_lost_consistency_error_is_errno;
534 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_exception)) :
535 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_exception)));
539 constexpr status_bitfield_type &set_have_error_is_errno(bool v) noexcept
541 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
547 case status::have_value:
550 case status::have_error:
553 status_value = status::have_error_error_is_errno;
556 case status::have_exception:
559 case status::have_error_exception:
562 status_value = status::have_error_exception_error_is_errno;
565 case status::have_value_lost_consistency:
568 case status::have_error_lost_consistency:
571 status_value = status::have_error_lost_consistency_error_is_errno;
574 case status::have_exception_lost_consistency:
577 case status::have_error_exception_lost_consistency:
580 status_value = status::have_error_exception_lost_consistency_error_is_errno;
583 case status::have_error_error_is_errno:
586 status_value = status::have_error;
589 case status::have_error_exception_error_is_errno:
592 status_value = status::have_error_exception;
595 case status::have_error_lost_consistency_error_is_errno:
598 status_value = status::have_error_lost_consistency;
601 case status::have_error_exception_lost_consistency_error_is_errno:
604 status_value = status::have_error_exception_lost_consistency;
609 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error_is_errno)) :
610 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error_is_errno)));
614 constexpr status_bitfield_type &set_have_lost_consistency(bool v) noexcept
616 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
625 case status::have_value:
628 status_value = status::have_value_lost_consistency;
631 case status::have_error:
634 status_value = status::have_error_lost_consistency;
637 case status::have_exception:
640 status_value = status::have_exception_lost_consistency;
643 case status::have_error_exception:
646 status_value = status::have_error_exception_lost_consistency;
649 case status::have_value_lost_consistency:
652 status_value = status::have_value;
655 case status::have_error_lost_consistency:
658 status_value = status::have_error;
661 case status::have_exception_lost_consistency:
664 status_value = status::have_exception;
667 case status::have_error_exception_lost_consistency:
670 status_value = status::have_error_exception;
673 case status::have_error_error_is_errno:
676 status_value = status::have_error_lost_consistency_error_is_errno;
679 case status::have_error_exception_error_is_errno:
682 status_value = status::have_error_exception_lost_consistency_error_is_errno;
685 case status::have_error_lost_consistency_error_is_errno:
688 status_value = status::have_error_exception_error_is_errno;
691 case status::have_error_exception_lost_consistency_error_is_errno:
694 status_value = status::have_error_exception_error_is_errno;
699 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_lost_consistency)) :
700 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_lost_consistency)));
704 constexpr status_bitfield_type &set_have_moved_from(bool v) noexcept
706 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
709 status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_moved_from)) :
710 (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_moved_from)));
716 // Check is trivial in all ways except default constructibility
717 static_assert(sizeof(status_bitfield_type) == 4, "status_bitfield_type is not sized 4 bytes!");
718 static_assert(std::is_trivially_copyable<status_bitfield_type>::value, "status_bitfield_type is not trivially copyable!");
719 static_assert(std::is_trivially_assignable<status_bitfield_type, status_bitfield_type>::value, "status_bitfield_type is not trivially assignable!");
720 static_assert(std::is_trivially_destructible<status_bitfield_type>::value, "status_bitfield_type is not trivially destructible!");
721 static_assert(std::is_trivially_copy_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially copy constructible!");
722 static_assert(std::is_trivially_move_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially move constructible!");
723 static_assert(std::is_trivially_copy_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially copy assignable!");
724 static_assert(std::is_trivially_move_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially move assignable!");
725 // Also check is standard layout
726 static_assert(std::is_standard_layout<status_bitfield_type>::value, "status_bitfield_type is not a standard layout type!");
729 // Used if T is trivial
730 template <class T> struct value_storage_trivial
732 using value_type = T;
737 status_bitfield_type _status;
738 constexpr value_storage_trivial() noexcept
742 // Special from-void catchall constructor, always constructs default T irrespective of whether void is valued or not (can do no better if T cannot be
744 struct disable_void_catchall
747 using void_value_storage_trivial = std::conditional_t<std::is_void<T>::value, disable_void_catchall, value_storage_trivial<void>>;
748 explicit constexpr value_storage_trivial(const void_value_storage_trivial &o) noexcept(std::is_nothrow_default_constructible<value_type>::value)
753 value_storage_trivial(const value_storage_trivial &) = default; // NOLINT
754 value_storage_trivial(value_storage_trivial &&) = default; // NOLINT
755 value_storage_trivial &operator=(const value_storage_trivial &) = default; // NOLINT
756 value_storage_trivial &operator=(value_storage_trivial &&) = default; // NOLINT
757 ~value_storage_trivial() = default;
758 constexpr explicit value_storage_trivial(status_bitfield_type status)
763 template <class... Args>
764 constexpr explicit value_storage_trivial(in_place_type_t<value_type> /*unused*/,
765 Args &&... args) noexcept(detail::is_nothrow_constructible<value_type, Args...>)
766 : _value(static_cast<Args &&>(args)...)
767 , _status(status::have_value)
770 template <class U, class... Args>
771 constexpr value_storage_trivial(in_place_type_t<value_type> /*unused*/, std::initializer_list<U> il,
772 Args &&... args) noexcept(detail::is_nothrow_constructible<value_type, std::initializer_list<U>, Args...>)
773 : _value(il, static_cast<Args &&>(args)...)
774 , _status(status::have_value)
778 static constexpr bool enable_converting_constructor = !std::is_same<std::decay_t<U>, value_type>::value && detail::is_constructible<value_type, U>;
779 BOOST_OUTCOME_TEMPLATE(class U)
780 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
781 constexpr explicit value_storage_trivial(const value_storage_trivial<U> &o) noexcept(detail::is_nothrow_constructible<value_type, U>)
782 : value_storage_trivial(o._status.have_value() ? value_storage_trivial(in_place_type<value_type>, o._value) : value_storage_trivial()) // NOLINT
786 BOOST_OUTCOME_TEMPLATE(class U)
787 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
788 constexpr explicit value_storage_trivial(value_storage_trivial<U> &&o) noexcept(detail::is_nothrow_constructible<value_type, U>)
789 : value_storage_trivial(o._status.have_value() ? value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
790 value_storage_trivial()) // NOLINT
794 constexpr void swap(value_storage_trivial &o) noexcept
796 // storage is trivial, so just use assignment
797 auto temp = static_cast<value_storage_trivial &&>(*this);
798 *this = static_cast<value_storage_trivial &&>(o);
799 o = static_cast<value_storage_trivial &&>(temp);
802 // Used if T is non-trivial
803 template <class T> struct value_storage_nontrivial
805 using value_type = T;
810 status_bitfield_type _status;
811 value_storage_nontrivial() noexcept
815 value_storage_nontrivial &operator=(const value_storage_nontrivial &) = default; // if reaches here, copy assignment is trivial
816 value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default; // NOLINT if reaches here, move assignment is trivial
817 value_storage_nontrivial(value_storage_nontrivial &&o) noexcept(std::is_nothrow_move_constructible<value_type>::value) // NOLINT
820 if(this->_status.have_value())
822 this->_status.set_have_value(false);
823 new(&_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
827 value_storage_nontrivial(const value_storage_nontrivial &o) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
830 if(this->_status.have_value())
832 this->_status.set_have_value(false);
833 new(&_value) value_type(o._value); // NOLINT
837 // Special from-void constructor, constructs default T if void valued
838 explicit value_storage_nontrivial(const value_storage_trivial<void> &o) noexcept(std::is_nothrow_default_constructible<value_type>::value)
841 if(this->_status.have_value())
843 this->_status.set_have_value(false);
844 new(&_value) value_type; // NOLINT
848 explicit value_storage_nontrivial(status_bitfield_type status)
853 template <class... Args>
854 explicit value_storage_nontrivial(in_place_type_t<value_type> /*unused*/,
855 Args &&... args) noexcept(detail::is_nothrow_constructible<value_type, Args...>)
856 : _value(static_cast<Args &&>(args)...) // NOLINT
857 , _status(status::have_value)
860 template <class U, class... Args>
861 value_storage_nontrivial(in_place_type_t<value_type> /*unused*/, std::initializer_list<U> il,
862 Args &&... args) noexcept(detail::is_nothrow_constructible<value_type, std::initializer_list<U>, Args...>)
863 : _value(il, static_cast<Args &&>(args)...)
864 , _status(status::have_value)
868 static constexpr bool enable_converting_constructor = !std::is_same<std::decay_t<U>, value_type>::value && detail::is_constructible<value_type, U>;
869 BOOST_OUTCOME_TEMPLATE(class U)
870 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
871 constexpr explicit value_storage_nontrivial(const value_storage_nontrivial<U> &o) noexcept(detail::is_nothrow_constructible<value_type, U>)
872 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, o._value) : value_storage_nontrivial())
876 BOOST_OUTCOME_TEMPLATE(class U)
877 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
878 constexpr explicit value_storage_nontrivial(const value_storage_trivial<U> &o) noexcept(detail::is_nothrow_constructible<value_type, U>)
879 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, o._value) : value_storage_nontrivial())
883 BOOST_OUTCOME_TEMPLATE(class U)
884 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
885 constexpr explicit value_storage_nontrivial(value_storage_nontrivial<U> &&o) noexcept(detail::is_nothrow_constructible<value_type, U>)
886 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
887 value_storage_nontrivial())
891 BOOST_OUTCOME_TEMPLATE(class U)
892 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
893 constexpr explicit value_storage_nontrivial(value_storage_trivial<U> &&o) noexcept(detail::is_nothrow_constructible<value_type, U>)
894 : value_storage_nontrivial(o._status.have_value() ? value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
895 value_storage_nontrivial())
899 ~value_storage_nontrivial() noexcept(std::is_nothrow_destructible<T>::value)
901 if(this->_status.have_value())
903 this->_value.~value_type(); // NOLINT
904 this->_status.set_have_value(false);
907 constexpr void swap(value_storage_nontrivial &o) noexcept(detail::is_nothrow_swappable<value_type>::value)
910 if(!_status.have_value() && !o._status.have_value())
912 swap(_status, o._status);
915 if(_status.have_value() && o._status.have_value())
919 status_bitfield_type &a, &b;
920 bool all_good{false};
925 // We lost one of the values
926 a.set_have_lost_consistency(true);
927 b.set_have_lost_consistency(true);
930 } _{_status, o._status};
931 strong_swap(_.all_good, _value, o._value);
932 swap(_status, o._status);
935 // One must be empty and the other non-empty, so use move construction
936 if(_status.have_value())
938 // Move construct me into other
939 new(&o._value) value_type(static_cast<value_type &&>(_value)); // NOLINT
940 this->_value.~value_type(); // NOLINT
941 swap(_status, o._status);
945 // Move construct other into me
946 new(&_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
947 o._value.~value_type(); // NOLINT
948 swap(_status, o._status);
952 template <class Base> struct value_storage_delete_copy_constructor : Base // NOLINT
955 using value_type = typename Base::value_type;
956 value_storage_delete_copy_constructor() = default;
957 value_storage_delete_copy_constructor(const value_storage_delete_copy_constructor &) = delete;
958 value_storage_delete_copy_constructor(value_storage_delete_copy_constructor &&) = default; // NOLINT
960 template <class Base> struct value_storage_delete_copy_assignment : Base // NOLINT
963 using value_type = typename Base::value_type;
964 value_storage_delete_copy_assignment() = default;
965 value_storage_delete_copy_assignment(const value_storage_delete_copy_assignment &) = default;
966 value_storage_delete_copy_assignment(value_storage_delete_copy_assignment &&) = default; // NOLINT
967 value_storage_delete_copy_assignment &operator=(const value_storage_delete_copy_assignment &o) = delete;
968 value_storage_delete_copy_assignment &operator=(value_storage_delete_copy_assignment &&o) = default; // NOLINT
970 template <class Base> struct value_storage_delete_move_assignment : Base // NOLINT
973 using value_type = typename Base::value_type;
974 value_storage_delete_move_assignment() = default;
975 value_storage_delete_move_assignment(const value_storage_delete_move_assignment &) = default;
976 value_storage_delete_move_assignment(value_storage_delete_move_assignment &&) = default; // NOLINT
977 value_storage_delete_move_assignment &operator=(const value_storage_delete_move_assignment &o) = default;
978 value_storage_delete_move_assignment &operator=(value_storage_delete_move_assignment &&o) = delete;
980 template <class Base> struct value_storage_delete_move_constructor : Base // NOLINT
983 using value_type = typename Base::value_type;
984 value_storage_delete_move_constructor() = default;
985 value_storage_delete_move_constructor(const value_storage_delete_move_constructor &) = default;
986 value_storage_delete_move_constructor(value_storage_delete_move_constructor &&) = delete;
988 template <class Base> struct value_storage_nontrivial_move_assignment : Base // NOLINT
991 using value_type = typename Base::value_type;
992 value_storage_nontrivial_move_assignment() = default;
993 value_storage_nontrivial_move_assignment(const value_storage_nontrivial_move_assignment &) = default;
994 value_storage_nontrivial_move_assignment(value_storage_nontrivial_move_assignment &&) = default; // NOLINT
995 value_storage_nontrivial_move_assignment &operator=(const value_storage_nontrivial_move_assignment &o) = default;
996 value_storage_nontrivial_move_assignment &
997 operator=(value_storage_nontrivial_move_assignment &&o) noexcept(std::is_nothrow_move_assignable<value_type>::value) // NOLINT
999 if(this->_status.have_value() && o._status.have_value())
1001 this->_value = static_cast<value_type &&>(o._value); // NOLINT
1003 else if(this->_status.have_value() && !o._status.have_value())
1005 this->_value.~value_type(); // NOLINT
1007 else if(!this->_status.have_value() && o._status.have_value())
1009 new(&this->_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
1011 this->_status = o._status;
1015 template <class Base> struct value_storage_nontrivial_copy_assignment : Base // NOLINT
1018 using value_type = typename Base::value_type;
1019 value_storage_nontrivial_copy_assignment() = default;
1020 value_storage_nontrivial_copy_assignment(const value_storage_nontrivial_copy_assignment &) = default;
1021 value_storage_nontrivial_copy_assignment(value_storage_nontrivial_copy_assignment &&) = default; // NOLINT
1022 value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default; // NOLINT
1023 value_storage_nontrivial_copy_assignment &
1024 operator=(const value_storage_nontrivial_copy_assignment &o) noexcept(std::is_nothrow_copy_assignable<value_type>::value)
1026 if(this->_status.have_value() && o._status.have_value())
1028 this->_value = o._value; // NOLINT
1030 else if(this->_status.have_value() && !o._status.have_value())
1032 this->_value.~value_type(); // NOLINT
1034 else if(!this->_status.have_value() && o._status.have_value())
1036 new(&this->_value) value_type(o._value); // NOLINT
1038 this->_status = o._status;
1043 // We don't actually need all of std::is_trivial<>, std::is_trivially_copyable<> is sufficient
1045 using value_storage_select_trivality =
1046 std::conditional_t<std::is_trivially_copyable<devoid<T>>::value, value_storage_trivial<T>, value_storage_nontrivial<T>>;
1048 using value_storage_select_move_constructor = std::conditional_t<std::is_move_constructible<devoid<T>>::value, value_storage_select_trivality<T>,
1049 value_storage_delete_move_constructor<value_storage_select_trivality<T>>>;
1051 using value_storage_select_copy_constructor = std::conditional_t<std::is_copy_constructible<devoid<T>>::value, value_storage_select_move_constructor<T>,
1052 value_storage_delete_copy_constructor<value_storage_select_move_constructor<T>>>;
1054 using value_storage_select_move_assignment = std::conditional_t<
1055 std::is_trivially_move_assignable<devoid<T>>::value, value_storage_select_copy_constructor<T>,
1056 std::conditional_t<std::is_move_assignable<devoid<T>>::value, value_storage_nontrivial_move_assignment<value_storage_select_copy_constructor<T>>,
1057 value_storage_delete_copy_assignment<value_storage_select_copy_constructor<T>>>>;
1059 using value_storage_select_copy_assignment = std::conditional_t<
1060 std::is_trivially_copy_assignable<devoid<T>>::value, value_storage_select_move_assignment<T>,
1061 std::conditional_t<std::is_copy_assignable<devoid<T>>::value, value_storage_nontrivial_copy_assignment<value_storage_select_move_assignment<T>>,
1062 value_storage_delete_copy_assignment<value_storage_select_move_assignment<T>>>>;
1063 template <class T> using value_storage_select_impl = value_storage_select_copy_assignment<T>;
1065 // Check is trivial in all ways except default constructibility
1066 // static_assert(std::is_trivial<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivial!");
1067 // static_assert(std::is_trivially_default_constructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially default
1068 // constructible!");
1069 static_assert(std::is_trivially_copyable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially copyable!");
1070 static_assert(std::is_trivially_assignable<value_storage_select_impl<int>, value_storage_select_impl<int>>::value,
1071 "value_storage_select_impl<int> is not trivially assignable!");
1072 static_assert(std::is_trivially_destructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially destructible!");
1073 static_assert(std::is_trivially_copy_constructible<value_storage_select_impl<int>>::value,
1074 "value_storage_select_impl<int> is not trivially copy constructible!");
1075 static_assert(std::is_trivially_move_constructible<value_storage_select_impl<int>>::value,
1076 "value_storage_select_impl<int> is not trivially move constructible!");
1077 static_assert(std::is_trivially_copy_assignable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially copy assignable!");
1078 static_assert(std::is_trivially_move_assignable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially move assignable!");
1079 // Also check is standard layout
1080 static_assert(std::is_standard_layout<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not a standard layout type!");
1082 } // namespace detail
1084 BOOST_OUTCOME_V2_NAMESPACE_END