// // Copyright (c) 2024 Klemens Morgenstern (klemens.morgenstern@gmx.net) // // 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_EXPERIMENTAL_YIELD_CONTEXT_HPP #define BOOST_COBALT_EXPERIMENTAL_YIELD_CONTEXT_HPP #include #include #include #include template struct std::coroutine_handle> { constexpr operator coroutine_handle<>() const noexcept { return coroutine_handle<>::from_address(address()); } constexpr explicit operator bool() const noexcept { return true; } constexpr bool done() const noexcept { return false; } void operator()() const noexcept {} void resume() const noexcept {frame_->promiseresume();} void destroy() const noexcept {frame_->destroy();} boost::asio::basic_yield_context & promise() const noexcept { return frame_->promise; } constexpr void* address() const noexcept { return frame_; } struct yield_context_frame : boost::cobalt::experimental::frame> { using boost::cobalt::experimental::frame>::frame; void resume() { lifetime.resume(); } void destroy() { // destroy the lifetime. auto lf = std::move(lifetime); } boost::asio::detail::spawn_handler_base lifetime{this->promise}; }; coroutine_handle(yield_context_frame & frame) : frame_(&frame) {} private: yield_context_frame * frame_; }; namespace boost::cobalt::experimental { template auto await(Aw && aw, boost::asio::basic_yield_context ctx) { if (!std::forward(aw).await_ready()) { using ch = std::coroutine_handle>; typename ch::yield_context_frame fr{std::move(ctx)}; ch h{fr}; ctx.spawned_thread_->suspend_with( [&] { using rt = decltype(std::forward(aw).await_suspend(h)); if constexpr (std::is_void_v) std::forward(aw).await_suspend(h); else if constexpr (std::is_same_v) { if (!std::forward(aw).await_suspend(h)) ctx.spawned_thread_->resume(); } else std::forward(aw).await_suspend(h).resume(); } ); } return std::forward(aw).await_resume(); } template requires requires (Aw && aw) {{std::forward(aw).operator co_await()} -> awaitable_type; } auto await(Aw && aw, boost::asio::basic_yield_context ctx) { return await(std::forward(aw).operator co_await(), std::move(ctx)); } template requires requires (Aw && aw) {{operator co_await(std::forward(aw))} -> awaitable_type; } auto await(Aw && aw, boost::asio::basic_yield_context ctx) { return await(operator co_await(std::forward(aw)), std::move(ctx)); } } #endif //BOOST_COBALT_EXPERIMENTAL_YIELD_CONTEXT_HPP