inline_or_executor.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. //
  2. // inline_or_executor.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 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. #ifndef BOOST_ASIO_INLINE_OR_EXECUTOR_HPP
  11. #define BOOST_ASIO_INLINE_OR_EXECUTOR_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/detail/non_const_lvalue.hpp>
  17. #include <boost/asio/detail/type_traits.hpp>
  18. #include <boost/asio/execution/blocking.hpp>
  19. #include <boost/asio/execution/executor.hpp>
  20. #include <boost/asio/execution/inline_exception_handling.hpp>
  21. #include <boost/asio/execution_context.hpp>
  22. #include <boost/asio/is_executor.hpp>
  23. #include <boost/asio/detail/push_options.hpp>
  24. namespace boost {
  25. namespace asio {
  26. /// Adapts an executor to add inline invocation of the submitted function.
  27. /**
  28. * The @c inline_or_executor class template adapts an existing executor such
  29. * that:
  30. *
  31. * @li posted function objects (or when the @c blocking property is set to
  32. * @c blocking.never) are submitted to the wrapped executor; and
  33. *
  34. * @li dispatched function objects (or when @c blocking is @c blocking.always or
  35. * @c blocking.possibly) are executed inline.
  36. */
  37. template <typename Executor,
  38. typename Blocking = execution::blocking_t::always_t,
  39. typename InlineExceptionHandling
  40. = execution::inline_exception_handling_t::propagate_t>
  41. class inline_or_executor
  42. {
  43. public:
  44. /// The type of the underlying executor.
  45. typedef Executor inner_executor_type;
  46. /// Default constructor.
  47. /**
  48. * This constructor is only valid if the underlying executor type is default
  49. * constructible.
  50. */
  51. inline_or_executor()
  52. : executor_()
  53. {
  54. }
  55. /// Construct an inline_or_executor for the specified executor.
  56. template <typename Executor1>
  57. explicit inline_or_executor(const Executor1& e,
  58. constraint_t<
  59. conditional_t<
  60. !is_same<Executor1, inline_or_executor>::value,
  61. is_convertible<Executor1, Executor>,
  62. false_type
  63. >::value
  64. > = 0)
  65. : executor_(e)
  66. {
  67. }
  68. /// Copy constructor.
  69. inline_or_executor(const inline_or_executor& other) noexcept
  70. : executor_(other.executor_)
  71. {
  72. }
  73. /// Converting constructor.
  74. /**
  75. * This constructor is only valid if the @c OtherExecutor type is convertible
  76. * to @c Executor.
  77. */
  78. template <class OtherExecutor>
  79. inline_or_executor(
  80. const inline_or_executor<OtherExecutor>& other) noexcept
  81. : executor_(other.executor_)
  82. {
  83. }
  84. /// Assignment operator.
  85. inline_or_executor& operator=(const inline_or_executor& other) noexcept
  86. {
  87. executor_ = other.executor_;
  88. return *this;
  89. }
  90. /// Converting assignment operator.
  91. /**
  92. * This assignment operator is only valid if the @c OtherExecutor type is
  93. * convertible to @c Executor.
  94. */
  95. template <class OtherExecutor>
  96. inline_or_executor& operator=(
  97. const inline_or_executor<OtherExecutor>& other) noexcept
  98. {
  99. executor_ = other.executor_;
  100. return *this;
  101. }
  102. /// Move constructor.
  103. inline_or_executor(inline_or_executor&& other) noexcept
  104. : executor_(static_cast<Executor&&>(other.executor_))
  105. {
  106. }
  107. /// Converting move constructor.
  108. /**
  109. * This constructor is only valid if the @c OtherExecutor type is convertible
  110. * to @c Executor.
  111. */
  112. template <class OtherExecutor>
  113. inline_or_executor(inline_or_executor<OtherExecutor>&& other) noexcept
  114. : executor_(static_cast<OtherExecutor&&>(other.executor_))
  115. {
  116. }
  117. /// Move assignment operator.
  118. inline_or_executor& operator=(inline_or_executor&& other) noexcept
  119. {
  120. executor_ = static_cast<Executor&&>(other.executor_);
  121. return *this;
  122. }
  123. /// Converting move assignment operator.
  124. /**
  125. * This assignment operator is only valid if the @c OtherExecutor type is
  126. * convertible to @c Executor.
  127. */
  128. template <class OtherExecutor>
  129. inline_or_executor& operator=(
  130. inline_or_executor<OtherExecutor>&& other) noexcept
  131. {
  132. executor_ = static_cast<OtherExecutor&&>(other.executor_);
  133. return *this;
  134. }
  135. /// Destructor.
  136. ~inline_or_executor() noexcept
  137. {
  138. }
  139. /// Obtain the underlying executor.
  140. inner_executor_type get_inner_executor() const noexcept
  141. {
  142. return executor_;
  143. }
  144. /// Query the current value of the @c blocking property.
  145. /**
  146. * Do not call this function directly. It is intended for use with the
  147. * boost::asio::query customisation point.
  148. *
  149. * For example:
  150. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  151. * if (boost::asio::query(ex, boost::asio::execution::blocking)
  152. * == boost::asio::execution::blocking.possibly)
  153. * ... @endcode
  154. */
  155. static constexpr execution::blocking_t query(execution::blocking_t) noexcept
  156. {
  157. return Blocking();
  158. }
  159. /// Query the current value of the @c inline_exception_handling property.
  160. /**
  161. * Do not call this function directly. It is intended for use with the
  162. * boost::asio::query customisation point.
  163. *
  164. * For example:
  165. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  166. * if (boost::asio::query(ex,
  167. * boost::asio::execution::inline_exception_handling)
  168. * == boost::asio::execution::inline_exception_handling.propagate)
  169. * ... @endcode
  170. */
  171. static constexpr execution::inline_exception_handling_t query(
  172. execution::inline_exception_handling_t) noexcept
  173. {
  174. return InlineExceptionHandling();
  175. }
  176. /// Forward a query to the underlying executor.
  177. /**
  178. * Do not call this function directly. It is intended for use with the
  179. * boost::asio::query customisation point.
  180. *
  181. * For example:
  182. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  183. * if (boost::asio::query(ex, boost::asio::execution::blocking)
  184. * == boost::asio::execution::blocking.never)
  185. * ... @endcode
  186. */
  187. template <typename Property>
  188. query_result_t<const Executor&, Property> query(const Property& p,
  189. constraint_t<
  190. can_query<const Executor&, Property>::value
  191. > = 0,
  192. constraint_t<
  193. !is_convertible<Property, execution::blocking_t>::value
  194. > = 0,
  195. constraint_t<
  196. !is_convertible<Property, execution::inline_exception_handling_t>::value
  197. > = 0) const
  198. noexcept(is_nothrow_query<const Executor&, Property>::value)
  199. {
  200. return boost::asio::query(executor_, p);
  201. }
  202. /// Obtain an executor with the @c blocking.possibly property.
  203. /**
  204. * Do not call this function directly. It is intended for use with the
  205. * boost::asio::require customisation point.
  206. *
  207. * For example:
  208. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  209. * auto ex2 = boost::asio::require(ex1,
  210. * boost::asio::execution::blocking.possibly); @endcode
  211. */
  212. inline_or_executor<Executor, execution::blocking_t::possibly_t,
  213. InlineExceptionHandling>
  214. require(const execution::blocking_t::possibly_t&) const noexcept
  215. {
  216. return inline_or_executor<Executor, execution::blocking_t::possibly_t,
  217. InlineExceptionHandling>(executor_);
  218. }
  219. /// Obtain an executor with the @c blocking.always property.
  220. /**
  221. * Do not call this function directly. It is intended for use with the
  222. * boost::asio::require customisation point.
  223. *
  224. * For example:
  225. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  226. * auto ex2 = boost::asio::require(ex1,
  227. * boost::asio::execution::blocking.always); @endcode
  228. */
  229. inline_or_executor<Executor, execution::blocking_t::always_t,
  230. InlineExceptionHandling>
  231. require(const execution::blocking_t::always_t&) const noexcept
  232. {
  233. return inline_or_executor<Executor, execution::blocking_t::always_t,
  234. InlineExceptionHandling>(executor_);
  235. }
  236. /// Obtain an executor with the @c blocking.never property.
  237. /**
  238. * Do not call this function directly. It is intended for use with the
  239. * boost::asio::require customisation point.
  240. *
  241. * For example:
  242. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  243. * auto ex2 = boost::asio::require(ex1,
  244. * boost::asio::execution::blocking.never); @endcode
  245. */
  246. inline_or_executor<Executor, execution::blocking_t::never_t,
  247. InlineExceptionHandling>
  248. require(const execution::blocking_t::never_t&) const noexcept
  249. {
  250. return inline_or_executor<Executor, execution::blocking_t::never_t,
  251. InlineExceptionHandling>(executor_);
  252. }
  253. /// Obtain an executor with the @c inline_exception_handling.propagate
  254. /// property.
  255. /**
  256. * Do not call this function directly. It is intended for use with the
  257. * boost::asio::require customisation point.
  258. *
  259. * For example:
  260. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  261. * auto ex2 = boost::asio::require(ex1,
  262. * boost::asio::execution::inline_exception_handling.propagate); @endcode
  263. */
  264. inline_or_executor<Executor, Blocking,
  265. execution::inline_exception_handling_t::propagate_t>
  266. require(const execution::inline_exception_handling_t::propagate_t&)
  267. const noexcept
  268. {
  269. return inline_or_executor<Executor, Blocking,
  270. execution::inline_exception_handling_t::propagate_t>(executor_);
  271. }
  272. /// Obtain an executor with the @c inline_exception_handling.terminate
  273. /// property.
  274. /**
  275. * Do not call this function directly. It is intended for use with the
  276. * boost::asio::require customisation point.
  277. *
  278. * For example:
  279. * @code boost::asio::inline_or_executor<my_executor_type> ex = ...;
  280. * auto ex2 = boost::asio::require(ex1,
  281. * boost::asio::execution::inline_exception_handling.terminate); @endcode
  282. */
  283. inline_or_executor<Executor, Blocking,
  284. execution::inline_exception_handling_t::terminate_t>
  285. require(const execution::inline_exception_handling_t::terminate_t&)
  286. const noexcept
  287. {
  288. return inline_or_executor<Executor, Blocking,
  289. execution::inline_exception_handling_t::terminate_t>(executor_);
  290. }
  291. /// Forward a requirement to the underlying executor.
  292. /**
  293. * Do not call this function directly. It is intended for use with the
  294. * boost::asio::require customisation point.
  295. *
  296. * For example:
  297. * @code boost::asio::inline_or_executor<my_executor_type> ex1 = ...;
  298. * auto ex2 = boost::asio::require(ex1,
  299. * boost::asio::execution::relationship.continuation); @endcode
  300. */
  301. template <typename Property>
  302. inline_or_executor<decay_t<require_result_t<const Executor&, Property>>,
  303. Blocking, InlineExceptionHandling>
  304. require(const Property& p,
  305. constraint_t<
  306. can_require<const Executor&, Property>::value
  307. > = 0,
  308. constraint_t<
  309. !is_convertible<Property, execution::blocking_t>::value
  310. > = 0,
  311. constraint_t<
  312. !is_convertible<Property, execution::inline_exception_handling_t>::value
  313. > = 0) const
  314. noexcept(is_nothrow_require<const Executor&, Property>::value)
  315. {
  316. return inline_or_executor<
  317. decay_t<require_result_t<const Executor&, Property>>,
  318. Blocking, InlineExceptionHandling>(boost::asio::require(executor_, p));
  319. }
  320. /// Forward a preference to the underlying executor.
  321. /**
  322. * Do not call this function directly. It is intended for use with the
  323. * boost::asio::prefer customisation point.
  324. *
  325. * For example:
  326. * @code boost::asio::inline_or_executor<my_executor_type> ex1 = ...;
  327. * auto ex2 = boost::asio::prefer(ex1,
  328. * boost::asio::execution::relationship.continuation); @endcode
  329. */
  330. template <typename Property>
  331. inline_or_executor<decay_t<prefer_result_t<const Executor&, Property>>,
  332. Blocking, InlineExceptionHandling>
  333. prefer(const Property& p,
  334. constraint_t<
  335. can_prefer<const Executor&, Property>::value
  336. > = 0,
  337. constraint_t<
  338. !is_convertible<Property, execution::blocking_t>::value
  339. > = 0,
  340. constraint_t<
  341. !is_convertible<Property, execution::inline_exception_handling_t>::value
  342. > = 0) const
  343. noexcept(is_nothrow_prefer<const Executor&, Property>::value)
  344. {
  345. return inline_or_executor<
  346. decay_t<prefer_result_t<const Executor&, Property>>,
  347. Blocking, InlineExceptionHandling>(boost::asio::prefer(executor_, p));
  348. }
  349. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  350. /// Obtain the underlying execution context.
  351. execution_context& context() const noexcept
  352. {
  353. return executor_.context();
  354. }
  355. /// Inform the inline_or_executor that it has some outstanding work to do.
  356. /**
  357. * The inline_or_executor delegates this call to its underlying executor.
  358. */
  359. void on_work_started() const noexcept
  360. {
  361. executor_.on_work_started();
  362. }
  363. /// Inform the inline_or_executor that some work is no longer outstanding.
  364. /**
  365. * The inline_or_executor delegates this call to its underlying executor.
  366. */
  367. void on_work_finished() const noexcept
  368. {
  369. executor_.on_work_finished();
  370. }
  371. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  372. /// Request the inline_or_executor to invoke the given function object.
  373. /**
  374. * This function is used to ask the inline_or_executor to execute the given
  375. * function object. The function object will be executed inline or according
  376. * to the properties of the underlying executor.
  377. *
  378. * @param f The function object to be called. The executor will make
  379. * a copy of the handler object as required. The function signature of the
  380. * function object must be: @code void function(); @endcode
  381. */
  382. template <typename Function>
  383. constraint_t<
  384. traits::execute_member<const Executor&, Function>::is_valid,
  385. void
  386. > execute(Function&& f) const
  387. {
  388. this->execute_helper(static_cast<Function&&>(f), Blocking{});
  389. }
  390. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  391. /// Request the inline_or_executor to invoke the given function object.
  392. /**
  393. * This function is used to ask the inline_or_executor to execute the given
  394. * function object. The function object will be executed inside this function.
  395. *
  396. * @param f The function object to be called. The executor will make
  397. * a copy of the handler object as required. The function signature of the
  398. * function object must be: @code void function(); @endcode
  399. *
  400. * @param a An allocator that may be used by the executor to allocate the
  401. * internal storage needed for function invocation.
  402. */
  403. template <typename Function, typename Allocator>
  404. void dispatch(Function&& f, const Allocator& a) const
  405. {
  406. (void)a;
  407. detail::non_const_lvalue<Function> f2(f);
  408. static_cast<decay_t<Function>&&>(f2.value)();
  409. }
  410. /// Request the inline_or_executor to invoke the given function object.
  411. /**
  412. * This function is used to ask the executor to execute the given function
  413. * object. The function object will never be executed inside this function.
  414. * Instead, it will be scheduled by the underlying executor's post function.
  415. *
  416. * @param f The function object to be called. The executor will make
  417. * a copy of the handler object as required. The function signature of the
  418. * function object must be: @code void function(); @endcode
  419. *
  420. * @param a An allocator that may be used by the executor to allocate the
  421. * internal storage needed for function invocation.
  422. */
  423. template <typename Function, typename Allocator>
  424. void post(Function&& f, const Allocator& a) const
  425. {
  426. executor_.post(static_cast<Function&&>(f), a);
  427. }
  428. /// Request the inline_or_executor to invoke the given function object.
  429. /**
  430. * This function is used to ask the executor to execute the given function
  431. * object. The function object will never be executed inside this function.
  432. * Instead, it will be scheduled by the underlying executor's defer function.
  433. *
  434. * @param f The function object to be called. The executor will make
  435. * a copy of the handler object as required. The function signature of the
  436. * function object must be: @code void function(); @endcode
  437. *
  438. * @param a An allocator that may be used by the executor to allocate the
  439. * internal storage needed for function invocation.
  440. */
  441. template <typename Function, typename Allocator>
  442. void defer(Function&& f, const Allocator& a) const
  443. {
  444. executor_.defer(static_cast<Function&&>(f), a);
  445. }
  446. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  447. /// Compare two inline_or_executors for equality.
  448. /**
  449. * Two inline_or_executors are equal if their underlying executors are equal.
  450. */
  451. friend bool operator==(const inline_or_executor& a,
  452. const inline_or_executor& b) noexcept
  453. {
  454. return a.executor_ == b.executor_;
  455. }
  456. /// Compare two inline_or_executors for inequality.
  457. /**
  458. * Two inline_or_executors are equal if their underlying executors are equal.
  459. */
  460. friend bool operator!=(const inline_or_executor& a,
  461. const inline_or_executor& b) noexcept
  462. {
  463. return a.executor_ != b.executor_;
  464. }
  465. #if defined(GENERATING_DOCUMENTATION)
  466. private:
  467. #endif // defined(GENERATING_DOCUMENTATION)
  468. template <typename Function>
  469. void execute_helper(Function&& f, execution::blocking_t::possibly_t) const
  470. {
  471. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  472. try
  473. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  474. {
  475. detail::non_const_lvalue<Function> f2(f);
  476. static_cast<decay_t<Function>&&>(f2.value)();
  477. }
  478. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  479. catch (...)
  480. {
  481. if (is_same<InlineExceptionHandling,
  482. execution::inline_exception_handling_t::terminate_t>::value)
  483. {
  484. std::terminate();
  485. }
  486. else
  487. {
  488. throw;
  489. }
  490. }
  491. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  492. }
  493. template <typename Function>
  494. void execute_helper(Function&& f, execution::blocking_t::always_t) const
  495. {
  496. this->execute_helper(static_cast<Function&&>(f),
  497. execution::blocking.possibly);
  498. }
  499. template <typename Function>
  500. void execute_helper(Function&& f, execution::blocking_t::never_t) const
  501. {
  502. boost::asio::require(executor_, execution::blocking.never).execute(
  503. static_cast<Function&&>(f));
  504. }
  505. Executor executor_;
  506. };
  507. /** @defgroup inline_or boost::asio::inline_or
  508. *
  509. * @brief The boost::asio::inline_or function creates an @ref inline_or_executor
  510. * object for an executor or execution context.
  511. */
  512. /*@{*/
  513. /// Create an @ref inline_or_executor object for an executor.
  514. /**
  515. * @param ex An executor.
  516. *
  517. * @returns An inline_or_executor constructed with the specified executor.
  518. */
  519. template <typename Executor>
  520. inline inline_or_executor<Executor> inline_or(const Executor& ex,
  521. constraint_t<
  522. is_executor<Executor>::value || execution::is_executor<Executor>::value
  523. > = 0)
  524. {
  525. return inline_or_executor<Executor>(ex);
  526. }
  527. /// Create an @ref inline_or_executor object for an execution context.
  528. /**
  529. * @param ctx An execution context, from which an executor will be obtained.
  530. *
  531. * @returns An inline_or_executor constructed with the execution context's
  532. * executor, obtained by performing <tt>ctx.get_executor()</tt>.
  533. */
  534. template <typename ExecutionContext>
  535. inline inline_or_executor<typename ExecutionContext::executor_type>
  536. inline_or(ExecutionContext& ctx,
  537. constraint_t<
  538. is_convertible<ExecutionContext&, execution_context&>::value
  539. > = 0)
  540. {
  541. return inline_or_executor<typename ExecutionContext::executor_type>(
  542. ctx.get_executor());
  543. }
  544. /*@}*/
  545. #if !defined(GENERATING_DOCUMENTATION)
  546. namespace traits {
  547. #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  548. template <typename Executor, typename Blocking,
  549. typename InlineExceptionHandling>
  550. struct equality_comparable<
  551. inline_or_executor<Executor, Blocking, InlineExceptionHandling>>
  552. {
  553. static constexpr bool is_valid = true;
  554. static constexpr bool is_noexcept = true;
  555. };
  556. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  557. #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  558. template <typename Executor, typename Blocking,
  559. typename InlineExceptionHandling, typename Function>
  560. struct execute_member<
  561. inline_or_executor<Executor, Blocking, InlineExceptionHandling>, Function,
  562. enable_if_t<
  563. traits::execute_member<const Executor&, Function>::is_valid
  564. >
  565. >
  566. {
  567. static constexpr bool is_valid = true;
  568. static constexpr bool is_noexcept = false;
  569. typedef void result_type;
  570. };
  571. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  572. #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
  573. template <typename Executor, typename Blocking,
  574. typename InlineExceptionHandling, typename Property>
  575. struct query_static_constexpr_member<
  576. inline_or_executor<Executor, Blocking, InlineExceptionHandling>,
  577. Property,
  578. enable_if_t<
  579. is_convertible<
  580. Property,
  581. execution::blocking_t
  582. >::value
  583. >
  584. >
  585. {
  586. static constexpr bool is_valid = true;
  587. static constexpr bool is_noexcept = true;
  588. typedef Blocking result_type;
  589. static constexpr result_type value() noexcept
  590. {
  591. return result_type();
  592. }
  593. };
  594. template <typename Executor, typename Blocking,
  595. typename InlineExceptionHandling, typename Property>
  596. struct query_static_constexpr_member<
  597. inline_or_executor<Executor, Blocking, InlineExceptionHandling>,
  598. Property,
  599. enable_if_t<
  600. is_convertible<
  601. Property,
  602. execution::inline_exception_handling_t
  603. >::value
  604. >
  605. >
  606. {
  607. static constexpr bool is_valid = true;
  608. static constexpr bool is_noexcept = true;
  609. typedef InlineExceptionHandling result_type;
  610. static constexpr result_type value() noexcept
  611. {
  612. return result_type();
  613. }
  614. };
  615. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
  616. #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  617. template <typename Executor, typename Blocking,
  618. typename InlineExceptionHandling, typename Property>
  619. struct query_member<
  620. inline_or_executor<Executor, Blocking, InlineExceptionHandling>, Property,
  621. enable_if_t<
  622. can_query<const Executor&, Property>::value
  623. && !is_convertible<Property,
  624. execution::blocking_t>::value
  625. && !is_convertible<Property,
  626. execution::inline_exception_handling_t>::value
  627. >
  628. >
  629. {
  630. static constexpr bool is_valid = true;
  631. static constexpr bool is_noexcept =
  632. is_nothrow_query<Executor, Property>::value;
  633. typedef query_result_t<Executor, Property> result_type;
  634. };
  635. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  636. #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  637. template <typename Executor, typename Blocking,
  638. typename InlineExceptionHandling>
  639. struct require_member<
  640. inline_or_executor<Executor, Blocking, InlineExceptionHandling>,
  641. execution::blocking_t::possibly_t
  642. >
  643. {
  644. static constexpr bool is_valid = true;
  645. static constexpr bool is_noexcept = true;
  646. typedef inline_or_executor<Executor, execution::blocking_t::possibly_t,
  647. InlineExceptionHandling> result_type;
  648. };
  649. template <typename Executor, typename Blocking,
  650. typename InlineExceptionHandling>
  651. struct require_member<
  652. inline_or_executor<Executor, Blocking, InlineExceptionHandling>,
  653. execution::blocking_t::always_t
  654. >
  655. {
  656. static constexpr bool is_valid = true;
  657. static constexpr bool is_noexcept = true;
  658. typedef inline_or_executor<Executor, execution::blocking_t::always_t,
  659. InlineExceptionHandling> result_type;
  660. };
  661. template <typename Executor, typename Blocking,
  662. typename InlineExceptionHandling>
  663. struct require_member<
  664. inline_or_executor<Executor, Blocking, InlineExceptionHandling>,
  665. execution::blocking_t::never_t
  666. >
  667. {
  668. static constexpr bool is_valid = true;
  669. static constexpr bool is_noexcept = true;
  670. typedef inline_or_executor<Executor, execution::blocking_t::never_t,
  671. InlineExceptionHandling> result_type;
  672. };
  673. template <typename Executor, typename Blocking,
  674. typename InlineExceptionHandling>
  675. struct require_member<
  676. inline_or_executor<Executor, Blocking, InlineExceptionHandling>,
  677. execution::inline_exception_handling_t::propagate_t
  678. >
  679. {
  680. static constexpr bool is_valid = true;
  681. static constexpr bool is_noexcept = true;
  682. typedef inline_or_executor<Executor, Blocking,
  683. execution::inline_exception_handling_t::propagate_t> result_type;
  684. };
  685. template <typename Executor, typename Blocking,
  686. typename InlineExceptionHandling>
  687. struct require_member<
  688. inline_or_executor<Executor, Blocking, InlineExceptionHandling>,
  689. execution::inline_exception_handling_t::terminate_t
  690. >
  691. {
  692. static constexpr bool is_valid = true;
  693. static constexpr bool is_noexcept = true;
  694. typedef inline_or_executor<Executor, Blocking,
  695. execution::inline_exception_handling_t::terminate_t> result_type;
  696. };
  697. template <typename Executor, typename Blocking,
  698. typename InlineExceptionHandling, typename Property>
  699. struct require_member<
  700. inline_or_executor<Executor, Blocking, InlineExceptionHandling>, Property,
  701. enable_if_t<
  702. can_require<const Executor&, Property>::value
  703. && !is_convertible<Property,
  704. execution::blocking_t>::value
  705. && !is_convertible<Property,
  706. execution::inline_exception_handling_t>::value
  707. >
  708. >
  709. {
  710. static constexpr bool is_valid = true;
  711. static constexpr bool is_noexcept =
  712. is_nothrow_require<const Executor&, Property>::value;
  713. typedef inline_or_executor<
  714. decay_t<require_result_t<const Executor&, Property>>,
  715. Blocking, InlineExceptionHandling> result_type;
  716. };
  717. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  718. #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
  719. template <typename Executor, typename Blocking,
  720. typename InlineExceptionHandling, typename Property>
  721. struct prefer_member<
  722. inline_or_executor<Executor, Blocking, InlineExceptionHandling>, Property,
  723. enable_if_t<
  724. can_prefer<const Executor&, Property>::value
  725. && !is_convertible<Property, execution::blocking_t::always_t>::value
  726. >
  727. >
  728. {
  729. static constexpr bool is_valid = true;
  730. static constexpr bool is_noexcept =
  731. is_nothrow_prefer<const Executor&, Property>::value;
  732. typedef inline_or_executor<
  733. decay_t<prefer_result_t<const Executor&, Property>>,
  734. Blocking, InlineExceptionHandling> result_type;
  735. };
  736. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
  737. } // namespace traits
  738. #endif // !defined(GENERATING_DOCUMENTATION)
  739. } // namespace asio
  740. } // namespace boost
  741. #include <boost/asio/detail/pop_options.hpp>
  742. #endif // BOOST_ASIO_INLINE_OR_EXECUTOR_HPP