1 //
2 // impl/defer.hpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 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_IMPL_DEFER_HPP
12 #define BOOST_ASIO_IMPL_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/associated_allocator.hpp>
20 #include <boost/asio/associated_executor.hpp>
21 #include <boost/asio/detail/work_dispatcher.hpp>
22 #include <boost/asio/execution/allocator.hpp>
23 #include <boost/asio/execution/blocking.hpp>
24 #include <boost/asio/execution/relationship.hpp>
25 #include <boost/asio/prefer.hpp>
26 #include <boost/asio/require.hpp>
27
28 #include <boost/asio/detail/push_options.hpp>
29
30 namespace boost {
31 namespace asio {
32 namespace detail {
33
34 class initiate_defer
35 {
36 public:
37 template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<execution::is_executor<typename associated_executor<typename decay<CompletionHandler>::type>::type>::value>::type * =0) const38 void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
39 typename enable_if<
40 execution::is_executor<
41 typename associated_executor<
42 typename decay<CompletionHandler>::type
43 >::type
44 >::value
45 >::type* = 0) const
46 {
47 typedef typename decay<CompletionHandler>::type handler_t;
48
49 typename associated_executor<handler_t>::type ex(
50 (get_associated_executor)(handler));
51
52 typename associated_allocator<handler_t>::type alloc(
53 (get_associated_allocator)(handler));
54
55 execution::execute(
56 boost::asio::prefer(
57 boost::asio::require(ex, execution::blocking.never),
58 execution::relationship.continuation,
59 execution::allocator(alloc)),
60 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler));
61 }
62
63 template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<!execution::is_executor<typename associated_executor<typename decay<CompletionHandler>::type>::type>::value>::type * =0) const64 void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
65 typename enable_if<
66 !execution::is_executor<
67 typename associated_executor<
68 typename decay<CompletionHandler>::type
69 >::type
70 >::value
71 >::type* = 0) const
72 {
73 typedef typename decay<CompletionHandler>::type handler_t;
74
75 typename associated_executor<handler_t>::type ex(
76 (get_associated_executor)(handler));
77
78 typename associated_allocator<handler_t>::type alloc(
79 (get_associated_allocator)(handler));
80
81 ex.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
82 }
83 };
84
85 template <typename Executor>
86 class initiate_defer_with_executor
87 {
88 public:
89 typedef Executor executor_type;
90
initiate_defer_with_executor(const Executor & ex)91 explicit initiate_defer_with_executor(const Executor& ex)
92 : ex_(ex)
93 {
94 }
95
get_executor() const96 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
97 {
98 return ex_;
99 }
100
101 template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value &&!detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const102 void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
103 typename enable_if<
104 execution::is_executor<
105 typename conditional<true, executor_type, CompletionHandler>::type
106 >::value
107 &&
108 !detail::is_work_dispatcher_required<
109 typename decay<CompletionHandler>::type,
110 Executor
111 >::value
112 >::type* = 0) const
113 {
114 typedef typename decay<CompletionHandler>::type handler_t;
115
116 typename associated_allocator<handler_t>::type alloc(
117 (get_associated_allocator)(handler));
118
119 execution::execute(
120 boost::asio::prefer(
121 boost::asio::require(ex_, execution::blocking.never),
122 execution::relationship.continuation,
123 execution::allocator(alloc)),
124 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler));
125 }
126
127 template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value && detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const128 void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
129 typename enable_if<
130 execution::is_executor<
131 typename conditional<true, executor_type, CompletionHandler>::type
132 >::value
133 &&
134 detail::is_work_dispatcher_required<
135 typename decay<CompletionHandler>::type,
136 Executor
137 >::value
138 >::type* = 0) const
139 {
140 typedef typename decay<CompletionHandler>::type handler_t;
141
142 typedef typename associated_executor<
143 handler_t, Executor>::type handler_ex_t;
144 handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
145
146 typename associated_allocator<handler_t>::type alloc(
147 (get_associated_allocator)(handler));
148
149 execution::execute(
150 boost::asio::prefer(
151 boost::asio::require(ex_, execution::blocking.never),
152 execution::relationship.continuation,
153 execution::allocator(alloc)),
154 detail::work_dispatcher<handler_t, handler_ex_t>(
155 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));
156 }
157
158 template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<!execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value &&!detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const159 void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
160 typename enable_if<
161 !execution::is_executor<
162 typename conditional<true, executor_type, CompletionHandler>::type
163 >::value
164 &&
165 !detail::is_work_dispatcher_required<
166 typename decay<CompletionHandler>::type,
167 Executor
168 >::value
169 >::type* = 0) const
170 {
171 typedef typename decay<CompletionHandler>::type handler_t;
172
173 typename associated_allocator<handler_t>::type alloc(
174 (get_associated_allocator)(handler));
175
176 ex_.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
177 }
178
179 template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<!execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value && detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const180 void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
181 typename enable_if<
182 !execution::is_executor<
183 typename conditional<true, executor_type, CompletionHandler>::type
184 >::value
185 &&
186 detail::is_work_dispatcher_required<
187 typename decay<CompletionHandler>::type,
188 Executor
189 >::value
190 >::type* = 0) const
191 {
192 typedef typename decay<CompletionHandler>::type handler_t;
193
194 typedef typename associated_executor<
195 handler_t, Executor>::type handler_ex_t;
196 handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
197
198 typename associated_allocator<handler_t>::type alloc(
199 (get_associated_allocator)(handler));
200
201 ex_.defer(detail::work_dispatcher<handler_t, handler_ex_t>(
202 BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler),
203 handler_ex), alloc);
204 }
205
206 private:
207 Executor ex_;
208 };
209
210 } // namespace detail
211
212 template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,void ())213 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
214 BOOST_ASIO_MOVE_ARG(CompletionToken) token)
215 {
216 return async_initiate<CompletionToken, void()>(
217 detail::initiate_defer(), token);
218 }
219
220 template <typename Executor,
221 BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,void ())222 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
223 const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token,
224 typename enable_if<
225 execution::is_executor<Executor>::value || is_executor<Executor>::value
226 >::type*)
227 {
228 return async_initiate<CompletionToken, void()>(
229 detail::initiate_defer_with_executor<Executor>(ex), token);
230 }
231
232 template <typename ExecutionContext,
233 BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,void ())234 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
235 ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token,
236 typename enable_if<is_convertible<
237 ExecutionContext&, execution_context&>::value>::type*)
238 {
239 return async_initiate<CompletionToken, void()>(
240 detail::initiate_defer_with_executor<
241 typename ExecutionContext::executor_type>(
242 ctx.get_executor()), token);
243 }
244
245 } // namespace asio
246 } // namespace boost
247
248 #include <boost/asio/detail/pop_options.hpp>
249
250 #endif // BOOST_ASIO_IMPL_DEFER_HPP
251