123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323 |
- //
- // 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
|