bind_executor.hpp 17 KB

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