blob: d9b78a5eea3bbbf1eecde72b8ddc34d8ea50e425 [file] [log] [blame]
//
// execution/prefer_only.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_PREFER_ONLY_HPP
#define ASIO_EXECUTION_PREFER_ONLY_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/is_applicable_property.hpp"
#include "asio/prefer.hpp"
#include "asio/query.hpp"
#include "asio/traits/static_query.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if defined(GENERATING_DOCUMENTATION)
namespace execution {
/// A property adapter that is used with the polymorphic executor wrapper
/// to mark properties as preferable, but not requirable.
template <typename Property>
struct prefer_only
{
/// The prefer_only adapter applies to the same types as the nested property.
template <typename T>
static constexpr bool is_applicable_property_v =
is_applicable_property<T, Property>::value;
/// The context_t property cannot be required.
static constexpr bool is_requirable = false;
/// The context_t property can be preferred, it the underlying property can
/// be preferred.
/**
* @c true if @c Property::is_preferable is @c true, otherwise @c false.
*/
static constexpr bool is_preferable = automatically_determined;
/// The type returned by queries against an @c any_executor.
typedef typename Property::polymorphic_query_result_type
polymorphic_query_result_type;
};
} // namespace execution
#else // defined(GENERATING_DOCUMENTATION)
namespace execution {
namespace detail {
template <typename InnerProperty, typename = void>
struct prefer_only_is_preferable
{
ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
};
template <typename InnerProperty>
struct prefer_only_is_preferable<InnerProperty,
typename enable_if<
InnerProperty::is_preferable
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
};
template <typename InnerProperty, typename = void>
struct prefer_only_polymorphic_query_result_type
{
};
template <typename InnerProperty>
struct prefer_only_polymorphic_query_result_type<InnerProperty,
typename void_type<
typename InnerProperty::polymorphic_query_result_type
>::type>
{
typedef typename InnerProperty::polymorphic_query_result_type
polymorphic_query_result_type;
};
template <typename InnerProperty, typename = void, typename = void>
struct prefer_only_property
{
InnerProperty property;
prefer_only_property(const InnerProperty& p)
: property(p)
{
}
};
#if defined(ASIO_HAS_DECLTYPE) \
&& defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
template <typename InnerProperty>
struct prefer_only_property<InnerProperty,
typename void_type<
decltype(asio::declval<const InnerProperty>().value())
>::type>
{
InnerProperty property;
prefer_only_property(const InnerProperty& p)
: property(p)
{
}
ASIO_CONSTEXPR auto value() const
ASIO_NOEXCEPT_IF((
noexcept(asio::declval<const InnerProperty>().value())))
-> decltype(asio::declval<const InnerProperty>().value())
{
return property.value();
}
};
#else // defined(ASIO_HAS_DECLTYPE)
// && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
struct prefer_only_memfns_base
{
void value();
};
template <typename T>
struct prefer_only_memfns_derived
: T, prefer_only_memfns_base
{
};
template <typename T, T>
struct prefer_only_memfns_check
{
};
template <typename>
char (&prefer_only_value_memfn_helper(...))[2];
template <typename T>
char prefer_only_value_memfn_helper(
prefer_only_memfns_check<
void (prefer_only_memfns_base::*)(),
&prefer_only_memfns_derived<T>::value>*);
template <typename InnerProperty>
struct prefer_only_property<InnerProperty,
typename enable_if<
sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1
>::type,
typename enable_if<
!is_same<
typename InnerProperty::polymorphic_query_result_type,
void
>::value
>::type>
{
InnerProperty property;
prefer_only_property(const InnerProperty& p)
: property(p)
{
}
ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type
value() const
{
return property.value();
}
};
#endif // defined(ASIO_HAS_DECLTYPE)
// && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
} // namespace detail
template <typename InnerProperty>
struct prefer_only :
detail::prefer_only_is_preferable<InnerProperty>,
detail::prefer_only_polymorphic_query_result_type<InnerProperty>,
detail::prefer_only_property<InnerProperty>
{
ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
ASIO_CONSTEXPR prefer_only(const InnerProperty& p)
: detail::prefer_only_property<InnerProperty>(p)
{
}
#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
&& defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
template <typename T>
static ASIO_CONSTEXPR
typename traits::static_query<T, InnerProperty>::result_type
static_query()
ASIO_NOEXCEPT_IF((
traits::static_query<T, InnerProperty>::is_noexcept))
{
return traits::static_query<T, InnerProperty>::value();
}
template <typename E, typename T = decltype(prefer_only::static_query<E>())>
static ASIO_CONSTEXPR const T static_query_v
= prefer_only::static_query<E>();
#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
// && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
template <typename Executor, typename Property>
friend ASIO_CONSTEXPR
typename prefer_result<const Executor&, const InnerProperty&>::type
prefer(const Executor& ex, const prefer_only<Property>& p,
typename enable_if<
is_same<Property, InnerProperty>::value
>::type* = 0,
typename enable_if<
can_prefer<const Executor&, const InnerProperty&>::value
>::type* = 0)
#if !defined(ASIO_MSVC) \
&& !defined(__clang__) // Clang crashes if noexcept is used here.
ASIO_NOEXCEPT_IF((
is_nothrow_prefer<const Executor&, const InnerProperty&>::value))
#endif // !defined(ASIO_MSVC)
// && !defined(__clang__)
{
return asio::prefer(ex, p.property);
}
template <typename Executor, typename Property>
friend ASIO_CONSTEXPR
typename query_result<const Executor&, const InnerProperty&>::type
query(const Executor& ex, const prefer_only<Property>& p,
typename enable_if<
is_same<Property, InnerProperty>::value
>::type* = 0,
typename enable_if<
can_query<const Executor&, const InnerProperty&>::value
>::type* = 0)
#if !defined(ASIO_MSVC) \
&& !defined(__clang__) // Clang crashes if noexcept is used here.
ASIO_NOEXCEPT_IF((
is_nothrow_query<const Executor&, const InnerProperty&>::value))
#endif // !defined(ASIO_MSVC)
// && !defined(__clang__)
{
return asio::query(ex, p.property);
}
};
#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
&& defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
template <typename InnerProperty> template <typename E, typename T>
const T prefer_only<InnerProperty>::static_query_v;
#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
// && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
} // namespace execution
template <typename T, typename InnerProperty>
struct is_applicable_property<T, execution::prefer_only<InnerProperty> >
: is_applicable_property<T, InnerProperty>
{
};
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
|| !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
template <typename T, typename InnerProperty>
struct static_query<T, execution::prefer_only<InnerProperty> > :
static_query<T, const InnerProperty&>
{
};
#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
// || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
template <typename T, typename InnerProperty>
struct prefer_free_default<T, execution::prefer_only<InnerProperty>,
typename enable_if<
can_prefer<const T&, const InnerProperty&>::value
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
(is_nothrow_prefer<const T&, const InnerProperty&>::value));
typedef typename prefer_result<const T&,
const InnerProperty&>::type result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
template <typename T, typename InnerProperty>
struct query_free<T, execution::prefer_only<InnerProperty>,
typename enable_if<
can_query<const T&, const InnerProperty&>::value
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
(is_nothrow_query<const T&, const InnerProperty&>::value));
typedef typename query_result<const T&,
const InnerProperty&>::type result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
} // namespace traits
#endif // defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_EXECUTION_PREFER_ONLY_HPP