From 35e3f69ad22c06bb8e6e7081946c61d8a82b0194 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 31 Jan 2018 19:33:42 +1100 Subject: [PATCH] maths, view: rationalise equal,almost_equal,== views should not do elementwise comparisons for equality operators. they are pairs of iterators and are only equal if their iterators are equal. instead, use `equal` for elementwise equality. we update the name of exactly_equal to perform this operation too. --- json/tree.cpp | 4 +- maths.hpp | 114 +++++++++++++++++------------------------ matrix.cpp | 2 +- test/float.cpp | 4 +- test/introspection.cpp | 4 +- test/iterator.cpp | 2 +- test/json_types.cpp | 4 +- test/point.cpp | 8 +-- test/string.cpp | 8 ++- view.hpp | 19 +++++-- 10 files changed, 78 insertions(+), 91 deletions(-) diff --git a/json/tree.cpp b/json/tree.cpp index 4a49ccd2..fe4b8312 100644 --- a/json/tree.cpp +++ b/json/tree.cpp @@ -909,7 +909,7 @@ json::tree::number::sint (void) const return m_value.s; case REAL: - if (!::util::exactly_equal (real_t (sint_t (m_value.r)), m_value.r)) + if (!::util::equal (real_t (sint_t (m_value.r)), m_value.r)) throw type_error ("number is not a sint"); return sint_t (m_value.r); @@ -932,7 +932,7 @@ json::tree::number::uint (void) const return m_value.u; case REAL: - if (!::util::exactly_equal (real_t (uint_t (m_value.r)), m_value.r)) + if (!::util::equal (real_t (uint_t (m_value.r)), m_value.r)) throw type_error ("number is not a uint"); return uint_t (m_value.r); diff --git a/maths.hpp b/maths.hpp index 8a318736..cd030e00 100644 --- a/maths.hpp +++ b/maths.hpp @@ -43,67 +43,6 @@ /////////////////////////////////////////////////////////////////////////////// namespace util { - /////////////////////////////////////////////////////////////////////////// - // Comparisons - inline bool - almost_equal (const float &a, const float &b) - { - return ieee_single::almost_equal (a, b); - } - - - //----------------------------------------------------------------------------- - inline bool - almost_equal (const double &a, const double &b) - { - return ieee_double::almost_equal (a, b); - } - - - //----------------------------------------------------------------------------- - template - inline - typename std::enable_if_t< - std::is_floating_point::value && - std::is_floating_point::value && - !std::is_same::value , - bool - > - almost_equal (const A &a, const B &b) - { - using common_t = std::common_type_t; - return almost_equal (static_cast (a), - static_cast (b)); - } - - - //----------------------------------------------------------------------------- - template - inline - typename std::enable_if_t< - std::is_integral_v && - std::is_integral_v && - std::is_signed::value == std::is_signed::value, - bool - > - almost_equal (const A &a, const B &b) { - using common_t = std::common_type_t; - return static_cast (a) == static_cast (b); - } - - - //----------------------------------------------------------------------------- - template - constexpr inline - typename std::enable_if< - !std::is_arithmetic::value || - !std::is_arithmetic::value, - bool - >::type - almost_equal (const Ta &a, const Tb &b) - { return a == b; } - - //----------------------------------------------------------------------------- // Useful for explictly ignore equality warnings #pragma GCC diagnostic push @@ -115,7 +54,7 @@ namespace util { std::is_arithmetic::value, bool > - exactly_equal (const Ta &a, const Tb &b) + equal (const Ta &a, const Tb &b) { return a == b; } @@ -128,13 +67,50 @@ namespace util { !std::is_arithmetic::value, bool > - exactly_equal (const Ta &a, const Tb &b) + equal (const Ta &a, const Tb &b) { return a == b; } #pragma GCC diagnostic pop + /////////////////////////////////////////////////////////////////////////// + // Comparisons + inline bool + almost_equal (float a, float b) + { + return ieee_single::almost_equal (a, b); + } + + + //----------------------------------------------------------------------------- + inline bool + almost_equal (double a, double b) + { + return ieee_double::almost_equal (a, b); + } + + + //----------------------------------------------------------------------------- + template + constexpr auto + almost_equal (const ValueA &a, const ValueB &b) + { + if constexpr (std::is_floating_point_v && std::is_floating_point_v) { + using common_t = std::common_type_t; + return almost_equal (common_t {a}, common_t{b}); + } else if constexpr (std::is_integral_v && + std::is_integral_v && + std::is_signed_v == std::is_signed_v) + { + using common_t = std::common_type_t; + return static_cast (a) == static_cast (b); + } else { + return equal (a, b); + } + } + + //----------------------------------------------------------------------------- template constexpr @@ -146,12 +122,16 @@ namespace util { return t == 0; } + + //------------------------------------------------------------------------- template std::enable_if_t< !std::is_integral::value, bool > almost_zero (T a) - { return almost_equal (a, T{0}); } + { + return almost_equal (a, T{0}); + } //------------------------------------------------------------------------- @@ -162,7 +142,7 @@ namespace util { > exactly_zero (T t) { - return exactly_equal (t, T{0}); + return equal (t, T{0}); } @@ -173,7 +153,7 @@ namespace util { > exactly_zero (T t) { - return exactly_equal (t, T{0}); + return equal (t, T{0}); } @@ -337,7 +317,7 @@ namespace util { is_integer (T t) { T i = 0; - return exactly_equal (std::modf (t, &i), T{0}); + return equal (std::modf (t, &i), T{0}); } diff --git a/matrix.cpp b/matrix.cpp index f25fb070..8af742d4 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -126,7 +126,7 @@ matrix::is_affine (void) const if (!exactly_zero (values[Rows-1][i])) return false; - return exactly_equal (values[Rows-1][Rows-1], T{1}); + return equal (values[Rows-1][Rows-1], T{1}); } diff --git a/test/float.cpp b/test/float.cpp index 0241baf3..2be6c906 100644 --- a/test/float.cpp +++ b/test/float.cpp @@ -38,7 +38,7 @@ test_double (util::TAP::logger &tap) util::ieee_double val; val.set_bits (tests[i].bits); - success = success && util::exactly_equal (val, tests[i].floating); + success = success && util::equal (val, tests[i].floating); } tap.expect (success, "double precision bitwise equality"); @@ -74,7 +74,7 @@ test_single (util::TAP::logger &tap) util::ieee_single val; val.set_bits (tests[i].bits); - success = success && util::exactly_equal (val, tests[i].floating); + success = success && util::equal (val, tests[i].floating); } tap.expect (success, "single precision bitwise equality"); diff --git a/test/introspection.cpp b/test/introspection.cpp index 72a19efb..570ad6eb 100644 --- a/test/introspection.cpp +++ b/test/introspection.cpp @@ -46,8 +46,8 @@ int main () foo d_foo { 7, 42.0 }; auto f_tuple = util::as_tuple (d_foo); - tap.expect (util::exactly_equal (d_foo.a, std::get<0> (f_tuple)) && - util::exactly_equal (d_foo.b, std::get<1> (f_tuple)), + tap.expect (util::equal (d_foo.a, std::get<0> (f_tuple)) && + util::equal (d_foo.b, std::get<1> (f_tuple)), "dynamic member access after conversion to tuple"); } diff --git a/test/iterator.cpp b/test/iterator.cpp index fcf7a4bb..7dda5d39 100644 --- a/test/iterator.cpp +++ b/test/iterator.cpp @@ -20,7 +20,7 @@ main (int, char**) for (const auto &[i, v, a, c]: util::izip (v_int, a_float, c_char)) { success = success && v_int[i] == v && - util::exactly_equal (a_float[i], a) && + util::equal (a_float[i], a) && c_char[i] == c; } diff --git a/test/json_types.cpp b/test/json_types.cpp index bc9173e5..c18bb2fa 100644 --- a/test/json_types.cpp +++ b/test/json_types.cpp @@ -53,7 +53,7 @@ main (void) tap.expect (!ref["integer"].is_object (), "integer not is_object"); tap.expect (!ref["integer"].is_string (), "integer not is_string"); tap.expect ( - util::exactly_equal ( + util::equal ( (unsigned)ref["integer"].as_number ().as_uint (), 1u ), @@ -101,7 +101,7 @@ main (void) tap.expect (!ref["double"].is_object (), "double not is_object"); tap.expect (!ref["double"].is_string (), "double not is_string"); tap.expect ( - util::exactly_equal ( + util::equal ( ref["double"].as_number ().as (), 3.14 ), diff --git a/test/point.cpp b/test/point.cpp index d63559df..e882de9f 100644 --- a/test/point.cpp +++ b/test/point.cpp @@ -69,10 +69,10 @@ main (void) const point4f q = p.homog<4> (); tap.expect ( - almost_equal (q.x, 3.f) && - almost_equal (q.y, 4.f) && - almost_equal (q.z, 0.f) && - almost_equal (q.w, 1.f), + equal (q.x, 3.f) && + equal (q.y, 4.f) && + equal (q.z, 0.f) && + equal (q.w, 1.f), "homogenous redim" ); diff --git a/test/string.cpp b/test/string.cpp index 3f090678..ffc91186 100644 --- a/test/string.cpp +++ b/test/string.cpp @@ -29,11 +29,9 @@ main (int, char**) { "", "trailing empty" } }; - for (const auto tok: util::tokeniser (csv.c_str (), ',')) - std::cout << '"' << tok << "\"\n"; - - for (const auto &[tok, expected]: util::zip (util::tokeniser (csv.c_str (), ','), TESTS)) - tap.expect_eq (tok, expected.value, "%s", expected.message); + util::view src { csv.c_str (), csv.size () }; + for (const auto &[tok, expected]: util::zip (util::tokeniser (src, ','), TESTS)) + tap.expect (equal (tok, expected.value), "%s", expected.message); return tap.status (); } \ No newline at end of file diff --git a/view.hpp b/view.hpp index 85c1fb59..7939076c 100644 --- a/view.hpp +++ b/view.hpp @@ -589,7 +589,7 @@ namespace util { typename BeginB, typename EndB > constexpr bool - operator== (const view &a, const view &b) + equal (const view &a, const view &b) { return a.size () == b.size () && std::equal (std::begin (a), std::end (a), std::begin (b)); @@ -608,9 +608,9 @@ namespace util { > > constexpr bool - operator== (const view &a, const ValueT &b) + equal (const view &a, const ValueT &b) { - return a == make_view (b); + return equal (a, make_view (b)); } @@ -628,15 +628,24 @@ namespace util { > > constexpr bool - operator== (const ValueT &a, const view &b) + equal (const ValueT &a, const view &b) { - return b == a; + return equal (b, a); } /////////////////////////////////////////////////////////////////////////// template constexpr bool + operator== (const view &a, const view &b) + { + return a.begin () == b.begin () && a.end () == b.end (); + } + + + //------------------------------------------------------------------------- + template + constexpr bool operator!= (const view &a, const view &b) { return !(a == b);