//
// execution/any_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 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 ASIO_EXECUTION_ANY_EXECUTOR_HPP
#define ASIO_EXECUTION_ANY_EXECUTOR_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include <new>
#include <typeinfo>
#include "asio/detail/assert.hpp"
#include "asio/detail/cstddef.hpp"
#include "asio/detail/executor_function.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/scoped_ptr.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/throw_exception.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/execution/bad_executor.hpp"
#include "asio/execution/blocking.hpp"
#include "asio/execution/execute.hpp"
#include "asio/execution/executor.hpp"
#include "asio/prefer.hpp"
#include "asio/query.hpp"
#include "asio/require.hpp"

#include "asio/detail/push_options.hpp"

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 a polymorphic wrapper for the specified executor.
  template <typename Executor>
  any_executor(Executor e);

  /// 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
   * asio::require and asio::prefer customisation points.
   *
   * For example:
   * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...;
   * auto ex2 = asio::requre(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
   * asio::prefer customisation point.
   *
   * For example:
   * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...;
   * auto ex2 = 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
   * asio::query customisation point.
   *
   * For example:
   * @code execution::any_executor<execution::occupancy_t> ex = ...;
   * size_t n = 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.
  /**
   * Do not call this function directly. It is intended for use with the
   * execution::execute customisation point.
   *
   * For example:
   * @code execution::any_executor<> ex = ...;
   * execution::execute(ex, my_function_object); @endcode
   *
   * Throws 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(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)
#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL

#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename... SupportableProperties>
class any_executor;

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename = void, typename = void, typename = void,
    typename = void, typename = void, typename = void,
    typename = void, typename = void, typename = void>
class any_executor;

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)

#endif // !defined(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, typename enable_if<T::is_requirable>::type> :
  true_type {};

template <typename T, typename = void>
struct is_preferable : false_type {};

template <typename T>
struct is_preferable<T, typename enable_if<T::is_preferable>::type> :
  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
  {
    ASIO_STATIC_CONSTEXPR(bool, value = true);
    typedef Prop type;
    typedef typename Prop::polymorphic_query_result_type query_result_type;
    ASIO_STATIC_CONSTEXPR(std::size_t, index = I);
  };

  struct not_found
  {
    ASIO_STATIC_CONSTEXPR(bool, value = false);
  };

  template <typename T>
  struct find_convertible_property :
      conditional<
        is_same<T, Prop>::value || is_convertible<T, Prop>::value,
        found,
        not_found
      >::type {};

  template <typename T>
  struct find_convertible_requirable_property :
      conditional<
        is_requirable<Prop>::value
          && (is_same<T, Prop>::value || is_convertible<T, Prop>::value),
        found,
        not_found
      >::type {};

  template <typename T>
  struct find_convertible_preferable_property :
      conditional<
        is_preferable<Prop>::value
          && (is_same<T, Prop>::value || is_convertible<T, Prop>::value),
        found,
        not_found
      >::type {};

  struct find_context_as_property :
      conditional<
        is_context_as<Prop>::value,
        found,
        not_found
      >::type {};
};

#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

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<
        is_convertible<T, Head>::value,
        typename supportable_properties<I, void(Head)>::found,
        typename supportable_properties<I + 1,
            void(Tail...)>::template find_convertible_property<T>
      >::type {};

  template <typename T>
  struct find_convertible_requirable_property :
      conditional<
        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>
      >::type {};

  template <typename T>
  struct find_convertible_preferable_property :
      conditional<
        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>
      >::type {};

  struct find_context_as_property :
      conditional<
        is_context_as<Head>::value,
        typename supportable_properties<I, void(Head)>::found,
        typename supportable_properties<I + 1,
            void(Tail...)>::find_context_as_property
      >::type {};
};

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

#define ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF(n) \
  template <std::size_t I, \
    typename Head, ASIO_VARIADIC_TPARAMS(n)> \
  struct supportable_properties<I, \
      void(Head, ASIO_VARIADIC_TARGS(n))> \
  { \
    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(ASIO_VARIADIC_TARGS(n))>::template \
                is_valid_target<T>::value \
        ) \
      > \
    { \
    }; \
  \
    template <typename T> \
    struct find_convertible_property : \
        conditional< \
          is_convertible<T, Head>::value, \
          typename supportable_properties<I, void(Head)>::found, \
          typename supportable_properties<I + 1, \
              void(ASIO_VARIADIC_TARGS(n))>::template \
                find_convertible_property<T> \
        >::type {}; \
  \
    template <typename T> \
    struct find_convertible_requirable_property : \
        conditional< \
          is_requirable<Head>::value \
            && is_convertible<T, Head>::value, \
          typename supportable_properties<I, void(Head)>::found, \
          typename supportable_properties<I + 1, \
              void(ASIO_VARIADIC_TARGS(n))>::template \
                find_convertible_requirable_property<T> \
        >::type {}; \
  \
    template <typename T> \
    struct find_convertible_preferable_property : \
        conditional< \
          is_preferable<Head>::value \
            && is_convertible<T, Head>::value, \
          typename supportable_properties<I, void(Head)>::found, \
          typename supportable_properties<I + 1, \
              void(ASIO_VARIADIC_TARGS(n))>::template \
                find_convertible_preferable_property<T> \
        >::type {}; \
  \
    struct find_context_as_property : \
        conditional< \
          is_context_as<Head>::value, \
          typename supportable_properties<I, void(Head)>::found, \
          typename supportable_properties<I + 1, void( \
            ASIO_VARIADIC_TARGS(n))>::find_context_as_property \
        >::type {}; \
  }; \
  /**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF)
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename T, typename Props>
struct is_valid_target_executor :
  conditional<
    is_executor<T>::value,
    typename supportable_properties<0, Props>::template is_valid_target<T>,
    false_type
  >::type
{
};

class any_executor_base
{
public:
  any_executor_base() ASIO_NOEXCEPT
    : object_fns_(object_fns_table<void>()),
      target_(0),
      target_fns_(target_fns_table<void>())
  {
  }

  template <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 <ASIO_EXECUTION_EXECUTOR Executor>
  any_executor_base(Executor other, true_type)
    : object_fns_(object_fns_table<asio::detail::shared_ptr<void> >()),
      target_fns_(other.target_fns_)
  {
    asio::detail::shared_ptr<Executor> p =
      asio::detail::make_shared<Executor>(
          ASIO_MOVE_CAST(Executor)(other));
    target_ = p->template target<void>();
    new (&object_) asio::detail::shared_ptr<void>(
        ASIO_MOVE_CAST(asio::detail::shared_ptr<Executor>)(p));
  }

  any_executor_base(const any_executor_base& other) ASIO_NOEXCEPT
    : object_fns_(other.object_fns_),
      target_fns_(other.target_fns_)
  {
    object_fns_->copy(*this, other);
  }

  ~any_executor_base() ASIO_NOEXCEPT
  {
    object_fns_->destroy(*this);
  }

  any_executor_base& operator=(
      const any_executor_base& other) ASIO_NOEXCEPT
  {
    if (this != &other)
    {
      object_fns_->destroy(*this);
      object_fns_ = other.object_fns_;
      target_fns_ = other.target_fns_;
      object_fns_->copy(*this, other);
    }
    return *this;
  }

  any_executor_base& operator=(nullptr_t) ASIO_NOEXCEPT
  {
    object_fns_->destroy(*this);
    target_ = 0;
    object_fns_ = object_fns_table<void>();
    target_fns_ = target_fns_table<void>();
    return *this;
  }

#if defined(ASIO_HAS_MOVE)

  any_executor_base(any_executor_base&& other) ASIO_NOEXCEPT
    : object_fns_(other.object_fns_),
      target_fns_(other.target_fns_)
  {
    other.object_fns_ = object_fns_table<void>();
    other.target_fns_ = target_fns_table<void>();
    object_fns_->move(*this, other);
    other.target_ = 0;
  }

  any_executor_base& operator=(
      any_executor_base&& other) ASIO_NOEXCEPT
  {
    if (this != &other)
    {
      object_fns_->destroy(*this);
      object_fns_ = other.object_fns_;
      other.object_fns_ = object_fns_table<void>();
      target_fns_ = other.target_fns_;
      other.target_fns_ = target_fns_table<void>();
      object_fns_->move(*this, other);
      other.target_ = 0;
    }
    return *this;
  }

#endif // defined(ASIO_HAS_MOVE)

  void swap(any_executor_base& other) ASIO_NOEXCEPT
  {
    if (this != &other)
    {
      any_executor_base tmp(ASIO_MOVE_CAST(any_executor_base)(other));
      other = ASIO_MOVE_CAST(any_executor_base)(*this);
      *this = ASIO_MOVE_CAST(any_executor_base)(tmp);
    }
  }

  template <typename F>
  void execute(ASIO_MOVE_ARG(F) f) const
  {
    if (target_fns_->blocking_execute != 0)
    {
      asio::detail::non_const_lvalue<F> f2(f);
      target_fns_->blocking_execute(*this, function_view(f2.value));
    }
    else
    {
      target_fns_->execute(*this,
          function(ASIO_MOVE_CAST(F)(f), std::allocator<void>()));
    }
  }

  template <typename Executor>
  Executor* target()
  {
    return static_cast<Executor*>(target_);
  }

  template <typename Executor>
  const Executor* target() const
  {
    return static_cast<Executor*>(target_);
  }

  const std::type_info& target_type() const
  {
    return target_fns_->target_type();
  }

  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 ASIO_NOEXCEPT
  {
    return target_ ? &any_executor_base::unspecified_bool_true : 0;
  }

  bool operator!() const ASIO_NOEXCEPT
  {
    return target_ == 0;
  }

protected:
  bool equality_helper(const any_executor_base& other) const ASIO_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_void(any_executor_base&)
  {
  }

  static void copy_void(any_executor_base& ex1, const any_executor_base&)
  {
    ex1.target_ = 0;
  }

  static void move_void(any_executor_base& ex1, any_executor_base&)
  {
    ex1.target_ = 0;
  }

  static const void* target_void(const any_executor_base&)
  {
    return 0;
  }

  template <typename Obj>
  static const object_fns* object_fns_table(
      typename enable_if<
        is_same<Obj, void>::value
      >::type* = 0)
  {
    static const object_fns fns =
    {
      &any_executor_base::destroy_void,
      &any_executor_base::copy_void,
      &any_executor_base::move_void,
      &any_executor_base::target_void
    };
    return &fns;
  }

  static void destroy_shared(any_executor_base& ex)
  {
    typedef asio::detail::shared_ptr<void> type;
    ex.object<type>().~type();
  }

  static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2)
  {
    typedef asio::detail::shared_ptr<void> 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 asio::detail::shared_ptr<void> type;
    new (&ex1.object_) type(ASIO_MOVE_CAST(type)(ex2.object<type>()));
    ex1.target_ = ex2.target_;
    ex2.object<type>().~type();
  }

  static const void* target_shared(const any_executor_base& ex)
  {
    typedef asio::detail::shared_ptr<void> type;
    return ex.object<type>().get();
  }

  template <typename Obj>
  static const object_fns* object_fns_table(
      typename enable_if<
        is_same<Obj, asio::detail::shared_ptr<void> >::value
      >::type* = 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(ASIO_MOVE_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(
      typename enable_if<
        !is_same<Obj, void>::value
          && !is_same<Obj, asio::detail::shared_ptr<void> >::value
      >::type* = 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 asio::detail::executor_function function;
  typedef asio::detail::executor_function_view function_view;

  struct target_fns
  {
    const std::type_info& (*target_type)();
    bool (*equal)(const any_executor_base&, const any_executor_base&);
    void (*execute)(const any_executor_base&, ASIO_MOVE_ARG(function));
    void (*blocking_execute)(const any_executor_base&, function_view);
  };

  static const std::type_info& target_type_void()
  {
    return typeid(void);
  }

  static bool equal_void(const any_executor_base&, const any_executor_base&)
  {
    return true;
  }

  static void execute_void(const any_executor_base&,
      ASIO_MOVE_ARG(function))
  {
    bad_executor ex;
    asio::detail::throw_exception(ex);
  }

  static void blocking_execute_void(const any_executor_base&, function_view)
  {
    bad_executor ex;
    asio::detail::throw_exception(ex);
  }

  template <typename Ex>
  static const target_fns* target_fns_table(
      typename enable_if<
        is_same<Ex, void>::value
      >::type* = 0)
  {
    static const target_fns fns =
    {
      &any_executor_base::target_type_void,
      &any_executor_base::equal_void,
      &any_executor_base::execute_void,
      &any_executor_base::blocking_execute_void
    };
    return &fns;
  }

  template <typename Ex>
  static const std::type_info& target_type_ex()
  {
    return typeid(Ex);
  }

  template <typename Ex>
  static bool equal_ex(const any_executor_base& ex1,
      const any_executor_base& ex2)
  {
    return *ex1.target<Ex>() == *ex2.target<Ex>();
  }

  template <typename Ex>
  static void execute_ex(const any_executor_base& ex,
      ASIO_MOVE_ARG(function) f)
  {
    execution::execute(*ex.target<Ex>(), ASIO_MOVE_CAST(function)(f));
  }

  template <typename Ex>
  static void blocking_execute_ex(const any_executor_base& ex, function_view f)
  {
    execution::execute(*ex.target<Ex>(), f);
  }

  template <typename Ex>
  static const target_fns* target_fns_table(bool is_always_blocking,
      typename enable_if<
        !is_same<Ex, void>::value
      >::type* = 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(ASIO_MSVC)
# pragma warning (push)
# pragma warning (disable:4702)
#endif // defined(ASIO_MSVC)

  static void query_fn_void(void*, const void*, const void*)
  {
    bad_executor ex;
    asio::detail::throw_exception(ex);
  }

  template <typename Ex, class Prop>
  static void query_fn_non_void(void*, const void* ex, const void* prop,
      typename enable_if<
        asio::can_query<const Ex&, const Prop&>::value
          && is_same<typename Prop::polymorphic_query_result_type, void>::value
      >::type*)
  {
    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*,
      typename enable_if<
        !asio::can_query<const Ex&, const Prop&>::value
          && is_same<typename Prop::polymorphic_query_result_type, void>::value
      >::type*)
  {
  }

  template <typename Ex, class Prop>
  static void query_fn_non_void(void* result, const void* ex, const void* prop,
      typename enable_if<
        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
      >::type*)
  {
    *static_cast<typename remove_reference<
      typename Prop::polymorphic_query_result_type>::type**>(result)
        = &static_cast<typename Prop::polymorphic_query_result_type>(
            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*,
      typename enable_if<
        !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
      >::type*)
  {
    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,
      typename enable_if<
        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
      >::type*)
  {
    *static_cast<typename Prop::polymorphic_query_result_type*>(result)
      = static_cast<typename Prop::polymorphic_query_result_type>(
          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*,
      typename enable_if<
        !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
      >::type*)
  {
    *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,
      typename enable_if<
        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
      >::type*)
  {
    *static_cast<typename Prop::polymorphic_query_result_type**>(result)
      = new typename Prop::polymorphic_query_result_type(
          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,
      typename enable_if<
        is_same<Ex, void>::value
      >::type*)
  {
    query_fn_void(result, ex, prop);
  }

  template <typename Ex, class Prop>
  static void query_fn_impl(void* result, const void* ex, const void* prop,
      typename enable_if<
        !is_same<Ex, void>::value
      >::type*)
  {
    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*,
      typename enable_if<
        is_same<Ex, void>::value
      >::type*)
  {
    bad_executor ex;
    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,
      typename enable_if<
        !is_same<Ex, void>::value && Prop::is_requirable
      >::type*)
  {
    return 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*,
      typename enable_if<
        is_same<Ex, void>::value
      >::type*)
  {
    bad_executor ex;
    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,
      typename enable_if<
        !is_same<Ex, void>::value && Prop::is_preferable
      >::type*)
  {
    return 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(ASIO_MSVC)
# pragma warning (pop)
#endif // defined(ASIO_MSVC)

private:
  template <typename Executor>
  static execution::blocking_t query_blocking(const Executor& ex, true_type)
  {
    return 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(ASIO_MOVE_CAST(Executor)(ex));
  }

  template <typename Executor>
  void construct_object(Executor& ex, false_type)
  {
    object_fns_ = object_fns_table<asio::detail::shared_ptr<void> >();
    asio::detail::shared_ptr<Executor> p =
      asio::detail::make_shared<Executor>(
          ASIO_MOVE_CAST(Executor)(ex));
    target_ = p.get();
    new (&object_) asio::detail::shared_ptr<void>(
        ASIO_MOVE_CAST(asio::detail::shared_ptr<Executor>)(p));
  }

/*private:*/public:
//  template <typename...> friend class any_executor;

  typedef aligned_storage<
      sizeof(asio::detail::shared_ptr<void>),
      alignment_of<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(ASIO_NO_TS_EXECUTORS)

template <typename Derived, typename Property>
struct any_executor_context<Derived, Property,
    typename enable_if<Property::value>::type>
{
  typename Property::query_result_type context() const
  {
    return static_cast<const Derived*>(this)->query(typename Property::type());
  }
};

#endif // !defined(ASIO_NO_TS_EXECUTORS)

} // namespace detail

