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