// 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 #include #include #include #include #include #include #include #include #if BOOST_COBALT_NO_SELF_DELETE #include #endif namespace boost::cobalt::detail { template struct partial_promise_base { template 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 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(raw, size); } }; template<> struct partial_promise_base> {}; template<> struct partial_promise_base {}; template struct partial_promise_base> {}; // alloc options are two: allocator or aligned storage template struct partial_promise : partial_promise_base { auto initial_suspend() noexcept { return std::suspend_always(); } auto final_suspend() noexcept { return std::suspend_never(); } void return_void() {} }; template struct post_coroutine_promise : partial_promise { template 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 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> get_return_object() { return std::coroutine_handle>::from_promise(*this); } void unhandled_exception() { detail::self_destroy(std::coroutine_handle>::from_promise(*this)); throw; } }; } namespace std { template struct coroutine_traits>, Args...> { using promise_type = boost::cobalt::detail::post_coroutine_promise; }; } // namespace std namespace boost::cobalt::detail { template auto post_coroutine(CompletionToken token) -> std::coroutine_handle>> { co_yield std::move(token); } template auto post_coroutine(Executor exec, CompletionToken token) -> std::coroutine_handle>> { co_yield asio::bind_executor(exec, std::move(token)); } template auto post_coroutine(Context &ctx, CompletionToken token) -> std::coroutine_handle>> { co_yield asio::bind_executor(ctx.get_executor(), std::move(token)); } } #endif //BOOST_COBALT_WRAPPER_HPP