boost/asio/deferred.hpp
//
// deferred.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 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 BOOST_ASIO_DEFERRED_HPP
#define BOOST_ASIO_DEFERRED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <tuple>
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/utility.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Trait for detecting objects that are usable as deferred operations.
template <typename T>
struct is_deferred : false_type
{
};
/// Helper type to wrap multiple completion signatures.
template <typename... Signatures>
struct deferred_signatures
{
};
namespace detail {
// Helper trait for getting the completion signatures of the tail in a sequence
// when invoked with the specified arguments.
template <typename Tail, typename... Signatures>
struct deferred_sequence_signatures;
template <typename Tail, typename R, typename... Args, typename... Signatures>
struct deferred_sequence_signatures<Tail, R(Args...), Signatures...>
: completion_signature_of<decltype(declval<Tail>()(declval<Args>()...))>
{
static_assert(
!is_same<decltype(declval<Tail>()(declval<Args>()...)), void>::value,
"deferred functions must produce a deferred return type");
};
// Completion handler for the head component of a deferred sequence.
template <typename Handler, typename Tail>
class deferred_sequence_handler
{
public:
template <typename H, typename T>
explicit deferred_sequence_handler(H&& handler, T&& tail)
: handler_(static_cast<H&&>(handler)),
tail_(static_cast<T&&>(tail))
{
}
template <typename... Args>
void operator()(Args&&... args)
{
static_cast<Tail&&>(tail_)(
static_cast<Args&&>(args)...)(
static_cast<Handler&&>(handler_));
}
//private:
Handler handler_;
Tail tail_;
};
template <typename Head, typename Tail, typename... Signatures>
class deferred_sequence_base
{
private:
struct initiate
{
template <typename Handler>
void operator()(Handler&& handler, Head head, Tail&& tail)
{
static_cast<Head&&>(head)(
deferred_sequence_handler<decay_t<Handler>, decay_t<Tail>>(
static_cast<Handler&&>(handler), static_cast<Tail&&>(tail)));
}
};
Head head_;
Tail tail_;
public:
template <typename H, typename T>
constexpr explicit deferred_sequence_base(H&& head, T&& tail)
: head_(static_cast<H&&>(head)),
tail_(static_cast<T&&>(tail))
{
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiate(), token, static_cast<Head&&>(this->head_),
static_cast<Tail&&>(this->tail_)))
{
return async_initiate<CompletionToken, Signatures...>(initiate(),
token, static_cast<Head&&>(head_), static_cast<Tail&&>(tail_));
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiate(), token, this->head_, this->tail_))
{
return async_initiate<CompletionToken, Signatures...>(
initiate(), token, head_, tail_);
}
};
// Two-step application of variadic Signatures to determine correct base type.
template <typename Head, typename Tail>
struct deferred_sequence_types
{
template <typename... Signatures>
struct op1
{
typedef deferred_sequence_base<Head, Tail, Signatures...> type;
};
template <typename... Signatures>
struct op2
{
typedef typename deferred_sequence_signatures<Tail, Signatures...>::template
apply<op1>::type::type type;
};
typedef typename completion_signature_of<Head>::template
apply<op2>::type::type base;
};
} // namespace detail
/// Used to represent an empty deferred action.
struct deferred_noop
{
/// No effect.
template <typename... Args>
void operator()(Args&&...) &&
{
}
/// No effect.
template <typename... Args>
void operator()(Args&&...) const &
{
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
struct is_deferred<deferred_noop> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Tag type to disambiguate deferred constructors.
struct deferred_init_tag {};
/// Wraps a function object so that it may be used as an element in a deferred
/// composition.
template <typename Function>
class deferred_function
{
public:
/// Constructor.
template <typename F>
constexpr explicit deferred_function(deferred_init_tag, F&& function)
: function_(static_cast<F&&>(function))
{
}
//private:
Function function_;
public:
template <typename... Args>
auto operator()(Args&&... args) &&
-> decltype(
static_cast<Function&&>(this->function_)(static_cast<Args&&>(args)...))
{
return static_cast<Function&&>(function_)(static_cast<Args&&>(args)...);
}
template <typename... Args>
auto operator()(Args&&... args) const &
-> decltype(Function(function_)(static_cast<Args&&>(args)...))
{
return Function(function_)(static_cast<Args&&>(args)...);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Function>
struct is_deferred<deferred_function<Function>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Encapsulates deferred values.
template <typename... Values>
class BOOST_ASIO_NODISCARD deferred_values
{
private:
std::tuple<Values...> values_;
struct initiate
{
template <typename Handler, typename... V>
void operator()(Handler handler, V&&... values)
{
static_cast<Handler&&>(handler)(static_cast<V&&>(values)...);
}
};
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, void(Values...)>(initiate(), token,
std::get<I>(static_cast<std::tuple<Values...>&&>(this->values_))...))
{
return async_initiate<CompletionToken, void(Values...)>(initiate(), token,
std::get<I>(static_cast<std::tuple<Values...>&&>(values_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, void(Values...)>(
initiate(), token, std::get<I>(values_)...))
{
return async_initiate<CompletionToken, void(Values...)>(
initiate(), token, std::get<I>(values_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename... V>
constexpr explicit deferred_values(
deferred_init_tag, V&&... values)
: values_(static_cast<V&&>(values)...)
{
}
/// Initiate the deferred operation using the supplied completion token.
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>());
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>());
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename... Values>
struct is_deferred<deferred_values<Values...>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Encapsulates a deferred asynchronous operation.
template <typename Signature, typename Initiation, typename... InitArgs>
class BOOST_ASIO_NODISCARD deferred_async_operation
{
private:
typedef decay_t<Initiation> initiation_t;
initiation_t initiation_;
typedef std::tuple<decay_t<InitArgs>...> init_args_t;
init_args_t init_args_;
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, Signature>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...))
{
return async_initiate<CompletionToken, Signature>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>) const &
-> decltype(
async_initiate<CompletionToken, Signature>(
conditional_t<true, initiation_t, CompletionToken>(initiation_),
token, std::get<I>(init_args_)...))
{
return async_initiate<CompletionToken, Signature>(
initiation_t(initiation_), token, std::get<I>(init_args_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename I, typename... A>
constexpr explicit deferred_async_operation(
deferred_init_tag, I&& initiation, A&&... init_args)
: initiation_(static_cast<I&&>(initiation)),
init_args_(static_cast<A&&>(init_args)...)
{
}
/// Initiate the asynchronous operation using the supplied completion token.
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
};
/// Encapsulates a deferred asynchronous operation thas has multiple completion
/// signatures.
template <typename... Signatures, typename Initiation, typename... InitArgs>
class BOOST_ASIO_NODISCARD deferred_async_operation<
deferred_signatures<Signatures...>, Initiation, InitArgs...>
{
private:
typedef decay_t<Initiation> initiation_t;
initiation_t initiation_;
typedef std::tuple<decay_t<InitArgs>...> init_args_t;
init_args_t init_args_;
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, Signatures...>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...))
{
return async_initiate<CompletionToken, Signatures...>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>) const &
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiation_t(initiation_), token, std::get<I>(init_args_)...))
{
return async_initiate<CompletionToken, Signatures...>(
initiation_t(initiation_), token, std::get<I>(init_args_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename I, typename... A>
constexpr explicit deferred_async_operation(
deferred_init_tag, I&& initiation, A&&... init_args)
: initiation_(static_cast<I&&>(initiation)),
init_args_(static_cast<A&&>(init_args)...)
{
}
/// Initiate the asynchronous operation using the supplied completion token.
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Signature, typename Initiation, typename... InitArgs>
struct is_deferred<
deferred_async_operation<Signature, Initiation, InitArgs...>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Defines a link between two consecutive operations in a sequence.
template <typename Head, typename Tail>
class BOOST_ASIO_NODISCARD deferred_sequence :
public detail::deferred_sequence_types<Head, Tail>::base
{
public:
template <typename H, typename T>
constexpr explicit deferred_sequence(deferred_init_tag, H&& head, T&& tail)
: detail::deferred_sequence_types<Head, Tail>::base(
static_cast<H&&>(head), static_cast<T&&>(tail))
{
}
#if defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken>
auto operator()(CompletionToken&& token) &&;
template <typename CompletionToken>
auto operator()(CompletionToken&& token) const &;
#endif // defined(GENERATING_DOCUMENTATION)
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Head, typename Tail>
struct is_deferred<deferred_sequence<Head, Tail>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Used to represent a deferred conditional branch.
template <typename OnTrue = deferred_noop, typename OnFalse = deferred_noop>
class BOOST_ASIO_NODISCARD deferred_conditional
{
private:
template <typename T, typename F> friend class deferred_conditional;
// Helper constructor.
template <typename T, typename F>
explicit deferred_conditional(bool b, T&& on_true, F&& on_false)
: on_true_(static_cast<T&&>(on_true)),
on_false_(static_cast<F&&>(on_false)),
bool_(b)
{
}
OnTrue on_true_;
OnFalse on_false_;
bool bool_;
public:
/// Construct a deferred conditional with the value to determine which branch
/// will be executed.
constexpr explicit deferred_conditional(bool b)
: on_true_(),
on_false_(),
bool_(b)
{
}
/// Invoke the conditional branch bsaed on the stored value.
template <typename... Args>
auto operator()(Args&&... args) &&
-> decltype(static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...))
{
if (bool_)
{
return static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...);
}
else
{
return static_cast<OnFalse&&>(on_false_)(static_cast<Args&&>(args)...);
}
}
template <typename... Args>
auto operator()(Args&&... args) const &
-> decltype(on_true_(static_cast<Args&&>(args)...))
{
if (bool_)
{
return on_true_(static_cast<Args&&>(args)...);
}
else
{
return on_false_(static_cast<Args&&>(args)...);
}
}
/// Set the true branch of the conditional.
template <typename T>
deferred_conditional<T, OnFalse> then(T on_true,
constraint_t<
is_deferred<T>::value
>* = 0,
constraint_t<
is_same<
conditional_t<true, OnTrue, T>,
deferred_noop
>::value
>* = 0) &&
{
return deferred_conditional<T, OnFalse>(
bool_, static_cast<T&&>(on_true),
static_cast<OnFalse&&>(on_false_));
}
/// Set the false branch of the conditional.
template <typename T>
deferred_conditional<OnTrue, T> otherwise(T on_false,
constraint_t<
is_deferred<T>::value
>* = 0,
constraint_t<
!is_same<
conditional_t<true, OnTrue, T>,
deferred_noop
>::value
>* = 0,
constraint_t<
is_same<
conditional_t<true, OnFalse, T>,
deferred_noop
>::value
>* = 0) &&
{
return deferred_conditional<OnTrue, T>(
bool_, static_cast<OnTrue&&>(on_true_),
static_cast<T&&>(on_false));
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename OnTrue, typename OnFalse>
struct is_deferred<deferred_conditional<OnTrue, OnFalse>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Class used to specify that an asynchronous operation should return a
/// function object to lazily launch the operation.
/**
* The deferred_t class is used to indicate that an asynchronous operation
* should return a function object which is itself an initiation function. A
* deferred_t object may be passed as a completion token to an asynchronous
* operation, typically as the default completion token:
*
* @code auto my_deferred_op = my_socket.async_read_some(my_buffer); @endcode
*
* or by explicitly passing the special value @c boost::asio::deferred:
*
* @code auto my_deferred_op
* = my_socket.async_read_some(my_buffer,
* boost::asio::deferred); @endcode
*
* The initiating function (async_read_some in the above example) returns a
* function object that will lazily initiate the operation.
*/
class deferred_t
{
public:
/// Default constructor.
constexpr deferred_t()
{
}
/// Adapts an executor to add the @c deferred_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c deferred_t as the default completion token type.
typedef deferred_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
template <typename InnerExecutor1>
executor_with_default(const InnerExecutor1& ex,
constraint_t<
conditional_t<
!is_same<InnerExecutor1, executor_with_default>::value,
is_convertible<InnerExecutor1, InnerExecutor>,
false_type
>::value
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c deferred_t as its
/// default completion token type.
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type>>::other;
/// Function helper to adapt an I/O object to use @c deferred_t as its
/// default completion token type.
template <typename T>
static typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other
as_default_on(T&& object)
{
return typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other(static_cast<T&&>(object));
}
/// Creates a new deferred from a function.
template <typename Function>
constraint_t<
!is_deferred<decay_t<Function>>::value,
deferred_function<decay_t<Function>>
> operator()(Function&& function) const
{
return deferred_function<decay_t<Function>>(
deferred_init_tag{}, static_cast<Function&&>(function));
}
/// Passes through anything that is already deferred.
template <typename T>
constraint_t<
is_deferred<decay_t<T>>::value,
decay_t<T>
> operator()(T&& t) const
{
return static_cast<T&&>(t);
}
/// Returns a deferred operation that returns the provided values.
template <typename... Args>
static constexpr deferred_values<decay_t<Args>...> values(Args&&... args)
{
return deferred_values<decay_t<Args>...>(
deferred_init_tag{}, static_cast<Args&&>(args)...);
}
/// Creates a conditional object for branching deferred operations.
static constexpr deferred_conditional<> when(bool b)
{
return deferred_conditional<>(b);
}
};
/// Pipe operator used to chain deferred operations.
template <typename Head, typename Tail>
inline auto operator|(Head head, Tail&& tail)
-> constraint_t<
is_deferred<Head>::value,
decltype(static_cast<Head&&>(head)(static_cast<Tail&&>(tail)))
>
{
return static_cast<Head&&>(head)(static_cast<Tail&&>(tail));
}
/// A @ref completion_token object used to specify that an asynchronous
/// operation should return a function object to lazily launch the operation.
/**
* See the documentation for boost::asio::deferred_t for a usage example.
*/
BOOST_ASIO_INLINE_VARIABLE constexpr deferred_t deferred;
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/deferred.hpp>
#endif // BOOST_ASIO_DEFERRED_HPP