Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:51

0001 //
0002 // experimental/impl/co_composed.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
0012 #define BOOST_ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <new>
0020 #include <tuple>
0021 #include <variant>
0022 #include <boost/asio/associated_cancellation_slot.hpp>
0023 #include <boost/asio/associator.hpp>
0024 #include <boost/asio/async_result.hpp>
0025 #include <boost/asio/cancellation_state.hpp>
0026 #include <boost/asio/detail/composed_work.hpp>
0027 #include <boost/asio/detail/recycling_allocator.hpp>
0028 #include <boost/asio/detail/throw_error.hpp>
0029 #include <boost/asio/detail/type_traits.hpp>
0030 #include <boost/asio/error.hpp>
0031 
0032 #if defined(BOOST_ASIO_HAS_STD_COROUTINE)
0033 # include <coroutine>
0034 #else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
0035 # include <experimental/coroutine>
0036 #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
0037 
0038 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0039 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0040 #  include <boost/asio/detail/source_location.hpp>
0041 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0042 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0043 
0044 #include <boost/asio/detail/push_options.hpp>
0045 
0046 namespace boost {
0047 namespace asio {
0048 namespace experimental {
0049 namespace detail {
0050 
0051 #if defined(BOOST_ASIO_HAS_STD_COROUTINE)
0052 using std::coroutine_handle;
0053 using std::suspend_always;
0054 using std::suspend_never;
0055 #else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
0056 using std::experimental::coroutine_handle;
0057 using std::experimental::suspend_always;
0058 using std::experimental::suspend_never;
0059 #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
0060 
0061 using boost::asio::detail::composed_io_executors;
0062 using boost::asio::detail::composed_work;
0063 using boost::asio::detail::composed_work_guard;
0064 using boost::asio::detail::get_composed_io_executor;
0065 using boost::asio::detail::make_composed_io_executors;
0066 using boost::asio::detail::recycling_allocator;
0067 using boost::asio::detail::throw_error;
0068 
0069 template <typename Executors, typename Handler, typename Return>
0070 class co_composed_state;
0071 
0072 template <typename Executors, typename Handler, typename Return>
0073 class co_composed_handler_base;
0074 
0075 template <typename Executors, typename Handler, typename Return>
0076 class co_composed_promise;
0077 
0078 template <completion_signature... Signatures>
0079 class co_composed_returns
0080 {
0081 };
0082 
0083 struct co_composed_on_suspend
0084 {
0085   void (*fn_)(void*) = nullptr;
0086   void* arg_ = nullptr;
0087 };
0088 
0089 template <typename... T>
0090 struct co_composed_completion : std::tuple<T&&...>
0091 {
0092   template <typename... U>
0093   co_composed_completion(U&&... u) noexcept
0094     : std::tuple<T&&...>(std::forward<U>(u)...)
0095   {
0096   }
0097 };
0098 
0099 template <typename Executors, typename Handler,
0100     typename Return, typename Signature>
0101 class co_composed_state_return_overload;
0102 
0103 template <typename Executors, typename Handler,
0104     typename Return, typename R, typename... Args>
0105 class co_composed_state_return_overload<
0106     Executors, Handler, Return, R(Args...)>
0107 {
0108 public:
0109   using derived_type = co_composed_state<Executors, Handler, Return>;
0110   using promise_type = co_composed_promise<Executors, Handler, Return>;
0111   using return_type = std::tuple<Args...>;
0112 
0113   void on_cancellation_complete_with(Args... args)
0114   {
0115     derived_type& state = *static_cast<derived_type*>(this);
0116     state.return_value_ = std::make_tuple(std::move(args)...);
0117     state.cancellation_on_suspend_fn(
0118         [](void* p)
0119         {
0120           auto& promise = *static_cast<promise_type*>(p);
0121 
0122           co_composed_handler_base<Executors, Handler,
0123             Return> composed_handler(promise);
0124 
0125           Handler handler(std::move(promise.state().handler_));
0126           return_type result(
0127               std::move(std::get<return_type>(promise.state().return_value_)));
0128 
0129           co_composed_handler_base<Executors, Handler,
0130             Return>(std::move(composed_handler));
0131 
0132           std::apply(std::move(handler), std::move(result));
0133         });
0134   }
0135 };
0136 
0137 template <typename Executors, typename Handler, typename Return>
0138 class co_composed_state_return;
0139 
0140 template <typename Executors, typename Handler, typename... Signatures>
0141 class co_composed_state_return<
0142     Executors, Handler, co_composed_returns<Signatures...>>
0143   : public co_composed_state_return_overload<Executors,
0144       Handler, co_composed_returns<Signatures...>, Signatures>...
0145 {
0146 public:
0147   using co_composed_state_return_overload<Executors,
0148     Handler, co_composed_returns<Signatures...>,
0149       Signatures>::on_cancellation_complete_with...;
0150 
0151 private:
0152   template <typename, typename, typename, typename>
0153     friend class co_composed_promise_return_overload;
0154   template <typename, typename, typename, typename>
0155     friend class co_composed_state_return_overload;
0156 
0157   std::variant<std::monostate,
0158     typename co_composed_state_return_overload<
0159       Executors, Handler, co_composed_returns<Signatures...>,
0160         Signatures>::return_type...> return_value_;
0161 };
0162 
0163 template <typename Executors, typename Handler,
0164     typename Return, typename... Signatures>
0165 struct co_composed_state_default_cancellation_on_suspend_impl;
0166 
0167 template <typename Executors, typename Handler, typename Return>
0168 struct co_composed_state_default_cancellation_on_suspend_impl<
0169     Executors, Handler, Return>
0170 {
0171   static constexpr void (*fn())(void*)
0172   {
0173     return nullptr;
0174   }
0175 };
0176 
0177 template <typename Executors, typename Handler, typename Return,
0178     typename R, typename... Args, typename... Signatures>
0179 struct co_composed_state_default_cancellation_on_suspend_impl<
0180     Executors, Handler, Return, R(Args...), Signatures...>
0181 {
0182   static constexpr void (*fn())(void*)
0183   {
0184     return co_composed_state_default_cancellation_on_suspend_impl<
0185       Executors, Handler, Return, Signatures...>::fn();
0186   }
0187 };
0188 
0189 template <typename Executors, typename Handler, typename Return,
0190     typename R, typename... Args, typename... Signatures>
0191 struct co_composed_state_default_cancellation_on_suspend_impl<Executors,
0192     Handler, Return, R(boost::system::error_code, Args...), Signatures...>
0193 {
0194   using promise_type = co_composed_promise<Executors, Handler, Return>;
0195   using return_type = std::tuple<boost::system::error_code, Args...>;
0196 
0197   static constexpr void (*fn())(void*)
0198   {
0199     if constexpr ((is_constructible<Args>::value && ...))
0200     {
0201       return [](void* p)
0202       {
0203         auto& promise = *static_cast<promise_type*>(p);
0204 
0205         co_composed_handler_base<Executors, Handler,
0206           Return> composed_handler(promise);
0207 
0208         Handler handler(std::move(promise.state().handler_));
0209 
0210         co_composed_handler_base<Executors, Handler,
0211           Return>(std::move(composed_handler));
0212 
0213         std::move(handler)(
0214             boost::system::error_code(boost::asio::error::operation_aborted),
0215             Args{}...);
0216       };
0217     }
0218     else
0219     {
0220       return co_composed_state_default_cancellation_on_suspend_impl<
0221         Executors, Handler, Return, Signatures...>::fn();
0222     }
0223   }
0224 };
0225 
0226 template <typename Executors, typename Handler, typename Return,
0227     typename R, typename... Args, typename... Signatures>
0228 struct co_composed_state_default_cancellation_on_suspend_impl<Executors,
0229     Handler, Return, R(std::exception_ptr, Args...), Signatures...>
0230 {
0231   using promise_type = co_composed_promise<Executors, Handler, Return>;
0232   using return_type = std::tuple<std::exception_ptr, Args...>;
0233 
0234   static constexpr void (*fn())(void*)
0235   {
0236     if constexpr ((is_constructible<Args>::value && ...))
0237     {
0238       return [](void* p)
0239       {
0240         auto& promise = *static_cast<promise_type*>(p);
0241 
0242         co_composed_handler_base<Executors, Handler,
0243           Return> composed_handler(promise);
0244 
0245         Handler handler(std::move(promise.state().handler_));
0246 
0247         co_composed_handler_base<Executors, Handler,
0248           Return>(std::move(composed_handler));
0249 
0250         std::move(handler)(
0251             std::make_exception_ptr(
0252               boost::system::system_error(
0253                 boost::asio::error::operation_aborted, "co_await")),
0254             Args{}...);
0255       };
0256     }
0257     else
0258     {
0259       return co_composed_state_default_cancellation_on_suspend_impl<
0260         Executors, Handler, Return, Signatures...>::fn();
0261     }
0262   }
0263 };
0264 
0265 template <typename Executors, typename Handler, typename Return>
0266 struct co_composed_state_default_cancellation_on_suspend;
0267 
0268 template <typename Executors, typename Handler, typename... Signatures>
0269 struct co_composed_state_default_cancellation_on_suspend<
0270     Executors, Handler, co_composed_returns<Signatures...>>
0271   : co_composed_state_default_cancellation_on_suspend_impl<Executors,
0272       Handler, co_composed_returns<Signatures...>, Signatures...>
0273 {
0274 };
0275 
0276 template <typename Executors, typename Handler, typename Return>
0277 class co_composed_state_cancellation
0278 {
0279 public:
0280   using cancellation_slot_type = cancellation_slot;
0281 
0282   cancellation_slot_type get_cancellation_slot() const noexcept
0283   {
0284     return cancellation_state_.slot();
0285   }
0286 
0287   cancellation_state get_cancellation_state() const noexcept
0288   {
0289     return cancellation_state_;
0290   }
0291 
0292   void reset_cancellation_state()
0293   {
0294     cancellation_state_ = cancellation_state(
0295         (get_associated_cancellation_slot)(
0296           static_cast<co_composed_state<Executors, Handler, Return>*>(
0297             this)->handler()));
0298   }
0299 
0300   template <typename Filter>
0301   void reset_cancellation_state(Filter filter)
0302   {
0303     cancellation_state_ = cancellation_state(
0304         (get_associated_cancellation_slot)(
0305           static_cast<co_composed_state<Executors, Handler, Return>*>(
0306             this)->handler()), filter, filter);
0307   }
0308 
0309   template <typename InFilter, typename OutFilter>
0310   void reset_cancellation_state(InFilter&& in_filter, OutFilter&& out_filter)
0311   {
0312     cancellation_state_ = cancellation_state(
0313         (get_associated_cancellation_slot)(
0314           static_cast<co_composed_state<Executors, Handler, Return>*>(
0315             this)->handler()),
0316         std::forward<InFilter>(in_filter),
0317         std::forward<OutFilter>(out_filter));
0318   }
0319 
0320   cancellation_type_t cancelled() const noexcept
0321   {
0322     return cancellation_state_.cancelled();
0323   }
0324 
0325   void clear_cancellation_slot() noexcept
0326   {
0327     cancellation_state_.slot().clear();
0328   }
0329 
0330   [[nodiscard]] bool throw_if_cancelled() const noexcept
0331   {
0332     return throw_if_cancelled_;
0333   }
0334 
0335   void throw_if_cancelled(bool b) noexcept
0336   {
0337     throw_if_cancelled_ = b;
0338   }
0339 
0340   [[nodiscard]] bool complete_if_cancelled() const noexcept
0341   {
0342     return complete_if_cancelled_;
0343   }
0344 
0345   void complete_if_cancelled(bool b) noexcept
0346   {
0347     complete_if_cancelled_ = b;
0348   }
0349 
0350 private:
0351   template <typename, typename, typename>
0352     friend class co_composed_promise;
0353   template <typename, typename, typename, typename>
0354     friend class co_composed_state_return_overload;
0355 
0356   void cancellation_on_suspend_fn(void (*fn)(void*))
0357   {
0358     cancellation_on_suspend_fn_ = fn;
0359   }
0360 
0361   void check_for_cancellation_on_transform()
0362   {
0363     if (throw_if_cancelled_ && !!cancelled())
0364       throw_error(boost::asio::error::operation_aborted, "co_await");
0365   }
0366 
0367   bool check_for_cancellation_on_suspend(
0368       co_composed_promise<Executors, Handler, Return>& promise) noexcept
0369   {
0370     if (complete_if_cancelled_ && !!cancelled() && cancellation_on_suspend_fn_)
0371     {
0372       promise.state().work_.reset();
0373       promise.state().on_suspend_->fn_ = cancellation_on_suspend_fn_;
0374       promise.state().on_suspend_->arg_ = &promise;
0375       return false;
0376     }
0377     return true;
0378   }
0379 
0380   cancellation_state cancellation_state_;
0381   void (*cancellation_on_suspend_fn_)(void*) =
0382     co_composed_state_default_cancellation_on_suspend<
0383       Executors, Handler, Return>::fn();
0384   bool throw_if_cancelled_ = false;
0385   bool complete_if_cancelled_ = true;
0386 };
0387 
0388 template <typename Executors, typename Handler, typename Return>
0389   requires is_same<
0390     typename associated_cancellation_slot<
0391       Handler, cancellation_slot
0392     >::asio_associated_cancellation_slot_is_unspecialised,
0393     void>::value
0394 class co_composed_state_cancellation<Executors, Handler, Return>
0395 {
0396 public:
0397   void reset_cancellation_state()
0398   {
0399   }
0400 
0401   template <typename Filter>
0402   void reset_cancellation_state(Filter)
0403   {
0404   }
0405 
0406   template <typename InFilter, typename OutFilter>
0407   void reset_cancellation_state(InFilter&&, OutFilter&&)
0408   {
0409   }
0410 
0411   cancellation_type_t cancelled() const noexcept
0412   {
0413     return cancellation_type::none;
0414   }
0415 
0416   void clear_cancellation_slot() noexcept
0417   {
0418   }
0419 
0420   [[nodiscard]] bool throw_if_cancelled() const noexcept
0421   {
0422     return false;
0423   }
0424 
0425   void throw_if_cancelled(bool) noexcept
0426   {
0427   }
0428 
0429   [[nodiscard]] bool complete_if_cancelled() const noexcept
0430   {
0431     return false;
0432   }
0433 
0434   void complete_if_cancelled(bool) noexcept
0435   {
0436   }
0437 
0438 private:
0439   template <typename, typename, typename>
0440     friend class co_composed_promise;
0441   template <typename, typename, typename, typename>
0442     friend class co_composed_state_return_overload;
0443 
0444   void cancellation_on_suspend_fn(void (*)(void*))
0445   {
0446   }
0447 
0448   void check_for_cancellation_on_transform() noexcept
0449   {
0450   }
0451 
0452   bool check_for_cancellation_on_suspend(
0453       co_composed_promise<Executors, Handler, Return>&) noexcept
0454   {
0455     return true;
0456   }
0457 };
0458 
0459 template <typename Executors, typename Handler, typename Return>
0460 class co_composed_state
0461   : public co_composed_state_return<Executors, Handler, Return>,
0462     public co_composed_state_cancellation<Executors, Handler, Return>
0463 {
0464 public:
0465   using io_executor_type = typename composed_work_guard<
0466     typename composed_work<Executors>::head_type>::executor_type;
0467 
0468   template <typename H>
0469   co_composed_state(composed_io_executors<Executors>&& executors,
0470       H&& h, co_composed_on_suspend& on_suspend)
0471     : work_(std::move(executors)),
0472       handler_(std::forward<H>(h)),
0473       on_suspend_(&on_suspend)
0474   {
0475     this->reset_cancellation_state(enable_terminal_cancellation());
0476   }
0477 
0478   io_executor_type get_io_executor() const noexcept
0479   {
0480     return work_.head_.get_executor();
0481   }
0482 
0483   template <typename... Args>
0484   [[nodiscard]] co_composed_completion<Args...> complete(Args&&... args)
0485     requires requires { declval<Handler>()(std::forward<Args>(args)...); }
0486   {
0487     return co_composed_completion<Args...>(std::forward<Args>(args)...);
0488   }
0489 
0490   const Handler& handler() const noexcept
0491   {
0492     return handler_;
0493   }
0494 
0495 private:
0496   template <typename, typename, typename>
0497     friend class co_composed_handler_base;
0498   template <typename, typename, typename>
0499     friend class co_composed_promise;
0500   template <typename, typename, typename, typename>
0501     friend class co_composed_promise_return_overload;
0502   template <typename, typename, typename>
0503     friend class co_composed_state_cancellation;
0504   template <typename, typename, typename, typename>
0505     friend class co_composed_state_return_overload;
0506   template <typename, typename, typename, typename...>
0507     friend struct co_composed_state_default_cancellation_on_suspend_impl;
0508 
0509   composed_work<Executors> work_;
0510   Handler handler_;
0511   co_composed_on_suspend* on_suspend_;
0512 };
0513 
0514 template <typename Executors, typename Handler, typename Return>
0515 class co_composed_handler_cancellation
0516 {
0517 public:
0518   using cancellation_slot_type = cancellation_slot;
0519 
0520   cancellation_slot_type get_cancellation_slot() const noexcept
0521   {
0522     return static_cast<
0523       const co_composed_handler_base<Executors, Handler, Return>*>(
0524         this)->promise().state().get_cancellation_slot();
0525   }
0526 };
0527 
0528 template <typename Executors, typename Handler, typename Return>
0529   requires is_same<
0530     typename associated_cancellation_slot<
0531       Handler, cancellation_slot
0532     >::asio_associated_cancellation_slot_is_unspecialised,
0533     void>::value
0534 class co_composed_handler_cancellation<Executors, Handler, Return>
0535 {
0536 };
0537 
0538 template <typename Executors, typename Handler, typename Return>
0539 class co_composed_handler_base :
0540   public co_composed_handler_cancellation<Executors, Handler, Return>
0541 {
0542 public:
0543   co_composed_handler_base(
0544       co_composed_promise<Executors, Handler, Return>& p) noexcept
0545     : p_(&p)
0546   {
0547   }
0548 
0549   co_composed_handler_base(co_composed_handler_base&& other) noexcept
0550     : p_(std::exchange(other.p_, nullptr))
0551   {
0552   }
0553 
0554   ~co_composed_handler_base()
0555   {
0556     if (p_) [[unlikely]]
0557       p_->destroy();
0558   }
0559 
0560   co_composed_promise<Executors, Handler, Return>& promise() const noexcept
0561   {
0562     return *p_;
0563   }
0564 
0565 protected:
0566   void resume(void* result)
0567   {
0568     co_composed_on_suspend on_suspend{};
0569     std::exchange(p_, nullptr)->resume(p_, result, on_suspend);
0570     if (on_suspend.fn_)
0571       on_suspend.fn_(on_suspend.arg_);
0572   }
0573 
0574 private:
0575   co_composed_promise<Executors, Handler, Return>* p_;
0576 };
0577 
0578 template <typename Executors, typename Handler,
0579     typename Return, typename Signature>
0580 class co_composed_handler;
0581 
0582 template <typename Executors, typename Handler,
0583     typename Return, typename R, typename... Args>
0584 class co_composed_handler<Executors, Handler, Return, R(Args...)>
0585   : public co_composed_handler_base<Executors, Handler, Return>
0586 {
0587 public:
0588   using co_composed_handler_base<Executors,
0589     Handler, Return>::co_composed_handler_base;
0590 
0591   using result_type = std::tuple<decay_t<Args>...>;
0592 
0593   template <typename... T>
0594   void operator()(T&&... args)
0595   {
0596     result_type result(std::forward<T>(args)...);
0597     this->resume(&result);
0598   }
0599 
0600   static auto on_resume(void* result)
0601   {
0602     auto& args = *static_cast<result_type*>(result);
0603     if constexpr (sizeof...(Args) == 0)
0604       return;
0605     else if constexpr (sizeof...(Args) == 1)
0606       return std::move(std::get<0>(args));
0607     else
0608       return std::move(args);
0609   }
0610 };
0611 
0612 template <typename Executors, typename Handler,
0613     typename Return, typename R, typename... Args>
0614 class co_composed_handler<Executors, Handler,
0615     Return, R(boost::system::error_code, Args...)>
0616   : public co_composed_handler_base<Executors, Handler, Return>
0617 {
0618 public:
0619   using co_composed_handler_base<Executors,
0620     Handler, Return>::co_composed_handler_base;
0621 
0622   using args_type = std::tuple<decay_t<Args>...>;
0623   using result_type = std::tuple<boost::system::error_code, args_type>;
0624 
0625   template <typename... T>
0626   void operator()(const boost::system::error_code& ec, T&&... args)
0627   {
0628     result_type result(ec, args_type(std::forward<T>(args)...));
0629     this->resume(&result);
0630   }
0631 
0632   static auto on_resume(void* result)
0633   {
0634     auto& [ec, args] = *static_cast<result_type*>(result);
0635     throw_error(ec);
0636     if constexpr (sizeof...(Args) == 0)
0637       return;
0638     else if constexpr (sizeof...(Args) == 1)
0639       return std::move(std::get<0>(args));
0640     else
0641       return std::move(args);
0642   }
0643 };
0644 
0645 template <typename Executors, typename Handler,
0646     typename Return, typename R, typename... Args>
0647 class co_composed_handler<Executors, Handler,
0648     Return, R(std::exception_ptr, Args...)>
0649   : public co_composed_handler_base<Executors, Handler, Return>
0650 {
0651 public:
0652   using co_composed_handler_base<Executors,
0653     Handler, Return>::co_composed_handler_base;
0654 
0655   using args_type = std::tuple<decay_t<Args>...>;
0656   using result_type = std::tuple<std::exception_ptr, args_type>;
0657 
0658   template <typename... T>
0659   void operator()(std::exception_ptr ex, T&&... args)
0660   {
0661     result_type result(std::move(ex), args_type(std::forward<T>(args)...));
0662     this->resume(&result);
0663   }
0664 
0665   static auto on_resume(void* result)
0666   {
0667     auto& [ex, args] = *static_cast<result_type*>(result);
0668     if (ex)
0669       std::rethrow_exception(ex);
0670     if constexpr (sizeof...(Args) == 0)
0671       return;
0672     else if constexpr (sizeof...(Args) == 1)
0673       return std::move(std::get<0>(args));
0674     else
0675       return std::move(args);
0676   }
0677 };
0678 
0679 template <typename Executors, typename Handler, typename Return>
0680 class co_composed_promise_return;
0681 
0682 template <typename Executors, typename Handler>
0683 class co_composed_promise_return<Executors, Handler, co_composed_returns<>>
0684 {
0685 public:
0686   auto final_suspend() noexcept
0687   {
0688     return suspend_never();
0689   }
0690 
0691   void return_void() noexcept
0692   {
0693   }
0694 };
0695 
0696 template <typename Executors, typename Handler,
0697     typename Return, typename Signature>
0698 class co_composed_promise_return_overload;
0699 
0700 template <typename Executors, typename Handler,
0701     typename Return, typename R, typename... Args>
0702 class co_composed_promise_return_overload<
0703     Executors, Handler, Return, R(Args...)>
0704 {
0705 public:
0706   using derived_type = co_composed_promise<Executors, Handler, Return>;
0707   using return_type = std::tuple<Args...>;
0708 
0709   void return_value(std::tuple<Args...>&& value)
0710   {
0711     derived_type& promise = *static_cast<derived_type*>(this);
0712     promise.state().return_value_ = std::move(value);
0713     promise.state().work_.reset();
0714     promise.state().on_suspend_->arg_ = this;
0715     promise.state().on_suspend_->fn_ =
0716       [](void* p)
0717       {
0718         auto& promise = *static_cast<derived_type*>(p);
0719 
0720         co_composed_handler_base<Executors, Handler,
0721           Return> composed_handler(promise);
0722 
0723         Handler handler(std::move(promise.state().handler_));
0724         return_type result(
0725             std::move(std::get<return_type>(promise.state().return_value_)));
0726 
0727         co_composed_handler_base<Executors, Handler,
0728           Return>(std::move(composed_handler));
0729 
0730         std::apply(std::move(handler), std::move(result));
0731       };
0732   }
0733 };
0734 
0735 template <typename Executors, typename Handler, typename... Signatures>
0736 class co_composed_promise_return<Executors,
0737     Handler, co_composed_returns<Signatures...>>
0738   : public co_composed_promise_return_overload<Executors,
0739       Handler, co_composed_returns<Signatures...>, Signatures>...
0740 {
0741 public:
0742   auto final_suspend() noexcept
0743   {
0744     return suspend_always();
0745   }
0746 
0747   using co_composed_promise_return_overload<Executors, Handler,
0748     co_composed_returns<Signatures...>, Signatures>::return_value...;
0749 
0750 private:
0751   template <typename, typename, typename, typename>
0752     friend class co_composed_promise_return_overload;
0753 };
0754 
0755 template <typename Executors, typename Handler, typename Return>
0756 class co_composed_promise
0757   : public co_composed_promise_return<Executors, Handler, Return>
0758 {
0759 public:
0760   template <typename... Args>
0761   void* operator new(std::size_t size,
0762       co_composed_state<Executors, Handler, Return>& state, Args&&...)
0763   {
0764     block_allocator_type allocator(
0765       (get_associated_allocator)(state.handler_,
0766         recycling_allocator<void>()));
0767 
0768     block* base_ptr = std::allocator_traits<block_allocator_type>::allocate(
0769         allocator, blocks(sizeof(allocator_type)) + blocks(size));
0770 
0771     new (static_cast<void*>(base_ptr)) allocator_type(std::move(allocator));
0772 
0773     return base_ptr + blocks(sizeof(allocator_type));
0774   }
0775 
0776   template <typename C, typename... Args>
0777   void* operator new(std::size_t size, C&&,
0778       co_composed_state<Executors, Handler, Return>& state, Args&&...)
0779   {
0780     return co_composed_promise::operator new(size, state);
0781   }
0782 
0783   void operator delete(void* ptr, std::size_t size)
0784   {
0785     block* base_ptr = static_cast<block*>(ptr) - blocks(sizeof(allocator_type));
0786 
0787     allocator_type* allocator_ptr = std::launder(
0788         static_cast<allocator_type*>(static_cast<void*>(base_ptr)));
0789 
0790     block_allocator_type block_allocator(std::move(*allocator_ptr));
0791     allocator_ptr->~allocator_type();
0792 
0793     std::allocator_traits<block_allocator_type>::deallocate(block_allocator,
0794         base_ptr, blocks(sizeof(allocator_type)) + blocks(size));
0795   }
0796 
0797   template <typename... Args>
0798   co_composed_promise(
0799       co_composed_state<Executors, Handler, Return>& state, Args&&...)
0800     : state_(state)
0801   {
0802   }
0803 
0804   template <typename C, typename... Args>
0805   co_composed_promise(C&&,
0806       co_composed_state<Executors, Handler, Return>& state, Args&&...)
0807     : state_(state)
0808   {
0809   }
0810 
0811   void destroy() noexcept
0812   {
0813     coroutine_handle<co_composed_promise>::from_promise(*this).destroy();
0814   }
0815 
0816   void resume(co_composed_promise*& owner, void* result,
0817       co_composed_on_suspend& on_suspend)
0818   {
0819     state_.on_suspend_ = &on_suspend;
0820     state_.clear_cancellation_slot();
0821     owner_ = &owner;
0822     result_ = result;
0823     coroutine_handle<co_composed_promise>::from_promise(*this).resume();
0824   }
0825 
0826   co_composed_state<Executors, Handler, Return>& state() noexcept
0827   {
0828     return state_;
0829   }
0830 
0831   void get_return_object() noexcept
0832   {
0833   }
0834 
0835   auto initial_suspend() noexcept
0836   {
0837     return suspend_never();
0838   }
0839 
0840   void unhandled_exception()
0841   {
0842     if (owner_)
0843       *owner_ = this;
0844     throw;
0845   }
0846 
0847   template <async_operation Op>
0848   auto await_transform(Op&& op
0849 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0850 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0851       , boost::asio::detail::source_location location
0852         = boost::asio::detail::source_location::current()
0853 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0854 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0855     )
0856   {
0857     class [[nodiscard]] awaitable
0858     {
0859     public:
0860       awaitable(Op&& op, co_composed_promise& promise
0861 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0862 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0863           , const boost::asio::detail::source_location& location
0864 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0865 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0866         )
0867         : op_(std::forward<Op>(op)),
0868           promise_(promise)
0869 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0870 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0871         , location_(location)
0872 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0873 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0874       {
0875       }
0876 
0877       constexpr bool await_ready() const noexcept
0878       {
0879         return false;
0880       }
0881 
0882       void await_suspend(coroutine_handle<co_composed_promise>)
0883       {
0884         if (promise_.state_.check_for_cancellation_on_suspend(promise_))
0885         {
0886           promise_.state_.on_suspend_->arg_ = this;
0887           promise_.state_.on_suspend_->fn_ =
0888             [](void* p)
0889             {
0890 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0891 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0892               BOOST_ASIO_HANDLER_LOCATION((
0893                   static_cast<awaitable*>(p)->location_.file_name(),
0894                   static_cast<awaitable*>(p)->location_.line(),
0895                   static_cast<awaitable*>(p)->location_.function_name()));
0896 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0897 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0898               std::forward<Op>(static_cast<awaitable*>(p)->op_)(
0899                   co_composed_handler<Executors, Handler,
0900                     Return, completion_signature_of_t<Op>>(
0901                       static_cast<awaitable*>(p)->promise_));
0902             };
0903         }
0904       }
0905 
0906       auto await_resume()
0907       {
0908         return co_composed_handler<Executors, Handler, Return,
0909           completion_signature_of_t<Op>>::on_resume(promise_.result_);
0910       }
0911 
0912     private:
0913       Op&& op_;
0914       co_composed_promise& promise_;
0915 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0916 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0917       boost::asio::detail::source_location location_;
0918 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0919 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0920     };
0921 
0922     state_.check_for_cancellation_on_transform();
0923     return awaitable{std::forward<Op>(op), *this
0924 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0925 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0926         , location
0927 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0928 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0929       };
0930   }
0931 
0932   template <typename... Args>
0933   auto yield_value(co_composed_completion<Args...>&& result)
0934   {
0935     class [[nodiscard]] awaitable
0936     {
0937     public:
0938       awaitable(co_composed_completion<Args...>&& result,
0939           co_composed_promise& promise)
0940         : result_(std::move(result)),
0941           promise_(promise)
0942       {
0943       }
0944 
0945       constexpr bool await_ready() const noexcept
0946       {
0947         return false;
0948       }
0949 
0950       void await_suspend(coroutine_handle<co_composed_promise>)
0951       {
0952         promise_.state_.work_.reset();
0953         promise_.state_.on_suspend_->arg_ = this;
0954         promise_.state_.on_suspend_->fn_ =
0955           [](void* p)
0956           {
0957             awaitable& a = *static_cast<awaitable*>(p);
0958 
0959             co_composed_handler_base<Executors, Handler,
0960               Return> composed_handler(a.promise_);
0961 
0962             Handler handler(std::move(a.promise_.state_.handler_));
0963             std::tuple<decay_t<Args>...> result(
0964                 std::move(static_cast<std::tuple<Args&&...>>(a.result_)));
0965 
0966             co_composed_handler_base<Executors, Handler,
0967               Return>(std::move(composed_handler));
0968 
0969             std::apply(std::move(handler), std::move(result));
0970           };
0971       }
0972 
0973       void await_resume() noexcept
0974       {
0975       }
0976 
0977     private:
0978       co_composed_completion<Args...> result_;
0979       co_composed_promise& promise_;
0980     };
0981 
0982     return awaitable{std::move(result), *this};
0983   }
0984 
0985 private:
0986   using allocator_type =
0987     associated_allocator_t<Handler, recycling_allocator<void>>;
0988 
0989   union block
0990   {
0991     std::max_align_t max_align;
0992     alignas(allocator_type) char pad[alignof(allocator_type)];
0993   };
0994 
0995   using block_allocator_type =
0996     typename std::allocator_traits<allocator_type>
0997       ::template rebind_alloc<block>;
0998 
0999   static constexpr std::size_t blocks(std::size_t size)
1000   {
1001     return (size + sizeof(block) - 1) / sizeof(block);
1002   }
1003 
1004   co_composed_state<Executors, Handler, Return>& state_;
1005   co_composed_promise** owner_ = nullptr;
1006   void* result_ = nullptr;
1007 };
1008 
1009 template <typename Implementation, typename Executors, typename... Signatures>
1010 class initiate_co_composed
1011 {
1012 public:
1013   using executor_type = typename composed_io_executors<Executors>::head_type;
1014 
1015   template <typename I>
1016   initiate_co_composed(I&& impl, composed_io_executors<Executors>&& executors)
1017     : implementation_(std::forward<I>(impl)),
1018       executors_(std::move(executors))
1019   {
1020   }
1021 
1022   executor_type get_executor() const noexcept
1023   {
1024     return executors_.head_;
1025   }
1026 
1027   template <typename Handler, typename... InitArgs>
1028   void operator()(Handler&& handler, InitArgs&&... init_args) const &
1029   {
1030     using handler_type = decay_t<Handler>;
1031     using returns_type = co_composed_returns<Signatures...>;
1032     co_composed_on_suspend on_suspend{};
1033     implementation_(
1034         co_composed_state<Executors, handler_type, returns_type>(
1035           executors_, std::forward<Handler>(handler), on_suspend),
1036         std::forward<InitArgs>(init_args)...);
1037     if (on_suspend.fn_)
1038       on_suspend.fn_(on_suspend.arg_);
1039   }
1040 
1041   template <typename Handler, typename... InitArgs>
1042   void operator()(Handler&& handler, InitArgs&&... init_args) &&
1043   {
1044     using handler_type = decay_t<Handler>;
1045     using returns_type = co_composed_returns<Signatures...>;
1046     co_composed_on_suspend on_suspend{};
1047     std::move(implementation_)(
1048         co_composed_state<Executors, handler_type, returns_type>(
1049           std::move(executors_), std::forward<Handler>(handler), on_suspend),
1050         std::forward<InitArgs>(init_args)...);
1051     if (on_suspend.fn_)
1052       on_suspend.fn_(on_suspend.arg_);
1053   }
1054 
1055 private:
1056   Implementation implementation_;
1057   composed_io_executors<Executors> executors_;
1058 };
1059 
1060 template <typename... Signatures, typename Implementation, typename Executors>
1061 inline initiate_co_composed<Implementation, Executors, Signatures...>
1062 make_initiate_co_composed(Implementation&& implementation,
1063     composed_io_executors<Executors>&& executors)
1064 {
1065   return initiate_co_composed<
1066     decay_t<Implementation>, Executors, Signatures...>(
1067         std::forward<Implementation>(implementation), std::move(executors));
1068 }
1069 
1070 } // namespace detail
1071 
1072 template <completion_signature... Signatures,
1073     typename Implementation, typename... IoObjectsOrExecutors>
1074 inline auto co_composed(Implementation&& implementation,
1075     IoObjectsOrExecutors&&... io_objects_or_executors)
1076 {
1077   return detail::make_initiate_co_composed<Signatures...>(
1078       std::forward<Implementation>(implementation),
1079       detail::make_composed_io_executors(
1080         detail::get_composed_io_executor(
1081           std::forward<IoObjectsOrExecutors>(
1082             io_objects_or_executors))...));
1083 }
1084 
1085 } // namespace experimental
1086 
1087 #if !defined(GENERATING_DOCUMENTATION)
1088 
1089 template <template <typename, typename> class Associator,
1090     typename Executors, typename Handler, typename Return,
1091     typename Signature, typename DefaultCandidate>
1092 struct associator<Associator,
1093     experimental::detail::co_composed_handler<
1094       Executors, Handler, Return, Signature>,
1095     DefaultCandidate>
1096   : Associator<Handler, DefaultCandidate>
1097 {
1098   static typename Associator<Handler, DefaultCandidate>::type get(
1099       const experimental::detail::co_composed_handler<
1100         Executors, Handler, Return, Signature>& h) noexcept
1101   {
1102     return Associator<Handler, DefaultCandidate>::get(
1103         h.promise().state().handler());
1104   }
1105 
1106   static auto get(
1107       const experimental::detail::co_composed_handler<
1108         Executors, Handler, Return, Signature>& h,
1109       const DefaultCandidate& c) noexcept
1110     -> decltype(
1111       Associator<Handler, DefaultCandidate>::get(
1112         h.promise().state().handler(), c))
1113   {
1114     return Associator<Handler, DefaultCandidate>::get(
1115         h.promise().state().handler(), c);
1116   }
1117 };
1118 
1119 #endif // !defined(GENERATING_DOCUMENTATION)
1120 
1121 } // namespace asio
1122 } // namespace boost
1123 
1124 #if !defined(GENERATING_DOCUMENTATION)
1125 # if defined(BOOST_ASIO_HAS_STD_COROUTINE)
1126 namespace std {
1127 # else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1128 namespace std { namespace experimental {
1129 # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1130 
1131 template <typename C, typename Executors,
1132     typename Handler, typename Return, typename... Args>
1133 struct coroutine_traits<void, C&,
1134     boost::asio::experimental::detail::co_composed_state<
1135       Executors, Handler, Return>,
1136     Args...>
1137 {
1138   using promise_type =
1139     boost::asio::experimental::detail::co_composed_promise<
1140       Executors, Handler, Return>;
1141 };
1142 
1143 template <typename C, typename Executors,
1144     typename Handler, typename Return, typename... Args>
1145 struct coroutine_traits<void, C&&,
1146     boost::asio::experimental::detail::co_composed_state<
1147       Executors, Handler, Return>,
1148     Args...>
1149 {
1150   using promise_type =
1151     boost::asio::experimental::detail::co_composed_promise<
1152       Executors, Handler, Return>;
1153 };
1154 
1155 template <typename Executors, typename Handler,
1156     typename Return, typename... Args>
1157 struct coroutine_traits<void,
1158     boost::asio::experimental::detail::co_composed_state<
1159       Executors, Handler, Return>,
1160     Args...>
1161 {
1162   using promise_type =
1163     boost::asio::experimental::detail::co_composed_promise<
1164       Executors, Handler, Return>;
1165 };
1166 
1167 # if defined(BOOST_ASIO_HAS_STD_COROUTINE)
1168 } // namespace std
1169 # else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1170 }} // namespace std::experimental
1171 # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1172 #endif // !defined(GENERATING_DOCUMENTATION)
1173 
1174 #include <boost/asio/detail/pop_options.hpp>
1175 
1176 #endif // BOOST_ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP