Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-22 08:23:35

0001 /* Essentially an internal optional implementation :)
0002 (C) 2017-2024 Niall Douglas <http://www.nedproductions.biz/> (24 commits)
0003 File Created: June 2017
0004 
0005 
0006 Boost Software License - Version 1.0 - August 17th, 2003
0007 
0008 Permission is hereby granted, free of charge, to any person or organization
0009 obtaining a copy of the software and accompanying documentation covered by
0010 this license (the "Software") to use, reproduce, display, distribute,
0011 execute, and transmit the Software, and to prepare derivative works of the
0012 Software, and to permit third-parties to whom the Software is furnished to
0013 do so, all subject to the following:
0014 
0015 The copyright notices in the Software and this entire statement, including
0016 the above license grant, this restriction and the following disclaimer,
0017 must be included in all copies of the Software, in whole or in part, and
0018 all derivative works of the Software, unless such copies or derivative
0019 works are solely in the form of machine-executable object code generated by
0020 a source language processor.
0021 
0022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0023 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0024 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
0025 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
0026 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
0027 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0028 DEALINGS IN THE SOFTWARE.
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   // Helpers for move assigning to empty storage
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   // Prefer to use move or copy construction
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   // But fall back on default construction and move assign if necessary
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   // Void does nothing
0064   template <> struct move_assign_to_empty<void, false, false>
0065   {
0066     move_assign_to_empty(void *, void *) noexcept { /* nothing to assign */ }
0067   };
0068   template <> struct move_assign_to_empty<const void, false, false>
0069   {
0070     move_assign_to_empty(const void *, const void *) noexcept { /* nothing to assign */ }
0071   };
0072   // Helpers for copy assigning to empty storage
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   // Prefer to use copy construction
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   // But fall back on default construction and copy assign if necessary
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   // Void does nothing
0095   template <> struct copy_assign_to_empty<void, false, false>
0096   {
0097     copy_assign_to_empty(void *, void *) noexcept { /* nothing to assign */ }
0098   };
0099   template <> struct copy_assign_to_empty<const void, false, false>
0100   {
0101     copy_assign_to_empty(const void *, const void *) noexcept { /* nothing to assign */ }
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         // Try to put back a
0137         try
0138         {
0139           a = static_cast<T &&>(v);
0140           // fall through as all good
0141         }
0142         catch(...)
0143         {
0144           // failed to completely restore
0145           allgood = false;
0146           // throw away second exception
0147         }
0148         throw;  // rethrow original exception
0149       }
0150       // b has been moved to a, try to move v to b
0151       try
0152       {
0153         b = static_cast<T &&>(v);
0154       }
0155       catch(...)
0156       {
0157         // Try to restore a to b, and v to a
0158         try
0159         {
0160           b = static_cast<T &&>(a);
0161           a = static_cast<T &&>(v);
0162           // fall through as all good
0163         }
0164         catch(...)
0165         {
0166           // failed to completely restore
0167           allgood = false;
0168           // throw away second exception
0169         }
0170         throw;  // rethrow original exception
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         // Try to put back a, but only if we are still good
0187         if(allgood)
0188         {
0189           try
0190           {
0191             new(b) T(static_cast<T &&>(*a));
0192             // fall through as all good
0193           }
0194           catch(...)
0195           {
0196             // failed to completely restore
0197             allgood = false;
0198             // throw away second exception
0199           }
0200           throw;  // rethrow original exception
0201         }
0202       }
0203     }
0204   };
0205 #endif
0206 }  // namespace detail
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 && /*unused*/)
0236   {
0237     BOOST_OUTCOME_ASSERT(false);  // NOLINT
0238 #if defined(__GNUC__) || defined(__clang__)
0239     __builtin_unreachable();
0240 #elif defined(_MSC_VER)
0241     __assume(0);
0242 #endif
0243   }
0244 
0245   /* Outcome v1 used a C bitfield whose values were tracked by compiler optimisers nicely,
0246   but that produces ICEs when used in constexpr.
0247 
0248   Outcome v2.0-v2.1 used a 32 bit integer and manually set and cleared bits. Unfortunately
0249   only GCC's optimiser tracks bit values during constant folding, and only per byte, and
0250   even then unreliably. https://wg21.link/P1886 "Error speed benchmarking" showed just how
0251   poorly clang and MSVC fails to optimise outcome-using code, if you manually set bits.
0252 
0253   Outcome v2.2 therefore uses an enum with fixed values, and constexpr manipulation functions
0254   to change the value to one of the enum's values. This is stupid to look at in source code,
0255   but it make clang's optimiser do the right thing, so it's worth it.
0256   */
0257   enum class status : uint16_t
0258   {
0259     // WARNING: These bits are not tracked by abi-dumper, but changing them will break ABI!
0260     // bits 0-5 in use.
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     // failed to complete a strong swap
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     // can errno be set from this error?
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     // value has been moved from
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};  // hooks::spare_storage()
0309 
0310     constexpr status_bitfield_type() = default;
0311     constexpr status_bitfield_type(status v) noexcept
0312         : status_value(v)
0313     {
0314     }  // NOLINT
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     //~status_bitfield_type() = default;  // Do NOT uncomment this, it breaks older clangs!
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   // Check is trivial in all ways except default constructibility
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   // Also check is standard layout
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 & /*unused*/) {}
0391 
0392 #ifdef _MSC_VER
0393 #pragma warning(push)
0394 #pragma warning(disable : 4127)  // conditional expression is constant
0395 #pragma warning(disable : 4624)  // destructor was implicitly defined as deleted
0396 #endif
0397   // Used if both T and E are trivial
0398   template <class T, class E> struct value_storage_trivial
0399   {
0400     using value_type = T;
0401     using error_type = E;
0402 
0403     // Disable in place construction if they are the same type
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;             // NOLINT
0427     value_storage_trivial(value_storage_trivial &&) = default;                  // NOLINT
0428     value_storage_trivial &operator=(const value_storage_trivial &) = default;  // NOLINT
0429     value_storage_trivial &operator=(value_storage_trivial &&) = default;       // NOLINT
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> /*unused*/,
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> /*unused*/, 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> /*unused*/,
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> /*unused*/, 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 /*unused*/ = {}) 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()))  // NOLINT
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 /*unused*/ = {}) 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()))  // NOLINT
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 /*unused*/ = {}) 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()))  // NOLINT
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 /*unused*/ = {}) 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()))  // NOLINT
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 /*unused*/ = {}) 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()))  // NOLINT
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 /*unused*/ = {}) 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()))  // NOLINT
0549     {
0550       _status = o._status;
0551     }
0552     constexpr void swap(value_storage_trivial &o) noexcept
0553     {
0554       // storage is trivial, so just use assignment
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   /* Used if T or E is non-trivial. The additional constexpr is injected in C++ 20 to enable Outcome to
0562   work in constexpr evaluation contexts in C++ 20 where non-trivial constexpr destructors are now allowed.
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;  // if reaches here, copy assignment is trivial
0599     value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default;       // NOLINT if reaches here, move assignment is trivial
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)  // NOLINT
0605     {
0606       if(o._status.have_value())
0607       {
0608         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));  // NOLINT
0609       }
0610       else if(o._status.have_error())
0611       {
0612         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));  // NOLINT
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);  // NOLINT
0626       }
0627       else if(o._status.have_error())
0628       {
0629         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error);  // NOLINT
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> /*unused*/,
0644                                                 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
0645         : _value(static_cast<Args &&>(args)...)  // NOLINT
0646         , _status(status::have_value)
0647     {
0648     }
0649     template <class U, class... Args>
0650     constexpr value_storage_nontrivial(in_place_type_t<_value_type> /*unused*/, 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> /*unused*/,
0658                                                 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
0659         : _status(status::have_error)
0660         , _error(static_cast<Args &&>(args)...)  // NOLINT
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> /*unused*/, 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 /*unused*/ = {}) 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 /*unused*/ = {}) 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 /*unused*/ = {}) 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 /*unused*/ = {}) 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 /*unused*/ = {}) 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_();  // NOLINT
0737       }
0738       else if(o._status.have_error())
0739       {
0740         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error);  // NOLINT
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 /*unused*/ = {}) 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_();  // NOLINT
0752       }
0753       else if(o._status.have_error())
0754       {
0755         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));  // NOLINT
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 /*unused*/ = {}) 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);  // NOLINT
0775       }
0776       else if(o._status.have_error())
0777       {
0778         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_();  // NOLINT
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 /*unused*/ = {}) 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));  // NOLINT
0790       }
0791       else if(o._status.have_error())
0792       {
0793         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_();  // NOLINT
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_();  // NOLINT
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_();  // NOLINT
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       // empty/empty
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       // value/value
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               // We lost one of the values
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       // error/error
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               // We lost one of the values
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       // Could be value/empty, error/empty, etc
0877       if(_status.have_value() && !o._status.have_error())
0878       {
0879         // Move construct me into other
0880         new(BOOST_OUTCOME_ADDRESS_OF(o._value)) _value_type_(static_cast<_value_type_ &&>(_value));  // NOLINT
0881         if(!trait::is_move_bitcopying<value_type>::value)
0882         {
0883           this->_value.~value_type();  // NOLINT
0884         }
0885         swap(_status, o._status);
0886         return;
0887       }
0888       if(o._status.have_value() && !_status.have_error())
0889       {
0890         // Move construct other into me
0891         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));  // NOLINT
0892         if(!trait::is_move_bitcopying<value_type>::value)
0893         {
0894           o._value.~value_type();  // NOLINT
0895         }
0896         swap(_status, o._status);
0897         return;
0898       }
0899       if(_status.have_error() && !o._status.have_value())
0900       {
0901         // Move construct me into other
0902         new(BOOST_OUTCOME_ADDRESS_OF(o._error)) _error_type_(static_cast<_error_type_ &&>(_error));  // NOLINT
0903         if(!trait::is_move_bitcopying<error_type>::value)
0904         {
0905           this->_error.~error_type();  // NOLINT
0906         }
0907         swap(_status, o._status);
0908         return;
0909       }
0910       if(o._status.have_error() && !_status.have_value())
0911       {
0912         // Move construct other into me
0913         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));  // NOLINT
0914         if(!trait::is_move_bitcopying<error_type>::value)
0915         {
0916           o._error.~error_type();  // NOLINT
0917         }
0918         swap(_status, o._status);
0919         return;
0920       }
0921       // It can now only be value/error, or error/value
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             // We lost one of the values
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       // Should never reach here
0957       make_ub(_value);
0958     }
0959   };
0960   template <class Base> struct value_storage_delete_copy_constructor : Base  // NOLINT
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;  // NOLINT
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;  // NOLINT
0970     ~value_storage_delete_copy_constructor() = default;
0971   };
0972   template <class Base> struct value_storage_delete_copy_assignment : Base  // NOLINT
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;  // NOLINT
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;  // NOLINT
0982     ~value_storage_delete_copy_assignment() = default;
0983   };
0984   template <class Base> struct value_storage_delete_move_assignment : Base  // NOLINT
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;  // NOLINT
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  // NOLINT
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  // NOLINT
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;  // NOLINT
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))))  // NOLINT
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);  // NOLINT
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);  // NOLINT
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_();  // NOLINT
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_();  // NOLINT
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_();  // NOLINT
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_();  // NOLINT
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       // Should never reach here
1108       make_ub(this->_value);
1109     }
1110   };
1111   template <class Base> struct value_storage_nontrivial_copy_assignment : Base  // NOLINT
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;              // NOLINT
1119     value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default;  // NOLINT
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;  // NOLINT
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;  // NOLINT
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_();  // NOLINT
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_();  // NOLINT
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_();  // NOLINT
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_();  // NOLINT
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       // Should never reach here
1200       make_ub(this->_value);
1201     }
1202   };
1203 #ifdef _MSC_VER
1204 #pragma warning(pop)
1205 #endif
1206 
1207   // is_trivially_copyable is true even if type is not copyable, so handle that here
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   // work around libstdc++ 7 bug
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   // Ability to do copy assigns needs more than just copy assignment
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   // Ability to do move assigns needs more than just move assignment
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   // Check is trivial in all ways except default constructibility
1260   // static_assert(std::is_trivial<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivial!");
1261   // static_assert(std::is_trivially_default_constructible<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not
1262   // trivially default constructible!");
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   // Also check is standard layout
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 }  // namespace detail
1280 
1281 BOOST_OUTCOME_V2_NAMESPACE_END
1282 
1283 #endif