Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:34:32

0001 // Copyright (c) 2022 Klemens D. Morgenstern
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 #ifndef BOOST_COBALT_DETAIL_WITH_HPP
0006 #define BOOST_COBALT_DETAIL_WITH_HPP
0007 
0008 #include <boost/cobalt/concepts.hpp>
0009 #include <boost/cobalt/this_coro.hpp>
0010 
0011 #include <boost/asio/cancellation_signal.hpp>
0012 
0013 namespace boost::cobalt::detail
0014 {
0015 
0016 template<typename T>
0017 struct [[nodiscard]] with_impl
0018 {
0019     struct promise_type;
0020 
0021     bool await_ready() { return false;}
0022 
0023     template<typename Promise>
0024     BOOST_NOINLINE auto await_suspend(std::coroutine_handle<Promise> h) -> std::coroutine_handle<promise_type>;
0025     inline T await_resume();
0026 
0027   private:
0028     with_impl(promise_type & promise) : promise(promise) {}
0029     promise_type & promise;
0030 };
0031 
0032 template<typename T>
0033 struct with_promise_value
0034 {
0035   std::optional<T> result;
0036 
0037   void return_value(std::optional<T> && value)
0038   {
0039     if (value) // so non-move-assign types work
0040       result.emplace(std::move(*value));
0041   }
0042 
0043   T get_result()
0044   {
0045     return std::move(result).value();
0046   }
0047 };
0048 
0049 template<>
0050 struct with_promise_value<void>
0051 {
0052   void return_void() {}
0053   void get_result() {}
0054 };
0055 
0056 
0057 template<typename T>
0058 struct with_impl<T>::promise_type
0059         : with_promise_value<T>,
0060           enable_awaitables<promise_type>,
0061           enable_await_allocator<promise_type>
0062 {
0063   using enable_awaitables<promise_type>::await_transform;
0064   using enable_await_allocator<promise_type>::await_transform;
0065 
0066 
0067   using executor_type = executor;
0068   const executor_type & get_executor() const {return *exec;}
0069   std::optional<executor_type> exec;
0070 
0071   with_impl get_return_object()
0072   {
0073       return with_impl{*this};
0074   }
0075 
0076   std::exception_ptr e;
0077   void unhandled_exception()
0078   {
0079     e = std::current_exception();
0080   }
0081 
0082   std::suspend_always initial_suspend() {return {};}
0083 
0084   struct final_awaitable
0085   {
0086     promise_type *promise;
0087 
0088     bool await_ready() const noexcept
0089     {
0090       return false;
0091     }
0092     BOOST_NOINLINE
0093     auto await_suspend(std::coroutine_handle<promise_type> h) noexcept -> std::coroutine_handle<void>
0094     {
0095       return std::coroutine_handle<void>::from_address(h.promise().awaited_from.address());
0096     }
0097 
0098     void await_resume() noexcept
0099     {
0100     }
0101   };
0102 
0103   auto final_suspend() noexcept
0104   {
0105     return final_awaitable{this};
0106   }
0107   using cancellation_slot_type = asio::cancellation_slot;
0108   cancellation_slot_type get_cancellation_slot() const {return slot_;}
0109   asio::cancellation_slot slot_;
0110 
0111   std::coroutine_handle<void> awaited_from{nullptr};
0112 
0113 };
0114 
0115 template<typename T>
0116 T with_impl<T>::await_resume()
0117 {
0118     auto e = promise.e;
0119     auto res = std::move(promise.get_result());
0120     std::coroutine_handle<promise_type>::from_promise(promise).destroy();
0121     if (e)
0122         std::rethrow_exception(e);
0123 
0124     return std::move(res);
0125 }
0126 
0127 template<>
0128 inline void with_impl<void>::await_resume()
0129 {
0130   auto e = promise.e;
0131   std::coroutine_handle<promise_type>::from_promise(promise).destroy();
0132   if (e)
0133     std::rethrow_exception(e);
0134 }
0135 
0136 template<typename T>
0137 template<typename Promise>
0138 auto with_impl<T>::await_suspend(std::coroutine_handle<Promise> h) -> std::coroutine_handle<promise_type>
0139 {
0140     if constexpr (requires (Promise p) {p.get_executor();})
0141         promise.exec.emplace(h.promise().get_executor());
0142     else
0143         promise.exec.emplace(this_thread::get_executor());
0144 
0145     if constexpr (requires (Promise p) {p.get_cancellation_slot();})
0146         promise.slot_ = h.promise().get_cancellation_slot();
0147 
0148     promise.awaited_from = h;
0149     return std::coroutine_handle<promise_type>::from_promise(promise);
0150 }
0151 
0152 }
0153 
0154 #endif //BOOST_COBALT_DETAIL_WITH_HPP