template <>
class any_executor<> : public detail::any_executor_base
{
public:
  any_executor() ASIO_NOEXCEPT
    : detail::any_executor_base()
  {
  }

  any_executor(nullptr_t) ASIO_NOEXCEPT
    : detail::any_executor_base()
  {
  }

  template <typename Executor>
  any_executor(Executor ex,
      typename enable_if<
        conditional<
          !is_same<Executor, any_executor>::value
            && !is_base_of<detail::any_executor_base, Executor>::value,
          is_executor<Executor>,
          false_type
        >::type::value
      >::type* = 0)
    : detail::any_executor_base(
        ASIO_MOVE_CAST(Executor)(ex), false_type())
  {
  }

#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

  template <typename... OtherSupportableProperties>
  any_executor(any_executor<OtherSupportableProperties...> other)
    : detail::any_executor_base(
        static_cast<const detail::any_executor_base&>(other))
  {
  }

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

  template <typename U0, typename U1, typename U2, typename U3,
      typename U4, typename U5, typename U6, typename U7>
  any_executor(any_executor<U0, U1, U2, U3, U4, U5, U6, U7> other)
    : detail::any_executor_base(
        static_cast<const detail::any_executor_base&>(other))
  {
  }

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)

  any_executor(const any_executor& other) ASIO_NOEXCEPT
    : detail::any_executor_base(
        static_cast<const detail::any_executor_base&>(other))
  {
  }

  any_executor& operator=(const any_executor& other) ASIO_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) ASIO_NOEXCEPT
  {
    detail::any_executor_base::operator=(p);
    return *this;
  }

