bind_executor.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. //
  2. // bind_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_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) &&
  338. {
  339. return static_cast<T&&>(this->target_)(static_cast<Args&&>(args)...);
  340. }
  341. /// Forwarding function call operator.
  342. template <typename... Args>
  343. result_of_t<T(Args...)> operator()(Args&&... args) const&
  344. {
  345. return this->target_(static_cast<Args&&>(args)...);
  346. }
  347. private:
  348. typedef detail::executor_binder_base<T, Executor,
  349. uses_executor<T, Executor>::value> base_type;
  350. };
  351. /// A function object type that adapts a @ref completion_token to specify that
  352. /// the completion handler should have the supplied executor as its associated
  353. /// executor.
  354. /**
  355. * May also be used directly as a completion token, in which case it adapts the
  356. * asynchronous operation's default completion token (or boost::asio::deferred
  357. * if no default is available).
  358. */
  359. template <typename Executor>
  360. struct partial_executor_binder
  361. {
  362. /// Constructor that specifies associated executor.
  363. explicit partial_executor_binder(const Executor& ex)
  364. : executor_(ex)
  365. {
  366. }
  367. /// Adapt a @ref completion_token to specify that the completion handler
  368. /// should have the executor as its associated executor.
  369. template <typename CompletionToken>
  370. BOOST_ASIO_NODISCARD inline
  371. constexpr executor_binder<decay_t<CompletionToken>, Executor>
  372. operator()(CompletionToken&& completion_token) const
  373. {
  374. return executor_binder<decay_t<CompletionToken>, Executor>(executor_arg_t(),
  375. static_cast<CompletionToken&&>(completion_token), executor_);
  376. }
  377. //private:
  378. Executor executor_;
  379. };
  380. /// Create a partial completion token that associates an executor.
  381. template <typename Executor>
  382. BOOST_ASIO_NODISCARD inline partial_executor_binder<Executor>
  383. bind_executor(const Executor& ex,
  384. constraint_t<
  385. is_executor<Executor>::value || execution::is_executor<Executor>::value
  386. > = 0)
  387. {
  388. return partial_executor_binder<Executor>(ex);
  389. }
  390. /// Associate an object of type @c T with an executor of type @c Executor.
  391. template <typename Executor, typename T>
  392. BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor>
  393. bind_executor(const Executor& ex, T&& t,
  394. constraint_t<
  395. is_executor<Executor>::value || execution::is_executor<Executor>::value
  396. > = 0)
  397. {
  398. return executor_binder<decay_t<T>, Executor>(
  399. executor_arg_t(), ex, static_cast<T&&>(t));
  400. }
  401. /// Create a partial completion token that associates an execution context's
  402. /// executor.
  403. template <typename ExecutionContext>
  404. BOOST_ASIO_NODISCARD inline partial_executor_binder<
  405. typename ExecutionContext::executor_type>
  406. bind_executor(ExecutionContext& ctx,
  407. constraint_t<
  408. is_convertible<ExecutionContext&, execution_context&>::value
  409. > = 0)
  410. {
  411. return partial_executor_binder<typename ExecutionContext::executor_type>(
  412. ctx.get_executor());
  413. }
  414. /// Associate an object of type @c T with an execution context's executor.
  415. template <typename ExecutionContext, typename T>
  416. BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>,
  417. typename ExecutionContext::executor_type>
  418. bind_executor(ExecutionContext& ctx, T&& t,
  419. constraint_t<
  420. is_convertible<ExecutionContext&, execution_context&>::value
  421. > = 0)
  422. {
  423. return executor_binder<decay_t<T>, typename ExecutionContext::executor_type>(
  424. executor_arg_t(), ctx.get_executor(), static_cast<T&&>(t));
  425. }
  426. #if !defined(GENERATING_DOCUMENTATION)
  427. template <typename T, typename Executor>
  428. struct uses_executor<executor_binder<T, Executor>, Executor>
  429. : true_type {};
  430. namespace detail {
  431. template <typename TargetAsyncResult, typename Executor, typename = void>
  432. class executor_binder_completion_handler_async_result
  433. {
  434. public:
  435. template <typename T>
  436. explicit executor_binder_completion_handler_async_result(T&)
  437. {
  438. }
  439. };
  440. template <typename TargetAsyncResult, typename Executor>
  441. class executor_binder_completion_handler_async_result<
  442. TargetAsyncResult, Executor,
  443. void_t<typename TargetAsyncResult::completion_handler_type >>
  444. {
  445. private:
  446. TargetAsyncResult target_;
  447. public:
  448. typedef executor_binder<
  449. typename TargetAsyncResult::completion_handler_type, Executor>
  450. completion_handler_type;
  451. explicit executor_binder_completion_handler_async_result(
  452. typename TargetAsyncResult::completion_handler_type& handler)
  453. : target_(handler)
  454. {
  455. }
  456. auto get() -> decltype(target_.get())
  457. {
  458. return target_.get();
  459. }
  460. };
  461. template <typename TargetAsyncResult, typename = void>
  462. struct executor_binder_async_result_return_type
  463. {
  464. };
  465. template <typename TargetAsyncResult>
  466. struct executor_binder_async_result_return_type<TargetAsyncResult,
  467. void_t<typename TargetAsyncResult::return_type>>
  468. {
  469. typedef typename TargetAsyncResult::return_type return_type;
  470. };
  471. } // namespace detail
  472. template <typename T, typename Executor, typename Signature>
  473. class async_result<executor_binder<T, Executor>, Signature> :
  474. public detail::executor_binder_completion_handler_async_result<
  475. async_result<T, Signature>, Executor>,
  476. public detail::executor_binder_async_result_return_type<
  477. async_result<T, Signature>>
  478. {
  479. public:
  480. explicit async_result(executor_binder<T, Executor>& b)
  481. : detail::executor_binder_completion_handler_async_result<
  482. async_result<T, Signature>, Executor>(b.get())
  483. {
  484. }
  485. template <typename Initiation>
  486. struct init_wrapper : detail::initiation_base<Initiation>
  487. {
  488. using detail::initiation_base<Initiation>::initiation_base;
  489. template <typename Handler, typename... Args>
  490. void operator()(Handler&& handler, const Executor& e, Args&&... args) &&
  491. {
  492. static_cast<Initiation&&>(*this)(
  493. executor_binder<decay_t<Handler>, Executor>(
  494. executor_arg_t(), e, static_cast<Handler&&>(handler)),
  495. static_cast<Args&&>(args)...);
  496. }
  497. template <typename Handler, typename... Args>
  498. void operator()(Handler&& handler,
  499. const Executor& e, Args&&... args) const &
  500. {
  501. static_cast<const Initiation&>(*this)(
  502. executor_binder<decay_t<Handler>, Executor>(
  503. executor_arg_t(), e, static_cast<Handler&&>(handler)),
  504. static_cast<Args&&>(args)...);
  505. }
  506. };
  507. template <typename Initiation, typename RawCompletionToken, typename... Args>
  508. static auto initiate(Initiation&& initiation,
  509. RawCompletionToken&& token, Args&&... args)
  510. -> decltype(
  511. async_initiate<
  512. conditional_t<
  513. is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
  514. Signature>(
  515. declval<init_wrapper<decay_t<Initiation>>>(),
  516. token.get(), token.get_executor(), static_cast<Args&&>(args)...))
  517. {
  518. return async_initiate<
  519. conditional_t<
  520. is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
  521. Signature>(
  522. init_wrapper<decay_t<Initiation>>(
  523. static_cast<Initiation&&>(initiation)),
  524. token.get(), token.get_executor(), static_cast<Args&&>(args)...);
  525. }
  526. private:
  527. async_result(const async_result&) = delete;
  528. async_result& operator=(const async_result&) = delete;
  529. };
  530. template <typename Executor, typename... Signatures>
  531. struct async_result<partial_executor_binder<Executor>, Signatures...>
  532. {
  533. template <typename Initiation, typename RawCompletionToken, typename... Args>
  534. static auto initiate(Initiation&& initiation,
  535. RawCompletionToken&& token, Args&&... args)
  536. -> decltype(
  537. async_initiate<Signatures...>(
  538. static_cast<Initiation&&>(initiation),
  539. executor_binder<
  540. default_completion_token_t<associated_executor_t<Initiation>>,
  541. Executor>(executor_arg_t(), token.executor_,
  542. default_completion_token_t<associated_executor_t<Initiation>>{}),
  543. static_cast<Args&&>(args)...))
  544. {
  545. return async_initiate<Signatures...>(
  546. static_cast<Initiation&&>(initiation),
  547. executor_binder<
  548. default_completion_token_t<associated_executor_t<Initiation>>,
  549. Executor>(executor_arg_t(), token.executor_,
  550. default_completion_token_t<associated_executor_t<Initiation>>{}),
  551. static_cast<Args&&>(args)...);
  552. }
  553. };
  554. template <template <typename, typename> class Associator,
  555. typename T, typename Executor, typename DefaultCandidate>
  556. struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate>
  557. : Associator<T, DefaultCandidate>
  558. {
  559. static typename Associator<T, DefaultCandidate>::type get(
  560. const executor_binder<T, Executor>& b) noexcept
  561. {
  562. return Associator<T, DefaultCandidate>::get(b.get());
  563. }
  564. static auto get(const executor_binder<T, Executor>& b,
  565. const DefaultCandidate& c) noexcept
  566. -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
  567. {
  568. return Associator<T, DefaultCandidate>::get(b.get(), c);
  569. }
  570. };
  571. template <typename T, typename Executor, typename Executor1>
  572. struct associated_executor<executor_binder<T, Executor>, Executor1>
  573. {
  574. typedef Executor type;
  575. static auto get(const executor_binder<T, Executor>& b,
  576. const Executor1& = Executor1()) noexcept
  577. -> decltype(b.get_executor())
  578. {
  579. return b.get_executor();
  580. }
  581. };
  582. #endif // !defined(GENERATING_DOCUMENTATION)
  583. } // namespace asio
  584. } // namespace boost
  585. #include <boost/asio/detail/pop_options.hpp>
  586. #endif // BOOST_ASIO_BIND_EXECUTOR_HPP