File indexing completed on 2025-01-30 09:34:32
0001
0002
0003
0004
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)
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