#if defined(ASIO_HAS_MOVE)

  any_executor(any_executor&& other) ASIO_NOEXCEPT
    : detail::any_executor_base(
        static_cast<any_executor_base&&>(
          static_cast<any_executor_base&>(other)))
  {
  }

  any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT
  {
    if (this != &other)
    {
      detail::any_executor_base::operator=(
          static_cast<detail::any_executor_base&&>(
            static_cast<detail::any_executor_base&>(other)));
    }
    return *this;
  }

#endif // defined(ASIO_HAS_MOVE)

  void swap(any_executor& other) ASIO_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 ASIO_NOEXCEPT
  {
    return any_executor_base::equality_helper(other);
  }
};

inline bool operator==(const any_executor<>& a,
    const any_executor<>& b) ASIO_NOEXCEPT
{
  return a.equality_helper(b);
}

inline bool operator==(const any_executor<>& a, nullptr_t) ASIO_NOEXCEPT
{
  return !a;
}

inline bool operator==(nullptr_t, const any_executor<>& b) ASIO_NOEXCEPT
{
  return !b;
}

inline bool operator!=(const any_executor<>& a,
    const any_executor<>& b) ASIO_NOEXCEPT
{
  return !a.equality_helper(b);
}

inline bool operator!=(const any_executor<>& a, nullptr_t) ASIO_NOEXCEPT
{
  return !!a;
}

