1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174 |
- //
- // 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<decay_t<Args>...>;
- 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<decay_t<Args>...>;
- 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<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(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<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_(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 = 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_, 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 = 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_), 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<
- decay_t<Implementation>, 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) noexcept
- {
- return Associator<Handler, DefaultCandidate>::get(
- h.promise().state().handler());
- }
- static auto get(
- const experimental::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
- #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
|