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
39namespace boost {
40namespace asio {
41
42#if defined(GENERATING_DOCUMENTATION)
43
44namespace execution {
45
46/// Polymorphic executor wrapper.
47template <typename... SupportableProperties>
48class any_executor
49{
50public:
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 */
178template <typename... SupportableProperties>
179bool operator==(const any_executor<SupportableProperties...>& a,
180 const any_executor<SupportableProperties...>& b) noexcept;
181
182/// Equality operator.
183/**
184 * @relates any_executor
185 */
186template <typename... SupportableProperties>
187bool operator==(const any_executor<SupportableProperties...>& a,
188 nullptr_t) noexcept;
189
190/// Equality operator.
191/**
192 * @relates any_executor
193 */
194template <typename... SupportableProperties>
195bool operator==(nullptr_t,
196 const any_executor<SupportableProperties...>& b) noexcept;
197
198/// Inequality operator.
199/**
200 * @relates any_executor
201 */
202template <typename... SupportableProperties>
203bool operator!=(const any_executor<SupportableProperties...>& a,
204 const any_executor<SupportableProperties...>& b) noexcept;
205
206/// Inequality operator.
207/**
208 * @relates any_executor
209 */
210template <typename... SupportableProperties>
211bool operator!=(const any_executor<SupportableProperties...>& a,
212 nullptr_t) noexcept;
213
214/// Inequality operator.
215/**
216 * @relates any_executor
217 */
218template <typename... SupportableProperties>
219bool operator!=(nullptr_t,
220 const any_executor<SupportableProperties...>& b) noexcept;
221
222} // namespace execution
223
224#else // defined(GENERATING_DOCUMENTATION)
225
226namespace execution {
227
228#if !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
229#define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL
230
231template <typename... SupportableProperties>
232class any_executor;
233
234#endif // !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
235
236template <typename U>
237struct context_as_t;
238
239namespace 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
245template <typename T, typename = void>
246struct is_requirable : false_type {};
247
248template <typename T>
249struct is_requirable<T, enable_if_t<T::is_requirable>> : true_type {};
250
251template <typename T, typename = void>
252struct is_preferable : false_type {};
253
254template <typename T>
255struct is_preferable<T, enable_if_t<T::is_preferable>> : true_type {};
256
257// Trait used to detect context_as property, for backward compatibility.
258
259template <typename T>
260struct is_context_as : false_type {};
261
262template <typename U>
263struct 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
269template <std::size_t I, typename Props>
270struct supportable_properties;
271
272template <std::size_t I, typename Prop>
273struct 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
345template <std::size_t I, typename Head, typename... Tail>
346struct 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
399template <typename T, typename Props>
400struct 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
409template <typename Props>
410struct is_valid_target_executor<int, Props> : false_type
411{
412};
413
414class shared_target_executor
415{
416public:
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
460private:
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
486class any_executor_base
487{
488public:
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
734protected:
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
1143private:
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
1206template <typename Derived, typename Property, typename = void>
1207struct any_executor_context
1208{
1209};
1210
1211#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
1212
1213template <typename Derived, typename Property>
1214struct 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
1226template <>
1227class any_executor<> : public detail::any_executor_base
1228{
1229public:
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
1414inline void swap(any_executor<>& a, any_executor<>& b) noexcept
1415{
1416 return a.swap(other&: b);
1417}
1418
1419template <typename... SupportableProperties>
1420class 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{
1427public:
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
1837template <typename... SupportableProperties>
1838inline void swap(any_executor<SupportableProperties...>& a,
1839 any_executor<SupportableProperties...>& b) noexcept
1840{
1841 return a.swap(b);
1842}
1843
1844} // namespace execution
1845namespace traits {
1846
1847#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1848
1849template <typename... SupportableProperties>
1850struct 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
1860template <typename F, typename... SupportableProperties>
1861struct 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
1872template <typename Prop, typename... SupportableProperties>
1873struct 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
1892template <typename Prop, typename... SupportableProperties>
1893struct 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
1910template <typename Prop, typename... SupportableProperties>
1911struct 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

source code of boost/libs/asio/include/boost/asio/execution/any_executor.hpp