inline bool operator!=(nullptr_t, const any_executor<>& b) ASIO_NOEXCEPT
{
  return !!b;
}

inline void swap(any_executor<>& a, any_executor<>& b) ASIO_NOEXCEPT
{
  return a.swap(b);
}

#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

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() ASIO_NOEXCEPT
    : detail::any_executor_base(),
      prop_fns_(prop_fns_table<void>())
  {
  }

  any_executor(nullptr_t) ASIO_NOEXCEPT
    : detail::any_executor_base(),
      prop_fns_(prop_fns_table<void>())
  {
  }

  template <typename Executor>
  any_executor(Executor ex,
      typename enable_if<
        conditional<
          !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
        >::type::value
      >::type* = 0)
    : detail::any_executor_base(
        ASIO_MOVE_CAST(Executor)(ex), false_type()),
      prop_fns_(prop_fns_table<Executor>())
  {
  }

  template <typename... OtherSupportableProperties>
  any_executor(any_executor<OtherSupportableProperties...> other,
      typename enable_if<
        conditional<
          !is_same<
            any_executor<OtherSupportableProperties...>,
            any_executor
          >::value,
          typename detail::supportable_properties<
            0, void(SupportableProperties...)>::template is_valid_target<
              any_executor<OtherSupportableProperties...> >,
          false_type
        >::type::value
      >::type* = 0)
    : detail::any_executor_base(ASIO_MOVE_CAST(
          any_executor<OtherSupportableProperties...>)(other), true_type()),
      prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...> >())
  {
  }

  any_executor(const any_executor& other) ASIO_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) ASIO_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) ASIO_NOEXCEPT
  {
    prop_fns_ = prop_fns_table<void>();
    detail::any_executor_base::operator=(p);
    return *this;
  }

