1 //
2 // execution/blocking.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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_EXECUTION_BLOCKING_HPP
12 #define BOOST_ASIO_EXECUTION_BLOCKING_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/detail/type_traits.hpp>
20 #include <boost/asio/execution/execute.hpp>
21 #include <boost/asio/execution/executor.hpp>
22 #include <boost/asio/execution/scheduler.hpp>
23 #include <boost/asio/execution/sender.hpp>
24 #include <boost/asio/is_applicable_property.hpp>
25 #include <boost/asio/prefer.hpp>
26 #include <boost/asio/query.hpp>
27 #include <boost/asio/require.hpp>
28 #include <boost/asio/traits/query_free.hpp>
29 #include <boost/asio/traits/query_member.hpp>
30 #include <boost/asio/traits/query_static_constexpr_member.hpp>
31 #include <boost/asio/traits/static_query.hpp>
32 #include <boost/asio/traits/static_require.hpp>
33 
34 #include <boost/asio/detail/push_options.hpp>
35 
36 namespace boost {
37 namespace asio {
38 
39 #if defined(GENERATING_DOCUMENTATION)
40 
41 namespace execution {
42 
43 /// A property to describe what guarantees an executor makes about the blocking
44 /// behaviour of their execution functions.
45 struct blocking_t
46 {
47   /// The blocking_t property applies to executors, senders, and schedulers.
48   template <typename T>
49   static constexpr bool is_applicable_property_v =
50     is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
51 
52   /// The top-level blocking_t property cannot be required.
53   static constexpr bool is_requirable = false;
54 
55   /// The top-level blocking_t property cannot be preferred.
56   static constexpr bool is_preferable = false;
57 
58   /// The type returned by queries against an @c any_executor.
59   typedef blocking_t polymorphic_query_result_type;
60 
61   /// A sub-property that indicates that invocation of an executor's execution
62   /// function may block pending completion of one or more invocations of the
63   /// submitted function object.
64   struct possibly_t
65   {
66     /// The blocking_t::possibly_t property applies to executors, senders, and
67     /// schedulers.
68     template <typename T>
69     static constexpr bool is_applicable_property_v =
70       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
71 
72     /// The blocking_t::possibly_t property can be required.
73     static constexpr bool is_requirable = true;
74 
75     /// The blocking_t::possibly_t property can be preferred.
76     static constexpr bool is_preferable = true;
77 
78     /// The type returned by queries against an @c any_executor.
79     typedef blocking_t polymorphic_query_result_type;
80 
81     /// Default constructor.
82     constexpr possibly_t();
83 
84     /// Get the value associated with a property object.
85     /**
86      * @returns possibly_t();
87      */
88     static constexpr blocking_t value();
89   };
90 
91   /// A sub-property that indicates that invocation of an executor's execution
92   /// function shall block until completion of all invocations of the submitted
93   /// function object.
94   struct always_t
95   {
96     /// The blocking_t::always_t property applies to executors, senders, and
97     /// schedulers.
98     template <typename T>
99     static constexpr bool is_applicable_property_v =
100       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
101 
102     /// The blocking_t::always_t property can be required.
103     static constexpr bool is_requirable = true;
104 
105     /// The blocking_t::always_t property can be preferred.
106     static constexpr bool is_preferable = false;
107 
108     /// The type returned by queries against an @c any_executor.
109     typedef blocking_t polymorphic_query_result_type;
110 
111     /// Default constructor.
112     constexpr always_t();
113 
114     /// Get the value associated with a property object.
115     /**
116      * @returns always_t();
117      */
118     static constexpr blocking_t value();
119   };
120 
121   /// A sub-property that indicates that invocation of an executor's execution
122   /// function shall not block pending completion of the invocations of the
123   /// submitted function object.
124   struct never_t
125   {
126     /// The blocking_t::never_t property applies to executors, senders, and
127     /// schedulers.
128     template <typename T>
129     static constexpr bool is_applicable_property_v =
130       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
131 
132     /// The blocking_t::never_t property can be required.
133     static constexpr bool is_requirable = true;
134 
135     /// The blocking_t::never_t property can be preferred.
136     static constexpr bool is_preferable = true;
137 
138     /// The type returned by queries against an @c any_executor.
139     typedef blocking_t polymorphic_query_result_type;
140 
141     /// Default constructor.
142     constexpr never_t();
143 
144     /// Get the value associated with a property object.
145     /**
146      * @returns never_t();
147      */
148     static constexpr blocking_t value();
149   };
150 
151   /// A special value used for accessing the blocking_t::possibly_t property.
152   static constexpr possibly_t possibly;
153 
154   /// A special value used for accessing the blocking_t::always_t property.
155   static constexpr always_t always;
156 
157   /// A special value used for accessing the blocking_t::never_t property.
158   static constexpr never_t never;
159 
160   /// Default constructor.
161   constexpr blocking_t();
162 
163   /// Construct from a sub-property value.
164   constexpr blocking_t(possibly_t);
165 
166   /// Construct from a sub-property value.
167   constexpr blocking_t(always_t);
168 
169   /// Construct from a sub-property value.
170   constexpr blocking_t(never_t);
171 
172   /// Compare property values for equality.
173   friend constexpr bool operator==(
174       const blocking_t& a, const blocking_t& b) noexcept;
175 
176   /// Compare property values for inequality.
177   friend constexpr bool operator!=(
178       const blocking_t& a, const blocking_t& b) noexcept;
179 };
180 
181 /// A special value used for accessing the blocking_t property.
182 constexpr blocking_t blocking;
183 
184 } // namespace execution
185 
186 #else // defined(GENERATING_DOCUMENTATION)
187 
188 namespace execution {
189 namespace detail {
190 namespace blocking {
191 
192 template <int I> struct possibly_t;
193 template <int I> struct always_t;
194 template <int I> struct never_t;
195 
196 } // namespace blocking
197 namespace blocking_adaptation {
198 
199 template <int I> struct allowed_t;
200 
201 template <typename Executor, typename Function>
202 void blocking_execute(
203     BOOST_ASIO_MOVE_ARG(Executor) ex,
204     BOOST_ASIO_MOVE_ARG(Function) func);
205 
206 } // namespace blocking_adaptation
207 
208 template <int I = 0>
209 struct blocking_t
210 {
211 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
212   template <typename T>
213   BOOST_ASIO_STATIC_CONSTEXPR(bool,
214     is_applicable_property_v = (
215       is_executor<T>::value
216         || conditional<
217             is_executor<T>::value,
218             false_type,
219             is_sender<T>
220           >::type::value
221         || conditional<
222             is_executor<T>::value,
223             false_type,
224             is_scheduler<T>
225           >::type::value));
226 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
227 
228   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
229   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
230   typedef blocking_t polymorphic_query_result_type;
231 
232   typedef detail::blocking::possibly_t<I> possibly_t;
233   typedef detail::blocking::always_t<I> always_t;
234   typedef detail::blocking::never_t<I> never_t;
235 
236   BOOST_ASIO_CONSTEXPR blocking_t()
237     : value_(-1)
238   {
239   }
240 
241   BOOST_ASIO_CONSTEXPR blocking_t(possibly_t)
242     : value_(0)
243   {
244   }
245 
246   BOOST_ASIO_CONSTEXPR blocking_t(always_t)
247     : value_(1)
248   {
249   }
250 
251   BOOST_ASIO_CONSTEXPR blocking_t(never_t)
252     : value_(2)
253   {
254   }
255 
256   template <typename T>
257   struct proxy
258   {
259 #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
260     struct type
261     {
262       template <typename P>
263       auto query(BOOST_ASIO_MOVE_ARG(P) p) const
264         noexcept(
265           noexcept(
266             declval<typename conditional<true, T, P>::type>().query(
267               BOOST_ASIO_MOVE_CAST(P)(p))
268           )
269         )
270         -> decltype(
271           declval<typename conditional<true, T, P>::type>().query(
272             BOOST_ASIO_MOVE_CAST(P)(p))
273         );
274     };
275 #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
276     typedef T type;
277 #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
278   };
279 
280   template <typename T>
281   struct static_proxy
282   {
283 #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
284     struct type
285     {
286       template <typename P>
287       static constexpr auto query(BOOST_ASIO_MOVE_ARG(P) p)
288         noexcept(
289           noexcept(
290             conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
291           )
292         )
293         -> decltype(
294           conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
295         )
296       {
297         return T::query(BOOST_ASIO_MOVE_CAST(P)(p));
298       }
299     };
300 #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
301     typedef T type;
302 #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
303   };
304 
305   template <typename T>
306   struct query_member :
307     traits::query_member<typename proxy<T>::type, blocking_t> {};
308 
309   template <typename T>
310   struct query_static_constexpr_member :
311     traits::query_static_constexpr_member<
312       typename static_proxy<T>::type, blocking_t> {};
313 
314 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
315   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
316   template <typename T>
317   static BOOST_ASIO_CONSTEXPR
318   typename query_static_constexpr_member<T>::result_type
319   static_query()
320     BOOST_ASIO_NOEXCEPT_IF((
321       query_static_constexpr_member<T>::is_noexcept))
322   {
323     return query_static_constexpr_member<T>::value();
324   }
325 
326   template <typename T>
327   static BOOST_ASIO_CONSTEXPR
328   typename traits::static_query<T, possibly_t>::result_type
329   static_query(
330       typename enable_if<
331         !query_static_constexpr_member<T>::is_valid
332       >::type* = 0,
333       typename enable_if<
334         !query_member<T>::is_valid
335       >::type* = 0,
336       typename enable_if<
337         traits::static_query<T, possibly_t>::is_valid
338       >::type* = 0) BOOST_ASIO_NOEXCEPT
339   {
340     return traits::static_query<T, possibly_t>::value();
341   }
342 
343   template <typename T>
344   static BOOST_ASIO_CONSTEXPR
345   typename traits::static_query<T, always_t>::result_type
346   static_query(
347       typename enable_if<
348         !query_static_constexpr_member<T>::is_valid
349       >::type* = 0,
350       typename enable_if<
351         !query_member<T>::is_valid
352       >::type* = 0,
353       typename enable_if<
354         !traits::static_query<T, possibly_t>::is_valid
355       >::type* = 0,
356       typename enable_if<
357         traits::static_query<T, always_t>::is_valid
358       >::type* = 0) BOOST_ASIO_NOEXCEPT
359   {
360     return traits::static_query<T, always_t>::value();
361   }
362 
363   template <typename T>
364   static BOOST_ASIO_CONSTEXPR
365   typename traits::static_query<T, never_t>::result_type
366   static_query(
367       typename enable_if<
368         !query_static_constexpr_member<T>::is_valid
369       >::type* = 0,
370       typename enable_if<
371         !query_member<T>::is_valid
372       >::type* = 0,
373       typename enable_if<
374         !traits::static_query<T, possibly_t>::is_valid
375       >::type* = 0,
376       typename enable_if<
377         !traits::static_query<T, always_t>::is_valid
378       >::type* = 0,
379       typename enable_if<
380         traits::static_query<T, never_t>::is_valid
381       >::type* = 0) BOOST_ASIO_NOEXCEPT
382   {
383     return traits::static_query<T, never_t>::value();
384   }
385 
386   template <typename E, typename T = decltype(blocking_t::static_query<E>())>
387   static BOOST_ASIO_CONSTEXPR const T static_query_v
388     = blocking_t::static_query<E>();
389 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
390        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
391 
392   friend BOOST_ASIO_CONSTEXPR bool operator==(
393       const blocking_t& a, const blocking_t& b)
394   {
395     return a.value_ == b.value_;
396   }
397 
398   friend BOOST_ASIO_CONSTEXPR bool operator!=(
399       const blocking_t& a, const blocking_t& b)
400   {
401     return a.value_ != b.value_;
402   }
403 
404   struct convertible_from_blocking_t
405   {
406     BOOST_ASIO_CONSTEXPR convertible_from_blocking_t(blocking_t) {}
407   };
408 
409   template <typename Executor>
410   friend BOOST_ASIO_CONSTEXPR blocking_t query(
411       const Executor& ex, convertible_from_blocking_t,
412       typename enable_if<
413         can_query<const Executor&, possibly_t>::value
414       >::type* = 0)
415 #if !defined(__clang__) // Clang crashes if noexcept is used here.
416 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
417     BOOST_ASIO_NOEXCEPT_IF((
418       is_nothrow_query<const Executor&, blocking_t<>::possibly_t>::value))
419 #else // defined(BOOST_ASIO_MSVC)
420     BOOST_ASIO_NOEXCEPT_IF((
421       is_nothrow_query<const Executor&, possibly_t>::value))
422 #endif // defined(BOOST_ASIO_MSVC)
423 #endif // !defined(__clang__)
424   {
425     return boost::asio::query(ex, possibly_t());
426   }
427 
428   template <typename Executor>
429   friend BOOST_ASIO_CONSTEXPR blocking_t query(
430       const Executor& ex, convertible_from_blocking_t,
431       typename enable_if<
432         !can_query<const Executor&, possibly_t>::value
433       >::type* = 0,
434       typename enable_if<
435         can_query<const Executor&, always_t>::value
436       >::type* = 0)
437 #if !defined(__clang__) // Clang crashes if noexcept is used here.
438 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
439     BOOST_ASIO_NOEXCEPT_IF((
440       is_nothrow_query<const Executor&, blocking_t<>::always_t>::value))
441 #else // defined(BOOST_ASIO_MSVC)
442     BOOST_ASIO_NOEXCEPT_IF((
443       is_nothrow_query<const Executor&, always_t>::value))
444 #endif // defined(BOOST_ASIO_MSVC)
445 #endif // !defined(__clang__)
446   {
447     return boost::asio::query(ex, always_t());
448   }
449 
450   template <typename Executor>
451   friend BOOST_ASIO_CONSTEXPR blocking_t query(
452       const Executor& ex, convertible_from_blocking_t,
453       typename enable_if<
454         !can_query<const Executor&, possibly_t>::value
455       >::type* = 0,
456       typename enable_if<
457         !can_query<const Executor&, always_t>::value
458       >::type* = 0,
459       typename enable_if<
460         can_query<const Executor&, never_t>::value
461       >::type* = 0)
462 #if !defined(__clang__) // Clang crashes if noexcept is used here.
463 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
464     BOOST_ASIO_NOEXCEPT_IF((
465       is_nothrow_query<const Executor&, blocking_t<>::never_t>::value))
466 #else // defined(BOOST_ASIO_MSVC)
467     BOOST_ASIO_NOEXCEPT_IF((
468       is_nothrow_query<const Executor&, never_t>::value))
469 #endif // defined(BOOST_ASIO_MSVC)
470 #endif // !defined(__clang__)
471   {
472     return boost::asio::query(ex, never_t());
473   }
474 
475   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly);
476   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always);
477   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never);
478 
479 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
480   static const blocking_t instance;
481 #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR)
482 
483 private:
484   int value_;
485 };
486 
487 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
488   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
489 template <int I> template <typename E, typename T>
490 const T blocking_t<I>::static_query_v;
491 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
492        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
493 
494 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
495 template <int I>
496 const blocking_t<I> blocking_t<I>::instance;
497 #endif
498 
499 template <int I>
500 const typename blocking_t<I>::possibly_t blocking_t<I>::possibly;
501 
502 template <int I>
503 const typename blocking_t<I>::always_t blocking_t<I>::always;
504 
505 template <int I>
506 const typename blocking_t<I>::never_t blocking_t<I>::never;
507 
508 namespace blocking {
509 
510 template <int I = 0>
511 struct possibly_t
512 {
513 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
514   template <typename T>
515   BOOST_ASIO_STATIC_CONSTEXPR(bool,
516     is_applicable_property_v = (
517       is_executor<T>::value
518         || conditional<
519             is_executor<T>::value,
520             false_type,
521             is_sender<T>
522           >::type::value
523         || conditional<
524             is_executor<T>::value,
525             false_type,
526             is_scheduler<T>
527           >::type::value));
528 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
529 
530   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
531   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
532   typedef blocking_t<I> polymorphic_query_result_type;
533 
534   BOOST_ASIO_CONSTEXPR possibly_t()
535   {
536   }
537 
538   template <typename T>
539   struct query_member :
540     traits::query_member<
541       typename blocking_t<I>::template proxy<T>::type, possibly_t> {};
542 
543   template <typename T>
544   struct query_static_constexpr_member :
545     traits::query_static_constexpr_member<
546       typename blocking_t<I>::template static_proxy<T>::type, possibly_t> {};
547 
548 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
549   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
550   template <typename T>
551   static BOOST_ASIO_CONSTEXPR
552   typename query_static_constexpr_member<T>::result_type
553   static_query()
554     BOOST_ASIO_NOEXCEPT_IF((
555       query_static_constexpr_member<T>::is_noexcept))
556   {
557     return query_static_constexpr_member<T>::value();
558   }
559 
560   template <typename T>
561   static BOOST_ASIO_CONSTEXPR possibly_t static_query(
562       typename enable_if<
563         !query_static_constexpr_member<T>::is_valid
564       >::type* = 0,
565       typename enable_if<
566         !query_member<T>::is_valid
567       >::type* = 0,
568       typename enable_if<
569         !traits::query_free<T, possibly_t>::is_valid
570       >::type* = 0,
571       typename enable_if<
572         !can_query<T, always_t<I> >::value
573       >::type* = 0,
574       typename enable_if<
575         !can_query<T, never_t<I> >::value
576       >::type* = 0) BOOST_ASIO_NOEXCEPT
577   {
578     return possibly_t();
579   }
580 
581   template <typename E, typename T = decltype(possibly_t::static_query<E>())>
582   static BOOST_ASIO_CONSTEXPR const T static_query_v
583     = possibly_t::static_query<E>();
584 #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
585        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
586 
587   static BOOST_ASIO_CONSTEXPR blocking_t<I> value()
588   {
589     return possibly_t();
590   }
591 
592   friend BOOST_ASIO_CONSTEXPR bool operator==(
593       const possibly_t&, const possibly_t&)
594   {
595     return true;
596   }
597 
598   friend BOOST_ASIO_CONSTEXPR bool operator!=(
599       const possibly_t&, const possibly_t&)
600   {
601     return false;
602   }
603 
604   friend BOOST_ASIO_CONSTEXPR bool operator==(
605       const possibly_t&, const always_t<I>&)
606   {
607     return false;
608   }
609 
610   friend BOOST_ASIO_CONSTEXPR bool operator!=(
611       const possibly_t&, const always_t<I>&)
612   {
613     return true;
614   }
615 
616   friend BOOST_ASIO_CONSTEXPR bool operator==(
617       const possibly_t&, const never_t<I>&)
618   {
619     return false;
620   }
621 
622   friend BOOST_ASIO_CONSTEXPR bool operator!=(
623       const possibly_t&, const never_t<I>&)
624   {
625     return true;
626   }
627 };
628 
629 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
630   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
631 template <int I> template <typename E, typename T>
632 const T possibly_t<I>::static_query_v;
633 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
634        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
635 
636 template <typename Executor>
637 class adapter
638 {
639 public:
640   adapter(int, const Executor& e) BOOST_ASIO_NOEXCEPT
641     : executor_(e)
642   {
643   }
644 
645   adapter(const adapter& other) BOOST_ASIO_NOEXCEPT
646     : executor_(other.executor_)
647   {
648   }
649 
650 #if defined(BOOST_ASIO_HAS_MOVE)
651   adapter(adapter&& other) BOOST_ASIO_NOEXCEPT
652     : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_))
653   {
654   }
655 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
656 
657   template <int I>
658   static BOOST_ASIO_CONSTEXPR always_t<I> query(
659       blocking_t<I>) BOOST_ASIO_NOEXCEPT
660   {
661     return always_t<I>();
662   }
663 
664   template <int I>
665   static BOOST_ASIO_CONSTEXPR always_t<I> query(
666       possibly_t<I>) BOOST_ASIO_NOEXCEPT
667   {
668     return always_t<I>();
669   }
670 
671   template <int I>
672   static BOOST_ASIO_CONSTEXPR always_t<I> query(
673       always_t<I>) BOOST_ASIO_NOEXCEPT
674   {
675     return always_t<I>();
676   }
677 
678   template <int I>
679   static BOOST_ASIO_CONSTEXPR always_t<I> query(
680       never_t<I>) BOOST_ASIO_NOEXCEPT
681   {
682     return always_t<I>();
683   }
684 
685   template <typename Property>
686   typename enable_if<
687     can_query<const Executor&, Property>::value,
688     typename query_result<const Executor&, Property>::type
689   >::type query(const Property& p) const
690     BOOST_ASIO_NOEXCEPT_IF((
691       is_nothrow_query<const Executor&, Property>::value))
692   {
693     return boost::asio::query(executor_, p);
694   }
695 
696   template <int I>
697   typename enable_if<
698     can_require<const Executor&, possibly_t<I> >::value,
699     typename require_result<const Executor&, possibly_t<I> >::type
700   >::type require(possibly_t<I>) const BOOST_ASIO_NOEXCEPT
701   {
702     return boost::asio::require(executor_, possibly_t<I>());
703   }
704 
705   template <int I>
706   typename enable_if<
707     can_require<const Executor&, never_t<I> >::value,
708     typename require_result<const Executor&, never_t<I> >::type
709   >::type require(never_t<I>) const BOOST_ASIO_NOEXCEPT
710   {
711     return boost::asio::require(executor_, never_t<I>());
712   }
713 
714   template <typename Property>
715   typename enable_if<
716     can_require<const Executor&, Property>::value,
717     adapter<typename decay<
718       typename require_result<const Executor&, Property>::type
719     >::type>
720   >::type require(const Property& p) const
721     BOOST_ASIO_NOEXCEPT_IF((
722       is_nothrow_require<const Executor&, Property>::value))
723   {
724     return adapter<typename decay<
725       typename require_result<const Executor&, Property>::type
726         >::type>(0, boost::asio::require(executor_, p));
727   }
728 
729   template <typename Property>
730   typename enable_if<
731     can_prefer<const Executor&, Property>::value,
732     adapter<typename decay<
733       typename prefer_result<const Executor&, Property>::type
734     >::type>
735   >::type prefer(const Property& p) const
736     BOOST_ASIO_NOEXCEPT_IF((
737       is_nothrow_prefer<const Executor&, Property>::value))
738   {
739     return adapter<typename decay<
740       typename prefer_result<const Executor&, Property>::type
741         >::type>(0, boost::asio::prefer(executor_, p));
742   }
743 
744   template <typename Function>
745   typename enable_if<
746     execution::can_execute<const Executor&, Function>::value
747   >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const
748   {
749     blocking_adaptation::blocking_execute(
750         executor_, BOOST_ASIO_MOVE_CAST(Function)(f));
751   }
752 
753   friend bool operator==(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
754   {
755     return a.executor_ == b.executor_;
756   }
757 
758   friend bool operator!=(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
759   {
760     return a.executor_ != b.executor_;
761   }
762 
763 private:
764   Executor executor_;
765 };
766 
767 template <int I = 0>
768 struct always_t
769 {
770 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
771   template <typename T>
772   BOOST_ASIO_STATIC_CONSTEXPR(bool,
773     is_applicable_property_v = (
774       is_executor<T>::value
775         || conditional<
776             is_executor<T>::value,
777             false_type,
778             is_sender<T>
779           >::type::value
780         || conditional<
781             is_executor<T>::value,
782             false_type,
783             is_scheduler<T>
784           >::type::value));
785 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
786 
787   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
788   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
789   typedef blocking_t<I> polymorphic_query_result_type;
790 
791   BOOST_ASIO_CONSTEXPR always_t()
792   {
793   }
794 
795   template <typename T>
796   struct query_member :
797     traits::query_member<
798       typename blocking_t<I>::template proxy<T>::type, always_t> {};
799 
800   template <typename T>
801   struct query_static_constexpr_member :
802     traits::query_static_constexpr_member<
803       typename blocking_t<I>::template static_proxy<T>::type, always_t> {};
804 
805 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
806   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
807   template <typename T>
808   static BOOST_ASIO_CONSTEXPR
809   typename query_static_constexpr_member<T>::result_type
810   static_query()
811     BOOST_ASIO_NOEXCEPT_IF((
812       query_static_constexpr_member<T>::is_noexcept))
813   {
814     return query_static_constexpr_member<T>::value();
815   }
816 
817   template <typename E, typename T = decltype(always_t::static_query<E>())>
818   static BOOST_ASIO_CONSTEXPR const T static_query_v
819     = always_t::static_query<E>();
820 #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
821        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
822 
823   static BOOST_ASIO_CONSTEXPR blocking_t<I> value()
824   {
825     return always_t();
826   }
827 
828   friend BOOST_ASIO_CONSTEXPR bool operator==(
829       const always_t&, const always_t&)
830   {
831     return true;
832   }
833 
834   friend BOOST_ASIO_CONSTEXPR bool operator!=(
835       const always_t&, const always_t&)
836   {
837     return false;
838   }
839 
840   friend BOOST_ASIO_CONSTEXPR bool operator==(
841       const always_t&, const possibly_t<I>&)
842   {
843     return false;
844   }
845 
846   friend BOOST_ASIO_CONSTEXPR bool operator!=(
847       const always_t&, const possibly_t<I>&)
848   {
849     return true;
850   }
851 
852   friend BOOST_ASIO_CONSTEXPR bool operator==(
853       const always_t&, const never_t<I>&)
854   {
855     return false;
856   }
857 
858   friend BOOST_ASIO_CONSTEXPR bool operator!=(
859       const always_t&, const never_t<I>&)
860   {
861     return true;
862   }
863 
864   template <typename Executor>
865   friend adapter<Executor> require(
866       const Executor& e, const always_t&,
867       typename enable_if<
868         is_executor<Executor>::value
869       >::type* = 0,
870       typename enable_if<
871         traits::static_require<
872           const Executor&,
873           blocking_adaptation::allowed_t<0>
874         >::is_valid
875       >::type* = 0)
876   {
877     return adapter<Executor>(0, e);
878   }
879 };
880 
881 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
882   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
883 template <int I> template <typename E, typename T>
884 const T always_t<I>::static_query_v;
885 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
886        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
887 
888 template <int I>
889 struct never_t
890 {
891 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
892   template <typename T>
893   BOOST_ASIO_STATIC_CONSTEXPR(bool,
894     is_applicable_property_v = (
895       is_executor<T>::value
896         || conditional<
897             is_executor<T>::value,
898             false_type,
899             is_sender<T>
900           >::type::value
901         || conditional<
902             is_executor<T>::value,
903             false_type,
904             is_scheduler<T>
905           >::type::value));
906 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
907 
908   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
909   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
910   typedef blocking_t<I> polymorphic_query_result_type;
911 
912   BOOST_ASIO_CONSTEXPR never_t()
913   {
914   }
915 
916   template <typename T>
917   struct query_member :
918     traits::query_member<
919       typename blocking_t<I>::template proxy<T>::type, never_t> {};
920 
921   template <typename T>
922   struct query_static_constexpr_member :
923     traits::query_static_constexpr_member<
924       typename blocking_t<I>::template static_proxy<T>::type, never_t> {};
925 
926 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
927   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
928   template <typename T>
929   static BOOST_ASIO_CONSTEXPR
930   typename query_static_constexpr_member<T>::result_type
931   static_query()
932     BOOST_ASIO_NOEXCEPT_IF((
933       query_static_constexpr_member<T>::is_noexcept))
934   {
935     return query_static_constexpr_member<T>::value();
936   }
937 
938   template <typename E, typename T = decltype(never_t::static_query<E>())>
939   static BOOST_ASIO_CONSTEXPR const T static_query_v
940     = never_t::static_query<E>();
941 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
942        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
943 
944   static BOOST_ASIO_CONSTEXPR blocking_t<I> value()
945   {
946     return never_t();
947   }
948 
949   friend BOOST_ASIO_CONSTEXPR bool operator==(
950       const never_t&, const never_t&)
951   {
952     return true;
953   }
954 
955   friend BOOST_ASIO_CONSTEXPR bool operator!=(
956       const never_t&, const never_t&)
957   {
958     return false;
959   }
960 
961   friend BOOST_ASIO_CONSTEXPR bool operator==(
962       const never_t&, const possibly_t<I>&)
963   {
964     return false;
965   }
966 
967   friend BOOST_ASIO_CONSTEXPR bool operator!=(
968       const never_t&, const possibly_t<I>&)
969   {
970     return true;
971   }
972 
973   friend BOOST_ASIO_CONSTEXPR bool operator==(
974       const never_t&, const always_t<I>&)
975   {
976     return false;
977   }
978 
979   friend BOOST_ASIO_CONSTEXPR bool operator!=(
980       const never_t&, const always_t<I>&)
981   {
982     return true;
983   }
984 };
985 
986 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
987   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
988 template <int I> template <typename E, typename T>
989 const T never_t<I>::static_query_v;
990 #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
991 
992 } // namespace blocking
993 } // namespace detail
994 
995 typedef detail::blocking_t<> blocking_t;
996 
997 #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
998 constexpr blocking_t blocking;
999 #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
1000 namespace { static const blocking_t& blocking = blocking_t::instance; }
1001 #endif
1002 
1003 } // namespace execution
1004 
1005 #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
1006 
1007 template <typename T>
1008 struct is_applicable_property<T, execution::blocking_t>
1009   : integral_constant<bool,
1010       execution::is_executor<T>::value
1011         || conditional<
1012             execution::is_executor<T>::value,
1013             false_type,
1014             execution::is_sender<T>
1015           >::type::value
1016         || conditional<
1017             execution::is_executor<T>::value,
1018             false_type,
1019             execution::is_scheduler<T>
1020           >::type::value>
1021 {
1022 };
1023 
1024 template <typename T>
1025 struct is_applicable_property<T, execution::blocking_t::possibly_t>
1026   : integral_constant<bool,
1027       execution::is_executor<T>::value
1028         || conditional<
1029             execution::is_executor<T>::value,
1030             false_type,
1031             execution::is_sender<T>
1032           >::type::value
1033         || conditional<
1034             execution::is_executor<T>::value,
1035             false_type,
1036             execution::is_scheduler<T>
1037           >::type::value>
1038 {
1039 };
1040 
1041 template <typename T>
1042 struct is_applicable_property<T, execution::blocking_t::always_t>
1043   : integral_constant<bool,
1044       execution::is_executor<T>::value
1045         || conditional<
1046             execution::is_executor<T>::value,
1047             false_type,
1048             execution::is_sender<T>
1049           >::type::value
1050         || conditional<
1051             execution::is_executor<T>::value,
1052             false_type,
1053             execution::is_scheduler<T>
1054           >::type::value>
1055 {
1056 };
1057 
1058 template <typename T>
1059 struct is_applicable_property<T, execution::blocking_t::never_t>
1060   : integral_constant<bool,
1061       execution::is_executor<T>::value
1062         || conditional<
1063             execution::is_executor<T>::value,
1064             false_type,
1065             execution::is_sender<T>
1066           >::type::value
1067         || conditional<
1068             execution::is_executor<T>::value,
1069             false_type,
1070             execution::is_scheduler<T>
1071           >::type::value>
1072 {
1073 };
1074 
1075 #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
1076 
1077 namespace traits {
1078 
1079 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
1080 
1081 template <typename T>
1082 struct query_free_default<T, execution::blocking_t,
1083   typename enable_if<
1084     can_query<T, execution::blocking_t::possibly_t>::value
1085   >::type>
1086 {
1087   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1088   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1089     (is_nothrow_query<T, execution::blocking_t::possibly_t>::value));
1090 
1091   typedef execution::blocking_t result_type;
1092 };
1093 
1094 template <typename T>
1095 struct query_free_default<T, execution::blocking_t,
1096   typename enable_if<
1097     !can_query<T, execution::blocking_t::possibly_t>::value
1098       && can_query<T, execution::blocking_t::always_t>::value
1099   >::type>
1100 {
1101   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1102   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1103     (is_nothrow_query<T, execution::blocking_t::always_t>::value));
1104 
1105   typedef execution::blocking_t result_type;
1106 };
1107 
1108 template <typename T>
1109 struct query_free_default<T, execution::blocking_t,
1110   typename enable_if<
1111     !can_query<T, execution::blocking_t::possibly_t>::value
1112       && !can_query<T, execution::blocking_t::always_t>::value
1113       && can_query<T, execution::blocking_t::never_t>::value
1114   >::type>
1115 {
1116   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1117   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1118     (is_nothrow_query<T, execution::blocking_t::never_t>::value));
1119 
1120   typedef execution::blocking_t result_type;
1121 };
1122 
1123 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
1124 
1125 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
1126   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
1127 
1128 template <typename T>
1129 struct static_query<T, execution::blocking_t,
1130   typename enable_if<
1131     execution::detail::blocking_t<0>::
1132       query_static_constexpr_member<T>::is_valid
1133   >::type>
1134 {
1135   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1136   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1137 
1138   typedef typename execution::detail::blocking_t<0>::
1139     query_static_constexpr_member<T>::result_type result_type;
1140 
1141   static BOOST_ASIO_CONSTEXPR result_type value()
1142   {
1143     return execution::blocking_t::query_static_constexpr_member<T>::value();
1144   }
1145 };
1146 
1147 template <typename T>
1148 struct static_query<T, execution::blocking_t,
1149   typename enable_if<
1150     !execution::detail::blocking_t<0>::
1151         query_static_constexpr_member<T>::is_valid
1152       && !execution::detail::blocking_t<0>::
1153         query_member<T>::is_valid
1154       && traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
1155   >::type>
1156 {
1157   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1158   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1159 
1160   typedef typename traits::static_query<T,
1161     execution::blocking_t::possibly_t>::result_type result_type;
1162 
1163   static BOOST_ASIO_CONSTEXPR result_type value()
1164   {
1165     return traits::static_query<T, execution::blocking_t::possibly_t>::value();
1166   }
1167 };
1168 
1169 template <typename T>
1170 struct static_query<T, execution::blocking_t,
1171   typename enable_if<
1172     !execution::detail::blocking_t<0>::
1173         query_static_constexpr_member<T>::is_valid
1174       && !execution::detail::blocking_t<0>::
1175         query_member<T>::is_valid
1176       && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
1177       && traits::static_query<T, execution::blocking_t::always_t>::is_valid
1178   >::type>
1179 {
1180   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1181   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1182 
1183   typedef typename traits::static_query<T,
1184     execution::blocking_t::always_t>::result_type result_type;
1185 
1186   static BOOST_ASIO_CONSTEXPR result_type value()
1187   {
1188     return traits::static_query<T, execution::blocking_t::always_t>::value();
1189   }
1190 };
1191 
1192 template <typename T>
1193 struct static_query<T, execution::blocking_t,
1194   typename enable_if<
1195     !execution::detail::blocking_t<0>::
1196         query_static_constexpr_member<T>::is_valid
1197       && !execution::detail::blocking_t<0>::
1198         query_member<T>::is_valid
1199       && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid
1200       && !traits::static_query<T, execution::blocking_t::always_t>::is_valid
1201       && traits::static_query<T, execution::blocking_t::never_t>::is_valid
1202   >::type>
1203 {
1204   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1205   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1206 
1207   typedef typename traits::static_query<T,
1208     execution::blocking_t::never_t>::result_type result_type;
1209 
1210   static BOOST_ASIO_CONSTEXPR result_type value()
1211   {
1212     return traits::static_query<T, execution::blocking_t::never_t>::value();
1213   }
1214 };
1215 
1216 template <typename T>
1217 struct static_query<T, execution::blocking_t::possibly_t,
1218   typename enable_if<
1219     execution::detail::blocking::possibly_t<0>::
1220       query_static_constexpr_member<T>::is_valid
1221   >::type>
1222 {
1223   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1224   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1225 
1226   typedef typename execution::detail::blocking::possibly_t<0>::
1227     query_static_constexpr_member<T>::result_type result_type;
1228 
1229   static BOOST_ASIO_CONSTEXPR result_type value()
1230   {
1231     return execution::detail::blocking::possibly_t<0>::
1232       query_static_constexpr_member<T>::value();
1233   }
1234 };
1235 
1236 template <typename T>
1237 struct static_query<T, execution::blocking_t::possibly_t,
1238   typename enable_if<
1239     !execution::detail::blocking::possibly_t<0>::
1240         query_static_constexpr_member<T>::is_valid
1241       && !execution::detail::blocking::possibly_t<0>::
1242         query_member<T>::is_valid
1243       && !traits::query_free<T, execution::blocking_t::possibly_t>::is_valid
1244       && !can_query<T, execution::blocking_t::always_t>::value
1245       && !can_query<T, execution::blocking_t::never_t>::value
1246   >::type>
1247 {
1248   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1249   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1250 
1251   typedef execution::blocking_t::possibly_t result_type;
1252 
1253   static BOOST_ASIO_CONSTEXPR result_type value()
1254   {
1255     return result_type();
1256   }
1257 };
1258 
1259 template <typename T>
1260 struct static_query<T, execution::blocking_t::always_t,
1261   typename enable_if<
1262     execution::detail::blocking::always_t<0>::
1263       query_static_constexpr_member<T>::is_valid
1264   >::type>
1265 {
1266   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1267   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1268 
1269   typedef typename execution::detail::blocking::always_t<0>::
1270     query_static_constexpr_member<T>::result_type result_type;
1271 
1272   static BOOST_ASIO_CONSTEXPR result_type value()
1273   {
1274     return execution::detail::blocking::always_t<0>::
1275       query_static_constexpr_member<T>::value();
1276   }
1277 };
1278 
1279 template <typename T>
1280 struct static_query<T, execution::blocking_t::never_t,
1281   typename enable_if<
1282     execution::detail::blocking::never_t<0>::
1283       query_static_constexpr_member<T>::is_valid
1284   >::type>
1285 {
1286   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1287   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1288 
1289   typedef typename execution::detail::blocking::never_t<0>::
1290     query_static_constexpr_member<T>::result_type result_type;
1291 
1292   static BOOST_ASIO_CONSTEXPR result_type value()
1293   {
1294     return execution::detail::blocking::never_t<0>::
1295       query_static_constexpr_member<T>::value();
1296   }
1297 };
1298 
1299 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
1300        //   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
1301 
1302 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
1303 
1304 template <typename T>
1305 struct static_require<T, execution::blocking_t::possibly_t,
1306   typename enable_if<
1307     static_query<T, execution::blocking_t::possibly_t>::is_valid
1308   >::type>
1309 {
1310   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1311     (is_same<typename static_query<T,
1312       execution::blocking_t::possibly_t>::result_type,
1313         execution::blocking_t::possibly_t>::value));
1314 };
1315 
1316 template <typename T>
1317 struct static_require<T, execution::blocking_t::always_t,
1318   typename enable_if<
1319     static_query<T, execution::blocking_t::always_t>::is_valid
1320   >::type>
1321 {
1322   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1323     (is_same<typename static_query<T,
1324       execution::blocking_t::always_t>::result_type,
1325         execution::blocking_t::always_t>::value));
1326 };
1327 
1328 template <typename T>
1329 struct static_require<T, execution::blocking_t::never_t,
1330   typename enable_if<
1331     static_query<T, execution::blocking_t::never_t>::is_valid
1332   >::type>
1333 {
1334   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1335     (is_same<typename static_query<T,
1336       execution::blocking_t::never_t>::result_type,
1337         execution::blocking_t::never_t>::value));
1338 };
1339 
1340 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
1341 
1342 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
1343 
1344 template <typename T>
1345 struct require_free_default<T, execution::blocking_t::always_t,
1346   typename enable_if<
1347     is_same<T, typename decay<T>::type>::value
1348       && execution::is_executor<T>::value
1349       && traits::static_require<
1350           const T&,
1351           execution::detail::blocking_adaptation::allowed_t<0>
1352         >::is_valid
1353   >::type>
1354 {
1355   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1356   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
1357   typedef execution::detail::blocking::adapter<T> result_type;
1358 };
1359 
1360 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
1361 
1362 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1363 
1364 template <typename Executor>
1365 struct equality_comparable<
1366   execution::detail::blocking::adapter<Executor> >
1367 {
1368   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1369   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1370 };
1371 
1372 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1373 
1374 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1375 
1376 template <typename Executor, typename Function>
1377 struct execute_member<
1378   execution::detail::blocking::adapter<Executor>, Function>
1379 {
1380   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1381   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
1382   typedef void result_type;
1383 };
1384 
1385 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1386 
1387 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1388 
1389 template <typename Executor, int I>
1390 struct query_static_constexpr_member<
1391   execution::detail::blocking::adapter<Executor>,
1392   execution::detail::blocking_t<I> >
1393 {
1394   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1395   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1396   typedef execution::blocking_t::always_t result_type;
1397 
1398   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1399   {
1400     return result_type();
1401   }
1402 };
1403 
1404 template <typename Executor, int I>
1405 struct query_static_constexpr_member<
1406   execution::detail::blocking::adapter<Executor>,
1407   execution::detail::blocking::always_t<I> >
1408 {
1409   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1410   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1411   typedef execution::blocking_t::always_t result_type;
1412 
1413   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1414   {
1415     return result_type();
1416   }
1417 };
1418 
1419 template <typename Executor, int I>
1420 struct query_static_constexpr_member<
1421   execution::detail::blocking::adapter<Executor>,
1422   execution::detail::blocking::possibly_t<I> >
1423 {
1424   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1425   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1426   typedef execution::blocking_t::always_t result_type;
1427 
1428   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1429   {
1430     return result_type();
1431   }
1432 };
1433 
1434 template <typename Executor, int I>
1435 struct query_static_constexpr_member<
1436   execution::detail::blocking::adapter<Executor>,
1437   execution::detail::blocking::never_t<I> >
1438 {
1439   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1440   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1441   typedef execution::blocking_t::always_t result_type;
1442 
1443   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1444   {
1445     return result_type();
1446   }
1447 };
1448 
1449 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1450 
1451 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1452 
1453 template <typename Executor, typename Property>
1454 struct query_member<
1455   execution::detail::blocking::adapter<Executor>, Property,
1456   typename enable_if<
1457     can_query<const Executor&, Property>::value
1458   >::type>
1459 {
1460   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1461   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1462       (is_nothrow_query<Executor, Property>::value));
1463   typedef typename query_result<Executor, Property>::type result_type;
1464 };
1465 
1466 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1467 
1468 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1469 
1470 template <typename Executor, int I>
1471 struct require_member<
1472   execution::detail::blocking::adapter<Executor>,
1473   execution::detail::blocking::possibly_t<I>,
1474   typename enable_if<
1475     can_require<
1476       const Executor&,
1477       execution::detail::blocking::possibly_t<I>
1478     >::value
1479   >::type>
1480 {
1481   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1482   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1483       (is_nothrow_require<const Executor&,
1484         execution::detail::blocking::possibly_t<I> >::value));
1485   typedef typename require_result<const Executor&,
1486     execution::detail::blocking::possibly_t<I> >::type result_type;
1487 };
1488 
1489 template <typename Executor, int I>
1490 struct require_member<
1491   execution::detail::blocking::adapter<Executor>,
1492   execution::detail::blocking::never_t<I>,
1493   typename enable_if<
1494     can_require<
1495       const Executor&,
1496       execution::detail::blocking::never_t<I>
1497     >::value
1498   >::type>
1499 {
1500   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1501   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1502       (is_nothrow_require<const Executor&,
1503         execution::detail::blocking::never_t<I> >::value));
1504   typedef typename require_result<const Executor&,
1505     execution::detail::blocking::never_t<I> >::type result_type;
1506 };
1507 
1508 template <typename Executor, typename Property>
1509 struct require_member<
1510   execution::detail::blocking::adapter<Executor>, Property,
1511   typename enable_if<
1512     can_require<const Executor&, Property>::value
1513   >::type>
1514 {
1515   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1516   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1517       (is_nothrow_require<Executor, Property>::value));
1518   typedef execution::detail::blocking::adapter<typename decay<
1519     typename require_result<Executor, Property>::type
1520       >::type> result_type;
1521 };
1522 
1523 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1524 
1525 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1526 
1527 template <typename Executor, typename Property>
1528 struct prefer_member<
1529   execution::detail::blocking::adapter<Executor>, Property,
1530   typename enable_if<
1531     can_prefer<const Executor&, Property>::value
1532   >::type>
1533 {
1534   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1535   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1536       (is_nothrow_prefer<Executor, Property>::value));
1537   typedef execution::detail::blocking::adapter<typename decay<
1538     typename prefer_result<Executor, Property>::type
1539       >::type> result_type;
1540 };
1541 
1542 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1543 
1544 } // namespace traits
1545 
1546 #endif // defined(GENERATING_DOCUMENTATION)
1547 
1548 } // namespace asio
1549 } // namespace boost
1550 
1551 #include <boost/asio/detail/pop_options.hpp>
1552 
1553 #endif // BOOST_ASIO_EXECUTION_BLOCKING_HPP
1554