blob: e56b6e3b1042dc235d1c6543a06a55f270159078 [file] [log] [blame]
//
// prefer_only.cpp
// ~~~~~~~~~~~~~~~
//
// 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)
//
// Disable autolinking for unit tests.
#if !defined(BOOST_ALL_NO_LIB)
#define BOOST_ALL_NO_LIB 1
#endif // !defined(BOOST_ALL_NO_LIB)
// Test that header file is self-contained.
#include "asio/execution/prefer_only.hpp"
#include "asio/execution/any_executor.hpp"
#include "../unit_test.hpp"
#if defined(ASIO_HAS_BOOST_BIND)
# include <boost/bind/bind.hpp>
#else // defined(ASIO_HAS_BOOST_BIND)
# include <functional>
#endif // defined(ASIO_HAS_BOOST_BIND)
using namespace asio;
#if defined(ASIO_HAS_BOOST_BIND)
namespace bindns = boost;
#else // defined(ASIO_HAS_BOOST_BIND)
namespace bindns = std;
#endif
static int possibly_blocking_count = 0;
static int never_blocking_count = 0;
struct possibly_blocking_executor
{
template <typename F>
void execute(const F&) const
{
++possibly_blocking_count;
}
friend bool operator==(const possibly_blocking_executor&,
const possibly_blocking_executor&) ASIO_NOEXCEPT
{
return true;
}
friend bool operator!=(const possibly_blocking_executor&,
const possibly_blocking_executor&) ASIO_NOEXCEPT
{
return false;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<possibly_blocking_executor, F>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<possibly_blocking_executor>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
} // namespace traits
} // namespace asio
struct never_blocking_executor
{
static ASIO_CONSTEXPR execution::blocking_t::never_t
query(execution::blocking_t) ASIO_NOEXCEPT
{
return execution::blocking_t::never_t();
}
template <typename F>
void execute(const F&) const
{
++never_blocking_count;
}
friend bool operator==(const never_blocking_executor&,
const never_blocking_executor&) ASIO_NOEXCEPT
{
return true;
}
friend bool operator!=(const never_blocking_executor&,
const never_blocking_executor&) ASIO_NOEXCEPT
{
return false;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<never_blocking_executor, F>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<never_blocking_executor>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
template <typename Param>
struct query_static_constexpr_member<
never_blocking_executor, Param,
typename asio::enable_if<
asio::is_convertible<Param, execution::blocking_t>::value
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef execution::blocking_t::never_t result_type;
static ASIO_CONSTEXPR result_type value()
{
return result_type();
}
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
struct either_blocking_executor
{
execution::blocking_t blocking_;
explicit either_blocking_executor(execution::blocking_t b)
: blocking_(b)
{
}
execution::blocking_t query(execution::blocking_t) const ASIO_NOEXCEPT
{
return blocking_;
}
either_blocking_executor require(execution::blocking_t::possibly_t) const
{
return either_blocking_executor(execution::blocking.possibly);
}
either_blocking_executor require(execution::blocking_t::never_t) const
{
return either_blocking_executor(execution::blocking.never);
}
template <typename F>
void execute(const F&) const
{
if (blocking_ == execution::blocking.never)
++never_blocking_count;
else
++possibly_blocking_count;
}
friend bool operator==(const either_blocking_executor& a,
const either_blocking_executor& b) ASIO_NOEXCEPT
{
return a.blocking_ == b.blocking_;
}
friend bool operator!=(const either_blocking_executor& a,
const either_blocking_executor& b) ASIO_NOEXCEPT
{
return a.blocking_ != b.blocking_;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<either_blocking_executor, F>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<either_blocking_executor>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <typename Param>
struct query_member<
either_blocking_executor, Param,
typename asio::enable_if<
asio::is_convertible<Param, execution::blocking_t>::value
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef execution::blocking_t result_type;
};
#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <typename Param>
struct require_member<
either_blocking_executor, Param,
typename asio::enable_if<
asio::is_convertible<Param, execution::blocking_t>::value
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef either_blocking_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
void prefer_only_executor_query_test()
{
typedef execution::any_executor<
execution::blocking_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::blocking_t::never_t>
> executor_type;
executor_type ex1 = possibly_blocking_executor();
ASIO_CHECK(
asio::query(ex1, execution::blocking)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex1, execution::blocking.possibly)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex1, execution::blocking.never)
== execution::blocking.possibly);
executor_type ex2 = asio::prefer(ex1, execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex2, execution::blocking)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex2, execution::blocking.possibly)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex2, execution::blocking.never)
== execution::blocking.possibly);
executor_type ex3 = asio::prefer(ex1, execution::blocking.never);
ASIO_CHECK(
asio::query(ex3, execution::blocking)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex3, execution::blocking.possibly)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex3, execution::blocking.never)
== execution::blocking.possibly);
executor_type ex4 = never_blocking_executor();
ASIO_CHECK(
asio::query(ex4, execution::blocking)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex4, execution::blocking.possibly)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex4, execution::blocking.never)
== execution::blocking.never);
executor_type ex5 = asio::prefer(ex4, execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex5, execution::blocking)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex5, execution::blocking.possibly)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex5, execution::blocking.never)
== execution::blocking.never);
executor_type ex6 = asio::prefer(ex4, execution::blocking.never);
ASIO_CHECK(
asio::query(ex6, execution::blocking)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex6, execution::blocking.possibly)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex6, execution::blocking.never)
== execution::blocking.never);
executor_type ex7 = either_blocking_executor(execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex7, execution::blocking)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex7, execution::blocking.possibly)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex7, execution::blocking.never)
== execution::blocking.possibly);
executor_type ex8 = asio::prefer(ex7, execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex8, execution::blocking)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex8, execution::blocking.possibly)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex8, execution::blocking.never)
== execution::blocking.possibly);
executor_type ex9 = asio::prefer(ex7, execution::blocking.never);
ASIO_CHECK(
asio::query(ex9, execution::blocking)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex9, execution::blocking.possibly)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex9, execution::blocking.never)
== execution::blocking.never);
executor_type ex10 = either_blocking_executor(execution::blocking.never);
ASIO_CHECK(
asio::query(ex10, execution::blocking)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex10, execution::blocking.possibly)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex10, execution::blocking.never)
== execution::blocking.never);
executor_type ex11 = asio::prefer(ex7, execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex11, execution::blocking)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex11, execution::blocking.possibly)
== execution::blocking.possibly);
ASIO_CHECK(
asio::query(ex11, execution::blocking.never)
== execution::blocking.possibly);
executor_type ex12 = asio::prefer(ex7, execution::blocking.never);
ASIO_CHECK(
asio::query(ex12, execution::blocking)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex12, execution::blocking.possibly)
== execution::blocking.never);
ASIO_CHECK(
asio::query(ex12, execution::blocking.never)
== execution::blocking.never);
}
void do_nothing()
{
}
void prefer_only_executor_execute_test()
{
typedef execution::any_executor<
execution::blocking_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::blocking_t::never_t>
> executor_type;
executor_type ex1 = possibly_blocking_executor();
execution::execute(ex1, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 1);
ASIO_CHECK(never_blocking_count == 0);
executor_type ex2 = asio::prefer(ex1, execution::blocking.possibly);
execution::execute(ex2, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 2);
ASIO_CHECK(never_blocking_count == 0);
executor_type ex3 = asio::prefer(ex1, execution::blocking.never);
execution::execute(ex3, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 3);
ASIO_CHECK(never_blocking_count == 0);
executor_type ex4 = never_blocking_executor();
execution::execute(ex4, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 3);
ASIO_CHECK(never_blocking_count == 1);
executor_type ex5 = asio::prefer(ex4, execution::blocking.possibly);
execution::execute(ex5, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 3);
ASIO_CHECK(never_blocking_count == 2);
executor_type ex6 = asio::prefer(ex4, execution::blocking.never);
execution::execute(ex6, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 3);
ASIO_CHECK(never_blocking_count == 3);
executor_type ex7 = either_blocking_executor(execution::blocking.possibly);
execution::execute(ex7, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 4);
ASIO_CHECK(never_blocking_count == 3);
executor_type ex8 = asio::prefer(ex7, execution::blocking.possibly);
execution::execute(ex8, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 5);
ASIO_CHECK(never_blocking_count == 3);
executor_type ex9 = asio::prefer(ex7, execution::blocking.never);
execution::execute(ex9, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 5);
ASIO_CHECK(never_blocking_count == 4);
executor_type ex10 = either_blocking_executor(execution::blocking.never);
execution::execute(ex10, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 5);
ASIO_CHECK(never_blocking_count == 5);
executor_type ex11 = asio::prefer(ex7, execution::blocking.possibly);
execution::execute(ex11, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 6);
ASIO_CHECK(never_blocking_count == 5);
executor_type ex12 = asio::prefer(ex7, execution::blocking.never);
execution::execute(ex12, &do_nothing);
ASIO_CHECK(possibly_blocking_count == 6);
ASIO_CHECK(never_blocking_count == 6);
}
namespace test_props {
struct noncopyable_property
{
ASIO_STATIC_CONSTEXPR(bool, is_applicable = true);
ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
typedef int polymorphic_query_result_type;
explicit noncopyable_property(int value)
: value_(value)
{
}
int value_;
private:
noncopyable_property(const noncopyable_property&) ASIO_DELETED;
noncopyable_property& operator=(noncopyable_property&) ASIO_DELETED;
};
} // namespace test_props
namespace asio {
template <typename T>
struct is_applicable_property<T, test_props::noncopyable_property> : true_type
{
};
} // namespace asio
static int total_value_count = 0;
struct noncopyable_property_executor
{
int value_;
explicit noncopyable_property_executor(int value = 0)
: value_(value)
{
}
int query(const test_props::noncopyable_property&) const ASIO_NOEXCEPT
{
return value_;
}
noncopyable_property_executor require(const test_props::noncopyable_property& p) const
{
return noncopyable_property_executor(p.value_);
}
template <typename F>
void execute(const F&) const
{
total_value_count += value_;
}
friend bool operator==(const noncopyable_property_executor& a,
const noncopyable_property_executor& b) ASIO_NOEXCEPT
{
return a.value_ == b.value_;
}
friend bool operator!=(const noncopyable_property_executor& a,
const noncopyable_property_executor& b) ASIO_NOEXCEPT
{
return a.value_ != b.value_;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<noncopyable_property_executor, F>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<noncopyable_property_executor>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <>
struct query_member<
noncopyable_property_executor, test_props::noncopyable_property>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef int result_type;
};
#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <>
struct require_member<
noncopyable_property_executor, test_props::noncopyable_property>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef noncopyable_property_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
void prefer_only_noncopyable_property_test()
{
typedef execution::any_executor<
execution::prefer_only<test_props::noncopyable_property>
> executor_type;
noncopyable_property_executor ex;
executor_type ex1 = noncopyable_property_executor();
execution::execute(ex1, &do_nothing);
ASIO_CHECK(total_value_count == 0);
test_props::noncopyable_property prop1(42);
executor_type ex2 = asio::prefer(ex1, prop1);
execution::execute(ex2, &do_nothing);
ASIO_CHECK(total_value_count == 42);
}
ASIO_TEST_SUITE
(
"prefer_only",
ASIO_TEST_CASE(prefer_only_executor_query_test)
ASIO_TEST_CASE(prefer_only_executor_execute_test)
ASIO_TEST_CASE(prefer_only_noncopyable_property_test)
)