gnss-sim/3rdparty/boost/cobalt/experimental/yield_context.hpp

107 lines
3.2 KiB
C++

//
// 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