1176 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			1176 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //
 | ||
|  | // experimental/impl/co_composed.hpp
 | ||
|  | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
|  | //
 | ||
|  | // Copyright (c) 2003-2023 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 ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
 | ||
|  | #define ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
 | ||
|  | 
 | ||
|  | #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 | ||
|  | # pragma once
 | ||
|  | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 | ||
|  | 
 | ||
|  | #include "asio/detail/config.hpp"
 | ||
|  | #include <new>
 | ||
|  | #include <tuple>
 | ||
|  | #include <variant>
 | ||
|  | #include "asio/associated_cancellation_slot.hpp"
 | ||
|  | #include "asio/associator.hpp"
 | ||
|  | #include "asio/async_result.hpp"
 | ||
|  | #include "asio/cancellation_state.hpp"
 | ||
|  | #include "asio/detail/composed_work.hpp"
 | ||
|  | #include "asio/detail/recycling_allocator.hpp"
 | ||
|  | #include "asio/detail/throw_error.hpp"
 | ||
|  | #include "asio/detail/type_traits.hpp"
 | ||
|  | #include "asio/error.hpp"
 | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | # include <coroutine>
 | ||
|  | #else // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | # include <experimental/coroutine>
 | ||
|  | #endif // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | 
 | ||
|  | #if defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | # if defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #  include "asio/detail/source_location.hpp"
 | ||
|  | # endif // defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | 
 | ||
|  | #include "asio/detail/push_options.hpp"
 | ||
|  | 
 | ||
