716 lines
21 KiB
C++
716 lines
21 KiB
C++
|
//
|
||
|
// 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 ASIO_DEFERRED_HPP
|
||
|
#define ASIO_DEFERRED_HPP
|
||
|
|
||
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||
|
# pragma once
|
||
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||
|
|
||
|
#include "asio/detail/config.hpp"
|
||
|
#include <tuple>
|
||
|
#include "asio/associator.hpp"
|
||
|
#include "asio/async_result.hpp"
|
||
|
#include "asio/detail/type_traits.hpp"
|
||
|
#include "asio/detail/utility.hpp"
|
||
|
|
||
|
#include "asio/detail/push_options.hpp"
|
||
|
|
||
|
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 <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 <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 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 <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 <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 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>(
|
||
|
initiation_t(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 <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 <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 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 <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 <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 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 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 using the special value @c asio::deferred. For
|
||
|
* example:
|
||
|
*
|
||
|
* @code auto my_deferred_op
|
||
|
* = my_socket.async_read_some(my_buffer,
|
||
|
* 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 asio::deferred_t for a usage example.
|
||
|
*/
|
||
|
constexpr deferred_t deferred;
|
||
|
|
||
|
} // namespace asio
|
||
|
|
||
|
#include "asio/detail/pop_options.hpp"
|
||
|
|
||
|
#include "asio/impl/deferred.hpp"
|
||
|
|
||
|
#endif // ASIO_DEFERRED_HPP
|