gnss-sim/3rdparty/boost/cobalt/detail/with.hpp

155 lines
3.6 KiB
C++

// 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_DETAIL_WITH_HPP
#define BOOST_COBALT_DETAIL_WITH_HPP
#include <boost/cobalt/concepts.hpp>
#include <boost/cobalt/this_coro.hpp>
#include <boost/asio/cancellation_signal.hpp>
namespace boost::cobalt::detail
{
template<typename T>
struct [[nodiscard]] with_impl
{
struct promise_type;
bool await_ready() { return false;}
template<typename Promise>
BOOST_NOINLINE auto await_suspend(std::coroutine_handle<Promise> h) -> std::coroutine_handle<promise_type>;
inline T await_resume();
private:
with_impl(promise_type & promise) : promise(promise) {}
promise_type & promise;
};
template<typename T>
struct with_promise_value
{
std::optional<T> result;
void return_value(std::optional<T> && value)
{
if (value) // so non-move-assign types work
result.emplace(std::move(*value));
}
T get_result()
{
return std::move(result).value();
}
};
template<>
struct with_promise_value<void>
{
void return_void() {}
void get_result() {}
};
template<typename T>
struct with_impl<T>::promise_type
: with_promise_value<T>,
enable_awaitables<promise_type>,
enable_await_allocator<promise_type>
{
using enable_awaitables<promise_type>::await_transform;
using enable_await_allocator<promise_type>::await_transform;
using executor_type = executor;
const executor_type & get_executor() const {return *exec;}
std::optional<executor_type> exec;
with_impl get_return_object()
{
return with_impl{*this};
}
std::exception_ptr e;
void unhandled_exception()
{
e = std::current_exception();
}
std::suspend_always initial_suspend() noexcept {return {};}
struct final_awaitable
{
promise_type *promise;
bool await_ready() const noexcept
{
return false;
}
BOOST_NOINLINE
auto await_suspend(std::coroutine_handle<promise_type> h) noexcept -> std::coroutine_handle<void>
{
return std::coroutine_handle<void>::from_address(h.promise().awaited_from.address());
}
void await_resume() noexcept
{
}
};
auto final_suspend() noexcept
{
return final_awaitable{this};
}
using cancellation_slot_type = asio::cancellation_slot;
cancellation_slot_type get_cancellation_slot() const {return slot_;}
asio::cancellation_slot slot_;
std::coroutine_handle<void> awaited_from{nullptr};
};
template<typename T>
T with_impl<T>::await_resume()
{
auto e = promise.e;
auto res = std::move(promise.get_result());
std::coroutine_handle<promise_type>::from_promise(promise).destroy();
if (e)
std::rethrow_exception(e);
return std::move(res);
}
template<>
inline void with_impl<void>::await_resume()
{
auto e = promise.e;
std::coroutine_handle<promise_type>::from_promise(promise).destroy();
if (e)
std::rethrow_exception(e);
}
template<typename T>
template<typename Promise>
auto with_impl<T>::await_suspend(std::coroutine_handle<Promise> h) -> std::coroutine_handle<promise_type>
{
if constexpr (requires (Promise p) {p.get_executor();})
promise.exec.emplace(h.promise().get_executor());
else
promise.exec.emplace(this_thread::get_executor());
if constexpr (requires (Promise p) {p.get_cancellation_slot();})
promise.slot_ = h.promise().get_cancellation_slot();
promise.awaited_from = h;
return std::coroutine_handle<promise_type>::from_promise(promise);
}
}
#endif //BOOST_COBALT_DETAIL_WITH_HPP