|  | namespace asio { | ||
|  | namespace experimental { | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | using std::coroutine_handle; | ||
|  | using std::suspend_always; | ||
|  | using std::suspend_never; | ||
|  | #else // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | using std::experimental::coroutine_handle; | ||
|  | using std::experimental::suspend_always; | ||
|  | using std::experimental::suspend_never; | ||
|  | #endif // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | 
 | ||
|  | using asio::detail::composed_io_executors; | ||
|  | using asio::detail::composed_work; | ||
|  | using asio::detail::composed_work_guard; | ||
|  | using asio::detail::get_composed_io_executor; | ||
|  | using asio::detail::make_composed_io_executors; | ||
|  | using asio::detail::recycling_allocator; | ||
|  | using 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 <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&&...>(std::forward<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(asio::error_code, Args...), Signatures...> | ||
|  | { | ||
|  |   using promise_type = co_composed_promise<Executors, Handler, Return>; | ||
|  |   using return_type = std::tuple<asio::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)( | ||
|  |             asio::error_code(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( | ||
|  |               asio::system_error( | ||
|  |                 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()), | ||
|  |         std::forward<InFilter>(in_filter), | ||
|  |         std::forward<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(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_(std::forward<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>()(std::forward<Args>(args)...); } | ||
|  |   { | ||
|  |     return co_composed_completion<Args...>(std::forward<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<typename decay<Args>::type...>; | ||
|  | 
 | ||
|  |   template <typename... T> | ||
|  |   void operator()(T&&... args) | ||
|  |   { | ||
|  |     result_type result(std::forward<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(asio::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<typename decay<Args>::type...>; | ||
|  |   using result_type = std::tuple<asio::error_code, args_type>; | ||
|  | 
 | ||
|  |   template <typename... T> | ||
|  |   void operator()(const asio::error_code& ec, T&&... args) | ||
|  |   { | ||
|  |     result_type result(ec, args_type(std::forward<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<typename decay<Args>::type...>; | ||
|  |   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(std::forward<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(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | # if defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  |       , asio::detail::source_location location | ||
|  |         = asio::detail::source_location::current() | ||
|  | # endif // defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  |     ) | ||
|  |   { | ||
|  |     class [[nodiscard]] awaitable | ||
|  |     { | ||
|  |     public: | ||
|  |       awaitable(Op&& op, co_composed_promise& promise | ||
|  | #if defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | # if defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  |           , const asio::detail::source_location& location | ||
|  | # endif // defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  |         ) | ||
|  |         : op_(std::forward<Op>(op)), | ||
|  |           promise_(promise) | ||
|  | #if defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | # if defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  |         , location_(location) | ||
|  | # endif // defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #endif // defined(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(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | # if defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  |               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(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  |               std::forward<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(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | # if defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  |       asio::detail::source_location location_; | ||
|  | # endif // defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  |     }; | ||
|  | 
 | ||
|  |     state_.check_for_cancellation_on_transform(); | ||
|  |     return awaitable{std::forward<Op>(op), *this | ||
|  | #if defined(ASIO_ENABLE_HANDLER_TRACKING)
 | ||
|  | # if defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  |         , location | ||
|  | # endif // defined(ASIO_HAS_SOURCE_LOCATION)
 | ||
|  | #endif // defined(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<typename decay<Args>::type...> 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_(std::forward<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 = typename decay<Handler>::type; | ||
|  |     using returns_type = co_composed_returns<Signatures...>; | ||
|  |     co_composed_on_suspend on_suspend{}; | ||
|  |     implementation_( | ||
|  |         co_composed_state<Executors, handler_type, returns_type>( | ||
|  |           executors_, std::forward<Handler>(handler), on_suspend), | ||
|  |         std::forward<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 = typename decay<Handler>::type; | ||
|  |     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_), std::forward<Handler>(handler), on_suspend), | ||
|  |         std::forward<InitArgs>(init_args)...); | ||
|  |     if (on_suspend.fn_) | ||
|  |       on_suspend.fn_(on_suspend.arg_); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   Implementation implementation_; | ||
|  |   composed_io_executors<Executors> executors_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename... Signatures, typename Implementation, typename Executors> | ||
|  | inline initiate_co_composed<Implementation, Executors, Signatures...> | ||
|  | make_initiate_co_composed(Implementation&& implementation, | ||
|  |     composed_io_executors<Executors>&& executors) | ||
|  | { | ||
|  |   return initiate_co_composed< | ||
|  |     typename decay<Implementation>::type, Executors, Signatures...>( | ||
|  |         std::forward<Implementation>(implementation), std::move(executors)); | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace detail
 | ||
|  | 
 | ||
|  | template <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...>( | ||
|  |       std::forward<Implementation>(implementation), | ||
|  |       detail::make_composed_io_executors( | ||
|  |         detail::get_composed_io_executor( | ||
|  |           std::forward<IoObjectsOrExecutors>( | ||
|  |             io_objects_or_executors))...)); | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace experimental
 | ||
|  | 
 | ||
|  | #if !defined(GENERATING_DOCUMENTATION)
 | ||
|  | 
 | ||
|  | template <template <typename, typename> class Associator, | ||
|  |     typename Executors, typename Handler, typename Return, | ||
|  |     typename Signature, typename DefaultCandidate> | ||
|  | struct associator<Associator, | ||
|  |     experimental::detail::co_composed_handler< | ||
|  |       Executors, Handler, Return, Signature>, | ||
|  |     DefaultCandidate> | ||
|  |   : Associator<Handler, DefaultCandidate> | ||
|  | { | ||
|  |   static typename Associator<Handler, DefaultCandidate>::type | ||
|  |   get(const experimental::detail::co_composed_handler< | ||
|  |         Executors, Handler, Return, Signature>& h) ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return Associator<Handler, DefaultCandidate>::get( | ||
|  |         h.promise().state().handler()); | ||
|  |   } | ||
|  | 
 | ||
|  |   static ASIO_AUTO_RETURN_TYPE_PREFIX2( | ||
|  |       typename Associator<Handler, DefaultCandidate>::type) | ||
|  |   get(const experimental::detail::co_composed_handler< | ||
|  |         Executors, Handler, Return, Signature>& h, | ||
|  |       const DefaultCandidate& c) ASIO_NOEXCEPT | ||
|  |     ASIO_AUTO_RETURN_TYPE_SUFFIX(( | ||
|  |       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
 | ||
|  | 
 | ||
|  | #if !defined(GENERATING_DOCUMENTATION)
 | ||
|  | # if defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | namespace std { | ||
|  | # else // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | namespace std { namespace experimental { | ||
|  | # endif // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | 
 | ||
|  | template <typename C, typename Executors, | ||
|  |     typename Handler, typename Return, typename... Args> | ||
|  | struct coroutine_traits<void, C&, | ||
|  |     asio::experimental::detail::co_composed_state< | ||
|  |       Executors, Handler, Return>, | ||
|  |     Args...> | ||
|  | { | ||
|  |   using promise_type = | ||
|  |     asio::experimental::detail::co_composed_promise< | ||
|  |       Executors, Handler, Return>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename C, typename Executors, | ||
|  |     typename Handler, typename Return, typename... Args> | ||
|  | struct coroutine_traits<void, C&&, | ||
|  |     asio::experimental::detail::co_composed_state< | ||
|  |       Executors, Handler, Return>, | ||
|  |     Args...> | ||
|  | { | ||
|  |   using promise_type = | ||
|  |     asio::experimental::detail::co_composed_promise< | ||
|  |       Executors, Handler, Return>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executors, typename Handler, | ||
|  |     typename Return, typename... Args> | ||
|  | struct coroutine_traits<void, | ||
|  |     asio::experimental::detail::co_composed_state< | ||
|  |       Executors, Handler, Return>, | ||
|  |     Args...> | ||
|  | { | ||
|  |   using promise_type = | ||
|  |     asio::experimental::detail::co_composed_promise< | ||
|  |       Executors, Handler, Return>; | ||
|  | }; | ||
|  | 
 | ||
|  | # if defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | } // namespace std
 | ||
|  | # else // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | }} // namespace std::experimental
 | ||
|  | # endif // defined(ASIO_HAS_STD_COROUTINE)
 | ||
|  | #endif // !defined(GENERATING_DOCUMENTATION)
 | ||
|  | 
 | ||
|  | #include "asio/detail/pop_options.hpp"
 | ||
|  | 
 | ||
|  | #endif // ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
 |