%PDF- %PDF-
Direktori : /backups/router/usr/local/include/boost/asio/ |
Current File : //backups/router/usr/local/include/boost/asio/co_composed.hpp |
// // co_composed.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_CO_COMPOSED_HPP #define BOOST_ASIO_CO_COMPOSED_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #include <new> #include <tuple> #include <variant> #include <boost/asio/associated_cancellation_slot.hpp> #include <boost/asio/associator.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/cancellation_state.hpp> #include <boost/asio/detail/composed_work.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #if defined(BOOST_ASIO_HAS_STD_COROUTINE) # include <coroutine> #else // defined(BOOST_ASIO_HAS_STD_COROUTINE) # include <experimental/coroutine> #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) # include <boost/asio/detail/source_location.hpp> # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_STD_COROUTINE) using std::coroutine_handle; using std::suspend_always; using std::suspend_never; #else // defined(BOOST_ASIO_HAS_STD_COROUTINE) using std::experimental::coroutine_handle; using std::experimental::suspend_always; using std::experimental::suspend_never; #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) using boost::asio::detail::composed_io_executors; using boost::asio::detail::composed_work; using boost::asio::detail::composed_work_guard; using boost::asio::detail::get_composed_io_executor; using boost::asio::detail::make_composed_io_executors; using boost::asio::detail::recycling_allocator; using boost::asio::detail::throw_error; template <typename Executors, typename Handler, typename Return> class co_composed_state; template <typename Executors, typename Handler, typename Return> class co_composed_handler_base; template <typename Executors, typename Handler, typename Return> class co_composed_promise; template <BOOST_ASIO_COMPLETION_SIGNATURE... Signatures> class co_composed_returns { }; struct co_composed_on_suspend { void (*fn_)(void*) = nullptr; void* arg_ = nullptr; }; template <typename... T> struct co_composed_completion : std::tuple<T&&...> { template <typename... U> co_composed_completion(U&&... u) noexcept : std::tuple<T&&...>(static_cast<U&&>(u)...) { } }; template <typename Executors, typename Handler, typename Return, typename Signature> class co_composed_state_return_overload; template <typename Executors, typename Handler, typename Return, typename R, typename... Args> class co_composed_state_return_overload< Executors, Handler, Return, R(Args...)> { public: using derived_type = co_composed_state<Executors, Handler, Return>; using promise_type = co_composed_promise<Executors, Handler, Return>; using return_type = std::tuple<Args...>; void on_cancellation_complete_with(Args... args) { derived_type& state = *static_cast<derived_type*>(this); state.return_value_ = std::make_tuple(std::move(args)...); state.cancellation_on_suspend_fn( [](void* p) { auto& promise = *static_cast<promise_type*>(p); co_composed_handler_base<Executors, Handler, Return> composed_handler(promise); Handler handler(std::move(promise.state().handler_)); return_type result( std::move(std::get<return_type>(promise.state().return_value_))); co_composed_handler_base<Executors, Handler, Return>(std::move(composed_handler)); std::apply(std::move(handler), std::move(result)); }); } }; template <typename Executors, typename Handler, typename Return> class co_composed_state_return; template <typename Executors, typename Handler, typename... Signatures> class co_composed_state_return< Executors, Handler, co_composed_returns<Signatures...>> : public co_composed_state_return_overload<Executors, Handler, co_composed_returns<Signatures...>, Signatures>... { public: using co_composed_state_return_overload<Executors, Handler, co_composed_returns<Signatures...>, Signatures>::on_cancellation_complete_with...; private: template <typename, typename, typename, typename> friend class co_composed_promise_return_overload; template <typename, typename, typename, typename> friend class co_composed_state_return_overload; std::variant<std::monostate, typename co_composed_state_return_overload< Executors, Handler, co_composed_returns<Signatures...>, Signatures>::return_type...> return_value_; }; template <typename Executors, typename Handler, typename Return, typename... Signatures> struct co_composed_state_default_cancellation_on_suspend_impl; template <typename Executors, typename Handler, typename Return> struct co_composed_state_default_cancellation_on_suspend_impl< Executors, Handler, Return> { static constexpr void (*fn())(void*) { return nullptr; } }; template <typename Executors, typename Handler, typename Return, typename R, typename... Args, typename... Signatures> struct co_composed_state_default_cancellation_on_suspend_impl< Executors, Handler, Return, R(Args...), Signatures...> { static constexpr void (*fn())(void*) { return co_composed_state_default_cancellation_on_suspend_impl< Executors, Handler, Return, Signatures...>::fn(); } }; template <typename Executors, typename Handler, typename Return, typename R, typename... Args, typename... Signatures> struct co_composed_state_default_cancellation_on_suspend_impl<Executors, Handler, Return, R(boost::system::error_code, Args...), Signatures...> { using promise_type = co_composed_promise<Executors, Handler, Return>; using return_type = std::tuple<boost::system::error_code, Args...>; static constexpr void (*fn())(void*) { if constexpr ((is_constructible<Args>::value && ...)) { return [](void* p) { auto& promise = *static_cast<promise_type*>(p); co_composed_handler_base<Executors, Handler, Return> composed_handler(promise); Handler handler(std::move(promise.state().handler_)); co_composed_handler_base<Executors, Handler, Return>(std::move(composed_handler)); std::move(handler)( boost::system::error_code(boost::asio::error::operation_aborted), Args{}...); }; } else { return co_composed_state_default_cancellation_on_suspend_impl< Executors, Handler, Return, Signatures...>::fn(); } } }; template <typename Executors, typename Handler, typename Return, typename R, typename... Args, typename... Signatures> struct co_composed_state_default_cancellation_on_suspend_impl<Executors, Handler, Return, R(std::exception_ptr, Args...), Signatures...> { using promise_type = co_composed_promise<Executors, Handler, Return>; using return_type = std::tuple<std::exception_ptr, Args...>; static constexpr void (*fn())(void*) { if constexpr ((is_constructible<Args>::value && ...)) { return [](void* p) { auto& promise = *static_cast<promise_type*>(p); co_composed_handler_base<Executors, Handler, Return> composed_handler(promise); Handler handler(std::move(promise.state().handler_)); co_composed_handler_base<Executors, Handler, Return>(std::move(composed_handler)); std::move(handler)( std::make_exception_ptr( boost::system::system_error( boost::asio::error::operation_aborted, "co_await")), Args{}...); }; } else { return co_composed_state_default_cancellation_on_suspend_impl< Executors, Handler, Return, Signatures...>::fn(); } } }; template <typename Executors, typename Handler, typename Return> struct co_composed_state_default_cancellation_on_suspend; template <typename Executors, typename Handler, typename... Signatures> struct co_composed_state_default_cancellation_on_suspend< Executors, Handler, co_composed_returns<Signatures...>> : co_composed_state_default_cancellation_on_suspend_impl<Executors, Handler, co_composed_returns<Signatures...>, Signatures...> { }; template <typename Executors, typename Handler, typename Return> class co_composed_state_cancellation { public: using cancellation_slot_type = cancellation_slot; cancellation_slot_type get_cancellation_slot() const noexcept { return cancellation_state_.slot(); } cancellation_state get_cancellation_state() const noexcept { return cancellation_state_; } void reset_cancellation_state() { cancellation_state_ = cancellation_state( (get_associated_cancellation_slot)( static_cast<co_composed_state<Executors, Handler, Return>*>( this)->handler())); } template <typename Filter> void reset_cancellation_state(Filter filter) { cancellation_state_ = cancellation_state( (get_associated_cancellation_slot)( static_cast<co_composed_state<Executors, Handler, Return>*>( this)->handler()), filter, filter); } template <typename InFilter, typename OutFilter> void reset_cancellation_state(InFilter&& in_filter, OutFilter&& out_filter) { cancellation_state_ = cancellation_state( (get_associated_cancellation_slot)( static_cast<co_composed_state<Executors, Handler, Return>*>( this)->handler()), static_cast<InFilter&&>(in_filter), static_cast<OutFilter&&>(out_filter)); } cancellation_type_t cancelled() const noexcept { return cancellation_state_.cancelled(); } void clear_cancellation_slot() noexcept { cancellation_state_.slot().clear(); } [[nodiscard]] bool throw_if_cancelled() const noexcept { return throw_if_cancelled_; } void throw_if_cancelled(bool b) noexcept { throw_if_cancelled_ = b; } [[nodiscard]] bool complete_if_cancelled() const noexcept { return complete_if_cancelled_; } void complete_if_cancelled(bool b) noexcept { complete_if_cancelled_ = b; } private: template <typename, typename, typename> friend class co_composed_promise; template <typename, typename, typename, typename> friend class co_composed_state_return_overload; void cancellation_on_suspend_fn(void (*fn)(void*)) { cancellation_on_suspend_fn_ = fn; } void check_for_cancellation_on_transform() { if (throw_if_cancelled_ && !!cancelled()) throw_error(boost::asio::error::operation_aborted, "co_await"); } bool check_for_cancellation_on_suspend( co_composed_promise<Executors, Handler, Return>& promise) noexcept { if (complete_if_cancelled_ && !!cancelled() && cancellation_on_suspend_fn_) { promise.state().work_.reset(); promise.state().on_suspend_->fn_ = cancellation_on_suspend_fn_; promise.state().on_suspend_->arg_ = &promise; return false; } return true; } cancellation_state cancellation_state_; void (*cancellation_on_suspend_fn_)(void*) = co_composed_state_default_cancellation_on_suspend< Executors, Handler, Return>::fn(); bool throw_if_cancelled_ = false; bool complete_if_cancelled_ = true; }; template <typename Executors, typename Handler, typename Return> requires is_same< typename associated_cancellation_slot< Handler, cancellation_slot >::asio_associated_cancellation_slot_is_unspecialised, void>::value class co_composed_state_cancellation<Executors, Handler, Return> { public: void reset_cancellation_state() { } template <typename Filter> void reset_cancellation_state(Filter) { } template <typename InFilter, typename OutFilter> void reset_cancellation_state(InFilter&&, OutFilter&&) { } cancellation_type_t cancelled() const noexcept { return cancellation_type::none; } void clear_cancellation_slot() noexcept { } [[nodiscard]] bool throw_if_cancelled() const noexcept { return false; } void throw_if_cancelled(bool) noexcept { } [[nodiscard]] bool complete_if_cancelled() const noexcept { return false; } void complete_if_cancelled(bool) noexcept { } private: template <typename, typename, typename> friend class co_composed_promise; template <typename, typename, typename, typename> friend class co_composed_state_return_overload; void cancellation_on_suspend_fn(void (*)(void*)) { } void check_for_cancellation_on_transform() noexcept { } bool check_for_cancellation_on_suspend( co_composed_promise<Executors, Handler, Return>&) noexcept { return true; } }; template <typename Executors, typename Handler, typename Return> class co_composed_state : public co_composed_state_return<Executors, Handler, Return>, public co_composed_state_cancellation<Executors, Handler, Return> { public: using io_executor_type = typename composed_work_guard< typename composed_work<Executors>::head_type>::executor_type; template <typename H> co_composed_state(composed_io_executors<Executors>&& executors, H&& h, co_composed_on_suspend& on_suspend) : work_(std::move(executors)), handler_(static_cast<H&&>(h)), on_suspend_(&on_suspend) { this->reset_cancellation_state(enable_terminal_cancellation()); } io_executor_type get_io_executor() const noexcept { return work_.head_.get_executor(); } template <typename... Args> [[nodiscard]] co_composed_completion<Args...> complete(Args&&... args) requires requires { declval<Handler>()(static_cast<Args&&>(args)...); } { return co_composed_completion<Args...>(static_cast<Args&&>(args)...); } const Handler& handler() const noexcept { return handler_; } private: template <typename, typename, typename> friend class co_composed_handler_base; template <typename, typename, typename> friend class co_composed_promise; template <typename, typename, typename, typename> friend class co_composed_promise_return_overload; template <typename, typename, typename> friend class co_composed_state_cancellation; template <typename, typename, typename, typename> friend class co_composed_state_return_overload; template <typename, typename, typename, typename...> friend struct co_composed_state_default_cancellation_on_suspend_impl; composed_work<Executors> work_; Handler handler_; co_composed_on_suspend* on_suspend_; }; template <typename Executors, typename Handler, typename Return> class co_composed_handler_cancellation { public: using cancellation_slot_type = cancellation_slot; cancellation_slot_type get_cancellation_slot() const noexcept { return static_cast< const co_composed_handler_base<Executors, Handler, Return>*>( this)->promise().state().get_cancellation_slot(); } }; template <typename Executors, typename Handler, typename Return> requires is_same< typename associated_cancellation_slot< Handler, cancellation_slot >::asio_associated_cancellation_slot_is_unspecialised, void>::value class co_composed_handler_cancellation<Executors, Handler, Return> { }; template <typename Executors, typename Handler, typename Return> class co_composed_handler_base : public co_composed_handler_cancellation<Executors, Handler, Return> { public: co_composed_handler_base( co_composed_promise<Executors, Handler, Return>& p) noexcept : p_(&p) { } co_composed_handler_base(co_composed_handler_base&& other) noexcept : p_(std::exchange(other.p_, nullptr)) { } ~co_composed_handler_base() { if (p_) [[unlikely]] p_->destroy(); } co_composed_promise<Executors, Handler, Return>& promise() const noexcept { return *p_; } protected: void resume(void* result) { co_composed_on_suspend on_suspend{}; std::exchange(p_, nullptr)->resume(p_, result, on_suspend); if (on_suspend.fn_) on_suspend.fn_(on_suspend.arg_); } private: co_composed_promise<Executors, Handler, Return>* p_; }; template <typename Executors, typename Handler, typename Return, typename Signature> class co_composed_handler; template <typename Executors, typename Handler, typename Return, typename R, typename... Args> class co_composed_handler<Executors, Handler, Return, R(Args...)> : public co_composed_handler_base<Executors, Handler, Return> { public: using co_composed_handler_base<Executors, Handler, Return>::co_composed_handler_base; using result_type = std::tuple<decay_t<Args>...>; template <typename... T> void operator()(T&&... args) { result_type result(static_cast<T&&>(args)...); this->resume(&result); } static auto on_resume(void* result) { auto& args = *static_cast<result_type*>(result); if constexpr (sizeof...(Args) == 0) return; else if constexpr (sizeof...(Args) == 1) return std::move(std::get<0>(args)); else return std::move(args); } }; template <typename Executors, typename Handler, typename Return, typename R, typename... Args> class co_composed_handler<Executors, Handler, Return, R(boost::system::error_code, Args...)> : public co_composed_handler_base<Executors, Handler, Return> { public: using co_composed_handler_base<Executors, Handler, Return>::co_composed_handler_base; using args_type = std::tuple<decay_t<Args>...>; using result_type = std::tuple<boost::system::error_code, args_type>; template <typename... T> void operator()(const boost::system::error_code& ec, T&&... args) { result_type result(ec, args_type(static_cast<T&&>(args)...)); this->resume(&result); } static auto on_resume(void* result) { auto& [ec, args] = *static_cast<result_type*>(result); throw_error(ec); if constexpr (sizeof...(Args) == 0) return; else if constexpr (sizeof...(Args) == 1) return std::move(std::get<0>(args)); else return std::move(args); } }; template <typename Executors, typename Handler, typename Return, typename R, typename... Args> class co_composed_handler<Executors, Handler, Return, R(std::exception_ptr, Args...)> : public co_composed_handler_base<Executors, Handler, Return> { public: using co_composed_handler_base<Executors, Handler, Return>::co_composed_handler_base; using args_type = std::tuple<decay_t<Args>...>; using result_type = std::tuple<std::exception_ptr, args_type>; template <typename... T> void operator()(std::exception_ptr ex, T&&... args) { result_type result(std::move(ex), args_type(static_cast<T&&>(args)...)); this->resume(&result); } static auto on_resume(void* result) { auto& [ex, args] = *static_cast<result_type*>(result); if (ex) std::rethrow_exception(ex); if constexpr (sizeof...(Args) == 0) return; else if constexpr (sizeof...(Args) == 1) return std::move(std::get<0>(args)); else return std::move(args); } }; template <typename Executors, typename Handler, typename Return> class co_composed_promise_return; template <typename Executors, typename Handler> class co_composed_promise_return<Executors, Handler, co_composed_returns<>> { public: auto final_suspend() noexcept { return suspend_never(); } void return_void() noexcept { } }; template <typename Executors, typename Handler, typename Return, typename Signature> class co_composed_promise_return_overload; template <typename Executors, typename Handler, typename Return, typename R, typename... Args> class co_composed_promise_return_overload< Executors, Handler, Return, R(Args...)> { public: using derived_type = co_composed_promise<Executors, Handler, Return>; using return_type = std::tuple<Args...>; void return_value(std::tuple<Args...>&& value) { derived_type& promise = *static_cast<derived_type*>(this); promise.state().return_value_ = std::move(value); promise.state().work_.reset(); promise.state().on_suspend_->arg_ = this; promise.state().on_suspend_->fn_ = [](void* p) { auto& promise = *static_cast<derived_type*>(p); co_composed_handler_base<Executors, Handler, Return> composed_handler(promise); Handler handler(std::move(promise.state().handler_)); return_type result( std::move(std::get<return_type>(promise.state().return_value_))); co_composed_handler_base<Executors, Handler, Return>(std::move(composed_handler)); std::apply(std::move(handler), std::move(result)); }; } }; template <typename Executors, typename Handler, typename... Signatures> class co_composed_promise_return<Executors, Handler, co_composed_returns<Signatures...>> : public co_composed_promise_return_overload<Executors, Handler, co_composed_returns<Signatures...>, Signatures>... { public: auto final_suspend() noexcept { return suspend_always(); } using co_composed_promise_return_overload<Executors, Handler, co_composed_returns<Signatures...>, Signatures>::return_value...; private: template <typename, typename, typename, typename> friend class co_composed_promise_return_overload; }; template <typename Executors, typename Handler, typename Return> class co_composed_promise : public co_composed_promise_return<Executors, Handler, Return> { public: template <typename... Args> void* operator new(std::size_t size, co_composed_state<Executors, Handler, Return>& state, Args&&...) { block_allocator_type allocator( (get_associated_allocator)(state.handler_, recycling_allocator<void>())); block* base_ptr = std::allocator_traits<block_allocator_type>::allocate( allocator, blocks(sizeof(allocator_type)) + blocks(size)); new (static_cast<void*>(base_ptr)) allocator_type(std::move(allocator)); return base_ptr + blocks(sizeof(allocator_type)); } template <typename C, typename... Args> void* operator new(std::size_t size, C&&, co_composed_state<Executors, Handler, Return>& state, Args&&...) { return co_composed_promise::operator new(size, state); } void operator delete(void* ptr, std::size_t size) { block* base_ptr = static_cast<block*>(ptr) - blocks(sizeof(allocator_type)); allocator_type* allocator_ptr = std::launder( static_cast<allocator_type*>(static_cast<void*>(base_ptr))); block_allocator_type block_allocator(std::move(*allocator_ptr)); allocator_ptr->~allocator_type(); std::allocator_traits<block_allocator_type>::deallocate(block_allocator, base_ptr, blocks(sizeof(allocator_type)) + blocks(size)); } template <typename... Args> co_composed_promise( co_composed_state<Executors, Handler, Return>& state, Args&&...) : state_(state) { } template <typename C, typename... Args> co_composed_promise(C&&, co_composed_state<Executors, Handler, Return>& state, Args&&...) : state_(state) { } void destroy() noexcept { coroutine_handle<co_composed_promise>::from_promise(*this).destroy(); } void resume(co_composed_promise*& owner, void* result, co_composed_on_suspend& on_suspend) { state_.on_suspend_ = &on_suspend; state_.clear_cancellation_slot(); owner_ = &owner; result_ = result; coroutine_handle<co_composed_promise>::from_promise(*this).resume(); } co_composed_state<Executors, Handler, Return>& state() noexcept { return state_; } void get_return_object() noexcept { } auto initial_suspend() noexcept { return suspend_never(); } void unhandled_exception() { if (owner_) *owner_ = this; throw; } template <async_operation Op> auto await_transform(Op&& op #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) , boost::asio::detail::source_location location = boost::asio::detail::source_location::current() # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) ) { class [[nodiscard]] awaitable { public: awaitable(Op&& op, co_composed_promise& promise #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) , const boost::asio::detail::source_location& location # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) ) : op_(static_cast<Op&&>(op)), promise_(promise) #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) , location_(location) # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) { } constexpr bool await_ready() const noexcept { return false; } void await_suspend(coroutine_handle<co_composed_promise>) { if (promise_.state_.check_for_cancellation_on_suspend(promise_)) { promise_.state_.on_suspend_->arg_ = this; promise_.state_.on_suspend_->fn_ = [](void* p) { #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) BOOST_ASIO_HANDLER_LOCATION(( static_cast<awaitable*>(p)->location_.file_name(), static_cast<awaitable*>(p)->location_.line(), static_cast<awaitable*>(p)->location_.function_name())); # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) static_cast<Op&&>(static_cast<awaitable*>(p)->op_)( co_composed_handler<Executors, Handler, Return, completion_signature_of_t<Op>>( static_cast<awaitable*>(p)->promise_)); }; } } auto await_resume() { return co_composed_handler<Executors, Handler, Return, completion_signature_of_t<Op>>::on_resume(promise_.result_); } private: Op&& op_; co_composed_promise& promise_; #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) boost::asio::detail::source_location location_; # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) }; state_.check_for_cancellation_on_transform(); return awaitable{static_cast<Op&&>(op), *this #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) , location # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) }; } template <typename... Args> auto yield_value(co_composed_completion<Args...>&& result) { class [[nodiscard]] awaitable { public: awaitable(co_composed_completion<Args...>&& result, co_composed_promise& promise) : result_(std::move(result)), promise_(promise) { } constexpr bool await_ready() const noexcept { return false; } void await_suspend(coroutine_handle<co_composed_promise>) { promise_.state_.work_.reset(); promise_.state_.on_suspend_->arg_ = this; promise_.state_.on_suspend_->fn_ = [](void* p) { awaitable& a = *static_cast<awaitable*>(p); co_composed_handler_base<Executors, Handler, Return> composed_handler(a.promise_); Handler handler(std::move(a.promise_.state_.handler_)); std::tuple<decay_t<Args>...> result( std::move(static_cast<std::tuple<Args&&...>&>(a.result_))); co_composed_handler_base<Executors, Handler, Return>(std::move(composed_handler)); std::apply(std::move(handler), std::move(result)); }; } void await_resume() noexcept { } private: co_composed_completion<Args...> result_; co_composed_promise& promise_; }; return awaitable{std::move(result), *this}; } private: using allocator_type = associated_allocator_t<Handler, recycling_allocator<void>>; union block { std::max_align_t max_align; alignas(allocator_type) char pad[alignof(allocator_type)]; }; using block_allocator_type = typename std::allocator_traits<allocator_type> ::template rebind_alloc<block>; static constexpr std::size_t blocks(std::size_t size) { return (size + sizeof(block) - 1) / sizeof(block); } co_composed_state<Executors, Handler, Return>& state_; co_composed_promise** owner_ = nullptr; void* result_ = nullptr; }; template <typename Implementation, typename Executors, typename... Signatures> class initiate_co_composed { public: using executor_type = typename composed_io_executors<Executors>::head_type; template <typename I> initiate_co_composed(I&& impl, composed_io_executors<Executors>&& executors) : implementation_(static_cast<I&&>(impl)), executors_(std::move(executors)) { } executor_type get_executor() const noexcept { return executors_.head_; } template <typename Handler, typename... InitArgs> void operator()(Handler&& handler, InitArgs&&... init_args) const & { using handler_type = decay_t<Handler>; using returns_type = co_composed_returns<Signatures...>; co_composed_on_suspend on_suspend{}; implementation_( co_composed_state<Executors, handler_type, returns_type>( executors_, static_cast<Handler&&>(handler), on_suspend), static_cast<InitArgs&&>(init_args)...); if (on_suspend.fn_) on_suspend.fn_(on_suspend.arg_); } template <typename Handler, typename... InitArgs> void operator()(Handler&& handler, InitArgs&&... init_args) && { using handler_type = decay_t<Handler>; using returns_type = co_composed_returns<Signatures...>; co_composed_on_suspend on_suspend{}; std::move(implementation_)( co_composed_state<Executors, handler_type, returns_type>( std::move(executors_), static_cast<Handler&&>(handler), on_suspend), static_cast<InitArgs&&>(init_args)...); if (on_suspend.fn_) on_suspend.fn_(on_suspend.arg_); } private: Implementation implementation_; composed_io_executors<Executors> executors_; }; template <typename Implementation, typename... Signatures> class initiate_co_composed<Implementation, void(), Signatures...> { public: template <typename I> initiate_co_composed(I&& impl, composed_io_executors<void()>&&) : implementation_(static_cast<I&&>(impl)) { } template <typename Handler, typename... InitArgs> void operator()(Handler&& handler, InitArgs&&... init_args) const & { using handler_type = decay_t<Handler>; using returns_type = co_composed_returns<Signatures...>; co_composed_on_suspend on_suspend{}; implementation_( co_composed_state<void(), handler_type, returns_type>( composed_io_executors<void()>(), static_cast<Handler&&>(handler), on_suspend), static_cast<InitArgs&&>(init_args)...); if (on_suspend.fn_) on_suspend.fn_(on_suspend.arg_); } template <typename Handler, typename... InitArgs> void operator()(Handler&& handler, InitArgs&&... init_args) && { using handler_type = decay_t<Handler>; using returns_type = co_composed_returns<Signatures...>; co_composed_on_suspend on_suspend{}; std::move(implementation_)( co_composed_state<void(), handler_type, returns_type>( composed_io_executors<void()>(), static_cast<Handler&&>(handler), on_suspend), static_cast<InitArgs&&>(init_args)...); if (on_suspend.fn_) on_suspend.fn_(on_suspend.arg_); } private: Implementation implementation_; }; template <typename... Signatures, typename Implementation, typename Executors> inline initiate_co_composed<decay_t<Implementation>, Executors, Signatures...> make_initiate_co_composed(Implementation&& implementation, composed_io_executors<Executors>&& executors) { return initiate_co_composed< decay_t<Implementation>, Executors, Signatures...>( static_cast<Implementation&&>(implementation), std::move(executors)); } } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <template <typename, typename> class Associator, typename Executors, typename Handler, typename Return, typename Signature, typename DefaultCandidate> struct associator<Associator, detail::co_composed_handler<Executors, Handler, Return, Signature>, DefaultCandidate> : Associator<Handler, DefaultCandidate> { static typename Associator<Handler, DefaultCandidate>::type get( const detail::co_composed_handler< Executors, Handler, Return, Signature>& h) noexcept { return Associator<Handler, DefaultCandidate>::get( h.promise().state().handler()); } static auto get( const detail::co_composed_handler< Executors, Handler, Return, Signature>& h, const DefaultCandidate& c) noexcept -> decltype( Associator<Handler, DefaultCandidate>::get( h.promise().state().handler(), c)) { return Associator<Handler, DefaultCandidate>::get( h.promise().state().handler(), c); } }; #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #if !defined(GENERATING_DOCUMENTATION) # if defined(BOOST_ASIO_HAS_STD_COROUTINE) namespace std { # else // defined(BOOST_ASIO_HAS_STD_COROUTINE) namespace std { namespace experimental { # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) template <typename C, typename Executors, typename Handler, typename Return, typename... Args> struct coroutine_traits<void, C&, boost::asio::detail::co_composed_state<Executors, Handler, Return>, Args...> { using promise_type = boost::asio::detail::co_composed_promise<Executors, Handler, Return>; }; template <typename C, typename Executors, typename Handler, typename Return, typename... Args> struct coroutine_traits<void, C&&, boost::asio::detail::co_composed_state<Executors, Handler, Return>, Args...> { using promise_type = boost::asio::detail::co_composed_promise<Executors, Handler, Return>; }; template <typename Executors, typename Handler, typename Return, typename... Args> struct coroutine_traits<void, boost::asio::detail::co_composed_state<Executors, Handler, Return>, Args...> { using promise_type = boost::asio::detail::co_composed_promise<Executors, Handler, Return>; }; # if defined(BOOST_ASIO_HAS_STD_COROUTINE) } // namespace std # else // defined(BOOST_ASIO_HAS_STD_COROUTINE) }} // namespace std::experimental # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) #endif // !defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { /// Creates an initiation function object that may be used to launch a /// coroutine-based composed asynchronous operation. /** * The co_composed utility simplifies the implementation of composed * asynchronous operations by automatically adapting a coroutine to be an * initiation function object for use with @c async_initiate. When awaiting * asynchronous operations, the coroutine automatically uses a conforming * intermediate completion handler. * * @param implementation A function object that contains the coroutine-based * implementation of the composed asynchronous operation. The first argument to * the function object represents the state of the operation, and may be used * to test for cancellation. The remaining arguments are those passed to @c * async_initiate after the completion token. * * @param io_objects_or_executors Zero or more I/O objects or I/O executors for * which outstanding work must be maintained while the operation is incomplete. * * @par Per-Operation Cancellation * By default, terminal per-operation cancellation is enabled for composed * operations that use co_composed. To disable cancellation for the composed * operation, or to alter its supported cancellation types, call the state's * @c reset_cancellation_state function. * * @par Examples * The following example illustrates manual error handling and explicit checks * for cancellation. The completion handler is invoked via a @c co_yield to the * state's @c complete function, which never returns. * * @code template <typename CompletionToken> * auto async_echo(tcp::socket& socket, * CompletionToken&& token) * { * return boost::asio::async_initiate< * CompletionToken, void(boost::system::error_code)>( * boost::asio::co_composed( * [](auto state, tcp::socket& socket) -> void * { * state.reset_cancellation_state( * boost::asio::enable_terminal_cancellation()); * * while (!state.cancelled()) * { * char data[1024]; * auto [e1, n1] = * co_await socket.async_read_some( * boost::asio::buffer(data)); * * if (e1) * co_yield state.complete(e1); * * if (!!state.cancelled()) * co_yield state.complete( * make_error_code(boost::asio::error::operation_aborted)); * * auto [e2, n2] = * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n1)); * * if (e2) * co_yield state.complete(e2); * } * }, socket), * token, std::ref(socket)); * } @endcode * * This next example shows exception-based error handling and implicit checks * for cancellation. The completion handler is invoked after returning from the * coroutine via @c co_return. Valid @c co_return values are specified using * completion signatures passed to the @c co_composed function. * * @code template <typename CompletionToken> * auto async_echo(tcp::socket& socket, * CompletionToken&& token) * { * return boost::asio::async_initiate< * CompletionToken, void(boost::system::error_code)>( * boost::asio::co_composed< * void(boost::system::error_code)>( * [](auto state, tcp::socket& socket) -> void * { * try * { * state.throw_if_cancelled(true); * state.reset_cancellation_state( * boost::asio::enable_terminal_cancellation()); * * for (;;) * { * char data[1024]; * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data)); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n)); * } * } * catch (const boost::system::system_error& e) * { * co_return {e.code()}; * } * }, socket), * token, std::ref(socket)); * } @endcode */ template <BOOST_ASIO_COMPLETION_SIGNATURE... Signatures, typename Implementation, typename... IoObjectsOrExecutors> inline auto co_composed(Implementation&& implementation, IoObjectsOrExecutors&&... io_objects_or_executors) { return detail::make_initiate_co_composed<Signatures...>( static_cast<Implementation&&>(implementation), detail::make_composed_io_executors( detail::get_composed_io_executor( static_cast<IoObjectsOrExecutors&&>( io_objects_or_executors))...)); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_CO_COMPOSED_HPP