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

164 lines
4.4 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_WRAPPER_HPP
#define BOOST_COBALT_WRAPPER_HPP
#include <boost/cobalt/this_coro.hpp>
#include <boost/cobalt/concepts.hpp>
#include <boost/cobalt/detail/util.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/executor.hpp>
#include <boost/asio/post.hpp>
#include <boost/config.hpp>
#include <coroutine>
#include <utility>
#if BOOST_COBALT_NO_SELF_DELETE
#include <boost/asio/consign.hpp>
#endif
namespace boost::cobalt::detail
{
template<typename Allocator>
struct partial_promise_base
{
template<typename CompletionToken>
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<typename Executor, typename CompletionToken>
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));
}
#if defined(__cpp_sized_deallocation)
void operator delete(void * raw, const std::size_t size)
{
deallocate_coroutine<Allocator>(raw, size);
}
#else
void operator delete(void * raw)
{
deallocate_coroutine<Allocator>(raw);
}
#endif
};
template<>
struct partial_promise_base<std::allocator<void>> {};
template<> struct partial_promise_base<void> {};
template<typename T> struct partial_promise_base<std::allocator<T>> {};
// alloc options are two: allocator or aligned storage
template<typename Allocator = void>
struct partial_promise : partial_promise_base<Allocator>
{
auto initial_suspend() noexcept
{
return std::suspend_always();
}
auto final_suspend() noexcept
{
return std::suspend_never();
}
void return_void() {}
};
template<typename Allocator = void>
struct post_coroutine_promise : partial_promise<Allocator>
{
template<typename CompletionToken>
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<void> 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<post_coroutine_promise<Allocator>> get_return_object()
{
return std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this);
}
void unhandled_exception()
{
detail::self_destroy(std::coroutine_handle<post_coroutine_promise<Allocator>>::from_promise(*this));
throw;
}
};
}
namespace std
{
template <typename T, typename ... Args>
struct coroutine_traits<coroutine_handle<boost::cobalt::detail::post_coroutine_promise<T>>, Args...>
{
using promise_type = boost::cobalt::detail::post_coroutine_promise<T>;
};
} // namespace std
namespace boost::cobalt::detail
{
template <typename CompletionToken>
auto post_coroutine(CompletionToken token)
-> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
{
co_yield std::move(token);
}
template <asio::execution::executor Executor, typename CompletionToken>
auto post_coroutine(Executor exec, CompletionToken token)
-> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
{
co_yield asio::bind_executor(exec, std::move(token));
}
template <with_get_executor Context, typename CompletionToken>
auto post_coroutine(Context &ctx, CompletionToken token)
-> std::coroutine_handle<post_coroutine_promise<asio::associated_allocator_t<CompletionToken>>>
{
co_yield asio::bind_executor(ctx.get_executor(), std::move(token));
}
}
#endif //BOOST_COBALT_WRAPPER_HPP