partial_promise.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. //
  2. // experimental/detail/partial_promise.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2021-2023 Klemens D. Morgenstern
  6. // (klemens dot morgenstern at gmx dot net)
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. #ifndef BOOST_ASIO_EXPERIMENTAL_DETAIL_PARTIAL_PROMISE_HPP
  12. #define BOOST_ASIO_EXPERIMENTAL_DETAIL_PARTIAL_PROMISE_HPP
  13. #include <boost/asio/detail/config.hpp>
  14. #include <boost/asio/append.hpp>
  15. #include <boost/asio/awaitable.hpp>
  16. #include <boost/asio/experimental/coro_traits.hpp>
  17. #if defined(BOOST_ASIO_HAS_STD_COROUTINE)
  18. # include <coroutine>
  19. #else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  20. # include <experimental/coroutine>
  21. #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  22. namespace boost {
  23. namespace asio {
  24. namespace experimental {
  25. namespace detail {
  26. #if defined(BOOST_ASIO_HAS_STD_COROUTINE)
  27. using std::coroutine_handle;
  28. using std::coroutine_traits;
  29. using std::suspend_never;
  30. using std::suspend_always;
  31. using std::noop_coroutine;
  32. #else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  33. using std::experimental::coroutine_handle;
  34. using std::experimental::coroutine_traits;
  35. using std::experimental::suspend_never;
  36. using std::experimental::suspend_always;
  37. using std::experimental::noop_coroutine;
  38. #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  39. struct partial_coro
  40. {
  41. coroutine_handle<void> handle{nullptr};
  42. };
  43. template <typename Allocator>
  44. struct partial_promise_base
  45. {
  46. template <typename Executor, typename Token, typename... Args>
  47. void* operator new(std::size_t size, Executor&, Token& tk, Args&...)
  48. {
  49. return allocate_coroutine<Allocator>(size, get_associated_allocator(tk));
  50. }
  51. void operator delete(void* raw, std::size_t size)
  52. {
  53. deallocate_coroutine<Allocator>(raw, size);
  54. }
  55. };
  56. template <>
  57. struct partial_promise_base<std::allocator<void>>
  58. {
  59. };
  60. template <typename Allocator>
  61. struct partial_promise : partial_promise_base<Allocator>
  62. {
  63. auto initial_suspend() noexcept
  64. {
  65. return boost::asio::detail::suspend_always{};
  66. }
  67. auto final_suspend() noexcept
  68. {
  69. struct awaitable_t
  70. {
  71. partial_promise *p;
  72. constexpr bool await_ready() noexcept { return true; }
  73. auto await_suspend(boost::asio::detail::coroutine_handle<>) noexcept
  74. {
  75. p->get_return_object().handle.destroy();
  76. }
  77. constexpr void await_resume() noexcept {}
  78. };
  79. return awaitable_t{this};
  80. }
  81. void return_void() {}
  82. partial_coro get_return_object()
  83. {
  84. return partial_coro{coroutine_handle<partial_promise>::from_promise(*this)};
  85. }
  86. void unhandled_exception()
  87. {
  88. assert(false);
  89. }
  90. };
  91. } // namespace detail
  92. } // namespace experimental
  93. } // namespace asio
  94. } // namespace boost
  95. #if defined(BOOST_ASIO_HAS_STD_COROUTINE)
  96. namespace std {
  97. template <typename Executor, typename Completion, typename... Args>
  98. struct coroutine_traits<
  99. boost::asio::experimental::detail::partial_coro,
  100. Executor, Completion, Args...>
  101. {
  102. using promise_type =
  103. boost::asio::experimental::detail::partial_promise<
  104. boost::asio::associated_allocator_t<Completion>>;
  105. };
  106. } // namespace std
  107. #else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  108. namespace std { namespace experimental {
  109. template <typename Executor, typename Completion, typename... Args>
  110. struct coroutine_traits<
  111. boost::asio::experimental::detail::partial_coro,
  112. Executor, Completion, Args...>
  113. {
  114. using promise_type =
  115. boost::asio::experimental::detail::partial_promise<
  116. boost::asio::associated_allocator_t<Completion>>;
  117. };
  118. }} // namespace std::experimental
  119. #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  120. namespace boost {
  121. namespace asio {
  122. namespace experimental {
  123. namespace detail {
  124. template <execution::executor Executor,
  125. typename CompletionToken, typename... Args>
  126. partial_coro post_coroutine(Executor exec,
  127. CompletionToken token, Args&&... args) noexcept
  128. {
  129. post(exec, boost::asio::append(std::move(token), std::move(args)...));
  130. co_return;
  131. }
  132. template <detail::execution_context Context,
  133. typename CompletionToken, typename... Args>
  134. partial_coro post_coroutine(Context& ctx,
  135. CompletionToken token, Args&&... args) noexcept
  136. {
  137. post(ctx, boost::asio::append(std::move(token), std::move(args)...));
  138. co_return;
  139. }
  140. template <execution::executor Executor,
  141. typename CompletionToken, typename... Args>
  142. partial_coro dispatch_coroutine(Executor exec,
  143. CompletionToken token, Args&&... args) noexcept
  144. {
  145. dispatch(exec, boost::asio::append(std::move(token), std::move(args)...));
  146. co_return;
  147. }
  148. template <detail::execution_context Context,
  149. typename CompletionToken, typename... Args>
  150. partial_coro dispatch_coroutine(Context& ctx,
  151. CompletionToken token, Args &&... args) noexcept
  152. {
  153. dispatch(ctx, boost::asio::append(std::move(token), std::move(args)...));
  154. co_return;
  155. }
  156. } // namespace detail
  157. } // namespace experimental
  158. } // namespace asio
  159. } // namespace boost
  160. #endif // BOOST_ASIO_EXPERIMENTAL_DETAIL_PARTIAL_PROMISE_HPP