Clean up pairwise_all() and strictly_increasing()

This commit is contained in:
Chip Hogg
2022-01-08 14:21:13 -05:00
parent 92b7a15d6f
commit 3063aebe5a
2 changed files with 40 additions and 36 deletions

View File

@@ -176,23 +176,31 @@ constexpr auto pi_to_the() { return magnitude<pi_power<Power>()>{}; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Magnitude concept implementation. // Magnitude concept implementation.
template<typename Predicate, typename... Ts> template<typename Predicate>
constexpr bool pairwise_all(const std::tuple<Ts...> &ts, const Predicate &pred) { struct pairwise_all {
Predicate predicate;
template<typename... Ts>
constexpr bool operator()(Ts&&... ts) const {
// Carefully handle different sizes, avoiding unsigned integer underflow. // Carefully handle different sizes, avoiding unsigned integer underflow.
constexpr auto num_comparisons = [](auto num_elements) { constexpr auto num_comparisons = [](auto num_elements) {
return (num_elements > 1) ? (num_elements - 1) : 0; return (num_elements > 1) ? (num_elements - 1) : 0;
}(sizeof...(Ts)); }(sizeof...(Ts));
// Compare zero or more pairs of neighbours as needed. // Compare zero or more pairs of neighbours as needed.
return [&ts, &pred]<std::size_t... Is>(std::integer_sequence<std::size_t, Is...>) { return [this]<std::size_t... Is>(std::tuple<Ts...> &&t, std::index_sequence<Is...>) {
return (pred(std::get<Is>(ts), std::get<Is + 1>(ts)) && ...); return (predicate(std::get<Is>(t), std::get<Is + 1>(t)) && ...);
}(std::make_index_sequence<num_comparisons>()); }(std::make_tuple(std::forward<Ts>(ts)...), std::make_index_sequence<num_comparisons>());
} }
};
template<typename T>
pairwise_all(T) -> pairwise_all<T>;
// Check whether a tuple of (possibly heterogeneously typed) values are strictly increasing. // Check whether a tuple of (possibly heterogeneously typed) values are strictly increasing.
template<typename... Ts> template<typename... Ts>
constexpr bool strictly_increasing(const std::tuple<Ts...> &ts) { constexpr bool strictly_increasing(Ts&&... ts) {
return pairwise_all(ts, std::less{}); return pairwise_all{std::less{}}(std::forward<Ts>(ts)...);
} }
namespace detail namespace detail

View File

@@ -30,23 +30,23 @@ namespace units::mag
TEST_CASE("strictly_increasing") TEST_CASE("strictly_increasing")
{ {
SECTION ("Empty tuple is sorted") SECTION ("Empty input is sorted")
{ {
CHECK(strictly_increasing(std::make_tuple())); CHECK(strictly_increasing());
} }
SECTION ("Single-element tuple is sorted") SECTION ("Single-element input is sorted")
{ {
CHECK(strictly_increasing(std::make_tuple(3))); CHECK(strictly_increasing(3));
CHECK(strictly_increasing(std::make_tuple(15.42))); CHECK(strictly_increasing(15.42));
CHECK(strictly_increasing(std::make_tuple('c'))); CHECK(strictly_increasing('c'));
} }
SECTION ("Multi-element tuples compare correctly") SECTION ("Multi-value inputs compare correctly")
{ {
CHECK(strictly_increasing(std::make_tuple(3, 3.14))); CHECK(strictly_increasing(3, 3.14));
CHECK(!strictly_increasing(std::make_tuple(3, 3.0))); CHECK(!strictly_increasing(3, 3.0));
CHECK(!strictly_increasing(std::make_tuple(4, 3.0))); CHECK(!strictly_increasing(4, 3.0));
} }
} }
@@ -94,9 +94,6 @@ TEST_CASE("strictly_increasing")
// } // }
// } // }
template<double x>
using double_v = 2 * x;
TEST_CASE("Multiplication works for magnitudes") TEST_CASE("Multiplication works for magnitudes")
{ {
SECTION("Reciprocals reduce to null magnitude") SECTION("Reciprocals reduce to null magnitude")
@@ -107,7 +104,6 @@ TEST_CASE("Multiplication works for magnitudes")
SECTION("Products work as expected") SECTION("Products work as expected")
{ {
CHECK(make_ratio<4, 5>() * make_ratio<4, 3>() == make_ratio<16, 15>()); CHECK(make_ratio<4, 5>() * make_ratio<4, 3>() == make_ratio<16, 15>());
CHECK(double_v<1.5> == 3.0);
} }
//SECTION("Products handle pi correctly") //SECTION("Products handle pi correctly")
@@ -205,23 +201,23 @@ TEST_CASE("pairwise_all evaluates all pairs")
{ {
SECTION("always true for empty tuples") SECTION("always true for empty tuples")
{ {
CHECK(pairwise_all(std::make_tuple(), [](auto, auto){ return true; })); CHECK(pairwise_all{[](auto, auto){ return true; }}());
CHECK(pairwise_all(std::make_tuple(), [](auto, auto){ return false; })); CHECK(pairwise_all{[](auto, auto){ return false; }}());
} }
SECTION("always true for single-element tuples") SECTION("always true for single-element tuples")
{ {
CHECK(pairwise_all(std::make_tuple(1), [](auto, auto){ return true; })); CHECK(pairwise_all{[](auto, auto){ return true; }}(1));
CHECK(pairwise_all(std::make_tuple(3.14), [](auto, auto){ return false; })); CHECK(pairwise_all{[](auto, auto){ return false; }}(3.14));
CHECK(pairwise_all(std::make_tuple('x'), [](auto, auto){ return true; })); CHECK(pairwise_all{[](auto, auto){ return true; }}('x'));
} }
SECTION("true for longer tuples iff true for all neighbouring pairs") 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::less{}}(1, 1.5));
CHECK(pairwise_all(std::make_tuple(1, 1.5, 2), std::less{})); CHECK(pairwise_all{std::less{}}(1, 1.5, 2));
CHECK(!pairwise_all(std::make_tuple(1, 2.0, 2), std::less{})); CHECK(!pairwise_all{std::less{}}(1, 2.0, 2));
CHECK(!pairwise_all(std::make_tuple(1, 2.5, 2), std::less{})); CHECK(!pairwise_all{std::less{}}(1, 2.5, 2));
} }
} }