// 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 TEST_SUPPORT_NUMERIC_HPP #define TEST_SUPPORT_NUMERIC_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct numeric_type { constexpr explicit numeric_type(int v) : value(v) { } int value; constexpr operator int() const { return value; } }; using Numeric = boost::hana::tag_of_t; struct numeric_t { constexpr numeric_type operator()(int x) const { return numeric_type{x}; } }; constexpr numeric_t numeric{}; namespace boost { namespace hana { ////////////////////////////////////////////////////////////////////////// // Comparable ////////////////////////////////////////////////////////////////////////// template <> struct equal_impl { template static constexpr auto apply(X x, Y y) { return numeric(x.value == y.value); } }; ////////////////////////////////////////////////////////////////////////// // Orderable ////////////////////////////////////////////////////////////////////////// template <> struct less_impl { template static constexpr auto apply(X x, Y y) { // Workaround a _weird_ GCC bug: // error: parse error in template argument list // bool cmp = (x.value < y.value); // ^ int xv = x.value, yv = y.value; return numeric(xv < yv); } }; ////////////////////////////////////////////////////////////////////////// // Logical ////////////////////////////////////////////////////////////////////////// template <> struct eval_if_impl { template static constexpr auto apply(C const& c, T&& t, E&& e) { return c.value ? hana::eval(static_cast(t)) : hana::eval(static_cast(e)); } }; template <> struct not_impl { template static constexpr auto apply(X x) { return numeric(!x.value); } }; template <> struct while_impl { template static constexpr auto apply(Pred pred, State state, F f) -> decltype(true ? f(state) : state) { if (pred(state)) return hana::while_(pred, f(state), f); else return state; } }; ////////////////////////////////////////////////////////////////////////// // Monoid ////////////////////////////////////////////////////////////////////////// template <> struct plus_impl { template static constexpr auto apply(X x, Y y) { return numeric(x.value + y.value); } }; template <> struct zero_impl { static constexpr auto apply() { return numeric(0); } }; ////////////////////////////////////////////////////////////////////////// // Group // // Define either one to select which MCD is used: // BOOST_HANA_TEST_GROUP_NEGATE_MCD // BOOST_HANA_TEST_GROUP_MINUS_MCD // // If neither is defined, the MCD used is unspecified. ////////////////////////////////////////////////////////////////////////// #if defined(BOOST_HANA_TEST_GROUP_NEGATE_MCD) template <> struct negate_impl { template static constexpr auto apply(X x) { return numeric(-x.value); } }; #else template <> struct minus_impl { template static constexpr auto apply(X x, Y y) { return numeric(x.value - y.value); } }; #endif ////////////////////////////////////////////////////////////////////////// // Ring ////////////////////////////////////////////////////////////////////////// template <> struct mult_impl { template static constexpr auto apply(X x, Y y) { return numeric(x.value * y.value); } }; template <> struct one_impl { static constexpr auto apply() { return numeric(1); } }; ////////////////////////////////////////////////////////////////////////// // EuclideanRing ////////////////////////////////////////////////////////////////////////// template <> struct div_impl { template static constexpr auto apply(X x, Y y) { return numeric(x.value / y.value); } }; template <> struct mod_impl { template static constexpr auto apply(X x, Y y) { return numeric(x.value % y.value); } }; }} // end namespace boost::hana #endif //! TEST_SUPPORT_NUMERIC_HPP