wrapper.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright (c) 2022 Klemens D. Morgenstern
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_COBALT_WRAPPER_HPP
  6. #define BOOST_COBALT_WRAPPER_HPP
  7. #include <boost/cobalt/this_coro.hpp>
  8. #include <boost/cobalt/concepts.hpp>
  9. #include <boost/cobalt/detail/util.hpp>
  10. #include <boost/asio/bind_executor.hpp>
  11. #include <boost/asio/executor.hpp>
  12. #include <boost/asio/post.hpp>
  13. #include <boost/config.hpp>
  14. #include <coroutine>
  15. #include <utility>
  16. #if BOOST_COBALT_NO_SELF_DELETE
  17. #include <boost/asio/consign.hpp>
  18. #endif
  19. namespace boost::cobalt::detail
  20. {
  21. template<typename Allocator>
  22. struct partial_promise_base
  23. {
  24. template<typename CompletionToken>
  25. void * operator new(const std::size_t size, CompletionToken & token)
  26. {
  27. // gcc: 168 40
  28. // clang: 144 40
  29. return allocate_coroutine(size, asio::get_associated_allocator(token));
  30. }
  31. template<typename Executor, typename CompletionToken>
  32. void * operator new(const std::size_t size, Executor &, CompletionToken & token)
  33. {
  34. // gcc: 120 8 16
  35. // clang: 96 8 16
  36. return allocate_coroutine(size, asio::get_associated_allocator(token));
  37. }
  38. #if defined(__cpp_sized_deallocation)
  39. void operator delete(void * raw, const std::size_t size)
  40. {
  41. deallocate_coroutine<Allocator>(raw, size);
  42. }
  43. #else
  44. void operator delete(void * raw)
  45. {
  46. deallocate_coroutine<Allocator>(raw);
  47. }
  48. #endif
  49. };
  50. template<>
  51. struct partial_promise_base<std::allocator<void>> {};
  52. template<> struct partial_promise_base<void> {};
  53. template<typename T> struct partial_promise_base<std::allocator<T>> {};
  54. // alloc options are two: allocator or aligned storage
  55. template<typename Allocator = void>
  56. struct partial_promise : partial_promise_base<Allocator>
  57. {
  58. auto initial_suspend() noexcept
  59. {
  60. return std::suspend_always();
  61. }
  62. auto final_suspend() noexcept
  63. {
  64. return std::suspend_never();
  65. }
  66. void return_void() {}
  67. };
  68. template<typename Allocator = void>
  69. struct post_coroutine_promise : partial_promise<Allocator>
  70. {
  71. template<typename CompletionToken>
  72. auto yield_value(CompletionToken cpl)
  73. {
  74. struct awaitable_t
  75. {
  76. CompletionToken cpl;
  77. constexpr bool await_ready() noexcept { return false; }
  78. BOOST_NOINLINE
  79. auto await_suspend(std::coroutine_handle<void> h) noexcept
  80. {
  81. auto c = std::move(cpl);
  82. if (this_thread::has_executor())
  83. detail::self_destroy(h, asio::get_associated_executor(c, this_thread::get_executor()));
  84. else
  85. detail::self_destroy(h, asio::get_associated_executor(c));
  86. asio::post(std::move(c));
  87. }
  88. constexpr void await_resume() noexcept {}
  89. };
  90. return awaitable_t{std::move(cpl)};
  91. }
  92. std::coroutine_handle<post_coroutine_promise<Allocator>> get_return_object()
  93. {
  94. return std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this);
  95. }
  96. void unhandled_exception()
  97. {
  98. detail::self_destroy(std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this));
  99. throw;
  100. }
  101. };
  102. }
  103. namespace std
  104. {
  105. template <typename T, typename ... Args>
  106. struct coroutine_traits<coroutine_handle<boost::cobalt::detail::post_coroutine_promise<T>>, Args...>
  107. {
  108. using promise_type = boost::cobalt::detail::post_coroutine_promise<T>;
  109. };
  110. } // namespace std
  111. namespace boost::cobalt::detail
  112. {
  113. template <typename CompletionToken>
  114. auto post_coroutine(CompletionToken token)
  115. -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
  116. {
  117. co_yield std::move(token);
  118. }
  119. template <asio::execution::executor Executor, typename CompletionToken>
  120. auto post_coroutine(Executor exec, CompletionToken token)
  121. -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
  122. {
  123. co_yield asio::bind_executor(exec, std::move(token));
  124. }
  125. template <with_get_executor Context, typename CompletionToken>
  126. auto post_coroutine(Context &ctx, CompletionToken token)
  127. -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
  128. {
  129. co_yield asio::bind_executor(ctx.get_executor(), std::move(token));
  130. }
  131. }
  132. #endif //BOOST_COBALT_WRAPPER_HPP