Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // experimental/impl/coro.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2021-2023 Klemens D. Morgenstern
0006 //                         (klemens dot morgenstern at gmx dot net)
0007 //
0008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 
0011 //
0012 #ifndef BOOST_ASIO_EXPERIMENTAL_IMPL_CORO_HPP
0013 #define BOOST_ASIO_EXPERIMENTAL_IMPL_CORO_HPP
0014 
0015 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0016 # pragma once
0017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0018 
0019 #include <boost/asio/detail/config.hpp>
0020 #include <boost/asio/append.hpp>
0021 #include <boost/asio/associated_cancellation_slot.hpp>
0022 #include <boost/asio/bind_allocator.hpp>
0023 #include <boost/asio/deferred.hpp>
0024 #include <boost/asio/experimental/detail/coro_completion_handler.hpp>
0025 #include <boost/asio/detail/push_options.hpp>
0026 
0027 namespace boost {
0028 namespace asio {
0029 namespace experimental {
0030 
0031 template <typename Yield, typename Return,
0032     typename Executor, typename Allocator>
0033 struct coro;
0034 
0035 namespace detail {
0036 
0037 struct coro_cancellation_source
0038 {
0039   cancellation_slot slot;
0040   cancellation_state state;
0041   bool throw_if_cancelled_ = true;
0042 
0043   void reset_cancellation_state()
0044   {
0045     state = cancellation_state(slot);
0046   }
0047 
0048   template <typename Filter>
0049   void reset_cancellation_state(Filter&& filter)
0050   {
0051     state = cancellation_state(slot, static_cast<Filter&&>(filter));
0052   }
0053 
0054   template <typename InFilter, typename OutFilter>
0055   void reset_cancellation_state(InFilter&& in_filter,
0056       OutFilter&& out_filter)
0057   {
0058     state = cancellation_state(slot,
0059         static_cast<InFilter&&>(in_filter),
0060         static_cast<OutFilter&&>(out_filter));
0061   }
0062 
0063   bool throw_if_cancelled() const
0064   {
0065     return throw_if_cancelled_;
0066   }
0067 
0068   void throw_if_cancelled(bool value)
0069   {
0070     throw_if_cancelled_ = value;
0071   }
0072 };
0073 
0074 template <typename Signature, typename Return,
0075     typename Executor, typename Allocator>
0076 struct coro_promise;
0077 
0078 template <typename T>
0079 struct is_noexcept : std::false_type
0080 {
0081 };
0082 
0083 template <typename Return, typename... Args>
0084 struct is_noexcept<Return(Args...)> : std::false_type
0085 {
0086 };
0087 
0088 template <typename Return, typename... Args>
0089 struct is_noexcept<Return(Args...) noexcept> : std::true_type
0090 {
0091 };
0092 
0093 template <typename T>
0094 constexpr bool is_noexcept_v = is_noexcept<T>::value;
0095 
0096 template <typename T>
0097 struct coro_error;
0098 
0099 template <>
0100 struct coro_error<boost::system::error_code>
0101 {
0102   static boost::system::error_code invalid()
0103   {
0104     return boost::asio::error::fault;
0105   }
0106 
0107   static boost::system::error_code cancelled()
0108   {
0109     return boost::asio::error::operation_aborted;
0110   }
0111 
0112   static boost::system::error_code interrupted()
0113   {
0114     return boost::asio::error::interrupted;
0115   }
0116 
0117   static boost::system::error_code done()
0118   {
0119     return boost::asio::error::broken_pipe;
0120   }
0121 };
0122 
0123 template <>
0124 struct coro_error<std::exception_ptr>
0125 {
0126   static std::exception_ptr invalid()
0127   {
0128     return std::make_exception_ptr(
0129         boost::system::system_error(
0130           coro_error<boost::system::error_code>::invalid()));
0131   }
0132 
0133   static std::exception_ptr cancelled()
0134   {
0135     return std::make_exception_ptr(
0136         boost::system::system_error(
0137           coro_error<boost::system::error_code>::cancelled()));
0138   }
0139 
0140   static std::exception_ptr interrupted()
0141   {
0142     return std::make_exception_ptr(
0143         boost::system::system_error(
0144           coro_error<boost::system::error_code>::interrupted()));
0145   }
0146 
0147   static std::exception_ptr done()
0148   {
0149     return std::make_exception_ptr(
0150         boost::system::system_error(
0151           coro_error<boost::system::error_code>::done()));
0152   }
0153 };
0154 
0155 template <typename T, typename Coroutine >
0156 struct coro_with_arg
0157 {
0158   using coro_t = Coroutine;
0159   T value;
0160   coro_t& coro;
0161 
0162   struct awaitable_t
0163   {
0164     T value;
0165     coro_t& coro;
0166 
0167     constexpr static bool await_ready() { return false; }
0168 
0169     template <typename Y, typename R, typename E, typename A>
0170     auto await_suspend(coroutine_handle<coro_promise<Y, R, E, A>> h)
0171       -> coroutine_handle<>
0172     {
0173       auto& hp = h.promise();
0174 
0175       if constexpr (!coro_promise<Y, R, E, A>::is_noexcept)
0176       {
0177         if ((hp.cancel->state.cancelled() != cancellation_type::none)
0178             && hp.cancel->throw_if_cancelled_)
0179         {
0180           boost::asio::detail::throw_error(
0181               boost::asio::error::operation_aborted, "coro-cancelled");
0182         }
0183       }
0184 
0185       if (hp.get_executor() == coro.get_executor())
0186       {
0187         coro.coro_->awaited_from = h;
0188         coro.coro_->reset_error();
0189         coro.coro_->input_ = std::move(value);
0190         coro.coro_->cancel = hp.cancel;
0191         return coro.coro_->get_handle();
0192       }
0193       else
0194       {
0195         coro.coro_->awaited_from =
0196           dispatch_coroutine(
0197               boost::asio::prefer(hp.get_executor(),
0198                 execution::outstanding_work.tracked),
0199                 [h]() mutable { h.resume(); }).handle;
0200 
0201         coro.coro_->reset_error();
0202         coro.coro_->input_ = std::move(value);
0203 
0204         struct cancel_handler
0205         {
0206           using src = std::pair<cancellation_signal,
0207                 detail::coro_cancellation_source>;
0208 
0209           std::shared_ptr<src> st = std::make_shared<src>();
0210 
0211           cancel_handler(E e, coro_t& coro) : e(e), coro_(coro.coro_)
0212           {
0213             st->second.state =
0214               cancellation_state(st->second.slot = st->first.slot());
0215           }
0216 
0217           E e;
0218           typename coro_t::promise_type* coro_;
0219 
0220           void operator()(cancellation_type ct)
0221           {
0222             boost::asio::dispatch(e, [ct, st = st]() mutable
0223             {
0224               auto & [sig, state] = *st;
0225               sig.emit(ct);
0226             });
0227           }
0228         };
0229 
0230         if (hp.cancel->state.slot().is_connected())
0231         {
0232           hp.cancel->state.slot().template emplace<cancel_handler>(
0233               coro.get_executor(), coro);
0234         }
0235 
0236         auto hh = detail::coroutine_handle<
0237           typename coro_t::promise_type>::from_promise(*coro.coro_);
0238 
0239         return dispatch_coroutine(
0240             coro.coro_->get_executor(), [hh]() mutable { hh.resume(); }).handle;
0241       }
0242     }
0243 
0244     auto await_resume() -> typename coro_t::result_type
0245     {
0246       coro.coro_->cancel = nullptr;
0247       coro.coro_->rethrow_if();
0248       return std::move(coro.coro_->result_);
0249     }
0250   };
0251 
0252   template <typename CompletionToken>
0253   auto async_resume(CompletionToken&& token) &&
0254   {
0255     return coro.async_resume(std::move(value),
0256         std::forward<CompletionToken>(token));
0257   }
0258 
0259   auto operator co_await() &&
0260   {
0261     return awaitable_t{std::move(value), coro};
0262   }
0263 };
0264 
0265 template <bool IsNoexcept>
0266 struct coro_promise_error;
0267 
0268 template <>
0269 struct coro_promise_error<false>
0270 {
0271   std::exception_ptr error_;
0272 
0273   void reset_error()
0274   {
0275     error_ = std::exception_ptr{};
0276   }
0277 
0278   void unhandled_exception()
0279   {
0280     error_ = std::current_exception();
0281   }
0282 
0283   void rethrow_if()
0284   {
0285     if (error_)
0286       std::rethrow_exception(error_);
0287   }
0288 };
0289 
0290 #if defined(__GNUC__)
0291 # pragma GCC diagnostic push
0292 # if defined(__clang__)
0293 #  pragma GCC diagnostic ignored "-Wexceptions"
0294 # else
0295 #  pragma GCC diagnostic ignored "-Wterminate"
0296 # endif
0297 #elif defined(_MSC_VER)
0298 # pragma warning(push)
0299 # pragma warning (disable:4297)
0300 #endif
0301 
0302 template <>
0303 struct coro_promise_error<true>
0304 {
0305   void reset_error()
0306   {
0307   }
0308 
0309   void unhandled_exception() noexcept
0310   {
0311     throw;
0312   }
0313 
0314   void rethrow_if()
0315   {
0316   }
0317 };
0318 
0319 #if defined(__GNUC__)
0320 # pragma GCC diagnostic pop
0321 #elif defined(_MSC_VER)
0322 # pragma warning(pop)
0323 #endif
0324 
0325 template <typename T = void>
0326 struct yield_input
0327 {
0328   T& value;
0329   coroutine_handle<> awaited_from{noop_coroutine()};
0330 
0331   bool await_ready() const noexcept
0332   {
0333     return false;
0334   }
0335 
0336   template <typename U>
0337   coroutine_handle<> await_suspend(coroutine_handle<U>) noexcept
0338   {
0339     return std::exchange(awaited_from, noop_coroutine());
0340   }
0341 
0342   T await_resume() const noexcept
0343   {
0344     return std::move(value);
0345   }
0346 };
0347 
0348 template <>
0349 struct yield_input<void>
0350 {
0351   coroutine_handle<> awaited_from{noop_coroutine()};
0352 
0353   bool await_ready() const noexcept
0354   {
0355     return false;
0356   }
0357 
0358   auto await_suspend(coroutine_handle<>) noexcept
0359   {
0360     return std::exchange(awaited_from, noop_coroutine());
0361   }
0362 
0363   constexpr void await_resume() const noexcept
0364   {
0365   }
0366 };
0367 
0368 struct coro_awaited_from
0369 {
0370   coroutine_handle<> awaited_from{noop_coroutine()};
0371 
0372   auto final_suspend() noexcept
0373   {
0374     struct suspendor
0375     {
0376       coroutine_handle<> awaited_from;
0377 
0378       constexpr static bool await_ready() noexcept
0379       {
0380         return false;
0381       }
0382 
0383       auto await_suspend(coroutine_handle<>) noexcept
0384       {
0385         return std::exchange(awaited_from, noop_coroutine());
0386       }
0387 
0388       constexpr static void await_resume() noexcept
0389       {
0390       }
0391     };
0392 
0393     return suspendor{std::exchange(awaited_from, noop_coroutine())};
0394   }
0395 
0396   ~coro_awaited_from()
0397   {
0398     awaited_from.resume();
0399   }//must be on the right executor
0400 };
0401 
0402 template <typename Yield, typename Input, typename Return>
0403 struct coro_promise_exchange : coro_awaited_from
0404 {
0405   using result_type = coro_result_t<Yield, Return>;
0406 
0407   result_type result_;
0408   Input input_;
0409 
0410   auto yield_value(Yield&& y)
0411   {
0412     result_ = std::move(y);
0413     return yield_input<Input>{std::move(input_),
0414         std::exchange(awaited_from, noop_coroutine())};
0415   }
0416 
0417   auto yield_value(const Yield& y)
0418   {
0419     result_ = y;
0420     return yield_input<Input>{std::move(input_),
0421         std::exchange(awaited_from, noop_coroutine())};
0422   }
0423 
0424   void return_value(const Return& r)
0425   {
0426     result_ = r;
0427   }
0428 
0429   void return_value(Return&& r)
0430   {
0431     result_ = std::move(r);
0432   }
0433 };
0434 
0435 template <typename YieldReturn>
0436 struct coro_promise_exchange<YieldReturn, void, YieldReturn> : coro_awaited_from
0437 {
0438   using result_type = coro_result_t<YieldReturn, YieldReturn>;
0439 
0440   result_type result_;
0441 
0442   auto yield_value(const YieldReturn& y)
0443   {
0444     result_ = y;
0445     return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
0446   }
0447 
0448   auto yield_value(YieldReturn&& y)
0449   {
0450     result_ = std::move(y);
0451     return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
0452   }
0453 
0454   void return_value(const YieldReturn& r)
0455   {
0456     result_ = r;
0457   }
0458 
0459   void return_value(YieldReturn&& r)
0460   {
0461     result_ = std::move(r);
0462   }
0463 };
0464 
0465 template <typename Yield, typename Return>
0466 struct coro_promise_exchange<Yield, void, Return> : coro_awaited_from
0467 {
0468   using result_type = coro_result_t<Yield, Return>;
0469 
0470   result_type result_;
0471 
0472   auto yield_value(const Yield& y)
0473   {
0474     result_.template emplace<0>(y);
0475     return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
0476   }
0477 
0478   auto yield_value(Yield&& y)
0479   {
0480     result_.template emplace<0>(std::move(y));
0481     return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
0482   }
0483 
0484   void return_value(const Return& r)
0485   {
0486     result_.template emplace<1>(r);
0487   }
0488 
0489   void return_value(Return&& r)
0490   {
0491     result_.template emplace<1>(std::move(r));
0492   }
0493 };
0494 
0495 template <typename Yield, typename Input>
0496 struct coro_promise_exchange<Yield, Input, void> : coro_awaited_from
0497 {
0498   using result_type = coro_result_t<Yield, void>;
0499 
0500   result_type result_;
0501   Input input_;
0502 
0503   auto yield_value(Yield&& y)
0504   {
0505     result_ = std::move(y);
0506     return yield_input<Input>{input_,
0507                               std::exchange(awaited_from, noop_coroutine())};
0508   }
0509 
0510   auto yield_value(const Yield& y)
0511   {
0512     result_ = y;
0513     return yield_input<Input>{input_,
0514                               std::exchange(awaited_from, noop_coroutine())};
0515   }
0516 
0517   void return_void()
0518   {
0519     result_.reset();
0520   }
0521 };
0522 
0523 template <typename Return>
0524 struct coro_promise_exchange<void, void, Return> : coro_awaited_from
0525 {
0526   using result_type = coro_result_t<void, Return>;
0527 
0528   result_type result_;
0529 
0530   void yield_value();
0531 
0532   void return_value(const Return& r)
0533   {
0534     result_ = r;
0535   }
0536 
0537   void return_value(Return&& r)
0538   {
0539     result_ = std::move(r);
0540   }
0541 };
0542 
0543 template <>
0544 struct coro_promise_exchange<void, void, void> : coro_awaited_from
0545 {
0546   void return_void() {}
0547 
0548   void yield_value();
0549 };
0550 
0551 template <typename Yield>
0552 struct coro_promise_exchange<Yield, void, void> : coro_awaited_from
0553 {
0554   using result_type = coro_result_t<Yield, void>;
0555 
0556   result_type result_;
0557 
0558   auto yield_value(const Yield& y)
0559   {
0560     result_ = y;
0561     return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
0562   }
0563 
0564   auto yield_value(Yield&& y)
0565   {
0566     result_ = std::move(y);
0567     return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
0568   }
0569 
0570   void return_void()
0571   {
0572     result_.reset();
0573   }
0574 };
0575 
0576 template <typename Yield, typename Return,
0577     typename Executor, typename Allocator>
0578 struct coro_promise final :
0579   coro_promise_allocator<Allocator>,
0580   coro_promise_error<coro_traits<Yield, Return, Executor>::is_noexcept>,
0581   coro_promise_exchange<
0582       typename coro_traits<Yield, Return, Executor>::yield_type,
0583       typename coro_traits<Yield, Return, Executor>::input_type,
0584       typename coro_traits<Yield, Return, Executor>::return_type>
0585 {
0586   using coro_type = coro<Yield, Return, Executor, Allocator>;
0587 
0588   auto handle()
0589   {
0590     return coroutine_handle<coro_promise>::from_promise(this);
0591   }
0592 
0593   using executor_type = Executor;
0594 
0595   executor_type executor_;
0596 
0597   std::optional<coro_cancellation_source> cancel_source;
0598   coro_cancellation_source * cancel;
0599 
0600   using cancellation_slot_type = boost::asio::cancellation_slot;
0601 
0602   cancellation_slot_type get_cancellation_slot() const noexcept
0603   {
0604     return cancel ? cancel->slot : cancellation_slot_type{};
0605   }
0606 
0607   using allocator_type =
0608     typename std::allocator_traits<associated_allocator_t<Executor>>::
0609       template rebind_alloc<std::byte>;
0610   using traits = coro_traits<Yield, Return, Executor>;
0611 
0612   using input_type = typename traits::input_type;
0613   using yield_type = typename traits::yield_type;
0614   using return_type = typename traits::return_type;
0615   using error_type = typename traits::error_type;
0616   using result_type = typename traits::result_type;
0617   constexpr static bool is_noexcept = traits::is_noexcept;
0618 
0619   auto get_executor() const -> Executor
0620   {
0621     return executor_;
0622   }
0623 
0624   auto get_handle()
0625   {
0626     return coroutine_handle<coro_promise>::from_promise(*this);
0627   }
0628 
0629   template <typename... Args>
0630   coro_promise(Executor executor, Args&&... args) noexcept
0631     : coro_promise_allocator<Allocator>(
0632         executor, std::forward<Args>(args)...),
0633       executor_(std::move(executor))
0634   {
0635   }
0636 
0637   template <typename First, typename... Args>
0638   coro_promise(First&& f, Executor executor, Args&&... args) noexcept
0639     : coro_promise_allocator<Allocator>(
0640         f, executor, std::forward<Args>(args)...),
0641       executor_(std::move(executor))
0642   {
0643   }
0644 
0645   template <typename First, detail::execution_context Context, typename... Args>
0646   coro_promise(First&& f, Context&& ctx, Args&&... args) noexcept
0647     : coro_promise_allocator<Allocator>(
0648         f, ctx, std::forward<Args>(args)...),
0649       executor_(ctx.get_executor())
0650   {
0651   }
0652 
0653   template <detail::execution_context Context, typename... Args>
0654   coro_promise(Context&& ctx, Args&&... args) noexcept
0655     : coro_promise_allocator<Allocator>(
0656         ctx, std::forward<Args>(args)...),
0657       executor_(ctx.get_executor())
0658   {
0659   }
0660 
0661   auto get_return_object()
0662   {
0663     return coro<Yield, Return, Executor, Allocator>{this};
0664   }
0665 
0666   auto initial_suspend() noexcept
0667   {
0668     return suspend_always{};
0669   }
0670 
0671   using coro_promise_exchange<
0672       typename coro_traits<Yield, Return, Executor>::yield_type,
0673       typename coro_traits<Yield, Return, Executor>::input_type,
0674       typename coro_traits<Yield, Return, Executor>::return_type>::yield_value;
0675 
0676   auto await_transform(this_coro::executor_t) const
0677   {
0678     struct exec_helper
0679     {
0680       const executor_type& value;
0681 
0682       constexpr static bool await_ready() noexcept
0683       {
0684         return true;
0685       }
0686 
0687       constexpr static void await_suspend(coroutine_handle<>) noexcept
0688       {
0689       }
0690 
0691       executor_type await_resume() const noexcept
0692       {
0693         return value;
0694       }
0695     };
0696 
0697     return exec_helper{executor_};
0698   }
0699 
0700   auto await_transform(this_coro::cancellation_state_t) const
0701   {
0702     struct exec_helper
0703     {
0704       const boost::asio::cancellation_state& value;
0705 
0706       constexpr static bool await_ready() noexcept
0707       {
0708         return true;
0709       }
0710 
0711       constexpr static void await_suspend(coroutine_handle<>) noexcept
0712       {
0713       }
0714 
0715       boost::asio::cancellation_state await_resume() const noexcept
0716       {
0717         return value;
0718       }
0719     };
0720     assert(cancel);
0721     return exec_helper{cancel->state};
0722   }
0723 
0724   // This await transformation resets the associated cancellation state.
0725   auto await_transform(this_coro::reset_cancellation_state_0_t) noexcept
0726   {
0727     struct result
0728     {
0729       detail::coro_cancellation_source * src_;
0730 
0731       bool await_ready() const noexcept
0732       {
0733         return true;
0734       }
0735 
0736       void await_suspend(coroutine_handle<void>) noexcept
0737       {
0738       }
0739 
0740       auto await_resume() const
0741       {
0742         return src_->reset_cancellation_state();
0743       }
0744     };
0745 
0746     return result{cancel};
0747   }
0748 
0749   // This await transformation resets the associated cancellation state.
0750   template <typename Filter>
0751   auto await_transform(
0752       this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept
0753   {
0754     struct result
0755     {
0756       detail::coro_cancellation_source* src_;
0757       Filter filter_;
0758 
0759       bool await_ready() const noexcept
0760       {
0761         return true;
0762       }
0763 
0764       void await_suspend(coroutine_handle<void>) noexcept
0765       {
0766       }
0767 
0768       auto await_resume()
0769       {
0770         return src_->reset_cancellation_state(
0771             static_cast<Filter&&>(filter_));
0772       }
0773     };
0774 
0775     return result{cancel, static_cast<Filter&&>(reset.filter)};
0776   }
0777 
0778   // This await transformation resets the associated cancellation state.
0779   template <typename InFilter, typename OutFilter>
0780   auto await_transform(
0781       this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset)
0782   noexcept
0783   {
0784     struct result
0785     {
0786       detail::coro_cancellation_source* src_;
0787       InFilter in_filter_;
0788       OutFilter out_filter_;
0789 
0790       bool await_ready() const noexcept
0791       {
0792         return true;
0793       }
0794 
0795       void await_suspend(coroutine_handle<void>) noexcept
0796       {
0797       }
0798 
0799       auto await_resume()
0800       {
0801         return src_->reset_cancellation_state(
0802             static_cast<InFilter&&>(in_filter_),
0803             static_cast<OutFilter&&>(out_filter_));
0804       }
0805     };
0806 
0807     return result{cancel,
0808         static_cast<InFilter&&>(reset.in_filter),
0809         static_cast<OutFilter&&>(reset.out_filter)};
0810   }
0811 
0812   // This await transformation determines whether cancellation is propagated as
0813   // an exception.
0814   auto await_transform(this_coro::throw_if_cancelled_0_t) noexcept
0815     requires (!is_noexcept)
0816   {
0817     struct result
0818     {
0819       detail::coro_cancellation_source* src_;
0820 
0821       bool await_ready() const noexcept
0822       {
0823         return true;
0824       }
0825 
0826       void await_suspend(coroutine_handle<void>) noexcept
0827       {
0828       }
0829 
0830       auto await_resume()
0831       {
0832         return src_->throw_if_cancelled();
0833       }
0834     };
0835 
0836     return result{cancel};
0837   }
0838 
0839   // This await transformation sets whether cancellation is propagated as an
0840   // exception.
0841   auto await_transform(
0842       this_coro::throw_if_cancelled_1_t throw_if_cancelled) noexcept
0843     requires (!is_noexcept)
0844   {
0845     struct result
0846     {
0847       detail::coro_cancellation_source* src_;
0848       bool value_;
0849 
0850       bool await_ready() const noexcept
0851       {
0852         return true;
0853       }
0854 
0855       void await_suspend(coroutine_handle<void>) noexcept
0856       {
0857       }
0858 
0859       auto await_resume()
0860       {
0861         src_->throw_if_cancelled(value_);
0862       }
0863     };
0864 
0865     return result{cancel, throw_if_cancelled.value};
0866   }
0867 
0868   template <typename Yield_, typename Return_,
0869       typename Executor_, typename Allocator_>
0870   auto await_transform(coro<Yield_, Return_, Executor_, Allocator_>& kr)
0871     -> decltype(auto)
0872   {
0873     return kr;
0874   }
0875 
0876   template <typename Yield_, typename Return_,
0877       typename Executor_, typename Allocator_>
0878   auto await_transform(coro<Yield_, Return_, Executor_, Allocator_>&& kr)
0879   {
0880     return std::move(kr);
0881   }
0882 
0883   template <typename T_, typename Coroutine >
0884   auto await_transform(coro_with_arg<T_, Coroutine>&& kr) -> decltype(auto)
0885   {
0886     return std::move(kr);
0887   }
0888 
0889   template <typename T_>
0890     requires requires(T_ t) {{ t.async_wait(deferred) }; }
0891   auto await_transform(T_& t) -> decltype(auto)
0892   {
0893     return await_transform(t.async_wait(deferred));
0894   }
0895 
0896   template <typename Op>
0897   auto await_transform(Op&& op,
0898       constraint_t<is_async_operation<Op>::value> = 0)
0899   {
0900     if ((cancel->state.cancelled() != cancellation_type::none)
0901         && cancel->throw_if_cancelled_)
0902     {
0903       boost::asio::detail::throw_error(
0904           boost::asio::error::operation_aborted, "coro-cancelled");
0905     }
0906     using signature = completion_signature_of_t<Op>;
0907     using result_type = detail::coro_completion_handler_type_t<signature>;
0908     using handler_type =
0909       typename detail::coro_completion_handler_type<signature>::template
0910         completion_handler<coro_promise>;
0911 
0912     struct aw_t
0913     {
0914       Op op;
0915       std::optional<result_type> result;
0916 
0917       constexpr static bool await_ready()
0918       {
0919         return false;
0920       }
0921 
0922       void await_suspend(coroutine_handle<coro_promise> h)
0923       {
0924         std::move(op)(handler_type{h, result});
0925       }
0926 
0927       auto await_resume()
0928       {
0929         if constexpr (is_noexcept)
0930         {
0931           if constexpr (std::tuple_size_v<result_type> == 0u)
0932             return;
0933           else if constexpr (std::tuple_size_v<result_type> == 1u)
0934             return std::get<0>(std::move(result).value());
0935           else
0936             return std::move(result).value();
0937         }
0938         else
0939           return detail::coro_interpret_result(std::move(result).value());
0940       }
0941     };
0942 
0943     return aw_t{std::move(op), {}};
0944   }
0945 };
0946 
0947 } // namespace detail
0948 
0949 template <typename Yield, typename Return,
0950     typename Executor, typename Allocator>
0951 struct coro<Yield, Return, Executor, Allocator>::awaitable_t
0952 {
0953   coro& coro_;
0954 
0955   constexpr static bool await_ready() { return false; }
0956 
0957   template <typename Y, typename R, typename E, typename A>
0958   auto await_suspend(
0959       detail::coroutine_handle<detail::coro_promise<Y, R, E, A>> h)
0960     -> detail::coroutine_handle<>
0961   {
0962     auto& hp = h.promise();
0963 
0964     if constexpr (!detail::coro_promise<Y, R, E, A>::is_noexcept)
0965     {
0966       if ((hp.cancel->state.cancelled() != cancellation_type::none)
0967           && hp.cancel->throw_if_cancelled_)
0968       {
0969         boost::asio::detail::throw_error(
0970             boost::asio::error::operation_aborted, "coro-cancelled");
0971       }
0972     }
0973 
0974     if (hp.get_executor() == coro_.get_executor())
0975     {
0976       coro_.coro_->awaited_from  = h;
0977       coro_.coro_->cancel = hp.cancel;
0978       coro_.coro_->reset_error();
0979 
0980       return coro_.coro_->get_handle();
0981     }
0982     else
0983     {
0984       coro_.coro_->awaited_from = detail::dispatch_coroutine(
0985           boost::asio::prefer(hp.get_executor(),
0986             execution::outstanding_work.tracked),
0987           [h]() mutable
0988           {
0989             h.resume();
0990           }).handle;
0991 
0992       coro_.coro_->reset_error();
0993 
0994       struct cancel_handler
0995       {
0996         std::shared_ptr<std::pair<cancellation_signal,
0997           detail::coro_cancellation_source>> st = std::make_shared<
0998             std::pair<cancellation_signal, detail::coro_cancellation_source>>();
0999 
1000         cancel_handler(E e, coro& coro) : e(e), coro_(coro.coro_)
1001         {
1002           st->second.state = cancellation_state(
1003               st->second.slot = st->first.slot());
1004         }
1005 
1006         E e;
1007         typename coro::promise_type* coro_;
1008 
1009         void operator()(cancellation_type ct)
1010         {
1011           boost::asio::dispatch(e,
1012               [ct, st = st]() mutable
1013               {
1014                 auto & [sig, state] = *st;
1015                 sig.emit(ct);
1016               });
1017         }
1018       };
1019 
1020       if (hp.cancel->state.slot().is_connected())
1021       {
1022         hp.cancel->state.slot().template emplace<cancel_handler>(
1023             coro_.get_executor(), coro_);
1024       }
1025 
1026       auto hh = detail::coroutine_handle<
1027         detail::coro_promise<Yield, Return, Executor, Allocator>>::from_promise(
1028             *coro_.coro_);
1029 
1030       return detail::dispatch_coroutine(
1031           coro_.coro_->get_executor(),
1032           [hh]() mutable { hh.resume(); }).handle;
1033     }
1034   }
1035 
1036   auto await_resume() -> result_type
1037   {
1038     coro_.coro_->cancel = nullptr;
1039     coro_.coro_->rethrow_if();
1040     if constexpr (!std::is_void_v<result_type>)
1041       return std::move(coro_.coro_->result_);
1042   }
1043 };
1044 
1045 template <typename Yield, typename Return,
1046     typename Executor, typename Allocator>
1047 struct coro<Yield, Return, Executor, Allocator>::initiate_async_resume
1048 {
1049   typedef Executor executor_type;
1050   typedef Allocator allocator_type;
1051   typedef boost::asio::cancellation_slot cancellation_slot_type;
1052 
1053   explicit initiate_async_resume(coro* self)
1054     : coro_(self->coro_)
1055   {
1056   }
1057 
1058   executor_type get_executor() const noexcept
1059   {
1060     return coro_->get_executor();
1061   }
1062 
1063   allocator_type get_allocator() const noexcept
1064   {
1065     return coro_->get_allocator();
1066   }
1067 
1068   template <typename E, typename WaitHandler>
1069   auto handle(E exec, WaitHandler&& handler,
1070       std::true_type /* error is noexcept */,
1071       std::true_type /* result is void */)  //noexcept
1072   {
1073     return [this, the_coro = coro_,
1074         h = std::forward<WaitHandler>(handler),
1075         exec = std::move(exec)]() mutable
1076     {
1077       assert(the_coro);
1078 
1079       auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro);
1080       assert(ch && !ch.done());
1081 
1082       the_coro->awaited_from = post_coroutine(std::move(exec), std::move(h));
1083       the_coro->reset_error();
1084       ch.resume();
1085     };
1086   }
1087 
1088   template <typename E, typename WaitHandler>
1089   requires (!std::is_void_v<result_type>)
1090   auto handle(E exec, WaitHandler&& handler,
1091       std::true_type /* error is noexcept */,
1092       std::false_type  /* result is void */)  //noexcept
1093   {
1094     return [the_coro = coro_,
1095         h = std::forward<WaitHandler>(handler),
1096         exec = std::move(exec)]() mutable
1097     {
1098       assert(the_coro);
1099 
1100       auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro);
1101       assert(ch && !ch.done());
1102 
1103       the_coro->awaited_from = detail::post_coroutine(
1104           exec, std::move(h), the_coro->result_).handle;
1105       the_coro->reset_error();
1106       ch.resume();
1107     };
1108   }
1109 
1110   template <typename E, typename WaitHandler>
1111   auto handle(E exec, WaitHandler&& handler,
1112       std::false_type /* error is noexcept */,
1113       std::true_type /* result is void */)
1114   {
1115     return [the_coro = coro_,
1116         h = std::forward<WaitHandler>(handler),
1117         exec = std::move(exec)]() mutable
1118     {
1119       if (!the_coro)
1120         return boost::asio::post(exec,
1121             boost::asio::append(std::move(h),
1122               detail::coro_error<error_type>::invalid()));
1123 
1124       auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro);
1125       if (!ch)
1126         return boost::asio::post(exec,
1127             boost::asio::append(std::move(h),
1128               detail::coro_error<error_type>::invalid()));
1129       else if (ch.done())
1130         return boost::asio::post(exec,
1131             boost::asio::append(std::move(h),
1132               detail::coro_error<error_type>::done()));
1133       else
1134       {
1135         the_coro->awaited_from = detail::post_coroutine(
1136             exec, std::move(h), the_coro->error_).handle;
1137         the_coro->reset_error();
1138         ch.resume();
1139       }
1140     };
1141   }
1142 
1143   template <typename E, typename WaitHandler>
1144   auto handle(E exec, WaitHandler&& handler,
1145       std::false_type /* error is noexcept */,
1146       std::false_type  /* result is void */)
1147   {
1148     return [the_coro = coro_,
1149         h = std::forward<WaitHandler>(handler),
1150         exec = std::move(exec)]() mutable
1151     {
1152       if (!the_coro)
1153         return boost::asio::post(exec,
1154             boost::asio::append(std::move(h),
1155               detail::coro_error<error_type>::invalid(), result_type{}));
1156 
1157       auto ch =
1158         detail::coroutine_handle<promise_type>::from_promise(*the_coro);
1159       if (!ch)
1160         return boost::asio::post(exec,
1161             boost::asio::append(std::move(h),
1162               detail::coro_error<error_type>::invalid(), result_type{}));
1163       else if (ch.done())
1164         return boost::asio::post(exec,
1165             boost::asio::append(std::move(h),
1166               detail::coro_error<error_type>::done(), result_type{}));
1167       else
1168       {
1169         the_coro->awaited_from = detail::post_coroutine(
1170             exec, std::move(h), the_coro->error_, the_coro->result_).handle;
1171         the_coro->reset_error();
1172         ch.resume();
1173       }
1174     };
1175   }
1176 
1177   template <typename WaitHandler>
1178   void operator()(WaitHandler&& handler)
1179   {
1180     const auto exec = boost::asio::prefer(
1181         get_associated_executor(handler, get_executor()),
1182         execution::outstanding_work.tracked);
1183 
1184     coro_->cancel = &coro_->cancel_source.emplace();
1185     coro_->cancel->state = cancellation_state(
1186         coro_->cancel->slot = get_associated_cancellation_slot(handler));
1187     boost::asio::dispatch(get_executor(),
1188         handle(exec, std::forward<WaitHandler>(handler),
1189           std::integral_constant<bool, is_noexcept>{},
1190           std::is_void<result_type>{}));
1191   }
1192 
1193   template <typename WaitHandler, typename Input>
1194   void operator()(WaitHandler&& handler, Input&& input)
1195   {
1196     const auto exec = boost::asio::prefer(
1197         get_associated_executor(handler, get_executor()),
1198         execution::outstanding_work.tracked);
1199 
1200     coro_->cancel = &coro_->cancel_source.emplace();
1201     coro_->cancel->state = cancellation_state(
1202         coro_->cancel->slot = get_associated_cancellation_slot(handler));
1203     boost::asio::dispatch(get_executor(),
1204         [h = handle(exec, std::forward<WaitHandler>(handler),
1205             std::integral_constant<bool, is_noexcept>{},
1206             std::is_void<result_type>{}),
1207             in = std::forward<Input>(input), the_coro = coro_]() mutable
1208         {
1209           the_coro->input_ = std::move(in);
1210           std::move(h)();
1211         });
1212   }
1213 
1214 private:
1215   typename coro::promise_type* coro_;
1216 };
1217 
1218 } // namespace experimental
1219 } // namespace asio
1220 } // namespace boost
1221 
1222 #include <boost/asio/detail/pop_options.hpp>
1223 
1224 #endif // BOOST_ASIO_EXPERIMENTAL_IMPL_CORO_HPP