1//
2// defer.hpp
3// ~~~~~~~~~
4//
5// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DEFER_HPP
12#define BOOST_ASIO_DEFER_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <boost/asio/async_result.hpp>
20#include <boost/asio/detail/initiate_defer.hpp>
21#include <boost/asio/detail/type_traits.hpp>
22#include <boost/asio/execution_context.hpp>
23#include <boost/asio/execution/blocking.hpp>
24#include <boost/asio/execution/executor.hpp>
25#include <boost/asio/is_executor.hpp>
26#include <boost/asio/require.hpp>
27
28#include <boost/asio/detail/push_options.hpp>
29
30namespace boost {
31namespace asio {
32
33/// Submits a completion token or function object for execution.
34/**
35 * This function submits an object for execution using the object's associated
36 * executor. The function object is queued for execution, and is never called
37 * from the current thread prior to returning from <tt>defer()</tt>.
38 *
39 * The use of @c defer(), rather than @ref post(), indicates the caller's
40 * preference that the executor defer the queueing of the function object. This
41 * may allow the executor to optimise queueing for cases when the function
42 * object represents a continuation of the current call context.
43 *
44 * @param token The @ref completion_token that will be used to produce a
45 * completion handler. The function signature of the completion handler must be:
46 * @code void handler(); @endcode
47 *
48 * @returns This function returns <tt>async_initiate<NullaryToken,
49 * void()>(Init{}, token)</tt>, where @c Init is a function object type defined
50 * as:
51 *
52 * @code class Init
53 * {
54 * public:
55 * template <typename CompletionHandler>
56 * void operator()(CompletionHandler&& completion_handler) const;
57 * }; @endcode
58 *
59 * The function call operator of @c Init:
60 *
61 * @li Obtains the handler's associated executor object @c ex of type @c Ex by
62 * performing @code auto ex = get_associated_executor(handler); @endcode
63 *
64 * @li Obtains the handler's associated allocator object @c alloc by performing
65 * @code auto alloc = get_associated_allocator(handler); @endcode
66 *
67 * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
68 * @code prefer(
69 * require(ex, execution::blocking.never),
70 * execution::relationship.continuation,
71 * execution::allocator(alloc)
72 * ).execute(std::forward<CompletionHandler>(completion_handler)); @endcode
73 *
74 * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
75 * @code ex.defer(
76 * std::forward<CompletionHandler>(completion_handler),
77 * alloc); @endcode
78 *
79 * @par Completion Signature
80 * @code void() @endcode
81 */
82template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken>
83auto defer(NullaryToken&& token)
84 -> decltype(
85 async_initiate<NullaryToken, void()>(
86 declval<detail::initiate_defer>(), token))
87{
88 return async_initiate<NullaryToken, void()>(
89 detail::initiate_defer(), token);
90}
91
92/// Submits a completion token or function object for execution.
93/**
94 * This function submits an object for execution using the specified executor.
95 * The function object is queued for execution, and is never called from the
96 * current thread prior to returning from <tt>defer()</tt>.
97 *
98 * The use of @c defer(), rather than @ref post(), indicates the caller's
99 * preference that the executor defer the queueing of the function object. This
100 * may allow the executor to optimise queueing for cases when the function
101 * object represents a continuation of the current call context.
102 *
103 * @param ex The target executor.
104 *
105 * @param token The @ref completion_token that will be used to produce a
106 * completion handler. The function signature of the completion handler must be:
107 * @code void handler(); @endcode
108 *
109 * @returns This function returns <tt>async_initiate<NullaryToken,
110 * void()>(Init{ex}, token)</tt>, where @c Init is a function object type
111 * defined as:
112 *
113 * @code class Init
114 * {
115 * public:
116 * using executor_type = Executor;
117 * explicit Init(const Executor& ex) : ex_(ex) {}
118 * executor_type get_executor() const noexcept { return ex_; }
119 * template <typename CompletionHandler>
120 * void operator()(CompletionHandler&& completion_handler) const;
121 * private:
122 * Executor ex_; // exposition only
123 * }; @endcode
124 *
125 * The function call operator of @c Init:
126 *
127 * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
128 * performing @code auto ex1 = get_associated_executor(handler, ex); @endcode
129 *
130 * @li Obtains the handler's associated allocator object @c alloc by performing
131 * @code auto alloc = get_associated_allocator(handler); @endcode
132 *
133 * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a
134 * function object @c f with a member @c executor_ that is initialised with
135 * <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c
136 * handler_ that is a decay-copy of @c completion_handler, and a function call
137 * operator that performs:
138 * @code auto a = get_associated_allocator(handler_);
139 * prefer(executor_, execution::allocator(a)).execute(std::move(handler_));
140 * @endcode
141 *
142 * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a
143 * function object @c f with a member @c work_ that is initialised with
144 * <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of
145 * @c completion_handler, and a function call operator that performs:
146 * @code auto a = get_associated_allocator(handler_);
147 * work_.get_executor().dispatch(std::move(handler_), a);
148 * work_.reset(); @endcode
149 *
150 * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
151 * @code prefer(
152 * require(ex, execution::blocking.never),
153 * execution::relationship.continuation,
154 * execution::allocator(alloc)
155 * ).execute(std::move(f)); @endcode
156 *
157 * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
158 * @code ex.defer(std::move(f), alloc); @endcode
159 *
160 * @par Completion Signature
161 * @code void() @endcode
162 */
163template <typename Executor,
164 BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
165 = default_completion_token_t<Executor>>
166auto defer(const Executor& ex,
167 NullaryToken&& token
168 = default_completion_token_t<Executor>(),
169 constraint_t<
170 (execution::is_executor<Executor>::value
171 && can_require<Executor, execution::blocking_t::never_t>::value)
172 || is_executor<Executor>::value
173 > = 0)
174 -> decltype(
175 async_initiate<NullaryToken, void()>(
176 declval<detail::initiate_defer_with_executor<Executor>>(), token))
177{
178 return async_initiate<NullaryToken, void()>(
179 detail::initiate_defer_with_executor<Executor>(ex), token);
180}
181
182/// Submits a completion token or function object for execution.
183/**
184 * @param ctx An execution context, from which the target executor is obtained.
185 *
186 * @param token The @ref completion_token that will be used to produce a
187 * completion handler. The function signature of the completion handler must be:
188 * @code void handler(); @endcode
189 *
190 * @returns <tt>defer(ctx.get_executor(), forward<NullaryToken>(token))</tt>.
191 *
192 * @par Completion Signature
193 * @code void() @endcode
194 */
195template <typename ExecutionContext,
196 BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
197 = default_completion_token_t<typename ExecutionContext::executor_type>>
198auto defer(ExecutionContext& ctx,
199 NullaryToken&& token
200 = default_completion_token_t<typename ExecutionContext::executor_type>(),
201 constraint_t<
202 is_convertible<ExecutionContext&, execution_context&>::value
203 > = 0)
204 -> decltype(
205 async_initiate<NullaryToken, void()>(
206 declval<detail::initiate_defer_with_executor<
207 typename ExecutionContext::executor_type>>(), token))
208{
209 return async_initiate<NullaryToken, void()>(
210 detail::initiate_defer_with_executor<
211 typename ExecutionContext::executor_type>(
212 ctx.get_executor()), token);
213}
214
215} // namespace asio
216} // namespace boost
217
218#include <boost/asio/detail/pop_options.hpp>
219
220#endif // BOOST_ASIO_DEFER_HPP
221

source code of boost/libs/asio/include/boost/asio/defer.hpp