#if defined(ASIO_HAS_MOVE)

  any_executor(any_executor&& other) ASIO_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) ASIO_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;
  }

#endif // defined(ASIO_HAS_MOVE)

  void swap(any_executor& other) ASIO_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 ASIO_NOEXCEPT
  {
    return any_executor_base::equality_helper(other);
  }

  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,
      typename enable_if<
        is_same<
          typename find_convertible_property<Property>::query_result_type,
          void
        >::value
      >::type* = 0) const
  {
    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,
      typename enable_if<
        !is_same<
          typename find_convertible_property<Property>::query_result_type,
          void
        >::value
        &&
        is_reference<
          typename find_convertible_property<Property>::query_result_type
        >::value
      >::type* = 0) const
  {
    typedef find_convertible_property<Property> found;
    typename remove_reference<
      typename found::query_result_type>::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,
      typename enable_if<
        !is_same<
          typename find_convertible_property<Property>::query_result_type,
          void
        >::value
        &&
        is_scalar<
          typename find_convertible_property<Property>::query_result_type
        >::value
      >::type* = 0) const
  {
    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,
      typename enable_if<
        !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
      >::type* = 0) const
  {
    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 *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,
      typename enable_if<
        find_convertible_requirable_property<Property>::value
      >::type* = 0) const
  {
    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,
      typename enable_if<
        find_convertible_preferable_property<Property>::value
      >::type* = 0) const
  {
    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 bool operator==(const any_executor<SupportableProperties...>& a,
    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
{
  return a.equality_helper(b);
}

template <typename... SupportableProperties>
inline bool operator==(const any_executor<SupportableProperties...>& a,
    nullptr_t) ASIO_NOEXCEPT
{
  return !a;
}

template <typename... SupportableProperties>
inline bool operator==(nullptr_t,
    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
{
  return !b;
}

template <typename... SupportableProperties>
inline bool operator!=(const any_executor<SupportableProperties...>& a,
    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
{
  return !a.equality_helper(b);
}

template <typename... SupportableProperties>
inline bool operator!=(const any_executor<SupportableProperties...>& a,
    nullptr_t) ASIO_NOEXCEPT
{
  return !!a;
}

template <typename... SupportableProperties>
inline bool operator!=(nullptr_t,
    const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
{
  return !!b;
}

template <typename... SupportableProperties>
inline void swap(any_executor<SupportableProperties...>& a,
    any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT
{
  return a.swap(b);
}

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_##n

#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 \
  {  \
    &detail::any_executor_base::query_fn<Ex, T1>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T1>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T1> \
  }
#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1, \
  { \
    &detail::any_executor_base::query_fn<Ex, T2>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T2>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T2> \
  }
#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2, \
  { \
    &detail::any_executor_base::query_fn<Ex, T3>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T3>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T3> \
  }
#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3, \
  { \
    &detail::any_executor_base::query_fn<Ex, T4>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T4>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T4> \
  }
#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4, \
  { \
    &detail::any_executor_base::query_fn<Ex, T5>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T5>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T5> \
  }
#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5, \
  { \
    &detail::any_executor_base::query_fn<Ex, T6>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T6>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T6> \
  }
#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6, \
  { \
    &detail::any_executor_base::query_fn<Ex, T7>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T7>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T7> \
  }
#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 \
  ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7, \
  { \
    &detail::any_executor_base::query_fn<Ex, T8>, \
    &detail::any_executor_base::require_fn<any_executor, Ex, T8>, \
    &detail::any_executor_base::prefer_fn<any_executor, Ex, T8> \
  }

#if defined(ASIO_HAS_MOVE)

# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \
  any_executor(any_executor&& other) ASIO_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) ASIO_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; \
  } \
  /**/
#else // defined(ASIO_HAS_MOVE)

# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS

#endif // defined(ASIO_HAS_MOVE)

#define ASIO_PRIVATE_ANY_EXECUTOR_DEF(n) \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  class any_executor<ASIO_VARIADIC_TARGS(n)> : \
    public detail::any_executor_base, \
    public detail::any_executor_context< \
      any_executor<ASIO_VARIADIC_TARGS(n)>, \
        typename detail::supportable_properties< \
          0, void(ASIO_VARIADIC_TARGS(n))>::find_context_as_property> \
  { \
  public: \
    any_executor() ASIO_NOEXCEPT \
      : detail::any_executor_base(), \
        prop_fns_(prop_fns_table<void>()) \
    { \
    } \
    \
    any_executor(nullptr_t) ASIO_NOEXCEPT \
      : detail::any_executor_base(), \
        prop_fns_(prop_fns_table<void>()) \
    { \
    } \
    \
    template <ASIO_EXECUTION_EXECUTOR Executor> \
    any_executor(Executor ex, \
        typename enable_if< \
          conditional< \
            !is_same<Executor, any_executor>::value \
              && !is_base_of<detail::any_executor_base, Executor>::value, \
            detail::is_valid_target_executor< \
              Executor, void(ASIO_VARIADIC_TARGS(n))>, \
            false_type \
          >::type::value \
        >::type* = 0) \
      : detail::any_executor_base(ASIO_MOVE_CAST( \
            Executor)(ex), false_type()), \
        prop_fns_(prop_fns_table<Executor>()) \
    { \
    } \
    \
    any_executor(const any_executor& other) ASIO_NOEXCEPT \
      : detail::any_executor_base( \
          static_cast<const detail::any_executor_base&>(other)), \
        prop_fns_(other.prop_fns_) \
    { \
    } \
    \
    any_executor(any_executor<> other) \
      : detail::any_executor_base(ASIO_MOVE_CAST( \
            any_executor<>)(other), true_type()), \
        prop_fns_(prop_fns_table<any_executor<> >()) \
    { \
    } \
    \
    template <typename OtherAnyExecutor> \
    any_executor(OtherAnyExecutor other, \
        typename enable_if< \
          conditional< \
            !is_same<OtherAnyExecutor, any_executor>::value \
              && is_base_of<detail::any_executor_base, \
                OtherAnyExecutor>::value, \
            typename detail::supportable_properties< \
              0, void(ASIO_VARIADIC_TARGS(n))>::template \
                is_valid_target<OtherAnyExecutor>, \
            false_type \
          >::type::value \
        >::type* = 0) \
      : detail::any_executor_base(ASIO_MOVE_CAST( \
            OtherAnyExecutor)(other), true_type()), \
        prop_fns_(prop_fns_table<OtherAnyExecutor>()) \
    { \
    } \
    \
    any_executor& operator=(const any_executor& other) ASIO_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) ASIO_NOEXCEPT \
    { \
      prop_fns_ = prop_fns_table<void>(); \
      detail::any_executor_base::operator=(p); \
      return *this; \
    } \
    \
    ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \
    \
    void swap(any_executor& other) ASIO_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 ASIO_NOEXCEPT \
    { \
      return any_executor_base::equality_helper(other); \
    } \
    \
    template <typename T> \
    struct find_convertible_property : \
        detail::supportable_properties< \
          0, void(ASIO_VARIADIC_TARGS(n))>::template \
            find_convertible_property<T> {}; \
    \
    template <typename Property> \
    void query(const Property& p, \
        typename enable_if< \
          is_same< \
            typename find_convertible_property<Property>::query_result_type, \
            void \
          >::value \
        >::type* = 0) const \
    { \
      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, \
        typename enable_if< \
          !is_same< \
            typename find_convertible_property<Property>::query_result_type, \
            void \
          >::value \
          && \
          is_reference< \
            typename find_convertible_property<Property>::query_result_type \
          >::value \
        >::type* = 0) const \
    { \
      typedef find_convertible_property<Property> found; \
      typename remove_reference< \
        typename found::query_result_type>::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, \
        typename enable_if< \
          !is_same< \
            typename find_convertible_property<Property>::query_result_type, \
            void \
          >::value \
          && \
          is_scalar< \
            typename find_convertible_property<Property>::query_result_type \
          >::value \
        >::type* = 0) const \
    { \
      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, \
        typename enable_if< \
          !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 \
        >::type* = 0) const \
    { \
      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 *asio::detail::scoped_ptr< \
        typename found::query_result_type>(result); \
    } \
    \
    template <typename T> \
    struct find_convertible_requirable_property : \
        detail::supportable_properties< \
          0, void(ASIO_VARIADIC_TARGS(n))>::template \
            find_convertible_requirable_property<T> {}; \
    \
    template <typename Property> \
    any_executor require(const Property& p, \
        typename enable_if< \
          find_convertible_requirable_property<Property>::value \
        >::type* = 0) const \
    { \
      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(ASIO_VARIADIC_TARGS(n))>::template \
            find_convertible_preferable_property<T> {}; \
    \
    template <typename Property> \
    any_executor prefer(const Property& p, \
        typename enable_if< \
          find_convertible_preferable_property<Property>::value \
        >::type* = 0) const \
    { \
      typedef find_convertible_preferable_property<Property> found; \
      return prop_fns_[found::index].prefer(object_fns_->target(*this), \
          &static_cast<const typename found::type&>(p)); \
    } \
    \
    template <typename Ex> \
    static const prop_fns<any_executor>* prop_fns_table() \
    { \
      static const prop_fns<any_executor> fns[] = \
      { \
        ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \
      }; \
      return fns; \
    } \
    \
    const prop_fns<any_executor>* prop_fns_; \
    typedef detail::supportable_properties<0, \
        void(ASIO_VARIADIC_TARGS(n))> supportable_properties_type; \
  }; \
  \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  inline bool operator==(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
  { \
    return a.equality_helper(b); \
  } \
  \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  inline bool operator==(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
      nullptr_t) ASIO_NOEXCEPT \
  { \
    return !a; \
  } \
  \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  inline bool operator==(nullptr_t, \
      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
  { \
    return !b; \
  } \
  \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  inline bool operator!=(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
  { \
    return !a.equality_helper(b); \
  } \
  \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  inline bool operator!=(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
      nullptr_t) ASIO_NOEXCEPT \
  { \
    return !!a; \
  } \
  \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  inline bool operator!=(nullptr_t, \
      const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
  { \
    return !!b; \
  } \
  \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  inline void swap(any_executor<ASIO_VARIADIC_TARGS(n)>& a, \
      any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \
  { \
    return a.swap(b); \
  } \
  /**/
  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_DEF)
#undef ASIO_PRIVATE_ANY_EXECUTOR_DEF
#undef ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7
#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8

#endif // if defined(ASIO_HAS_VARIADIC_TEMPLATES)

} // namespace execution
namespace traits {

#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename... SupportableProperties>
struct equality_comparable<execution::any_executor<SupportableProperties...> >
{
  static const bool is_valid = true;
  static const bool is_noexcept = true;
};

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <>
struct equality_comparable<execution::any_executor<> >
{
  static const bool is_valid = true;
  static const bool is_noexcept = true;
};

#define ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF(n) \
  template <ASIO_VARIADIC_TPARAMS(n)> \
  struct equality_comparable< \
      execution::any_executor<ASIO_VARIADIC_TARGS(n)> > \
  { \
    static const bool is_valid = true; \
    static const bool is_noexcept = true; \
  }; \
  /**/
  ASIO_VARIADIC_GENERATE(
      ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF)
#undef ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)

#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename F, typename... SupportableProperties>
struct execute_member<execution::any_executor<SupportableProperties...>, F>
{
  static const bool is_valid = true;
  static const bool is_noexcept = false;
  typedef void result_type;
};

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename F>
struct execute_member<execution::any_executor<>, F>
{
  static const bool is_valid = true;
  static const bool is_noexcept = false;
  typedef void result_type;
};

#define ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF(n) \
  template <typename F, ASIO_VARIADIC_TPARAMS(n)> \
  struct execute_member< \
      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, F> \
  { \
    static const bool is_valid = true; \
    static const bool is_noexcept = false; \
    typedef void result_type; \
  }; \
  /**/
  ASIO_VARIADIC_GENERATE(
      ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF)
#undef ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)

#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename Prop, typename... SupportableProperties>
struct query_member<
    execution::any_executor<SupportableProperties...>, Prop,
    typename enable_if<
      execution::detail::supportable_properties<
        0, void(SupportableProperties...)>::template
          find_convertible_property<Prop>::value
    >::type>
{
  static const bool is_valid = true;
  static const bool is_noexcept = false;
  typedef typename execution::detail::supportable_properties<
      0, void(SupportableProperties...)>::template
        find_convertible_property<Prop>::query_result_type result_type;
};

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

#define ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF(n) \
  template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \
  struct query_member< \
      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \
      typename enable_if< \
        execution::detail::supportable_properties< \
          0, void(ASIO_VARIADIC_TARGS(n))>::template \
            find_convertible_property<Prop>::value \
    >::type> \
  { \
    static const bool is_valid = true; \
    static const bool is_noexcept = false; \
    typedef typename execution::detail::supportable_properties< \
        0, void(ASIO_VARIADIC_TARGS(n))>::template \
          find_convertible_property<Prop>::query_result_type result_type; \
  }; \
  /**/
  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF)
#undef ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)

#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename Prop, typename... SupportableProperties>
struct require_member<
    execution::any_executor<SupportableProperties...>, Prop,
    typename enable_if<
      execution::detail::supportable_properties<
        0, void(SupportableProperties...)>::template
          find_convertible_requirable_property<Prop>::value
    >::type>
{
  static const bool is_valid = true;
  static const bool is_noexcept = false;
  typedef execution::any_executor<SupportableProperties...> result_type;
};

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

#define ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF(n) \
  template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \
  struct require_member< \
      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \
      typename enable_if< \
        execution::detail::supportable_properties< \
          0, void(ASIO_VARIADIC_TARGS(n))>::template \
            find_convertible_requirable_property<Prop>::value \
      >::type> \
  { \
    static const bool is_valid = true; \
    static const bool is_noexcept = false; \
    typedef execution::any_executor<ASIO_VARIADIC_TARGS(n)> result_type; \
  }; \
  /**/
  ASIO_VARIADIC_GENERATE(
      ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF)
#undef ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)

#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename Prop, typename... SupportableProperties>
struct prefer_member<
    execution::any_executor<SupportableProperties...>, Prop,
    typename enable_if<
      execution::detail::supportable_properties<
        0, void(SupportableProperties...)>::template
          find_convertible_preferable_property<Prop>::value
    >::type>
{
  static const bool is_valid = true;
  static const bool is_noexcept = false;
  typedef execution::any_executor<SupportableProperties...> result_type;
};

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

#define ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF(n) \
  template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \
  struct prefer_member< \
      execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \
      typename enable_if< \
        execution::detail::supportable_properties< \
          0, void(ASIO_VARIADIC_TARGS(n))>::template \
            find_convertible_preferable_property<Prop>::value \
      >::type> \
  { \
    static const bool is_valid = true; \
    static const bool is_noexcept = false; \
    typedef execution::any_executor<ASIO_VARIADIC_TARGS(n)> result_type; \
  }; \
  /**/
  ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF)
#undef ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)

} // namespace traits

#endif // defined(GENERATING_DOCUMENTATION)

} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // ASIO_EXECUTION_ANY_EXECUTOR_HPP
