1 | // |
2 | // execution/any_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_EXECUTION_ANY_EXECUTOR_HPP |
12 | #define BOOST_ASIO_EXECUTION_ANY_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 | #include <new> |
20 | #include <typeinfo> |
21 | #include <boost/asio/detail/assert.hpp> |
22 | #include <boost/asio/detail/atomic_count.hpp> |
23 | #include <boost/asio/detail/cstddef.hpp> |
24 | #include <boost/asio/detail/executor_function.hpp> |
25 | #include <boost/asio/detail/memory.hpp> |
26 | #include <boost/asio/detail/non_const_lvalue.hpp> |
27 | #include <boost/asio/detail/scoped_ptr.hpp> |
28 | #include <boost/asio/detail/type_traits.hpp> |
29 | #include <boost/asio/detail/throw_exception.hpp> |
30 | #include <boost/asio/execution/bad_executor.hpp> |
31 | #include <boost/asio/execution/blocking.hpp> |
32 | #include <boost/asio/execution/executor.hpp> |
33 | #include <boost/asio/prefer.hpp> |
34 | #include <boost/asio/query.hpp> |
35 | #include <boost/asio/require.hpp> |
36 | |
37 | #include <boost/asio/detail/push_options.hpp> |
38 | |
39 | namespace boost { |
40 | namespace asio { |
41 | |
42 | #if defined(GENERATING_DOCUMENTATION) |
43 | |
44 | namespace execution { |
45 | |
46 | /// Polymorphic executor wrapper. |
47 | template <typename... SupportableProperties> |
48 | class any_executor |
49 | { |
50 | public: |
51 | /// Default constructor. |
52 | any_executor() noexcept; |
53 | |
54 | /// Construct in an empty state. Equivalent effects to default constructor. |
55 | any_executor(nullptr_t) noexcept; |
56 | |
57 | /// Copy constructor. |
58 | any_executor(const any_executor& e) noexcept; |
59 | |
60 | /// Move constructor. |
61 | any_executor(any_executor&& e) noexcept; |
62 | |
63 | /// Construct to point to the same target as another any_executor. |
64 | template <class... OtherSupportableProperties> |
65 | any_executor(any_executor<OtherSupportableProperties...> e); |
66 | |
67 | /// Construct to point to the same target as another any_executor. |
68 | template <class... OtherSupportableProperties> |
69 | any_executor(std::nothrow_t, |
70 | any_executor<OtherSupportableProperties...> e) noexcept; |
71 | |
72 | /// Construct to point to the same target as another any_executor. |
73 | any_executor(std::nothrow_t, const any_executor& e) noexcept; |
74 | |
75 | /// Construct to point to the same target as another any_executor. |
76 | any_executor(std::nothrow_t, any_executor&& e) noexcept; |
77 | |
78 | /// Construct a polymorphic wrapper for the specified executor. |
79 | template <typename Executor> |
80 | any_executor(Executor e); |
81 | |
82 | /// Construct a polymorphic wrapper for the specified executor. |
83 | template <typename Executor> |
84 | any_executor(std::nothrow_t, Executor e) noexcept; |
85 | |
86 | /// Assignment operator. |
87 | any_executor& operator=(const any_executor& e) noexcept; |
88 | |
89 | /// Move assignment operator. |
90 | any_executor& operator=(any_executor&& e) noexcept; |
91 | |
92 | /// Assignment operator that sets the polymorphic wrapper to the empty state. |
93 | any_executor& operator=(nullptr_t); |
94 | |
95 | /// Assignment operator to create a polymorphic wrapper for the specified |
96 | /// executor. |
97 | template <typename Executor> |
98 | any_executor& operator=(Executor e); |
99 | |
100 | /// Destructor. |
101 | ~any_executor(); |
102 | |
103 | /// Swap targets with another polymorphic wrapper. |
104 | void swap(any_executor& other) noexcept; |
105 | |
106 | /// Obtain a polymorphic wrapper with the specified property. |
107 | /** |
108 | * Do not call this function directly. It is intended for use with the |
109 | * boost::asio::require and boost::asio::prefer customisation points. |
110 | * |
111 | * For example: |
112 | * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...; |
113 | * auto ex2 = boost::asio::requre(ex, execution::blocking.possibly); @endcode |
114 | */ |
115 | template <typename Property> |
116 | any_executor require(Property) const; |
117 | |
118 | /// Obtain a polymorphic wrapper with the specified property. |
119 | /** |
120 | * Do not call this function directly. It is intended for use with the |
121 | * boost::asio::prefer customisation point. |
122 | * |
123 | * For example: |
124 | * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...; |
125 | * auto ex2 = boost::asio::prefer(ex, execution::blocking.possibly); @endcode |
126 | */ |
127 | template <typename Property> |
128 | any_executor prefer(Property) const; |
129 | |
130 | /// Obtain the value associated with the specified property. |
131 | /** |
132 | * Do not call this function directly. It is intended for use with the |
133 | * boost::asio::query customisation point. |
134 | * |
135 | * For example: |
136 | * @code execution::any_executor<execution::occupancy_t> ex = ...; |
137 | * size_t n = boost::asio::query(ex, execution::occupancy); @endcode |
138 | */ |
139 | template <typename Property> |
140 | typename Property::polymorphic_query_result_type query(Property) const; |
141 | |
142 | /// Execute the function on the target executor. |
143 | /** |
144 | * Throws boost::asio::bad_executor if the polymorphic wrapper has no target. |
145 | */ |
146 | template <typename Function> |
147 | void execute(Function&& f) const; |
148 | |
149 | /// Obtain the underlying execution context. |
150 | /** |
151 | * This function is provided for backward compatibility. It is automatically |
152 | * defined when the @c SupportableProperties... list includes a property of |
153 | * type <tt>execution::context_as<U></tt>, for some type <tt>U</tt>. |
154 | */ |
155 | automatically_determined context() const; |
156 | |
157 | /// Determine whether the wrapper has a target executor. |
158 | /** |
159 | * @returns @c true if the polymorphic wrapper has a target executor, |
160 | * otherwise false. |
161 | */ |
162 | explicit operator bool() const noexcept; |
163 | |
164 | /// Get the type of the target executor. |
165 | const type_info& target_type() const noexcept; |
166 | |
167 | /// Get a pointer to the target executor. |
168 | template <typename Executor> Executor* target() noexcept; |
169 | |
170 | /// Get a pointer to the target executor. |
171 | template <typename Executor> const Executor* target() const noexcept; |
172 | }; |
173 | |
174 | /// Equality operator. |
175 | /** |
176 | * @relates any_executor |
177 | */ |
178 | template <typename... SupportableProperties> |
179 | bool operator==(const any_executor<SupportableProperties...>& a, |
180 | const any_executor<SupportableProperties...>& b) noexcept; |
181 | |
182 | /// Equality operator. |
183 | /** |
184 | * @relates any_executor |
185 | */ |
186 | template <typename... SupportableProperties> |
187 | bool operator==(const any_executor<SupportableProperties...>& a, |
188 | nullptr_t) noexcept; |
189 | |
190 | /// Equality operator. |
191 | /** |
192 | * @relates any_executor |
193 | */ |
194 | template <typename... SupportableProperties> |
195 | bool operator==(nullptr_t, |
196 | const any_executor<SupportableProperties...>& b) noexcept; |
197 | |
198 | /// Inequality operator. |
199 | /** |
200 | * @relates any_executor |
201 | */ |
202 | template <typename... SupportableProperties> |
203 | bool operator!=(const any_executor<SupportableProperties...>& a, |
204 | const any_executor<SupportableProperties...>& b) noexcept; |
205 | |
206 | /// Inequality operator. |
207 | /** |
208 | * @relates any_executor |
209 | */ |
210 | template <typename... SupportableProperties> |
211 | bool operator!=(const any_executor<SupportableProperties...>& a, |
212 | nullptr_t) noexcept; |
213 | |
214 | /// Inequality operator. |
215 | /** |
216 | * @relates any_executor |
217 | */ |
218 | template <typename... SupportableProperties> |
219 | bool operator!=(nullptr_t, |
220 | const any_executor<SupportableProperties...>& b) noexcept; |
221 | |
222 | } // namespace execution |
223 | |
224 | #else // defined(GENERATING_DOCUMENTATION) |
225 | |
226 | namespace execution { |
227 | |
228 | #if !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) |
229 | #define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL |
230 | |
231 | template <typename... SupportableProperties> |
232 | class any_executor; |
233 | |
234 | #endif // !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) |
235 | |
236 | template <typename U> |
237 | struct context_as_t; |
238 | |
239 | namespace detail { |
240 | |
241 | // Traits used to detect whether a property is requirable or preferable, taking |
242 | // into account that T::is_requirable or T::is_preferable may not not be well |
243 | // formed. |
244 | |
245 | template <typename T, typename = void> |
246 | struct is_requirable : false_type {}; |
247 | |
248 | template <typename T> |
249 | struct is_requirable<T, enable_if_t<T::is_requirable>> : true_type {}; |
250 | |
251 | template <typename T, typename = void> |
252 | struct is_preferable : false_type {}; |
253 | |
254 | template <typename T> |
255 | struct is_preferable<T, enable_if_t<T::is_preferable>> : true_type {}; |
256 | |
257 | // Trait used to detect context_as property, for backward compatibility. |
258 | |
259 | template <typename T> |
260 | struct is_context_as : false_type {}; |
261 | |
262 | template <typename U> |
263 | struct is_context_as<context_as_t<U>> : true_type {}; |
264 | |
265 | // Helper template to: |
266 | // - Check if a target can supply the supportable properties. |
267 | // - Find the first convertible-from-T property in the list. |
268 | |
269 | template <std::size_t I, typename Props> |
270 | struct supportable_properties; |
271 | |
272 | template <std::size_t I, typename Prop> |
273 | struct supportable_properties<I, void(Prop)> |
274 | { |
275 | template <typename T> |
276 | struct is_valid_target : integral_constant<bool, |
277 | ( |
278 | is_requirable<Prop>::value |
279 | ? can_require<T, Prop>::value |
280 | : true |
281 | ) |
282 | && |
283 | ( |
284 | is_preferable<Prop>::value |
285 | ? can_prefer<T, Prop>::value |
286 | : true |
287 | ) |
288 | && |
289 | ( |
290 | !is_requirable<Prop>::value && !is_preferable<Prop>::value |
291 | ? can_query<T, Prop>::value |
292 | : true |
293 | ) |
294 | > |
295 | { |
296 | }; |
297 | |
298 | struct found |
299 | { |
300 | static constexpr bool value = true; |
301 | typedef Prop type; |
302 | typedef typename Prop::polymorphic_query_result_type query_result_type; |
303 | static constexpr std::size_t index = I; |
304 | }; |
305 | |
306 | struct not_found |
307 | { |
308 | static constexpr bool value = false; |
309 | }; |
310 | |
311 | template <typename T> |
312 | struct find_convertible_property : |
313 | conditional_t< |
314 | is_same<T, Prop>::value || is_convertible<T, Prop>::value, |
315 | found, |
316 | not_found |
317 | > {}; |
318 | |
319 | template <typename T> |
320 | struct find_convertible_requirable_property : |
321 | conditional_t< |
322 | is_requirable<Prop>::value |
323 | && (is_same<T, Prop>::value || is_convertible<T, Prop>::value), |
324 | found, |
325 | not_found |
326 | > {}; |
327 | |
328 | template <typename T> |
329 | struct find_convertible_preferable_property : |
330 | conditional_t< |
331 | is_preferable<Prop>::value |
332 | && (is_same<T, Prop>::value || is_convertible<T, Prop>::value), |
333 | found, |
334 | not_found |
335 | > {}; |
336 | |
337 | struct find_context_as_property : |
338 | conditional_t< |
339 | is_context_as<Prop>::value, |
340 | found, |
341 | not_found |
342 | > {}; |
343 | }; |
344 | |
345 | template <std::size_t I, typename Head, typename... Tail> |
346 | struct supportable_properties<I, void(Head, Tail...)> |
347 | { |
348 | template <typename T> |
349 | struct is_valid_target : integral_constant<bool, |
350 | ( |
351 | supportable_properties<I, |
352 | void(Head)>::template is_valid_target<T>::value |
353 | && |
354 | supportable_properties<I + 1, |
355 | void(Tail...)>::template is_valid_target<T>::value |
356 | ) |
357 | > |
358 | { |
359 | }; |
360 | |
361 | template <typename T> |
362 | struct find_convertible_property : |
363 | conditional_t< |
364 | is_convertible<T, Head>::value, |
365 | typename supportable_properties<I, void(Head)>::found, |
366 | typename supportable_properties<I + 1, |
367 | void(Tail...)>::template find_convertible_property<T> |
368 | > {}; |
369 | |
370 | template <typename T> |
371 | struct find_convertible_requirable_property : |
372 | conditional_t< |
373 | is_requirable<Head>::value |
374 | && is_convertible<T, Head>::value, |
375 | typename supportable_properties<I, void(Head)>::found, |
376 | typename supportable_properties<I + 1, |
377 | void(Tail...)>::template find_convertible_requirable_property<T> |
378 | > {}; |
379 | |
380 | template <typename T> |
381 | struct find_convertible_preferable_property : |
382 | conditional_t< |
383 | is_preferable<Head>::value |
384 | && is_convertible<T, Head>::value, |
385 | typename supportable_properties<I, void(Head)>::found, |
386 | typename supportable_properties<I + 1, |
387 | void(Tail...)>::template find_convertible_preferable_property<T> |
388 | > {}; |
389 | |
390 | struct find_context_as_property : |
391 | conditional_t< |
392 | is_context_as<Head>::value, |
393 | typename supportable_properties<I, void(Head)>::found, |
394 | typename supportable_properties<I + 1, |
395 | void(Tail...)>::find_context_as_property |
396 | > {}; |
397 | }; |
398 | |
399 | template <typename T, typename Props> |
400 | struct is_valid_target_executor : |
401 | conditional_t< |
402 | is_executor<T>::value, |
403 | typename supportable_properties<0, Props>::template is_valid_target<T>, |
404 | false_type |
405 | > |
406 | { |
407 | }; |
408 | |
409 | template <typename Props> |
410 | struct is_valid_target_executor<int, Props> : false_type |
411 | { |
412 | }; |
413 | |
414 | class shared_target_executor |
415 | { |
416 | public: |
417 | template <typename E> |
418 | shared_target_executor(E&& e, decay_t<E>*& target) |
419 | { |
420 | impl<decay_t<E>>* i = |
421 | new impl<decay_t<E>>(static_cast<E&&>(e)); |
422 | target = &i->ex_; |
423 | impl_ = i; |
424 | } |
425 | |
426 | template <typename E> |
427 | shared_target_executor(std::nothrow_t, E&& e, decay_t<E>*& target) noexcept |
428 | { |
429 | impl<decay_t<E>>* i = |
430 | new (std::nothrow) impl<decay_t<E>>(static_cast<E&&>(e)); |
431 | target = i ? &i->ex_ : 0; |
432 | impl_ = i; |
433 | } |
434 | |
435 | shared_target_executor(const shared_target_executor& other) noexcept |
436 | : impl_(other.impl_) |
437 | { |
438 | if (impl_) |
439 | boost::asio::detail::ref_count_up(a&: impl_->ref_count_); |
440 | } |
441 | |
442 | shared_target_executor(shared_target_executor&& other) noexcept |
443 | : impl_(other.impl_) |
444 | { |
445 | other.impl_ = 0; |
446 | } |
447 | |
448 | ~shared_target_executor() |
449 | { |
450 | if (impl_) |
451 | if (boost::asio::detail::ref_count_down(a&: impl_->ref_count_)) |
452 | delete impl_; |
453 | } |
454 | |
455 | void* get() const noexcept |
456 | { |
457 | return impl_ ? impl_->get() : 0; |
458 | } |
459 | |
460 | private: |
461 | shared_target_executor& operator=( |
462 | const shared_target_executor& other) = delete; |
463 | |
464 | shared_target_executor& operator=( |
465 | shared_target_executor&& other) = delete; |
466 | |
467 | struct impl_base |
468 | { |
469 | impl_base() : ref_count_(1) {} |
470 | virtual ~impl_base() {} |
471 | virtual void* get() = 0; |
472 | boost::asio::detail::atomic_count ref_count_; |
473 | }; |
474 | |
475 | template <typename Executor> |
476 | struct impl : impl_base |
477 | { |
478 | impl(Executor ex) : ex_(static_cast<Executor&&>(ex)) {} |
479 | virtual void* get() { return &ex_; } |
480 | Executor ex_; |
481 | }; |
482 | |
483 | impl_base* impl_; |
484 | }; |
485 | |
486 | class any_executor_base |
487 | { |
488 | public: |
489 | any_executor_base() noexcept |
490 | : object_fns_(0), |
491 | target_(0), |
492 | target_fns_(0) |
493 | { |
494 | } |
495 | |
496 | template <BOOST_ASIO_EXECUTION_EXECUTOR Executor> |
497 | any_executor_base(Executor ex, false_type) |
498 | : target_fns_(target_fns_table<Executor>( |
499 | any_executor_base::query_blocking(ex, |
500 | can_query<const Executor&, const execution::blocking_t&>()) |
501 | == execution::blocking.always)) |
502 | { |
503 | any_executor_base::construct_object(ex, |
504 | integral_constant<bool, |
505 | sizeof(Executor) <= sizeof(object_type) |
506 | && alignment_of<Executor>::value <= alignment_of<object_type>::value |
507 | >()); |
508 | } |
509 | |
510 | template <BOOST_ASIO_EXECUTION_EXECUTOR Executor> |
511 | any_executor_base(std::nothrow_t, Executor ex, false_type) noexcept |
512 | : target_fns_(target_fns_table<Executor>( |
513 | any_executor_base::query_blocking(ex, |
514 | can_query<const Executor&, const execution::blocking_t&>()) |
515 | == execution::blocking.always)) |
516 | { |
517 | any_executor_base::construct_object(std::nothrow, ex, |
518 | integral_constant<bool, |
519 | sizeof(Executor) <= sizeof(object_type) |
520 | && alignment_of<Executor>::value <= alignment_of<object_type>::value |
521 | >()); |
522 | if (target_ == 0) |
523 | { |
524 | object_fns_ = 0; |
525 | target_fns_ = 0; |
526 | } |
527 | } |
528 | |
529 | template <BOOST_ASIO_EXECUTION_EXECUTOR Executor> |
530 | any_executor_base(Executor other, true_type) |
531 | : object_fns_(object_fns_table<shared_target_executor>()), |
532 | target_fns_(other.target_fns_) |
533 | { |
534 | Executor* p = 0; |
535 | new (&object_) shared_target_executor( |
536 | static_cast<Executor&&>(other), p); |
537 | target_ = p->template target<void>(); |
538 | } |
539 | |
540 | template <BOOST_ASIO_EXECUTION_EXECUTOR Executor> |
541 | any_executor_base(std::nothrow_t, |
542 | Executor other, true_type) noexcept |
543 | : object_fns_(object_fns_table<shared_target_executor>()), |
544 | target_fns_(other.target_fns_) |
545 | { |
546 | Executor* p = 0; |
547 | new (&object_) shared_target_executor( |
548 | std::nothrow, static_cast<Executor&&>(other), p); |
549 | if (p) |
550 | target_ = p->template target<void>(); |
551 | else |
552 | { |
553 | target_ = 0; |
554 | object_fns_ = 0; |
555 | target_fns_ = 0; |
556 | } |
557 | } |
558 | |
559 | any_executor_base(const any_executor_base& other) noexcept |
560 | { |
561 | if (!!other) |
562 | { |
563 | object_fns_ = other.object_fns_; |
564 | target_fns_ = other.target_fns_; |
565 | object_fns_->copy(*this, other); |
566 | } |
567 | else |
568 | { |
569 | object_fns_ = 0; |
570 | target_ = 0; |
571 | target_fns_ = 0; |
572 | } |
573 | } |
574 | |
575 | ~any_executor_base() noexcept |
576 | { |
577 | if (!!*this) |
578 | object_fns_->destroy(*this); |
579 | } |
580 | |
581 | any_executor_base& operator=( |
582 | const any_executor_base& other) noexcept |
583 | { |
584 | if (this != &other) |
585 | { |
586 | if (!!*this) |
587 | object_fns_->destroy(*this); |
588 | if (!!other) |
589 | { |
590 | object_fns_ = other.object_fns_; |
591 | target_fns_ = other.target_fns_; |
592 | object_fns_->copy(*this, other); |
593 | } |
594 | else |
595 | { |
596 | object_fns_ = 0; |
597 | target_ = 0; |
598 | target_fns_ = 0; |
599 | } |
600 | } |
601 | return *this; |
602 | } |
603 | |
604 | any_executor_base& operator=(nullptr_t) noexcept |
605 | { |
606 | if (target_) |
607 | object_fns_->destroy(*this); |
608 | target_ = 0; |
609 | object_fns_ = 0; |
610 | target_fns_ = 0; |
611 | return *this; |
612 | } |
613 | |
614 | any_executor_base(any_executor_base&& other) noexcept |
615 | { |
616 | if (other.target_) |
617 | { |
618 | object_fns_ = other.object_fns_; |
619 | target_fns_ = other.target_fns_; |
620 | other.object_fns_ = 0; |
621 | other.target_fns_ = 0; |
622 | object_fns_->move(*this, other); |
623 | other.target_ = 0; |
624 | } |
625 | else |
626 | { |
627 | object_fns_ = 0; |
628 | target_ = 0; |
629 | target_fns_ = 0; |
630 | } |
631 | } |
632 | |
633 | any_executor_base& operator=( |
634 | any_executor_base&& other) noexcept |
635 | { |
636 | if (this != &other) |
637 | { |
638 | if (!!*this) |
639 | object_fns_->destroy(*this); |
640 | if (!!other) |
641 | { |
642 | object_fns_ = other.object_fns_; |
643 | target_fns_ = other.target_fns_; |
644 | other.object_fns_ = 0; |
645 | other.target_fns_ = 0; |
646 | object_fns_->move(*this, other); |
647 | other.target_ = 0; |
648 | } |
649 | else |
650 | { |
651 | object_fns_ = 0; |
652 | target_ = 0; |
653 | target_fns_ = 0; |
654 | } |
655 | } |
656 | return *this; |
657 | } |
658 | |
659 | void swap(any_executor_base& other) noexcept |
660 | { |
661 | if (this != &other) |
662 | { |
663 | any_executor_base tmp(static_cast<any_executor_base&&>(other)); |
664 | other = static_cast<any_executor_base&&>(*this); |
665 | *this = static_cast<any_executor_base&&>(tmp); |
666 | } |
667 | } |
668 | |
669 | template <typename F> |
670 | void execute(F&& f) const |
671 | { |
672 | if (target_) |
673 | { |
674 | if (target_fns_->blocking_execute != 0) |
675 | { |
676 | boost::asio::detail::non_const_lvalue<F> f2(f); |
677 | target_fns_->blocking_execute(*this, function_view(f2.value)); |
678 | } |
679 | else |
680 | { |
681 | target_fns_->execute(*this, |
682 | function(static_cast<F&&>(f), std::allocator<void>())); |
683 | } |
684 | } |
685 | else |
686 | { |
687 | bad_executor ex; |
688 | boost::asio::detail::throw_exception(e: ex); |
689 | } |
690 | } |
691 | |
692 | template <typename Executor> |
693 | Executor* target() |
694 | { |
695 | return target_ && (is_same<Executor, void>::value |
696 | || target_fns_->target_type() == target_type_ex<Executor>()) |
697 | ? static_cast<Executor*>(target_) : 0; |
698 | } |
699 | |
700 | template <typename Executor> |
701 | const Executor* target() const |
702 | { |
703 | return target_ && (is_same<Executor, void>::value |
704 | || target_fns_->target_type() == target_type_ex<Executor>()) |
705 | ? static_cast<const Executor*>(target_) : 0; |
706 | } |
707 | |
708 | #if !defined(BOOST_ASIO_NO_TYPEID) |
709 | const std::type_info& target_type() const |
710 | { |
711 | return target_ ? target_fns_->target_type() : typeid(void); |
712 | } |
713 | #else // !defined(BOOST_ASIO_NO_TYPEID) |
714 | const void* target_type() const |
715 | { |
716 | return target_ ? target_fns_->target_type() : 0; |
717 | } |
718 | #endif // !defined(BOOST_ASIO_NO_TYPEID) |
719 | |
720 | struct unspecified_bool_type_t {}; |
721 | typedef void (*unspecified_bool_type)(unspecified_bool_type_t); |
722 | static void unspecified_bool_true(unspecified_bool_type_t) {} |
723 | |
724 | operator unspecified_bool_type() const noexcept |
725 | { |
726 | return target_ ? &any_executor_base::unspecified_bool_true : 0; |
727 | } |
728 | |
729 | bool operator!() const noexcept |
730 | { |
731 | return target_ == 0; |
732 | } |
733 | |
734 | protected: |
735 | bool equality_helper(const any_executor_base& other) const noexcept |
736 | { |
737 | if (target_ == other.target_) |
738 | return true; |
739 | if (target_ && !other.target_) |
740 | return false; |
741 | if (!target_ && other.target_) |
742 | return false; |
743 | if (target_fns_ != other.target_fns_) |
744 | return false; |
745 | return target_fns_->equal(*this, other); |
746 | } |
747 | |
748 | template <typename Ex> |
749 | Ex& object() |
750 | { |
751 | return *static_cast<Ex*>(static_cast<void*>(&object_)); |
752 | } |
753 | |
754 | template <typename Ex> |
755 | const Ex& object() const |
756 | { |
757 | return *static_cast<const Ex*>(static_cast<const void*>(&object_)); |
758 | } |
759 | |
760 | struct object_fns |
761 | { |
762 | void (*destroy)(any_executor_base&); |
763 | void (*copy)(any_executor_base&, const any_executor_base&); |
764 | void (*move)(any_executor_base&, any_executor_base&); |
765 | const void* (*target)(const any_executor_base&); |
766 | }; |
767 | |
768 | static void destroy_shared(any_executor_base& ex) |
769 | { |
770 | typedef shared_target_executor type; |
771 | ex.object<type>().~type(); |
772 | } |
773 | |
774 | static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2) |
775 | { |
776 | typedef shared_target_executor type; |
777 | new (&ex1.object_) type(ex2.object<type>()); |
778 | ex1.target_ = ex2.target_; |
779 | } |
780 | |
781 | static void move_shared(any_executor_base& ex1, any_executor_base& ex2) |
782 | { |
783 | typedef shared_target_executor type; |
784 | new (&ex1.object_) type(static_cast<type&&>(ex2.object<type>())); |
785 | ex1.target_ = ex2.target_; |
786 | ex2.object<type>().~type(); |
787 | } |
788 | |
789 | static const void* target_shared(const any_executor_base& ex) |
790 | { |
791 | typedef shared_target_executor type; |
792 | return ex.object<type>().get(); |
793 | } |
794 | |
795 | template <typename Obj> |
796 | static const object_fns* object_fns_table( |
797 | enable_if_t< |
798 | is_same<Obj, shared_target_executor>::value |
799 | >* = 0) |
800 | { |
801 | static const object_fns fns = |
802 | { |
803 | .destroy: &any_executor_base::destroy_shared, |
804 | .copy: &any_executor_base::copy_shared, |
805 | .move: &any_executor_base::move_shared, |
806 | .target: &any_executor_base::target_shared |
807 | }; |
808 | return &fns; |
809 | } |
810 | |
811 | template <typename Obj> |
812 | static void destroy_object(any_executor_base& ex) |
813 | { |
814 | ex.object<Obj>().~Obj(); |
815 | } |
816 | |
817 | template <typename Obj> |
818 | static void copy_object(any_executor_base& ex1, const any_executor_base& ex2) |
819 | { |
820 | new (&ex1.object_) Obj(ex2.object<Obj>()); |
821 | ex1.target_ = &ex1.object<Obj>(); |
822 | } |
823 | |
824 | template <typename Obj> |
825 | static void move_object(any_executor_base& ex1, any_executor_base& ex2) |
826 | { |
827 | new (&ex1.object_) Obj(static_cast<Obj&&>(ex2.object<Obj>())); |
828 | ex1.target_ = &ex1.object<Obj>(); |
829 | ex2.object<Obj>().~Obj(); |
830 | } |
831 | |
832 | template <typename Obj> |
833 | static const void* target_object(const any_executor_base& ex) |
834 | { |
835 | return &ex.object<Obj>(); |
836 | } |
837 | |
838 | template <typename Obj> |
839 | static const object_fns* object_fns_table( |
840 | enable_if_t< |
841 | !is_same<Obj, void>::value |
842 | && !is_same<Obj, shared_target_executor>::value |
843 | >* = 0) |
844 | { |
845 | static const object_fns fns = |
846 | { |
847 | &any_executor_base::destroy_object<Obj>, |
848 | &any_executor_base::copy_object<Obj>, |
849 | &any_executor_base::move_object<Obj>, |
850 | &any_executor_base::target_object<Obj> |
851 | }; |
852 | return &fns; |
853 | } |
854 | |
855 | typedef boost::asio::detail::executor_function function; |
856 | typedef boost::asio::detail::executor_function_view function_view; |
857 | |
858 | struct target_fns |
859 | { |
860 | #if !defined(BOOST_ASIO_NO_TYPEID) |
861 | const std::type_info& (*target_type)(); |
862 | #else // !defined(BOOST_ASIO_NO_TYPEID) |
863 | const void* (*target_type)(); |
864 | #endif // !defined(BOOST_ASIO_NO_TYPEID) |
865 | bool (*equal)(const any_executor_base&, const any_executor_base&); |
866 | void (*execute)(const any_executor_base&, function&&); |
867 | void (*blocking_execute)(const any_executor_base&, function_view); |
868 | }; |
869 | |
870 | #if !defined(BOOST_ASIO_NO_TYPEID) |
871 | template <typename Ex> |
872 | static const std::type_info& target_type_ex() |
873 | { |
874 | return typeid(Ex); |
875 | } |
876 | #else // !defined(BOOST_ASIO_NO_TYPEID) |
877 | template <typename Ex> |
878 | static const void* target_type_ex() |
879 | { |
880 | static int unique_id; |
881 | return &unique_id; |
882 | } |
883 | #endif // !defined(BOOST_ASIO_NO_TYPEID) |
884 | |
885 | template <typename Ex> |
886 | static bool equal_ex(const any_executor_base& ex1, |
887 | const any_executor_base& ex2) |
888 | { |
889 | const Ex* p1 = ex1.target<Ex>(); |
890 | const Ex* p2 = ex2.target<Ex>(); |
891 | BOOST_ASIO_ASSUME(p1 != 0 && p2 != 0); |
892 | return *p1 == *p2; |
893 | } |
894 | |
895 | template <typename Ex> |
896 | static void execute_ex(const any_executor_base& ex, function&& f) |
897 | { |
898 | const Ex* p = ex.target<Ex>(); |
899 | BOOST_ASIO_ASSUME(p != 0); |
900 | p->execute(static_cast<function&&>(f)); |
901 | } |
902 | |
903 | template <typename Ex> |
904 | static void blocking_execute_ex(const any_executor_base& ex, function_view f) |
905 | { |
906 | const Ex* p = ex.target<Ex>(); |
907 | BOOST_ASIO_ASSUME(p != 0); |
908 | p->execute(f); |
909 | } |
910 | |
911 | template <typename Ex> |
912 | static const target_fns* target_fns_table(bool is_always_blocking, |
913 | enable_if_t< |
914 | !is_same<Ex, void>::value |
915 | >* = 0) |
916 | { |
917 | static const target_fns fns_with_execute = |
918 | { |
919 | &any_executor_base::target_type_ex<Ex>, |
920 | &any_executor_base::equal_ex<Ex>, |
921 | &any_executor_base::execute_ex<Ex>, |
922 | 0 |
923 | }; |
924 | |
925 | static const target_fns fns_with_blocking_execute = |
926 | { |
927 | &any_executor_base::target_type_ex<Ex>, |
928 | &any_executor_base::equal_ex<Ex>, |
929 | 0, |
930 | &any_executor_base::blocking_execute_ex<Ex> |
931 | }; |
932 | |
933 | return is_always_blocking ? &fns_with_blocking_execute : &fns_with_execute; |
934 | } |
935 | |
936 | #if defined(BOOST_ASIO_MSVC) |
937 | # pragma warning (push) |
938 | # pragma warning (disable:4702) |
939 | #endif // defined(BOOST_ASIO_MSVC) |
940 | |
941 | static void query_fn_void(void*, const void*, const void*) |
942 | { |
943 | bad_executor ex; |
944 | boost::asio::detail::throw_exception(e: ex); |
945 | } |
946 | |
947 | template <typename Ex, class Prop> |
948 | static void query_fn_non_void(void*, const void* ex, const void* prop, |
949 | enable_if_t< |
950 | boost::asio::can_query<const Ex&, const Prop&>::value |
951 | && is_same<typename Prop::polymorphic_query_result_type, void>::value |
952 | >*) |
953 | { |
954 | boost::asio::query(*static_cast<const Ex*>(ex), |
955 | *static_cast<const Prop*>(prop)); |
956 | } |
957 | |
958 | template <typename Ex, class Prop> |
959 | static void query_fn_non_void(void*, const void*, const void*, |
960 | enable_if_t< |
961 | !boost::asio::can_query<const Ex&, const Prop&>::value |
962 | && is_same<typename Prop::polymorphic_query_result_type, void>::value |
963 | >*) |
964 | { |
965 | } |
966 | |
967 | template <typename Ex, class Prop> |
968 | static void query_fn_non_void(void* result, const void* ex, const void* prop, |
969 | enable_if_t< |
970 | boost::asio::can_query<const Ex&, const Prop&>::value |
971 | && !is_same<typename Prop::polymorphic_query_result_type, void>::value |
972 | && is_reference<typename Prop::polymorphic_query_result_type>::value |
973 | >*) |
974 | { |
975 | *static_cast<remove_reference_t< |
976 | typename Prop::polymorphic_query_result_type>**>(result) |
977 | = &static_cast<typename Prop::polymorphic_query_result_type>( |
978 | boost::asio::query(*static_cast<const Ex*>(ex), |
979 | *static_cast<const Prop*>(prop))); |
980 | } |
981 | |
982 | template <typename Ex, class Prop> |
983 | static void query_fn_non_void(void*, const void*, const void*, |
984 | enable_if_t< |
985 | !boost::asio::can_query<const Ex&, const Prop&>::value |
986 | && !is_same<typename Prop::polymorphic_query_result_type, void>::value |
987 | && is_reference<typename Prop::polymorphic_query_result_type>::value |
988 | >*) |
989 | { |
990 | std::terminate(); // Combination should not be possible. |
991 | } |
992 | |
993 | template <typename Ex, class Prop> |
994 | static void query_fn_non_void(void* result, const void* ex, const void* prop, |
995 | enable_if_t< |
996 | boost::asio::can_query<const Ex&, const Prop&>::value |
997 | && !is_same<typename Prop::polymorphic_query_result_type, void>::value |
998 | && is_scalar<typename Prop::polymorphic_query_result_type>::value |
999 | >*) |
1000 | { |
1001 | *static_cast<typename Prop::polymorphic_query_result_type*>(result) |
1002 | = static_cast<typename Prop::polymorphic_query_result_type>( |
1003 | boost::asio::query(*static_cast<const Ex*>(ex), |
1004 | *static_cast<const Prop*>(prop))); |
1005 | } |
1006 | |
1007 | template <typename Ex, class Prop> |
1008 | static void query_fn_non_void(void* result, const void*, const void*, |
1009 | enable_if_t< |
1010 | !boost::asio::can_query<const Ex&, const Prop&>::value |
1011 | && !is_same<typename Prop::polymorphic_query_result_type, void>::value |
1012 | && is_scalar<typename Prop::polymorphic_query_result_type>::value |
1013 | >*) |
1014 | { |
1015 | *static_cast<typename Prop::polymorphic_query_result_type*>(result) |
1016 | = typename Prop::polymorphic_query_result_type(); |
1017 | } |
1018 | |
1019 | template <typename Ex, class Prop> |
1020 | static void query_fn_non_void(void* result, const void* ex, const void* prop, |
1021 | enable_if_t< |
1022 | boost::asio::can_query<const Ex&, const Prop&>::value |
1023 | && !is_same<typename Prop::polymorphic_query_result_type, void>::value |
1024 | && !is_reference<typename Prop::polymorphic_query_result_type>::value |
1025 | && !is_scalar<typename Prop::polymorphic_query_result_type>::value |
1026 | >*) |
1027 | { |
1028 | *static_cast<typename Prop::polymorphic_query_result_type**>(result) |
1029 | = new typename Prop::polymorphic_query_result_type( |
1030 | boost::asio::query(*static_cast<const Ex*>(ex), |
1031 | *static_cast<const Prop*>(prop))); |
1032 | } |
1033 | |
1034 | template <typename Ex, class Prop> |
1035 | static void query_fn_non_void(void* result, const void*, const void*, ...) |
1036 | { |
1037 | *static_cast<typename Prop::polymorphic_query_result_type**>(result) |
1038 | = new typename Prop::polymorphic_query_result_type(); |
1039 | } |
1040 | |
1041 | template <typename Ex, class Prop> |
1042 | static void query_fn_impl(void* result, const void* ex, const void* prop, |
1043 | enable_if_t< |
1044 | is_same<Ex, void>::value |
1045 | >*) |
1046 | { |
1047 | query_fn_void(result, ex, prop); |
1048 | } |
1049 | |
1050 | template <typename Ex, class Prop> |
1051 | static void query_fn_impl(void* result, const void* ex, const void* prop, |
1052 | enable_if_t< |
1053 | !is_same<Ex, void>::value |
1054 | >*) |
1055 | { |
1056 | query_fn_non_void<Ex, Prop>(result, ex, prop, 0); |
1057 | } |
1058 | |
1059 | template <typename Ex, class Prop> |
1060 | static void query_fn(void* result, const void* ex, const void* prop) |
1061 | { |
1062 | query_fn_impl<Ex, Prop>(result, ex, prop, 0); |
1063 | } |
1064 | |
1065 | template <typename Poly, typename Ex, class Prop> |
1066 | static Poly require_fn_impl(const void*, const void*, |
1067 | enable_if_t< |
1068 | is_same<Ex, void>::value |
1069 | >*) |
1070 | { |
1071 | bad_executor ex; |
1072 | boost::asio::detail::throw_exception(e: ex); |
1073 | return Poly(); |
1074 | } |
1075 | |
1076 | template <typename Poly, typename Ex, class Prop> |
1077 | static Poly require_fn_impl(const void* ex, const void* prop, |
1078 | enable_if_t< |
1079 | !is_same<Ex, void>::value && Prop::is_requirable |
1080 | >*) |
1081 | { |
1082 | return boost::asio::require(*static_cast<const Ex*>(ex), |
1083 | *static_cast<const Prop*>(prop)); |
1084 | } |
1085 | |
1086 | template <typename Poly, typename Ex, class Prop> |
1087 | static Poly require_fn_impl(const void*, const void*, ...) |
1088 | { |
1089 | return Poly(); |
1090 | } |
1091 | |
1092 | template <typename Poly, typename Ex, class Prop> |
1093 | static Poly require_fn(const void* ex, const void* prop) |
1094 | { |
1095 | return require_fn_impl<Poly, Ex, Prop>(ex, prop, 0); |
1096 | } |
1097 | |
1098 | template <typename Poly, typename Ex, class Prop> |
1099 | static Poly prefer_fn_impl(const void*, const void*, |
1100 | enable_if_t< |
1101 | is_same<Ex, void>::value |
1102 | >*) |
1103 | { |
1104 | bad_executor ex; |
1105 | boost::asio::detail::throw_exception(e: ex); |
1106 | return Poly(); |
1107 | } |
1108 | |
1109 | template <typename Poly, typename Ex, class Prop> |
1110 | static Poly prefer_fn_impl(const void* ex, const void* prop, |
1111 | enable_if_t< |
1112 | !is_same<Ex, void>::value && Prop::is_preferable |
1113 | >*) |
1114 | { |
1115 | return boost::asio::prefer(*static_cast<const Ex*>(ex), |
1116 | *static_cast<const Prop*>(prop)); |
1117 | } |
1118 | |
1119 | template <typename Poly, typename Ex, class Prop> |
1120 | static Poly prefer_fn_impl(const void*, const void*, ...) |
1121 | { |
1122 | return Poly(); |
1123 | } |
1124 | |
1125 | template <typename Poly, typename Ex, class Prop> |
1126 | static Poly prefer_fn(const void* ex, const void* prop) |
1127 | { |
1128 | return prefer_fn_impl<Poly, Ex, Prop>(ex, prop, 0); |
1129 | } |
1130 | |
1131 | template <typename Poly> |
1132 | struct prop_fns |
1133 | { |
1134 | void (*query)(void*, const void*, const void*); |
1135 | Poly (*require)(const void*, const void*); |
1136 | Poly (*prefer)(const void*, const void*); |
1137 | }; |
1138 | |
1139 | #if defined(BOOST_ASIO_MSVC) |
1140 | # pragma warning (pop) |
1141 | #endif // defined(BOOST_ASIO_MSVC) |
1142 | |
1143 | private: |
1144 | template <typename Executor> |
1145 | static execution::blocking_t query_blocking(const Executor& ex, true_type) |
1146 | { |
1147 | return boost::asio::query(ex, execution::blocking); |
1148 | } |
1149 | |
1150 | template <typename Executor> |
1151 | static execution::blocking_t query_blocking(const Executor&, false_type) |
1152 | { |
1153 | return execution::blocking_t(); |
1154 | } |
1155 | |
1156 | template <typename Executor> |
1157 | void construct_object(Executor& ex, true_type) |
1158 | { |
1159 | object_fns_ = object_fns_table<Executor>(); |
1160 | target_ = new (&object_) Executor(static_cast<Executor&&>(ex)); |
1161 | } |
1162 | |
1163 | template <typename Executor> |
1164 | void construct_object(Executor& ex, false_type) |
1165 | { |
1166 | object_fns_ = object_fns_table<shared_target_executor>(); |
1167 | Executor* p = 0; |
1168 | new (&object_) shared_target_executor( |
1169 | static_cast<Executor&&>(ex), p); |
1170 | target_ = p; |
1171 | } |
1172 | |
1173 | template <typename Executor> |
1174 | void construct_object(std::nothrow_t, |
1175 | Executor& ex, true_type) noexcept |
1176 | { |
1177 | object_fns_ = object_fns_table<Executor>(); |
1178 | target_ = new (&object_) Executor(static_cast<Executor&&>(ex)); |
1179 | } |
1180 | |
1181 | template <typename Executor> |
1182 | void construct_object(std::nothrow_t, |
1183 | Executor& ex, false_type) noexcept |
1184 | { |
1185 | object_fns_ = object_fns_table<shared_target_executor>(); |
1186 | Executor* p = 0; |
1187 | new (&object_) shared_target_executor( |
1188 | std::nothrow, static_cast<Executor&&>(ex), p); |
1189 | target_ = p; |
1190 | } |
1191 | |
1192 | /*private:*/public: |
1193 | // template <typename...> friend class any_executor; |
1194 | |
1195 | typedef aligned_storage< |
1196 | sizeof(boost::asio::detail::shared_ptr<void>) + sizeof(void*), |
1197 | alignment_of<boost::asio::detail::shared_ptr<void>>::value |
1198 | >::type object_type; |
1199 | |
1200 | object_type object_; |
1201 | const object_fns* object_fns_; |
1202 | void* target_; |
1203 | const target_fns* target_fns_; |
1204 | }; |
1205 | |
1206 | template <typename Derived, typename Property, typename = void> |
1207 | struct any_executor_context |
1208 | { |
1209 | }; |
1210 | |
1211 | #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
1212 | |
1213 | template <typename Derived, typename Property> |
1214 | struct any_executor_context<Derived, Property, enable_if_t<Property::value>> |
1215 | { |
1216 | typename Property::query_result_type context() const |
1217 | { |
1218 | return static_cast<const Derived*>(this)->query(typename Property::type()); |
1219 | } |
1220 | }; |
1221 | |
1222 | #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
1223 | |
1224 | } // namespace detail |
1225 | |
1226 | template <> |
1227 | class any_executor<> : public detail::any_executor_base |
1228 | { |
1229 | public: |
1230 | any_executor() noexcept |
1231 | : detail::any_executor_base() |
1232 | { |
1233 | } |
1234 | |
1235 | any_executor(nullptr_t) noexcept |
1236 | : detail::any_executor_base() |
1237 | { |
1238 | } |
1239 | |
1240 | template <typename Executor> |
1241 | any_executor(Executor ex, |
1242 | enable_if_t< |
1243 | conditional_t< |
1244 | !is_same<Executor, any_executor>::value |
1245 | && !is_base_of<detail::any_executor_base, Executor>::value, |
1246 | is_executor<Executor>, |
1247 | false_type |
1248 | >::value |
1249 | >* = 0) |
1250 | : detail::any_executor_base( |
1251 | static_cast<Executor&&>(ex), false_type()) |
1252 | { |
1253 | } |
1254 | |
1255 | template <typename Executor> |
1256 | any_executor(std::nothrow_t, Executor ex, |
1257 | enable_if_t< |
1258 | conditional_t< |
1259 | !is_same<Executor, any_executor>::value |
1260 | && !is_base_of<detail::any_executor_base, Executor>::value, |
1261 | is_executor<Executor>, |
1262 | false_type |
1263 | >::value |
1264 | >* = 0) noexcept |
1265 | : detail::any_executor_base(std::nothrow, |
1266 | static_cast<Executor&&>(ex), false_type()) |
1267 | { |
1268 | } |
1269 | |
1270 | template <typename... OtherSupportableProperties> |
1271 | any_executor(any_executor<OtherSupportableProperties...> other) |
1272 | : detail::any_executor_base( |
1273 | static_cast<const detail::any_executor_base&>(other)) |
1274 | { |
1275 | } |
1276 | |
1277 | template <typename... OtherSupportableProperties> |
1278 | any_executor(std::nothrow_t, |
1279 | any_executor<OtherSupportableProperties...> other) noexcept |
1280 | : detail::any_executor_base( |
1281 | static_cast<const detail::any_executor_base&>(other)) |
1282 | { |
1283 | } |
1284 | |
1285 | any_executor(const any_executor& other) noexcept |
1286 | : detail::any_executor_base( |
1287 | static_cast<const detail::any_executor_base&>(other)) |
1288 | { |
1289 | } |
1290 | |
1291 | any_executor(std::nothrow_t, const any_executor& other) noexcept |
1292 | : detail::any_executor_base( |
1293 | static_cast<const detail::any_executor_base&>(other)) |
1294 | { |
1295 | } |
1296 | |
1297 | any_executor& operator=(const any_executor& other) noexcept |
1298 | { |
1299 | if (this != &other) |
1300 | { |
1301 | detail::any_executor_base::operator=( |
1302 | other: static_cast<const detail::any_executor_base&>(other)); |
1303 | } |
1304 | return *this; |
1305 | } |
1306 | |
1307 | any_executor& operator=(nullptr_t p) noexcept |
1308 | { |
1309 | detail::any_executor_base::operator=(p); |
1310 | return *this; |
1311 | } |
1312 | |
1313 | any_executor(any_executor&& other) noexcept |
1314 | : detail::any_executor_base( |
1315 | static_cast<any_executor_base&&>( |
1316 | static_cast<any_executor_base&>(other))) |
1317 | { |
1318 | } |
1319 | |
1320 | any_executor(std::nothrow_t, any_executor&& other) noexcept |
1321 | : detail::any_executor_base( |
1322 | static_cast<any_executor_base&&>( |
1323 | static_cast<any_executor_base&>(other))) |
1324 | { |
1325 | } |
1326 | |
1327 | any_executor& operator=(any_executor&& other) noexcept |
1328 | { |
1329 | if (this != &other) |
1330 | { |
1331 | detail::any_executor_base::operator=( |
1332 | other: static_cast<detail::any_executor_base&&>( |
1333 | static_cast<detail::any_executor_base&>(other))); |
1334 | } |
1335 | return *this; |
1336 | } |
1337 | |
1338 | void swap(any_executor& other) noexcept |
1339 | { |
1340 | detail::any_executor_base::swap( |
1341 | other&: static_cast<detail::any_executor_base&>(other)); |
1342 | } |
1343 | |
1344 | using detail::any_executor_base::execute; |
1345 | using detail::any_executor_base::target; |
1346 | using detail::any_executor_base::target_type; |
1347 | using detail::any_executor_base::operator unspecified_bool_type; |
1348 | using detail::any_executor_base::operator!; |
1349 | |
1350 | bool equality_helper(const any_executor& other) const noexcept |
1351 | { |
1352 | return any_executor_base::equality_helper(other); |
1353 | } |
1354 | |
1355 | template <typename AnyExecutor1, typename AnyExecutor2> |
1356 | friend enable_if_t< |
1357 | is_base_of<any_executor, AnyExecutor1>::value |
1358 | || is_base_of<any_executor, AnyExecutor2>::value, |
1359 | bool |
1360 | > operator==(const AnyExecutor1& a, |
1361 | const AnyExecutor2& b) noexcept |
1362 | { |
1363 | return static_cast<const any_executor&>(a).equality_helper(other: b); |
1364 | } |
1365 | |
1366 | template <typename AnyExecutor> |
1367 | friend enable_if_t< |
1368 | is_same<AnyExecutor, any_executor>::value, |
1369 | bool |
1370 | > operator==(const AnyExecutor& a, nullptr_t) noexcept |
1371 | { |
1372 | return !a; |
1373 | } |
1374 | |
1375 | template <typename AnyExecutor> |
1376 | friend enable_if_t< |
1377 | is_same<AnyExecutor, any_executor>::value, |
1378 | bool |
1379 | > operator==(nullptr_t, const AnyExecutor& b) noexcept |
1380 | { |
1381 | return !b; |
1382 | } |
1383 | |
1384 | template <typename AnyExecutor1, typename AnyExecutor2> |
1385 | friend enable_if_t< |
1386 | is_base_of<any_executor, AnyExecutor1>::value |
1387 | || is_base_of<any_executor, AnyExecutor2>::value, |
1388 | bool |
1389 | > operator!=(const AnyExecutor1& a, |
1390 | const AnyExecutor2& b) noexcept |
1391 | { |
1392 | return !static_cast<const any_executor&>(a).equality_helper(other: b); |
1393 | } |
1394 | |
1395 | template <typename AnyExecutor> |
1396 | friend enable_if_t< |
1397 | is_same<AnyExecutor, any_executor>::value, |
1398 | bool |
1399 | > operator!=(const AnyExecutor& a, nullptr_t) noexcept |
1400 | { |
1401 | return !!a; |
1402 | } |
1403 | |
1404 | template <typename AnyExecutor> |
1405 | friend enable_if_t< |
1406 | is_same<AnyExecutor, any_executor>::value, |
1407 | bool |
1408 | > operator!=(nullptr_t, const AnyExecutor& b) noexcept |
1409 | { |
1410 | return !!b; |
1411 | } |
1412 | }; |
1413 | |
1414 | inline void swap(any_executor<>& a, any_executor<>& b) noexcept |
1415 | { |
1416 | return a.swap(other&: b); |
1417 | } |
1418 | |
1419 | template <typename... SupportableProperties> |
1420 | class any_executor : |
1421 | public detail::any_executor_base, |
1422 | public detail::any_executor_context< |
1423 | any_executor<SupportableProperties...>, |
1424 | typename detail::supportable_properties< |
1425 | 0, void(SupportableProperties...)>::find_context_as_property> |
1426 | { |
1427 | public: |
1428 | any_executor() noexcept |
1429 | : detail::any_executor_base(), |
1430 | prop_fns_(prop_fns_table<void>()) |
1431 | { |
1432 | } |
1433 | |
1434 | any_executor(nullptr_t) noexcept |
1435 | : detail::any_executor_base(), |
1436 | prop_fns_(prop_fns_table<void>()) |
1437 | { |
1438 | } |
1439 | |
1440 | template <typename Executor> |
1441 | any_executor(Executor ex, |
1442 | enable_if_t< |
1443 | conditional_t< |
1444 | !is_same<Executor, any_executor>::value |
1445 | && !is_base_of<detail::any_executor_base, Executor>::value, |
1446 | detail::is_valid_target_executor< |
1447 | Executor, void(SupportableProperties...)>, |
1448 | false_type |
1449 | >::value |
1450 | >* = 0) |
1451 | : detail::any_executor_base( |
1452 | static_cast<Executor&&>(ex), false_type()), |
1453 | prop_fns_(prop_fns_table<Executor>()) |
1454 | { |
1455 | } |
1456 | |
1457 | template <typename Executor> |
1458 | any_executor(std::nothrow_t, Executor ex, |
1459 | enable_if_t< |
1460 | conditional_t< |
1461 | !is_same<Executor, any_executor>::value |
1462 | && !is_base_of<detail::any_executor_base, Executor>::value, |
1463 | detail::is_valid_target_executor< |
1464 | Executor, void(SupportableProperties...)>, |
1465 | false_type |
1466 | >::value |
1467 | >* = 0) noexcept |
1468 | : detail::any_executor_base(std::nothrow, |
1469 | static_cast<Executor&&>(ex), false_type()), |
1470 | prop_fns_(prop_fns_table<Executor>()) |
1471 | { |
1472 | if (this->template target<void>() == 0) |
1473 | prop_fns_ = prop_fns_table<void>(); |
1474 | } |
1475 | |
1476 | template <typename... OtherSupportableProperties> |
1477 | any_executor(any_executor<OtherSupportableProperties...> other, |
1478 | enable_if_t< |
1479 | conditional_t< |
1480 | !is_same< |
1481 | any_executor<OtherSupportableProperties...>, |
1482 | any_executor |
1483 | >::value, |
1484 | typename detail::supportable_properties< |
1485 | 0, void(SupportableProperties...)>::template is_valid_target< |
1486 | any_executor<OtherSupportableProperties...>>, |
1487 | false_type |
1488 | >::value |
1489 | >* = 0) |
1490 | : detail::any_executor_base( |
1491 | static_cast<any_executor<OtherSupportableProperties...>&&>(other), |
1492 | true_type()), |
1493 | prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...>>()) |
1494 | { |
1495 | } |
1496 | |
1497 | template <typename... OtherSupportableProperties> |
1498 | any_executor(std::nothrow_t, |
1499 | any_executor<OtherSupportableProperties...> other, |
1500 | enable_if_t< |
1501 | conditional_t< |
1502 | !is_same< |
1503 | any_executor<OtherSupportableProperties...>, |
1504 | any_executor |
1505 | >::value, |
1506 | typename detail::supportable_properties< |
1507 | 0, void(SupportableProperties...)>::template is_valid_target< |
1508 | any_executor<OtherSupportableProperties...>>, |
1509 | false_type |
1510 | >::value |
1511 | >* = 0) noexcept |
1512 | : detail::any_executor_base(std::nothrow, |
1513 | static_cast<any_executor<OtherSupportableProperties...>&&>(other), |
1514 | true_type()), |
1515 | prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...>>()) |
1516 | { |
1517 | if (this->template target<void>() == 0) |
1518 | prop_fns_ = prop_fns_table<void>(); |
1519 | } |
1520 | |
1521 | any_executor(const any_executor& other) noexcept |
1522 | : detail::any_executor_base( |
1523 | static_cast<const detail::any_executor_base&>(other)), |
1524 | prop_fns_(other.prop_fns_) |
1525 | { |
1526 | } |
1527 | |
1528 | any_executor(std::nothrow_t, const any_executor& other) noexcept |
1529 | : detail::any_executor_base( |
1530 | static_cast<const detail::any_executor_base&>(other)), |
1531 | prop_fns_(other.prop_fns_) |
1532 | { |
1533 | } |
1534 | |
1535 | any_executor& operator=(const any_executor& other) noexcept |
1536 | { |
1537 | if (this != &other) |
1538 | { |
1539 | prop_fns_ = other.prop_fns_; |
1540 | detail::any_executor_base::operator=( |
1541 | static_cast<const detail::any_executor_base&>(other)); |
1542 | } |
1543 | return *this; |
1544 | } |
1545 | |
1546 | any_executor& operator=(nullptr_t p) noexcept |
1547 | { |
1548 | prop_fns_ = prop_fns_table<void>(); |
1549 | detail::any_executor_base::operator=(p); |
1550 | return *this; |
1551 | } |
1552 | |
1553 | any_executor(any_executor&& other) noexcept |
1554 | : detail::any_executor_base( |
1555 | static_cast<any_executor_base&&>( |
1556 | static_cast<any_executor_base&>(other))), |
1557 | prop_fns_(other.prop_fns_) |
1558 | { |
1559 | other.prop_fns_ = prop_fns_table<void>(); |
1560 | } |
1561 | |
1562 | any_executor(std::nothrow_t, any_executor&& other) noexcept |
1563 | : detail::any_executor_base( |
1564 | static_cast<any_executor_base&&>( |
1565 | static_cast<any_executor_base&>(other))), |
1566 | prop_fns_(other.prop_fns_) |
1567 | { |
1568 | other.prop_fns_ = prop_fns_table<void>(); |
1569 | } |
1570 | |
1571 | any_executor& operator=(any_executor&& other) noexcept |
1572 | { |
1573 | if (this != &other) |
1574 | { |
1575 | prop_fns_ = other.prop_fns_; |
1576 | detail::any_executor_base::operator=( |
1577 | static_cast<detail::any_executor_base&&>( |
1578 | static_cast<detail::any_executor_base&>(other))); |
1579 | } |
1580 | return *this; |
1581 | } |
1582 | |
1583 | void swap(any_executor& other) noexcept |
1584 | { |
1585 | if (this != &other) |
1586 | { |
1587 | detail::any_executor_base::swap( |
1588 | other&: static_cast<detail::any_executor_base&>(other)); |
1589 | const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_; |
1590 | other.prop_fns_ = prop_fns_; |
1591 | prop_fns_ = tmp_prop_fns; |
1592 | } |
1593 | } |
1594 | |
1595 | using detail::any_executor_base::execute; |
1596 | using detail::any_executor_base::target; |
1597 | using detail::any_executor_base::target_type; |
1598 | using detail::any_executor_base::operator unspecified_bool_type; |
1599 | using detail::any_executor_base::operator!; |
1600 | |
1601 | bool equality_helper(const any_executor& other) const noexcept |
1602 | { |
1603 | return any_executor_base::equality_helper(other); |
1604 | } |
1605 | |
1606 | template <typename AnyExecutor1, typename AnyExecutor2> |
1607 | friend enable_if_t< |
1608 | is_base_of<any_executor, AnyExecutor1>::value |
1609 | || is_base_of<any_executor, AnyExecutor2>::value, |
1610 | bool |
1611 | > operator==(const AnyExecutor1& a, |
1612 | const AnyExecutor2& b) noexcept |
1613 | { |
1614 | return static_cast<const any_executor&>(a).equality_helper(b); |
1615 | } |
1616 | |
1617 | template <typename AnyExecutor> |
1618 | friend enable_if_t< |
1619 | is_same<AnyExecutor, any_executor>::value, |
1620 | bool |
1621 | > operator==(const AnyExecutor& a, nullptr_t) noexcept |
1622 | { |
1623 | return !a; |
1624 | } |
1625 | |
1626 | template <typename AnyExecutor> |
1627 | friend enable_if_t< |
1628 | is_same<AnyExecutor, any_executor>::value, |
1629 | bool |
1630 | > operator==(nullptr_t, const AnyExecutor& b) noexcept |
1631 | { |
1632 | return !b; |
1633 | } |
1634 | |
1635 | template <typename AnyExecutor1, typename AnyExecutor2> |
1636 | friend enable_if_t< |
1637 | is_base_of<any_executor, AnyExecutor1>::value |
1638 | || is_base_of<any_executor, AnyExecutor2>::value, |
1639 | bool |
1640 | > operator!=(const AnyExecutor1& a, |
1641 | const AnyExecutor2& b) noexcept |
1642 | { |
1643 | return !static_cast<const any_executor&>(a).equality_helper(b); |
1644 | } |
1645 | |
1646 | template <typename AnyExecutor> |
1647 | friend enable_if_t< |
1648 | is_same<AnyExecutor, any_executor>::value, |
1649 | bool |
1650 | > operator!=(const AnyExecutor& a, nullptr_t) noexcept |
1651 | { |
1652 | return !!a; |
1653 | } |
1654 | |
1655 | template <typename AnyExecutor> |
1656 | friend enable_if_t< |
1657 | is_same<AnyExecutor, any_executor>::value, |
1658 | bool |
1659 | > operator!=(nullptr_t, const AnyExecutor& b) noexcept |
1660 | { |
1661 | return !!b; |
1662 | } |
1663 | |
1664 | template <typename T> |
1665 | struct find_convertible_property : |
1666 | detail::supportable_properties< |
1667 | 0, void(SupportableProperties...)>::template |
1668 | find_convertible_property<T> {}; |
1669 | |
1670 | template <typename Property> |
1671 | void query(const Property& p, |
1672 | enable_if_t< |
1673 | is_same< |
1674 | typename find_convertible_property<Property>::query_result_type, |
1675 | void |
1676 | >::value |
1677 | >* = 0) const |
1678 | { |
1679 | if (!target_) |
1680 | { |
1681 | bad_executor ex; |
1682 | boost::asio::detail::throw_exception(e: ex); |
1683 | } |
1684 | typedef find_convertible_property<Property> found; |
1685 | prop_fns_[found::index].query(0, object_fns_->target(*this), |
1686 | &static_cast<const typename found::type&>(p)); |
1687 | } |
1688 | |
1689 | template <typename Property> |
1690 | typename find_convertible_property<Property>::query_result_type |
1691 | query(const Property& p, |
1692 | enable_if_t< |
1693 | !is_same< |
1694 | typename find_convertible_property<Property>::query_result_type, |
1695 | void |
1696 | >::value |
1697 | && |
1698 | is_reference< |
1699 | typename find_convertible_property<Property>::query_result_type |
1700 | >::value |
1701 | >* = 0) const |
1702 | { |
1703 | if (!target_) |
1704 | { |
1705 | bad_executor ex; |
1706 | boost::asio::detail::throw_exception(e: ex); |
1707 | } |
1708 | typedef find_convertible_property<Property> found; |
1709 | remove_reference_t<typename found::query_result_type>* result = 0; |
1710 | prop_fns_[found::index].query(&result, object_fns_->target(*this), |
1711 | &static_cast<const typename found::type&>(p)); |
1712 | return *result; |
1713 | } |
1714 | |
1715 | template <typename Property> |
1716 | typename find_convertible_property<Property>::query_result_type |
1717 | query(const Property& p, |
1718 | enable_if_t< |
1719 | !is_same< |
1720 | typename find_convertible_property<Property>::query_result_type, |
1721 | void |
1722 | >::value |
1723 | && |
1724 | is_scalar< |
1725 | typename find_convertible_property<Property>::query_result_type |
1726 | >::value |
1727 | >* = 0) const |
1728 | { |
1729 | if (!target_) |
1730 | { |
1731 | bad_executor ex; |
1732 | boost::asio::detail::throw_exception(e: ex); |
1733 | } |
1734 | typedef find_convertible_property<Property> found; |
1735 | typename found::query_result_type result; |
1736 | prop_fns_[found::index].query(&result, object_fns_->target(*this), |
1737 | &static_cast<const typename found::type&>(p)); |
1738 | return result; |
1739 | } |
1740 | |
1741 | template <typename Property> |
1742 | typename find_convertible_property<Property>::query_result_type |
1743 | query(const Property& p, |
1744 | enable_if_t< |
1745 | !is_same< |
1746 | typename find_convertible_property<Property>::query_result_type, |
1747 | void |
1748 | >::value |
1749 | && |
1750 | !is_reference< |
1751 | typename find_convertible_property<Property>::query_result_type |
1752 | >::value |
1753 | && |
1754 | !is_scalar< |
1755 | typename find_convertible_property<Property>::query_result_type |
1756 | >::value |
1757 | >* = 0) const |
1758 | { |
1759 | if (!target_) |
1760 | { |
1761 | bad_executor ex; |
1762 | boost::asio::detail::throw_exception(e: ex); |
1763 | } |
1764 | typedef find_convertible_property<Property> found; |
1765 | typename found::query_result_type* result; |
1766 | prop_fns_[found::index].query(&result, object_fns_->target(*this), |
1767 | &static_cast<const typename found::type&>(p)); |
1768 | return *boost::asio::detail::scoped_ptr< |
1769 | typename found::query_result_type>(result); |
1770 | } |
1771 | |
1772 | template <typename T> |
1773 | struct find_convertible_requirable_property : |
1774 | detail::supportable_properties< |
1775 | 0, void(SupportableProperties...)>::template |
1776 | find_convertible_requirable_property<T> {}; |
1777 | |
1778 | template <typename Property> |
1779 | any_executor require(const Property& p, |
1780 | enable_if_t< |
1781 | find_convertible_requirable_property<Property>::value |
1782 | >* = 0) const |
1783 | { |
1784 | if (!target_) |
1785 | { |
1786 | bad_executor ex; |
1787 | boost::asio::detail::throw_exception(e: ex); |
1788 | } |
1789 | typedef find_convertible_requirable_property<Property> found; |
1790 | return prop_fns_[found::index].require(object_fns_->target(*this), |
1791 | &static_cast<const typename found::type&>(p)); |
1792 | } |
1793 | |
1794 | template <typename T> |
1795 | struct find_convertible_preferable_property : |
1796 | detail::supportable_properties< |
1797 | 0, void(SupportableProperties...)>::template |
1798 | find_convertible_preferable_property<T> {}; |
1799 | |
1800 | template <typename Property> |
1801 | any_executor prefer(const Property& p, |
1802 | enable_if_t< |
1803 | find_convertible_preferable_property<Property>::value |
1804 | >* = 0) const |
1805 | { |
1806 | if (!target_) |
1807 | { |
1808 | bad_executor ex; |
1809 | boost::asio::detail::throw_exception(e: ex); |
1810 | } |
1811 | typedef find_convertible_preferable_property<Property> found; |
1812 | return prop_fns_[found::index].prefer(object_fns_->target(*this), |
1813 | &static_cast<const typename found::type&>(p)); |
1814 | } |
1815 | |
1816 | //private: |
1817 | template <typename Ex> |
1818 | static const prop_fns<any_executor>* prop_fns_table() |
1819 | { |
1820 | static const prop_fns<any_executor> fns[] = |
1821 | { |
1822 | { |
1823 | &detail::any_executor_base::query_fn< |
1824 | Ex, SupportableProperties>, |
1825 | &detail::any_executor_base::require_fn< |
1826 | any_executor, Ex, SupportableProperties>, |
1827 | &detail::any_executor_base::prefer_fn< |
1828 | any_executor, Ex, SupportableProperties> |
1829 | }... |
1830 | }; |
1831 | return fns; |
1832 | } |
1833 | |
1834 | const prop_fns<any_executor>* prop_fns_; |
1835 | }; |
1836 | |
1837 | template <typename... SupportableProperties> |
1838 | inline void swap(any_executor<SupportableProperties...>& a, |
1839 | any_executor<SupportableProperties...>& b) noexcept |
1840 | { |
1841 | return a.swap(b); |
1842 | } |
1843 | |
1844 | } // namespace execution |
1845 | namespace traits { |
1846 | |
1847 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) |
1848 | |
1849 | template <typename... SupportableProperties> |
1850 | struct equality_comparable<execution::any_executor<SupportableProperties...>> |
1851 | { |
1852 | static constexpr bool is_valid = true; |
1853 | static constexpr bool is_noexcept = true; |
1854 | }; |
1855 | |
1856 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) |
1857 | |
1858 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) |
1859 | |
1860 | template <typename F, typename... SupportableProperties> |
1861 | struct execute_member<execution::any_executor<SupportableProperties...>, F> |
1862 | { |
1863 | static constexpr bool is_valid = true; |
1864 | static constexpr bool is_noexcept = false; |
1865 | typedef void result_type; |
1866 | }; |
1867 | |
1868 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) |
1869 | |
1870 | #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) |
1871 | |
1872 | template <typename Prop, typename... SupportableProperties> |
1873 | struct query_member< |
1874 | execution::any_executor<SupportableProperties...>, Prop, |
1875 | enable_if_t< |
1876 | execution::detail::supportable_properties< |
1877 | 0, void(SupportableProperties...)>::template |
1878 | find_convertible_property<Prop>::value |
1879 | >> |
1880 | { |
1881 | static constexpr bool is_valid = true; |
1882 | static constexpr bool is_noexcept = false; |
1883 | typedef typename execution::detail::supportable_properties< |
1884 | 0, void(SupportableProperties...)>::template |
1885 | find_convertible_property<Prop>::query_result_type result_type; |
1886 | }; |
1887 | |
1888 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) |
1889 | |
1890 | #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) |
1891 | |
1892 | template <typename Prop, typename... SupportableProperties> |
1893 | struct require_member< |
1894 | execution::any_executor<SupportableProperties...>, Prop, |
1895 | enable_if_t< |
1896 | execution::detail::supportable_properties< |
1897 | 0, void(SupportableProperties...)>::template |
1898 | find_convertible_requirable_property<Prop>::value |
1899 | >> |
1900 | { |
1901 | static constexpr bool is_valid = true; |
1902 | static constexpr bool is_noexcept = false; |
1903 | typedef execution::any_executor<SupportableProperties...> result_type; |
1904 | }; |
1905 | |
1906 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) |
1907 | |
1908 | #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) |
1909 | |
1910 | template <typename Prop, typename... SupportableProperties> |
1911 | struct prefer_member< |
1912 | execution::any_executor<SupportableProperties...>, Prop, |
1913 | enable_if_t< |
1914 | execution::detail::supportable_properties< |
1915 | 0, void(SupportableProperties...)>::template |
1916 | find_convertible_preferable_property<Prop>::value |
1917 | >> |
1918 | { |
1919 | static constexpr bool is_valid = true; |
1920 | static constexpr bool is_noexcept = false; |
1921 | typedef execution::any_executor<SupportableProperties...> result_type; |
1922 | }; |
1923 | |
1924 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) |
1925 | |
1926 | } // namespace traits |
1927 | |
1928 | #endif // defined(GENERATING_DOCUMENTATION) |
1929 | |
1930 | } // namespace asio |
1931 | } // namespace boost |
1932 | |
1933 | #include <boost/asio/detail/pop_options.hpp> |
1934 | |
1935 | #endif // BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP |
1936 | |