summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/hana/test/_include/laws/base.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/hana/test/_include/laws/base.hpp')
-rw-r--r--src/boost/libs/hana/test/_include/laws/base.hpp369
1 files changed, 369 insertions, 0 deletions
diff --git a/src/boost/libs/hana/test/_include/laws/base.hpp b/src/boost/libs/hana/test/_include/laws/base.hpp
new file mode 100644
index 000000000..0f421b8ae
--- /dev/null
+++ b/src/boost/libs/hana/test/_include/laws/base.hpp
@@ -0,0 +1,369 @@
+// Copyright Louis Dionne 2013-2017
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_HANA_TEST_LAWS_BASE_HPP
+#define BOOST_HANA_TEST_LAWS_BASE_HPP
+
+#include <boost/hana/and.hpp>
+#include <boost/hana/bool.hpp>
+#include <boost/hana/core/when.hpp>
+#include <boost/hana/detail/wrong.hpp>
+#include <boost/hana/equal.hpp>
+#include <boost/hana/eval_if.hpp>
+#include <boost/hana/for_each.hpp>
+#include <boost/hana/functional/compose.hpp>
+#include <boost/hana/functional/infix.hpp>
+#include <boost/hana/functional/partial.hpp>
+#include <boost/hana/fwd/concept/integral_constant.hpp>
+#include <boost/hana/fwd/core/to.hpp>
+#include <boost/hana/fwd/less.hpp>
+#include <boost/hana/not.hpp>
+#include <boost/hana/or.hpp>
+#include <boost/hana/tuple.hpp>
+
+#include <support/tracked.hpp>
+
+#include <type_traits>
+#include <utility>
+
+
+namespace boost { namespace hana {
+ //////////////////////////////////////////////////////////////////////////
+ // Misc
+ //////////////////////////////////////////////////////////////////////////
+ namespace test {
+ struct laws;
+
+ template <int i>
+ struct for_each_n_t {
+ static_assert(i > 0, "can't use for_each_n with i < 0");
+
+ template <typename Xs, typename F>
+ constexpr auto operator()(Xs const& xs, F const& f) const {
+ hana::for_each(xs,
+ hana::compose(
+ hana::partial(for_each_n_t<i - 1>{}, xs),
+ hana::partial(hana::partial, f)
+ )
+ );
+ }
+ };
+
+ template <>
+ struct for_each_n_t<1> {
+ template <typename Xs, typename F>
+ constexpr auto operator()(Xs const& xs, F const& f) const {
+ hana::for_each(xs, f);
+ }
+ };
+
+ template <int i>
+ constexpr for_each_n_t<i> for_each_n{};
+
+ auto foreach = hana::for_each;
+ constexpr auto foreach3 = for_each_n<3>;
+ constexpr auto foreach2 = for_each_n<2>;
+
+ struct implies_t {
+ template <typename P, typename Q>
+ constexpr decltype(auto) operator()(P&& p, Q&& q) const {
+ return hana::or_(hana::not_(static_cast<P&&>(p)),
+ static_cast<Q&&>(q));
+ }
+ };
+ constexpr auto implies = hana::infix(implies_t{});
+
+ struct iff_t {
+ template <typename P, typename Q>
+ constexpr decltype(auto) operator()(P&& p, Q&& q) const {
+ return hana::and_(implies(p, q), implies(q, p));
+ }
+ };
+ constexpr auto iff = hana::infix(iff_t{});
+
+ template <typename Cond, typename F>
+ constexpr decltype(auto) only_when_(Cond cond, F f) {
+ return hana::eval_if(cond, f, [](auto){ });
+ }
+
+ // A type with a constructor that must not be instantiated.
+ // This is to make sure we don't instantiate something else than
+ // the copy-constructor of the elements inside a container when we
+ // copy the container.
+ struct trap_construct {
+ trap_construct() = default;
+ trap_construct(trap_construct const&) = default;
+#ifndef BOOST_HANA_WORKAROUND_MSVC_MULTIPLECTOR_106654
+ trap_construct(trap_construct&) = default;
+#endif
+ trap_construct(trap_construct&&) = default;
+
+ template <typename X>
+ trap_construct(X&&) {
+ static_assert(detail::wrong<X>{},
+ "this constructor must not be instantiated");
+ }
+ };
+
+ // A move-only type. Useful for testing containers.
+ struct move_only {
+ move_only() = default;
+ move_only(move_only const&) = delete;
+ move_only(move_only&&) = default;
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // InjectionResult
+ //////////////////////////////////////////////////////////////////////
+ struct InjectionResult { };
+
+ template <int i, typename ...X>
+ struct injection_result {
+ using hana_tag = InjectionResult;
+ static constexpr int injection_id = i;
+ hana::tuple<X...> args;
+ Tracked tracker;
+
+ template <typename ...Y, typename = decltype(tuple<X...>{std::declval<Y>()...})>
+ constexpr explicit injection_result(Y&& ...y)
+ : args{static_cast<Y&&>(y)...}, tracker{i}
+ { }
+ };
+
+ //! A monotonic injective function.
+ //!
+ //! This is used in the unit tests, where we often just need a function
+ //! which preserves equality and order, but which also satisfies the
+ //! following law for all `Injection`s `f` and `g`:
+ //! @code
+ //! f(x) == g(x) if and only if f === g
+ //! @endcode
+ //! where `===` means _was created by the same call to `injection`_.
+ //! This allows creating several such functions in the unit tests while
+ //! conserving precious information such as the fact that
+ //! `f(g(x)) != g(f(x))`.
+ template <int i>
+ struct _injection {
+ template <typename ...X>
+ constexpr auto operator()(X&& ...x) const {
+ return injection_result<i,
+ typename std::decay<X>::type...
+ >{static_cast<X&&>(x)...};
+ }
+ };
+ } // end namespace test
+
+ template <>
+ struct equal_impl<test::InjectionResult, test::InjectionResult> {
+ template <typename X, typename Y>
+ static constexpr auto apply(X x, Y y) {
+ return hana::and_(
+ hana::bool_c<X::injection_id == Y::injection_id>,
+ hana::equal(x.args, y.args)
+ );
+ }
+ };
+
+ template <>
+ struct less_impl<test::InjectionResult, test::InjectionResult> {
+ template <typename X, typename Y>
+ static constexpr auto apply(X x, Y y) {
+ static_assert(X::injection_id == Y::injection_id,
+ "can't order the result of two different injections");
+ return hana::less(x.args, y.args);
+ }
+ };
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Integer
+ //////////////////////////////////////////////////////////////////////////
+ namespace test {
+ enum class Policy : int {
+ // One of those is mandatory
+ Constant = 1 << 0
+ , Constexpr = 1 << 1
+ , Runtime = 1 << 2
+
+ // Those are optional
+ , Tracked = 1 << 3
+ , Comparable = 1 << 4
+ , Orderable = 1 << 5
+ };
+
+ constexpr bool operator&&(Policy a, Policy b) {
+ return static_cast<int>(a) && static_cast<int>(b);
+ }
+
+ constexpr bool operator&&(Policy a, bool b) {
+ return static_cast<int>(a) && b;
+ }
+
+ constexpr bool operator&&(bool a, Policy b) {
+ return a && static_cast<int>(b);
+ }
+
+ constexpr bool operator||(Policy a, Policy b) {
+ return static_cast<int>(a) || static_cast<int>(b);
+ }
+
+ constexpr bool operator||(Policy a, bool b) {
+ return static_cast<int>(a) || b;
+ }
+
+ constexpr bool operator||(bool a, Policy b) {
+ return a || static_cast<int>(b);
+ }
+
+ constexpr bool operator!(Policy a) {
+ return !static_cast<int>(a);
+ }
+
+ constexpr Policy operator|(Policy a, Policy b) {
+ return static_cast<Policy>(static_cast<int>(a) | static_cast<int>(b));
+ }
+
+ constexpr Policy operator&(Policy a, Policy b) {
+ return static_cast<Policy>(static_cast<int>(a) & static_cast<int>(b));
+ }
+
+ template <Policy policy, typename = void>
+ struct Integer { };
+
+ template <Policy policy>
+ struct Integer<policy, std::enable_if_t<!!(policy & Policy::Constant)>> {
+ using value_type = int;
+ };
+
+ template <int i, Policy policy, typename = void>
+ struct integer {
+ static_assert(
+ !!(policy & (Policy::Constant | Policy::Constexpr | Policy::Runtime))
+ , "You must choose at least one of Constant, Constexpr and Runtime.");
+
+ static constexpr int value = i;
+ constexpr operator int() const { return value; }
+ using hana_tag = Integer<policy>;
+ Tracked tracker{i};
+ };
+
+ template <int i, Policy policy>
+ struct integer <i, policy, std::enable_if_t<!!(policy & Policy::Constexpr)>> {
+ static constexpr int value = i;
+ constexpr operator int() const { return value; }
+ using hana_tag = Integer<policy>;
+ };
+
+ template <int i>
+ struct eq : integer<i, Policy::Comparable | Policy::Runtime> { };
+
+ template <int i>
+ struct ct_eq : integer<i, Policy::Comparable | Policy::Constant> { };
+
+ template <int i>
+ struct cx_eq : integer<i, Policy::Comparable | Policy::Constexpr> { };
+
+ template <int i>
+ struct ord : integer<i, Policy::Orderable | Policy::Runtime> { };
+
+ template <int i>
+ struct ct_ord : integer<i, Policy::Orderable | Policy::Constant> { };
+
+ template <int i>
+ struct cx_ord : integer<i, Policy::Orderable | Policy::Constexpr> { };
+
+ template <int i>
+ struct _constant
+ : integer<i, Policy::Constant | Policy::Comparable | Policy::Orderable>
+ { };
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Model of Constant/IntegralConstant
+ //////////////////////////////////////////////////////////////////////////
+ template <test::Policy policy>
+ struct IntegralConstant<test::Integer<policy>> {
+ static constexpr bool value = static_cast<bool>(policy & test::Policy::Constant);
+ };
+
+ template <test::Policy policy, typename C>
+ struct to_impl<test::Integer<policy>, C, when<
+ (policy & test::Policy::Constant) &&
+ hana::IntegralConstant<C>::value
+ >>
+ : embedding<is_embedded<typename C::value_type, int>::value>
+ {
+ template <typename N>
+ static constexpr auto apply(N const&) {
+ return test::integer<N::value, policy>{};
+ }
+ };
+
+ //////////////////////////////////////////////////////////////////////////
+ // Model of Comparable
+ //////////////////////////////////////////////////////////////////////////
+ template <test::Policy p1, test::Policy p2>
+ struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
+ // both Comparable or Orderable
+ (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
+ (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
+
+ // one Constexpr and the other Constant, or both Constexpr
+ (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
+ ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
+ ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
+ >> {
+ template <typename X, typename Y>
+ static constexpr bool apply(X const&, Y const&)
+ { return X::value == Y::value; }
+ };
+
+ template <test::Policy p1, test::Policy p2>
+ struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
+ // both Comparable or Orderable
+ (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
+ (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
+
+ // either one is Runtime
+ ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
+ >> {
+ template <typename X, typename Y>
+ static bool apply(X const&, Y const&)
+ { return X::value == Y::value; }
+ };
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Model of Orderable
+ //////////////////////////////////////////////////////////////////////////
+ template <test::Policy p1, test::Policy p2>
+ struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
+ // both Orderable
+ (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
+
+ // one Constexpr and the other Constant, or both Constexpr
+ (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
+ ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
+ ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
+ >> {
+ template <typename X, typename Y>
+ static constexpr bool apply(X const&, Y const&)
+ { return X::value < Y::value; }
+ };
+
+ template <test::Policy p1, test::Policy p2>
+ struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
+ // both Orderable
+ (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
+
+ // either one is Runtime
+ ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
+ >> {
+ template <typename X, typename Y>
+ static bool apply(X const&, Y const&)
+ { return X::value < Y::value; }
+ };
+}} // end namespace boost::hana
+
+#endif // !BOOST_HANA_TEST_LAWS_BASE_HPP