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.

342 lines
9.6KB

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