123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // Copyright (c) 2022 Klemens D. Morgenstern
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_COBALT_WRAPPER_HPP
- #define BOOST_COBALT_WRAPPER_HPP
- #include <boost/cobalt/this_coro.hpp>
- #include <boost/cobalt/concepts.hpp>
- #include <boost/cobalt/detail/util.hpp>
- #include <boost/asio/bind_executor.hpp>
- #include <boost/asio/executor.hpp>
- #include <boost/asio/post.hpp>
- #include <boost/config.hpp>
- #include <coroutine>
- #include <utility>
- #if BOOST_COBALT_NO_SELF_DELETE
- #include <boost/asio/consign.hpp>
- #endif
- namespace boost::cobalt::detail
- {
- template<typename Allocator>
- struct partial_promise_base
- {
- template<typename CompletionToken>
- void * operator new(const std::size_t size, CompletionToken & token)
- {
- // gcc: 168 40
- // clang: 144 40
- return allocate_coroutine(size, asio::get_associated_allocator(token));
- }
- template<typename Executor, typename CompletionToken>
- void * operator new(const std::size_t size, Executor &, CompletionToken & token)
- {
- // gcc: 120 8 16
- // clang: 96 8 16
- return allocate_coroutine(size, asio::get_associated_allocator(token));
- }
- void operator delete(void * raw, const std::size_t size)
- {
- deallocate_coroutine<Allocator>(raw, size);
- }
- };
- template<>
- struct partial_promise_base<std::allocator<void>> {};
- template<> struct partial_promise_base<void> {};
- template<typename T> struct partial_promise_base<std::allocator<T>> {};
- // alloc options are two: allocator or aligned storage
- template<typename Allocator = void>
- struct partial_promise : partial_promise_base<Allocator>
- {
- auto initial_suspend() noexcept
- {
- return std::suspend_always();
- }
- auto final_suspend() noexcept
- {
- return std::suspend_never();
- }
- void return_void() {}
- };
- template<typename Allocator = void>
- struct post_coroutine_promise : partial_promise<Allocator>
- {
- template<typename CompletionToken>
- auto yield_value(CompletionToken cpl)
- {
- struct awaitable_t
- {
- CompletionToken cpl;
- constexpr bool await_ready() noexcept { return false; }
- BOOST_NOINLINE
- auto await_suspend(std::coroutine_handle<void> h) noexcept
- {
- auto c = std::move(cpl);
- if (this_thread::has_executor())
- detail::self_destroy(h, asio::get_associated_executor(c, this_thread::get_executor()));
- else
- detail::self_destroy(h, asio::get_associated_executor(c));
- asio::post(std::move(c));
- }
- constexpr void await_resume() noexcept {}
- };
- return awaitable_t{std::move(cpl)};
- }
- std::coroutine_handle<post_coroutine_promise<Allocator>> get_return_object()
- {
- return std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this);
- }
- void unhandled_exception()
- {
- detail::self_destroy(std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this));
- throw;
- }
- };
- }
- namespace std
- {
- template <typename T, typename ... Args>
- struct coroutine_traits<coroutine_handle<boost::cobalt::detail::post_coroutine_promise<T>>, Args...>
- {
- using promise_type = boost::cobalt::detail::post_coroutine_promise<T>;
- };
- } // namespace std
- namespace boost::cobalt::detail
- {
- template <typename CompletionToken>
- auto post_coroutine(CompletionToken token)
- -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
- {
- co_yield std::move(token);
- }
- template <asio::execution::executor Executor, typename CompletionToken>
- auto post_coroutine(Executor exec, CompletionToken token)
- -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
- {
- co_yield asio::bind_executor(exec, std::move(token));
- }
- template <with_get_executor Context, typename CompletionToken>
- auto post_coroutine(Context &ctx, CompletionToken token)
- -> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
- {
- co_yield asio::bind_executor(ctx.get_executor(), std::move(token));
- }
- }
- #endif //BOOST_COBALT_WRAPPER_HPP
|