Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:18:34

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