관리-도구
편집 파일: 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>( 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 <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 using the special value @c boost::asio::deferred. For * example: * * @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. */ 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