executor.hpp 9.8 KB

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