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