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