1 // Copyright Louis Dionne 2013-2017 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 4 5 #ifndef TEST_SUPPORT_NUMERIC_HPP 6 #define TEST_SUPPORT_NUMERIC_HPP 7 8 #include <boost/hana/core/tag_of.hpp> 9 #include <boost/hana/eval.hpp> 10 #include <boost/hana/fwd/div.hpp> 11 #include <boost/hana/fwd/equal.hpp> 12 #include <boost/hana/fwd/eval_if.hpp> 13 #include <boost/hana/fwd/less.hpp> 14 #include <boost/hana/fwd/minus.hpp> 15 #include <boost/hana/fwd/mod.hpp> 16 #include <boost/hana/fwd/mult.hpp> 17 #include <boost/hana/fwd/negate.hpp> 18 #include <boost/hana/fwd/not.hpp> 19 #include <boost/hana/fwd/one.hpp> 20 #include <boost/hana/fwd/plus.hpp> 21 #include <boost/hana/fwd/while.hpp> 22 #include <boost/hana/fwd/zero.hpp> 23 24 25 struct numeric_type { numeric_typenumeric_type26 constexpr explicit numeric_type(int v) : value(v) { } 27 int value; operator intnumeric_type28 constexpr operator int() const { return value; } 29 }; 30 31 using Numeric = boost::hana::tag_of_t<numeric_type>; 32 33 struct numeric_t { operator ()numeric_t34 constexpr numeric_type operator()(int x) const { 35 return numeric_type{x}; 36 } 37 }; 38 constexpr numeric_t numeric{}; 39 40 41 namespace boost { namespace hana { 42 ////////////////////////////////////////////////////////////////////////// 43 // Comparable 44 ////////////////////////////////////////////////////////////////////////// 45 template <> 46 struct equal_impl<Numeric, Numeric> { 47 template <typename X, typename Y> applyboost::hana::equal_impl48 static constexpr auto apply(X x, Y y) 49 { return numeric(x.value == y.value); } 50 }; 51 52 ////////////////////////////////////////////////////////////////////////// 53 // Orderable 54 ////////////////////////////////////////////////////////////////////////// 55 template <> 56 struct less_impl<Numeric, Numeric> { 57 template <typename X, typename Y> applyboost::hana::less_impl58 static constexpr auto apply(X x, Y y) { 59 // Workaround a _weird_ GCC bug: 60 // error: parse error in template argument list 61 // bool cmp = (x.value < y.value); 62 // ^ 63 int xv = x.value, yv = y.value; 64 return numeric(xv < yv); 65 } 66 }; 67 68 ////////////////////////////////////////////////////////////////////////// 69 // Logical 70 ////////////////////////////////////////////////////////////////////////// 71 template <> 72 struct eval_if_impl<Numeric> { 73 template <typename C, typename T, typename E> applyboost::hana::eval_if_impl74 static constexpr auto apply(C const& c, T&& t, E&& e) { 75 return c.value ? hana::eval(static_cast<T&&>(t)) 76 : hana::eval(static_cast<E&&>(e)); 77 } 78 }; 79 80 template <> 81 struct not_impl<Numeric> { 82 template <typename X> applyboost::hana::not_impl83 static constexpr auto apply(X x) 84 { return numeric(!x.value); } 85 }; 86 87 template <> 88 struct while_impl<Numeric> { 89 template <typename Pred, typename State, typename F> applyboost::hana::while_impl90 static constexpr auto apply(Pred pred, State state, F f) 91 -> decltype(true ? f(state) : state) 92 { 93 if (pred(state)) 94 return hana::while_(pred, f(state), f); 95 else 96 return state; 97 } 98 }; 99 100 ////////////////////////////////////////////////////////////////////////// 101 // Monoid 102 ////////////////////////////////////////////////////////////////////////// 103 template <> 104 struct plus_impl<Numeric, Numeric> { 105 template <typename X, typename Y> applyboost::hana::plus_impl106 static constexpr auto apply(X x, Y y) 107 { return numeric(x.value + y.value); } 108 }; 109 110 template <> 111 struct zero_impl<Numeric> { applyboost::hana::zero_impl112 static constexpr auto apply() 113 { return numeric(0); } 114 }; 115 116 ////////////////////////////////////////////////////////////////////////// 117 // Group 118 // 119 // Define either one to select which MCD is used: 120 // BOOST_HANA_TEST_GROUP_NEGATE_MCD 121 // BOOST_HANA_TEST_GROUP_MINUS_MCD 122 // 123 // If neither is defined, the MCD used is unspecified. 124 ////////////////////////////////////////////////////////////////////////// 125 #if defined(BOOST_HANA_TEST_GROUP_NEGATE_MCD) 126 template <> 127 struct negate_impl<Numeric> { 128 template <typename X> applyboost::hana::negate_impl129 static constexpr auto apply(X x) 130 { return numeric(-x.value); } 131 }; 132 #else 133 template <> 134 struct minus_impl<Numeric, Numeric> { 135 template <typename X, typename Y> applyboost::hana::minus_impl136 static constexpr auto apply(X x, Y y) 137 { return numeric(x.value - y.value); } 138 }; 139 #endif 140 141 ////////////////////////////////////////////////////////////////////////// 142 // Ring 143 ////////////////////////////////////////////////////////////////////////// 144 template <> 145 struct mult_impl<Numeric, Numeric> { 146 template <typename X, typename Y> applyboost::hana::mult_impl147 static constexpr auto apply(X x, Y y) 148 { return numeric(x.value * y.value); } 149 }; 150 151 template <> 152 struct one_impl<Numeric> { applyboost::hana::one_impl153 static constexpr auto apply() 154 { return numeric(1); } 155 }; 156 157 ////////////////////////////////////////////////////////////////////////// 158 // EuclideanRing 159 ////////////////////////////////////////////////////////////////////////// 160 template <> 161 struct div_impl<Numeric, Numeric> { 162 template <typename X, typename Y> applyboost::hana::div_impl163 static constexpr auto apply(X x, Y y) 164 { return numeric(x.value / y.value); } 165 }; 166 167 template <> 168 struct mod_impl<Numeric, Numeric> { 169 template <typename X, typename Y> applyboost::hana::mod_impl170 static constexpr auto apply(X x, Y y) 171 { return numeric(x.value % y.value); } 172 }; 173 }} // end namespace boost::hana 174 175 #endif //! TEST_SUPPORT_NUMERIC_HPP 176