Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:59:08

0001 /* Tells C++ coroutines about Outcome's result
0002 (C) 2019-2024 Niall Douglas <http://www.nedproductions.biz/> (12 commits)
0003 File Created: Oct 2019
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_COROUTINE_SUPPORT_NAMESPACE_BEGIN
0032 #error This header must only be included by outcome/coroutine_support.hpp or outcome/experimental/coroutine_support.hpp
0033 #endif
0034 
0035 #ifndef BOOST_OUTCOME_DETAIL_COROUTINE_SUPPORT_HPP
0036 #define BOOST_OUTCOME_DETAIL_COROUTINE_SUPPORT_HPP
0037 
0038 #include <atomic>
0039 #include <exception>
0040 
0041 #ifndef BOOST_OUTCOME_COROUTINE_HEADER_TYPE
0042 #if __has_include(<coroutine>)
0043 #define BOOST_OUTCOME_COROUTINE_HEADER_TYPE 1
0044 #elif __has_include(<experimental/coroutine>)
0045 #define BOOST_OUTCOME_COROUTINE_HEADER_TYPE 2
0046 #else
0047 #define BOOST_OUTCOME_COROUTINE_HEADER_TYPE 0
0048 #endif
0049 #endif
0050 
0051 #if BOOST_OUTCOME_COROUTINE_HEADER_TYPE && (__cpp_impl_coroutine || (defined(_MSC_VER) && __cpp_coroutines))
0052 #ifndef BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0053 #if defined(__has_builtin)
0054 #if __has_builtin(__builtin_coro_noop) || (!defined(__clang__) && __GNUC__ >= 10)
0055 #define BOOST_OUTCOME_HAVE_NOOP_COROUTINE 1
0056 #endif
0057 #endif
0058 #endif
0059 #ifndef BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0060 #if _MSC_VER >= 1928 || (!defined(__clang__) && __GNUC__ >= 10)
0061 #define BOOST_OUTCOME_HAVE_NOOP_COROUTINE 1
0062 #else
0063 #define BOOST_OUTCOME_HAVE_NOOP_COROUTINE 0
0064 #endif
0065 #endif
0066 #if BOOST_OUTCOME_COROUTINE_HEADER_TYPE == 1
0067 #include <coroutine>
0068 BOOST_OUTCOME_V2_NAMESPACE_BEGIN
0069 namespace awaitables
0070 {
0071   template <class Promise = void> using coroutine_handle = std::coroutine_handle<Promise>;
0072   template <class... Args> using coroutine_traits = std::coroutine_traits<Args...>;
0073   using std::suspend_always;
0074   using std::suspend_never;
0075 #if BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0076   using std::noop_coroutine;
0077 #endif
0078 }  // namespace awaitables
0079 BOOST_OUTCOME_V2_NAMESPACE_END
0080 #define BOOST_OUTCOME_FOUND_COROUTINE_HEADER 1
0081 #elif BOOST_OUTCOME_COROUTINE_HEADER_TYPE == 2
0082 #include <experimental/coroutine>
0083 BOOST_OUTCOME_V2_NAMESPACE_BEGIN
0084 namespace awaitables
0085 {
0086   template <class Promise = void> using coroutine_handle = std::experimental::coroutine_handle<Promise>;
0087   template <class... Args> using coroutine_traits = std::experimental::coroutine_traits<Args...>;
0088   using std::experimental::suspend_always;
0089   using std::experimental::suspend_never;
0090 #if BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0091   using std::experimental::noop_coroutine;
0092 #endif
0093 }  // namespace awaitables
0094 BOOST_OUTCOME_V2_NAMESPACE_END
0095 #define BOOST_OUTCOME_FOUND_COROUTINE_HEADER 1
0096 #endif
0097 #endif
0098 
0099 #ifndef BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER
0100 // #include <iostream>
0101 // #define BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(...) std::cout << __VA_ARGS__ << std::endl;
0102 #define BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(...)
0103 #endif
0104 
0105 BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN
0106 namespace awaitables
0107 {
0108   namespace detail
0109   {
0110     struct error_type_not_found
0111     {
0112     };
0113     struct exception_type_not_found
0114     {
0115     };
0116     template <class T> struct type_found
0117     {
0118       using type = T;
0119     };
0120     template <class T, class U = typename T::error_type> constexpr inline type_found<U> extract_error_type(int /*unused*/)
0121     {
0122       return {};
0123     }
0124     template <class T> constexpr inline type_found<error_type_not_found> extract_error_type(...)
0125     {
0126       return {};
0127     }
0128     template <class T, class U = typename T::exception_type> constexpr inline type_found<U> extract_exception_type(int /*unused*/)
0129     {
0130       return {};
0131     }
0132     template <class T> constexpr inline type_found<exception_type_not_found> extract_exception_type(...)
0133     {
0134       return {};
0135     }
0136 
0137     BOOST_OUTCOME_TEMPLATE(class T, class U)
0138     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(BOOST_OUTCOME_V2_NAMESPACE::detail::is_constructible<U, T>))
0139     inline bool try_set_error(T &&e, U *result)
0140     {
0141       new(result) U(static_cast<T &&>(e));
0142       return true;
0143     }
0144     template <class T> inline bool try_set_error(T && /*unused*/, ...)
0145     {
0146       return false;
0147     }
0148     BOOST_OUTCOME_TEMPLATE(class T, class U)
0149     BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(BOOST_OUTCOME_V2_NAMESPACE::detail::is_constructible<U, T>))
0150     inline void set_or_rethrow(T &e, U *result)
0151     {
0152       new(result) U(e);
0153     }
0154     template <class T> inline void set_or_rethrow(T &e, ...)
0155     {
0156       rethrow_exception(e);
0157     }
0158     template <class T> class fake_atomic
0159     {
0160       T _v;
0161 
0162     public:
0163       constexpr fake_atomic(T v)
0164           : _v(v)
0165       {
0166       }
0167       T load(std::memory_order /*unused*/) { return _v; }
0168       void store(T v, std::memory_order /*unused*/) { _v = v; }
0169       bool compare_exchange_strong(T &expected, T v, std::memory_order /*unused*/, std::memory_order /*unused*/)
0170       {
0171         if(_v == expected)
0172         {
0173           _v = v;
0174           return true;
0175         }
0176         return false;
0177       }
0178     };
0179 
0180 #ifdef BOOST_OUTCOME_FOUND_COROUTINE_HEADER
0181     template <class Awaitable, bool suspend_initial, bool use_atomic, bool is_void> struct outcome_promise_type
0182     {
0183       using container_type = typename Awaitable::container_type;
0184       using result_set_type = std::conditional_t<use_atomic, std::atomic<bool>, fake_atomic<bool>>;
0185       union
0186       {
0187         BOOST_OUTCOME_V2_NAMESPACE::detail::empty_type _default{};
0188         container_type result;
0189       };
0190       result_set_type result_set{false}, pending_first_resumption{is_initially_suspended};
0191       coroutine_handle<> continuation;
0192 
0193       static constexpr bool is_initially_suspended = suspend_initial;
0194       static constexpr bool is_using_atomics = use_atomic;
0195 
0196       outcome_promise_type() noexcept { BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise constructed"); }
0197       outcome_promise_type(const outcome_promise_type &) = delete;
0198       outcome_promise_type(outcome_promise_type &&) = delete;
0199       outcome_promise_type &operator=(const outcome_promise_type &) = delete;
0200       outcome_promise_type &operator=(outcome_promise_type &&) = delete;
0201       ~outcome_promise_type()
0202       {
0203         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise destructs");
0204         if(result_set.load(std::memory_order_acquire))
0205         {
0206           result.~container_type();  // could throw
0207         }
0208       }
0209       auto get_return_object()
0210       {
0211         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise returns awaitable");
0212         return Awaitable{*this};  // could throw bad_alloc
0213       }
0214       void return_value(container_type &&value)
0215       {
0216         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise returns value");
0217         BOOST_OUTCOME_ASSERT(!result_set.load(std::memory_order_acquire));
0218         if(result_set.load(std::memory_order_acquire))
0219         {
0220           result.~container_type();  // could throw
0221         }
0222         new(&result) container_type(static_cast<container_type &&>(value));  // could throw
0223         result_set.store(true, std::memory_order_release);
0224       }
0225       void return_value(const container_type &value)
0226       {
0227         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise returns value");
0228         BOOST_OUTCOME_ASSERT(!result_set.load(std::memory_order_acquire));
0229         if(result_set.load(std::memory_order_acquire))
0230         {
0231           result.~container_type();  // could throw
0232         }
0233         new(&result) container_type(value);  // could throw
0234         result_set.store(true, std::memory_order_release);
0235       }
0236       void unhandled_exception()
0237       {
0238         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise unhandled exception");
0239         BOOST_OUTCOME_ASSERT(!result_set.load(std::memory_order_acquire));
0240         if(result_set.load(std::memory_order_acquire))
0241         {
0242           result.~container_type();
0243         }
0244 #ifndef BOOST_NO_EXCEPTIONS
0245         auto e = std::current_exception();
0246         auto ec = detail::error_from_exception(static_cast<decltype(e) &&>(e), {});
0247         // Try to set error code first
0248         if(!detail::error_is_set(ec) || !detail::try_set_error(static_cast<decltype(ec) &&>(ec), &result))
0249         {
0250           detail::set_or_rethrow(e, &result);  // could throw
0251         }
0252 #else
0253         std::terminate();
0254 #endif
0255         result_set.store(true, std::memory_order_release);
0256       }
0257       auto initial_suspend() noexcept
0258       {
0259         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise initial suspend = " << suspend_initial);
0260         struct awaiter
0261         {
0262           constexpr bool await_ready() noexcept { return !suspend_initial; }
0263           void await_resume() noexcept {}
0264           void await_suspend(coroutine_handle<> /*unused*/) noexcept {}
0265         };
0266         return awaiter{};
0267       }
0268       auto final_suspend() noexcept
0269       {
0270         struct awaiter
0271         {
0272           // If we don't force a final suspend, promise will get deleted before awaitable
0273           // TODO: Implement detachable awaitables
0274           constexpr bool await_ready() noexcept { return false; }
0275           void await_resume() noexcept {}
0276 #if BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0277           coroutine_handle<> await_suspend(coroutine_handle<outcome_promise_type> self) noexcept
0278           {
0279             if(self.promise().continuation)
0280             {
0281               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will resume coroutine " << self.promise().continuation.address());
0282             }
0283             else
0284             {
0285               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will exit");
0286             }
0287             return self.promise().continuation ? self.promise().continuation : noop_coroutine();
0288           }
0289 #else
0290           void await_suspend(coroutine_handle<outcome_promise_type> self)
0291           {
0292             if(self.promise().continuation)
0293             {
0294               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will resume coroutine " << self.promise().continuation.address());
0295               return self.promise().continuation.resume();
0296             }
0297             else
0298             {
0299               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will exit");
0300             }
0301           }
0302 #endif
0303         };
0304         return awaiter{};
0305       }
0306     };
0307     template <class Awaitable, bool suspend_initial, bool use_atomic> struct outcome_promise_type<Awaitable, suspend_initial, use_atomic, true>
0308     {
0309       using container_type = void;
0310       using result_set_type = std::conditional_t<use_atomic, std::atomic<bool>, fake_atomic<bool>>;
0311       result_set_type result_set{false}, pending_first_resumption{is_initially_suspended};
0312       coroutine_handle<> continuation;
0313 
0314       static constexpr bool is_initially_suspended = suspend_initial;
0315       static constexpr bool is_using_atomics = use_atomic;
0316 
0317       outcome_promise_type() { BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise constructed"); }
0318       outcome_promise_type(const outcome_promise_type &) = delete;
0319       outcome_promise_type(outcome_promise_type &&) = delete;
0320       outcome_promise_type &operator=(const outcome_promise_type &) = delete;
0321       outcome_promise_type &operator=(outcome_promise_type &&) = delete;
0322       ~outcome_promise_type() = default;
0323       auto get_return_object()
0324       {
0325         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise returns awaitable");
0326         return Awaitable{*this};  // could throw bad_alloc
0327       }
0328       void return_void() noexcept
0329       {
0330         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise returns void");
0331         BOOST_OUTCOME_ASSERT(!result_set.load(std::memory_order_acquire));
0332         result_set.store(true, std::memory_order_release);
0333       }
0334       void unhandled_exception()
0335       {
0336         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise unhandled exception");
0337         BOOST_OUTCOME_ASSERT(!result_set.load(std::memory_order_acquire));
0338         std::rethrow_exception(std::current_exception());  // throws
0339       }
0340       auto initial_suspend() noexcept
0341       {
0342         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(this << " promise initial suspend = " << suspend_initial);
0343         struct awaiter
0344         {
0345           constexpr bool await_ready() noexcept { return !suspend_initial; }
0346           void await_resume() noexcept {}
0347           void await_suspend(coroutine_handle<> /*unused*/) noexcept {}
0348         };
0349         return awaiter{};
0350       }
0351       auto final_suspend() noexcept
0352       {
0353         struct awaiter
0354         {
0355           // If we don't force a final suspend, promise will get deleted before awaitable
0356           // TODO: Implement detachable awaitables
0357           constexpr bool await_ready() noexcept { return false; }
0358           void await_resume() noexcept {}
0359 #if BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0360           coroutine_handle<> await_suspend(coroutine_handle<outcome_promise_type> self) noexcept
0361           {
0362             if(self.promise().continuation)
0363             {
0364               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will resume coroutine " << self.promise().continuation.address());
0365             }
0366             else
0367             {
0368               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will exit");
0369             }
0370             return self.promise().continuation ? self.promise().continuation : noop_coroutine();
0371           }
0372 #else
0373           void await_suspend(coroutine_handle<outcome_promise_type> self)
0374           {
0375             if(self.promise().continuation)
0376             {
0377               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will resume coroutine " << self.promise().continuation.address());
0378               return self.promise().continuation.resume();
0379             }
0380             else
0381             {
0382               BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&self.promise() << " promise final suspend will exit");
0383             }
0384           }
0385 #endif
0386         };
0387         return awaiter{};
0388       }
0389     };
0390     template <class Awaitable, bool suspend_initial, bool use_atomic>
0391     constexpr inline auto move_result_from_promise_if_not_void(outcome_promise_type<Awaitable, suspend_initial, use_atomic, false> &p)
0392     {
0393       return static_cast<typename Awaitable::container_type &&>(p.result);
0394     }
0395     template <class Awaitable, bool suspend_initial, bool use_atomic>
0396     constexpr inline void move_result_from_promise_if_not_void(outcome_promise_type<Awaitable, suspend_initial, use_atomic, true> & /*unused*/)
0397     {
0398     }
0399 
0400     template <class Cont, class Executor, bool suspend_initial, bool use_atomic> struct BOOST_OUTCOME_NODISCARD awaitable
0401     {
0402       using container_type = Cont;
0403       using value_type = Cont;
0404       using executor_type = Executor;
0405       using promise_type = outcome_promise_type<awaitable, suspend_initial, use_atomic, std::is_void<container_type>::value>;
0406       coroutine_handle<promise_type> _h;
0407 
0408       awaitable(awaitable &&o) noexcept
0409           : _h(static_cast<coroutine_handle<promise_type> &&>(o._h))
0410       {
0411         o._h = nullptr;
0412       }
0413       awaitable(const awaitable &o) = delete;
0414       awaitable &operator=(awaitable &&) = delete;  // as per P1056
0415       awaitable &operator=(const awaitable &) = delete;
0416       ~awaitable()
0417       {
0418         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise() << " awaitable destructs");
0419         if(_h)
0420         {
0421           _h.destroy();
0422         }
0423       }
0424       explicit awaitable(promise_type &p)  // could throw
0425           : _h(coroutine_handle<promise_type>::from_promise(p))
0426       {
0427         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise() << " awaitable constructs for coroutine " << _h.address()
0428                                                           << " shall resume on first suspend = " << promise_type::is_initially_suspended);
0429       }
0430       bool valid() const noexcept { return _h != nullptr; }
0431       bool await_ready() noexcept
0432       {
0433         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise() << " await_ready = " << _h.promise().result_set.load(std::memory_order_acquire));
0434         return _h.promise().result_set.load(std::memory_order_acquire);
0435       }
0436       container_type await_resume()
0437       {
0438         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise() << " await_resume");
0439         BOOST_OUTCOME_ASSERT(_h.promise().result_set.load(std::memory_order_acquire));
0440         if(!_h.promise().result_set.load(std::memory_order_acquire))
0441         {
0442           std::terminate();
0443         }
0444         return detail::move_result_from_promise_if_not_void(_h.promise());
0445       }
0446 #if BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0447       coroutine_handle<> await_suspend(coroutine_handle<> cont) noexcept
0448       {
0449         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise() << " await_suspend suspends coroutine " << cont.address());
0450         auto &p = _h.promise();
0451         p.continuation = cont;
0452         bool expected = true;
0453         if(p.pending_first_resumption.compare_exchange_strong(expected, false, std::memory_order_acq_rel, std::memory_order_relaxed))
0454         {
0455           BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise()
0456                                               << " await_suspend does one time first resumption of initially suspended coroutine " << _h.address());
0457           return _h;
0458         }
0459         return noop_coroutine();
0460       }
0461 #else
0462       void await_suspend(coroutine_handle<> cont)
0463       {
0464         BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise() << " await_suspend suspends coroutine " << cont.address());
0465         auto &p = _h.promise();
0466         p.continuation = cont;
0467         bool expected = true;
0468         if(p.pending_first_resumption.compare_exchange_strong(expected, false, std::memory_order_acq_rel, std::memory_order_relaxed))
0469         {
0470           BOOST_OUTCOME_V2_AWAITABLES_DEBUG_PRINTER(&_h.promise()
0471                                               << " await_suspend does one time first resumption of initially suspended coroutine " << _h.address());
0472           _h.resume();
0473         }
0474       }
0475 #endif
0476     };
0477 
0478     template <class ContType, class Executor, bool suspend_initial, bool use_atomic> struct generator
0479     {
0480       using container_type = ContType;
0481       using value_type = ContType;
0482       using executor_type = Executor;
0483       class promise_type
0484       {
0485         friend struct generator;
0486         using result_set_type = std::conditional_t<use_atomic, std::atomic<int8_t>, fake_atomic<int8_t>>;
0487         union
0488         {
0489           BOOST_OUTCOME_V2_NAMESPACE::detail::empty_type _default{};
0490           container_type result;
0491         };
0492         result_set_type result_set{0};
0493         coroutine_handle<> continuation;
0494 
0495       public:
0496         promise_type() {}
0497         promise_type(const promise_type &) = delete;
0498         promise_type(promise_type &&) = delete;
0499         promise_type &operator=(const promise_type &) = delete;
0500         promise_type &operator=(promise_type &&) = delete;
0501         ~promise_type()
0502         {
0503           if(result_set.load(std::memory_order_acquire) == 1)
0504           {
0505             result.~container_type();  // could throw
0506           }
0507         }
0508 
0509         auto get_return_object()
0510         {
0511           return generator{*this};  // could throw bad_alloc
0512         }
0513         void return_void() noexcept
0514         {
0515           BOOST_OUTCOME_ASSERT(result_set.load(std::memory_order_acquire) >= 0);
0516           if(result_set.load(std::memory_order_acquire) == 1)
0517           {
0518             result.~container_type();  // could throw
0519           }
0520           result_set.store(-1, std::memory_order_release);
0521         }
0522         suspend_always yield_value(container_type &&value)
0523         {
0524           BOOST_OUTCOME_ASSERT(result_set.load(std::memory_order_acquire) >= 0);
0525           if(result_set.load(std::memory_order_acquire) == 1)
0526           {
0527             result.~container_type();  // could throw
0528           }
0529           new(&result) container_type(static_cast<container_type &&>(value));  // could throw
0530           result_set.store(1, std::memory_order_release);
0531           return {};
0532         }
0533         suspend_always yield_value(const container_type &value)
0534         {
0535           BOOST_OUTCOME_ASSERT(result_set.load(std::memory_order_acquire) >= 0);
0536           if(result_set.load(std::memory_order_acquire) == 1)
0537           {
0538             result.~container_type();  // could throw
0539           }
0540           new(&result) container_type(value);  // could throw
0541           result_set.store(1, std::memory_order_release);
0542           return {};
0543         }
0544         void unhandled_exception()
0545         {
0546           BOOST_OUTCOME_ASSERT(result_set.load(std::memory_order_acquire) >= 0);
0547           if(result_set.load(std::memory_order_acquire) == 1)
0548           {
0549             result.~container_type();
0550           }
0551 #ifndef BOOST_NO_EXCEPTIONS
0552           auto e = std::current_exception();
0553           auto ec = detail::error_from_exception(static_cast<decltype(e) &&>(e), {});
0554           // Try to set error code first
0555           if(!detail::error_is_set(ec) || !detail::try_set_error(static_cast<decltype(ec) &&>(ec), &result))
0556           {
0557             detail::set_or_rethrow(e, &result);  // could throw
0558           }
0559 #else
0560           std::terminate();
0561 #endif
0562           result_set.store(1, std::memory_order_release);
0563         }
0564         auto initial_suspend() noexcept
0565         {
0566           struct awaiter
0567           {
0568             bool await_ready() noexcept { return !suspend_initial; }
0569             void await_resume() noexcept {}
0570             void await_suspend(coroutine_handle<> /*unused*/) noexcept {}
0571           };
0572           return awaiter{};
0573         }
0574         auto final_suspend() noexcept
0575         {
0576           struct awaiter
0577           {
0578             bool await_ready() noexcept { return false; }
0579             void await_resume() noexcept {}
0580 #if BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0581             coroutine_handle<> await_suspend(coroutine_handle<promise_type> self) noexcept
0582             {
0583               return self.promise().continuation ? self.promise().continuation : noop_coroutine();
0584             }
0585 #else
0586             void await_suspend(coroutine_handle<promise_type> self)
0587             {
0588               if(self.promise().continuation)
0589               {
0590                 return self.promise().continuation.resume();
0591               }
0592             }
0593 #endif
0594           };
0595           return awaiter{};
0596         }
0597       };
0598       coroutine_handle<promise_type> _h;
0599 
0600       generator(generator &&o) noexcept
0601           : _h(static_cast<coroutine_handle<promise_type> &&>(o._h))
0602       {
0603         o._h = nullptr;
0604       }
0605       generator(const generator &o) = delete;
0606       generator &operator=(generator &&) = delete;  // as per P1056
0607       generator &operator=(const generator &) = delete;
0608       ~generator()
0609       {
0610         if(_h)
0611         {
0612           _h.destroy();
0613         }
0614       }
0615       explicit generator(promise_type &p)  // could throw
0616           : _h(coroutine_handle<promise_type>::from_promise(p))
0617       {
0618       }
0619       explicit operator bool() const  // could throw
0620       {
0621         return valid();
0622       }
0623       bool valid() const  // could throw
0624       {
0625         auto &p = _h.promise();
0626         if(p.result_set.load(std::memory_order_acquire) == 0)
0627         {
0628           const_cast<generator *>(this)->_h();
0629         }
0630         return p.result_set.load(std::memory_order_acquire) >= 0;
0631       }
0632       container_type operator()()  // could throw
0633       {
0634         auto &p = _h.promise();
0635         if(p.result_set.load(std::memory_order_acquire) == 0)
0636         {
0637           _h();
0638         }
0639         BOOST_OUTCOME_ASSERT(p.result_set.load(std::memory_order_acquire) >= 0);
0640         if(p.result_set.load(std::memory_order_acquire) < 0)
0641         {
0642           std::terminate();
0643         }
0644         container_type ret(static_cast<container_type &&>(p.result));
0645         p.result.~container_type();  // could throw
0646         p.result_set.store(0, std::memory_order_release);
0647         return ret;
0648       }
0649 #if BOOST_OUTCOME_HAVE_NOOP_COROUTINE
0650       coroutine_handle<> await_suspend(coroutine_handle<> cont) noexcept
0651       {
0652         _h.promise().continuation = cont;
0653         return _h;
0654       }
0655 #else
0656       void await_suspend(coroutine_handle<> cont)
0657       {
0658         _h.promise().continuation = cont;
0659         _h.resume();
0660       }
0661 #endif
0662     };
0663 #endif
0664   }  // namespace detail
0665 
0666 }  // namespace awaitables
0667 
0668 BOOST_OUTCOME_V2_NAMESPACE_END
0669 
0670 #endif
0671 
0672 #ifdef BOOST_OUTCOME_FOUND_COROUTINE_HEADER
0673 BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_EXPORT_BEGIN
0674 /*! AWAITING HUGO JSON CONVERSION TOOL
0675 SIGNATURE NOT RECOGNISED
0676 */
0677 template <class T, class Executor = void> using eager = BOOST_OUTCOME_V2_NAMESPACE::awaitables::detail::awaitable<T, Executor, false, false>;
0678 
0679 /*! AWAITING HUGO JSON CONVERSION TOOL
0680 SIGNATURE NOT RECOGNISED
0681 */
0682 template <class T, class Executor = void> using atomic_eager = BOOST_OUTCOME_V2_NAMESPACE::awaitables::detail::awaitable<T, Executor, false, true>;
0683 
0684 /*! AWAITING HUGO JSON CONVERSION TOOL
0685 SIGNATURE NOT RECOGNISED
0686 */
0687 template <class T, class Executor = void> using lazy = BOOST_OUTCOME_V2_NAMESPACE::awaitables::detail::awaitable<T, Executor, true, false>;
0688 
0689 /*! AWAITING HUGO JSON CONVERSION TOOL
0690 SIGNATURE NOT RECOGNISED
0691 */
0692 template <class T, class Executor = void> using atomic_lazy = BOOST_OUTCOME_V2_NAMESPACE::awaitables::detail::awaitable<T, Executor, true, true>;
0693 
0694 /*! AWAITING HUGO JSON CONVERSION TOOL
0695 SIGNATURE NOT RECOGNISED
0696 */
0697 template <class T, class Executor = void> using generator = BOOST_OUTCOME_V2_NAMESPACE::awaitables::detail::generator<T, Executor, true, false>;
0698 
0699 BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_END
0700 #endif