]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // |
2 | // experimental/deferred.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
5 | // Copyright (c) 2003-2022 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_EXPERIMENTAL_DEFERRED_HPP | |
12 | #define BOOST_ASIO_EXPERIMENTAL_DEFERRED_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 <tuple> | |
20 | #include <boost/asio/associator.hpp> | |
21 | #include <boost/asio/async_result.hpp> | |
22 | #include <boost/asio/detail/type_traits.hpp> | |
23 | ||
24 | #include <boost/asio/detail/push_options.hpp> | |
25 | ||
26 | namespace boost { | |
27 | namespace asio { | |
28 | namespace experimental { | |
29 | ||
30 | /// Trait for detecting objects that are usable as deferred operations. | |
31 | template <typename T> | |
32 | struct is_deferred : false_type | |
33 | { | |
34 | }; | |
35 | ||
36 | namespace detail { | |
37 | ||
38 | // Helper trait for getting the completion signature from an async operation. | |
39 | ||
40 | struct deferred_signature_probe {}; | |
41 | ||
42 | template <typename T> | |
43 | struct deferred_signature_probe_result | |
44 | { | |
45 | typedef T type; | |
46 | }; | |
47 | ||
48 | template <typename T> | |
49 | struct deferred_signature | |
50 | { | |
51 | typedef typename decltype( | |
52 | declval<T>()(declval<deferred_signature_probe>()))::type type; | |
53 | }; | |
54 | ||
55 | // Helper trait for getting the completion signature of the tail in a sequence | |
56 | // when invoked with the specified arguments. | |
57 | ||
58 | template <typename HeadSignature, typename Tail> | |
59 | struct deferred_sequence_signature; | |
60 | ||
61 | template <typename R, typename... Args, typename Tail> | |
62 | struct deferred_sequence_signature<R(Args...), Tail> | |
63 | { | |
64 | static_assert( | |
65 | !is_same<decltype(declval<Tail>()(declval<Args>()...)), void>::value, | |
66 | "deferred functions must produce a deferred return type"); | |
67 | ||
68 | typedef typename decltype( | |
69 | declval<Tail>()(declval<Args>()...)( | |
70 | declval<deferred_signature_probe>()))::type type; | |
71 | }; | |
72 | ||
73 | // Completion handler for the head component of a deferred sequence. | |
74 | template <typename Handler, typename Tail> | |
75 | class deferred_sequence_handler | |
76 | { | |
77 | public: | |
78 | template <typename H, typename T> | |
79 | explicit deferred_sequence_handler( | |
80 | BOOST_ASIO_MOVE_ARG(H) handler, BOOST_ASIO_MOVE_ARG(T) tail) | |
81 | : handler_(BOOST_ASIO_MOVE_CAST(H)(handler)), | |
82 | tail_(BOOST_ASIO_MOVE_CAST(T)(tail)) | |
83 | { | |
84 | } | |
85 | ||
86 | template <typename... Args> | |
87 | void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) | |
88 | { | |
89 | BOOST_ASIO_MOVE_OR_LVALUE(Tail)(tail_)( | |
90 | BOOST_ASIO_MOVE_CAST(Args)(args)...)( | |
91 | BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)); | |
92 | } | |
93 | ||
94 | //private: | |
95 | Handler handler_; | |
96 | Tail tail_; | |
97 | }; | |
98 | ||
99 | } // namespace detail | |
100 | ||
101 | /// Used to represent an empty deferred action. | |
102 | struct deferred_noop | |
103 | { | |
104 | /// No effect. | |
105 | template <typename... Args> | |
106 | void operator()(BOOST_ASIO_MOVE_ARG(Args)...) BOOST_ASIO_RVALUE_REF_QUAL | |
107 | { | |
108 | } | |
109 | ||
110 | #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
111 | /// No effect. | |
112 | template <typename... Args> | |
113 | decltype(auto) operator()(BOOST_ASIO_MOVE_ARG(Args)...) const & | |
114 | { | |
115 | } | |
116 | #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
117 | }; | |
118 | ||
119 | #if !defined(GENERATING_DOCUMENTATION) | |
120 | template <> | |
121 | struct is_deferred<deferred_noop> : true_type | |
122 | { | |
123 | }; | |
124 | #endif // !defined(GENERATING_DOCUMENTATION) | |
125 | ||
126 | /// Tag type to disambiguate deferred constructors. | |
127 | struct deferred_init_tag {}; | |
128 | ||
129 | /// Wraps a function object so that it may be used as an element in a deferred | |
130 | /// composition. | |
131 | template <typename Function> | |
132 | class deferred_function | |
133 | { | |
134 | public: | |
135 | /// Constructor. | |
136 | template <typename F> | |
137 | BOOST_ASIO_CONSTEXPR explicit deferred_function( | |
138 | deferred_init_tag, BOOST_ASIO_MOVE_ARG(F) function) | |
139 | : function_(BOOST_ASIO_MOVE_CAST(F)(function)) | |
140 | { | |
141 | } | |
142 | ||
143 | template <typename... Args> | |
144 | decltype(auto) operator()( | |
145 | BOOST_ASIO_MOVE_ARG(Args)... args) BOOST_ASIO_RVALUE_REF_QUAL | |
146 | { | |
147 | return BOOST_ASIO_MOVE_CAST(Function)(function_)( | |
148 | BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
149 | } | |
150 | ||
151 | #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
152 | template <typename... Args> | |
153 | decltype(auto) operator()( | |
154 | BOOST_ASIO_MOVE_ARG(Args)... args) const & | |
155 | { | |
156 | return deferred_function(*this)( | |
157 | BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
158 | } | |
159 | #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
160 | ||
161 | //private: | |
162 | Function function_; | |
163 | }; | |
164 | ||
165 | #if !defined(GENERATING_DOCUMENTATION) | |
166 | template <typename Function> | |
167 | struct is_deferred<deferred_function<Function> > : true_type | |
168 | { | |
169 | }; | |
170 | #endif // !defined(GENERATING_DOCUMENTATION) | |
171 | ||
172 | /// Encapsulates deferred values. | |
173 | template <typename... Values> | |
174 | class BOOST_ASIO_NODISCARD deferred_values | |
175 | { | |
176 | private: | |
177 | std::tuple<Values...> values_; | |
178 | ||
179 | struct initiate | |
180 | { | |
181 | template <typename Handler, typename... V> | |
182 | void operator()(Handler handler, BOOST_ASIO_MOVE_ARG(V)... values) | |
183 | { | |
184 | BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler)( | |
185 | BOOST_ASIO_MOVE_CAST(V)(values)...); | |
186 | } | |
187 | }; | |
188 | ||
189 | template <typename CompletionToken, std::size_t... I> | |
190 | decltype(auto) invoke_helper( | |
191 | BOOST_ASIO_MOVE_ARG(CompletionToken) token, | |
192 | std::index_sequence<I...>) | |
193 | { | |
194 | return boost::asio::async_initiate<CompletionToken, void(Values...)>( | |
195 | initiate(), token, | |
196 | std::get<I>(BOOST_ASIO_MOVE_CAST(std::tuple<Values...>)(values_))...); | |
197 | } | |
198 | ||
199 | public: | |
200 | /// Construct a deferred asynchronous operation from the arguments to an | |
201 | /// initiation function object. | |
202 | template <typename... V> | |
203 | BOOST_ASIO_CONSTEXPR explicit deferred_values( | |
204 | deferred_init_tag, BOOST_ASIO_MOVE_ARG(V)... values) | |
205 | : values_(BOOST_ASIO_MOVE_CAST(V)(values)...) | |
206 | { | |
207 | } | |
208 | ||
209 | /// Initiate the deferred operation using the supplied completion token. | |
210 | template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken> | |
211 | decltype(auto) operator()( | |
212 | BOOST_ASIO_MOVE_ARG(CompletionToken) token) BOOST_ASIO_RVALUE_REF_QUAL | |
213 | { | |
214 | return this->invoke_helper( | |
215 | BOOST_ASIO_MOVE_CAST(CompletionToken)(token), | |
216 | std::index_sequence_for<Values...>()); | |
217 | } | |
218 | ||
219 | #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
220 | template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken> | |
221 | decltype(auto) operator()( | |
222 | BOOST_ASIO_MOVE_ARG(CompletionToken) token) const & | |
223 | { | |
224 | return deferred_values(*this)( | |
225 | BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); | |
226 | } | |
227 | #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
228 | }; | |
229 | ||
230 | #if !defined(GENERATING_DOCUMENTATION) | |
231 | template <typename... Values> | |
232 | struct is_deferred<deferred_values<Values...> > : true_type | |
233 | { | |
234 | }; | |
235 | #endif // !defined(GENERATING_DOCUMENTATION) | |
236 | ||
237 | /// Encapsulates a deferred asynchronous operation. | |
238 | template <typename Signature, typename Initiation, typename... InitArgs> | |
239 | class BOOST_ASIO_NODISCARD deferred_async_operation | |
240 | { | |
241 | private: | |
242 | typename decay<Initiation>::type initiation_; | |
243 | typedef std::tuple<typename decay<InitArgs>::type...> init_args_t; | |
244 | init_args_t init_args_; | |
245 | ||
246 | template <typename CompletionToken, std::size_t... I> | |
247 | decltype(auto) invoke_helper( | |
248 | BOOST_ASIO_MOVE_ARG(CompletionToken) token, | |
249 | std::index_sequence<I...>) | |
250 | { | |
251 | return boost::asio::async_initiate<CompletionToken, Signature>( | |
252 | BOOST_ASIO_MOVE_CAST(typename decay<Initiation>::type)(initiation_), | |
253 | token, std::get<I>(BOOST_ASIO_MOVE_CAST(init_args_t)(init_args_))...); | |
254 | } | |
255 | ||
256 | public: | |
257 | /// Construct a deferred asynchronous operation from the arguments to an | |
258 | /// initiation function object. | |
259 | template <typename I, typename... A> | |
260 | BOOST_ASIO_CONSTEXPR explicit deferred_async_operation( | |
261 | deferred_init_tag, BOOST_ASIO_MOVE_ARG(I) initiation, | |
262 | BOOST_ASIO_MOVE_ARG(A)... init_args) | |
263 | : initiation_(BOOST_ASIO_MOVE_CAST(I)(initiation)), | |
264 | init_args_(BOOST_ASIO_MOVE_CAST(A)(init_args)...) | |
265 | { | |
266 | } | |
267 | ||
268 | /// Initiate the asynchronous operation using the supplied completion token. | |
269 | template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken> | |
270 | decltype(auto) operator()( | |
271 | BOOST_ASIO_MOVE_ARG(CompletionToken) token) BOOST_ASIO_RVALUE_REF_QUAL | |
272 | { | |
273 | return this->invoke_helper( | |
274 | BOOST_ASIO_MOVE_CAST(CompletionToken)(token), | |
275 | std::index_sequence_for<InitArgs...>()); | |
276 | } | |
277 | ||
278 | #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
279 | template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken> | |
280 | decltype(auto) operator()( | |
281 | BOOST_ASIO_MOVE_ARG(CompletionToken) token) const & | |
282 | { | |
283 | return deferred_async_operation(*this)( | |
284 | BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); | |
285 | } | |
286 | #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
287 | }; | |
288 | ||
289 | #if !defined(GENERATING_DOCUMENTATION) | |
290 | template <typename Signature, typename Initiation, typename... InitArgs> | |
291 | struct is_deferred< | |
292 | deferred_async_operation<Signature, Initiation, InitArgs...> > : true_type | |
293 | { | |
294 | }; | |
295 | #endif // !defined(GENERATING_DOCUMENTATION) | |
296 | ||
297 | /// Defines a link between two consecutive operations in a sequence. | |
298 | template <typename Head, typename Tail> | |
299 | class BOOST_ASIO_NODISCARD deferred_sequence | |
300 | { | |
301 | private: | |
302 | typedef typename detail::deferred_sequence_signature< | |
303 | typename detail::deferred_signature<Head>::type, Tail>::type | |
304 | signature; | |
305 | ||
306 | public: | |
307 | template <typename H, typename T> | |
308 | BOOST_ASIO_CONSTEXPR explicit deferred_sequence(deferred_init_tag, | |
309 | BOOST_ASIO_MOVE_ARG(H) head, BOOST_ASIO_MOVE_ARG(T) tail) | |
310 | : head_(BOOST_ASIO_MOVE_CAST(H)(head)), | |
311 | tail_(BOOST_ASIO_MOVE_CAST(T)(tail)) | |
312 | { | |
313 | } | |
314 | ||
315 | template <BOOST_ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken> | |
316 | decltype(auto) operator()( | |
317 | BOOST_ASIO_MOVE_ARG(CompletionToken) token) BOOST_ASIO_RVALUE_REF_QUAL | |
318 | { | |
319 | return boost::asio::async_initiate<CompletionToken, signature>( | |
320 | initiate(), token, BOOST_ASIO_MOVE_OR_LVALUE(Head)(head_), | |
321 | BOOST_ASIO_MOVE_OR_LVALUE(Tail)(tail_)); | |
322 | } | |
323 | ||
324 | #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
325 | template <BOOST_ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken> | |
326 | decltype(auto) operator()( | |
327 | BOOST_ASIO_MOVE_ARG(CompletionToken) token) const & | |
328 | { | |
329 | return deferred_sequence(*this)( | |
330 | BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); | |
331 | } | |
332 | #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
333 | ||
334 | private: | |
335 | struct initiate | |
336 | { | |
337 | template <typename Handler> | |
338 | void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler, | |
339 | Head head, BOOST_ASIO_MOVE_ARG(Tail) tail) | |
340 | { | |
341 | BOOST_ASIO_MOVE_OR_LVALUE(Head)(head)( | |
342 | detail::deferred_sequence_handler< | |
343 | typename decay<Handler>::type, | |
344 | typename decay<Tail>::type>( | |
345 | BOOST_ASIO_MOVE_CAST(Handler)(handler), | |
346 | BOOST_ASIO_MOVE_CAST(Tail)(tail))); | |
347 | } | |
348 | }; | |
349 | ||
350 | Head head_; | |
351 | Tail tail_; | |
352 | }; | |
353 | ||
354 | #if !defined(GENERATING_DOCUMENTATION) | |
355 | template <typename Head, typename Tail> | |
356 | struct is_deferred<deferred_sequence<Head, Tail> > : true_type | |
357 | { | |
358 | }; | |
359 | #endif // !defined(GENERATING_DOCUMENTATION) | |
360 | ||
361 | /// Used to represent a deferred conditional branch. | |
362 | template <typename OnTrue = deferred_noop, | |
363 | typename OnFalse = deferred_noop> | |
364 | class BOOST_ASIO_NODISCARD deferred_conditional | |
365 | { | |
366 | public: | |
367 | /// Construct a deferred conditional with the value to determine which branch | |
368 | /// will be executed. | |
369 | BOOST_ASIO_CONSTEXPR explicit deferred_conditional(bool b) | |
370 | : on_true_(), | |
371 | on_false_(), | |
372 | bool_(b) | |
373 | { | |
374 | } | |
375 | ||
376 | /// Invoke the conditional branch bsaed on the stored alue. | |
377 | template <typename... Args> | |
378 | auto operator()(BOOST_ASIO_MOVE_ARG(Args)... args) BOOST_ASIO_RVALUE_REF_QUAL | |
379 | { | |
380 | if (bool_) | |
381 | { | |
382 | return BOOST_ASIO_MOVE_OR_LVALUE(OnTrue)(on_true_)( | |
383 | BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
384 | } | |
385 | else | |
386 | { | |
387 | return BOOST_ASIO_MOVE_OR_LVALUE(OnFalse)(on_false_)( | |
388 | BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
389 | } | |
390 | } | |
391 | ||
392 | #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
393 | template <typename... Args> | |
394 | auto operator()(BOOST_ASIO_MOVE_ARG(Args)... args) const & | |
395 | { | |
396 | return deferred_conditional(*this)( | |
397 | BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
398 | } | |
399 | #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) | |
400 | ||
401 | /// Set the true branch of the conditional. | |
402 | template <typename T> | |
403 | deferred_conditional<T, OnFalse> then(T on_true, | |
404 | typename constraint< | |
405 | is_deferred<T>::value | |
406 | >::type* = 0, | |
407 | typename constraint< | |
408 | is_same< | |
409 | typename conditional<true, OnTrue, T>::type, | |
410 | deferred_noop | |
411 | >::value | |
412 | >::type* = 0) BOOST_ASIO_RVALUE_REF_QUAL | |
413 | { | |
414 | return deferred_conditional<T, OnFalse>( | |
415 | bool_, BOOST_ASIO_MOVE_CAST(T)(on_true), | |
416 | BOOST_ASIO_MOVE_CAST(OnFalse)(on_false_)); | |
417 | } | |
418 | ||
419 | /// Set the false branch of the conditional. | |
420 | template <typename T> | |
421 | deferred_conditional<OnTrue, T> otherwise(T on_false, | |
422 | typename constraint< | |
423 | is_deferred<T>::value | |
424 | >::type* = 0, | |
425 | typename constraint< | |
426 | !is_same< | |
427 | typename conditional<true, OnTrue, T>::type, | |
428 | deferred_noop | |
429 | >::value | |
430 | >::type* = 0, | |
431 | typename constraint< | |
432 | is_same< | |
433 | typename conditional<true, OnFalse, T>::type, | |
434 | deferred_noop | |
435 | >::value | |
436 | >::type* = 0) BOOST_ASIO_RVALUE_REF_QUAL | |
437 | { | |
438 | return deferred_conditional<OnTrue, T>( | |
439 | bool_, BOOST_ASIO_MOVE_CAST(OnTrue)(on_true_), | |
440 | BOOST_ASIO_MOVE_CAST(T)(on_false)); | |
441 | } | |
442 | ||
443 | private: | |
444 | template <typename T, typename F> friend class deferred_conditional; | |
445 | ||
446 | // Helper constructor. | |
447 | template <typename T, typename F> | |
448 | explicit deferred_conditional(bool b, BOOST_ASIO_MOVE_ARG(T) on_true, | |
449 | BOOST_ASIO_MOVE_ARG(F) on_false) | |
450 | : on_true_(BOOST_ASIO_MOVE_CAST(T)(on_true)), | |
451 | on_false_(BOOST_ASIO_MOVE_CAST(F)(on_false)), | |
452 | bool_(b) | |
453 | { | |
454 | } | |
455 | ||
456 | OnTrue on_true_; | |
457 | OnFalse on_false_; | |
458 | bool bool_; | |
459 | }; | |
460 | ||
461 | #if !defined(GENERATING_DOCUMENTATION) | |
462 | template <typename OnTrue, typename OnFalse> | |
463 | struct is_deferred<deferred_conditional<OnTrue, OnFalse> > : true_type | |
464 | { | |
465 | }; | |
466 | #endif // !defined(GENERATING_DOCUMENTATION) | |
467 | ||
468 | /// Class used to specify that an asynchronous operation should return a | |
469 | /// function object to lazily launch the operation. | |
470 | /** | |
471 | * The deferred_t class is used to indicate that an asynchronous operation | |
472 | * should return a function object which is itself an initiation function. A | |
473 | * deferred_t object may be passed as a completion token to an asynchronous | |
474 | * operation, typically using the special value @c boost::asio::deferred. For | |
475 | * example: | |
476 | * | |
477 | * @code auto my_deferred_op | |
478 | * = my_socket.async_read_some(my_buffer, | |
479 | * boost::asio::experimental::deferred); @endcode | |
480 | * | |
481 | * The initiating function (async_read_some in the above example) returns a | |
482 | * function object that will lazily initiate the operation. | |
483 | */ | |
484 | class deferred_t | |
485 | { | |
486 | public: | |
487 | /// Default constructor. | |
488 | BOOST_ASIO_CONSTEXPR deferred_t() | |
489 | { | |
490 | } | |
491 | ||
492 | /// Adapts an executor to add the @c deferred_t completion token as the | |
493 | /// default. | |
494 | template <typename InnerExecutor> | |
495 | struct executor_with_default : InnerExecutor | |
496 | { | |
497 | /// Specify @c deferred_t as the default completion token type. | |
498 | typedef deferred_t default_completion_token_type; | |
499 | ||
500 | /// Construct the adapted executor from the inner executor type. | |
501 | template <typename InnerExecutor1> | |
502 | executor_with_default(const InnerExecutor1& ex, | |
503 | typename constraint< | |
504 | conditional< | |
505 | !is_same<InnerExecutor1, executor_with_default>::value, | |
506 | is_convertible<InnerExecutor1, InnerExecutor>, | |
507 | false_type | |
508 | >::type::value | |
509 | >::type = 0) BOOST_ASIO_NOEXCEPT | |
510 | : InnerExecutor(ex) | |
511 | { | |
512 | } | |
513 | }; | |
514 | ||
515 | /// Type alias to adapt an I/O object to use @c deferred_t as its | |
516 | /// default completion token type. | |
517 | #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \ | |
518 | || defined(GENERATING_DOCUMENTATION) | |
519 | template <typename T> | |
520 | using as_default_on_t = typename T::template rebind_executor< | |
521 | executor_with_default<typename T::executor_type> >::other; | |
522 | #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) | |
523 | // || defined(GENERATING_DOCUMENTATION) | |
524 | ||
525 | /// Function helper to adapt an I/O object to use @c deferred_t as its | |
526 | /// default completion token type. | |
527 | template <typename T> | |
528 | static typename decay<T>::type::template rebind_executor< | |
529 | executor_with_default<typename decay<T>::type::executor_type> | |
530 | >::other | |
531 | as_default_on(BOOST_ASIO_MOVE_ARG(T) object) | |
532 | { | |
533 | return typename decay<T>::type::template rebind_executor< | |
534 | executor_with_default<typename decay<T>::type::executor_type> | |
535 | >::other(BOOST_ASIO_MOVE_CAST(T)(object)); | |
536 | } | |
537 | ||
538 | /// Creates a new deferred from a function. | |
539 | template <typename Function> | |
540 | typename constraint< | |
541 | !is_deferred<typename decay<Function>::type>::value, | |
542 | deferred_function<typename decay<Function>::type> | |
543 | >::type operator()(BOOST_ASIO_MOVE_ARG(Function) function) const | |
544 | { | |
545 | return deferred_function<typename decay<Function>::type>( | |
546 | deferred_init_tag{}, BOOST_ASIO_MOVE_CAST(Function)(function)); | |
547 | } | |
548 | ||
549 | /// Passes through anything that is already deferred. | |
550 | template <typename T> | |
551 | typename constraint< | |
552 | is_deferred<typename decay<T>::type>::value, | |
553 | typename decay<T>::type | |
554 | >::type operator()(BOOST_ASIO_MOVE_ARG(T) t) const | |
555 | { | |
556 | return BOOST_ASIO_MOVE_CAST(T)(t); | |
557 | } | |
558 | ||
559 | /// Returns a deferred operation that returns the provided values. | |
560 | template <typename... Args> | |
561 | static BOOST_ASIO_CONSTEXPR deferred_values<typename decay<Args>::type...> | |
562 | values(BOOST_ASIO_MOVE_ARG(Args)... args) | |
563 | { | |
564 | return deferred_values<typename decay<Args>::type...>( | |
565 | deferred_init_tag{}, BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
566 | } | |
567 | ||
568 | /// Creates a conditional object for branching deferred operations. | |
569 | static BOOST_ASIO_CONSTEXPR deferred_conditional<> when(bool b) | |
570 | { | |
571 | return deferred_conditional<>(b); | |
572 | } | |
573 | }; | |
574 | ||
575 | /// Pipe operator used to chain deferred operations. | |
576 | template <typename Head, typename Tail> | |
577 | inline auto operator|(Head head, BOOST_ASIO_MOVE_ARG(Tail) tail) | |
578 | -> typename constraint< | |
579 | is_deferred<Head>::value, | |
580 | decltype(BOOST_ASIO_MOVE_OR_LVALUE(Head)(head)( | |
581 | BOOST_ASIO_MOVE_CAST(Tail)(tail))) | |
582 | >::type | |
583 | { | |
584 | return BOOST_ASIO_MOVE_OR_LVALUE(Head)(head)( | |
585 | BOOST_ASIO_MOVE_CAST(Tail)(tail)); | |
586 | } | |
587 | ||
588 | /// A @ref completion_token object used to specify that an asynchronous | |
589 | /// operation should return a function object to lazily launch the operation. | |
590 | /** | |
591 | * See the documentation for boost::asio::experimental::deferred_t for a usage | |
592 | * example. | |
593 | */ | |
594 | #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) | |
595 | constexpr deferred_t deferred; | |
596 | #elif defined(BOOST_ASIO_MSVC) | |
597 | __declspec(selectany) deferred_t deferred; | |
598 | #endif | |
599 | ||
600 | } // namespace experimental | |
601 | } // namespace asio | |
602 | } // namespace boost | |
603 | ||
604 | #include <boost/asio/detail/pop_options.hpp> | |
605 | ||
606 | #include <boost/asio/experimental/impl/deferred.hpp> | |
607 | ||
608 | #endif // BOOST_ASIO_EXPERIMENTAL_DEFERRED_HPP |