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

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