co_composed.hpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. //
  2. // experimental/impl/co_composed.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
  11. #define ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/config.hpp"
  16. #include <new>
  17. #include <tuple>
  18. #include <variant>
  19. #include "asio/associated_cancellation_slot.hpp"
  20. #include "asio/associator.hpp"
  21. #include "asio/async_result.hpp"
  22. #include "asio/cancellation_state.hpp"
  23. #include "asio/detail/composed_work.hpp"
  24. #include "asio/detail/recycling_allocator.hpp"
  25. #include "asio/detail/throw_error.hpp"
  26. #include "asio/detail/type_traits.hpp"
  27. #include "asio/error.hpp"
  28. #if defined(ASIO_HAS_STD_COROUTINE)
  29. # include <coroutine>
  30. #else // defined(ASIO_HAS_STD_COROUTINE)
  31. # include <experimental/coroutine>
  32. #endif // defined(ASIO_HAS_STD_COROUTINE)
  33. #if defined(ASIO_ENABLE_HANDLER_TRACKING)
  34. # if defined(ASIO_HAS_SOURCE_LOCATION)
  35. # include "asio/detail/source_location.hpp"
  36. # endif // defined(ASIO_HAS_SOURCE_LOCATION)
  37. #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
  38. #include "asio/detail/push_options.hpp"
  39. namespace asio {
  40. namespace experimental {
  41. namespace detail {
  42. #if defined(ASIO_HAS_STD_COROUTINE)
  43. using std::coroutine_handle;
  44. using std::suspend_always;
  45. using std::suspend_never;
  46. #else // defined(ASIO_HAS_STD_COROUTINE)
  47. using std::experimental::coroutine_handle;
  48. using std::experimental::suspend_always;
  49. using std::experimental::suspend_never;
  50. #endif // defined(ASIO_HAS_STD_COROUTINE)
  51. using asio::detail::composed_io_executors;
  52. using asio::detail::composed_work;
  53. using asio::detail::composed_work_guard;
  54. using asio::detail::get_composed_io_executor;
  55. using asio::detail::make_composed_io_executors;
  56. using asio::detail::recycling_allocator;
  57. using asio::detail::throw_error;
  58. template <typename Executors, typename Handler, typename Return>
  59. class co_composed_state;
  60. template <typename Executors, typename Handler, typename Return>
  61. class co_composed_handler_base;
  62. template <typename Executors, typename Handler, typename Return>
  63. class co_composed_promise;
  64. template <completion_signature... Signatures>
  65. class co_composed_returns
  66. {
  67. };
  68. struct co_composed_on_suspend
  69. {
  70. void (*fn_)(void*) = nullptr;
  71. void* arg_ = nullptr;
  72. };
  73. template <typename... T>
  74. struct co_composed_completion : std::tuple<T&&...>
  75. {
  76. template <typename... U>
  77. co_composed_completion(U&&... u) noexcept
  78. : std::tuple<T&&...>(std::forward<U>(u)...)
  79. {
  80. }
  81. };
  82. template <typename Executors, typename Handler,
  83. typename Return, typename Signature>
  84. class co_composed_state_return_overload;
  85. template <typename Executors, typename Handler,
  86. typename Return, typename R, typename... Args>
  87. class co_composed_state_return_overload<
  88. Executors, Handler, Return, R(Args...)>
  89. {
  90. public:
  91. using derived_type = co_composed_state<Executors, Handler, Return>;
  92. using promise_type = co_composed_promise<Executors, Handler, Return>;
  93. using return_type = std::tuple<Args...>;
  94. void on_cancellation_complete_with(Args... args)
  95. {
  96. derived_type& state = *static_cast<derived_type*>(this);
  97. state.return_value_ = std::make_tuple(std::move(args)...);
  98. state.cancellation_on_suspend_fn(
  99. [](void* p)
  100. {
  101. auto& promise = *static_cast<promise_type*>(p);
  102. co_composed_handler_base<Executors, Handler,
  103. Return> composed_handler(promise);
  104. Handler handler(std::move(promise.state().handler_));
  105. return_type result(
  106. std::move(std::get<return_type>(promise.state().return_value_)));
  107. co_composed_handler_base<Executors, Handler,
  108. Return>(std::move(composed_handler));
  109. std::apply(std::move(handler), std::move(result));
  110. });
  111. }
  112. };
  113. template <typename Executors, typename Handler, typename Return>
  114. class co_composed_state_return;
  115. template <typename Executors, typename Handler, typename... Signatures>
  116. class co_composed_state_return<
  117. Executors, Handler, co_composed_returns<Signatures...>>
  118. : public co_composed_state_return_overload<Executors,
  119. Handler, co_composed_returns<Signatures...>, Signatures>...
  120. {
  121. public:
  122. using co_composed_state_return_overload<Executors,
  123. Handler, co_composed_returns<Signatures...>,
  124. Signatures>::on_cancellation_complete_with...;
  125. private:
  126. template <typename, typename, typename, typename>
  127. friend class co_composed_promise_return_overload;
  128. template <typename, typename, typename, typename>
  129. friend class co_composed_state_return_overload;
  130. std::variant<std::monostate,
  131. typename co_composed_state_return_overload<
  132. Executors, Handler, co_composed_returns<Signatures...>,
  133. Signatures>::return_type...> return_value_;
  134. };
  135. template <typename Executors, typename Handler,
  136. typename Return, typename... Signatures>
  137. struct co_composed_state_default_cancellation_on_suspend_impl;
  138. template <typename Executors, typename Handler, typename Return>
  139. struct co_composed_state_default_cancellation_on_suspend_impl<
  140. Executors, Handler, Return>
  141. {
  142. static constexpr void (*fn())(void*)
  143. {
  144. return nullptr;
  145. }
  146. };
  147. template <typename Executors, typename Handler, typename Return,
  148. typename R, typename... Args, typename... Signatures>
  149. struct co_composed_state_default_cancellation_on_suspend_impl<
  150. Executors, Handler, Return, R(Args...), Signatures...>
  151. {
  152. static constexpr void (*fn())(void*)
  153. {
  154. return co_composed_state_default_cancellation_on_suspend_impl<
  155. Executors, Handler, Return, Signatures...>::fn();
  156. }
  157. };
  158. template <typename Executors, typename Handler, typename Return,
  159. typename R, typename... Args, typename... Signatures>
  160. struct co_composed_state_default_cancellation_on_suspend_impl<Executors,
  161. Handler, Return, R(asio::error_code, Args...), Signatures...>
  162. {
  163. using promise_type = co_composed_promise<Executors, Handler, Return>;
  164. using return_type = std::tuple<asio::error_code, Args...>;
  165. static constexpr void (*fn())(void*)
  166. {
  167. if constexpr ((is_constructible<Args>::value && ...))
  168. {
  169. return [](void* p)
  170. {
  171. auto& promise = *static_cast<promise_type*>(p);
  172. co_composed_handler_base<Executors, Handler,
  173. Return> composed_handler(promise);
  174. Handler handler(std::move(promise.state().handler_));
  175. co_composed_handler_base<Executors, Handler,
  176. Return>(std::move(composed_handler));
  177. std::move(handler)(
  178. asio::error_code(asio::error::operation_aborted),
  179. Args{}...);
  180. };
  181. }
  182. else
  183. {
  184. return co_composed_state_default_cancellation_on_suspend_impl<
  185. Executors, Handler, Return, Signatures...>::fn();
  186. }
  187. }
  188. };
  189. template <typename Executors, typename Handler, typename Return,
  190. typename R, typename... Args, typename... Signatures>
  191. struct co_composed_state_default_cancellation_on_suspend_impl<Executors,
  192. Handler, Return, R(std::exception_ptr, Args...), Signatures...>
  193. {
  194. using promise_type = co_composed_promise<Executors, Handler, Return>;
  195. using return_type = std::tuple<std::exception_ptr, Args...>;
  196. static constexpr void (*fn())(void*)
  197. {
  198. if constexpr ((is_constructible<Args>::value && ...))
  199. {
  200. return [](void* p)
  201. {
  202. auto& promise = *static_cast<promise_type*>(p);
  203. co_composed_handler_base<Executors, Handler,
  204. Return> composed_handler(promise);
  205. Handler handler(std::move(promise.state().handler_));
  206. co_composed_handler_base<Executors, Handler,
  207. Return>(std::move(composed_handler));
  208. std::move(handler)(
  209. std::make_exception_ptr(
  210. asio::system_error(
  211. asio::error::operation_aborted, "co_await")),
  212. Args{}...);
  213. };
  214. }
  215. else
  216. {
  217. return co_composed_state_default_cancellation_on_suspend_impl<
  218. Executors, Handler, Return, Signatures...>::fn();
  219. }
  220. }
  221. };
  222. template <typename Executors, typename Handler, typename Return>
  223. struct co_composed_state_default_cancellation_on_suspend;
  224. template <typename Executors, typename Handler, typename... Signatures>
  225. struct co_composed_state_default_cancellation_on_suspend<
  226. Executors, Handler, co_composed_returns<Signatures...>>
  227. : co_composed_state_default_cancellation_on_suspend_impl<Executors,
  228. Handler, co_composed_returns<Signatures...>, Signatures...>
  229. {
  230. };
  231. template <typename Executors, typename Handler, typename Return>
  232. class co_composed_state_cancellation
  233. {
  234. public:
  235. using cancellation_slot_type = cancellation_slot;
  236. cancellation_slot_type get_cancellation_slot() const noexcept
  237. {
  238. return cancellation_state_.slot();
  239. }
  240. cancellation_state get_cancellation_state() const noexcept
  241. {
  242. return cancellation_state_;
  243. }
  244. void reset_cancellation_state()
  245. {
  246. cancellation_state_ = cancellation_state(
  247. (get_associated_cancellation_slot)(
  248. static_cast<co_composed_state<Executors, Handler, Return>*>(
  249. this)->handler()));
  250. }
  251. template <typename Filter>
  252. void reset_cancellation_state(Filter filter)
  253. {
  254. cancellation_state_ = cancellation_state(
  255. (get_associated_cancellation_slot)(
  256. static_cast<co_composed_state<Executors, Handler, Return>*>(
  257. this)->handler()), filter, filter);
  258. }
  259. template <typename InFilter, typename OutFilter>
  260. void reset_cancellation_state(InFilter&& in_filter, OutFilter&& out_filter)
  261. {
  262. cancellation_state_ = cancellation_state(
  263. (get_associated_cancellation_slot)(
  264. static_cast<co_composed_state<Executors, Handler, Return>*>(
  265. this)->handler()),
  266. std::forward<InFilter>(in_filter),
  267. std::forward<OutFilter>(out_filter));
  268. }
  269. cancellation_type_t cancelled() const noexcept
  270. {
  271. return cancellation_state_.cancelled();
  272. }
  273. void clear_cancellation_slot() noexcept
  274. {
  275. cancellation_state_.slot().clear();
  276. }
  277. [[nodiscard]] bool throw_if_cancelled() const noexcept
  278. {
  279. return throw_if_cancelled_;
  280. }
  281. void throw_if_cancelled(bool b) noexcept
  282. {
  283. throw_if_cancelled_ = b;
  284. }
  285. [[nodiscard]] bool complete_if_cancelled() const noexcept
  286. {
  287. return complete_if_cancelled_;
  288. }
  289. void complete_if_cancelled(bool b) noexcept
  290. {
  291. complete_if_cancelled_ = b;
  292. }
  293. private:
  294. template <typename, typename, typename>
  295. friend class co_composed_promise;
  296. template <typename, typename, typename, typename>
  297. friend class co_composed_state_return_overload;
  298. void cancellation_on_suspend_fn(void (*fn)(void*))
  299. {
  300. cancellation_on_suspend_fn_ = fn;
  301. }
  302. void check_for_cancellation_on_transform()
  303. {
  304. if (throw_if_cancelled_ && !!cancelled())
  305. throw_error(asio::error::operation_aborted, "co_await");
  306. }
  307. bool check_for_cancellation_on_suspend(
  308. co_composed_promise<Executors, Handler, Return>& promise) noexcept
  309. {
  310. if (complete_if_cancelled_ && !!cancelled() && cancellation_on_suspend_fn_)
  311. {
  312. promise.state().work_.reset();
  313. promise.state().on_suspend_->fn_ = cancellation_on_suspend_fn_;
  314. promise.state().on_suspend_->arg_ = &promise;
  315. return false;
  316. }
  317. return true;
  318. }
  319. cancellation_state cancellation_state_;
  320. void (*cancellation_on_suspend_fn_)(void*) =
  321. co_composed_state_default_cancellation_on_suspend<
  322. Executors, Handler, Return>::fn();
  323. bool throw_if_cancelled_ = false;
  324. bool complete_if_cancelled_ = true;
  325. };
  326. template <typename Executors, typename Handler, typename Return>
  327. requires is_same<
  328. typename associated_cancellation_slot<
  329. Handler, cancellation_slot
  330. >::asio_associated_cancellation_slot_is_unspecialised,
  331. void>::value
  332. class co_composed_state_cancellation<Executors, Handler, Return>
  333. {
  334. public:
  335. void reset_cancellation_state()
  336. {
  337. }
  338. template <typename Filter>
  339. void reset_cancellation_state(Filter)
  340. {
  341. }
  342. template <typename InFilter, typename OutFilter>
  343. void reset_cancellation_state(InFilter&&, OutFilter&&)
  344. {
  345. }
  346. cancellation_type_t cancelled() const noexcept
  347. {
  348. return cancellation_type::none;
  349. }
  350. void clear_cancellation_slot() noexcept
  351. {
  352. }
  353. [[nodiscard]] bool throw_if_cancelled() const noexcept
  354. {
  355. return false;
  356. }
  357. void throw_if_cancelled(bool) noexcept
  358. {
  359. }
  360. [[nodiscard]] bool complete_if_cancelled() const noexcept
  361. {
  362. return false;
  363. }
  364. void complete_if_cancelled(bool) noexcept
  365. {
  366. }
  367. private:
  368. template <typename, typename, typename>
  369. friend class co_composed_promise;
  370. template <typename, typename, typename, typename>
  371. friend class co_composed_state_return_overload;
  372. void cancellation_on_suspend_fn(void (*)(void*))
  373. {
  374. }
  375. void check_for_cancellation_on_transform() noexcept
  376. {
  377. }
  378. bool check_for_cancellation_on_suspend(
  379. co_composed_promise<Executors, Handler, Return>&) noexcept
  380. {
  381. return true;
  382. }
  383. };
  384. template <typename Executors, typename Handler, typename Return>
  385. class co_composed_state
  386. : public co_composed_state_return<Executors, Handler, Return>,
  387. public co_composed_state_cancellation<Executors, Handler, Return>
  388. {
  389. public:
  390. using io_executor_type = typename composed_work_guard<
  391. typename composed_work<Executors>::head_type>::executor_type;
  392. template <typename H>
  393. co_composed_state(composed_io_executors<Executors>&& executors,
  394. H&& h, co_composed_on_suspend& on_suspend)
  395. : work_(std::move(executors)),
  396. handler_(std::forward<H>(h)),
  397. on_suspend_(&on_suspend)
  398. {
  399. this->reset_cancellation_state(enable_terminal_cancellation());
  400. }
  401. io_executor_type get_io_executor() const noexcept
  402. {
  403. return work_.head_.get_executor();
  404. }
  405. template <typename... Args>
  406. [[nodiscard]] co_composed_completion<Args...> complete(Args&&... args)
  407. requires requires { declval<Handler>()(std::forward<Args>(args)...); }
  408. {
  409. return co_composed_completion<Args...>(std::forward<Args>(args)...);
  410. }
  411. const Handler& handler() const noexcept
  412. {
  413. return handler_;
  414. }
  415. private:
  416. template <typename, typename, typename>
  417. friend class co_composed_handler_base;
  418. template <typename, typename, typename>
  419. friend class co_composed_promise;
  420. template <typename, typename, typename, typename>
  421. friend class co_composed_promise_return_overload;
  422. template <typename, typename, typename>
  423. friend class co_composed_state_cancellation;
  424. template <typename, typename, typename, typename>
  425. friend class co_composed_state_return_overload;
  426. template <typename, typename, typename, typename...>
  427. friend struct co_composed_state_default_cancellation_on_suspend_impl;
  428. composed_work<Executors> work_;
  429. Handler handler_;
  430. co_composed_on_suspend* on_suspend_;
  431. };
  432. template <typename Executors, typename Handler, typename Return>
  433. class co_composed_handler_cancellation
  434. {
  435. public:
  436. using cancellation_slot_type = cancellation_slot;
  437. cancellation_slot_type get_cancellation_slot() const noexcept
  438. {
  439. return static_cast<
  440. const co_composed_handler_base<Executors, Handler, Return>*>(
  441. this)->promise().state().get_cancellation_slot();
  442. }
  443. };
  444. template <typename Executors, typename Handler, typename Return>
  445. requires is_same<
  446. typename associated_cancellation_slot<
  447. Handler, cancellation_slot
  448. >::asio_associated_cancellation_slot_is_unspecialised,
  449. void>::value
  450. class co_composed_handler_cancellation<Executors, Handler, Return>
  451. {
  452. };
  453. template <typename Executors, typename Handler, typename Return>
  454. class co_composed_handler_base :
  455. public co_composed_handler_cancellation<Executors, Handler, Return>
  456. {
  457. public:
  458. co_composed_handler_base(
  459. co_composed_promise<Executors, Handler, Return>& p) noexcept
  460. : p_(&p)
  461. {
  462. }
  463. co_composed_handler_base(co_composed_handler_base&& other) noexcept
  464. : p_(std::exchange(other.p_, nullptr))
  465. {
  466. }
  467. ~co_composed_handler_base()
  468. {
  469. if (p_) [[unlikely]]
  470. p_->destroy();
  471. }
  472. co_composed_promise<Executors, Handler, Return>& promise() const noexcept
  473. {
  474. return *p_;
  475. }
  476. protected:
  477. void resume(void* result)
  478. {
  479. co_composed_on_suspend on_suspend{};
  480. std::exchange(p_, nullptr)->resume(p_, result, on_suspend);
  481. if (on_suspend.fn_)
  482. on_suspend.fn_(on_suspend.arg_);
  483. }
  484. private:
  485. co_composed_promise<Executors, Handler, Return>* p_;
  486. };
  487. template <typename Executors, typename Handler,
  488. typename Return, typename Signature>
  489. class co_composed_handler;
  490. template <typename Executors, typename Handler,
  491. typename Return, typename R, typename... Args>
  492. class co_composed_handler<Executors, Handler, Return, R(Args...)>
  493. : public co_composed_handler_base<Executors, Handler, Return>
  494. {
  495. public:
  496. using co_composed_handler_base<Executors,
  497. Handler, Return>::co_composed_handler_base;
  498. using result_type = std::tuple<decay_t<Args>...>;
  499. template <typename... T>
  500. void operator()(T&&... args)
  501. {
  502. result_type result(std::forward<T>(args)...);
  503. this->resume(&result);
  504. }
  505. static auto on_resume(void* result)
  506. {
  507. auto& args = *static_cast<result_type*>(result);
  508. if constexpr (sizeof...(Args) == 0)
  509. return;
  510. else if constexpr (sizeof...(Args) == 1)
  511. return std::move(std::get<0>(args));
  512. else
  513. return std::move(args);
  514. }
  515. };
  516. template <typename Executors, typename Handler,
  517. typename Return, typename R, typename... Args>
  518. class co_composed_handler<Executors, Handler,
  519. Return, R(asio::error_code, Args...)>
  520. : public co_composed_handler_base<Executors, Handler, Return>
  521. {
  522. public:
  523. using co_composed_handler_base<Executors,
  524. Handler, Return>::co_composed_handler_base;
  525. using args_type = std::tuple<decay_t<Args>...>;
  526. using result_type = std::tuple<asio::error_code, args_type>;
  527. template <typename... T>
  528. void operator()(const asio::error_code& ec, T&&... args)
  529. {
  530. result_type result(ec, args_type(std::forward<T>(args)...));
  531. this->resume(&result);
  532. }
  533. static auto on_resume(void* result)
  534. {
  535. auto& [ec, args] = *static_cast<result_type*>(result);
  536. throw_error(ec);
  537. if constexpr (sizeof...(Args) == 0)
  538. return;
  539. else if constexpr (sizeof...(Args) == 1)
  540. return std::move(std::get<0>(args));
  541. else
  542. return std::move(args);
  543. }
  544. };
  545. template <typename Executors, typename Handler,
  546. typename Return, typename R, typename... Args>
  547. class co_composed_handler<Executors, Handler,
  548. Return, R(std::exception_ptr, Args...)>
  549. : public co_composed_handler_base<Executors, Handler, Return>
  550. {
  551. public:
  552. using co_composed_handler_base<Executors,
  553. Handler, Return>::co_composed_handler_base;
  554. using args_type = std::tuple<decay_t<Args>...>;
  555. using result_type = std::tuple<std::exception_ptr, args_type>;
  556. template <typename... T>
  557. void operator()(std::exception_ptr ex, T&&... args)
  558. {
  559. result_type result(std::move(ex), args_type(std::forward<T>(args)...));
  560. this->resume(&result);
  561. }
  562. static auto on_resume(void* result)
  563. {
  564. auto& [ex, args] = *static_cast<result_type*>(result);
  565. if (ex)
  566. std::rethrow_exception(ex);
  567. if constexpr (sizeof...(Args) == 0)
  568. return;
  569. else if constexpr (sizeof...(Args) == 1)
  570. return std::move(std::get<0>(args));
  571. else
  572. return std::move(args);
  573. }
  574. };
  575. template <typename Executors, typename Handler, typename Return>
  576. class co_composed_promise_return;
  577. template <typename Executors, typename Handler>
  578. class co_composed_promise_return<Executors, Handler, co_composed_returns<>>
  579. {
  580. public:
  581. auto final_suspend() noexcept
  582. {
  583. return suspend_never();
  584. }
  585. void return_void() noexcept
  586. {
  587. }
  588. };
  589. template <typename Executors, typename Handler,
  590. typename Return, typename Signature>
  591. class co_composed_promise_return_overload;
  592. template <typename Executors, typename Handler,
  593. typename Return, typename R, typename... Args>
  594. class co_composed_promise_return_overload<
  595. Executors, Handler, Return, R(Args...)>
  596. {
  597. public:
  598. using derived_type = co_composed_promise<Executors, Handler, Return>;
  599. using return_type = std::tuple<Args...>;
  600. void return_value(std::tuple<Args...>&& value)
  601. {
  602. derived_type& promise = *static_cast<derived_type*>(this);
  603. promise.state().return_value_ = std::move(value);
  604. promise.state().work_.reset();
  605. promise.state().on_suspend_->arg_ = this;
  606. promise.state().on_suspend_->fn_ =
  607. [](void* p)
  608. {
  609. auto& promise = *static_cast<derived_type*>(p);
  610. co_composed_handler_base<Executors, Handler,
  611. Return> composed_handler(promise);
  612. Handler handler(std::move(promise.state().handler_));
  613. return_type result(
  614. std::move(std::get<return_type>(promise.state().return_value_)));
  615. co_composed_handler_base<Executors, Handler,
  616. Return>(std::move(composed_handler));
  617. std::apply(std::move(handler), std::move(result));
  618. };
  619. }
  620. };
  621. template <typename Executors, typename Handler, typename... Signatures>
  622. class co_composed_promise_return<Executors,
  623. Handler, co_composed_returns<Signatures...>>
  624. : public co_composed_promise_return_overload<Executors,
  625. Handler, co_composed_returns<Signatures...>, Signatures>...
  626. {
  627. public:
  628. auto final_suspend() noexcept
  629. {
  630. return suspend_always();
  631. }
  632. using co_composed_promise_return_overload<Executors, Handler,
  633. co_composed_returns<Signatures...>, Signatures>::return_value...;
  634. private:
  635. template <typename, typename, typename, typename>
  636. friend class co_composed_promise_return_overload;
  637. };
  638. template <typename Executors, typename Handler, typename Return>
  639. class co_composed_promise
  640. : public co_composed_promise_return<Executors, Handler, Return>
  641. {
  642. public:
  643. template <typename... Args>
  644. void* operator new(std::size_t size,
  645. co_composed_state<Executors, Handler, Return>& state, Args&&...)
  646. {
  647. block_allocator_type allocator(
  648. (get_associated_allocator)(state.handler_,
  649. recycling_allocator<void>()));
  650. block* base_ptr = std::allocator_traits<block_allocator_type>::allocate(
  651. allocator, blocks(sizeof(allocator_type)) + blocks(size));
  652. new (static_cast<void*>(base_ptr)) allocator_type(std::move(allocator));
  653. return base_ptr + blocks(sizeof(allocator_type));
  654. }
  655. template <typename C, typename... Args>
  656. void* operator new(std::size_t size, C&&,
  657. co_composed_state<Executors, Handler, Return>& state, Args&&...)
  658. {
  659. return co_composed_promise::operator new(size, state);
  660. }
  661. void operator delete(void* ptr, std::size_t size)
  662. {
  663. block* base_ptr = static_cast<block*>(ptr) - blocks(sizeof(allocator_type));
  664. allocator_type* allocator_ptr = std::launder(
  665. static_cast<allocator_type*>(static_cast<void*>(base_ptr)));
  666. block_allocator_type block_allocator(std::move(*allocator_ptr));
  667. allocator_ptr->~allocator_type();
  668. std::allocator_traits<block_allocator_type>::deallocate(block_allocator,
  669. base_ptr, blocks(sizeof(allocator_type)) + blocks(size));
  670. }
  671. template <typename... Args>
  672. co_composed_promise(
  673. co_composed_state<Executors, Handler, Return>& state, Args&&...)
  674. : state_(state)
  675. {
  676. }
  677. template <typename C, typename... Args>
  678. co_composed_promise(C&&,
  679. co_composed_state<Executors, Handler, Return>& state, Args&&...)
  680. : state_(state)
  681. {
  682. }
  683. void destroy() noexcept
  684. {
  685. coroutine_handle<co_composed_promise>::from_promise(*this).destroy();
  686. }
  687. void resume(co_composed_promise*& owner, void* result,
  688. co_composed_on_suspend& on_suspend)
  689. {
  690. state_.on_suspend_ = &on_suspend;
  691. state_.clear_cancellation_slot();
  692. owner_ = &owner;
  693. result_ = result;
  694. coroutine_handle<co_composed_promise>::from_promise(*this).resume();
  695. }
  696. co_composed_state<Executors, Handler, Return>& state() noexcept
  697. {
  698. return state_;
  699. }
  700. void get_return_object() noexcept
  701. {
  702. }
  703. auto initial_suspend() noexcept
  704. {
  705. return suspend_never();
  706. }
  707. void unhandled_exception()
  708. {
  709. if (owner_)
  710. *owner_ = this;
  711. throw;
  712. }
  713. template <async_operation Op>
  714. auto await_transform(Op&& op
  715. #if defined(ASIO_ENABLE_HANDLER_TRACKING)
  716. # if defined(ASIO_HAS_SOURCE_LOCATION)
  717. , asio::detail::source_location location
  718. = asio::detail::source_location::current()
  719. # endif // defined(ASIO_HAS_SOURCE_LOCATION)
  720. #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
  721. )
  722. {
  723. class [[nodiscard]] awaitable
  724. {
  725. public:
  726. awaitable(Op&& op, co_composed_promise& promise
  727. #if defined(ASIO_ENABLE_HANDLER_TRACKING)
  728. # if defined(ASIO_HAS_SOURCE_LOCATION)
  729. , const asio::detail::source_location& location
  730. # endif // defined(ASIO_HAS_SOURCE_LOCATION)
  731. #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
  732. )
  733. : op_(std::forward<Op>(op)),
  734. promise_(promise)
  735. #if defined(ASIO_ENABLE_HANDLER_TRACKING)
  736. # if defined(ASIO_HAS_SOURCE_LOCATION)
  737. , location_(location)
  738. # endif // defined(ASIO_HAS_SOURCE_LOCATION)
  739. #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
  740. {
  741. }
  742. constexpr bool await_ready() const noexcept
  743. {
  744. return false;
  745. }
  746. void await_suspend(coroutine_handle<co_composed_promise>)
  747. {
  748. if (promise_.state_.check_for_cancellation_on_suspend(promise_))
  749. {
  750. promise_.state_.on_suspend_->arg_ = this;
  751. promise_.state_.on_suspend_->fn_ =
  752. [](void* p)
  753. {
  754. #if defined(ASIO_ENABLE_HANDLER_TRACKING)
  755. # if defined(ASIO_HAS_SOURCE_LOCATION)
  756. ASIO_HANDLER_LOCATION((
  757. static_cast<awaitable*>(p)->location_.file_name(),
  758. static_cast<awaitable*>(p)->location_.line(),
  759. static_cast<awaitable*>(p)->location_.function_name()));
  760. # endif // defined(ASIO_HAS_SOURCE_LOCATION)
  761. #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
  762. std::forward<Op>(static_cast<awaitable*>(p)->op_)(
  763. co_composed_handler<Executors, Handler,
  764. Return, completion_signature_of_t<Op>>(
  765. static_cast<awaitable*>(p)->promise_));
  766. };
  767. }
  768. }
  769. auto await_resume()
  770. {
  771. return co_composed_handler<Executors, Handler, Return,
  772. completion_signature_of_t<Op>>::on_resume(promise_.result_);
  773. }
  774. private:
  775. Op&& op_;
  776. co_composed_promise& promise_;
  777. #if defined(ASIO_ENABLE_HANDLER_TRACKING)
  778. # if defined(ASIO_HAS_SOURCE_LOCATION)
  779. asio::detail::source_location location_;
  780. # endif // defined(ASIO_HAS_SOURCE_LOCATION)
  781. #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
  782. };
  783. state_.check_for_cancellation_on_transform();
  784. return awaitable{std::forward<Op>(op), *this
  785. #if defined(ASIO_ENABLE_HANDLER_TRACKING)
  786. # if defined(ASIO_HAS_SOURCE_LOCATION)
  787. , location
  788. # endif // defined(ASIO_HAS_SOURCE_LOCATION)
  789. #endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
  790. };
  791. }
  792. template <typename... Args>
  793. auto yield_value(co_composed_completion<Args...>&& result)
  794. {
  795. class [[nodiscard]] awaitable
  796. {
  797. public:
  798. awaitable(co_composed_completion<Args...>&& result,
  799. co_composed_promise& promise)
  800. : result_(std::move(result)),
  801. promise_(promise)
  802. {
  803. }
  804. constexpr bool await_ready() const noexcept
  805. {
  806. return false;
  807. }
  808. void await_suspend(coroutine_handle<co_composed_promise>)
  809. {
  810. promise_.state_.work_.reset();
  811. promise_.state_.on_suspend_->arg_ = this;
  812. promise_.state_.on_suspend_->fn_ =
  813. [](void* p)
  814. {
  815. awaitable& a = *static_cast<awaitable*>(p);
  816. co_composed_handler_base<Executors, Handler,
  817. Return> composed_handler(a.promise_);
  818. Handler handler(std::move(a.promise_.state_.handler_));
  819. std::tuple<decay_t<Args>...> result(
  820. std::move(static_cast<std::tuple<Args&&...>>(a.result_)));
  821. co_composed_handler_base<Executors, Handler,
  822. Return>(std::move(composed_handler));
  823. std::apply(std::move(handler), std::move(result));
  824. };
  825. }
  826. void await_resume() noexcept
  827. {
  828. }
  829. private:
  830. co_composed_completion<Args...> result_;
  831. co_composed_promise& promise_;
  832. };
  833. return awaitable{std::move(result), *this};
  834. }
  835. private:
  836. using allocator_type =
  837. associated_allocator_t<Handler, recycling_allocator<void>>;
  838. union block
  839. {
  840. std::max_align_t max_align;
  841. alignas(allocator_type) char pad[alignof(allocator_type)];
  842. };
  843. using block_allocator_type =
  844. typename std::allocator_traits<allocator_type>
  845. ::template rebind_alloc<block>;
  846. static constexpr std::size_t blocks(std::size_t size)
  847. {
  848. return (size + sizeof(block) - 1) / sizeof(block);
  849. }
  850. co_composed_state<Executors, Handler, Return>& state_;
  851. co_composed_promise** owner_ = nullptr;
  852. void* result_ = nullptr;
  853. };
  854. template <typename Implementation, typename Executors, typename... Signatures>
  855. class initiate_co_composed
  856. {
  857. public:
  858. using executor_type = typename composed_io_executors<Executors>::head_type;
  859. template <typename I>
  860. initiate_co_composed(I&& impl, composed_io_executors<Executors>&& executors)
  861. : implementation_(std::forward<I>(impl)),
  862. executors_(std::move(executors))
  863. {
  864. }
  865. executor_type get_executor() const noexcept
  866. {
  867. return executors_.head_;
  868. }
  869. template <typename Handler, typename... InitArgs>
  870. void operator()(Handler&& handler, InitArgs&&... init_args) const &
  871. {
  872. using handler_type = decay_t<Handler>;
  873. using returns_type = co_composed_returns<Signatures...>;
  874. co_composed_on_suspend on_suspend{};
  875. implementation_(
  876. co_composed_state<Executors, handler_type, returns_type>(
  877. executors_, std::forward<Handler>(handler), on_suspend),
  878. std::forward<InitArgs>(init_args)...);
  879. if (on_suspend.fn_)
  880. on_suspend.fn_(on_suspend.arg_);
  881. }
  882. template <typename Handler, typename... InitArgs>
  883. void operator()(Handler&& handler, InitArgs&&... init_args) &&
  884. {
  885. using handler_type = decay_t<Handler>;
  886. using returns_type = co_composed_returns<Signatures...>;
  887. co_composed_on_suspend on_suspend{};
  888. std::move(implementation_)(
  889. co_composed_state<Executors, handler_type, returns_type>(
  890. std::move(executors_), std::forward<Handler>(handler), on_suspend),
  891. std::forward<InitArgs>(init_args)...);
  892. if (on_suspend.fn_)
  893. on_suspend.fn_(on_suspend.arg_);
  894. }
  895. private:
  896. Implementation implementation_;
  897. composed_io_executors<Executors> executors_;
  898. };
  899. template <typename... Signatures, typename Implementation, typename Executors>
  900. inline initiate_co_composed<Implementation, Executors, Signatures...>
  901. make_initiate_co_composed(Implementation&& implementation,
  902. composed_io_executors<Executors>&& executors)
  903. {
  904. return initiate_co_composed<
  905. decay_t<Implementation>, Executors, Signatures...>(
  906. std::forward<Implementation>(implementation), std::move(executors));
  907. }
  908. } // namespace detail
  909. template <completion_signature... Signatures,
  910. typename Implementation, typename... IoObjectsOrExecutors>
  911. inline auto co_composed(Implementation&& implementation,
  912. IoObjectsOrExecutors&&... io_objects_or_executors)
  913. {
  914. return detail::make_initiate_co_composed<Signatures...>(
  915. std::forward<Implementation>(implementation),
  916. detail::make_composed_io_executors(
  917. detail::get_composed_io_executor(
  918. std::forward<IoObjectsOrExecutors>(
  919. io_objects_or_executors))...));
  920. }
  921. } // namespace experimental
  922. #if !defined(GENERATING_DOCUMENTATION)
  923. template <template <typename, typename> class Associator,
  924. typename Executors, typename Handler, typename Return,
  925. typename Signature, typename DefaultCandidate>
  926. struct associator<Associator,
  927. experimental::detail::co_composed_handler<
  928. Executors, Handler, Return, Signature>,
  929. DefaultCandidate>
  930. : Associator<Handler, DefaultCandidate>
  931. {
  932. static typename Associator<Handler, DefaultCandidate>::type get(
  933. const experimental::detail::co_composed_handler<
  934. Executors, Handler, Return, Signature>& h) noexcept
  935. {
  936. return Associator<Handler, DefaultCandidate>::get(
  937. h.promise().state().handler());
  938. }
  939. static auto get(
  940. const experimental::detail::co_composed_handler<
  941. Executors, Handler, Return, Signature>& h,
  942. const DefaultCandidate& c) noexcept
  943. -> decltype(
  944. Associator<Handler, DefaultCandidate>::get(
  945. h.promise().state().handler(), c))
  946. {
  947. return Associator<Handler, DefaultCandidate>::get(
  948. h.promise().state().handler(), c);
  949. }
  950. };
  951. #endif // !defined(GENERATING_DOCUMENTATION)
  952. } // namespace asio
  953. #if !defined(GENERATING_DOCUMENTATION)
  954. # if defined(ASIO_HAS_STD_COROUTINE)
  955. namespace std {
  956. # else // defined(ASIO_HAS_STD_COROUTINE)
  957. namespace std { namespace experimental {
  958. # endif // defined(ASIO_HAS_STD_COROUTINE)
  959. template <typename C, typename Executors,
  960. typename Handler, typename Return, typename... Args>
  961. struct coroutine_traits<void, C&,
  962. asio::experimental::detail::co_composed_state<
  963. Executors, Handler, Return>,
  964. Args...>
  965. {
  966. using promise_type =
  967. asio::experimental::detail::co_composed_promise<
  968. Executors, Handler, Return>;
  969. };
  970. template <typename C, typename Executors,
  971. typename Handler, typename Return, typename... Args>
  972. struct coroutine_traits<void, C&&,
  973. asio::experimental::detail::co_composed_state<
  974. Executors, Handler, Return>,
  975. Args...>
  976. {
  977. using promise_type =
  978. asio::experimental::detail::co_composed_promise<
  979. Executors, Handler, Return>;
  980. };
  981. template <typename Executors, typename Handler,
  982. typename Return, typename... Args>
  983. struct coroutine_traits<void,
  984. asio::experimental::detail::co_composed_state<
  985. Executors, Handler, Return>,
  986. Args...>
  987. {
  988. using promise_type =
  989. asio::experimental::detail::co_composed_promise<
  990. Executors, Handler, Return>;
  991. };
  992. # if defined(ASIO_HAS_STD_COROUTINE)
  993. } // namespace std
  994. # else // defined(ASIO_HAS_STD_COROUTINE)
  995. }} // namespace std::experimental
  996. # endif // defined(ASIO_HAS_STD_COROUTINE)
  997. #endif // !defined(GENERATING_DOCUMENTATION)
  998. #include "asio/detail/pop_options.hpp"
  999. #endif // ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP