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.

347 lines
9.8KB

  1. //
  2. // 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_EXECUTOR_HPP
  11. #define ASIO_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 <typeinfo>
  17. #include "asio/detail/cstddef.hpp"
  18. #include "asio/detail/memory.hpp"
  19. #include "asio/detail/throw_exception.hpp"
  20. #include "asio/execution_context.hpp"
  21. #include "asio/is_executor.hpp"
  22. #include "asio/detail/push_options.hpp"
  23. namespace asio {
  24. /// Exception thrown when trying to access an empty polymorphic executor.
  25. class bad_executor
  26. : public std::exception
  27. {
  28. public:
  29. /// Constructor.
  30. ASIO_DECL bad_executor() ASIO_NOEXCEPT;
  31. /// Obtain message associated with exception.
  32. ASIO_DECL virtual const char* what() const
  33. ASIO_NOEXCEPT_OR_NOTHROW;
  34. };
  35. /// Polymorphic wrapper for executors.
  36. class executor
  37. {
  38. public:
  39. /// Default constructor.
  40. executor() ASIO_NOEXCEPT
  41. : impl_(0)
  42. {
  43. }
  44. /// Construct from nullptr.
  45. executor(nullptr_t) ASIO_NOEXCEPT
  46. : impl_(0)
  47. {
  48. }
  49. /// Copy constructor.
  50. executor(const executor& other) ASIO_NOEXCEPT
  51. : impl_(other.clone())
  52. {
  53. }
  54. #if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  55. /// Move constructor.
  56. executor(executor&& other) ASIO_NOEXCEPT
  57. : impl_(other.impl_)
  58. {
  59. other.impl_ = 0;
  60. }
  61. #endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  62. /// Construct a polymorphic wrapper for the specified executor.
  63. template <typename Executor>
  64. executor(Executor e);
  65. /// Allocator-aware constructor to create a polymorphic wrapper for the
  66. /// specified executor.
  67. template <typename Executor, typename Allocator>
  68. executor(allocator_arg_t, const Allocator& a, Executor e);
  69. /// Destructor.
  70. ~executor()
  71. {
  72. destroy();
  73. }
  74. /// Assignment operator.
  75. executor& operator=(const executor& other) ASIO_NOEXCEPT
  76. {
  77. destroy();
  78. impl_ = other.clone();
  79. return *this;
  80. }
  81. #if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  82. // Move assignment operator.
  83. executor& operator=(executor&& other) ASIO_NOEXCEPT
  84. {
  85. destroy();
  86. impl_ = other.impl_;
  87. other.impl_ = 0;
  88. return *this;
  89. }
  90. #endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  91. /// Assignment operator for nullptr_t.
  92. executor& operator=(nullptr_t) ASIO_NOEXCEPT
  93. {
  94. destroy();
  95. impl_ = 0;
  96. return *this;
  97. }
  98. /// Assignment operator to create a polymorphic wrapper for the specified
  99. /// executor.
  100. template <typename Executor>
  101. executor& operator=(ASIO_MOVE_ARG(Executor) e) ASIO_NOEXCEPT
  102. {
  103. executor tmp(ASIO_MOVE_CAST(Executor)(e));
  104. destroy();
  105. impl_ = tmp.impl_;
  106. tmp.impl_ = 0;
  107. return *this;
  108. }
  109. /// Obtain the underlying execution context.
  110. execution_context& context() const ASIO_NOEXCEPT
  111. {
  112. return get_impl()->context();
  113. }
  114. /// Inform the executor that it has some outstanding work to do.
  115. void on_work_started() const ASIO_NOEXCEPT
  116. {
  117. get_impl()->on_work_started();
  118. }
  119. /// Inform the executor that some work is no longer outstanding.
  120. void on_work_finished() const ASIO_NOEXCEPT
  121. {
  122. get_impl()->on_work_finished();
  123. }
  124. /// Request the executor to invoke the given function object.
  125. /**
  126. * This function is used to ask the executor to execute the given function
  127. * object. The function object is executed according to the rules of the
  128. * target executor object.
  129. *
  130. * @param f The function object to be called. The executor will make a copy
  131. * of the handler object as required. The function signature of the function
  132. * object must be: @code void function(); @endcode
  133. *
  134. * @param a An allocator that may be used by the executor to allocate the
  135. * internal storage needed for function invocation.
  136. */
  137. template <typename Function, typename Allocator>
  138. void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
  139. /// Request the executor to invoke the given function object.
  140. /**
  141. * This function is used to ask the executor to execute the given function
  142. * object. The function object is executed according to the rules of the
  143. * target executor object.
  144. *
  145. * @param f The function object to be called. The executor will make
  146. * a copy of the handler object as required. The function signature of the
  147. * function object must be: @code void function(); @endcode
  148. *
  149. * @param a An allocator that may be used by the executor to allocate the
  150. * internal storage needed for function invocation.
  151. */
  152. template <typename Function, typename Allocator>
  153. void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
  154. /// Request the executor to invoke the given function object.
  155. /**
  156. * This function is used to ask the executor to execute the given function
  157. * object. The function object is executed according to the rules of the
  158. * target executor object.
  159. *
  160. * @param f The function object to be called. The executor will make
  161. * a copy of the handler object as required. The function signature of the
  162. * function object must be: @code void function(); @endcode
  163. *
  164. * @param a An allocator that may be used by the executor to allocate the
  165. * internal storage needed for function invocation.
  166. */
  167. template <typename Function, typename Allocator>
  168. void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
  169. struct unspecified_bool_type_t {};
  170. typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
  171. static void unspecified_bool_true(unspecified_bool_type_t) {}
  172. /// Operator to test if the executor contains a valid target.
  173. operator unspecified_bool_type() const ASIO_NOEXCEPT
  174. {
  175. return impl_ ? &executor::unspecified_bool_true : 0;
  176. }
  177. /// Obtain type information for the target executor object.
  178. /**
  179. * @returns If @c *this has a target type of type @c T, <tt>typeid(T)</tt>;
  180. * otherwise, <tt>typeid(void)</tt>.
  181. */
  182. #if !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
  183. const std::type_info& target_type() const ASIO_NOEXCEPT
  184. {
  185. return impl_ ? impl_->target_type() : typeid(void);
  186. }
  187. #else // !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
  188. const void* target_type() const ASIO_NOEXCEPT
  189. {
  190. return impl_ ? impl_->target_type() : 0;
  191. }
  192. #endif // !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
  193. /// Obtain a pointer to the target executor object.
  194. /**
  195. * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored
  196. * executor target; otherwise, a null pointer.
  197. */
  198. template <typename Executor>
  199. Executor* target() ASIO_NOEXCEPT;
  200. /// Obtain a pointer to the target executor object.
  201. /**
  202. * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored
  203. * executor target; otherwise, a null pointer.
  204. */
  205. template <typename Executor>
  206. const Executor* target() const ASIO_NOEXCEPT;
  207. /// Compare two executors for equality.
  208. friend bool operator==(const executor& a,
  209. const executor& b) ASIO_NOEXCEPT
  210. {
  211. if (a.impl_ == b.impl_)
  212. return true;
  213. if (!a.impl_ || !b.impl_)
  214. return false;
  215. return a.impl_->equals(b.impl_);
  216. }
  217. /// Compare two executors for inequality.
  218. friend bool operator!=(const executor& a,
  219. const executor& b) ASIO_NOEXCEPT
  220. {
  221. return !(a == b);
  222. }
  223. private:
  224. #if !defined(GENERATING_DOCUMENTATION)
  225. class function;
  226. template <typename, typename> class impl;
  227. #if !defined(ASIO_NO_TYPEID)
  228. typedef const std::type_info& type_id_result_type;
  229. #else // !defined(ASIO_NO_TYPEID)
  230. typedef const void* type_id_result_type;
  231. #endif // !defined(ASIO_NO_TYPEID)
  232. template <typename T>
  233. static type_id_result_type type_id()
  234. {
  235. #if !defined(ASIO_NO_TYPEID)
  236. return typeid(T);
  237. #else // !defined(ASIO_NO_TYPEID)
  238. static int unique_id;
  239. return &unique_id;
  240. #endif // !defined(ASIO_NO_TYPEID)
  241. }
  242. // Base class for all polymorphic executor implementations.
  243. class impl_base
  244. {
  245. public:
  246. virtual impl_base* clone() const ASIO_NOEXCEPT = 0;
  247. virtual void destroy() ASIO_NOEXCEPT = 0;
  248. virtual execution_context& context() ASIO_NOEXCEPT = 0;
  249. virtual void on_work_started() ASIO_NOEXCEPT = 0;
  250. virtual void on_work_finished() ASIO_NOEXCEPT = 0;
  251. virtual void dispatch(ASIO_MOVE_ARG(function)) = 0;
  252. virtual void post(ASIO_MOVE_ARG(function)) = 0;
  253. virtual void defer(ASIO_MOVE_ARG(function)) = 0;
  254. virtual type_id_result_type target_type() const ASIO_NOEXCEPT = 0;
  255. virtual void* target() ASIO_NOEXCEPT = 0;
  256. virtual const void* target() const ASIO_NOEXCEPT = 0;
  257. virtual bool equals(const impl_base* e) const ASIO_NOEXCEPT = 0;
  258. protected:
  259. impl_base(bool fast_dispatch) : fast_dispatch_(fast_dispatch) {}
  260. virtual ~impl_base() {}
  261. private:
  262. friend class executor;
  263. const bool fast_dispatch_;
  264. };
  265. // Helper function to check and return the implementation pointer.
  266. impl_base* get_impl() const
  267. {
  268. if (!impl_)
  269. {
  270. bad_executor ex;
  271. asio::detail::throw_exception(ex);
  272. }
  273. return impl_;
  274. }
  275. // Helper function to clone another implementation.
  276. impl_base* clone() const ASIO_NOEXCEPT
  277. {
  278. return impl_ ? impl_->clone() : 0;
  279. }
  280. // Helper function to destroy an implementation.
  281. void destroy() ASIO_NOEXCEPT
  282. {
  283. if (impl_)
  284. impl_->destroy();
  285. }
  286. impl_base* impl_;
  287. #endif // !defined(GENERATING_DOCUMENTATION)
  288. };
  289. #if !defined(GENERATING_DOCUMENTATION)
  290. template <> struct is_executor<executor> : true_type {};
  291. #endif // !defined(GENERATING_DOCUMENTATION)
  292. } // namespace asio
  293. ASIO_USES_ALLOCATOR(asio::executor)
  294. #include "asio/detail/pop_options.hpp"
  295. #include "asio/impl/executor.hpp"
  296. #if defined(ASIO_HEADER_ONLY)
  297. # include "asio/impl/executor.ipp"
  298. #endif // defined(ASIO_HEADER_ONLY)
  299. #endif // ASIO_EXECUTOR_HPP