123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- //
- // 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 <boost/cobalt/experimental/frame.hpp>
- #include <boost/cobalt/concepts.hpp>
- #include <boost/asio/spawn.hpp>
- #include <coroutine>
- template<typename Executor>
- struct std::coroutine_handle<boost::asio::basic_yield_context<Executor>>
- {
- 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<Executor> & promise() const noexcept { return frame_->promise; }
- constexpr void* address() const noexcept { return frame_; }
- struct yield_context_frame :
- boost::cobalt::experimental::frame<yield_context_frame, boost::asio::basic_yield_context<Executor>>
- {
- using boost::cobalt::experimental::frame<yield_context_frame, boost::asio::basic_yield_context<Executor>>::frame;
- void resume()
- {
- lifetime.resume();
- }
- void destroy()
- {
- // destroy the lifetime.
- auto lf = std::move(lifetime);
- }
- boost::asio::detail::spawn_handler_base<Executor> lifetime{this->promise};
- };
- coroutine_handle(yield_context_frame & frame) : frame_(&frame) {}
- private:
- yield_context_frame * frame_;
- };
- namespace boost::cobalt::experimental
- {
- template<awaitable_type Aw, typename Executor>
- auto await(Aw && aw, boost::asio::basic_yield_context<Executor> ctx)
- {
- if (!std::forward<Aw>(aw).await_ready())
- {
- using ch = std::coroutine_handle<boost::asio::basic_yield_context<Executor>>;
- typename ch::yield_context_frame fr{std::move(ctx)};
- ch h{fr};
- ctx.spawned_thread_->suspend_with(
- [&]
- {
- using rt = decltype(std::forward<Aw>(aw).await_suspend(h));
- if constexpr (std::is_void_v<rt>)
- std::forward<Aw>(aw).await_suspend(h);
- else if constexpr (std::is_same_v<rt, bool>)
- {
- if (!std::forward<Aw>(aw).await_suspend(h))
- ctx.spawned_thread_->resume();
- }
- else
- std::forward<Aw>(aw).await_suspend(h).resume();
- }
- );
- }
- return std::forward<Aw>(aw).await_resume();
- }
- template<typename Aw, typename Executor>
- requires requires (Aw && aw) {{std::forward<Aw>(aw).operator co_await()} -> awaitable_type; }
- auto await(Aw && aw, boost::asio::basic_yield_context<Executor> ctx)
- {
- return await(std::forward<Aw>(aw).operator co_await(), std::move(ctx));
- }
- template<typename Aw, typename Executor>
- requires requires (Aw && aw) {{operator co_await(std::forward<Aw>(aw))} -> awaitable_type; }
- auto await(Aw && aw, boost::asio::basic_yield_context<Executor> ctx)
- {
- return await(operator co_await(std::forward<Aw>(aw)), std::move(ctx));
- }
- }
- #endif //BOOST_COBALT_EXPERIMENTAL_YIELD_CONTEXT_HPP
|