use_awaitable.hpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //
  2. // impl/use_awaitable.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 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 BOOST_ASIO_IMPL_USE_AWAITABLE_HPP
  11. #define BOOST_ASIO_IMPL_USE_AWAITABLE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/async_result.hpp>
  17. #include <boost/asio/cancellation_signal.hpp>
  18. #include <boost/asio/disposition.hpp>
  19. #include <boost/asio/detail/push_options.hpp>
  20. namespace boost {
  21. namespace asio {
  22. namespace detail {
  23. template <typename Executor, typename T>
  24. class awaitable_handler_base
  25. : public awaitable_thread<Executor>
  26. {
  27. public:
  28. typedef void result_type;
  29. typedef awaitable<T, Executor> awaitable_type;
  30. // Construct from the entry point of a new thread of execution.
  31. awaitable_handler_base(awaitable<awaitable_thread_entry_point, Executor> a,
  32. const Executor& ex, cancellation_slot pcs, cancellation_state cs)
  33. : awaitable_thread<Executor>(std::move(a), ex, pcs, cs)
  34. {
  35. }
  36. // Transfer ownership from another awaitable_thread.
  37. explicit awaitable_handler_base(awaitable_thread<Executor>* h)
  38. : awaitable_thread<Executor>(std::move(*h))
  39. {
  40. }
  41. protected:
  42. awaitable_frame<T, Executor>* frame() noexcept
  43. {
  44. return static_cast<awaitable_frame<T, Executor>*>(
  45. this->entry_point()->top_of_stack_);
  46. }
  47. };
  48. template <typename, typename...>
  49. class awaitable_handler;
  50. template <typename Executor>
  51. class awaitable_handler<Executor>
  52. : public awaitable_handler_base<Executor, void>
  53. {
  54. public:
  55. using awaitable_handler_base<Executor, void>::awaitable_handler_base;
  56. void operator()()
  57. {
  58. this->frame()->attach_thread(this);
  59. this->frame()->return_void();
  60. this->frame()->clear_cancellation_slot();
  61. this->frame()->pop_frame();
  62. this->pump();
  63. }
  64. };
  65. template <typename Executor, typename T>
  66. class awaitable_handler<Executor, T>
  67. : public awaitable_handler_base<Executor,
  68. conditional_t<is_disposition<T>::value, void, T>>
  69. {
  70. public:
  71. using awaitable_handler_base<Executor,
  72. conditional_t<is_disposition<T>::value, void, T>>
  73. ::awaitable_handler_base;
  74. template <typename Arg>
  75. void operator()(Arg&& arg)
  76. {
  77. this->frame()->attach_thread(this);
  78. if constexpr (is_disposition<T>::value)
  79. {
  80. if (arg == no_error)
  81. this->frame()->return_void();
  82. else
  83. this->frame()->set_disposition(arg);
  84. }
  85. else
  86. this->frame()->return_value(std::forward<Arg>(arg));
  87. this->frame()->clear_cancellation_slot();
  88. this->frame()->pop_frame();
  89. this->pump();
  90. }
  91. };
  92. template <typename Executor, typename T0, typename T1>
  93. class awaitable_handler<Executor, T0, T1>
  94. : public awaitable_handler_base<Executor,
  95. conditional_t<is_disposition<T0>::value, T1, std::tuple<T0, T1>>>
  96. {
  97. public:
  98. using awaitable_handler_base<Executor,
  99. conditional_t<is_disposition<T0>::value, T1, std::tuple<T0, T1>>>
  100. ::awaitable_handler_base;
  101. template <typename Arg0, typename Arg1>
  102. void operator()(Arg0&& arg0, Arg1&& arg1)
  103. {
  104. this->frame()->attach_thread(this);
  105. if constexpr (is_disposition<T0>::value)
  106. {
  107. if (arg0 == no_error)
  108. this->frame()->return_value(std::forward<Arg1>(arg1));
  109. else
  110. this->frame()->set_disposition(std::forward<Arg0>(arg0));
  111. }
  112. else
  113. {
  114. this->frame()->return_values(std::forward<Arg0>(arg0),
  115. std::forward<Arg1>(arg1));
  116. }
  117. this->frame()->clear_cancellation_slot();
  118. this->frame()->pop_frame();
  119. this->pump();
  120. }
  121. };
  122. template <typename Executor, typename T0, typename... Ts>
  123. class awaitable_handler<Executor, T0, Ts...>
  124. : public awaitable_handler_base<Executor,
  125. conditional_t<is_disposition<T0>::value,
  126. std::tuple<Ts...>, std::tuple<T0, Ts...>>>
  127. {
  128. public:
  129. using awaitable_handler_base<Executor,
  130. conditional_t<is_disposition<T0>::value,
  131. std::tuple<Ts...>, std::tuple<T0, Ts...>>>
  132. ::awaitable_handler_base;
  133. template <typename Arg0, typename... Args>
  134. void operator()(Arg0&& arg0, Args&&... args)
  135. {
  136. this->frame()->attach_thread(this);
  137. if constexpr (is_disposition<T0>::value)
  138. {
  139. if (arg0 == no_error)
  140. this->frame()->return_values(std::forward<Args>(args)...);
  141. else
  142. this->frame()->set_disposition(std::forward<Arg0>(arg0));
  143. }
  144. else
  145. {
  146. this->frame()->return_values(std::forward<Arg0>(arg0),
  147. std::forward<Args>(args)...);
  148. }
  149. this->frame()->clear_cancellation_slot();
  150. this->frame()->pop_frame();
  151. this->pump();
  152. }
  153. };
  154. } // namespace detail
  155. #if !defined(GENERATING_DOCUMENTATION)
  156. #if defined(_MSC_VER)
  157. template <typename T>
  158. T dummy_return()
  159. {
  160. return std::move(*static_cast<T*>(nullptr));
  161. }
  162. template <>
  163. inline void dummy_return()
  164. {
  165. }
  166. #endif // defined(_MSC_VER)
  167. template <typename Executor, typename R, typename... Args>
  168. class async_result<use_awaitable_t<Executor>, R(Args...)>
  169. {
  170. public:
  171. typedef typename detail::awaitable_handler<
  172. Executor, decay_t<Args>...> handler_type;
  173. typedef typename handler_type::awaitable_type return_type;
  174. template <typename Initiation, typename... InitArgs>
  175. #if defined(__APPLE_CC__) && (__clang_major__ == 13)
  176. __attribute__((noinline))
  177. #endif // defined(__APPLE_CC__) && (__clang_major__ == 13)
  178. static handler_type* do_init(
  179. detail::awaitable_frame_base<Executor>* frame, Initiation& initiation,
  180. use_awaitable_t<Executor> u, InitArgs&... args)
  181. {
  182. (void)u;
  183. BOOST_ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_));
  184. handler_type handler(frame->detach_thread());
  185. std::move(initiation)(std::move(handler), std::move(args)...);
  186. return nullptr;
  187. }
  188. template <typename Initiation, typename... InitArgs>
  189. static return_type initiate(Initiation initiation,
  190. use_awaitable_t<Executor> u, InitArgs... args)
  191. {
  192. co_await [&] (auto* frame)
  193. {
  194. return do_init(frame, initiation, u, args...);
  195. };
  196. for (;;) {} // Never reached.
  197. #if defined(_MSC_VER) && !defined(__clang__)
  198. co_return dummy_return<typename return_type::value_type>();
  199. #endif // defined(_MSC_VER) && !defined(__clang__)
  200. }
  201. };
  202. #endif // !defined(GENERATING_DOCUMENTATION)
  203. } // namespace asio
  204. } // namespace boost
  205. #include <boost/asio/detail/pop_options.hpp>
  206. #endif // BOOST_ASIO_IMPL_USE_AWAITABLE_HPP