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