// // execution/any_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP #define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// Polymorphic executor wrapper. template class any_executor { public: /// Default constructor. any_executor() noexcept; /// Construct in an empty state. Equivalent effects to default constructor. any_executor(nullptr_t) noexcept; /// Copy constructor. any_executor(const any_executor& e) noexcept; /// Move constructor. any_executor(any_executor&& e) noexcept; /// Construct to point to the same target as another any_executor. template any_executor(any_executor e); /// Construct to point to the same target as another any_executor. template any_executor(std::nothrow_t, any_executor e) noexcept; /// Construct to point to the same target as another any_executor. any_executor(std::nothrow_t, const any_executor& e) noexcept; /// Construct to point to the same target as another any_executor. any_executor(std::nothrow_t, any_executor&& e) noexcept; /// Construct a polymorphic wrapper for the specified executor. template any_executor(Executor e); /// Construct a polymorphic wrapper for the specified executor. template any_executor(std::nothrow_t, Executor e) noexcept; /// Assignment operator. any_executor& operator=(const any_executor& e) noexcept; /// Move assignment operator. any_executor& operator=(any_executor&& e) noexcept; /// Assignment operator that sets the polymorphic wrapper to the empty state. any_executor& operator=(nullptr_t); /// Assignment operator to create a polymorphic wrapper for the specified /// executor. template any_executor& operator=(Executor e); /// Destructor. ~any_executor(); /// Swap targets with another polymorphic wrapper. void swap(any_executor& other) noexcept; /// Obtain a polymorphic wrapper with the specified property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require and boost::asio::prefer customisation points. * * For example: * @code execution::any_executor ex = ...; * auto ex2 = boost::asio::requre(ex, execution::blocking.possibly); @endcode */ template any_executor require(Property) const; /// Obtain a polymorphic wrapper with the specified property. /** * Do not call this function directly. It is intended for use with the * boost::asio::prefer customisation point. * * For example: * @code execution::any_executor ex = ...; * auto ex2 = boost::asio::prefer(ex, execution::blocking.possibly); @endcode */ template any_executor prefer(Property) const; /// Obtain the value associated with the specified property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code execution::any_executor ex = ...; * size_t n = boost::asio::query(ex, execution::occupancy); @endcode */ template typename Property::polymorphic_query_result_type query(Property) const; /// Execute the function on the target executor. /** * Throws boost::asio::bad_executor if the polymorphic wrapper has no target. */ template void execute(Function&& f) const; /// Obtain the underlying execution context. /** * This function is provided for backward compatibility. It is automatically * defined when the @c SupportableProperties... list includes a property of * type execution::context_as, for some type U. */ automatically_determined context() const; /// Determine whether the wrapper has a target executor. /** * @returns @c true if the polymorphic wrapper has a target executor, * otherwise false. */ explicit operator bool() const noexcept; /// Get the type of the target executor. const type_info& target_type() const noexcept; /// Get a pointer to the target executor. template Executor* target() noexcept; /// Get a pointer to the target executor. template const Executor* target() const noexcept; }; /// Equality operator. /** * @relates any_executor */ template bool operator==(const any_executor& a, const any_executor& b) noexcept; /// Equality operator. /** * @relates any_executor */ template bool operator==(const any_executor& a, nullptr_t) noexcept; /// Equality operator. /** * @relates any_executor */ template bool operator==(nullptr_t, const any_executor& b) noexcept; /// Inequality operator. /** * @relates any_executor */ template bool operator!=(const any_executor& a, const any_executor& b) noexcept; /// Inequality operator. /** * @relates any_executor */ template bool operator!=(const any_executor& a, nullptr_t) noexcept; /// Inequality operator. /** * @relates any_executor */ template bool operator!=(nullptr_t, const any_executor& b) noexcept; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { #if !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) #define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL template class any_executor; #endif // !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) template struct context_as_t; namespace detail { // Traits used to detect whether a property is requirable or preferable, taking // into account that T::is_requirable or T::is_preferable may not not be well // formed. template struct is_requirable : false_type {}; template struct is_requirable> : true_type {}; template struct is_preferable : false_type {}; template struct is_preferable> : true_type {}; // Trait used to detect context_as property, for backward compatibility. template struct is_context_as : false_type {}; template struct is_context_as> : true_type {}; // Helper template to: // - Check if a target can supply the supportable properties. // - Find the first convertible-from-T property in the list. template struct supportable_properties; template struct supportable_properties { template struct is_valid_target : integral_constant::value ? can_require::value : true ) && ( is_preferable::value ? can_prefer::value : true ) && ( !is_requirable::value && !is_preferable::value ? can_query::value : true ) > { }; struct found { static constexpr bool value = true; typedef Prop type; typedef typename Prop::polymorphic_query_result_type query_result_type; static constexpr std::size_t index = I; }; struct not_found { static constexpr bool value = false; }; template struct find_convertible_property : conditional_t< is_same::value || is_convertible::value, found, not_found > {}; template struct find_convertible_requirable_property : conditional_t< is_requirable::value && (is_same::value || is_convertible::value), found, not_found > {}; template struct find_convertible_preferable_property : conditional_t< is_preferable::value && (is_same::value || is_convertible::value), found, not_found > {}; struct find_context_as_property : conditional_t< is_context_as::value, found, not_found > {}; }; template struct supportable_properties { template struct is_valid_target : integral_constant::template is_valid_target::value && supportable_properties::template is_valid_target::value ) > { }; template struct find_convertible_property : conditional_t< is_convertible::value, typename supportable_properties::found, typename supportable_properties::template find_convertible_property > {}; template struct find_convertible_requirable_property : conditional_t< is_requirable::value && is_convertible::value, typename supportable_properties::found, typename supportable_properties::template find_convertible_requirable_property > {}; template struct find_convertible_preferable_property : conditional_t< is_preferable::value && is_convertible::value, typename supportable_properties::found, typename supportable_properties::template find_convertible_preferable_property > {}; struct find_context_as_property : conditional_t< is_context_as::value, typename supportable_properties::found, typename supportable_properties::find_context_as_property > {}; }; template struct is_valid_target_executor : conditional_t< is_executor::value, typename supportable_properties<0, Props>::template is_valid_target, false_type > { }; template struct is_valid_target_executor : false_type { }; class shared_target_executor { public: template shared_target_executor(E&& e, decay_t*& target) { impl>* i = new impl>(static_cast(e)); target = &i->ex_; impl_ = i; } template shared_target_executor(std::nothrow_t, E&& e, decay_t*& target) noexcept { impl>* i = new (std::nothrow) impl>(static_cast(e)); target = i ? &i->ex_ : 0; impl_ = i; } shared_target_executor(const shared_target_executor& other) noexcept : impl_(other.impl_) { if (impl_) boost::asio::detail::ref_count_up(impl_->ref_count_); } shared_target_executor(shared_target_executor&& other) noexcept : impl_(other.impl_) { other.impl_ = 0; } ~shared_target_executor() { if (impl_) if (boost::asio::detail::ref_count_down(impl_->ref_count_)) delete impl_; } void* get() const noexcept { return impl_ ? impl_->get() : 0; } private: shared_target_executor& operator=( const shared_target_executor& other) = delete; shared_target_executor& operator=( shared_target_executor&& other) = delete; struct impl_base { impl_base() : ref_count_(1) {} virtual ~impl_base() {} virtual void* get() = 0; boost::asio::detail::atomic_count ref_count_; }; template struct impl : impl_base { impl(Executor ex) : ex_(static_cast(ex)) {} virtual void* get() { return &ex_; } Executor ex_; }; impl_base* impl_; }; class any_executor_base { public: any_executor_base() noexcept : object_fns_(0), target_(0), target_fns_(0) { } template any_executor_base(Executor ex, false_type) : target_fns_(target_fns_table( any_executor_base::query_blocking(ex, can_query()) == execution::blocking.always)) { any_executor_base::construct_object(ex, integral_constant::value <= alignment_of::value >()); } template any_executor_base(std::nothrow_t, Executor ex, false_type) noexcept : target_fns_(target_fns_table( any_executor_base::query_blocking(ex, can_query()) == execution::blocking.always)) { any_executor_base::construct_object(std::nothrow, ex, integral_constant::value <= alignment_of::value >()); if (target_ == 0) { object_fns_ = 0; target_fns_ = 0; } } template any_executor_base(Executor other, true_type) : object_fns_(object_fns_table()), target_fns_(other.target_fns_) { Executor* p = 0; new (&object_) shared_target_executor( static_cast(other), p); target_ = p->template target(); } template any_executor_base(std::nothrow_t, Executor other, true_type) noexcept : object_fns_(object_fns_table()), target_fns_(other.target_fns_) { Executor* p = 0; new (&object_) shared_target_executor( std::nothrow, static_cast(other), p); if (p) target_ = p->template target(); else { target_ = 0; object_fns_ = 0; target_fns_ = 0; } } any_executor_base(const any_executor_base& other) noexcept { if (!!other) { object_fns_ = other.object_fns_; target_fns_ = other.target_fns_; object_fns_->copy(*this, other); } else { object_fns_ = 0; target_ = 0; target_fns_ = 0; } } ~any_executor_base() noexcept { if (!!*this) object_fns_->destroy(*this); } any_executor_base& operator=( const any_executor_base& other) noexcept { if (this != &other) { if (!!*this) object_fns_->destroy(*this); if (!!other) { object_fns_ = other.object_fns_; target_fns_ = other.target_fns_; object_fns_->copy(*this, other); } else { object_fns_ = 0; target_ = 0; target_fns_ = 0; } } return *this; } any_executor_base& operator=(nullptr_t) noexcept { if (target_) object_fns_->destroy(*this); target_ = 0; object_fns_ = 0; target_fns_ = 0; return *this; } any_executor_base(any_executor_base&& other) noexcept { if (other.target_) { object_fns_ = other.object_fns_; target_fns_ = other.target_fns_; other.object_fns_ = 0; other.target_fns_ = 0; object_fns_->move(*this, other); other.target_ = 0; } else { object_fns_ = 0; target_ = 0; target_fns_ = 0; } } any_executor_base& operator=( any_executor_base&& other) noexcept { if (this != &other) { if (!!*this) object_fns_->destroy(*this); if (!!other) { object_fns_ = other.object_fns_; target_fns_ = other.target_fns_; other.object_fns_ = 0; other.target_fns_ = 0; object_fns_->move(*this, other); other.target_ = 0; } else { object_fns_ = 0; target_ = 0; target_fns_ = 0; } } return *this; } void swap(any_executor_base& other) noexcept { if (this != &other) { any_executor_base tmp(static_cast(other)); other = static_cast(*this); *this = static_cast(tmp); } } template void execute(F&& f) const { if (target_) { if (target_fns_->blocking_execute != 0) { boost::asio::detail::non_const_lvalue f2(f); target_fns_->blocking_execute(*this, function_view(f2.value)); } else { target_fns_->execute(*this, function(static_cast(f), std::allocator())); } } else { bad_executor ex; boost::asio::detail::throw_exception(ex); } } template Executor* target() { return target_ && (is_same::value || target_fns_->target_type() == target_type_ex()) ? static_cast(target_) : 0; } template const Executor* target() const { return target_ && (is_same::value || target_fns_->target_type() == target_type_ex()) ? static_cast(target_) : 0; } #if !defined(BOOST_ASIO_NO_TYPEID) const std::type_info& target_type() const { return target_ ? target_fns_->target_type() : typeid(void); } #else // !defined(BOOST_ASIO_NO_TYPEID) const void* target_type() const { return target_ ? target_fns_->target_type() : 0; } #endif // !defined(BOOST_ASIO_NO_TYPEID) struct unspecified_bool_type_t {}; typedef void (*unspecified_bool_type)(unspecified_bool_type_t); static void unspecified_bool_true(unspecified_bool_type_t) {} operator unspecified_bool_type() const noexcept { return target_ ? &any_executor_base::unspecified_bool_true : 0; } bool operator!() const noexcept { return target_ == 0; } protected: bool equality_helper(const any_executor_base& other) const noexcept { if (target_ == other.target_) return true; if (target_ && !other.target_) return false; if (!target_ && other.target_) return false; if (target_fns_ != other.target_fns_) return false; return target_fns_->equal(*this, other); } template Ex& object() { return *static_cast(static_cast(&object_)); } template const Ex& object() const { return *static_cast(static_cast(&object_)); } struct object_fns { void (*destroy)(any_executor_base&); void (*copy)(any_executor_base&, const any_executor_base&); void (*move)(any_executor_base&, any_executor_base&); const void* (*target)(const any_executor_base&); }; static void destroy_shared(any_executor_base& ex) { typedef shared_target_executor type; ex.object().~type(); } static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2) { typedef shared_target_executor type; new (&ex1.object_) type(ex2.object()); ex1.target_ = ex2.target_; } static void move_shared(any_executor_base& ex1, any_executor_base& ex2) { typedef shared_target_executor type; new (&ex1.object_) type(static_cast(ex2.object())); ex1.target_ = ex2.target_; ex2.object().~type(); } static const void* target_shared(const any_executor_base& ex) { typedef shared_target_executor type; return ex.object().get(); } template static const object_fns* object_fns_table( enable_if_t< is_same::value >* = 0) { static const object_fns fns = { &any_executor_base::destroy_shared, &any_executor_base::copy_shared, &any_executor_base::move_shared, &any_executor_base::target_shared }; return &fns; } template static void destroy_object(any_executor_base& ex) { ex.object().~Obj(); } template static void copy_object(any_executor_base& ex1, const any_executor_base& ex2) { new (&ex1.object_) Obj(ex2.object()); ex1.target_ = &ex1.object(); } template static void move_object(any_executor_base& ex1, any_executor_base& ex2) { new (&ex1.object_) Obj(static_cast(ex2.object())); ex1.target_ = &ex1.object(); ex2.object().~Obj(); } template static const void* target_object(const any_executor_base& ex) { return &ex.object(); } template static const object_fns* object_fns_table( enable_if_t< !is_same::value && !is_same::value >* = 0) { static const object_fns fns = { &any_executor_base::destroy_object, &any_executor_base::copy_object, &any_executor_base::move_object, &any_executor_base::target_object }; return &fns; } typedef boost::asio::detail::executor_function function; typedef boost::asio::detail::executor_function_view function_view; struct target_fns { #if !defined(BOOST_ASIO_NO_TYPEID) const std::type_info& (*target_type)(); #else // !defined(BOOST_ASIO_NO_TYPEID) const void* (*target_type)(); #endif // !defined(BOOST_ASIO_NO_TYPEID) bool (*equal)(const any_executor_base&, const any_executor_base&); void (*execute)(const any_executor_base&, function&&); void (*blocking_execute)(const any_executor_base&, function_view); }; #if !defined(BOOST_ASIO_NO_TYPEID) template static const std::type_info& target_type_ex() { return typeid(Ex); } #else // !defined(BOOST_ASIO_NO_TYPEID) template static const void* target_type_ex() { static int unique_id; return &unique_id; } #endif // !defined(BOOST_ASIO_NO_TYPEID) template static bool equal_ex(const any_executor_base& ex1, const any_executor_base& ex2) { const Ex* p1 = ex1.target(); const Ex* p2 = ex2.target(); BOOST_ASIO_ASSUME(p1 != 0 && p2 != 0); return *p1 == *p2; } template static void execute_ex(const any_executor_base& ex, function&& f) { const Ex* p = ex.target(); BOOST_ASIO_ASSUME(p != 0); p->execute(static_cast(f)); } template static void blocking_execute_ex(const any_executor_base& ex, function_view f) { const Ex* p = ex.target(); BOOST_ASIO_ASSUME(p != 0); p->execute(f); } template static const target_fns* target_fns_table(bool is_always_blocking, enable_if_t< !is_same::value >* = 0) { static const target_fns fns_with_execute = { &any_executor_base::target_type_ex, &any_executor_base::equal_ex, &any_executor_base::execute_ex, 0 }; static const target_fns fns_with_blocking_execute = { &any_executor_base::target_type_ex, &any_executor_base::equal_ex, 0, &any_executor_base::blocking_execute_ex }; return is_always_blocking ? &fns_with_blocking_execute : &fns_with_execute; } #if defined(BOOST_ASIO_MSVC) # pragma warning (push) # pragma warning (disable:4702) #endif // defined(BOOST_ASIO_MSVC) static void query_fn_void(void*, const void*, const void*) { bad_executor ex; boost::asio::detail::throw_exception(ex); } template static void query_fn_non_void(void*, const void* ex, const void* prop, enable_if_t< boost::asio::can_query::value && is_same::value >*) { boost::asio::query(*static_cast(ex), *static_cast(prop)); } template static void query_fn_non_void(void*, const void*, const void*, enable_if_t< !boost::asio::can_query::value && is_same::value >*) { } template static void query_fn_non_void(void* result, const void* ex, const void* prop, enable_if_t< boost::asio::can_query::value && !is_same::value && is_reference::value >*) { *static_cast**>(result) = &static_cast( boost::asio::query(*static_cast(ex), *static_cast(prop))); } template static void query_fn_non_void(void*, const void*, const void*, enable_if_t< !boost::asio::can_query::value && !is_same::value && is_reference::value >*) { std::terminate(); // Combination should not be possible. } template static void query_fn_non_void(void* result, const void* ex, const void* prop, enable_if_t< boost::asio::can_query::value && !is_same::value && is_scalar::value >*) { *static_cast(result) = static_cast( boost::asio::query(*static_cast(ex), *static_cast(prop))); } template static void query_fn_non_void(void* result, const void*, const void*, enable_if_t< !boost::asio::can_query::value && !is_same::value && is_scalar::value >*) { *static_cast(result) = typename Prop::polymorphic_query_result_type(); } template static void query_fn_non_void(void* result, const void* ex, const void* prop, enable_if_t< boost::asio::can_query::value && !is_same::value && !is_reference::value && !is_scalar::value >*) { *static_cast(result) = new typename Prop::polymorphic_query_result_type( boost::asio::query(*static_cast(ex), *static_cast(prop))); } template static void query_fn_non_void(void* result, const void*, const void*, ...) { *static_cast(result) = new typename Prop::polymorphic_query_result_type(); } template static void query_fn_impl(void* result, const void* ex, const void* prop, enable_if_t< is_same::value >*) { query_fn_void(result, ex, prop); } template static void query_fn_impl(void* result, const void* ex, const void* prop, enable_if_t< !is_same::value >*) { query_fn_non_void(result, ex, prop, 0); } template static void query_fn(void* result, const void* ex, const void* prop) { query_fn_impl(result, ex, prop, 0); } template static Poly require_fn_impl(const void*, const void*, enable_if_t< is_same::value >*) { bad_executor ex; boost::asio::detail::throw_exception(ex); return Poly(); } template static Poly require_fn_impl(const void* ex, const void* prop, enable_if_t< !is_same::value && Prop::is_requirable >*) { return boost::asio::require(*static_cast(ex), *static_cast(prop)); } template static Poly require_fn_impl(const void*, const void*, ...) { return Poly(); } template static Poly require_fn(const void* ex, const void* prop) { return require_fn_impl(ex, prop, 0); } template static Poly prefer_fn_impl(const void*, const void*, enable_if_t< is_same::value >*) { bad_executor ex; boost::asio::detail::throw_exception(ex); return Poly(); } template static Poly prefer_fn_impl(const void* ex, const void* prop, enable_if_t< !is_same::value && Prop::is_preferable >*) { return boost::asio::prefer(*static_cast(ex), *static_cast(prop)); } template static Poly prefer_fn_impl(const void*, const void*, ...) { return Poly(); } template static Poly prefer_fn(const void* ex, const void* prop) { return prefer_fn_impl(ex, prop, 0); } template struct prop_fns { void (*query)(void*, const void*, const void*); Poly (*require)(const void*, const void*); Poly (*prefer)(const void*, const void*); }; #if defined(BOOST_ASIO_MSVC) # pragma warning (pop) #endif // defined(BOOST_ASIO_MSVC) private: template static execution::blocking_t query_blocking(const Executor& ex, true_type) { return boost::asio::query(ex, execution::blocking); } template static execution::blocking_t query_blocking(const Executor&, false_type) { return execution::blocking_t(); } template void construct_object(Executor& ex, true_type) { object_fns_ = object_fns_table(); target_ = new (&object_) Executor(static_cast(ex)); } template void construct_object(Executor& ex, false_type) { object_fns_ = object_fns_table(); Executor* p = 0; new (&object_) shared_target_executor( static_cast(ex), p); target_ = p; } template void construct_object(std::nothrow_t, Executor& ex, true_type) noexcept { object_fns_ = object_fns_table(); target_ = new (&object_) Executor(static_cast(ex)); } template void construct_object(std::nothrow_t, Executor& ex, false_type) noexcept { object_fns_ = object_fns_table(); Executor* p = 0; new (&object_) shared_target_executor( std::nothrow, static_cast(ex), p); target_ = p; } /*private:*/public: // template friend class any_executor; typedef aligned_storage< sizeof(boost::asio::detail::shared_ptr) + sizeof(void*), alignment_of>::value >::type object_type; object_type object_; const object_fns* object_fns_; void* target_; const target_fns* target_fns_; }; template struct any_executor_context { }; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template struct any_executor_context> { typename Property::query_result_type context() const { return static_cast(this)->query(typename Property::type()); } }; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) } // namespace detail template <> class any_executor<> : public detail::any_executor_base { public: any_executor() noexcept : detail::any_executor_base() { } any_executor(nullptr_t) noexcept : detail::any_executor_base() { } template any_executor(Executor ex, enable_if_t< conditional_t< !is_same::value && !is_base_of::value, is_executor, false_type >::value >* = 0) : detail::any_executor_base( static_cast(ex), false_type()) { } template any_executor(std::nothrow_t, Executor ex, enable_if_t< conditional_t< !is_same::value && !is_base_of::value, is_executor, false_type >::value >* = 0) noexcept : detail::any_executor_base(std::nothrow, static_cast(ex), false_type()) { } template any_executor(any_executor other) : detail::any_executor_base( static_cast(other)) { } template any_executor(std::nothrow_t, any_executor other) noexcept : detail::any_executor_base( static_cast(other)) { } any_executor(const any_executor& other) noexcept : detail::any_executor_base( static_cast(other)) { } any_executor(std::nothrow_t, const any_executor& other) noexcept : detail::any_executor_base( static_cast(other)) { } any_executor& operator=(const any_executor& other) noexcept { if (this != &other) { detail::any_executor_base::operator=( static_cast(other)); } return *this; } any_executor& operator=(nullptr_t p) noexcept { detail::any_executor_base::operator=(p); return *this; } any_executor(any_executor&& other) noexcept : detail::any_executor_base( static_cast( static_cast(other))) { } any_executor(std::nothrow_t, any_executor&& other) noexcept : detail::any_executor_base( static_cast( static_cast(other))) { } any_executor& operator=(any_executor&& other) noexcept { if (this != &other) { detail::any_executor_base::operator=( static_cast( static_cast(other))); } return *this; } void swap(any_executor& other) noexcept { detail::any_executor_base::swap( static_cast(other)); } using detail::any_executor_base::execute; using detail::any_executor_base::target; using detail::any_executor_base::target_type; using detail::any_executor_base::operator unspecified_bool_type; using detail::any_executor_base::operator!; bool equality_helper(const any_executor& other) const noexcept { return any_executor_base::equality_helper(other); } template friend enable_if_t< is_base_of::value || is_base_of::value, bool > operator==(const AnyExecutor1& a, const AnyExecutor2& b) noexcept { return static_cast(a).equality_helper(b); } template friend enable_if_t< is_same::value, bool > operator==(const AnyExecutor& a, nullptr_t) noexcept { return !a; } template friend enable_if_t< is_same::value, bool > operator==(nullptr_t, const AnyExecutor& b) noexcept { return !b; } template friend enable_if_t< is_base_of::value || is_base_of::value, bool > operator!=(const AnyExecutor1& a, const AnyExecutor2& b) noexcept { return !static_cast(a).equality_helper(b); } template friend enable_if_t< is_same::value, bool > operator!=(const AnyExecutor& a, nullptr_t) noexcept { return !!a; } template friend enable_if_t< is_same::value, bool > operator!=(nullptr_t, const AnyExecutor& b) noexcept { return !!b; } }; inline void swap(any_executor<>& a, any_executor<>& b) noexcept { return a.swap(b); } template class any_executor : public detail::any_executor_base, public detail::any_executor_context< any_executor, typename detail::supportable_properties< 0, void(SupportableProperties...)>::find_context_as_property> { public: any_executor() noexcept : detail::any_executor_base(), prop_fns_(prop_fns_table()) { } any_executor(nullptr_t) noexcept : detail::any_executor_base(), prop_fns_(prop_fns_table()) { } template any_executor(Executor ex, enable_if_t< conditional_t< !is_same::value && !is_base_of::value, detail::is_valid_target_executor< Executor, void(SupportableProperties...)>, false_type >::value >* = 0) : detail::any_executor_base( static_cast(ex), false_type()), prop_fns_(prop_fns_table()) { } template any_executor(std::nothrow_t, Executor ex, enable_if_t< conditional_t< !is_same::value && !is_base_of::value, detail::is_valid_target_executor< Executor, void(SupportableProperties...)>, false_type >::value >* = 0) noexcept : detail::any_executor_base(std::nothrow, static_cast(ex), false_type()), prop_fns_(prop_fns_table()) { if (this->template target() == 0) prop_fns_ = prop_fns_table(); } template any_executor(any_executor other, enable_if_t< conditional_t< !is_same< any_executor, any_executor >::value, typename detail::supportable_properties< 0, void(SupportableProperties...)>::template is_valid_target< any_executor>, false_type >::value >* = 0) : detail::any_executor_base( static_cast&&>(other), true_type()), prop_fns_(prop_fns_table>()) { } template any_executor(std::nothrow_t, any_executor other, enable_if_t< conditional_t< !is_same< any_executor, any_executor >::value, typename detail::supportable_properties< 0, void(SupportableProperties...)>::template is_valid_target< any_executor>, false_type >::value >* = 0) noexcept : detail::any_executor_base(std::nothrow, static_cast&&>(other), true_type()), prop_fns_(prop_fns_table>()) { if (this->template target() == 0) prop_fns_ = prop_fns_table(); } any_executor(const any_executor& other) noexcept : detail::any_executor_base( static_cast(other)), prop_fns_(other.prop_fns_) { } any_executor(std::nothrow_t, const any_executor& other) noexcept : detail::any_executor_base( static_cast(other)), prop_fns_(other.prop_fns_) { } any_executor& operator=(const any_executor& other) noexcept { if (this != &other) { prop_fns_ = other.prop_fns_; detail::any_executor_base::operator=( static_cast(other)); } return *this; } any_executor& operator=(nullptr_t p) noexcept { prop_fns_ = prop_fns_table(); detail::any_executor_base::operator=(p); return *this; } any_executor(any_executor&& other) noexcept : detail::any_executor_base( static_cast( static_cast(other))), prop_fns_(other.prop_fns_) { other.prop_fns_ = prop_fns_table(); } any_executor(std::nothrow_t, any_executor&& other) noexcept : detail::any_executor_base( static_cast( static_cast(other))), prop_fns_(other.prop_fns_) { other.prop_fns_ = prop_fns_table(); } any_executor& operator=(any_executor&& other) noexcept { if (this != &other) { prop_fns_ = other.prop_fns_; detail::any_executor_base::operator=( static_cast( static_cast(other))); } return *this; } void swap(any_executor& other) noexcept { if (this != &other) { detail::any_executor_base::swap( static_cast(other)); const prop_fns* tmp_prop_fns = other.prop_fns_; other.prop_fns_ = prop_fns_; prop_fns_ = tmp_prop_fns; } } using detail::any_executor_base::execute; using detail::any_executor_base::target; using detail::any_executor_base::target_type; using detail::any_executor_base::operator unspecified_bool_type; using detail::any_executor_base::operator!; bool equality_helper(const any_executor& other) const noexcept { return any_executor_base::equality_helper(other); } template friend enable_if_t< is_base_of::value || is_base_of::value, bool > operator==(const AnyExecutor1& a, const AnyExecutor2& b) noexcept { return static_cast(a).equality_helper(b); } template friend enable_if_t< is_same::value, bool > operator==(const AnyExecutor& a, nullptr_t) noexcept { return !a; } template friend enable_if_t< is_same::value, bool > operator==(nullptr_t, const AnyExecutor& b) noexcept { return !b; } template friend enable_if_t< is_base_of::value || is_base_of::value, bool > operator!=(const AnyExecutor1& a, const AnyExecutor2& b) noexcept { return !static_cast(a).equality_helper(b); } template friend enable_if_t< is_same::value, bool > operator!=(const AnyExecutor& a, nullptr_t) noexcept { return !!a; } template friend enable_if_t< is_same::value, bool > operator!=(nullptr_t, const AnyExecutor& b) noexcept { return !!b; } template struct find_convertible_property : detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_property {}; template void query(const Property& p, enable_if_t< is_same< typename find_convertible_property::query_result_type, void >::value >* = 0) const { if (!target_) { bad_executor ex; boost::asio::detail::throw_exception(ex); } typedef find_convertible_property found; prop_fns_[found::index].query(0, object_fns_->target(*this), &static_cast(p)); } template typename find_convertible_property::query_result_type query(const Property& p, enable_if_t< !is_same< typename find_convertible_property::query_result_type, void >::value && is_reference< typename find_convertible_property::query_result_type >::value >* = 0) const { if (!target_) { bad_executor ex; boost::asio::detail::throw_exception(ex); } typedef find_convertible_property found; remove_reference_t* result = 0; prop_fns_[found::index].query(&result, object_fns_->target(*this), &static_cast(p)); return *result; } template typename find_convertible_property::query_result_type query(const Property& p, enable_if_t< !is_same< typename find_convertible_property::query_result_type, void >::value && is_scalar< typename find_convertible_property::query_result_type >::value >* = 0) const { if (!target_) { bad_executor ex; boost::asio::detail::throw_exception(ex); } typedef find_convertible_property found; typename found::query_result_type result; prop_fns_[found::index].query(&result, object_fns_->target(*this), &static_cast(p)); return result; } template typename find_convertible_property::query_result_type query(const Property& p, enable_if_t< !is_same< typename find_convertible_property::query_result_type, void >::value && !is_reference< typename find_convertible_property::query_result_type >::value && !is_scalar< typename find_convertible_property::query_result_type >::value >* = 0) const { if (!target_) { bad_executor ex; boost::asio::detail::throw_exception(ex); } typedef find_convertible_property found; typename found::query_result_type* result; prop_fns_[found::index].query(&result, object_fns_->target(*this), &static_cast(p)); return *boost::asio::detail::scoped_ptr< typename found::query_result_type>(result); } template struct find_convertible_requirable_property : detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_requirable_property {}; template any_executor require(const Property& p, enable_if_t< find_convertible_requirable_property::value >* = 0) const { if (!target_) { bad_executor ex; boost::asio::detail::throw_exception(ex); } typedef find_convertible_requirable_property found; return prop_fns_[found::index].require(object_fns_->target(*this), &static_cast(p)); } template struct find_convertible_preferable_property : detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_preferable_property {}; template any_executor prefer(const Property& p, enable_if_t< find_convertible_preferable_property::value >* = 0) const { if (!target_) { bad_executor ex; boost::asio::detail::throw_exception(ex); } typedef find_convertible_preferable_property found; return prop_fns_[found::index].prefer(object_fns_->target(*this), &static_cast(p)); } //private: template static const prop_fns* prop_fns_table() { static const prop_fns fns[] = { { &detail::any_executor_base::query_fn< Ex, SupportableProperties>, &detail::any_executor_base::require_fn< any_executor, Ex, SupportableProperties>, &detail::any_executor_base::prefer_fn< any_executor, Ex, SupportableProperties> }... }; return fns; } const prop_fns* prop_fns_; }; template inline void swap(any_executor& a, any_executor& b) noexcept { return a.swap(b); } } // namespace execution namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template struct equality_comparable> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template struct execute_member, F> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = false; typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template struct query_member< execution::any_executor, Prop, enable_if_t< execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_property::value >> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = false; typedef typename execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_property::query_result_type result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template struct require_member< execution::any_executor, Prop, enable_if_t< execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_requirable_property::value >> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = false; typedef execution::any_executor result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) template struct prefer_member< execution::any_executor, Prop, enable_if_t< execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_preferable_property::value >> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = false; typedef execution::any_executor result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include #endif // BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP