wrapper.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. void operator delete(void * raw, const std::size_t size)
  39. {
  40. deallocate_coroutine<Allocator>(raw, size);
  41. }
  42. };
  43. template<>
  44. struct partial_promise_base<std::allocator<void>> {};
  45. template<> struct partial_promise_base<void> {};
  46. template<typename T> struct partial_promise_base<std::allocator<T>> {};
  47. // alloc options are two: allocator or aligned storage
  48. template<typename Allocator = void>
  49. struct partial_promise : partial_promise_base<Allocator>
  50. {
  51. auto initial_suspend() noexcept
  52. {
  53. return std::suspend_always();
  54. }
  55. auto final_suspend() noexcept
  56. {
  57. return std::suspend_never();
  58. }
  59. void return_void() {}
  60. };
  61. template<typename Allocator = void>
  62. struct post_coroutine_promise : partial_promise<Allocator>
  63. {
  64. template<typename CompletionToken>
  65. auto yield_value(CompletionToken cpl)
  66. {
  67. struct awaitable_t
  68. {
  69. CompletionToken cpl;
  70. constexpr bool await_ready() noexcept { return false; }
  71. BOOST_NOINLINE
  72. auto await_suspend(std::coroutine_handle<void> h) noexcept
  73. {
  74. auto c = std::move(cpl);
  75. if (this_thread::has_executor())
  76. detail::self_destroy(h, asio::get_associated_executor(c, this_thread::get_executor()));
  77. else
  78. detail::self_destroy(h, asio::get_associated_executor(c));
  79. asio::post(std::move(c));
  80. }
  81. constexpr void await_resume() noexcept {}
  82. };
  83. return awaitable_t{std::move(cpl)};
  84. }
  85. std::coroutine_handle<post_coroutine_promise<Allocator>> get_return_object()
  86. {
  87. return std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this);
  88. }
  89. void unhandled_exception()
  90. {
  91. detail::self_destroy(std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this));
  92. throw;
  93. }
  94. };
  95. }
  96. namespace std
  97. {
  98. template <typename T, typename ... Args>
  99. struct coroutine_traits<coroutine_handle<boost::cobalt::detail::post_coroutine_promise<T>>, Args...>
  100. {
  101. using promise_type = boost::cobalt::detail::post_coroutine_promise<T>;
  102. };
  103. } // namespace std
  104. namespace boost::cobalt::detail
  105. {
  106. template <typename CompletionToken>
  107. auto post_coroutine(CompletionToken token)
  108. -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
  109. {
  110. co_yield std::move(token);
  111. }
  112. template <asio::execution::executor Executor, typename CompletionToken>
  113. auto post_coroutine(Executor exec, CompletionToken token)
  114. -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
  115. {
  116. co_yield asio::bind_executor(exec, std::move(token));
  117. }
  118. template <with_get_executor Context, typename CompletionToken>
  119. auto post_coroutine(Context &ctx, CompletionToken token)
  120. -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
  121. {
  122. co_yield asio::bind_executor(ctx.get_executor(), std::move(token));
  123. }
  124. }
  125. #endif //BOOST_COBALT_WRAPPER_HPP