Insane_DNS/libraries/asio-1.28.1/include/asio/experimental/impl/co_composed.hpp

1176 lines
34 KiB
C++
Raw Normal View History

2023-10-24 21:59:30 -04:00
//
// experimental/impl/co_composed.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
#define ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <new>
#include <tuple>
#include <variant>
#include "asio/associated_cancellation_slot.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/cancellation_state.hpp"
#include "asio/detail/composed_work.hpp"
#include "asio/detail/recycling_allocator.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#if defined(ASIO_HAS_STD_COROUTINE)
# include <coroutine>
#else // defined(ASIO_HAS_STD_COROUTINE)
# include <experimental/coroutine>
#endif // defined(ASIO_HAS_STD_COROUTINE)
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# if defined(ASIO_HAS_SOURCE_LOCATION)
# include "asio/detail/source_location.hpp"
# endif // defined(ASIO_HAS_SOURCE_LOCATION)
#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace experimental {
namespace detail {
#if defined(ASIO_HAS_STD_COROUTINE)
using std::coroutine_handle;
using std::suspend_always;
using std::suspend_never;
#else // defined(ASIO_HAS_STD_COROUTINE)
using std::experimental::coroutine_handle;
using std::experimental::suspend_always;
using std::experimental::suspend_never;
#endif // defined(ASIO_HAS_STD_COROUTINE)
using asio::detail::composed_io_executors;
using asio::detail::composed_work;
using asio::detail::composed_work_guard;
using asio::detail::get_composed_io_executor;
using asio::detail::make_composed_io_executors;
using asio::detail::recycling_allocator;
using asio::detail::throw_error;
template <typename Executors, typename Handler, typename Return>
class co_composed_state;
template <typename Executors, typename Handler, typename Return>
class co_composed_handler_base;
template <typename Executors, typename Handler, typename Return>
class co_composed_promise;
template <completion_signature... Signatures>
class co_composed_returns
{
};
struct co_composed_on_suspend
{
void (*fn_)(void*) = nullptr;
void* arg_ = nullptr;
};
template <typename... T>
struct co_composed_completion : std::tuple<T&&...>
{
template <typename... U>
co_composed_completion(U&&... u) noexcept
: std::tuple<T&&...>(std::forward<U>(u)...)
{
}
};
template <typename Executors, typename Handler,
typename Return, typename Signature>
class co_composed_state_return_overload;
template <typename Executors, typename Handler,
typename Return, typename R, typename... Args>
class co_composed_state_return_overload<
Executors, Handler, Return, R(Args...)>
{
public:
using derived_type = co_composed_state<Executors, Handler, Return>;
using promise_type = co_composed_promise<Executors, Handler, Return>;
using return_type = std::tuple<Args...>;
void on_cancellation_complete_with(Args... args)
{
derived_type& state = *static_cast<derived_type*>(this);
state.return_value_ = std::make_tuple(std::move(args)...);
state.cancellation_on_suspend_fn(
[](void* p)
{
auto& promise = *static_cast<promise_type*>(p);
co_composed_handler_base<Executors, Handler,
Return> composed_handler(promise);
Handler handler(std::move(promise.state().handler_));
return_type result(
std::move(std::get<return_type>(promise.state().return_value_)));
co_composed_handler_base<Executors, Handler,
Return>(std::move(composed_handler));
std::apply(std::move(handler), std::move(result));
});
}
};
template <typename Executors, typename Handler, typename Return>
class co_composed_state_return;
template <typename Executors, typename Handler, typename... Signatures>
class co_composed_state_return<
Executors, Handler, co_composed_returns<Signatures...>>
: public co_composed_state_return_overload<Executors,
Handler, co_composed_returns<Signatures...>, Signatures>...
{
public:
using co_composed_state_return_overload<Executors,
Handler, co_composed_returns<Signatures...>,
Signatures>::on_cancellation_complete_with...;
private:
template <typename, typename, typename, typename>
friend class co_composed_promise_return_overload;
template <typename, typename, typename, typename>
friend class co_composed_state_return_overload;
std::variant<std::monostate,
typename co_composed_state_return_overload<
Executors, Handler, co_composed_returns<Signatures...>,
Signatures>::return_type...> return_value_;
};
template <typename Executors, typename Handler,
typename Return, typename... Signatures>
struct co_composed_state_default_cancellation_on_suspend_impl;
template <typename Executors, typename Handler, typename Return>
struct co_composed_state_default_cancellation_on_suspend_impl<
Executors, Handler, Return>
{
static constexpr void (*fn())(void*)
{
return nullptr;
}
};
template <typename Executors, typename Handler, typename Return,
typename R, typename... Args, typename... Signatures>
struct co_composed_state_default_cancellation_on_suspend_impl<
Executors, Handler, Return, R(Args...), Signatures...>
{
static constexpr void (*fn())(void*)
{
return co_composed_state_default_cancellation_on_suspend_impl<
Executors, Handler, Return, Signatures...>::fn();
}
};
template <typename Executors, typename Handler, typename Return,
typename R, typename... Args, typename... Signatures>
struct co_composed_state_default_cancellation_on_suspend_impl<Executors,
Handler, Return, R(asio::error_code, Args...), Signatures...>
{
using promise_type = co_composed_promise<Executors, Handler, Return>;
using return_type = std::tuple<asio::error_code, Args...>;
static constexpr void (*fn())(void*)
{
if constexpr ((is_constructible<Args>::value && ...))
{
return [](void* p)
{
auto& promise = *static_cast<promise_type*>(p);
co_composed_handler_base<Executors, Handler,
Return> composed_handler(promise);
Handler handler(std::move(promise.state().handler_));
co_composed_handler_base<Executors, Handler,
Return>(std::move(composed_handler));
std::move(handler)(
asio::error_code(asio::error::operation_aborted),
Args{}...);
};
}
else
{
return co_composed_state_default_cancellation_on_suspend_impl<
Executors, Handler, Return, Signatures...>::fn();
}
}
};
template <typename Executors, typename Handler, typename Return,
typename R, typename... Args, typename... Signatures>
struct co_composed_state_default_cancellation_on_suspend_impl<Executors,
Handler, Return, R(std::exception_ptr, Args...), Signatures...>
{
using promise_type = co_composed_promise<Executors, Handler, Return>;
using return_type = std::tuple<std::exception_ptr, Args...>;
static constexpr void (*fn())(void*)
{
if constexpr ((is_constructible<Args>::value && ...))
{
return [](void* p)
{
auto& promise = *static_cast<promise_type*>(p);
co_composed_handler_base<Executors, Handler,
Return> composed_handler(promise);
Handler handler(std::move(promise.state().handler_));
co_composed_handler_base<Executors, Handler,
Return>(std::move(composed_handler));
std::move(handler)(
std::make_exception_ptr(
asio::system_error(
asio::error::operation_aborted, "co_await")),
Args{}...);
};
}
else
{
return co_composed_state_default_cancellation_on_suspend_impl<
Executors, Handler, Return, Signatures...>::fn();
}
}
};
template <typename Executors, typename Handler, typename Return>
struct co_composed_state_default_cancellation_on_suspend;
template <typename Executors, typename Handler, typename... Signatures>
struct co_composed_state_default_cancellation_on_suspend<
Executors, Handler, co_composed_returns<Signatures...>>
: co_composed_state_default_cancellation_on_suspend_impl<Executors,
Handler, co_composed_returns<Signatures...>, Signatures...>
{
};
template <typename Executors, typename Handler, typename Return>
class co_composed_state_cancellation
{
public:
using cancellation_slot_type = cancellation_slot;
cancellation_slot_type get_cancellation_slot() const noexcept
{
return cancellation_state_.slot();
}
cancellation_state get_cancellation_state() const noexcept
{
return cancellation_state_;
}
void reset_cancellation_state()
{
cancellation_state_ = cancellation_state(
(get_associated_cancellation_slot)(
static_cast<co_composed_state<Executors, Handler, Return>*>(
this)->handler()));
}
template <typename Filter>
void reset_cancellation_state(Filter filter)
{
cancellation_state_ = cancellation_state(
(get_associated_cancellation_slot)(
static_cast<co_composed_state<Executors, Handler, Return>*>(
this)->handler()), filter, filter);
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(InFilter&& in_filter, OutFilter&& out_filter)
{
cancellation_state_ = cancellation_state(
(get_associated_cancellation_slot)(
static_cast<co_composed_state<Executors, Handler, Return>*>(
this)->handler()),
std::forward<InFilter>(in_filter),
std::forward<OutFilter>(out_filter));
}
cancellation_type_t cancelled() const noexcept
{
return cancellation_state_.cancelled();
}
void clear_cancellation_slot() noexcept
{
cancellation_state_.slot().clear();
}
[[nodiscard]] bool throw_if_cancelled() const noexcept
{
return throw_if_cancelled_;
}
void throw_if_cancelled(bool b) noexcept
{
throw_if_cancelled_ = b;
}
[[nodiscard]] bool complete_if_cancelled() const noexcept
{
return complete_if_cancelled_;
}
void complete_if_cancelled(bool b) noexcept
{
complete_if_cancelled_ = b;
}
private:
template <typename, typename, typename>
friend class co_composed_promise;
template <typename, typename, typename, typename>
friend class co_composed_state_return_overload;
void cancellation_on_suspend_fn(void (*fn)(void*))
{
cancellation_on_suspend_fn_ = fn;
}
void check_for_cancellation_on_transform()
{
if (throw_if_cancelled_ && !!cancelled())
throw_error(asio::error::operation_aborted, "co_await");
}
bool check_for_cancellation_on_suspend(
co_composed_promise<Executors, Handler, Return>& promise) noexcept
{
if (complete_if_cancelled_ && !!cancelled() && cancellation_on_suspend_fn_)
{
promise.state().work_.reset();
promise.state().on_suspend_->fn_ = cancellation_on_suspend_fn_;
promise.state().on_suspend_->arg_ = &promise;
return false;
}
return true;
}
cancellation_state cancellation_state_;
void (*cancellation_on_suspend_fn_)(void*) =
co_composed_state_default_cancellation_on_suspend<
Executors, Handler, Return>::fn();
bool throw_if_cancelled_ = false;
bool complete_if_cancelled_ = true;
};
template <typename Executors, typename Handler, typename Return>
requires is_same<
typename associated_cancellation_slot<
Handler, cancellation_slot
>::asio_associated_cancellation_slot_is_unspecialised,
void>::value
class co_composed_state_cancellation<Executors, Handler, Return>
{
public:
void reset_cancellation_state()
{
}
template <typename Filter>
void reset_cancellation_state(Filter)
{
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(InFilter&&, OutFilter&&)
{
}
cancellation_type_t cancelled() const noexcept
{
return cancellation_type::none;
}
void clear_cancellation_slot() noexcept
{
}
[[nodiscard]] bool throw_if_cancelled() const noexcept
{
return false;
}
void throw_if_cancelled(bool) noexcept
{
}
[[nodiscard]] bool complete_if_cancelled() const noexcept
{
return false;
}
void complete_if_cancelled(bool) noexcept
{
}
private:
template <typename, typename, typename>
friend class co_composed_promise;
template <typename, typename, typename, typename>
friend class co_composed_state_return_overload;
void cancellation_on_suspend_fn(void (*)(void*))
{
}
void check_for_cancellation_on_transform() noexcept
{
}
bool check_for_cancellation_on_suspend(
co_composed_promise<Executors, Handler, Return>&) noexcept
{
return true;
}
};
template <typename Executors, typename Handler, typename Return>
class co_composed_state
: public co_composed_state_return<Executors, Handler, Return>,
public co_composed_state_cancellation<Executors, Handler, Return>
{
public:
using io_executor_type = typename composed_work_guard<
typename composed_work<Executors>::head_type>::executor_type;
template <typename H>
co_composed_state(composed_io_executors<Executors>&& executors,
H&& h, co_composed_on_suspend& on_suspend)
: work_(std::move(executors)),
handler_(std::forward<H>(h)),
on_suspend_(&on_suspend)
{
this->reset_cancellation_state(enable_terminal_cancellation());
}
io_executor_type get_io_executor() const noexcept
{
return work_.head_.get_executor();
}
template <typename... Args>
[[nodiscard]] co_composed_completion<Args...> complete(Args&&... args)
requires requires { declval<Handler>()(std::forward<Args>(args)...); }
{
return co_composed_completion<Args...>(std::forward<Args>(args)...);
}
const Handler& handler() const noexcept
{
return handler_;
}
private:
template <typename, typename, typename>
friend class co_composed_handler_base;
template <typename, typename, typename>
friend class co_composed_promise;
template <typename, typename, typename, typename>
friend class co_composed_promise_return_overload;
template <typename, typename, typename>
friend class co_composed_state_cancellation;
template <typename, typename, typename, typename>
friend class co_composed_state_return_overload;
template <typename, typename, typename, typename...>
friend struct co_composed_state_default_cancellation_on_suspend_impl;
composed_work<Executors> work_;
Handler handler_;
co_composed_on_suspend* on_suspend_;
};
template <typename Executors, typename Handler, typename Return>
class co_composed_handler_cancellation
{
public:
using cancellation_slot_type = cancellation_slot;
cancellation_slot_type get_cancellation_slot() const noexcept
{
return static_cast<
const co_composed_handler_base<Executors, Handler, Return>*>(
this)->promise().state().get_cancellation_slot();
}
};
template <typename Executors, typename Handler, typename Return>
requires is_same<
typename associated_cancellation_slot<
Handler, cancellation_slot
>::asio_associated_cancellation_slot_is_unspecialised,
void>::value
class co_composed_handler_cancellation<Executors, Handler, Return>
{
};
template <typename Executors, typename Handler, typename Return>
class co_composed_handler_base :
public co_composed_handler_cancellation<Executors, Handler, Return>
{
public:
co_composed_handler_base(
co_composed_promise<Executors, Handler, Return>& p) noexcept
: p_(&p)
{
}
co_composed_handler_base(co_composed_handler_base&& other) noexcept
: p_(std::exchange(other.p_, nullptr))
{
}
~co_composed_handler_base()
{
if (p_) [[unlikely]]
p_->destroy();
}
co_composed_promise<Executors, Handler, Return>& promise() const noexcept
{
return *p_;
}
protected:
void resume(void* result)
{
co_composed_on_suspend on_suspend{};
std::exchange(p_, nullptr)->resume(p_, result, on_suspend);
if (on_suspend.fn_)
on_suspend.fn_(on_suspend.arg_);
}
private:
co_composed_promise<Executors, Handler, Return>* p_;
};
template <typename Executors, typename Handler,
typename Return, typename Signature>
class co_composed_handler;
template <typename Executors, typename Handler,
typename Return, typename R, typename... Args>
class co_composed_handler<Executors, Handler, Return, R(Args...)>
: public co_composed_handler_base<Executors, Handler, Return>
{
public:
using co_composed_handler_base<Executors,
Handler, Return>::co_composed_handler_base;
using result_type = std::tuple<typename decay<Args>::type...>;
template <typename... T>
void operator()(T&&... args)
{
result_type result(std::forward<T>(args)...);
this->resume(&result);
}
static auto on_resume(void* result)
{
auto& args = *static_cast<result_type*>(result);
if constexpr (sizeof...(Args) == 0)
return;
else if constexpr (sizeof...(Args) == 1)
return std::move(std::get<0>(args));
else
return std::move(args);
}
};
template <typename Executors, typename Handler,
typename Return, typename R, typename... Args>
class co_composed_handler<Executors, Handler,
Return, R(asio::error_code, Args...)>
: public co_composed_handler_base<Executors, Handler, Return>
{
public:
using co_composed_handler_base<Executors,
Handler, Return>::co_composed_handler_base;
using args_type = std::tuple<typename decay<Args>::type...>;
using result_type = std::tuple<asio::error_code, args_type>;
template <typename... T>
void operator()(const asio::error_code& ec, T&&... args)
{
result_type result(ec, args_type(std::forward<T>(args)...));
this->resume(&result);
}
static auto on_resume(void* result)
{
auto& [ec, args] = *static_cast<result_type*>(result);
throw_error(ec);
if constexpr (sizeof...(Args) == 0)
return;
else if constexpr (sizeof...(Args) == 1)
return std::move(std::get<0>(args));
else
return std::move(args);
}
};
template <typename Executors, typename Handler,
typename Return, typename R, typename... Args>
class co_composed_handler<Executors, Handler,
Return, R(std::exception_ptr, Args...)>
: public co_composed_handler_base<Executors, Handler, Return>
{
public:
using co_composed_handler_base<Executors,
Handler, Return>::co_composed_handler_base;
using args_type = std::tuple<typename decay<Args>::type...>;
using result_type = std::tuple<std::exception_ptr, args_type>;
template <typename... T>
void operator()(std::exception_ptr ex, T&&... args)
{
result_type result(std::move(ex), args_type(std::forward<T>(args)...));
this->resume(&result);
}
static auto on_resume(void* result)
{
auto& [ex, args] = *static_cast<result_type*>(result);
if (ex)
std::rethrow_exception(ex);
if constexpr (sizeof...(Args) == 0)
return;
else if constexpr (sizeof...(Args) == 1)
return std::move(std::get<0>(args));
else
return std::move(args);
}
};
template <typename Executors, typename Handler, typename Return>
class co_composed_promise_return;
template <typename Executors, typename Handler>
class co_composed_promise_return<Executors, Handler, co_composed_returns<>>
{
public:
auto final_suspend() noexcept
{
return suspend_never();
}
void return_void() noexcept
{
}
};
template <typename Executors, typename Handler,
typename Return, typename Signature>
class co_composed_promise_return_overload;
template <typename Executors, typename Handler,
typename Return, typename R, typename... Args>
class co_composed_promise_return_overload<
Executors, Handler, Return, R(Args...)>
{
public:
using derived_type = co_composed_promise<Executors, Handler, Return>;
using return_type = std::tuple<Args...>;
void return_value(std::tuple<Args...>&& value)
{
derived_type& promise = *static_cast<derived_type*>(this);
promise.state().return_value_ = std::move(value);
promise.state().work_.reset();
promise.state().on_suspend_->arg_ = this;
promise.state().on_suspend_->fn_ =
[](void* p)
{
auto& promise = *static_cast<derived_type*>(p);
co_composed_handler_base<Executors, Handler,
Return> composed_handler(promise);
Handler handler(std::move(promise.state().handler_));
return_type result(
std::move(std::get<return_type>(promise.state().return_value_)));
co_composed_handler_base<Executors, Handler,
Return>(std::move(composed_handler));
std::apply(std::move(handler), std::move(result));
};
}
};
template <typename Executors, typename Handler, typename... Signatures>
class co_composed_promise_return<Executors,
Handler, co_composed_returns<Signatures...>>
: public co_composed_promise_return_overload<Executors,
Handler, co_composed_returns<Signatures...>, Signatures>...
{
public:
auto final_suspend() noexcept
{
return suspend_always();
}
using co_composed_promise_return_overload<Executors, Handler,
co_composed_returns<Signatures...>, Signatures>::return_value...;
private:
template <typename, typename, typename, typename>
friend class co_composed_promise_return_overload;
};
template <typename Executors, typename Handler, typename Return>
class co_composed_promise
: public co_composed_promise_return<Executors, Handler, Return>
{
public:
template <typename... Args>
void* operator new(std::size_t size,
co_composed_state<Executors, Handler, Return>& state, Args&&...)
{
block_allocator_type allocator(
(get_associated_allocator)(state.handler_,
recycling_allocator<void>()));
block* base_ptr = std::allocator_traits<block_allocator_type>::allocate(
allocator, blocks(sizeof(allocator_type)) + blocks(size));
new (static_cast<void*>(base_ptr)) allocator_type(std::move(allocator));
return base_ptr + blocks(sizeof(allocator_type));
}
template <typename C, typename... Args>
void* operator new(std::size_t size, C&&,
co_composed_state<Executors, Handler, Return>& state, Args&&...)
{
return co_composed_promise::operator new(size, state);
}
void operator delete(void* ptr, std::size_t size)
{
block* base_ptr = static_cast<block*>(ptr) - blocks(sizeof(allocator_type));
allocator_type* allocator_ptr = std::launder(
static_cast<allocator_type*>(static_cast<void*>(base_ptr)));
block_allocator_type block_allocator(std::move(*allocator_ptr));
allocator_ptr->~allocator_type();
std::allocator_traits<block_allocator_type>::deallocate(block_allocator,
base_ptr, blocks(sizeof(allocator_type)) + blocks(size));
}
template <typename... Args>
co_composed_promise(
co_composed_state<Executors, Handler, Return>& state, Args&&...)
: state_(state)
{
}
template <typename C, typename... Args>
co_composed_promise(C&&,
co_composed_state<Executors, Handler, Return>& state, Args&&...)
: state_(state)
{
}
void destroy() noexcept
{
coroutine_handle<co_composed_promise>::from_promise(*this).destroy();
}
void resume(co_composed_promise*& owner, void* result,
co_composed_on_suspend& on_suspend)
{
state_.on_suspend_ = &on_suspend;
state_.clear_cancellation_slot();
owner_ = &owner;
result_ = result;
coroutine_handle<co_composed_promise>::from_promise(*this).resume();
}
co_composed_state<Executors, Handler, Return>& state() noexcept
{
return state_;
}
void get_return_object() noexcept
{
}
auto initial_suspend() noexcept
{
return suspend_never();
}
void unhandled_exception()
{
if (owner_)
*owner_ = this;
throw;
}
template <async_operation Op>
auto await_transform(Op&& op
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# if defined(ASIO_HAS_SOURCE_LOCATION)
, asio::detail::source_location location
= asio::detail::source_location::current()
# endif // defined(ASIO_HAS_SOURCE_LOCATION)
#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
)
{
class [[nodiscard]] awaitable
{
public:
awaitable(Op&& op, co_composed_promise& promise
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# if defined(ASIO_HAS_SOURCE_LOCATION)
, const asio::detail::source_location& location
# endif // defined(ASIO_HAS_SOURCE_LOCATION)
#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
)
: op_(std::forward<Op>(op)),
promise_(promise)
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# if defined(ASIO_HAS_SOURCE_LOCATION)
, location_(location)
# endif // defined(ASIO_HAS_SOURCE_LOCATION)
#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
{
}
constexpr bool await_ready() const noexcept
{
return false;
}
void await_suspend(coroutine_handle<co_composed_promise>)
{
if (promise_.state_.check_for_cancellation_on_suspend(promise_))
{
promise_.state_.on_suspend_->arg_ = this;
promise_.state_.on_suspend_->fn_ =
[](void* p)
{
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# if defined(ASIO_HAS_SOURCE_LOCATION)
ASIO_HANDLER_LOCATION((
static_cast<awaitable*>(p)->location_.file_name(),
static_cast<awaitable*>(p)->location_.line(),
static_cast<awaitable*>(p)->location_.function_name()));
# endif // defined(ASIO_HAS_SOURCE_LOCATION)
#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
std::forward<Op>(static_cast<awaitable*>(p)->op_)(
co_composed_handler<Executors, Handler,
Return, completion_signature_of_t<Op>>(
static_cast<awaitable*>(p)->promise_));
};
}
}
auto await_resume()
{
return co_composed_handler<Executors, Handler, Return,
completion_signature_of_t<Op>>::on_resume(promise_.result_);
}
private:
Op&& op_;
co_composed_promise& promise_;
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# if defined(ASIO_HAS_SOURCE_LOCATION)
asio::detail::source_location location_;
# endif // defined(ASIO_HAS_SOURCE_LOCATION)
#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
};
state_.check_for_cancellation_on_transform();
return awaitable{std::forward<Op>(op), *this
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# if defined(ASIO_HAS_SOURCE_LOCATION)
, location
# endif // defined(ASIO_HAS_SOURCE_LOCATION)
#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
};
}
template <typename... Args>
auto yield_value(co_composed_completion<Args...>&& result)
{
class [[nodiscard]] awaitable
{
public:
awaitable(co_composed_completion<Args...>&& result,
co_composed_promise& promise)
: result_(std::move(result)),
promise_(promise)
{
}
constexpr bool await_ready() const noexcept
{
return false;
}
void await_suspend(coroutine_handle<co_composed_promise>)
{
promise_.state_.work_.reset();
promise_.state_.on_suspend_->arg_ = this;
promise_.state_.on_suspend_->fn_ =
[](void* p)
{
awaitable& a = *static_cast<awaitable*>(p);
co_composed_handler_base<Executors, Handler,
Return> composed_handler(a.promise_);
Handler handler(std::move(a.promise_.state_.handler_));
std::tuple<typename decay<Args>::type...> result(
std::move(static_cast<std::tuple<Args&&...>>(a.result_)));
co_composed_handler_base<Executors, Handler,
Return>(std::move(composed_handler));
std::apply(std::move(handler), std::move(result));
};
}
void await_resume() noexcept
{
}
private:
co_composed_completion<Args...> result_;
co_composed_promise& promise_;
};
return awaitable{std::move(result), *this};
}
private:
using allocator_type =
associated_allocator_t<Handler, recycling_allocator<void>>;
union block
{
std::max_align_t max_align;
alignas(allocator_type) char pad[alignof(allocator_type)];
};
using block_allocator_type =
typename std::allocator_traits<allocator_type>
::template rebind_alloc<block>;
static constexpr std::size_t blocks(std::size_t size)
{
return (size + sizeof(block) - 1) / sizeof(block);
}
co_composed_state<Executors, Handler, Return>& state_;
co_composed_promise** owner_ = nullptr;
void* result_ = nullptr;
};
template <typename Implementation, typename Executors, typename... Signatures>
class initiate_co_composed
{
public:
using executor_type = typename composed_io_executors<Executors>::head_type;
template <typename I>
initiate_co_composed(I&& impl, composed_io_executors<Executors>&& executors)
: implementation_(std::forward<I>(impl)),
executors_(std::move(executors))
{
}
executor_type get_executor() const noexcept
{
return executors_.head_;
}
template <typename Handler, typename... InitArgs>
void operator()(Handler&& handler, InitArgs&&... init_args) const &
{
using handler_type = typename decay<Handler>::type;
using returns_type = co_composed_returns<Signatures...>;
co_composed_on_suspend on_suspend{};
implementation_(
co_composed_state<Executors, handler_type, returns_type>(
executors_, std::forward<Handler>(handler), on_suspend),
std::forward<InitArgs>(init_args)...);
if (on_suspend.fn_)
on_suspend.fn_(on_suspend.arg_);
}
template <typename Handler, typename... InitArgs>
void operator()(Handler&& handler, InitArgs&&... init_args) &&
{
using handler_type = typename decay<Handler>::type;
using returns_type = co_composed_returns<Signatures...>;
co_composed_on_suspend on_suspend{};
std::move(implementation_)(
co_composed_state<Executors, handler_type, returns_type>(
std::move(executors_), std::forward<Handler>(handler), on_suspend),
std::forward<InitArgs>(init_args)...);
if (on_suspend.fn_)
on_suspend.fn_(on_suspend.arg_);
}
private:
Implementation implementation_;
composed_io_executors<Executors> executors_;
};
template <typename... Signatures, typename Implementation, typename Executors>
inline initiate_co_composed<Implementation, Executors, Signatures...>
make_initiate_co_composed(Implementation&& implementation,
composed_io_executors<Executors>&& executors)
{
return initiate_co_composed<
typename decay<Implementation>::type, Executors, Signatures...>(
std::forward<Implementation>(implementation), std::move(executors));
}
} // namespace detail
template <completion_signature... Signatures,
typename Implementation, typename... IoObjectsOrExecutors>
inline auto co_composed(Implementation&& implementation,
IoObjectsOrExecutors&&... io_objects_or_executors)
{
return detail::make_initiate_co_composed<Signatures...>(
std::forward<Implementation>(implementation),
detail::make_composed_io_executors(
detail::get_composed_io_executor(
std::forward<IoObjectsOrExecutors>(
io_objects_or_executors))...));
}
} // namespace experimental
#if !defined(GENERATING_DOCUMENTATION)
template <template <typename, typename> class Associator,
typename Executors, typename Handler, typename Return,
typename Signature, typename DefaultCandidate>
struct associator<Associator,
experimental::detail::co_composed_handler<
Executors, Handler, Return, Signature>,
DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type
get(const experimental::detail::co_composed_handler<
Executors, Handler, Return, Signature>& h) ASIO_NOEXCEPT
{
return Associator<Handler, DefaultCandidate>::get(
h.promise().state().handler());
}
static ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const experimental::detail::co_composed_handler<
Executors, Handler, Return, Signature>& h,
const DefaultCandidate& c) ASIO_NOEXCEPT
ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(
h.promise().state().handler(), c)))
{
return Associator<Handler, DefaultCandidate>::get(
h.promise().state().handler(), c);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#if !defined(GENERATING_DOCUMENTATION)
# if defined(ASIO_HAS_STD_COROUTINE)
namespace std {
# else // defined(ASIO_HAS_STD_COROUTINE)
namespace std { namespace experimental {
# endif // defined(ASIO_HAS_STD_COROUTINE)
template <typename C, typename Executors,
typename Handler, typename Return, typename... Args>
struct coroutine_traits<void, C&,
asio::experimental::detail::co_composed_state<
Executors, Handler, Return>,
Args...>
{
using promise_type =
asio::experimental::detail::co_composed_promise<
Executors, Handler, Return>;
};
template <typename C, typename Executors,
typename Handler, typename Return, typename... Args>
struct coroutine_traits<void, C&&,
asio::experimental::detail::co_composed_state<
Executors, Handler, Return>,
Args...>
{
using promise_type =
asio::experimental::detail::co_composed_promise<
Executors, Handler, Return>;
};
template <typename Executors, typename Handler,
typename Return, typename... Args>
struct coroutine_traits<void,
asio::experimental::detail::co_composed_state<
Executors, Handler, Return>,
Args...>
{
using promise_type =
asio::experimental::detail::co_composed_promise<
Executors, Handler, Return>;
};
# if defined(ASIO_HAS_STD_COROUTINE)
} // namespace std
# else // defined(ASIO_HAS_STD_COROUTINE)
}} // namespace std::experimental
# endif // defined(ASIO_HAS_STD_COROUTINE)
#endif // !defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP