// // defer.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_DEFER_HPP #define ASIO_DEFER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/async_result.hpp" #include "asio/detail/initiate_defer.hpp" #include "asio/detail/type_traits.hpp" #include "asio/execution_context.hpp" #include "asio/execution/blocking.hpp" #include "asio/execution/executor.hpp" #include "asio/is_executor.hpp" #include "asio/require.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Submits a completion token or function object for execution. /** * This function submits an object for execution using the object's associated * executor. The function object is queued for execution, and is never called * from the current thread prior to returning from defer(). * * The use of @c defer(), rather than @ref post(), indicates the caller's * preference that the executor defer the queueing of the function object. This * may allow the executor to optimise queueing for cases when the function * object represents a continuation of the current call context. * * @param token The @ref completion_token that will be used to produce a * completion handler. The function signature of the completion handler must be: * @code void handler(); @endcode * * @returns This function returns async_initiate(Init{}, token), where @c Init is a function object type defined * as: * * @code class Init * { * public: * template * void operator()(CompletionHandler&& completion_handler) const; * }; @endcode * * The function call operator of @c Init: * * @li Obtains the handler's associated executor object @c ex of type @c Ex by * performing @code auto ex = get_associated_executor(handler); @endcode * * @li Obtains the handler's associated allocator object @c alloc by performing * @code auto alloc = get_associated_allocator(handler); @endcode * * @li If execution::is_executor::value is true, performs * @code prefer( * require(ex, execution::blocking.never), * execution::relationship.continuation, * execution::allocator(alloc) * ).execute(std::forward(completion_handler)); @endcode * * @li If execution::is_executor::value is false, performs * @code ex.defer( * std::forward(completion_handler), * alloc); @endcode * * @par Completion Signature * @code void() @endcode */ template auto defer(NullaryToken&& token) -> decltype( async_initiate( declval(), token)) { return async_initiate( detail::initiate_defer(), token); } /// Submits a completion token or function object for execution. /** * This function submits an object for execution using the specified executor. * The function object is queued for execution, and is never called from the * current thread prior to returning from defer(). * * The use of @c defer(), rather than @ref post(), indicates the caller's * preference that the executor defer the queueing of the function object. This * may allow the executor to optimise queueing for cases when the function * object represents a continuation of the current call context. * * @param ex The target executor. * * @param token The @ref completion_token that will be used to produce a * completion handler. The function signature of the completion handler must be: * @code void handler(); @endcode * * @returns This function returns async_initiate(Init{ex}, token), where @c Init is a function object type * defined as: * * @code class Init * { * public: * using executor_type = Executor; * explicit Init(const Executor& ex) : ex_(ex) {} * executor_type get_executor() const noexcept { return ex_; } * template * void operator()(CompletionHandler&& completion_handler) const; * private: * Executor ex_; // exposition only * }; @endcode * * The function call operator of @c Init: * * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by * performing @code auto ex1 = get_associated_executor(handler, ex); @endcode * * @li Obtains the handler's associated allocator object @c alloc by performing * @code auto alloc = get_associated_allocator(handler); @endcode * * @li If execution::is_executor::value is true, constructs a * function object @c f with a member @c executor_ that is initialised with * prefer(ex1, execution::outstanding_work.tracked), a member @c * handler_ that is a decay-copy of @c completion_handler, and a function call * operator that performs: * @code auto a = get_associated_allocator(handler_); * prefer(executor_, execution::allocator(a)).execute(std::move(handler_)); * @endcode * * @li If execution::is_executor::value is false, constructs a * function object @c f with a member @c work_ that is initialised with * make_work_guard(ex1), a member @c handler_ that is a decay-copy of * @c completion_handler, and a function call operator that performs: * @code auto a = get_associated_allocator(handler_); * work_.get_executor().dispatch(std::move(handler_), a); * work_.reset(); @endcode * * @li If execution::is_executor::value is true, performs * @code prefer( * require(ex, execution::blocking.never), * execution::relationship.continuation, * execution::allocator(alloc) * ).execute(std::move(f)); @endcode * * @li If execution::is_executor::value is false, performs * @code ex.defer(std::move(f), alloc); @endcode * * @par Completion Signature * @code void() @endcode */ template > auto defer(const Executor& ex, NullaryToken&& token = default_completion_token_t(), constraint_t< (execution::is_executor::value && can_require::value) || is_executor::value > = 0) -> decltype( async_initiate( declval>(), token)) { return async_initiate( detail::initiate_defer_with_executor(ex), token); } /// Submits a completion token or function object for execution. /** * @param ctx An execution context, from which the target executor is obtained. * * @param token The @ref completion_token that will be used to produce a * completion handler. The function signature of the completion handler must be: * @code void handler(); @endcode * * @returns defer(ctx.get_executor(), forward(token)). * * @par Completion Signature * @code void() @endcode */ template > auto defer(ExecutionContext& ctx, NullaryToken&& token = default_completion_token_t(), constraint_t< is_convertible::value > = 0) -> decltype( async_initiate( declval>(), token)) { return async_initiate( detail::initiate_defer_with_executor< typename ExecutionContext::executor_type>( ctx.get_executor()), token); } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DEFER_HPP