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 | |
30 | namespace boost { |
31 | namespace 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 | */ |
82 | template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken> |
83 | auto 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 | */ |
163 | template <typename Executor, |
164 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken |
165 | = default_completion_token_t<Executor>> |
166 | auto 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 | */ |
195 | template <typename ExecutionContext, |
196 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken |
197 | = default_completion_token_t<typename ExecutionContext::executor_type>> |
198 | auto 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 | |