1 //
2 // execution/blocking_adaptation.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_ADAPTATION_HPP
12 #define BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_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/event.hpp>
20 #include <boost/asio/detail/mutex.hpp>
21 #include <boost/asio/detail/type_traits.hpp>
22 #include <boost/asio/execution/execute.hpp>
23 #include <boost/asio/execution/executor.hpp>
24 #include <boost/asio/execution/scheduler.hpp>
25 #include <boost/asio/execution/sender.hpp>
26 #include <boost/asio/is_applicable_property.hpp>
27 #include <boost/asio/prefer.hpp>
28 #include <boost/asio/query.hpp>
29 #include <boost/asio/require.hpp>
30 #include <boost/asio/traits/prefer_member.hpp>
31 #include <boost/asio/traits/query_free.hpp>
32 #include <boost/asio/traits/query_member.hpp>
33 #include <boost/asio/traits/query_static_constexpr_member.hpp>
34 #include <boost/asio/traits/require_member.hpp>
35 #include <boost/asio/traits/static_query.hpp>
36 #include <boost/asio/traits/static_require.hpp>
37 
38 #include <boost/asio/detail/push_options.hpp>
39 
40 namespace boost {
41 namespace asio {
42 
43 #if defined(GENERATING_DOCUMENTATION)
44 
45 namespace execution {
46 
47 /// A property to describe whether automatic adaptation of an executor is
48 /// allowed in order to apply the blocking_adaptation_t::allowed_t property.
49 struct blocking_adaptation_t
50 {
51   /// The blocking_adaptation_t property applies to executors, senders, and
52   /// schedulers.
53   template <typename T>
54   static constexpr bool is_applicable_property_v =
55     is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
56 
57   /// The top-level blocking_adaptation_t property cannot be required.
58   static constexpr bool is_requirable = false;
59 
60   /// The top-level blocking_adaptation_t property cannot be preferred.
61   static constexpr bool is_preferable = false;
62 
63   /// The type returned by queries against an @c any_executor.
64   typedef blocking_adaptation_t polymorphic_query_result_type;
65 
66   /// A sub-property that indicates that automatic adaptation is not allowed.
67   struct disallowed_t
68   {
69     /// The blocking_adaptation_t::disallowed_t property applies to executors,
70     /// senders, and schedulers.
71     template <typename T>
72     static constexpr bool is_applicable_property_v =
73       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
74 
75     /// The blocking_adaptation_t::disallowed_t property can be required.
76     static constexpr bool is_requirable = true;
77 
78     /// The blocking_adaptation_t::disallowed_t property can be preferred.
79     static constexpr bool is_preferable = true;
80 
81     /// The type returned by queries against an @c any_executor.
82     typedef blocking_adaptation_t polymorphic_query_result_type;
83 
84     /// Default constructor.
85     constexpr disallowed_t();
86 
87     /// Get the value associated with a property object.
88     /**
89      * @returns disallowed_t();
90      */
91     static constexpr blocking_adaptation_t value();
92   };
93 
94   /// A sub-property that indicates that automatic adaptation is allowed.
95   struct allowed_t
96   {
97     /// The blocking_adaptation_t::allowed_t property applies to executors,
98     /// senders, and schedulers.
99     template <typename T>
100     static constexpr bool is_applicable_property_v =
101       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
102 
103     /// The blocking_adaptation_t::allowed_t property can be required.
104     static constexpr bool is_requirable = true;
105 
106     /// The blocking_adaptation_t::allowed_t property can be preferred.
107     static constexpr bool is_preferable = false;
108 
109     /// The type returned by queries against an @c any_executor.
110     typedef blocking_adaptation_t polymorphic_query_result_type;
111 
112     /// Default constructor.
113     constexpr allowed_t();
114 
115     /// Get the value associated with a property object.
116     /**
117      * @returns allowed_t();
118      */
119     static constexpr blocking_adaptation_t value();
120   };
121 
122   /// A special value used for accessing the blocking_adaptation_t::disallowed_t
123   /// property.
124   static constexpr disallowed_t disallowed;
125 
126   /// A special value used for accessing the blocking_adaptation_t::allowed_t
127   /// property.
128   static constexpr allowed_t allowed;
129 
130   /// Default constructor.
131   constexpr blocking_adaptation_t();
132 
133   /// Construct from a sub-property value.
134   constexpr blocking_adaptation_t(disallowed_t);
135 
136   /// Construct from a sub-property value.
137   constexpr blocking_adaptation_t(allowed_t);
138 
139   /// Compare property values for equality.
140   friend constexpr bool operator==(
141       const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;
142 
143   /// Compare property values for inequality.
144   friend constexpr bool operator!=(
145       const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;
146 };
147 
148 /// A special value used for accessing the blocking_adaptation_t property.
149 constexpr blocking_adaptation_t blocking_adaptation;
150 
151 } // namespace execution
152 
153 #else // defined(GENERATING_DOCUMENTATION)
154 
155 namespace execution {
156 namespace detail {
157 namespace blocking_adaptation {
158 
159 template <int I> struct disallowed_t;
160 template <int I> struct allowed_t;
161 
162 } // namespace blocking_adaptation
163 
164 template <int I = 0>
165 struct blocking_adaptation_t
166 {
167 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
168   template <typename T>
169   BOOST_ASIO_STATIC_CONSTEXPR(bool,
170     is_applicable_property_v = (
171       is_executor<T>::value
172         || conditional<
173             is_executor<T>::value,
174             false_type,
175             is_sender<T>
176           >::type::value
177         || conditional<
178             is_executor<T>::value,
179             false_type,
180             is_scheduler<T>
181           >::type::value));
182 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
183 
184   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
185   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
186   typedef blocking_adaptation_t polymorphic_query_result_type;
187 
188   typedef detail::blocking_adaptation::disallowed_t<I> disallowed_t;
189   typedef detail::blocking_adaptation::allowed_t<I> allowed_t;
190 
191   BOOST_ASIO_CONSTEXPR blocking_adaptation_t()
192     : value_(-1)
193   {
194   }
195 
196   BOOST_ASIO_CONSTEXPR blocking_adaptation_t(disallowed_t)
197     : value_(0)
198   {
199   }
200 
201   BOOST_ASIO_CONSTEXPR blocking_adaptation_t(allowed_t)
202     : value_(1)
203   {
204   }
205 
206   template <typename T>
207   struct proxy
208   {
209 #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
210     struct type
211     {
212       template <typename P>
213       auto query(BOOST_ASIO_MOVE_ARG(P) p) const
214         noexcept(
215           noexcept(
216             declval<typename conditional<true, T, P>::type>().query(
217               BOOST_ASIO_MOVE_CAST(P)(p))
218           )
219         )
220         -> decltype(
221           declval<typename conditional<true, T, P>::type>().query(
222             BOOST_ASIO_MOVE_CAST(P)(p))
223         );
224     };
225 #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
226     typedef T type;
227 #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
228   };
229 
230   template <typename T>
231   struct static_proxy
232   {
233 #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
234     struct type
235     {
236       template <typename P>
237       static constexpr auto query(BOOST_ASIO_MOVE_ARG(P) p)
238         noexcept(
239           noexcept(
240             conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
241           )
242         )
243         -> decltype(
244           conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
245         )
246       {
247         return T::query(BOOST_ASIO_MOVE_CAST(P)(p));
248       }
249     };
250 #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
251     typedef T type;
252 #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
253   };
254 
255   template <typename T>
256   struct query_member :
257     traits::query_member<typename proxy<T>::type, blocking_adaptation_t> {};
258 
259   template <typename T>
260   struct query_static_constexpr_member :
261     traits::query_static_constexpr_member<
262       typename static_proxy<T>::type, blocking_adaptation_t> {};
263 
264 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
265   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
266   template <typename T>
267   static BOOST_ASIO_CONSTEXPR
268   typename query_static_constexpr_member<T>::result_type
269   static_query()
270     BOOST_ASIO_NOEXCEPT_IF((
271       query_static_constexpr_member<T>::is_noexcept))
272   {
273     return query_static_constexpr_member<T>::value();
274   }
275 
276   template <typename T>
277   static BOOST_ASIO_CONSTEXPR
278   typename traits::static_query<T, disallowed_t>::result_type
279   static_query(
280       typename enable_if<
281         !query_static_constexpr_member<T>::is_valid
282       >::type* = 0,
283       typename enable_if<
284         !query_member<T>::is_valid
285       >::type* = 0,
286       typename enable_if<
287         traits::static_query<T, disallowed_t>::is_valid
288       >::type* = 0) BOOST_ASIO_NOEXCEPT
289   {
290     return traits::static_query<T, disallowed_t>::value();
291   }
292 
293   template <typename T>
294   static BOOST_ASIO_CONSTEXPR
295   typename traits::static_query<T, allowed_t>::result_type
296   static_query(
297       typename enable_if<
298         !query_static_constexpr_member<T>::is_valid
299       >::type* = 0,
300       typename enable_if<
301         !query_member<T>::is_valid
302       >::type* = 0,
303       typename enable_if<
304         !traits::static_query<T, disallowed_t>::is_valid
305       >::type* = 0,
306       typename enable_if<
307         traits::static_query<T, allowed_t>::is_valid
308       >::type* = 0) BOOST_ASIO_NOEXCEPT
309   {
310     return traits::static_query<T, allowed_t>::value();
311   }
312 
313   template <typename E,
314       typename T = decltype(blocking_adaptation_t::static_query<E>())>
315   static BOOST_ASIO_CONSTEXPR const T static_query_v
316     = blocking_adaptation_t::static_query<E>();
317 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
318        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
319 
320   friend BOOST_ASIO_CONSTEXPR bool operator==(
321       const blocking_adaptation_t& a, const blocking_adaptation_t& b)
322   {
323     return a.value_ == b.value_;
324   }
325 
326   friend BOOST_ASIO_CONSTEXPR bool operator!=(
327       const blocking_adaptation_t& a, const blocking_adaptation_t& b)
328   {
329     return a.value_ != b.value_;
330   }
331 
332   struct convertible_from_blocking_adaptation_t
333   {
334     BOOST_ASIO_CONSTEXPR convertible_from_blocking_adaptation_t(
335         blocking_adaptation_t)
336     {
337     }
338   };
339 
340   template <typename Executor>
341   friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query(
342       const Executor& ex, convertible_from_blocking_adaptation_t,
343       typename enable_if<
344         can_query<const Executor&, disallowed_t>::value
345       >::type* = 0)
346 #if !defined(__clang__) // Clang crashes if noexcept is used here.
347 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
348     BOOST_ASIO_NOEXCEPT_IF((
349       is_nothrow_query<const Executor&,
350         blocking_adaptation_t<>::disallowed_t>::value))
351 #else // defined(BOOST_ASIO_MSVC)
352     BOOST_ASIO_NOEXCEPT_IF((
353       is_nothrow_query<const Executor&, disallowed_t>::value))
354 #endif // defined(BOOST_ASIO_MSVC)
355 #endif // !defined(__clang__)
356   {
357     return boost::asio::query(ex, disallowed_t());
358   }
359 
360   template <typename Executor>
361   friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query(
362       const Executor& ex, convertible_from_blocking_adaptation_t,
363       typename enable_if<
364         !can_query<const Executor&, disallowed_t>::value
365       >::type* = 0,
366       typename enable_if<
367         can_query<const Executor&, allowed_t>::value
368       >::type* = 0)
369 #if !defined(__clang__) // Clang crashes if noexcept is used here.
370 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
371     BOOST_ASIO_NOEXCEPT_IF((
372       is_nothrow_query<const Executor&,
373         blocking_adaptation_t<>::allowed_t>::value))
374 #else // defined(BOOST_ASIO_MSVC)
375     BOOST_ASIO_NOEXCEPT_IF((
376       is_nothrow_query<const Executor&, allowed_t>::value))
377 #endif // defined(BOOST_ASIO_MSVC)
378 #endif // !defined(__clang__)
379   {
380     return boost::asio::query(ex, allowed_t());
381   }
382 
383   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed);
384   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed);
385 
386 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
387   static const blocking_adaptation_t instance;
388 #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR)
389 
390 private:
391   int value_;
392 };
393 
394 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
395   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
396 template <int I> template <typename E, typename T>
397 const T blocking_adaptation_t<I>::static_query_v;
398 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
399        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
400 
401 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
402 template <int I>
403 const blocking_adaptation_t<I> blocking_adaptation_t<I>::instance;
404 #endif
405 
406 template <int I>
407 const typename blocking_adaptation_t<I>::disallowed_t
408 blocking_adaptation_t<I>::disallowed;
409 
410 template <int I>
411 const typename blocking_adaptation_t<I>::allowed_t
412 blocking_adaptation_t<I>::allowed;
413 
414 namespace blocking_adaptation {
415 
416 template <int I = 0>
417 struct disallowed_t
418 {
419 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
420   template <typename T>
421   BOOST_ASIO_STATIC_CONSTEXPR(bool,
422     is_applicable_property_v = (
423       is_executor<T>::value
424         || conditional<
425             is_executor<T>::value,
426             false_type,
427             is_sender<T>
428           >::type::value
429         || conditional<
430             is_executor<T>::value,
431             false_type,
432             is_scheduler<T>
433           >::type::value));
434 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
435 
436   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
437   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
438   typedef blocking_adaptation_t<I> polymorphic_query_result_type;
439 
440   BOOST_ASIO_CONSTEXPR disallowed_t()
441   {
442   }
443 
444   template <typename T>
445   struct query_member :
446     traits::query_member<
447       typename blocking_adaptation_t<I>::template proxy<T>::type,
448         disallowed_t> {};
449 
450   template <typename T>
451   struct query_static_constexpr_member :
452     traits::query_static_constexpr_member<
453       typename blocking_adaptation_t<I>::template static_proxy<T>::type,
454         disallowed_t> {};
455 
456 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
457   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
458   template <typename T>
459   static BOOST_ASIO_CONSTEXPR
460   typename query_static_constexpr_member<T>::result_type
461   static_query()
462     BOOST_ASIO_NOEXCEPT_IF((
463       query_static_constexpr_member<T>::is_noexcept))
464   {
465     return query_static_constexpr_member<T>::value();
466   }
467 
468   template <typename T>
469   static BOOST_ASIO_CONSTEXPR disallowed_t static_query(
470       typename enable_if<
471         !query_static_constexpr_member<T>::is_valid
472       >::type* = 0,
473       typename enable_if<
474         !query_member<T>::is_valid
475       >::type* = 0,
476       typename enable_if<
477         !traits::query_free<T, disallowed_t>::is_valid
478       >::type* = 0,
479       typename enable_if<
480         !can_query<T, allowed_t<I> >::value
481       >::type* = 0) BOOST_ASIO_NOEXCEPT
482   {
483     return disallowed_t();
484   }
485 
486   template <typename E, typename T = decltype(disallowed_t::static_query<E>())>
487   static BOOST_ASIO_CONSTEXPR const T static_query_v
488     = disallowed_t::static_query<E>();
489 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
490        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
491 
492   static BOOST_ASIO_CONSTEXPR blocking_adaptation_t<I> value()
493   {
494     return disallowed_t();
495   }
496 
497   friend BOOST_ASIO_CONSTEXPR bool operator==(
498       const disallowed_t&, const disallowed_t&)
499   {
500     return true;
501   }
502 
503   friend BOOST_ASIO_CONSTEXPR bool operator!=(
504       const disallowed_t&, const disallowed_t&)
505   {
506     return false;
507   }
508 };
509 
510 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
511   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
512 template <int I> template <typename E, typename T>
513 const T disallowed_t<I>::static_query_v;
514 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
515        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
516 
517 template <typename Executor>
518 class adapter
519 {
520 public:
521   adapter(int, const Executor& e) BOOST_ASIO_NOEXCEPT
522     : executor_(e)
523   {
524   }
525 
526   adapter(const adapter& other) BOOST_ASIO_NOEXCEPT
527     : executor_(other.executor_)
528   {
529   }
530 
531 #if defined(BOOST_ASIO_HAS_MOVE)
532   adapter(adapter&& other) BOOST_ASIO_NOEXCEPT
533     : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_))
534   {
535   }
536 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
537 
538   template <int I>
539   static BOOST_ASIO_CONSTEXPR allowed_t<I> query(
540       blocking_adaptation_t<I>) BOOST_ASIO_NOEXCEPT
541   {
542     return allowed_t<I>();
543   }
544 
545   template <int I>
546   static BOOST_ASIO_CONSTEXPR allowed_t<I> query(
547       allowed_t<I>) BOOST_ASIO_NOEXCEPT
548   {
549     return allowed_t<I>();
550   }
551 
552   template <int I>
553   static BOOST_ASIO_CONSTEXPR allowed_t<I> query(
554       disallowed_t<I>) BOOST_ASIO_NOEXCEPT
555   {
556     return allowed_t<I>();
557   }
558 
559   template <typename Property>
560   typename enable_if<
561     can_query<const Executor&, Property>::value,
562     typename query_result<const Executor&, Property>::type
563   >::type query(const Property& p) const
564     BOOST_ASIO_NOEXCEPT_IF((
565       is_nothrow_query<const Executor&, Property>::value))
566   {
567     return boost::asio::query(executor_, p);
568   }
569 
570   template <int I>
571   Executor require(disallowed_t<I>) const BOOST_ASIO_NOEXCEPT
572   {
573     return executor_;
574   }
575 
576   template <typename Property>
577   typename enable_if<
578     can_require<const Executor&, Property>::value,
579     adapter<typename decay<
580       typename require_result<const Executor&, Property>::type
581     >::type>
582   >::type require(const Property& p) const
583     BOOST_ASIO_NOEXCEPT_IF((
584       is_nothrow_require<const Executor&, Property>::value))
585   {
586     return adapter<typename decay<
587       typename require_result<const Executor&, Property>::type
588         >::type>(0, boost::asio::require(executor_, p));
589   }
590 
591   template <typename Property>
592   typename enable_if<
593     can_prefer<const Executor&, Property>::value,
594     adapter<typename decay<
595       typename prefer_result<const Executor&, Property>::type
596     >::type>
597   >::type prefer(const Property& p) const
598     BOOST_ASIO_NOEXCEPT_IF((
599       is_nothrow_prefer<const Executor&, Property>::value))
600   {
601     return adapter<typename decay<
602       typename prefer_result<const Executor&, Property>::type
603         >::type>(0, boost::asio::prefer(executor_, p));
604   }
605 
606   template <typename Function>
607   typename enable_if<
608     execution::can_execute<const Executor&, Function>::value
609   >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const
610   {
611     execution::execute(executor_, BOOST_ASIO_MOVE_CAST(Function)(f));
612   }
613 
614   friend bool operator==(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
615   {
616     return a.executor_ == b.executor_;
617   }
618 
619   friend bool operator!=(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
620   {
621     return a.executor_ != b.executor_;
622   }
623 
624 private:
625   Executor executor_;
626 };
627 
628 template <int I = 0>
629 struct allowed_t
630 {
631 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
632   template <typename T>
633   BOOST_ASIO_STATIC_CONSTEXPR(bool,
634     is_applicable_property_v = (
635       is_executor<T>::value
636         || conditional<
637             is_executor<T>::value,
638             false_type,
639             is_sender<T>
640           >::type::value
641         || conditional<
642             is_executor<T>::value,
643             false_type,
644             is_scheduler<T>
645           >::type::value));
646 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
647 
648   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
649   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
650   typedef blocking_adaptation_t<I> polymorphic_query_result_type;
651 
652   BOOST_ASIO_CONSTEXPR allowed_t()
653   {
654   }
655 
656   template <typename T>
657   struct query_member :
658     traits::query_member<
659       typename blocking_adaptation_t<I>::template proxy<T>::type,
660         allowed_t> {};
661 
662   template <typename T>
663   struct query_static_constexpr_member :
664     traits::query_static_constexpr_member<
665       typename blocking_adaptation_t<I>::template static_proxy<T>::type,
666         allowed_t> {};
667 
668 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
669   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
670   template <typename T>
671   static BOOST_ASIO_CONSTEXPR
672   typename query_static_constexpr_member<T>::result_type
673   static_query()
674     BOOST_ASIO_NOEXCEPT_IF((
675       query_static_constexpr_member<T>::is_noexcept))
676   {
677     return query_static_constexpr_member<T>::value();
678   }
679 
680   template <typename E, typename T = decltype(allowed_t::static_query<E>())>
681   static BOOST_ASIO_CONSTEXPR const T static_query_v
682     = allowed_t::static_query<E>();
683 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
684        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
685 
686   static BOOST_ASIO_CONSTEXPR blocking_adaptation_t<I> value()
687   {
688     return allowed_t();
689   }
690 
691   friend BOOST_ASIO_CONSTEXPR bool operator==(
692       const allowed_t&, const allowed_t&)
693   {
694     return true;
695   }
696 
697   friend BOOST_ASIO_CONSTEXPR bool operator!=(
698       const allowed_t&, const allowed_t&)
699   {
700     return false;
701   }
702 
703   template <typename Executor>
704   friend adapter<Executor> require(
705       const Executor& e, const allowed_t&,
706       typename enable_if<
707         is_executor<Executor>::value
708       >::type* = 0)
709   {
710     return adapter<Executor>(0, e);
711   }
712 };
713 
714 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
715   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
716 template <int I> template <typename E, typename T>
717 const T allowed_t<I>::static_query_v;
718 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
719        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
720 
721 template <typename Function>
722 class blocking_execute_state
723 {
724 public:
725   template <typename F>
726   blocking_execute_state(BOOST_ASIO_MOVE_ARG(F) f)
727     : func_(BOOST_ASIO_MOVE_CAST(F)(f)),
728       is_complete_(false)
729   {
730   }
731 
732   template <typename Executor>
733   void execute_and_wait(BOOST_ASIO_MOVE_ARG(Executor) ex)
734   {
735     handler h = { this };
736     execution::execute(BOOST_ASIO_MOVE_CAST(Executor)(ex), h);
737     boost::asio::detail::mutex::scoped_lock lock(mutex_);
738     while (!is_complete_)
739       event_.wait(lock);
740   }
741 
742   struct cleanup
743   {
744     ~cleanup()
745     {
746       boost::asio::detail::mutex::scoped_lock lock(state_->mutex_);
747       state_->is_complete_ = true;
748       state_->event_.unlock_and_signal_one_for_destruction(lock);
749     }
750 
751     blocking_execute_state* state_;
752   };
753 
754   struct handler
755   {
756     void operator()()
757     {
758       cleanup c = { state_ };
759       state_->func_();
760     }
761 
762     blocking_execute_state* state_;
763   };
764 
765   Function func_;
766   boost::asio::detail::mutex mutex_;
767   boost::asio::detail::event event_;
768   bool is_complete_;
769 };
770 
771 template <typename Executor, typename Function>
772 void blocking_execute(
773     BOOST_ASIO_MOVE_ARG(Executor) ex,
774     BOOST_ASIO_MOVE_ARG(Function) func)
775 {
776   typedef typename decay<Function>::type func_t;
777   blocking_execute_state<func_t> state(BOOST_ASIO_MOVE_CAST(Function)(func));
778   state.execute_and_wait(ex);
779 }
780 
781 } // namespace blocking_adaptation
782 } // namespace detail
783 
784 typedef detail::blocking_adaptation_t<> blocking_adaptation_t;
785 
786 #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
787 constexpr blocking_adaptation_t blocking_adaptation;
788 #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
789 namespace { static const blocking_adaptation_t&
790   blocking_adaptation = blocking_adaptation_t::instance; }
791 #endif
792 
793 } // namespace execution
794 
795 #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
796 
797 template <typename T>
798 struct is_applicable_property<T, execution::blocking_adaptation_t>
799   : integral_constant<bool,
800       execution::is_executor<T>::value
801         || conditional<
802             execution::is_executor<T>::value,
803             false_type,
804             execution::is_sender<T>
805           >::type::value
806         || conditional<
807             execution::is_executor<T>::value,
808             false_type,
809             execution::is_scheduler<T>
810           >::type::value>
811 {
812 };
813 
814 template <typename T>
815 struct is_applicable_property<T, execution::blocking_adaptation_t::disallowed_t>
816   : integral_constant<bool,
817       execution::is_executor<T>::value
818         || conditional<
819             execution::is_executor<T>::value,
820             false_type,
821             execution::is_sender<T>
822           >::type::value
823         || conditional<
824             execution::is_executor<T>::value,
825             false_type,
826             execution::is_scheduler<T>
827           >::type::value>
828 {
829 };
830 
831 template <typename T>
832 struct is_applicable_property<T, execution::blocking_adaptation_t::allowed_t>
833   : integral_constant<bool,
834       execution::is_executor<T>::value
835         || conditional<
836             execution::is_executor<T>::value,
837             false_type,
838             execution::is_sender<T>
839           >::type::value
840         || conditional<
841             execution::is_executor<T>::value,
842             false_type,
843             execution::is_scheduler<T>
844           >::type::value>
845 {
846 };
847 
848 #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
849 
850 namespace traits {
851 
852 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
853 
854 template <typename T>
855 struct query_free_default<T, execution::blocking_adaptation_t,
856   typename enable_if<
857     can_query<T, execution::blocking_adaptation_t::disallowed_t>::value
858   >::type>
859 {
860   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
861   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T,
862       execution::blocking_adaptation_t::disallowed_t>::value));
863 
864   typedef execution::blocking_adaptation_t result_type;
865 };
866 
867 template <typename T>
868 struct query_free_default<T, execution::blocking_adaptation_t,
869   typename enable_if<
870     !can_query<T, execution::blocking_adaptation_t::disallowed_t>::value
871       && can_query<T, execution::blocking_adaptation_t::allowed_t>::value
872   >::type>
873 {
874   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
875   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
876     (is_nothrow_query<T, execution::blocking_adaptation_t::allowed_t>::value));
877 
878   typedef execution::blocking_adaptation_t result_type;
879 };
880 
881 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
882 
883 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
884   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
885 
886 template <typename T>
887 struct static_query<T, execution::blocking_adaptation_t,
888   typename enable_if<
889     execution::detail::blocking_adaptation_t<0>::
890       query_static_constexpr_member<T>::is_valid
891   >::type>
892 {
893   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
894   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
895 
896   typedef typename execution::detail::blocking_adaptation_t<0>::
897     query_static_constexpr_member<T>::result_type result_type;
898 
899   static BOOST_ASIO_CONSTEXPR result_type value()
900   {
901     return execution::detail::blocking_adaptation_t<0>::
902       query_static_constexpr_member<T>::value();
903   }
904 };
905 
906 template <typename T>
907 struct static_query<T, execution::blocking_adaptation_t,
908   typename enable_if<
909     !execution::detail::blocking_adaptation_t<0>::
910         query_static_constexpr_member<T>::is_valid
911       && !execution::detail::blocking_adaptation_t<0>::
912         query_member<T>::is_valid
913       && traits::static_query<T,
914         execution::blocking_adaptation_t::disallowed_t>::is_valid
915   >::type>
916 {
917   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
918   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
919 
920   typedef typename traits::static_query<T,
921     execution::blocking_adaptation_t::disallowed_t>::result_type result_type;
922 
923   static BOOST_ASIO_CONSTEXPR result_type value()
924   {
925     return traits::static_query<T,
926         execution::blocking_adaptation_t::disallowed_t>::value();
927   }
928 };
929 
930 template <typename T>
931 struct static_query<T, execution::blocking_adaptation_t,
932   typename enable_if<
933     !execution::detail::blocking_adaptation_t<0>::
934         query_static_constexpr_member<T>::is_valid
935       && !execution::detail::blocking_adaptation_t<0>::
936         query_member<T>::is_valid
937       && !traits::static_query<T,
938         execution::blocking_adaptation_t::disallowed_t>::is_valid
939       && traits::static_query<T,
940         execution::blocking_adaptation_t::allowed_t>::is_valid
941   >::type>
942 {
943   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
944   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
945 
946   typedef typename traits::static_query<T,
947     execution::blocking_adaptation_t::allowed_t>::result_type result_type;
948 
949   static BOOST_ASIO_CONSTEXPR result_type value()
950   {
951     return traits::static_query<T,
952         execution::blocking_adaptation_t::allowed_t>::value();
953   }
954 };
955 
956 template <typename T>
957 struct static_query<T, execution::blocking_adaptation_t::disallowed_t,
958   typename enable_if<
959     execution::detail::blocking_adaptation::disallowed_t<0>::
960       query_static_constexpr_member<T>::is_valid
961   >::type>
962 {
963   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
964   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
965 
966   typedef typename execution::detail::blocking_adaptation::disallowed_t<0>::
967     query_static_constexpr_member<T>::result_type result_type;
968 
969   static BOOST_ASIO_CONSTEXPR result_type value()
970   {
971     return execution::detail::blocking_adaptation::disallowed_t<0>::
972       query_static_constexpr_member<T>::value();
973   }
974 };
975 
976 template <typename T>
977 struct static_query<T, execution::blocking_adaptation_t::disallowed_t,
978   typename enable_if<
979     !execution::detail::blocking_adaptation::disallowed_t<0>::
980         query_static_constexpr_member<T>::is_valid
981       && !execution::detail::blocking_adaptation::disallowed_t<0>::
982         query_member<T>::is_valid
983       && !traits::query_free<T,
984         execution::blocking_adaptation_t::disallowed_t>::is_valid
985       && !can_query<T, execution::blocking_adaptation_t::allowed_t>::value
986   >::type>
987 {
988   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
989   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
990 
991   typedef execution::blocking_adaptation_t::disallowed_t result_type;
992 
993   static BOOST_ASIO_CONSTEXPR result_type value()
994   {
995     return result_type();
996   }
997 };
998 
999 template <typename T>
1000 struct static_query<T, execution::blocking_adaptation_t::allowed_t,
1001   typename enable_if<
1002     execution::detail::blocking_adaptation::allowed_t<0>::
1003       query_static_constexpr_member<T>::is_valid
1004   >::type>
1005 {
1006   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1007   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1008 
1009   typedef typename execution::detail::blocking_adaptation::allowed_t<0>::
1010     query_static_constexpr_member<T>::result_type result_type;
1011 
1012   static BOOST_ASIO_CONSTEXPR result_type value()
1013   {
1014     return execution::detail::blocking_adaptation::allowed_t<0>::
1015       query_static_constexpr_member<T>::value();
1016   }
1017 };
1018 
1019 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
1020        //   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
1021 
1022 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
1023 
1024 template <typename T>
1025 struct static_require<T, execution::blocking_adaptation_t::disallowed_t,
1026   typename enable_if<
1027     static_query<T, execution::blocking_adaptation_t::disallowed_t>::is_valid
1028   >::type>
1029 {
1030   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1031     (is_same<typename static_query<T,
1032       execution::blocking_adaptation_t::disallowed_t>::result_type,
1033         execution::blocking_adaptation_t::disallowed_t>::value));
1034 };
1035 
1036 template <typename T>
1037 struct static_require<T, execution::blocking_adaptation_t::allowed_t,
1038   typename enable_if<
1039     static_query<T, execution::blocking_adaptation_t::allowed_t>::is_valid
1040   >::type>
1041 {
1042   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
1043     (is_same<typename static_query<T,
1044       execution::blocking_adaptation_t::allowed_t>::result_type,
1045         execution::blocking_adaptation_t::allowed_t>::value));
1046 };
1047 
1048 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
1049 
1050 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
1051 
1052 template <typename T>
1053 struct require_free_default<T, execution::blocking_adaptation_t::allowed_t,
1054   typename enable_if<
1055     is_same<T, typename decay<T>::type>::value
1056       && execution::is_executor<T>::value
1057   >::type>
1058 {
1059   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1060   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
1061   typedef execution::detail::blocking_adaptation::adapter<T> result_type;
1062 };
1063 
1064 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
1065 
1066 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1067 
1068 template <typename Executor>
1069 struct equality_comparable<
1070   execution::detail::blocking_adaptation::adapter<Executor> >
1071 {
1072   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1073   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1074 };
1075 
1076 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1077 
1078 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1079 
1080 template <typename Executor, typename Function>
1081 struct execute_member<
1082   execution::detail::blocking_adaptation::adapter<Executor>, Function>
1083 {
1084   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1085   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
1086   typedef void result_type;
1087 };
1088 
1089 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1090 
1091 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1092 
1093 template <typename Executor, int I>
1094 struct query_static_constexpr_member<
1095   execution::detail::blocking_adaptation::adapter<Executor>,
1096   execution::detail::blocking_adaptation_t<I> >
1097 {
1098   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1099   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1100   typedef execution::blocking_adaptation_t::allowed_t result_type;
1101 
1102   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1103   {
1104     return result_type();
1105   }
1106 };
1107 
1108 template <typename Executor, int I>
1109 struct query_static_constexpr_member<
1110   execution::detail::blocking_adaptation::adapter<Executor>,
1111   execution::detail::blocking_adaptation::allowed_t<I> >
1112 {
1113   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1114   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1115   typedef execution::blocking_adaptation_t::allowed_t result_type;
1116 
1117   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1118   {
1119     return result_type();
1120   }
1121 };
1122 
1123 template <typename Executor, int I>
1124 struct query_static_constexpr_member<
1125   execution::detail::blocking_adaptation::adapter<Executor>,
1126   execution::detail::blocking_adaptation::disallowed_t<I> >
1127 {
1128   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1129   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1130   typedef execution::blocking_adaptation_t::allowed_t result_type;
1131 
1132   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1133   {
1134     return result_type();
1135   }
1136 };
1137 
1138 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1139 
1140 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1141 
1142 template <typename Executor, typename Property>
1143 struct query_member<
1144   execution::detail::blocking_adaptation::adapter<Executor>, Property,
1145   typename enable_if<
1146     can_query<const Executor&, Property>::value
1147   >::type>
1148 {
1149   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1150   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1151       (is_nothrow_query<Executor, Property>::value));
1152   typedef typename query_result<Executor, Property>::type result_type;
1153 };
1154 
1155 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1156 
1157 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1158 
1159 template <typename Executor, int I>
1160 struct require_member<
1161   execution::detail::blocking_adaptation::adapter<Executor>,
1162   execution::detail::blocking_adaptation::disallowed_t<I> >
1163 {
1164   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1165   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1166   typedef Executor result_type;
1167 };
1168 
1169 template <typename Executor, typename Property>
1170 struct require_member<
1171   execution::detail::blocking_adaptation::adapter<Executor>, Property,
1172   typename enable_if<
1173     can_require<const Executor&, Property>::value
1174   >::type>
1175 {
1176   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1177   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1178       (is_nothrow_require<Executor, Property>::value));
1179   typedef execution::detail::blocking_adaptation::adapter<typename decay<
1180     typename require_result<Executor, Property>::type
1181       >::type> result_type;
1182 };
1183 
1184 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1185 
1186 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1187 
1188 template <typename Executor, typename Property>
1189 struct prefer_member<
1190   execution::detail::blocking_adaptation::adapter<Executor>, Property,
1191   typename enable_if<
1192     can_prefer<const Executor&, Property>::value
1193   >::type>
1194 {
1195   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1196   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1197       (is_nothrow_prefer<Executor, Property>::value));
1198   typedef execution::detail::blocking_adaptation::adapter<typename decay<
1199     typename prefer_result<Executor, Property>::type
1200       >::type> result_type;
1201 };
1202 
1203 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1204 
1205 } // namespace traits
1206 
1207 #endif // defined(GENERATING_DOCUMENTATION)
1208 
1209 } // namespace asio
1210 } // namespace boost
1211 
1212 #include <boost/asio/detail/pop_options.hpp>
1213 
1214 #endif // BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP
1215