bind_executor.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. //
  2. // bind_executor.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. #ifndef BOOST_ASIO_BIND_EXECUTOR_HPP
  11. #define BOOST_ASIO_BIND_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/associated_executor.hpp>
  17. #include <boost/asio/associator.hpp>
  18. #include <boost/asio/async_result.hpp>
  19. #include <boost/asio/detail/initiation_base.hpp>
  20. #include <boost/asio/detail/type_traits.hpp>
  21. #include <boost/asio/execution/executor.hpp>
  22. #include <boost/asio/execution_context.hpp>
  23. #include <boost/asio/is_executor.hpp>
  24. #include <boost/asio/uses_executor.hpp>
  25. #include <boost/asio/detail/push_options.hpp>
  26. namespace boost {
  27. namespace asio {
  28. namespace detail {
  29. // Helper to automatically define nested typedef result_type.
  30. template <typename T, typename = void>
  31. struct executor_binder_result_type
  32. {
  33. protected:
  34. typedef void result_type_or_void;
  35. };
  36. template <typename T>
  37. struct executor_binder_result_type<T, void_t<typename T::result_type>>
  38. {
  39. typedef typename T::result_type result_type;
  40. protected:
  41. typedef result_type result_type_or_void;
  42. };
  43. template <typename R>
  44. struct executor_binder_result_type<R(*)()>
  45. {
  46. typedef R result_type;
  47. protected:
  48. typedef result_type result_type_or_void;
  49. };
  50. template <typename R>
  51. struct executor_binder_result_type<R(&)()>
  52. {
  53. typedef R result_type;
  54. protected:
  55. typedef result_type result_type_or_void;
  56. };
  57. template <typename R, typename A1>
  58. struct executor_binder_result_type<R(*)(A1)>
  59. {
  60. typedef R result_type;
  61. protected:
  62. typedef result_type result_type_or_void;
  63. };
  64. template <typename R, typename A1>
  65. struct executor_binder_result_type<R(&)(A1)>
  66. {
  67. typedef R result_type;
  68. protected:
  69. typedef result_type result_type_or_void;
  70. };
  71. template <typename R, typename A1, typename A2>
  72. struct executor_binder_result_type<R(*)(A1, A2)>
  73. {
  74. typedef R result_type;
  75. protected:
  76. typedef result_type result_type_or_void;
  77. };
  78. template <typename R, typename A1, typename A2>
  79. struct executor_binder_result_type<R(&)(A1, A2)>
  80. {
  81. typedef R result_type;
  82. protected:
  83. typedef result_type result_type_or_void;
  84. };
  85. // Helper to automatically define nested typedef argument_type.
  86. template <typename T, typename = void>
  87. struct executor_binder_argument_type {};
  88. template <typename T>
  89. struct executor_binder_argument_type<T, void_t<typename T::argument_type>>
  90. {
  91. typedef typename T::argument_type argument_type;
  92. };
  93. template <typename R, typename A1>
  94. struct executor_binder_argument_type<R(*)(A1)>
  95. {
  96. typedef A1 argument_type;
  97. };
  98. template <typename R, typename A1>
  99. struct executor_binder_argument_type<R(&)(A1)>
  100. {
  101. typedef A1 argument_type;
  102. };
  103. // Helper to automatically define nested typedefs first_argument_type and
  104. // second_argument_type.
  105. template <typename T, typename = void>
  106. struct executor_binder_argument_types {};
  107. template <typename T>
  108. struct executor_binder_argument_types<T,
  109. void_t<typename T::first_argument_type>>
  110. {
  111. typedef typename T::first_argument_type first_argument_type;
  112. typedef typename T::second_argument_type second_argument_type;
  113. };
  114. template <typename R, typename A1, typename A2>
  115. struct executor_binder_argument_type<R(*)(A1, A2)>
  116. {
  117. typedef A1 first_argument_type;
  118. typedef A2 second_argument_type;
  119. };
  120. template <typename R, typename A1, typename A2>
  121. struct executor_binder_argument_type<R(&)(A1, A2)>
  122. {
  123. typedef A1 first_argument_type;
  124. typedef A2 second_argument_type;
  125. };
  126. // Helper to perform uses_executor construction of the target type, if
  127. // required.
  128. template <typename T, typename Executor, bool UsesExecutor>
  129. class executor_binder_base;
  130. template <typename T, typename Executor>
  131. class executor_binder_base<T, Executor, true>
  132. {
  133. protected:
  134. template <typename E, typename U>
  135. executor_binder_base(E&& e, U&& u)
  136. : executor_(static_cast<E&&>(e)),
  137. target_(executor_arg_t(), executor_, static_cast<U&&>(u))
  138. {
  139. }
  140. Executor executor_;
  141. T target_;
  142. };
  143. template <typename T, typename Executor>
  144. class executor_binder_base<T, Executor, false>
  145. {
  146. protected:
  147. template <typename E, typename U>
  148. executor_binder_base(E&& e, U&& u)
  149. : executor_(static_cast<E&&>(e)),
  150. target_(static_cast<U&&>(u))
  151. {
  152. }
  153. Executor executor_;
  154. T target_;
  155. };
  156. } // namespace detail
  157. /// A call wrapper type to bind an executor of type @c Executor to an object of
  158. /// type @c T.
  159. template <typename T, typename Executor>
  160. class executor_binder
  161. #if !defined(GENERATING_DOCUMENTATION)
  162. : public detail::executor_binder_result_type<T>,
  163. public detail::executor_binder_argument_type<T>,
  164. public detail::executor_binder_argument_types<T>,
  165. private detail::executor_binder_base<
  166. T, Executor, uses_executor<T, Executor>::value>
  167. #endif // !defined(GENERATING_DOCUMENTATION)
  168. {
  169. public:
  170. /// The type of the target object.
  171. typedef T target_type;
  172. /// The type of the associated executor.
  173. typedef Executor executor_type;
  174. #if defined(GENERATING_DOCUMENTATION)
  175. /// The return type if a function.
  176. /**
  177. * The type of @c result_type is based on the type @c T of the wrapper's
  178. * target object:
  179. *
  180. * @li if @c T is a pointer to function type, @c result_type is a synonym for
  181. * the return type of @c T;
  182. *
  183. * @li if @c T is a class type with a member type @c result_type, then @c
  184. * result_type is a synonym for @c T::result_type;
  185. *
  186. * @li otherwise @c result_type is not defined.
  187. */
  188. typedef see_below result_type;
  189. /// The type of the function's argument.
  190. /**
  191. * The type of @c argument_type is based on the type @c T of the wrapper's
  192. * target object:
  193. *
  194. * @li if @c T is a pointer to a function type accepting a single argument,
  195. * @c argument_type is a synonym for the return type of @c T;
  196. *
  197. * @li if @c T is a class type with a member type @c argument_type, then @c
  198. * argument_type is a synonym for @c T::argument_type;
  199. *
  200. * @li otherwise @c argument_type is not defined.
  201. */
  202. typedef see_below argument_type;
  203. /// The type of the function's first argument.
  204. /**
  205. * The type of @c first_argument_type is based on the type @c T of the
  206. * wrapper's target object:
  207. *
  208. * @li if @c T is a pointer to a function type accepting two arguments, @c
  209. * first_argument_type is a synonym for the return type of @c T;
  210. *
  211. * @li if @c T is a class type with a member type @c first_argument_type,
  212. * then @c first_argument_type is a synonym for @c T::first_argument_type;
  213. *
  214. * @li otherwise @c first_argument_type is not defined.
  215. */
  216. typedef see_below first_argument_type;
  217. /// The type of the function's second argument.
  218. /**
  219. * The type of @c second_argument_type is based on the type @c T of the
  220. * wrapper's target object:
  221. *
  222. * @li if @c T is a pointer to a function type accepting two arguments, @c
  223. * second_argument_type is a synonym for the return type of @c T;
  224. *
  225. * @li if @c T is a class type with a member type @c first_argument_type,
  226. * then @c second_argument_type is a synonym for @c T::second_argument_type;
  227. *
  228. * @li otherwise @c second_argument_type is not defined.
  229. */
  230. typedef see_below second_argument_type;
  231. #endif // defined(GENERATING_DOCUMENTATION)
  232. /// Construct an executor wrapper for the specified object.
  233. /**
  234. * This constructor is only valid if the type @c T is constructible from type
  235. * @c U.
  236. */
  237. template <typename U>
  238. executor_binder(executor_arg_t, const executor_type& e,
  239. U&& u)
  240. : base_type(e, static_cast<U&&>(u))
  241. {
  242. }
  243. /// Copy constructor.
  244. executor_binder(const executor_binder& other)
  245. : base_type(other.get_executor(), other.get())
  246. {
  247. }
  248. /// Construct a copy, but specify a different executor.
  249. executor_binder(executor_arg_t, const executor_type& e,
  250. const executor_binder& other)
  251. : base_type(e, other.get())
  252. {
  253. }
  254. /// Construct a copy of a different executor wrapper type.
  255. /**
  256. * This constructor is only valid if the @c Executor type is constructible
  257. * from type @c OtherExecutor, and the type @c T is constructible from type
  258. * @c U.
  259. */
  260. template <typename U, typename OtherExecutor>
  261. executor_binder(const executor_binder<U, OtherExecutor>& other,
  262. constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
  263. constraint_t<is_constructible<T, U>::value> = 0)
  264. : base_type(other.get_executor(), other.get())
  265. {
  266. }
  267. /// Construct a copy of a different executor wrapper type, but specify a
  268. /// different executor.
  269. /**
  270. * This constructor is only valid if the type @c T is constructible from type
  271. * @c U.
  272. */
  273. template <typename U, typename OtherExecutor>
  274. executor_binder(executor_arg_t, const executor_type& e,
  275. const executor_binder<U, OtherExecutor>& other,
  276. constraint_t<is_constructible<T, U>::value> = 0)
  277. : base_type(e, other.get())
  278. {
  279. }
  280. /// Move constructor.
  281. executor_binder(executor_binder&& other)
  282. : base_type(static_cast<executor_type&&>(other.get_executor()),
  283. static_cast<T&&>(other.get()))
  284. {
  285. }
  286. /// Move construct the target object, but specify a different executor.
  287. executor_binder(executor_arg_t, const executor_type& e,
  288. executor_binder&& other)
  289. : base_type(e, static_cast<T&&>(other.get()))
  290. {
  291. }
  292. /// Move construct from a different executor wrapper type.
  293. template <typename U, typename OtherExecutor>
  294. executor_binder(executor_binder<U, OtherExecutor>&& other,
  295. constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
  296. constraint_t<is_constructible<T, U>::value> = 0)
  297. : base_type(static_cast<OtherExecutor&&>(other.get_executor()),
  298. static_cast<U&&>(other.get()))
  299. {
  300. }
  301. /// Move construct from a different executor wrapper type, but specify a
  302. /// different executor.
  303. template <typename U, typename OtherExecutor>
  304. executor_binder(executor_arg_t, const executor_type& e,
  305. executor_binder<U, OtherExecutor>&& other,
  306. constraint_t<is_constructible<T, U>::value> = 0)
  307. : base_type(e, static_cast<U&&>(other.get()))
  308. {
  309. }
  310. /// Destructor.
  311. ~executor_binder()
  312. {
  313. }
  314. /// Obtain a reference to the target object.
  315. target_type& get() noexcept
  316. {
  317. return this->target_;
  318. }
  319. /// Obtain a reference to the target object.
  320. const target_type& get() const noexcept
  321. {
  322. return this->target_;
  323. }
  324. /// Obtain the associated executor.
  325. executor_type get_executor() const noexcept
  326. {
  327. return this->executor_;
  328. }
  329. /// Forwarding function call operator.
  330. template <typename... Args>
  331. result_of_t<T(Args...)> operator()(Args&&... args)
  332. {
  333. return this->target_(static_cast<Args&&>(args)...);
  334. }
  335. /// Forwarding function call operator.
  336. template <typename... Args>
  337. result_of_t<T(Args...)> operator()(Args&&... args) const
  338. {
  339. return this->target_(static_cast<Args&&>(args)...);
  340. }
  341. private:
  342. typedef detail::executor_binder_base<T, Executor,
  343. uses_executor<T, Executor>::value> base_type;
  344. };
  345. /// A function object type that adapts a @ref completion_token to specify that
  346. /// the completion handler should have the supplied executor as its associated
  347. /// executor.
  348. /**
  349. * May also be used directly as a completion token, in which case it adapts the
  350. * asynchronous operation's default completion token (or boost::asio::deferred
  351. * if no default is available).
  352. */
  353. template <typename Executor>
  354. struct partial_executor_binder
  355. {
  356. /// Constructor that specifies associated executor.
  357. explicit partial_executor_binder(const Executor& ex)
  358. : executor_(ex)
  359. {
  360. }
  361. /// Adapt a @ref completion_token to specify that the completion handler
  362. /// should have the executor as its associated executor.
  363. template <typename CompletionToken>
  364. BOOST_ASIO_NODISCARD inline
  365. constexpr executor_binder<decay_t<CompletionToken>, Executor>
  366. operator()(CompletionToken&& completion_token) const
  367. {
  368. return executor_binder<decay_t<CompletionToken>, Executor>(executor_arg_t(),
  369. static_cast<CompletionToken&&>(completion_token), executor_);
  370. }
  371. //private:
  372. Executor executor_;
  373. };
  374. /// Create a partial completion token that associates an executor.
  375. template <typename Executor>
  376. BOOST_ASIO_NODISCARD inline partial_executor_binder<Executor>
  377. bind_executor(const Executor& ex,
  378. constraint_t<
  379. is_executor<Executor>::value || execution::is_executor<Executor>::value
  380. > = 0)
  381. {
  382. return partial_executor_binder<Executor>(ex);
  383. }
  384. /// Associate an object of type @c T with an executor of type @c Executor.
  385. template <typename Executor, typename T>
  386. BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor>
  387. bind_executor(const Executor& ex, T&& t,
  388. constraint_t<
  389. is_executor<Executor>::value || execution::is_executor<Executor>::value
  390. > = 0)
  391. {
  392. return executor_binder<decay_t<T>, Executor>(
  393. executor_arg_t(), ex, static_cast<T&&>(t));
  394. }
  395. /// Create a partial completion token that associates an execution context's
  396. /// executor.
  397. template <typename ExecutionContext>
  398. BOOST_ASIO_NODISCARD inline partial_executor_binder<
  399. typename ExecutionContext::executor_type>
  400. bind_executor(ExecutionContext& ctx,
  401. constraint_t<
  402. is_convertible<ExecutionContext&, execution_context&>::value
  403. > = 0)
  404. {
  405. return partial_executor_binder<typename ExecutionContext::executor_type>(
  406. ctx.get_executor());
  407. }
  408. /// Associate an object of type @c T with an execution context's executor.
  409. template <typename ExecutionContext, typename T>
  410. BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>,
  411. typename ExecutionContext::executor_type>
  412. bind_executor(ExecutionContext& ctx, T&& t,
  413. constraint_t<
  414. is_convertible<ExecutionContext&, execution_context&>::value
  415. > = 0)
  416. {
  417. return executor_binder<decay_t<T>, typename ExecutionContext::executor_type>(
  418. executor_arg_t(), ctx.get_executor(), static_cast<T&&>(t));
  419. }
  420. #if !defined(GENERATING_DOCUMENTATION)
  421. template <typename T, typename Executor>
  422. struct uses_executor<executor_binder<T, Executor>, Executor>
  423. : true_type {};
  424. namespace detail {
  425. template <typename TargetAsyncResult, typename Executor, typename = void>
  426. class executor_binder_completion_handler_async_result
  427. {
  428. public:
  429. template <typename T>
  430. explicit executor_binder_completion_handler_async_result(T&)
  431. {
  432. }
  433. };
  434. template <typename TargetAsyncResult, typename Executor>
  435. class executor_binder_completion_handler_async_result<
  436. TargetAsyncResult, Executor,
  437. void_t<typename TargetAsyncResult::completion_handler_type >>
  438. {
  439. private:
  440. TargetAsyncResult target_;
  441. public:
  442. typedef executor_binder<
  443. typename TargetAsyncResult::completion_handler_type, Executor>
  444. completion_handler_type;
  445. explicit executor_binder_completion_handler_async_result(
  446. typename TargetAsyncResult::completion_handler_type& handler)
  447. : target_(handler)
  448. {
  449. }
  450. auto get() -> decltype(target_.get())
  451. {
  452. return target_.get();
  453. }
  454. };
  455. template <typename TargetAsyncResult, typename = void>
  456. struct executor_binder_async_result_return_type
  457. {
  458. };
  459. template <typename TargetAsyncResult>
  460. struct executor_binder_async_result_return_type<TargetAsyncResult,
  461. void_t<typename TargetAsyncResult::return_type>>
  462. {
  463. typedef typename TargetAsyncResult::return_type return_type;
  464. };
  465. } // namespace detail
  466. template <typename T, typename Executor, typename Signature>
  467. class async_result<executor_binder<T, Executor>, Signature> :
  468. public detail::executor_binder_completion_handler_async_result<
  469. async_result<T, Signature>, Executor>,
  470. public detail::executor_binder_async_result_return_type<
  471. async_result<T, Signature>>
  472. {
  473. public:
  474. explicit async_result(executor_binder<T, Executor>& b)
  475. : detail::executor_binder_completion_handler_async_result<
  476. async_result<T, Signature>, Executor>(b.get())
  477. {
  478. }
  479. template <typename Initiation>
  480. struct init_wrapper : detail::initiation_base<Initiation>
  481. {
  482. using detail::initiation_base<Initiation>::initiation_base;
  483. template <typename Handler, typename... Args>
  484. void operator()(Handler&& handler, const Executor& e, Args&&... args) &&
  485. {
  486. static_cast<Initiation&&>(*this)(
  487. executor_binder<decay_t<Handler>, Executor>(
  488. executor_arg_t(), e, static_cast<Handler&&>(handler)),
  489. static_cast<Args&&>(args)...);
  490. }
  491. template <typename Handler, typename... Args>
  492. void operator()(Handler&& handler,
  493. const Executor& e, Args&&... args) const &
  494. {
  495. static_cast<const Initiation&>(*this)(
  496. executor_binder<decay_t<Handler>, Executor>(
  497. executor_arg_t(), e, static_cast<Handler&&>(handler)),
  498. static_cast<Args&&>(args)...);
  499. }
  500. };
  501. template <typename Initiation, typename RawCompletionToken, typename... Args>
  502. static auto initiate(Initiation&& initiation,
  503. RawCompletionToken&& token, Args&&... args)
  504. -> decltype(
  505. async_initiate<
  506. conditional_t<
  507. is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
  508. Signature>(
  509. declval<init_wrapper<decay_t<Initiation>>>(),
  510. token.get(), token.get_executor(), static_cast<Args&&>(args)...))
  511. {
  512. return async_initiate<
  513. conditional_t<
  514. is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
  515. Signature>(
  516. init_wrapper<decay_t<Initiation>>(
  517. static_cast<Initiation&&>(initiation)),
  518. token.get(), token.get_executor(), static_cast<Args&&>(args)...);
  519. }
  520. private:
  521. async_result(const async_result&) = delete;
  522. async_result& operator=(const async_result&) = delete;
  523. };
  524. template <typename Executor, typename... Signatures>
  525. struct async_result<partial_executor_binder<Executor>, Signatures...>
  526. {
  527. template <typename Initiation, typename RawCompletionToken, typename... Args>
  528. static auto initiate(Initiation&& initiation,
  529. RawCompletionToken&& token, Args&&... args)
  530. -> decltype(
  531. async_initiate<Signatures...>(
  532. static_cast<Initiation&&>(initiation),
  533. executor_binder<
  534. default_completion_token_t<associated_executor_t<Initiation>>,
  535. Executor>(executor_arg_t(), token.executor_,
  536. default_completion_token_t<associated_executor_t<Initiation>>{}),
  537. static_cast<Args&&>(args)...))
  538. {
  539. return async_initiate<Signatures...>(
  540. static_cast<Initiation&&>(initiation),
  541. executor_binder<
  542. default_completion_token_t<associated_executor_t<Initiation>>,
  543. Executor>(executor_arg_t(), token.executor_,
  544. default_completion_token_t<associated_executor_t<Initiation>>{}),
  545. static_cast<Args&&>(args)...);
  546. }
  547. };
  548. template <template <typename, typename> class Associator,
  549. typename T, typename Executor, typename DefaultCandidate>
  550. struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate>
  551. : Associator<T, DefaultCandidate>
  552. {
  553. static typename Associator<T, DefaultCandidate>::type get(
  554. const executor_binder<T, Executor>& b) noexcept
  555. {
  556. return Associator<T, DefaultCandidate>::get(b.get());
  557. }
  558. static auto get(const executor_binder<T, Executor>& b,
  559. const DefaultCandidate& c) noexcept
  560. -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
  561. {
  562. return Associator<T, DefaultCandidate>::get(b.get(), c);
  563. }
  564. };
  565. template <typename T, typename Executor, typename Executor1>
  566. struct associated_executor<executor_binder<T, Executor>, Executor1>
  567. {
  568. typedef Executor type;
  569. static auto get(const executor_binder<T, Executor>& b,
  570. const Executor1& = Executor1()) noexcept
  571. -> decltype(b.get_executor())
  572. {
  573. return b.get_executor();
  574. }
  575. };
  576. #endif // !defined(GENERATING_DOCUMENTATION)
  577. } // namespace asio
  578. } // namespace boost
  579. #include <boost/asio/detail/pop_options.hpp>
  580. #endif // BOOST_ASIO_BIND_EXECUTOR_HPP