diff options
Diffstat (limited to 'src/boost/libs/hana/test/_include/laws/base.hpp')
-rw-r--r-- | src/boost/libs/hana/test/_include/laws/base.hpp | 369 |
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 |