Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:20:29

0001 /* Essentially an internal optional implementation :)
0002 (C) 2017-2023 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 #include <cassert>
0037 
0038 BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN
0039 
0040 namespace detail
0041 {
0042   // Helpers for move assigning to empty storage
0043   template <class T, bool isCopyOrMoveConstructible = std::is_copy_constructible<T>::value || std::is_move_constructible<T>::value,
0044             bool isDefaultConstructibleAndCopyOrMoveAssignable =
0045             std::is_default_constructible<T>::value && (std::is_copy_assignable<T>::value || std::is_move_assignable<T>::value)>
0046   struct move_assign_to_empty;
0047   // Prefer to use move or copy construction
0048   template <class T> struct move_assign_to_empty<T, true, false>
0049   {
0050     move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
0051   };
0052   template <class T> struct move_assign_to_empty<T, true, true>
0053   {
0054     move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
0055   };
0056   // But fall back on default construction and move assign if necessary
0057   template <class T> struct move_assign_to_empty<T, false, true>
0058   {
0059     move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_default_constructible<T>::value &&std::is_nothrow_move_assignable<T>::value)
0060     {
0061       new(dest) T;
0062       *dest = static_cast<T &&>(*o);
0063     }
0064   };
0065   // Void does nothing
0066   template <> struct move_assign_to_empty<void, false, false>
0067   {
0068     move_assign_to_empty(void *, void *) noexcept
0069     { /* nothing to assign */
0070     }
0071   };
0072   template <> struct move_assign_to_empty<const void, false, false>
0073   {
0074     move_assign_to_empty(const void *, const void *) noexcept
0075     { /* nothing to assign */
0076     }
0077   };
0078   // Helpers for copy assigning to empty storage
0079   template <class T, bool isCopyConstructible = std::is_copy_constructible<T>::value,
0080             bool isDefaultConstructibleAndCopyAssignable = std::is_default_constructible<T>::value &&std::is_copy_assignable<T>::value>
0081   struct copy_assign_to_empty;
0082   // Prefer to use copy construction
0083   template <class T> struct copy_assign_to_empty<T, true, false>
0084   {
0085     copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
0086   };
0087   template <class T> struct copy_assign_to_empty<T, true, true>
0088   {
0089     copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
0090   };
0091   // But fall back on default construction and copy assign if necessary
0092   template <class T> struct copy_assign_to_empty<T, false, true>
0093   {
0094     copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_default_constructible<T>::value &&std::is_nothrow_copy_assignable<T>::value)
0095     {
0096       new(dest) T;
0097       *dest = *o;
0098     }
0099   };
0100   // Void does nothing
0101   template <> struct copy_assign_to_empty<void, false, false>
0102   {
0103     copy_assign_to_empty(void *, void *) noexcept
0104     { /* nothing to assign */
0105     }
0106   };
0107   template <> struct copy_assign_to_empty<const void, false, false>
0108   {
0109     copy_assign_to_empty(const void *, const void *) noexcept
0110     { /* nothing to assign */
0111     }
0112   };
0113 
0114   template <class T, bool nothrow> struct strong_swap_impl
0115   {
0116     constexpr strong_swap_impl(bool &allgood, T &a, T &b)
0117     {
0118       allgood = true;
0119       using std::swap;
0120       swap(a, b);
0121     }
0122   };
0123   template <class T, bool nothrow> struct strong_placement_impl
0124   {
0125     template <class F> constexpr strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
0126     {
0127       allgood = true;
0128       new(a) T(static_cast<T &&>(*b));
0129       b->~T();
0130       f();
0131     }
0132   };
0133 #ifndef BOOST_NO_EXCEPTIONS
0134   template <class T> struct strong_swap_impl<T, false>
0135   {
0136     strong_swap_impl(bool &allgood, T &a, T &b)
0137     {
0138       allgood = true;
0139       T v(static_cast<T &&>(a));
0140       try
0141       {
0142         a = static_cast<T &&>(b);
0143       }
0144       catch(...)
0145       {
0146         // Try to put back a
0147         try
0148         {
0149           a = static_cast<T &&>(v);
0150           // fall through as all good
0151         }
0152         catch(...)
0153         {
0154           // failed to completely restore
0155           allgood = false;
0156           // throw away second exception
0157         }
0158         throw;  // rethrow original exception
0159       }
0160       // b has been moved to a, try to move v to b
0161       try
0162       {
0163         b = static_cast<T &&>(v);
0164       }
0165       catch(...)
0166       {
0167         // Try to restore a to b, and v to a
0168         try
0169         {
0170           b = static_cast<T &&>(a);
0171           a = static_cast<T &&>(v);
0172           // fall through as all good
0173         }
0174         catch(...)
0175         {
0176           // failed to completely restore
0177           allgood = false;
0178           // throw away second exception
0179         }
0180         throw;  // rethrow original exception
0181       }
0182     }
0183   };
0184   template <class T> struct strong_placement_impl<T, false>
0185   {
0186     template <class F> strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
0187     {
0188       new(a) T(static_cast<T &&>(*b));
0189       try
0190       {
0191         b->~T();
0192         f();
0193       }
0194       catch(...)
0195       {
0196         // Try to put back a, but only if we are still good
0197         if(allgood)
0198         {
0199           try
0200           {
0201             new(b) T(static_cast<T &&>(*a));
0202             // fall through as all good
0203           }
0204           catch(...)
0205           {
0206             // failed to completely restore
0207             allgood = false;
0208             // throw away second exception
0209           }
0210           throw;  // rethrow original exception
0211         }
0212       }
0213     }
0214   };
0215 #endif
0216 }  // namespace detail
0217 
0218 /*!
0219  */
0220 BOOST_OUTCOME_TEMPLATE(class T)
0221 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
0222 constexpr inline void strong_swap(bool &allgood, T &a, T &b) noexcept(detail::is_nothrow_swappable<T>::value)
0223 {
0224   detail::strong_swap_impl<T, detail::is_nothrow_swappable<T>::value>(allgood, a, b);
0225 }
0226 /*!
0227  */
0228 BOOST_OUTCOME_TEMPLATE(class T, class F)
0229 BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
0230 constexpr inline void strong_placement(bool &allgood, T *a, T *b, F &&f) noexcept(std::is_nothrow_move_constructible<T>::value)
0231 {
0232   detail::strong_placement_impl<T, std::is_nothrow_move_constructible<T>::value>(allgood, a, b, static_cast<F &&>(f));
0233 }
0234 
0235 namespace detail
0236 {
0237   template <class T>
0238   constexpr
0239 #ifdef _MSC_VER
0240   __declspec(noreturn)
0241 #elif defined(__GNUC__) || defined(__clang__)
0242         __attribute__((noreturn))
0243 #endif
0244   void make_ub(T && /*unused*/)
0245   {
0246     assert(false);  // NOLINT
0247 #if defined(__GNUC__) || defined(__clang__)
0248     __builtin_unreachable();
0249 #elif defined(_MSC_VER)
0250     __assume(0);
0251 #endif
0252   }
0253 
0254   /* Outcome v1 used a C bitfield whose values were tracked by compiler optimisers nicely,
0255   but that produces ICEs when used in constexpr.
0256 
0257   Outcome v2.0-v2.1 used a 32 bit integer and manually set and cleared bits. Unfortunately
0258   only GCC's optimiser tracks bit values during constant folding, and only per byte, and
0259   even then unreliably. https://wg21.link/P1886 "Error speed benchmarking" showed just how
0260   poorly clang and MSVC fails to optimise outcome-using code, if you manually set bits.
0261 
0262   Outcome v2.2 therefore uses an enum with fixed values, and constexpr manipulation functions
0263   to change the value to one of the enum's values. This is stupid to look at in source code,
0264   but it make clang's optimiser do the right thing, so it's worth it.
0265   */
0266 #define BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS 0
0267   enum class status : uint16_t
0268   {
0269     // WARNING: These bits are not tracked by abi-dumper, but changing them will break ABI!
0270     none = 0,
0271 
0272     have_value = (1U << 0U),
0273     have_error = (1U << 1U),
0274     have_exception = (2U << 1U),
0275     have_error_exception = (3U << 1U),
0276 
0277     // failed to complete a strong swap
0278     have_lost_consistency = (1U << 3U),
0279     have_value_lost_consistency = (1U << 0U) | (1U << 3U),
0280     have_error_lost_consistency = (1U << 1U) | (1U << 3U),
0281     have_exception_lost_consistency = (2U << 1U) | (1U << 3U),
0282     have_error_exception_lost_consistency = (3U << 1U) | (1U << 3U),
0283 
0284     // can errno be set from this error?
0285     have_error_is_errno = (1U << 4U),
0286     have_error_error_is_errno = (1U << 1U) | (1U << 4U),
0287     have_error_exception_error_is_errno = (3U << 1U) | (1U << 4U),
0288 
0289     have_error_lost_consistency_error_is_errno = (1U << 1U) | (1U << 3U) | (1U << 4U),
0290     have_error_exception_lost_consistency_error_is_errno = (3U << 1U) | (1U << 3U) | (1U << 4U),
0291 
0292     // value has been moved from
0293     have_moved_from = (1U << 5U)
0294   };
0295   struct status_bitfield_type
0296   {
0297     status status_value{status::none};
0298     uint16_t spare_storage_value{0};  // hooks::spare_storage()
0299 
0300     constexpr status_bitfield_type() = default;
0301     constexpr status_bitfield_type(status v) noexcept
0302         : status_value(v)
0303     {
0304     }  // NOLINT
0305     constexpr status_bitfield_type(status v, uint16_t s) noexcept
0306         : status_value(v)
0307         , spare_storage_value(s)
0308     {
0309     }
0310     constexpr status_bitfield_type(const status_bitfield_type &) = default;
0311     constexpr status_bitfield_type(status_bitfield_type &&) = default;
0312     constexpr status_bitfield_type &operator=(const status_bitfield_type &) = default;
0313     constexpr status_bitfield_type &operator=(status_bitfield_type &&) = default;
0314     //~status_bitfield_type() = default;  // Do NOT uncomment this, it breaks older clangs!
0315 
0316     constexpr bool have_value() const noexcept
0317     {
0318 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0319       return (status_value == status::have_value)                      //
0320              || (status_value == status::have_value_lost_consistency)  //
0321       ;
0322 #else
0323       return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_value)) != 0;
0324 #endif
0325     }
0326     constexpr bool have_error() const noexcept
0327     {
0328 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0329       return (status_value == status::have_error)                                               //
0330              || (status_value == status::have_error_exception)                                  //
0331              || (status_value == status::have_error_lost_consistency)                           //
0332              || (status_value == status::have_error_exception_lost_consistency)                 //
0333              || (status_value == status::have_error_error_is_errno)                             //
0334              || (status_value == status::have_error_exception_error_is_errno)                   //
0335              || (status_value == status::have_error_lost_consistency_error_is_errno)            //
0336              || (status_value == status::have_error_exception_lost_consistency_error_is_errno)  //
0337       ;
0338 #else
0339       return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error)) != 0;
0340 #endif
0341     }
0342     constexpr bool have_exception() const noexcept
0343     {
0344 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0345       return (status_value == status::have_exception)                                           //
0346              || (status_value == status::have_error_exception)                                  //
0347              || (status_value == status::have_exception_lost_consistency)                       //
0348              || (status_value == status::have_error_exception_lost_consistency)                 //
0349              || (status_value == status::have_error_exception_error_is_errno)                   //
0350              || (status_value == status::have_error_exception_lost_consistency_error_is_errno)  //
0351       ;
0352 #else
0353       return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_exception)) != 0;
0354 #endif
0355     }
0356     constexpr bool have_lost_consistency() const noexcept
0357     {
0358 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0359       return (status_value == status::have_value_lost_consistency)                              //
0360              || (status_value == status::have_error_lost_consistency)                           //
0361              || (status_value == status::have_exception_lost_consistency)                       //
0362              || (status_value == status::have_error_lost_consistency_error_is_errno)            //
0363              || (status_value == status::have_error_exception_lost_consistency_error_is_errno)  //
0364       ;
0365 #else
0366       return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_lost_consistency)) != 0;
0367 #endif
0368     }
0369     constexpr bool have_error_is_errno() const noexcept
0370     {
0371 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0372       return (status_value == status::have_error_error_is_errno)                                //
0373              || (status_value == status::have_error_exception_error_is_errno)                   //
0374              || (status_value == status::have_error_lost_consistency_error_is_errno)            //
0375              || (status_value == status::have_error_exception_lost_consistency_error_is_errno)  //
0376       ;
0377 #else
0378       return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error_is_errno)) != 0;
0379 #endif
0380     }
0381     constexpr bool have_moved_from() const noexcept
0382     {
0383 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0384 #error Fixme
0385 #else
0386       return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_moved_from)) != 0;
0387 #endif
0388     }
0389 
0390     constexpr status_bitfield_type &set_have_value(bool v) noexcept
0391     {
0392 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0393       switch(status_value)
0394       {
0395       case status::none:
0396         if(v)
0397         {
0398           status_value = status::have_value;
0399         }
0400         break;
0401       case status::have_value:
0402         if(!v)
0403         {
0404           status_value = status::none;
0405         }
0406         break;
0407       case status::have_error:
0408         if(v)
0409         {
0410           make_ub(*this);
0411         }
0412         break;
0413       case status::have_exception:
0414         if(v)
0415         {
0416           make_ub(*this);
0417         }
0418         break;
0419       case status::have_error_exception:
0420         if(v)
0421         {
0422           make_ub(*this);
0423         }
0424         break;
0425       case status::have_value_lost_consistency:
0426         if(!v)
0427         {
0428           status_value = status::none;
0429         }
0430         break;
0431       case status::have_error_lost_consistency:
0432         if(v)
0433         {
0434           make_ub(*this);
0435         }
0436         break;
0437       case status::have_exception_lost_consistency:
0438         if(v)
0439         {
0440           make_ub(*this);
0441         }
0442         break;
0443       case status::have_error_exception_lost_consistency:
0444         if(v)
0445         {
0446           make_ub(*this);
0447         }
0448         break;
0449       case status::have_error_error_is_errno:
0450         if(v)
0451         {
0452           make_ub(*this);
0453         }
0454         break;
0455       case status::have_error_exception_error_is_errno:
0456         if(v)
0457         {
0458           make_ub(*this);
0459         }
0460         break;
0461       case status::have_error_lost_consistency_error_is_errno:
0462         if(v)
0463         {
0464           make_ub(*this);
0465         }
0466         break;
0467       case status::have_error_exception_lost_consistency_error_is_errno:
0468         if(v)
0469         {
0470           make_ub(*this);
0471         }
0472         break;
0473       }
0474 #else
0475       status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_value)) :
0476                                              (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_value)));
0477 #endif
0478       return *this;
0479     }
0480     constexpr status_bitfield_type &set_have_error(bool v) noexcept
0481     {
0482 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0483       switch(status_value)
0484       {
0485       case status::none:
0486         if(v)
0487         {
0488           status_value = status::have_error;
0489         }
0490         break;
0491       case status::have_value:
0492         if(v)
0493         {
0494           make_ub(*this);
0495         }
0496         break;
0497       case status::have_error:
0498         if(!v)
0499         {
0500           status_value = status::none;
0501         }
0502         break;
0503       case status::have_exception:
0504         if(v)
0505         {
0506           status_value = status::have_error_exception;
0507         }
0508         break;
0509       case status::have_error_exception:
0510         if(!v)
0511         {
0512           status_value = status::have_exception;
0513         }
0514         break;
0515       case status::have_value_lost_consistency:
0516         if(v)
0517         {
0518           make_ub(*this);
0519         }
0520         break;
0521       case status::have_error_lost_consistency:
0522         if(!v)
0523         {
0524           status_value = status::none;
0525         }
0526         break;
0527       case status::have_exception_lost_consistency:
0528         if(v)
0529         {
0530           status_value = status::have_error_exception_lost_consistency;
0531         }
0532         break;
0533       case status::have_error_exception_lost_consistency:
0534         if(!v)
0535         {
0536           status_value = status::have_exception_lost_consistency;
0537         }
0538         break;
0539       case status::have_error_error_is_errno:
0540         if(!v)
0541         {
0542           status_value = status::none;
0543         }
0544         break;
0545       case status::have_error_exception_error_is_errno:
0546         if(!v)
0547         {
0548           status_value = status::have_exception;
0549         }
0550         break;
0551       case status::have_error_lost_consistency_error_is_errno:
0552         if(!v)
0553         {
0554           status_value = status::none;
0555         }
0556         break;
0557       case status::have_error_exception_lost_consistency_error_is_errno:
0558         if(!v)
0559         {
0560           status_value = status::have_exception_lost_consistency;
0561         }
0562         break;
0563       }
0564 #else
0565       status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error)) :
0566                                              (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error)));
0567 #endif
0568       return *this;
0569     }
0570     constexpr status_bitfield_type &set_have_exception(bool v) noexcept
0571     {
0572 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0573       switch(status_value)
0574       {
0575       case status::none:
0576         if(v)
0577         {
0578           status_value = status::have_exception;
0579         }
0580         break;
0581       case status::have_value:
0582         if(v)
0583         {
0584           make_ub(*this);
0585         }
0586         break;
0587       case status::have_error:
0588         if(v)
0589         {
0590           status_value = status::have_error_exception;
0591         }
0592         break;
0593       case status::have_exception:
0594         if(!v)
0595         {
0596           status_value = status::none;
0597         }
0598         break;
0599       case status::have_error_exception:
0600         if(!v)
0601         {
0602           status_value = status::have_error;
0603         }
0604         break;
0605       case status::have_value_lost_consistency:
0606         if(v)
0607         {
0608           make_ub(*this);
0609         }
0610         break;
0611       case status::have_error_lost_consistency:
0612         if(v)
0613         {
0614           status_value = status::have_error_exception_lost_consistency;
0615         }
0616         break;
0617       case status::have_exception_lost_consistency:
0618         if(!v)
0619         {
0620           status_value = status::none;
0621         }
0622         break;
0623       case status::have_error_exception_lost_consistency:
0624         if(!v)
0625         {
0626           status_value = status::have_error_lost_consistency;
0627         }
0628         break;
0629       case status::have_error_error_is_errno:
0630         if(v)
0631         {
0632           status_value = status::have_error_exception_error_is_errno;
0633         }
0634         break;
0635       case status::have_error_exception_error_is_errno:
0636         if(!v)
0637         {
0638           status_value = status::have_error_error_is_errno;
0639         }
0640         break;
0641       case status::have_error_lost_consistency_error_is_errno:
0642         if(v)
0643         {
0644           status_value = status::have_error_exception_lost_consistency_error_is_errno;
0645         }
0646         break;
0647       case status::have_error_exception_lost_consistency_error_is_errno:
0648         if(!v)
0649         {
0650           status_value = status::have_error_lost_consistency_error_is_errno;
0651         }
0652         break;
0653       }
0654 #else
0655       status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_exception)) :
0656                                              (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_exception)));
0657 #endif
0658       return *this;
0659     }
0660     constexpr status_bitfield_type &set_have_error_is_errno(bool v) noexcept
0661     {
0662 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0663       switch(status_value)
0664       {
0665       case status::none:
0666         make_ub(*this);
0667         break;
0668       case status::have_value:
0669         make_ub(*this);
0670         break;
0671       case status::have_error:
0672         if(v)
0673         {
0674           status_value = status::have_error_error_is_errno;
0675         }
0676         break;
0677       case status::have_exception:
0678         make_ub(*this);
0679         break;
0680       case status::have_error_exception:
0681         if(v)
0682         {
0683           status_value = status::have_error_exception_error_is_errno;
0684         }
0685         break;
0686       case status::have_value_lost_consistency:
0687         make_ub(*this);
0688         break;
0689       case status::have_error_lost_consistency:
0690         if(v)
0691         {
0692           status_value = status::have_error_lost_consistency_error_is_errno;
0693         }
0694         break;
0695       case status::have_exception_lost_consistency:
0696         make_ub(*this);
0697         break;
0698       case status::have_error_exception_lost_consistency:
0699         if(v)
0700         {
0701           status_value = status::have_error_exception_lost_consistency_error_is_errno;
0702         }
0703         break;
0704       case status::have_error_error_is_errno:
0705         if(!v)
0706         {
0707           status_value = status::have_error;
0708         }
0709         break;
0710       case status::have_error_exception_error_is_errno:
0711         if(!v)
0712         {
0713           status_value = status::have_error_exception;
0714         }
0715         break;
0716       case status::have_error_lost_consistency_error_is_errno:
0717         if(!v)
0718         {
0719           status_value = status::have_error_lost_consistency;
0720         }
0721         break;
0722       case status::have_error_exception_lost_consistency_error_is_errno:
0723         if(!v)
0724         {
0725           status_value = status::have_error_exception_lost_consistency;
0726         }
0727         break;
0728       }
0729 #else
0730       status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error_is_errno)) :
0731                                              (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error_is_errno)));
0732 #endif
0733       return *this;
0734     }
0735     constexpr status_bitfield_type &set_have_lost_consistency(bool v) noexcept
0736     {
0737 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0738       switch(status_value)
0739       {
0740       case status::none:
0741         if(v)
0742         {
0743           make_ub(*this);
0744         }
0745         break;
0746       case status::have_value:
0747         if(v)
0748         {
0749           status_value = status::have_value_lost_consistency;
0750         }
0751         break;
0752       case status::have_error:
0753         if(v)
0754         {
0755           status_value = status::have_error_lost_consistency;
0756         }
0757         break;
0758       case status::have_exception:
0759         if(v)
0760         {
0761           status_value = status::have_exception_lost_consistency;
0762         }
0763         break;
0764       case status::have_error_exception:
0765         if(v)
0766         {
0767           status_value = status::have_error_exception_lost_consistency;
0768         }
0769         break;
0770       case status::have_value_lost_consistency:
0771         if(!v)
0772         {
0773           status_value = status::have_value;
0774         }
0775         break;
0776       case status::have_error_lost_consistency:
0777         if(!v)
0778         {
0779           status_value = status::have_error;
0780         }
0781         break;
0782       case status::have_exception_lost_consistency:
0783         if(!v)
0784         {
0785           status_value = status::have_exception;
0786         }
0787         break;
0788       case status::have_error_exception_lost_consistency:
0789         if(!v)
0790         {
0791           status_value = status::have_error_exception;
0792         }
0793         break;
0794       case status::have_error_error_is_errno:
0795         if(v)
0796         {
0797           status_value = status::have_error_lost_consistency_error_is_errno;
0798         }
0799         break;
0800       case status::have_error_exception_error_is_errno:
0801         if(v)
0802         {
0803           status_value = status::have_error_exception_lost_consistency_error_is_errno;
0804         }
0805         break;
0806       case status::have_error_lost_consistency_error_is_errno:
0807         if(!v)
0808         {
0809           status_value = status::have_error_exception_error_is_errno;
0810         }
0811         break;
0812       case status::have_error_exception_lost_consistency_error_is_errno:
0813         if(!v)
0814         {
0815           status_value = status::have_error_exception_error_is_errno;
0816         }
0817         break;
0818       }
0819 #else
0820       status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_lost_consistency)) :
0821                                              (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_lost_consistency)));
0822 #endif
0823       return *this;
0824     }
0825     constexpr status_bitfield_type &set_have_moved_from(bool v) noexcept
0826     {
0827 #if BOOST_OUTCOME_USE_CONSTEXPR_ENUM_STATUS
0828 #error Fixme
0829 #else
0830       status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_moved_from)) :
0831                                              (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_moved_from)));
0832 #endif
0833       return *this;
0834     }
0835   };
0836 #if !defined(NDEBUG)
0837   // Check is trivial in all ways except default constructibility
0838   static_assert(sizeof(status_bitfield_type) == 4, "status_bitfield_type is not sized 4 bytes!");
0839   static_assert(std::is_trivially_copyable<status_bitfield_type>::value, "status_bitfield_type is not trivially copyable!");
0840   static_assert(std::is_trivially_assignable<status_bitfield_type, status_bitfield_type>::value, "status_bitfield_type is not trivially assignable!");
0841   static_assert(std::is_trivially_destructible<status_bitfield_type>::value, "status_bitfield_type is not trivially destructible!");
0842   static_assert(std::is_trivially_copy_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially copy constructible!");
0843   static_assert(std::is_trivially_move_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially move constructible!");
0844   static_assert(std::is_trivially_copy_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially copy assignable!");
0845   static_assert(std::is_trivially_move_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially move assignable!");
0846   // Also check is standard layout
0847   static_assert(std::is_standard_layout<status_bitfield_type>::value, "status_bitfield_type is not a standard layout type!");
0848 #endif
0849 
0850   template <class State> constexpr inline void _set_error_is_errno(State & /*unused*/) {}
0851 
0852 #ifdef _MSC_VER
0853 #pragma warning(push)
0854 #pragma warning(disable : 4127)  // conditional expression is constant
0855 #pragma warning(disable : 4624)  // destructor was implicitly defined as deleted
0856 #endif
0857   // Used if both T and E are trivial
0858   template <class T, class E> struct value_storage_trivial
0859   {
0860     using value_type = T;
0861     using error_type = E;
0862 
0863     // Disable in place construction if they are the same type
0864     struct disable_in_place_value_type
0865     {
0866     };
0867     struct disable_in_place_error_type
0868     {
0869     };
0870     using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
0871     using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
0872     using _value_type_ = devoid<value_type>;
0873     using _error_type_ = devoid<error_type>;
0874 
0875     union
0876     {
0877       empty_type _empty;
0878       _value_type_ _value;
0879       _error_type_ _error;
0880     };
0881     status_bitfield_type _status;
0882     constexpr value_storage_trivial() noexcept
0883         : _empty{}
0884     {
0885     }
0886     value_storage_trivial(const value_storage_trivial &) = default;             // NOLINT
0887     value_storage_trivial(value_storage_trivial &&) = default;                  // NOLINT
0888     value_storage_trivial &operator=(const value_storage_trivial &) = default;  // NOLINT
0889     value_storage_trivial &operator=(value_storage_trivial &&) = default;       // NOLINT
0890     ~value_storage_trivial() = default;
0891     constexpr explicit value_storage_trivial(status_bitfield_type status)
0892         : _empty()
0893         , _status(status)
0894     {
0895     }
0896     template <class... Args>
0897     constexpr explicit value_storage_trivial(in_place_type_t<_value_type> /*unused*/,
0898                                              Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
0899         : _value(static_cast<Args &&>(args)...)
0900         , _status(status::have_value)
0901     {
0902     }
0903     template <class U, class... Args>
0904     constexpr value_storage_trivial(in_place_type_t<_value_type> /*unused*/, std::initializer_list<U> il,
0905                                     Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
0906         : _value(il, static_cast<Args &&>(args)...)
0907         , _status(status::have_value)
0908     {
0909     }
0910     template <class... Args>
0911     constexpr explicit value_storage_trivial(in_place_type_t<_error_type> /*unused*/,
0912                                              Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
0913         : _error(static_cast<Args &&>(args)...)
0914         , _status(status::have_error)
0915     {
0916       _set_error_is_errno(*this);
0917     }
0918     template <class U, class... Args>
0919     constexpr value_storage_trivial(in_place_type_t<_error_type> /*unused*/, std::initializer_list<U> il,
0920                                     Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
0921         : _error(il, static_cast<Args &&>(args)...)
0922         , _status(status::have_error)
0923     {
0924       _set_error_is_errno(*this);
0925     }
0926 
0927     struct nonvoid_converting_constructor_tag
0928     {
0929     };
0930     template <class U, class V>
0931     static constexpr bool enable_nonvoid_converting_constructor =
0932     !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value)  //
0933     && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
0934     BOOST_OUTCOME_TEMPLATE(class U, class V)
0935     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0936     constexpr explicit value_storage_trivial(const value_storage_trivial<U, V> &o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
0937     detail::is_nothrow_constructible<_value_type_, U> &&detail::is_nothrow_constructible<_error_type_, V>)
0938         : value_storage_trivial(o._status.have_value() ?
0939                                 value_storage_trivial(in_place_type<value_type>, o._value) :
0940                                 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial()))  // NOLINT
0941     {
0942       _status = o._status;
0943     }
0944     BOOST_OUTCOME_TEMPLATE(class U, class V)
0945     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
0946     constexpr explicit value_storage_trivial(value_storage_trivial<U, V> &&o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
0947     detail::is_nothrow_constructible<_value_type_, U> &&detail::is_nothrow_constructible<_error_type_, V>)
0948         : value_storage_trivial(
0949           o._status.have_value() ?
0950           value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
0951           (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial()))  // NOLINT
0952     {
0953       _status = o._status;
0954     }
0955 
0956     struct void_value_converting_constructor_tag
0957     {
0958     };
0959     template <class V>
0960     static constexpr bool enable_void_value_converting_constructor = std::is_default_constructible<value_type>::value &&detail::is_constructible<error_type, V>;
0961     BOOST_OUTCOME_TEMPLATE(class V)
0962     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
0963     constexpr explicit value_storage_trivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
0964     std::is_nothrow_default_constructible<_value_type_>::value &&detail::is_nothrow_constructible<_error_type_, V>)
0965         : value_storage_trivial(o._status.have_value() ?
0966                                 value_storage_trivial(in_place_type<value_type>) :
0967                                 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial()))  // NOLINT
0968     {
0969       _status = o._status;
0970     }
0971     BOOST_OUTCOME_TEMPLATE(class V)
0972     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
0973     constexpr explicit value_storage_trivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
0974     std::is_nothrow_default_constructible<_value_type_>::value &&detail::is_nothrow_constructible<_error_type_, V>)
0975         : value_storage_trivial(
0976           o._status.have_value() ?
0977           value_storage_trivial(in_place_type<value_type>) :
0978           (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial()))  // NOLINT
0979     {
0980       _status = o._status;
0981     }
0982 
0983     struct void_error_converting_constructor_tag
0984     {
0985     };
0986     template <class U>
0987     static constexpr bool enable_void_error_converting_constructor = std::is_default_constructible<error_type>::value &&detail::is_constructible<value_type, U>;
0988     BOOST_OUTCOME_TEMPLATE(class U)
0989     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
0990     constexpr explicit value_storage_trivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
0991     detail::is_nothrow_constructible<_value_type_, U> &&std::is_nothrow_default_constructible<_error_type_>::value)
0992         : value_storage_trivial(o._status.have_value() ?
0993                                 value_storage_trivial(in_place_type<value_type>, o._value) :
0994                                 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial()))  // NOLINT
0995     {
0996       _status = o._status;
0997     }
0998     BOOST_OUTCOME_TEMPLATE(class U)
0999     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
1000     constexpr explicit value_storage_trivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
1001     detail::is_nothrow_constructible<_value_type_, U> &&std::is_nothrow_default_constructible<_error_type_>::value)
1002         : value_storage_trivial(o._status.have_value() ?
1003                                 value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
1004                                 (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial()))  // NOLINT
1005     {
1006       _status = o._status;
1007     }
1008     constexpr void swap(value_storage_trivial &o) noexcept
1009     {
1010       // storage is trivial, so just use assignment
1011       auto temp = static_cast<value_storage_trivial &&>(*this);
1012       *this = static_cast<value_storage_trivial &&>(o);
1013       o = static_cast<value_storage_trivial &&>(temp);
1014     }
1015   };
1016 
1017   /* Used if T or E is non-trivial. The additional constexpr is injected in C++ 20 to enable Outcome to
1018   work in constexpr evaluation contexts in C++ 20 where non-trivial constexpr destructors are now allowed.
1019   */
1020   template <class T, class E> struct value_storage_nontrivial
1021   {
1022     using value_type = T;
1023     using error_type = E;
1024     struct disable_in_place_value_type
1025     {
1026     };
1027     struct disable_in_place_error_type
1028     {
1029     };
1030     using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
1031     using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
1032     using _value_type_ = devoid<value_type>;
1033     using _error_type_ = devoid<error_type>;
1034 
1035     union
1036     {
1037       empty_type _empty1;
1038       _value_type_ _value;
1039     };
1040     status_bitfield_type _status;
1041     union
1042     {
1043       empty_type _empty2;
1044       _error_type_ _error;
1045     };
1046 #if __cplusplus >= 202000L || _HAS_CXX20
1047     constexpr
1048 #endif
1049     value_storage_nontrivial() noexcept
1050         : _empty1{}
1051         , _empty2{}
1052     {
1053     }
1054     value_storage_nontrivial &operator=(const value_storage_nontrivial &) = default;  // if reaches here, copy assignment is trivial
1055     value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default;       // NOLINT if reaches here, move assignment is trivial
1056 #if __cplusplus >= 202000L || _HAS_CXX20
1057     constexpr
1058 #endif
1059     value_storage_nontrivial(value_storage_nontrivial &&o) noexcept(
1060     std::is_nothrow_move_constructible<_value_type_>::value &&std::is_nothrow_move_constructible<_error_type_>::value)  // NOLINT
1061     {
1062       if(o._status.have_value())
1063       {
1064         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));  // NOLINT
1065       }
1066       else if(o._status.have_error())
1067       {
1068         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));  // NOLINT
1069       }
1070       _status = o._status;
1071       o._status.set_have_moved_from(true);
1072     }
1073 #if __cplusplus >= 202000L || _HAS_CXX20
1074     constexpr
1075 #endif
1076     value_storage_nontrivial(const value_storage_nontrivial &o) noexcept(
1077     std::is_nothrow_copy_constructible<_value_type_>::value &&std::is_nothrow_copy_constructible<_error_type_>::value)
1078     {
1079       if(o._status.have_value())
1080       {
1081         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value);  // NOLINT
1082       }
1083       else if(o._status.have_error())
1084       {
1085         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error);  // NOLINT
1086       }
1087       _status = o._status;
1088     }
1089 #if __cplusplus >= 202000L || _HAS_CXX20
1090     constexpr
1091 #endif
1092     explicit value_storage_nontrivial(status_bitfield_type status)
1093         : _empty1()
1094         , _status(status)
1095         , _empty2()
1096     {
1097     }
1098     template <class... Args>
1099     constexpr explicit value_storage_nontrivial(in_place_type_t<_value_type> /*unused*/,
1100                                                 Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
1101         : _value(static_cast<Args &&>(args)...)  // NOLINT
1102         , _status(status::have_value)
1103     {
1104     }
1105     template <class U, class... Args>
1106     constexpr value_storage_nontrivial(in_place_type_t<_value_type> /*unused*/, std::initializer_list<U> il,
1107                                        Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
1108         : _value(il, static_cast<Args &&>(args)...)
1109         , _status(status::have_value)
1110     {
1111     }
1112     template <class... Args>
1113     constexpr explicit value_storage_nontrivial(in_place_type_t<_error_type> /*unused*/,
1114                                                 Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
1115         : _status(status::have_error)
1116         , _error(static_cast<Args &&>(args)...)  // NOLINT
1117     {
1118       _set_error_is_errno(*this);
1119     }
1120     template <class U, class... Args>
1121     constexpr value_storage_nontrivial(in_place_type_t<_error_type> /*unused*/, std::initializer_list<U> il,
1122                                        Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
1123         : _status(status::have_error)
1124         , _error(il, static_cast<Args &&>(args)...)
1125     {
1126       _set_error_is_errno(*this);
1127     }
1128 
1129     struct nonvoid_converting_constructor_tag
1130     {
1131     };
1132     template <class U, class V>
1133     static constexpr bool enable_nonvoid_converting_constructor =
1134     !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value)  //
1135     && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
1136     BOOST_OUTCOME_TEMPLATE(class U, class V)
1137     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1138     constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, V> &o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1139     detail::is_nothrow_constructible<_value_type_, U> &&detail::is_nothrow_constructible<_error_type_, V>)
1140         : value_storage_nontrivial(o._status.have_value() ?
1141                                    value_storage_nontrivial(in_place_type<value_type>, o._value) :
1142                                    (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
1143     {
1144       _status = o._status;
1145     }
1146     BOOST_OUTCOME_TEMPLATE(class U, class V)
1147     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1148     constexpr explicit value_storage_nontrivial(value_storage_trivial<U, V> &&o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1149     detail::is_nothrow_constructible<_value_type_, U> &&detail::is_nothrow_constructible<_error_type_, V>)
1150         : value_storage_nontrivial(
1151           o._status.have_value() ?
1152           value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
1153           (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
1154     {
1155       _status = o._status;
1156     }
1157     BOOST_OUTCOME_TEMPLATE(class U, class V)
1158     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1159     constexpr explicit value_storage_nontrivial(const value_storage_nontrivial<U, V> &o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1160     detail::is_nothrow_constructible<_value_type_, U> &&detail::is_nothrow_constructible<_error_type_, V>)
1161         : value_storage_nontrivial(o._status.have_value() ?
1162                                    value_storage_nontrivial(in_place_type<value_type>, o._value) :
1163                                    (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
1164     {
1165       _status = o._status;
1166     }
1167     BOOST_OUTCOME_TEMPLATE(class U, class V)
1168     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
1169     constexpr explicit value_storage_nontrivial(value_storage_nontrivial<U, V> &&o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
1170     detail::is_nothrow_constructible<_value_type_, U> &&detail::is_nothrow_constructible<_error_type_, V>)
1171         : value_storage_nontrivial(
1172           o._status.have_value() ?
1173           value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
1174           (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
1175     {
1176       _status = o._status;
1177     }
1178 
1179     struct void_value_converting_constructor_tag
1180     {
1181     };
1182     template <class V>
1183     static constexpr bool enable_void_value_converting_constructor = std::is_default_constructible<value_type>::value &&detail::is_constructible<error_type, V>;
1184     BOOST_OUTCOME_TEMPLATE(class V)
1185     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
1186     constexpr explicit value_storage_nontrivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
1187     std::is_nothrow_default_constructible<_value_type_>::value &&detail::is_nothrow_constructible<_error_type_, V>)
1188     {
1189       if(o._status.have_value())
1190       {
1191         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_();  // NOLINT
1192       }
1193       else if(o._status.have_error())
1194       {
1195         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error);  // NOLINT
1196       }
1197       _status = o._status;
1198     }
1199     BOOST_OUTCOME_TEMPLATE(class V)
1200     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
1201     constexpr explicit value_storage_nontrivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
1202     std::is_nothrow_default_constructible<_value_type_>::value &&detail::is_nothrow_constructible<_error_type_, V>)
1203     {
1204       if(o._status.have_value())
1205       {
1206         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_();  // NOLINT
1207       }
1208       else if(o._status.have_error())
1209       {
1210         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));  // NOLINT
1211       }
1212       _status = o._status;
1213       o._status.set_have_moved_from(true);
1214     }
1215 
1216     struct void_error_converting_constructor_tag
1217     {
1218     };
1219     template <class U>
1220     static constexpr bool enable_void_error_converting_constructor = std::is_default_constructible<error_type>::value &&detail::is_constructible<value_type, U>;
1221     BOOST_OUTCOME_TEMPLATE(class U)
1222     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
1223     constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
1224     detail::is_nothrow_constructible<_value_type_, U> &&std::is_nothrow_default_constructible<_error_type_>::value)
1225     {
1226       if(o._status.have_value())
1227       {
1228         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value);  // NOLINT
1229       }
1230       else if(o._status.have_error())
1231       {
1232         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_();  // NOLINT
1233       }
1234       _status = o._status;
1235     }
1236     BOOST_OUTCOME_TEMPLATE(class U)
1237     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
1238     constexpr explicit value_storage_nontrivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
1239     detail::is_nothrow_constructible<_value_type_, U> &&std::is_nothrow_default_constructible<_error_type_>::value)
1240     {
1241       if(o._status.have_value())
1242       {
1243         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));  // NOLINT
1244       }
1245       else if(o._status.have_error())
1246       {
1247         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_();  // NOLINT
1248       }
1249       _status = o._status;
1250       o._status.set_have_moved_from(true);
1251     }
1252 
1253 #if __cplusplus >= 202000L || _HAS_CXX20
1254     constexpr
1255 #endif
1256     ~value_storage_nontrivial() noexcept(std::is_nothrow_destructible<_value_type_>::value &&std::is_nothrow_destructible<_error_type_>::value)
1257     {
1258       if(this->_status.have_value())
1259       {
1260         if(!trait::is_move_bitcopying<value_type>::value || !this->_status.have_moved_from())
1261         {
1262           this->_value.~_value_type_();  // NOLINT
1263         }
1264         this->_status.set_have_value(false);
1265       }
1266       else if(this->_status.have_error())
1267       {
1268         if(!trait::is_move_bitcopying<error_type>::value || !this->_status.have_moved_from())
1269         {
1270           this->_error.~_error_type_();  // NOLINT
1271         }
1272         this->_status.set_have_error(false);
1273       }
1274     }
1275 #if __cplusplus >= 202000L || _HAS_CXX20
1276     constexpr
1277 #endif
1278     void
1279     swap(value_storage_nontrivial &o) noexcept(detail::is_nothrow_swappable<_value_type_>::value &&detail::is_nothrow_swappable<_error_type_>::value)
1280     {
1281       using std::swap;
1282       // empty/empty
1283       if(!_status.have_value() && !o._status.have_value() && !_status.have_error() && !o._status.have_error())
1284       {
1285         swap(_status, o._status);
1286         return;
1287       }
1288       // value/value
1289       if(_status.have_value() && o._status.have_value())
1290       {
1291         struct _
1292         {
1293           status_bitfield_type &a, &b;
1294           bool all_good{false};
1295           ~_()
1296           {
1297             if(!this->all_good)
1298             {
1299               // We lost one of the values
1300               this->a.set_have_lost_consistency(true);
1301               this->b.set_have_lost_consistency(true);
1302             }
1303           }
1304         } _{_status, o._status};
1305         strong_swap(_.all_good, _value, o._value);
1306         swap(_status, o._status);
1307         return;
1308       }
1309       // error/error
1310       if(_status.have_error() && o._status.have_error())
1311       {
1312         struct _
1313         {
1314           status_bitfield_type &a, &b;
1315           bool all_good{false};
1316           ~_()
1317           {
1318             if(!this->all_good)
1319             {
1320               // We lost one of the values
1321               this->a.set_have_lost_consistency(true);
1322               this->b.set_have_lost_consistency(true);
1323             }
1324           }
1325         } _{_status, o._status};
1326         strong_swap(_.all_good, _error, o._error);
1327         swap(_status, o._status);
1328         return;
1329       }
1330       // Could be value/empty, error/empty, etc
1331       if(_status.have_value() && !o._status.have_error())
1332       {
1333         // Move construct me into other
1334         new(BOOST_OUTCOME_ADDRESS_OF(o._value)) _value_type_(static_cast<_value_type_ &&>(_value));  // NOLINT
1335         if(!trait::is_move_bitcopying<value_type>::value)
1336         {
1337           this->_value.~value_type();  // NOLINT
1338         }
1339         swap(_status, o._status);
1340         return;
1341       }
1342       if(o._status.have_value() && !_status.have_error())
1343       {
1344         // Move construct other into me
1345         new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value));  // NOLINT
1346         if(!trait::is_move_bitcopying<value_type>::value)
1347         {
1348           o._value.~value_type();  // NOLINT
1349         }
1350         swap(_status, o._status);
1351         return;
1352       }
1353       if(_status.have_error() && !o._status.have_value())
1354       {
1355         // Move construct me into other
1356         new(BOOST_OUTCOME_ADDRESS_OF(o._error)) _error_type_(static_cast<_error_type_ &&>(_error));  // NOLINT
1357         if(!trait::is_move_bitcopying<error_type>::value)
1358         {
1359           this->_error.~error_type();  // NOLINT
1360         }
1361         swap(_status, o._status);
1362         return;
1363       }
1364       if(o._status.have_error() && !_status.have_value())
1365       {
1366         // Move construct other into me
1367         new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error));  // NOLINT
1368         if(!trait::is_move_bitcopying<error_type>::value)
1369         {
1370           o._error.~error_type();  // NOLINT
1371         }
1372         swap(_status, o._status);
1373         return;
1374       }
1375       // It can now only be value/error, or error/value
1376       struct _
1377       {
1378         status_bitfield_type &a, &b;
1379         _value_type_ *value, *o_value;
1380         _error_type_ *error, *o_error;
1381         bool all_good{true};
1382         ~_()
1383         {
1384           if(!this->all_good)
1385           {
1386             // We lost one of the values
1387             this->a.set_have_lost_consistency(true);
1388             this->b.set_have_lost_consistency(true);
1389           }
1390         }
1391       } _{_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)};
1392       if(_status.have_value() && o._status.have_error())
1393       {
1394         strong_placement(_.all_good, _.o_value, _.value, [&_] {    //
1395           strong_placement(_.all_good, _.error, _.o_error, [&_] {  //
1396             swap(_.a, _.b);                                        //
1397           });
1398         });
1399         return;
1400       }
1401       if(_status.have_error() && o._status.have_value())
1402       {
1403         strong_placement(_.all_good, _.o_error, _.error, [&_] {    //
1404           strong_placement(_.all_good, _.value, _.o_value, [&_] {  //
1405             swap(_.a, _.b);                                        //
1406           });
1407         });
1408         return;
1409       }
1410       // Should never reach here
1411       make_ub(_value);
1412     }
1413   };
1414   template <class Base> struct value_storage_delete_copy_constructor : Base  // NOLINT
1415   {
1416     using Base::Base;
1417     using value_type = typename Base::value_type;
1418     using error_type = typename Base::error_type;
1419     value_storage_delete_copy_constructor() = default;
1420     value_storage_delete_copy_constructor(const value_storage_delete_copy_constructor &) = delete;
1421     value_storage_delete_copy_constructor(value_storage_delete_copy_constructor &&) = default;  // NOLINT
1422     value_storage_delete_copy_constructor &operator=(const value_storage_delete_copy_constructor &o) = default;
1423     value_storage_delete_copy_constructor &operator=(value_storage_delete_copy_constructor &&o) = default;  // NOLINT
1424     ~value_storage_delete_copy_constructor() = default;
1425   };
1426   template <class Base> struct value_storage_delete_copy_assignment : Base  // NOLINT
1427   {
1428     using Base::Base;
1429     using value_type = typename Base::value_type;
1430     using error_type = typename Base::error_type;
1431     value_storage_delete_copy_assignment() = default;
1432     value_storage_delete_copy_assignment(const value_storage_delete_copy_assignment &) = default;
1433     value_storage_delete_copy_assignment(value_storage_delete_copy_assignment &&) = default;  // NOLINT
1434     value_storage_delete_copy_assignment &operator=(const value_storage_delete_copy_assignment &o) = delete;
1435     value_storage_delete_copy_assignment &operator=(value_storage_delete_copy_assignment &&o) = default;  // NOLINT
1436     ~value_storage_delete_copy_assignment() = default;
1437   };
1438   template <class Base> struct value_storage_delete_move_assignment : Base  // NOLINT
1439   {
1440     using Base::Base;
1441     using value_type = typename Base::value_type;
1442     using error_type = typename Base::error_type;
1443     value_storage_delete_move_assignment() = default;
1444     value_storage_delete_move_assignment(const value_storage_delete_move_assignment &) = default;
1445     value_storage_delete_move_assignment(value_storage_delete_move_assignment &&) = default;  // NOLINT
1446     value_storage_delete_move_assignment &operator=(const value_storage_delete_move_assignment &o) = default;
1447     value_storage_delete_move_assignment &operator=(value_storage_delete_move_assignment &&o) = delete;
1448     ~value_storage_delete_move_assignment() = default;
1449   };
1450   template <class Base> struct value_storage_delete_move_constructor : Base  // NOLINT
1451   {
1452     using Base::Base;
1453     using value_type = typename Base::value_type;
1454     using error_type = typename Base::error_type;
1455     value_storage_delete_move_constructor() = default;
1456     value_storage_delete_move_constructor(const value_storage_delete_move_constructor &) = default;
1457     value_storage_delete_move_constructor(value_storage_delete_move_constructor &&) = delete;
1458     value_storage_delete_move_constructor &operator=(const value_storage_delete_move_constructor &o) = default;
1459     value_storage_delete_move_constructor &operator=(value_storage_delete_move_constructor &&o) = default;
1460     ~value_storage_delete_move_constructor() = default;
1461   };
1462   template <class Base> struct value_storage_nontrivial_move_assignment : Base  // NOLINT
1463   {
1464     using Base::Base;
1465     using value_type = typename Base::value_type;
1466     using error_type = typename Base::error_type;
1467     value_storage_nontrivial_move_assignment() = default;
1468     value_storage_nontrivial_move_assignment(const value_storage_nontrivial_move_assignment &) = default;
1469     value_storage_nontrivial_move_assignment(value_storage_nontrivial_move_assignment &&) = default;  // NOLINT
1470     value_storage_nontrivial_move_assignment &operator=(const value_storage_nontrivial_move_assignment &o) = default;
1471     ~value_storage_nontrivial_move_assignment() = default;
1472 #if __cplusplus >= 202000L || _HAS_CXX20
1473     constexpr
1474 #endif
1475     value_storage_nontrivial_move_assignment &
1476     operator=(value_storage_nontrivial_move_assignment &&o) noexcept(
1477     std::is_nothrow_move_assignable<value_type>::value &&std::is_nothrow_move_assignable<error_type>::value &&noexcept(move_assign_to_empty<value_type>(
1478     static_cast<value_type *>(nullptr),
1479     static_cast<value_type *>(nullptr))) &&noexcept(move_assign_to_empty<error_type>(static_cast<error_type *>(nullptr),
1480                                                                                      static_cast<error_type *>(nullptr))))  // NOLINT
1481     {
1482       using _value_type_ = typename Base::_value_type_;
1483       using _error_type_ = typename Base::_error_type_;
1484       if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1485       {
1486         this->_status = o._status;
1487         o._status.set_have_moved_from(true);
1488         return *this;
1489       }
1490       if(this->_status.have_value() && o._status.have_value())
1491       {
1492         this->_value = static_cast<_value_type_ &&>(o._value);  // NOLINT
1493         this->_status = o._status;
1494         o._status.set_have_moved_from(true);
1495         return *this;
1496       }
1497       if(this->_status.have_error() && o._status.have_error())
1498       {
1499         this->_error = static_cast<_error_type_ &&>(o._error);  // NOLINT
1500         this->_status = o._status;
1501         o._status.set_have_moved_from(true);
1502         return *this;
1503       }
1504       if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
1505       {
1506         if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1507         {
1508           this->_value.~_value_type_();  // NOLINT
1509         }
1510         this->_status = o._status;
1511         o._status.set_have_moved_from(true);
1512         return *this;
1513       }
1514       if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
1515       {
1516         move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1517         this->_status = o._status;
1518         o._status.set_have_moved_from(true);
1519         return *this;
1520       }
1521       if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1522       {
1523         if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1524         {
1525           this->_error.~_error_type_();  // NOLINT
1526         }
1527         this->_status = o._status;
1528         o._status.set_have_moved_from(true);
1529         return *this;
1530       }
1531       if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
1532       {
1533         move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1534         this->_status = o._status;
1535         o._status.set_have_moved_from(true);
1536         return *this;
1537       }
1538       if(this->_status.have_value() && o._status.have_error())
1539       {
1540         if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1541         {
1542           this->_value.~_value_type_();  // NOLINT
1543         }
1544         move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1545         this->_status = o._status;
1546         o._status.set_have_moved_from(true);
1547         return *this;
1548       }
1549       if(this->_status.have_error() && o._status.have_value())
1550       {
1551         if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1552         {
1553           this->_error.~_error_type_();  // NOLINT
1554         }
1555         move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1556         this->_status = o._status;
1557         o._status.set_have_moved_from(true);
1558         return *this;
1559       }
1560       // Should never reach here
1561       make_ub(this->_value);
1562     }
1563   };
1564   template <class Base> struct value_storage_nontrivial_copy_assignment : Base  // NOLINT
1565   {
1566     using Base::Base;
1567     using value_type = typename Base::value_type;
1568     using error_type = typename Base::error_type;
1569     value_storage_nontrivial_copy_assignment() = default;
1570     value_storage_nontrivial_copy_assignment(const value_storage_nontrivial_copy_assignment &) = default;
1571     value_storage_nontrivial_copy_assignment(value_storage_nontrivial_copy_assignment &&) = default;              // NOLINT
1572     value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default;  // NOLINT
1573     ~value_storage_nontrivial_copy_assignment() = default;
1574 #if __cplusplus >= 202000L || _HAS_CXX20
1575     constexpr
1576 #endif
1577     value_storage_nontrivial_copy_assignment &
1578     operator=(const value_storage_nontrivial_copy_assignment &o) noexcept(
1579     std::is_nothrow_copy_assignable<value_type>::value &&std::is_nothrow_copy_assignable<error_type>::value &&noexcept(copy_assign_to_empty<value_type>(
1580     static_cast<value_type *>(nullptr), static_cast<value_type *>(nullptr))) &&noexcept(copy_assign_to_empty<error_type>(static_cast<error_type *>(nullptr),
1581                                                                                                                          static_cast<error_type *>(nullptr))))
1582     {
1583       using _value_type_ = typename Base::_value_type_;
1584       using _error_type_ = typename Base::_error_type_;
1585       if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1586       {
1587         this->_status = o._status;
1588         return *this;
1589       }
1590       if(this->_status.have_value() && o._status.have_value())
1591       {
1592         this->_value = o._value;  // NOLINT
1593         this->_status = o._status;
1594         return *this;
1595       }
1596       if(this->_status.have_error() && o._status.have_error())
1597       {
1598         this->_error = o._error;  // NOLINT
1599         this->_status = o._status;
1600         return *this;
1601       }
1602       if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
1603       {
1604         if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1605         {
1606           this->_value.~_value_type_();  // NOLINT
1607         }
1608         this->_status = o._status;
1609         return *this;
1610       }
1611       if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
1612       {
1613         copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1614         this->_status = o._status;
1615         return *this;
1616       }
1617       if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
1618       {
1619         if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1620         {
1621           this->_error.~_error_type_();  // NOLINT
1622         }
1623         this->_status = o._status;
1624         return *this;
1625       }
1626       if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
1627       {
1628         copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1629         this->_status = o._status;
1630         return *this;
1631       }
1632       if(this->_status.have_value() && o._status.have_error())
1633       {
1634         if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
1635         {
1636           this->_value.~_value_type_();  // NOLINT
1637         }
1638         copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
1639         this->_status = o._status;
1640         return *this;
1641       }
1642       if(this->_status.have_error() && o._status.have_value())
1643       {
1644         if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
1645         {
1646           this->_error.~_error_type_();  // NOLINT
1647         }
1648         copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
1649         this->_status = o._status;
1650         return *this;
1651       }
1652       // Should never reach here
1653       make_ub(this->_value);
1654     }
1655   };
1656 #ifdef _MSC_VER
1657 #pragma warning(pop)
1658 #endif
1659 
1660   // is_trivially_copyable is true even if type is not copyable, so handle that here
1661   template <class T> struct is_storage_trivial
1662   {
1663     static constexpr bool value = std::is_void<T>::value || (std::is_trivially_copy_constructible<T>::value && std::is_trivially_copyable<T>::value);
1664   };
1665   // work around libstdc++ 7 bug
1666   template <> struct is_storage_trivial<void>
1667   {
1668     static constexpr bool value = true;
1669   };
1670   template <> struct is_storage_trivial<const void>
1671   {
1672     static constexpr bool value = true;
1673   };
1674   // Ability to do copy assigns needs more than just copy assignment
1675   template <class T> struct is_copy_assignable
1676   {
1677     static constexpr bool value = std::is_copy_assignable<T>::value && (std::is_copy_constructible<T>::value || std::is_default_constructible<T>::value);
1678   };
1679   // Ability to do move assigns needs more than just move assignment
1680   template <class T> struct is_move_assignable
1681   {
1682     static constexpr bool value = std::is_move_assignable<T>::value && (std::is_move_constructible<T>::value || std::is_default_constructible<T>::value);
1683   };
1684 
1685   template <class T, class E>
1686   using value_storage_select_trivality =
1687   std::conditional_t<is_storage_trivial<T>::value && is_storage_trivial<E>::value, value_storage_trivial<T, E>, value_storage_nontrivial<T, E>>;
1688   template <class T, class E>
1689   using value_storage_select_move_constructor =
1690   std::conditional_t<std::is_move_constructible<devoid<T>>::value && std::is_move_constructible<devoid<E>>::value, value_storage_select_trivality<T, E>,
1691                      value_storage_delete_move_constructor<value_storage_select_trivality<T, E>>>;
1692   template <class T, class E>
1693   using value_storage_select_copy_constructor =
1694   std::conditional_t<std::is_copy_constructible<devoid<T>>::value && std::is_copy_constructible<devoid<E>>::value, value_storage_select_move_constructor<T, E>,
1695                      value_storage_delete_copy_constructor<value_storage_select_move_constructor<T, E>>>;
1696   template <class T, class E>
1697   using value_storage_select_move_assignment =
1698   std::conditional_t<std::is_trivially_move_assignable<devoid<T>>::value && std::is_trivially_move_assignable<devoid<E>>::value,
1699                      value_storage_select_copy_constructor<T, E>,
1700                      std::conditional_t<is_move_assignable<devoid<T>>::value && is_move_assignable<devoid<E>>::value,
1701                                         value_storage_nontrivial_move_assignment<value_storage_select_copy_constructor<T, E>>,
1702                                         value_storage_delete_move_assignment<value_storage_select_copy_constructor<T, E>>>>;
1703   template <class T, class E>
1704   using value_storage_select_copy_assignment =
1705   std::conditional_t<std::is_trivially_copy_assignable<devoid<T>>::value && std::is_trivially_copy_assignable<devoid<E>>::value,
1706                      value_storage_select_move_assignment<T, E>,
1707                      std::conditional_t<is_copy_assignable<devoid<T>>::value && is_copy_assignable<devoid<E>>::value,
1708                                         value_storage_nontrivial_copy_assignment<value_storage_select_move_assignment<T, E>>,
1709                                         value_storage_delete_copy_assignment<value_storage_select_move_assignment<T, E>>>>;
1710   template <class T, class E> using value_storage_select_impl = value_storage_select_copy_assignment<T, E>;
1711 #ifndef NDEBUG
1712   // Check is trivial in all ways except default constructibility
1713   // static_assert(std::is_trivial<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivial!");
1714   // static_assert(std::is_trivially_default_constructible<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivially
1715   // default constructible!");
1716   static_assert(std::is_trivially_copyable<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivially copyable!");
1717   static_assert(std::is_trivially_assignable<value_storage_select_impl<int, long>, value_storage_select_impl<int, long>>::value,
1718                 "value_storage_select_impl<int, long> is not trivially assignable!");
1719   static_assert(std::is_trivially_destructible<value_storage_select_impl<int, long>>::value,
1720                 "value_storage_select_impl<int, long> is not trivially destructible!");
1721   static_assert(std::is_trivially_copy_constructible<value_storage_select_impl<int, long>>::value,
1722                 "value_storage_select_impl<int, long> is not trivially copy constructible!");
1723   static_assert(std::is_trivially_move_constructible<value_storage_select_impl<int, long>>::value,
1724                 "value_storage_select_impl<int, long> is not trivially move constructible!");
1725   static_assert(std::is_trivially_copy_assignable<value_storage_select_impl<int, long>>::value,
1726                 "value_storage_select_impl<int, long> is not trivially copy assignable!");
1727   static_assert(std::is_trivially_move_assignable<value_storage_select_impl<int, long>>::value,
1728                 "value_storage_select_impl<int, long> is not trivially move assignable!");
1729   // Also check is standard layout
1730   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!");
1731 #endif
1732 }  // namespace detail
1733 
1734 BOOST_OUTCOME_V2_NAMESPACE_END
1735 
1736 #endif