Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bind_executor.hpp 16KB

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