164 lines
4.4 KiB
C++
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
|