cancellation_signal.hpp 6.3 KB

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