cancellation_signal.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. //
  2. // cancellation_signal.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_CANCELLATION_SIGNAL_HPP
  11. #define ASIO_CANCELLATION_SIGNAL_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 <cassert>
  17. #include <new>
  18. #include <utility>
  19. #include "asio/cancellation_type.hpp"
  20. #include "asio/detail/cstddef.hpp"
  21. #include "asio/detail/type_traits.hpp"
  22. #include "asio/detail/push_options.hpp"
  23. namespace asio {
  24. namespace detail {
  25. class cancellation_handler_base
  26. {
  27. public:
  28. virtual void call(cancellation_type_t) = 0;
  29. virtual std::pair<void*, std::size_t> destroy() noexcept = 0;
  30. protected:
  31. ~cancellation_handler_base() {}
  32. };
  33. template <typename Handler>
  34. class cancellation_handler
  35. : public cancellation_handler_base
  36. {
  37. public:
  38. template <typename... Args>
  39. cancellation_handler(std::size_t size, Args&&... args)
  40. : handler_(static_cast<Args&&>(args)...),
  41. size_(size)
  42. {
  43. }
  44. void call(cancellation_type_t type)
  45. {
  46. handler_(type);
  47. }
  48. std::pair<void*, std::size_t> destroy() noexcept
  49. {
  50. std::pair<void*, std::size_t> mem(this, size_);
  51. this->cancellation_handler::~cancellation_handler();
  52. return mem;
  53. }
  54. Handler& handler() noexcept
  55. {
  56. return handler_;
  57. }
  58. private:
  59. ~cancellation_handler()
  60. {
  61. }
  62. Handler handler_;
  63. std::size_t size_;
  64. };
  65. } // namespace detail
  66. class cancellation_slot;
  67. /// A cancellation signal with a single slot.
  68. class cancellation_signal
  69. {
  70. public:
  71. constexpr cancellation_signal()
  72. : handler_(0)
  73. {
  74. }
  75. ASIO_DECL ~cancellation_signal();
  76. /// Emits the signal and causes invocation of the slot's handler, if any.
  77. void emit(cancellation_type_t type)
  78. {
  79. if (handler_)
  80. handler_->call(type);
  81. }
  82. /// Returns the single slot associated with the signal.
  83. /**
  84. * The signal object must remain valid for as long the slot may be used.
  85. * Destruction of the signal invalidates the slot.
  86. */
  87. cancellation_slot slot() noexcept;
  88. private:
  89. cancellation_signal(const cancellation_signal&) = delete;
  90. cancellation_signal& operator=(const cancellation_signal&) = delete;
  91. detail::cancellation_handler_base* handler_;
  92. };
  93. /// A slot associated with a cancellation signal.
  94. class cancellation_slot
  95. {
  96. public:
  97. /// Creates a slot that is not connected to any cancellation signal.
  98. constexpr cancellation_slot()
  99. : handler_(0)
  100. {
  101. }
  102. /// Installs a handler into the slot, constructing the new object directly.
  103. /**
  104. * Destroys any existing handler in the slot, then installs the new handler,
  105. * constructing it with the supplied @c args.
  106. *
  107. * The handler is a function object to be called when the signal is emitted.
  108. * The signature of the handler must be
  109. * @code void handler(asio::cancellation_type_t); @endcode
  110. *
  111. * @param args Arguments to be passed to the @c CancellationHandler object's
  112. * constructor.
  113. *
  114. * @returns A reference to the newly installed handler.
  115. *
  116. * @note Handlers installed into the slot via @c emplace are not required to
  117. * be copy constructible or move constructible.
  118. */
  119. template <typename CancellationHandler, typename... Args>
  120. CancellationHandler& emplace(Args&&... args)
  121. {
  122. typedef detail::cancellation_handler<CancellationHandler>
  123. cancellation_handler_type;
  124. auto_delete_helper del = { prepare_memory(
  125. sizeof(cancellation_handler_type),
  126. alignof(CancellationHandler)) };
  127. cancellation_handler_type* handler_obj =
  128. new (del.mem.first) cancellation_handler_type(
  129. del.mem.second, static_cast<Args&&>(args)...);
  130. del.mem.first = 0;
  131. *handler_ = handler_obj;
  132. return handler_obj->handler();
  133. }
  134. /// Installs a handler into the slot.
  135. /**
  136. * Destroys any existing handler in the slot, then installs the new handler,
  137. * constructing it as a decay-copy of the supplied handler.
  138. *
  139. * The handler is a function object to be called when the signal is emitted.
  140. * The signature of the handler must be
  141. * @code void handler(asio::cancellation_type_t); @endcode
  142. *
  143. * @param handler The handler to be installed.
  144. *
  145. * @returns A reference to the newly installed handler.
  146. */
  147. template <typename CancellationHandler>
  148. decay_t<CancellationHandler>& assign(CancellationHandler&& handler)
  149. {
  150. return this->emplace<decay_t<CancellationHandler>>(
  151. static_cast<CancellationHandler&&>(handler));
  152. }
  153. /// Clears the slot.
  154. /**
  155. * Destroys any existing handler in the slot.
  156. */
  157. ASIO_DECL void clear();
  158. /// Returns whether the slot is connected to a signal.
  159. constexpr bool is_connected() const noexcept
  160. {
  161. return handler_ != 0;
  162. }
  163. /// Returns whether the slot is connected and has an installed handler.
  164. constexpr bool has_handler() const noexcept
  165. {
  166. return handler_ != 0 && *handler_ != 0;
  167. }
  168. /// Compare two slots for equality.
  169. friend constexpr bool operator==(const cancellation_slot& lhs,
  170. const cancellation_slot& rhs) noexcept
  171. {
  172. return lhs.handler_ == rhs.handler_;
  173. }
  174. /// Compare two slots for inequality.
  175. friend constexpr bool operator!=(const cancellation_slot& lhs,
  176. const cancellation_slot& rhs) noexcept
  177. {
  178. return lhs.handler_ != rhs.handler_;
  179. }
  180. private:
  181. friend class cancellation_signal;
  182. constexpr cancellation_slot(int,
  183. detail::cancellation_handler_base** handler)
  184. : handler_(handler)
  185. {
  186. }
  187. ASIO_DECL std::pair<void*, std::size_t> prepare_memory(
  188. std::size_t size, std::size_t align);
  189. struct auto_delete_helper
  190. {
  191. std::pair<void*, std::size_t> mem;
  192. ASIO_DECL ~auto_delete_helper();
  193. };
  194. detail::cancellation_handler_base** handler_;
  195. };
  196. inline cancellation_slot cancellation_signal::slot() noexcept
  197. {
  198. return cancellation_slot(0, &handler_);
  199. }
  200. } // namespace asio
  201. #include "asio/detail/pop_options.hpp"
  202. #if defined(ASIO_HEADER_ONLY)
  203. # include "asio/impl/cancellation_signal.ipp"
  204. #endif // defined(ASIO_HEADER_ONLY)
  205. #endif // ASIO_CANCELLATION_SIGNAL_HPP