diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index 25931150..0cbfd4d5 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -186,20 +186,25 @@ struct is_base_power> template struct is_magnitude: std::false_type {}; -// Check whether a tuple of (possibly heterogeneously typed) values are strictly increasing. -template -constexpr bool strictly_increasing(const std::tuple &ts) { +template +constexpr bool pairwise_all(const std::tuple &ts, const Predicate &pred) { // Carefully handle different sizes, avoiding unsigned integer underflow. constexpr auto num_comparisons = [](auto num_elements) { return (num_elements > 1) ? (num_elements - 1) : 0; }(sizeof...(Ts)); // Compare zero or more pairs of neighbours as needed. - return [&ts](std::integer_sequence) { - return ((std::get(ts) < std::get(ts)) && ...); + return [&ts, &pred](std::integer_sequence) { + return (pred(std::get(ts), std::get(ts)) && ...); }(std::make_index_sequence()); } +// Check whether a tuple of (possibly heterogeneously typed) values are strictly increasing. +template +constexpr bool strictly_increasing(const std::tuple &ts) { + return pairwise_all(ts, std::less{}); +} + // To be a valid magnitude, one must be a magnitude<...> of BasePowers with nonzero exponents, sorted by increasing base // value. template diff --git a/test/unit_test/runtime/magnitude_test.cpp b/test/unit_test/runtime/magnitude_test.cpp index 61115a4f..475d97f7 100644 --- a/test/unit_test/runtime/magnitude_test.cpp +++ b/test/unit_test/runtime/magnitude_test.cpp @@ -374,6 +374,30 @@ TEST_CASE("is_prime detects primes") } } +TEST_CASE("pairwise_all evaluates all pairs") +{ + SECTION("always true for empty tuples") + { + CHECK(pairwise_all(std::make_tuple(), [](auto a, auto b){ return true; })); + CHECK(pairwise_all(std::make_tuple(), [](auto a, auto b){ return false; })); + } + + SECTION("always true for single-element tuples") + { + CHECK(pairwise_all(std::make_tuple(1), [](auto a, auto b){ return true; })); + CHECK(pairwise_all(std::make_tuple(3.14), [](auto a, auto b){ return false; })); + CHECK(pairwise_all(std::make_tuple('x'), [](auto a, auto b){ return true; })); + } + + SECTION("true for longer tuples iff true for all neighbouring pairs") + { + CHECK(pairwise_all(std::make_tuple(1, 1.5), std::less{})); + CHECK(pairwise_all(std::make_tuple(1, 1.5, 2), std::less{})); + CHECK(!pairwise_all(std::make_tuple(1, 2.0, 2), std::less{})); + CHECK(!pairwise_all(std::make_tuple(1, 2.5, 2), std::less{})); + } +} + } // namespace detail } // namespace units::mag