partial_promise.hpp 4.7 KB

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