boost/asio/execution/any_executor.hpp
//
// 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 <boost/asio/detail/config.hpp>
#include <new>
#include <typeinfo>
#include <boost/asio/detail/assert.hpp>
#include <boost/asio/detail/atomic_count.hpp>
#include <boost/asio/detail/cstddef.hpp>
#include <boost/asio/detail/executor_function.hpp>
#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/scoped_ptr.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/throw_exception.hpp>
#include <boost/asio/execution/bad_executor.hpp>
#include <boost/asio/execution/blocking.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/prefer.hpp>
#include <boost/asio/query.hpp>
#include <boost/asio/require.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if defined(GENERATING_DOCUMENTATION)
namespace execution {
/// Polymorphic executor wrapper.
template <typename... SupportableProperties>
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 <class... OtherSupportableProperties>
any_executor(any_executor<OtherSupportableProperties...> e);
/// Construct to point to the same target as another any_executor.
template <class... OtherSupportableProperties>
any_executor(std::nothrow_t,
any_executor<OtherSupportableProperties...> 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 <typename Executor>
any_executor(Executor e);
/// Construct a polymorphic wrapper for the specified executor.
template <typename Executor>
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 <typename Executor>
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<execution::blocking_t::possibly_t> ex = ...;
* auto ex2 = boost::asio::require(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
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<execution::blocking_t::possibly_t> ex = ...;
* auto ex2 = boost::asio::prefer(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
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<execution::occupancy_t> ex = ...;
* size_t n = boost::asio::query(ex, execution::occupancy); @endcode
*/
template <typename Property>
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 <typename Function>
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 <tt>execution::context_as<U></tt>, for some type <tt>U</tt>.
*/
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 <typename Executor> Executor* target() noexcept;
/// Get a pointer to the target executor.
template <typename Executor> const Executor* target() const noexcept;
};
/// Equality operator.
/**
* @relates any_executor
*/
template <typename... SupportableProperties>
bool operator==(const any_executor<SupportableProperties...>& a,
const any_executor<SupportableProperties...>& b) noexcept;
/// Equality operator.
/**
* @relates any_executor
*/
template <typename... SupportableProperties>
bool operator==(const any_executor<SupportableProperties...>& a,
nullptr_t) noexcept;
/// Equality operator.
/**
* @relates any_executor
*/
template <typename... SupportableProperties>
bool operator==(nullptr_t,
const any_executor<SupportableProperties...>& b) noexcept;
/// Inequality operator.
/**
* @relates any_executor
*/
template <typename... SupportableProperties>
bool operator!=(const any_executor<SupportableProperties...>& a,
const any_executor<SupportableProperties...>& b) noexcept;
/// Inequality operator.
/**
* @relates any_executor
*/
template <typename... SupportableProperties>
bool operator!=(const any_executor<SupportableProperties...>& a,
nullptr_t) noexcept;
/// Inequality operator.
/**
* @relates any_executor
*/
template <typename... SupportableProperties>
bool operator!=(nullptr_t,
const any_executor<SupportableProperties...>& 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 <typename... SupportableProperties>
class any_executor;
#endif // !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
template <typename U>
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 <typename T, typename = void>
struct is_requirable : false_type {};
template <typename T>
struct is_requirable<T, enable_if_t<T::is_requirable>> : true_type {};
template <typename T, typename = void>
struct is_preferable : false_type {};
template <typename T>
struct is_preferable<T, enable_if_t<T::is_preferable>> : true_type {};
// Trait used to detect context_as property, for backward compatibility.
template <typename T>
struct is_context_as : false_type {};
template <typename U>
struct is_context_as<context_as_t<U>> : 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 <std::size_t I, typename Props>
struct supportable_properties;
template <std::size_t I, typename Prop>
struct supportable_properties<I, void(Prop)>
{
template <typename T>
struct is_valid_target : integral_constant<bool,
(
is_requirable<Prop>::value
? can_require<T, Prop>::value
: true
)
&&
(
is_preferable<Prop>::value
? can_prefer<T, Prop>::value
: true
)
&&
(
!is_requirable<Prop>::value && !is_preferable<Prop>::value
? can_query<T, Prop>::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 <typename T>
struct find_convertible_property :
conditional_t<
is_same<T, Prop>::value || is_convertible<T, Prop>::value,
found,
not_found
> {};
template <typename T>
struct find_convertible_requirable_property :
conditional_t<
is_requirable<Prop>::value
&& (is_same<T, Prop>::value || is_convertible<T, Prop>::value),
found,
not_found
> {};
template <typename T>
struct find_convertible_preferable_property :
conditional_t<
is_preferable<Prop>::value
&& (is_same<T, Prop>::value || is_convertible<T, Prop>::value),
found,
not_found
> {};
struct find_context_as_property :
conditional_t<
is_context_as<Prop>::value,
found,
not_found
> {};
};
template <std::size_t I, typename Head, typename... Tail>
struct supportable_properties<I, void(Head, Tail...)>
{
template <typename T>
struct is_valid_target : integral_constant<bool,
(
supportable_properties<I,
void(Head)>::template is_valid_target<T>::value
&&
supportable_properties<I + 1,
void(Tail...)>::template is_valid_target<T>::value
)
>
{
};
template <typename T>
struct find_convertible_property :
conditional_t<
is_convertible<T, Head>::value,
typename supportable_properties<I, void(Head)>::found,
typename supportable_properties<I + 1,
void(Tail...)>::template find_convertible_property<T>
> {};
template <typename T>
struct find_convertible_requirable_property :
conditional_t<
is_requirable<Head>::value
&& is_convertible<T, Head>::value,
typename supportable_properties<I, void(Head)>::found,
typename supportable_properties<I + 1,
void(Tail...)>::template find_convertible_requirable_property<T>
> {};
template <typename T>
struct find_convertible_preferable_property :
conditional_t<
is_preferable<Head>::value
&& is_convertible<T, Head>::value,
typename supportable_properties<I, void(Head)>::found,
typename supportable_properties<I + 1,
void(Tail...)>::template find_convertible_preferable_property<T>
> {};
struct find_context_as_property :
conditional_t<
is_context_as<Head>::value,
typename supportable_properties<I, void(Head)>::found,
typename supportable_properties<I + 1,
void(Tail...)>::find_context_as_property
> {};
};
template <typename T, typename Props>
struct is_valid_target_executor :
conditional_t<
is_executor<T>::value,
typename supportable_properties<0, Props>::template is_valid_target<T>,
false_type
>
{
};
template <typename Props>
struct is_valid_target_executor<int, Props> : false_type
{
};
class shared_target_executor
{
public:
template <typename E>
shared_target_executor(E&& e, decay_t<E>*& target)
{
impl<decay_t<E>>* i =
new impl<decay_t<E>>(static_cast<E&&>(e));
target = &i->ex_;
impl_ = i;
}
template <typename E>
shared_target_executor(std::nothrow_t, E&& e, decay_t<E>*& target) noexcept
{
impl<decay_t<E>>* i =
new (std::nothrow) impl<decay_t<E>>(static_cast<E&&>(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 <typename Executor>
struct impl : impl_base
{
impl(Executor ex) : ex_(static_cast<Executor&&>(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 <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_executor_base(Executor ex, false_type)
: target_fns_(target_fns_table<Executor>(
any_executor_base::query_blocking(ex,
can_query<const Executor&, const execution::blocking_t&>())
== execution::blocking.always))
{
any_executor_base::construct_object(ex,
integral_constant<bool,
sizeof(Executor) <= sizeof(object_type)
&& alignment_of<Executor>::value <= alignment_of<object_type>::value
>());
}
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_executor_base(std::nothrow_t, Executor ex, false_type) noexcept
: target_fns_(target_fns_table<Executor>(
any_executor_base::query_blocking(ex,
can_query<const Executor&, const execution::blocking_t&>())
== execution::blocking.always))
{
any_executor_base::construct_object(std::nothrow, ex,
integral_constant<bool,
sizeof(Executor) <= sizeof(object_type)
&& alignment_of<Executor>::value <= alignment_of<object_type>::value
>());
if (target_ == 0)
{
object_fns_ = 0;
target_fns_ = 0;
}
}
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_executor_base(Executor other, true_type)
: object_fns_(object_fns_table<shared_target_executor>()),
target_fns_(other.target_fns_)
{
Executor* p = 0;
new (&object_) shared_target_executor(
static_cast<Executor&&>(other), p);
target_ = p->template target<void>();
}
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_executor_base(std::nothrow_t,
Executor other, true_type) noexcept
: object_fns_(object_fns_table<shared_target_executor>()),
target_fns_(other.target_fns_)
{
Executor* p = 0;
new (&object_) shared_target_executor(
std::nothrow, static_cast<Executor&&>(other), p);
if (p)
target_ = p->template target<void>();
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<any_executor_base&&>(other));
other = static_cast<any_executor_base&&>(*this);
*this = static_cast<any_executor_base&&>(tmp);
}
}
template <typename F>
void execute(F&& f) const
{
if (target_)
{
if (target_fns_->blocking_execute != 0)
{
boost::asio::detail::non_const_lvalue<F> f2(f);
target_fns_->blocking_execute(*this, function_view(f2.value));
}
else
{
target_fns_->execute(*this,
function(static_cast<F&&>(f), std::allocator<void>()));
}
}
else
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
}
}
template <typename Executor>
Executor* target()
{
return target_ && (is_same<Executor, void>::value
|| target_fns_->target_type() == target_type_ex<Executor>())
? static_cast<Executor*>(target_) : 0;
}
template <typename Executor>
const Executor* target() const
{
return target_ && (is_same<Executor, void>::value
|| target_fns_->target_type() == target_type_ex<Executor>())
? static_cast<const Executor*>(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 <typename Ex>
Ex& object()
{
return *static_cast<Ex*>(static_cast<void*>(&object_));
}
template <typename Ex>
const Ex& object() const
{
return *static_cast<const Ex*>(static_cast<const void*>(&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>().~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<type>());
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<type&&>(ex2.object<type>()));
ex1.target_ = ex2.target_;
ex2.object<type>().~type();
}
static const void* target_shared(const any_executor_base& ex)
{
typedef shared_target_executor type;
return ex.object<type>().get();
}
template <typename Obj>
static const object_fns* object_fns_table(
enable_if_t<
is_same<Obj, shared_target_executor>::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 <typename Obj>
static void destroy_object(any_executor_base& ex)
{
ex.object<Obj>().~Obj();
}
template <typename Obj>
static void copy_object(any_executor_base& ex1, const any_executor_base& ex2)
{
new (&ex1.object_) Obj(ex2.object<Obj>());
ex1.target_ = &ex1.object<Obj>();
}
template <typename Obj>
static void move_object(any_executor_base& ex1, any_executor_base& ex2)
{
new (&ex1.object_) Obj(static_cast<Obj&&>(ex2.object<Obj>()));
ex1.target_ = &ex1.object<Obj>();
ex2.object<Obj>().~Obj();
}
template <typename Obj>
static const void* target_object(const any_executor_base& ex)
{
return &ex.object<Obj>();
}
template <typename Obj>
static const object_fns* object_fns_table(
enable_if_t<
!is_same<Obj, void>::value
&& !is_same<Obj, shared_target_executor>::value
>* = 0)
{
static const object_fns fns =
{
&any_executor_base::destroy_object<Obj>,
&any_executor_base::copy_object<Obj>,
&any_executor_base::move_object<Obj>,
&any_executor_base::target_object<Obj>
};
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 <typename Ex>
static const std::type_info& target_type_ex()
{
return typeid(Ex);
}
#else // !defined(BOOST_ASIO_NO_TYPEID)
template <typename Ex>
static const void* target_type_ex()
{
static int unique_id;
return &unique_id;
}
#endif // !defined(BOOST_ASIO_NO_TYPEID)
template <typename Ex>
static bool equal_ex(const any_executor_base& ex1,
const any_executor_base& ex2)
{
const Ex* p1 = ex1.target<Ex>();
const Ex* p2 = ex2.target<Ex>();
BOOST_ASIO_ASSUME(p1 != 0 && p2 != 0);
return *p1 == *p2;
}
template <typename Ex>
static void execute_ex(const any_executor_base& ex, function&& f)
{
const Ex* p = ex.target<Ex>();
BOOST_ASIO_ASSUME(p != 0);
p->execute(static_cast<function&&>(f));
}
template <typename Ex>
static void blocking_execute_ex(const any_executor_base& ex, function_view f)
{
const Ex* p = ex.target<Ex>();
BOOST_ASIO_ASSUME(p != 0);
p->execute(f);
}
template <typename Ex>
static const target_fns* target_fns_table(bool is_always_blocking,
enable_if_t<
!is_same<Ex, void>::value
>* = 0)
{
static const target_fns fns_with_execute =
{
&any_executor_base::target_type_ex<Ex>,
&any_executor_base::equal_ex<Ex>,
&any_executor_base::execute_ex<Ex>,
0
};
static const target_fns fns_with_blocking_execute =
{
&any_executor_base::target_type_ex<Ex>,
&any_executor_base::equal_ex<Ex>,
0,
&any_executor_base::blocking_execute_ex<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 <typename Ex, class Prop>
static void query_fn_non_void(void*, const void* ex, const void* prop,
enable_if_t<
boost::asio::can_query<const Ex&, const Prop&>::value
&& is_same<typename Prop::polymorphic_query_result_type, void>::value
>*)
{
boost::asio::query(*static_cast<const Ex*>(ex),
*static_cast<const Prop*>(prop));
}
template <typename Ex, class Prop>
static void query_fn_non_void(void*, const void*, const void*,
enable_if_t<
!boost::asio::can_query<const Ex&, const Prop&>::value
&& is_same<typename Prop::polymorphic_query_result_type, void>::value
>*)
{
}
template <typename Ex, class Prop>
static void query_fn_non_void(void* result, const void* ex, const void* prop,
enable_if_t<
boost::asio::can_query<const Ex&, const Prop&>::value
&& !is_same<typename Prop::polymorphic_query_result_type, void>::value
&& is_reference<typename Prop::polymorphic_query_result_type>::value
>*)
{
*static_cast<remove_reference_t<
typename Prop::polymorphic_query_result_type>**>(result)
= &static_cast<typename Prop::polymorphic_query_result_type>(
boost::asio::query(*static_cast<const Ex*>(ex),
*static_cast<const Prop*>(prop)));
}
template <typename Ex, class Prop>
static void query_fn_non_void(void*, const void*, const void*,
enable_if_t<
!boost::asio::can_query<const Ex&, const Prop&>::value
&& !is_same<typename Prop::polymorphic_query_result_type, void>::value
&& is_reference<typename Prop::polymorphic_query_result_type>::value
>*)
{
std::terminate(); // Combination should not be possible.
}
template <typename Ex, class Prop>
static void query_fn_non_void(void* result, const void* ex, const void* prop,
enable_if_t<
boost::asio::can_query<const Ex&, const Prop&>::value
&& !is_same<typename Prop::polymorphic_query_result_type, void>::value
&& is_scalar<typename Prop::polymorphic_query_result_type>::value
>*)
{
*static_cast<typename Prop::polymorphic_query_result_type*>(result)
= static_cast<typename Prop::polymorphic_query_result_type>(
boost::asio::query(*static_cast<const Ex*>(ex),
*static_cast<const Prop*>(prop)));
}
template <typename Ex, class Prop>
static void query_fn_non_void(void* result, const void*, const void*,
enable_if_t<
!boost::asio::can_query<const Ex&, const Prop&>::value
&& !is_same<typename Prop::polymorphic_query_result_type, void>::value
&& is_scalar<typename Prop::polymorphic_query_result_type>::value
>*)
{
*static_cast<typename Prop::polymorphic_query_result_type*>(result)
= typename Prop::polymorphic_query_result_type();
}
template <typename Ex, class Prop>
static void query_fn_non_void(void* result, const void* ex, const void* prop,
enable_if_t<
boost::asio::can_query<const Ex&, const Prop&>::value
&& !is_same<typename Prop::polymorphic_query_result_type, void>::value
&& !is_reference<typename Prop::polymorphic_query_result_type>::value
&& !is_scalar<typename Prop::polymorphic_query_result_type>::value
>*)
{
*static_cast<typename Prop::polymorphic_query_result_type**>(result)
= new typename Prop::polymorphic_query_result_type(
boost::asio::query(*static_cast<const Ex*>(ex),
*static_cast<const Prop*>(prop)));
}
template <typename Ex, class Prop>
static void query_fn_non_void(void* result, const void*, const void*, ...)
{
*static_cast<typename Prop::polymorphic_query_result_type**>(result)
= new typename Prop::polymorphic_query_result_type();
}
template <typename Ex, class Prop>
static void query_fn_impl(void* result, const void* ex, const void* prop,
enable_if_t<
is_same<Ex, void>::value
>*)
{
query_fn_void(result, ex, prop);
}
template <typename Ex, class Prop>
static void query_fn_impl(void* result, const void* ex, const void* prop,
enable_if_t<
!is_same<Ex, void>::value
>*)
{
query_fn_non_void<Ex, Prop>(result, ex, prop, 0);
}
template <typename Ex, class Prop>
static void query_fn(void* result, const void* ex, const void* prop)
{
query_fn_impl<Ex, Prop>(result, ex, prop, 0);
}
template <typename Poly, typename Ex, class Prop>
static Poly require_fn_impl(const void*, const void*,
enable_if_t<
is_same<Ex, void>::value
>*)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
return Poly();
}
template <typename Poly, typename Ex, class Prop>
static Poly require_fn_impl(const void* ex, const void* prop,
enable_if_t<
!is_same<Ex, void>::value && Prop::is_requirable
>*)
{
return boost::asio::require(*static_cast<const Ex*>(ex),
*static_cast<const Prop*>(prop));
}
template <typename Poly, typename Ex, class Prop>
static Poly require_fn_impl(const void*, const void*, ...)
{
return Poly();
}
template <typename Poly, typename Ex, class Prop>
static Poly require_fn(const void* ex, const void* prop)
{
return require_fn_impl<Poly, Ex, Prop>(ex, prop, 0);
}
template <typename Poly, typename Ex, class Prop>
static Poly prefer_fn_impl(const void*, const void*,
enable_if_t<
is_same<Ex, void>::value
>*)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
return Poly();
}
template <typename Poly, typename Ex, class Prop>
static Poly prefer_fn_impl(const void* ex, const void* prop,
enable_if_t<
!is_same<Ex, void>::value && Prop::is_preferable
>*)
{
return boost::asio::prefer(*static_cast<const Ex*>(ex),
*static_cast<const Prop*>(prop));
}
template <typename Poly, typename Ex, class Prop>
static Poly prefer_fn_impl(const void*, const void*, ...)
{
return Poly();
}
template <typename Poly, typename Ex, class Prop>
static Poly prefer_fn(const void* ex, const void* prop)
{
return prefer_fn_impl<Poly, Ex, Prop>(ex, prop, 0);
}
template <typename Poly>
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 <typename Executor>
static execution::blocking_t query_blocking(const Executor& ex, true_type)
{
return boost::asio::query(ex, execution::blocking);
}
template <typename Executor>
static execution::blocking_t query_blocking(const Executor&, false_type)
{
return execution::blocking_t();
}
template <typename Executor>
void construct_object(Executor& ex, true_type)
{
object_fns_ = object_fns_table<Executor>();
target_ = new (&object_) Executor(static_cast<Executor&&>(ex));
}
template <typename Executor>
void construct_object(Executor& ex, false_type)
{
object_fns_ = object_fns_table<shared_target_executor>();
Executor* p = 0;
new (&object_) shared_target_executor(
static_cast<Executor&&>(ex), p);
target_ = p;
}
template <typename Executor>
void construct_object(std::nothrow_t,
Executor& ex, true_type) noexcept
{
object_fns_ = object_fns_table<Executor>();
target_ = new (&object_) Executor(static_cast<Executor&&>(ex));
}
template <typename Executor>
void construct_object(std::nothrow_t,
Executor& ex, false_type) noexcept
{
object_fns_ = object_fns_table<shared_target_executor>();
Executor* p = 0;
new (&object_) shared_target_executor(
std::nothrow, static_cast<Executor&&>(ex), p);
target_ = p;
}
/*private:*/public:
// template <typename...> friend class any_executor;
typedef aligned_storage<
sizeof(boost::asio::detail::shared_ptr<void>) + sizeof(void*),
alignment_of<boost::asio::detail::shared_ptr<void>>::value
>::type object_type;
object_type object_;
const object_fns* object_fns_;
void* target_;
const target_fns* target_fns_;
};
template <typename Derived, typename Property, typename = void>
struct any_executor_context
{
};
#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template <typename Derived, typename Property>
struct any_executor_context<Derived, Property, enable_if_t<Property::value>>
{
typename Property::query_result_type context() const
{
return static_cast<const Derived*>(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 <typename Executor>
any_executor(Executor ex,
enable_if_t<
conditional_t<
!is_same<Executor, any_executor>::value
&& !is_base_of<detail::any_executor_base, Executor>::value,
is_executor<Executor>,
false_type
>::value
>* = 0)
: detail::any_executor_base(
static_cast<Executor&&>(ex), false_type())
{
}
template <typename Executor>
any_executor(std::nothrow_t, Executor ex,
enable_if_t<
conditional_t<
!is_same<Executor, any_executor>::value
&& !is_base_of<detail::any_executor_base, Executor>::value,
is_executor<Executor>,
false_type
>::value
>* = 0) noexcept
: detail::any_executor_base(std::nothrow,
static_cast<Executor&&>(ex), false_type())
{
}
template <typename... OtherSupportableProperties>
any_executor(any_executor<OtherSupportableProperties...> other)
: detail::any_executor_base(
static_cast<const detail::any_executor_base&>(other))
{
}
template <typename... OtherSupportableProperties>
any_executor(std::nothrow_t,
any_executor<OtherSupportableProperties...> other) noexcept
: detail::any_executor_base(
static_cast<const detail::any_executor_base&>(other))
{
}
any_executor(const any_executor& other) noexcept
: detail::any_executor_base(
static_cast<const detail::any_executor_base&>(other))
{
}
any_executor(std::nothrow_t, const any_executor& other) noexcept
: detail::any_executor_base(
static_cast<const detail::any_executor_base&>(other))
{
}
any_executor& operator=(const any_executor& other) noexcept
{
if (this != &other)
{
detail::any_executor_base::operator=(
static_cast<const detail::any_executor_base&>(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<any_executor_base&&>(
static_cast<any_executor_base&>(other)))
{
}
any_executor(std::nothrow_t, any_executor&& other) noexcept
: detail::any_executor_base(
static_cast<any_executor_base&&>(
static_cast<any_executor_base&>(other)))
{
}
any_executor& operator=(any_executor&& other) noexcept
{
if (this != &other)
{
detail::any_executor_base::operator=(
static_cast<detail::any_executor_base&&>(
static_cast<detail::any_executor_base&>(other)));
}
return *this;
}
void swap(any_executor& other) noexcept
{
detail::any_executor_base::swap(
static_cast<detail::any_executor_base&>(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 <typename AnyExecutor1, typename AnyExecutor2>
friend enable_if_t<
is_base_of<any_executor, AnyExecutor1>::value
|| is_base_of<any_executor, AnyExecutor2>::value,
bool
> operator==(const AnyExecutor1& a,
const AnyExecutor2& b) noexcept
{
return static_cast<const any_executor&>(a).equality_helper(b);
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::value,
bool
> operator==(const AnyExecutor& a, nullptr_t) noexcept
{
return !a;
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::value,
bool
> operator==(nullptr_t, const AnyExecutor& b) noexcept
{
return !b;
}
template <typename AnyExecutor1, typename AnyExecutor2>
friend enable_if_t<
is_base_of<any_executor, AnyExecutor1>::value
|| is_base_of<any_executor, AnyExecutor2>::value,
bool
> operator!=(const AnyExecutor1& a,
const AnyExecutor2& b) noexcept
{
return !static_cast<const any_executor&>(a).equality_helper(b);
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::value,
bool
> operator!=(const AnyExecutor& a, nullptr_t) noexcept
{
return !!a;
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::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 <typename... SupportableProperties>
class any_executor :
public detail::any_executor_base,
public detail::any_executor_context<
any_executor<SupportableProperties...>,
typename detail::supportable_properties<
0, void(SupportableProperties...)>::find_context_as_property>
{
public:
any_executor() noexcept
: detail::any_executor_base(),
prop_fns_(prop_fns_table<void>())
{
}
any_executor(nullptr_t) noexcept
: detail::any_executor_base(),
prop_fns_(prop_fns_table<void>())
{
}
template <typename Executor>
any_executor(Executor ex,
enable_if_t<
conditional_t<
!is_same<Executor, any_executor>::value
&& !is_base_of<detail::any_executor_base, Executor>::value,
detail::is_valid_target_executor<
Executor, void(SupportableProperties...)>,
false_type
>::value
>* = 0)
: detail::any_executor_base(
static_cast<Executor&&>(ex), false_type()),
prop_fns_(prop_fns_table<Executor>())
{
}
template <typename Executor>
any_executor(std::nothrow_t, Executor ex,
enable_if_t<
conditional_t<
!is_same<Executor, any_executor>::value
&& !is_base_of<detail::any_executor_base, Executor>::value,
detail::is_valid_target_executor<
Executor, void(SupportableProperties...)>,
false_type
>::value
>* = 0) noexcept
: detail::any_executor_base(std::nothrow,
static_cast<Executor&&>(ex), false_type()),
prop_fns_(prop_fns_table<Executor>())
{
if (this->template target<void>() == 0)
prop_fns_ = prop_fns_table<void>();
}
template <typename... OtherSupportableProperties>
any_executor(any_executor<OtherSupportableProperties...> other,
enable_if_t<
conditional_t<
!is_same<
any_executor<OtherSupportableProperties...>,
any_executor
>::value,
typename detail::supportable_properties<
0, void(SupportableProperties...)>::template is_valid_target<
any_executor<OtherSupportableProperties...>>,
false_type
>::value
>* = 0)
: detail::any_executor_base(
static_cast<any_executor<OtherSupportableProperties...>&&>(other),
true_type()),
prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...>>())
{
}
template <typename... OtherSupportableProperties>
any_executor(std::nothrow_t,
any_executor<OtherSupportableProperties...> other,
enable_if_t<
conditional_t<
!is_same<
any_executor<OtherSupportableProperties...>,
any_executor
>::value,
typename detail::supportable_properties<
0, void(SupportableProperties...)>::template is_valid_target<
any_executor<OtherSupportableProperties...>>,
false_type
>::value
>* = 0) noexcept
: detail::any_executor_base(std::nothrow,
static_cast<any_executor<OtherSupportableProperties...>&&>(other),
true_type()),
prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...>>())
{
if (this->template target<void>() == 0)
prop_fns_ = prop_fns_table<void>();
}
any_executor(const any_executor& other) noexcept
: detail::any_executor_base(
static_cast<const detail::any_executor_base&>(other)),
prop_fns_(other.prop_fns_)
{
}
any_executor(std::nothrow_t, const any_executor& other) noexcept
: detail::any_executor_base(
static_cast<const detail::any_executor_base&>(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<const detail::any_executor_base&>(other));
}
return *this;
}
any_executor& operator=(nullptr_t p) noexcept
{
prop_fns_ = prop_fns_table<void>();
detail::any_executor_base::operator=(p);
return *this;
}
any_executor(any_executor&& other) noexcept
: detail::any_executor_base(
static_cast<any_executor_base&&>(
static_cast<any_executor_base&>(other))),
prop_fns_(other.prop_fns_)
{
other.prop_fns_ = prop_fns_table<void>();
}
any_executor(std::nothrow_t, any_executor&& other) noexcept
: detail::any_executor_base(
static_cast<any_executor_base&&>(
static_cast<any_executor_base&>(other))),
prop_fns_(other.prop_fns_)
{
other.prop_fns_ = prop_fns_table<void>();
}
any_executor& operator=(any_executor&& other) noexcept
{
if (this != &other)
{
prop_fns_ = other.prop_fns_;
detail::any_executor_base::operator=(
static_cast<detail::any_executor_base&&>(
static_cast<detail::any_executor_base&>(other)));
}
return *this;
}
void swap(any_executor& other) noexcept
{
if (this != &other)
{
detail::any_executor_base::swap(
static_cast<detail::any_executor_base&>(other));
const prop_fns<any_executor>* 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 <typename AnyExecutor1, typename AnyExecutor2>
friend enable_if_t<
is_base_of<any_executor, AnyExecutor1>::value
|| is_base_of<any_executor, AnyExecutor2>::value,
bool
> operator==(const AnyExecutor1& a,
const AnyExecutor2& b) noexcept
{
return static_cast<const any_executor&>(a).equality_helper(b);
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::value,
bool
> operator==(const AnyExecutor& a, nullptr_t) noexcept
{
return !a;
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::value,
bool
> operator==(nullptr_t, const AnyExecutor& b) noexcept
{
return !b;
}
template <typename AnyExecutor1, typename AnyExecutor2>
friend enable_if_t<
is_base_of<any_executor, AnyExecutor1>::value
|| is_base_of<any_executor, AnyExecutor2>::value,
bool
> operator!=(const AnyExecutor1& a,
const AnyExecutor2& b) noexcept
{
return !static_cast<const any_executor&>(a).equality_helper(b);
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::value,
bool
> operator!=(const AnyExecutor& a, nullptr_t) noexcept
{
return !!a;
}
template <typename AnyExecutor>
friend enable_if_t<
is_same<AnyExecutor, any_executor>::value,
bool
> operator!=(nullptr_t, const AnyExecutor& b) noexcept
{
return !!b;
}
template <typename T>
struct find_convertible_property :
detail::supportable_properties<
0, void(SupportableProperties...)>::template
find_convertible_property<T> {};
template <typename Property>
void query(const Property& p,
enable_if_t<
is_same<
typename find_convertible_property<Property>::query_result_type,
void
>::value
>* = 0) const
{
if (!target_)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
}
typedef find_convertible_property<Property> found;
prop_fns_[found::index].query(0, object_fns_->target(*this),
&static_cast<const typename found::type&>(p));
}
template <typename Property>
typename find_convertible_property<Property>::query_result_type
query(const Property& p,
enable_if_t<
!is_same<
typename find_convertible_property<Property>::query_result_type,
void
>::value
&&
is_reference<
typename find_convertible_property<Property>::query_result_type
>::value
>* = 0) const
{
if (!target_)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
}
typedef find_convertible_property<Property> found;
remove_reference_t<typename found::query_result_type>* result = 0;
prop_fns_[found::index].query(&result, object_fns_->target(*this),
&static_cast<const typename found::type&>(p));
return *result;
}
template <typename Property>
typename find_convertible_property<Property>::query_result_type
query(const Property& p,
enable_if_t<
!is_same<
typename find_convertible_property<Property>::query_result_type,
void
>::value
&&
is_scalar<
typename find_convertible_property<Property>::query_result_type
>::value
>* = 0) const
{
if (!target_)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
}
typedef find_convertible_property<Property> found;
typename found::query_result_type result;
prop_fns_[found::index].query(&result, object_fns_->target(*this),
&static_cast<const typename found::type&>(p));
return result;
}
template <typename Property>
typename find_convertible_property<Property>::query_result_type
query(const Property& p,
enable_if_t<
!is_same<
typename find_convertible_property<Property>::query_result_type,
void
>::value
&&
!is_reference<
typename find_convertible_property<Property>::query_result_type
>::value
&&
!is_scalar<
typename find_convertible_property<Property>::query_result_type
>::value
>* = 0) const
{
if (!target_)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
}
typedef find_convertible_property<Property> found;
typename found::query_result_type* result;
prop_fns_[found::index].query(&result, object_fns_->target(*this),
&static_cast<const typename found::type&>(p));
return *boost::asio::detail::scoped_ptr<
typename found::query_result_type>(result);
}
template <typename T>
struct find_convertible_requirable_property :
detail::supportable_properties<
0, void(SupportableProperties...)>::template
find_convertible_requirable_property<T> {};
template <typename Property>
any_executor require(const Property& p,
enable_if_t<
find_convertible_requirable_property<Property>::value
>* = 0) const
{
if (!target_)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
}
typedef find_convertible_requirable_property<Property> found;
return prop_fns_[found::index].require(object_fns_->target(*this),
&static_cast<const typename found::type&>(p));
}
template <typename T>
struct find_convertible_preferable_property :
detail::supportable_properties<
0, void(SupportableProperties...)>::template
find_convertible_preferable_property<T> {};
template <typename Property>
any_executor prefer(const Property& p,
enable_if_t<
find_convertible_preferable_property<Property>::value
>* = 0) const
{
if (!target_)
{
bad_executor ex;
boost::asio::detail::throw_exception(ex);
}
typedef find_convertible_preferable_property<Property> found;
return prop_fns_[found::index].prefer(object_fns_->target(*this),
&static_cast<const typename found::type&>(p));
}
//private:
template <typename Ex>
static const prop_fns<any_executor>* prop_fns_table()
{
static const prop_fns<any_executor> 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<any_executor>* prop_fns_;
};
template <typename... SupportableProperties>
inline void swap(any_executor<SupportableProperties...>& a,
any_executor<SupportableProperties...>& b) noexcept
{
return a.swap(b);
}
} // namespace execution
namespace traits {
#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <typename... SupportableProperties>
struct equality_comparable<execution::any_executor<SupportableProperties...>>
{
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 <typename F, typename... SupportableProperties>
struct execute_member<execution::any_executor<SupportableProperties...>, 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 <typename Prop, typename... SupportableProperties>
struct query_member<
execution::any_executor<SupportableProperties...>, Prop,
enable_if_t<
execution::detail::supportable_properties<
0, void(SupportableProperties...)>::template
find_convertible_property<Prop>::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<Prop>::query_result_type result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
template <typename Prop, typename... SupportableProperties>
struct require_member<
execution::any_executor<SupportableProperties...>, Prop,
enable_if_t<
execution::detail::supportable_properties<
0, void(SupportableProperties...)>::template
find_convertible_requirable_property<Prop>::value
>>
{
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = false;
typedef execution::any_executor<SupportableProperties...> result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
template <typename Prop, typename... SupportableProperties>
struct prefer_member<
execution::any_executor<SupportableProperties...>, Prop,
enable_if_t<
execution::detail::supportable_properties<
0, void(SupportableProperties...)>::template
find_convertible_preferable_property<Prop>::value
>>
{
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = false;
typedef execution::any_executor<SupportableProperties...> result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
} // namespace traits
#endif // defined(GENERATING_DOCUMENTATION)
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP