File indexing completed on 2025-01-18 09:28:51
0001
0002
0003
0004
0005
0006
0007
0008
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
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
0035 # include <experimental/coroutine>
0036 #endif
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
0042 #endif
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
0056 using std::experimental::coroutine_handle;
0057 using std::experimental::suspend_always;
0058 using std::experimental::suspend_never;
0059 #endif
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
0854 #endif
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
0865 #endif
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
0873 #endif
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
0897 #endif
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
0919 #endif
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
0928 #endif
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 }
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 }
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
1120
1121 }
1122 }
1123
1124 #if !defined(GENERATING_DOCUMENTATION)
1125 # if defined(BOOST_ASIO_HAS_STD_COROUTINE)
1126 namespace std {
1127 # else
1128 namespace std { namespace experimental {
1129 # endif
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 }
1169 # else
1170 }}
1171 # endif
1172 #endif
1173
1174 #include <boost/asio/detail/pop_options.hpp>
1175
1176 #endif