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