bind_executor.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. //
  2. // bind_executor.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. #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/detail/type_traits.hpp>
  17. #include <boost/asio/detail/variadic_templates.hpp>
  18. #include <boost/asio/associated_executor.hpp>
  19. #include <boost/asio/associated_allocator.hpp>
  20. #include <boost/asio/async_result.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,
  38. typename void_type<typename T::result_type>::type>
  39. {
  40. typedef typename T::result_type result_type;
  41. protected:
  42. typedef result_type result_type_or_void;
  43. };
  44. template <typename R>
  45. struct executor_binder_result_type<R(*)()>
  46. {
  47. typedef R result_type;
  48. protected:
  49. typedef result_type result_type_or_void;
  50. };
  51. template <typename R>
  52. struct executor_binder_result_type<R(&)()>
  53. {
  54. typedef R result_type;
  55. protected:
  56. typedef result_type result_type_or_void;
  57. };
  58. template <typename R, typename A1>
  59. struct executor_binder_result_type<R(*)(A1)>
  60. {
  61. typedef R result_type;
  62. protected:
  63. typedef result_type result_type_or_void;
  64. };
  65. template <typename R, typename A1>
  66. struct executor_binder_result_type<R(&)(A1)>
  67. {
  68. typedef R result_type;
  69. protected:
  70. typedef result_type result_type_or_void;
  71. };
  72. template <typename R, typename A1, typename A2>
  73. struct executor_binder_result_type<R(*)(A1, A2)>
  74. {
  75. typedef R result_type;
  76. protected:
  77. typedef result_type result_type_or_void;
  78. };
  79. template <typename R, typename A1, typename A2>
  80. struct executor_binder_result_type<R(&)(A1, A2)>
  81. {
  82. typedef R result_type;
  83. protected:
  84. typedef result_type result_type_or_void;
  85. };
  86. // Helper to automatically define nested typedef argument_type.
  87. template <typename T, typename = void>
  88. struct executor_binder_argument_type {};
  89. template <typename T>
  90. struct executor_binder_argument_type<T,
  91. typename void_type<typename T::argument_type>::type>
  92. {
  93. typedef typename T::argument_type argument_type;
  94. };
  95. template <typename R, typename A1>
  96. struct executor_binder_argument_type<R(*)(A1)>
  97. {
  98. typedef A1 argument_type;
  99. };
  100. template <typename R, typename A1>
  101. struct executor_binder_argument_type<R(&)(A1)>
  102. {
  103. typedef A1 argument_type;
  104. };
  105. // Helper to automatically define nested typedefs first_argument_type and
  106. // second_argument_type.
  107. template <typename T, typename = void>
  108. struct executor_binder_argument_types {};
  109. template <typename T>
  110. struct executor_binder_argument_types<T,
  111. typename void_type<typename T::first_argument_type>::type>
  112. {
  113. typedef typename T::first_argument_type first_argument_type;
  114. typedef typename T::second_argument_type second_argument_type;
  115. };
  116. template <typename R, typename A1, typename A2>
  117. struct executor_binder_argument_type<R(*)(A1, A2)>
  118. {
  119. typedef A1 first_argument_type;
  120. typedef A2 second_argument_type;
  121. };
  122. template <typename R, typename A1, typename A2>
  123. struct executor_binder_argument_type<R(&)(A1, A2)>
  124. {
  125. typedef A1 first_argument_type;
  126. typedef A2 second_argument_type;
  127. };
  128. // Helper to perform uses_executor construction of the target type, if
  129. // required.
  130. template <typename T, typename Executor, bool UsesExecutor>
  131. class executor_binder_base;
  132. template <typename T, typename Executor>
  133. class executor_binder_base<T, Executor, true>
  134. {
  135. protected:
  136. template <typename E, typename U>
  137. executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u)
  138. : executor_(BOOST_ASIO_MOVE_CAST(E)(e)),
  139. target_(executor_arg_t(), executor_, BOOST_ASIO_MOVE_CAST(U)(u))
  140. {
  141. }
  142. Executor executor_;
  143. T target_;
  144. };
  145. template <typename T, typename Executor>
  146. class executor_binder_base<T, Executor, false>
  147. {
  148. protected:
  149. template <typename E, typename U>
  150. executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u)
  151. : executor_(BOOST_ASIO_MOVE_CAST(E)(e)),
  152. target_(BOOST_ASIO_MOVE_CAST(U)(u))
  153. {
  154. }
  155. Executor executor_;
  156. T target_;
  157. };
  158. // Helper to enable SFINAE on zero-argument operator() below.
  159. template <typename T, typename = void>
  160. struct executor_binder_result_of0
  161. {
  162. typedef void type;
  163. };
  164. template <typename T>
  165. struct executor_binder_result_of0<T,
  166. typename void_type<typename result_of<T()>::type>::type>
  167. {
  168. typedef typename result_of<T()>::type type;
  169. };
  170. } // namespace detail
  171. /// A call wrapper type to bind an executor of type @c Executor to an object of
  172. /// type @c T.
  173. template <typename T, typename Executor>
  174. class executor_binder
  175. #if !defined(GENERATING_DOCUMENTATION)
  176. : public detail::executor_binder_result_type<T>,
  177. public detail::executor_binder_argument_type<T>,
  178. public detail::executor_binder_argument_types<T>,
  179. private detail::executor_binder_base<
  180. T, Executor, uses_executor<T, Executor>::value>
  181. #endif // !defined(GENERATING_DOCUMENTATION)
  182. {
  183. public:
  184. /// The type of the target object.
  185. typedef T target_type;
  186. /// The type of the associated executor.
  187. typedef Executor executor_type;
  188. #if defined(GENERATING_DOCUMENTATION)
  189. /// The return type if a function.
  190. /**
  191. * The type of @c result_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 function type, @c result_type is a synonym for
  195. * the return type of @c T;
  196. *
  197. * @li if @c T is a class type with a member type @c result_type, then @c
  198. * result_type is a synonym for @c T::result_type;
  199. *
  200. * @li otherwise @c result_type is not defined.
  201. */
  202. typedef see_below result_type;
  203. /// The type of the function's argument.
  204. /**
  205. * The type of @c argument_type is based on the type @c T of the wrapper's
  206. * target object:
  207. *
  208. * @li if @c T is a pointer to a function type accepting a single argument,
  209. * @c 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 argument_type, then @c
  212. * argument_type is a synonym for @c T::argument_type;
  213. *
  214. * @li otherwise @c argument_type is not defined.
  215. */
  216. typedef see_below argument_type;
  217. /// The type of the function's first argument.
  218. /**
  219. * The type of @c first_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. * first_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 first_argument_type is a synonym for @c T::first_argument_type;
  227. *
  228. * @li otherwise @c first_argument_type is not defined.
  229. */
  230. typedef see_below first_argument_type;
  231. /// The type of the function's second argument.
  232. /**
  233. * The type of @c second_argument_type is based on the type @c T of the
  234. * wrapper's target object:
  235. *
  236. * @li if @c T is a pointer to a function type accepting two arguments, @c
  237. * second_argument_type is a synonym for the return type of @c T;
  238. *
  239. * @li if @c T is a class type with a member type @c first_argument_type,
  240. * then @c second_argument_type is a synonym for @c T::second_argument_type;
  241. *
  242. * @li otherwise @c second_argument_type is not defined.
  243. */
  244. typedef see_below second_argument_type;
  245. #endif // defined(GENERATING_DOCUMENTATION)
  246. /// Construct an executor wrapper for the specified object.
  247. /**
  248. * This constructor is only valid if the type @c T is constructible from type
  249. * @c U.
  250. */
  251. template <typename U>
  252. executor_binder(executor_arg_t, const executor_type& e,
  253. BOOST_ASIO_MOVE_ARG(U) u)
  254. : base_type(e, BOOST_ASIO_MOVE_CAST(U)(u))
  255. {
  256. }
  257. /// Copy constructor.
  258. executor_binder(const executor_binder& other)
  259. : base_type(other.get_executor(), other.get())
  260. {
  261. }
  262. /// Construct a copy, but specify a different executor.
  263. executor_binder(executor_arg_t, const executor_type& e,
  264. const executor_binder& other)
  265. : base_type(e, other.get())
  266. {
  267. }
  268. /// Construct a copy of a different executor wrapper type.
  269. /**
  270. * This constructor is only valid if the @c Executor type is constructible
  271. * from type @c OtherExecutor, and the type @c T is constructible from type
  272. * @c U.
  273. */
  274. template <typename U, typename OtherExecutor>
  275. executor_binder(const executor_binder<U, OtherExecutor>& other)
  276. : base_type(other.get_executor(), other.get())
  277. {
  278. }
  279. /// Construct a copy of a different executor wrapper type, but specify a
  280. /// different executor.
  281. /**
  282. * This constructor is only valid if the type @c T is constructible from type
  283. * @c U.
  284. */
  285. template <typename U, typename OtherExecutor>
  286. executor_binder(executor_arg_t, const executor_type& e,
  287. const executor_binder<U, OtherExecutor>& other)
  288. : base_type(e, other.get())
  289. {
  290. }
  291. #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  292. /// Move constructor.
  293. executor_binder(executor_binder&& other)
  294. : base_type(BOOST_ASIO_MOVE_CAST(executor_type)(other.get_executor()),
  295. BOOST_ASIO_MOVE_CAST(T)(other.get()))
  296. {
  297. }
  298. /// Move construct the target object, but specify a different executor.
  299. executor_binder(executor_arg_t, const executor_type& e,
  300. executor_binder&& other)
  301. : base_type(e, BOOST_ASIO_MOVE_CAST(T)(other.get()))
  302. {
  303. }
  304. /// Move construct from a different executor wrapper type.
  305. template <typename U, typename OtherExecutor>
  306. executor_binder(executor_binder<U, OtherExecutor>&& other)
  307. : base_type(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()),
  308. BOOST_ASIO_MOVE_CAST(U)(other.get()))
  309. {
  310. }
  311. /// Move construct from a different executor wrapper type, but specify a
  312. /// different executor.
  313. template <typename U, typename OtherExecutor>
  314. executor_binder(executor_arg_t, const executor_type& e,
  315. executor_binder<U, OtherExecutor>&& other)
  316. : base_type(e, BOOST_ASIO_MOVE_CAST(U)(other.get()))
  317. {
  318. }
  319. #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  320. /// Destructor.
  321. ~executor_binder()
  322. {
  323. }
  324. /// Obtain a reference to the target object.
  325. target_type& get() BOOST_ASIO_NOEXCEPT
  326. {
  327. return this->target_;
  328. }
  329. /// Obtain a reference to the target object.
  330. const target_type& get() const BOOST_ASIO_NOEXCEPT
  331. {
  332. return this->target_;
  333. }
  334. /// Obtain the associated executor.
  335. executor_type get_executor() const BOOST_ASIO_NOEXCEPT
  336. {
  337. return this->executor_;
  338. }
  339. #if defined(GENERATING_DOCUMENTATION)
  340. template <typename... Args> auto operator()(Args&& ...);
  341. template <typename... Args> auto operator()(Args&& ...) const;
  342. #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  343. /// Forwarding function call operator.
  344. template <typename... Args>
  345. typename result_of<T(Args...)>::type operator()(
  346. BOOST_ASIO_MOVE_ARG(Args)... args)
  347. {
  348. return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...);
  349. }
  350. /// Forwarding function call operator.
  351. template <typename... Args>
  352. typename result_of<T(Args...)>::type operator()(
  353. BOOST_ASIO_MOVE_ARG(Args)... args) const
  354. {
  355. return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...);
  356. }
  357. #elif defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
  358. typename detail::executor_binder_result_of0<T>::type operator()()
  359. {
  360. return this->target_();
  361. }
  362. typename detail::executor_binder_result_of0<T>::type operator()() const
  363. {
  364. return this->target_();
  365. }
  366. #define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
  367. template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  368. typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::type operator()( \
  369. BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \
  370. { \
  371. return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
  372. } \
  373. \
  374. template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  375. typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::type operator()( \
  376. BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \
  377. { \
  378. return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
  379. } \
  380. /**/
  381. BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
  382. #undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
  383. #else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
  384. typedef typename detail::executor_binder_result_type<T>::result_type_or_void
  385. result_type_or_void;
  386. result_type_or_void operator()()
  387. {
  388. return this->target_();
  389. }
  390. result_type_or_void operator()() const
  391. {
  392. return this->target_();
  393. }
  394. #define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
  395. template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  396. result_type_or_void operator()( \
  397. BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \
  398. { \
  399. return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
  400. } \
  401. \
  402. template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  403. result_type_or_void operator()( \
  404. BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \
  405. { \
  406. return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
  407. } \
  408. /**/
  409. BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
  410. #undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
  411. #endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
  412. private:
  413. typedef detail::executor_binder_base<T, Executor,
  414. uses_executor<T, Executor>::value> base_type;
  415. };
  416. /// Associate an object of type @c T with an executor of type @c Executor.
  417. template <typename Executor, typename T>
  418. inline executor_binder<typename decay<T>::type, Executor>
  419. bind_executor(const Executor& ex, BOOST_ASIO_MOVE_ARG(T) t,
  420. typename constraint<
  421. is_executor<Executor>::value || execution::is_executor<Executor>::value
  422. >::type = 0)
  423. {
  424. return executor_binder<typename decay<T>::type, Executor>(
  425. executor_arg_t(), ex, BOOST_ASIO_MOVE_CAST(T)(t));
  426. }
  427. /// Associate an object of type @c T with an execution context's executor.
  428. template <typename ExecutionContext, typename T>
  429. inline executor_binder<typename decay<T>::type,
  430. typename ExecutionContext::executor_type>
  431. bind_executor(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(T) t,
  432. typename constraint<is_convertible<
  433. ExecutionContext&, execution_context&>::value>::type = 0)
  434. {
  435. return executor_binder<typename decay<T>::type,
  436. typename ExecutionContext::executor_type>(
  437. executor_arg_t(), ctx.get_executor(), BOOST_ASIO_MOVE_CAST(T)(t));
  438. }
  439. #if !defined(GENERATING_DOCUMENTATION)
  440. template <typename T, typename Executor>
  441. struct uses_executor<executor_binder<T, Executor>, Executor>
  442. : true_type {};
  443. template <typename T, typename Executor, typename Signature>
  444. class async_result<executor_binder<T, Executor>, Signature>
  445. {
  446. public:
  447. typedef executor_binder<
  448. typename async_result<T, Signature>::completion_handler_type, Executor>
  449. completion_handler_type;
  450. typedef typename async_result<T, Signature>::return_type return_type;
  451. explicit async_result(executor_binder<T, Executor>& b)
  452. : target_(b.get())
  453. {
  454. }
  455. return_type get()
  456. {
  457. return target_.get();
  458. }
  459. private:
  460. async_result(const async_result&) BOOST_ASIO_DELETED;
  461. async_result& operator=(const async_result&) BOOST_ASIO_DELETED;
  462. async_result<T, Signature> target_;
  463. };
  464. template <typename T, typename Executor, typename Allocator>
  465. struct associated_allocator<executor_binder<T, Executor>, Allocator>
  466. {
  467. typedef typename associated_allocator<T, Allocator>::type type;
  468. static type get(const executor_binder<T, Executor>& b,
  469. const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
  470. {
  471. return associated_allocator<T, Allocator>::get(b.get(), a);
  472. }
  473. };
  474. template <typename T, typename Executor, typename Executor1>
  475. struct associated_executor<executor_binder<T, Executor>, Executor1>
  476. {
  477. typedef Executor type;
  478. static type get(const executor_binder<T, Executor>& b,
  479. const Executor1& = Executor1()) BOOST_ASIO_NOEXCEPT
  480. {
  481. return b.get_executor();
  482. }
  483. };
  484. #endif // !defined(GENERATING_DOCUMENTATION)
  485. } // namespace asio
  486. } // namespace boost
  487. #include <boost/asio/detail/pop_options.hpp>
  488. #endif // BOOST_ASIO_BIND_EXECUTOR_HPP