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.

581 lines
16KB

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