diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index 9f6ab618..38ded5e1 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -29,14 +29,24 @@ namespace units::mag { +template +struct base_power { + using base = base_; + static inline constexpr ratio power = power_; +}; + +template +struct is_base_power; +template +inline constexpr bool is_base_power_v = is_base_power::value; +template +concept BasePower = is_base_power_v; + // A `magnitude` represents a positive real number in a format which optimizes taking products and // rational powers. -template +template struct magnitude; -template -struct base_power; - template struct is_magnitude; template @@ -81,14 +91,25 @@ struct pi { // Implementation details below. //////////////////////////////////////////////////////////////////////////////////////////////////// -template +template struct magnitude { bool operator==(magnitude) const { return true; } - template - bool operator==(magnitude) const { return false; } + template + bool operator==(magnitude) const { return false; } }; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BasePower concept implementation. + +template +struct is_base_power: std::false_type {}; + +template + requires requires() { B::value; } +struct is_base_power> + : std::bool_constant<(B::value > 0)> {}; + //////////////////////////////////////////////////////////////////////////////////////////////////// // Magnitude concept implementation. @@ -109,18 +130,21 @@ constexpr bool strictly_increasing(const std::tuple &ts) { }(std::make_index_sequence()); } -template -struct is_magnitude...>> +template +struct is_magnitude> : std::bool_constant<( - strictly_increasing(std::make_tuple(bases::value...)) - && ((powers.num != 0) && ...))> {}; + strictly_increasing(std::make_tuple(Bs::base::value...)) + && ((Bs::power.num != 0) && ...))> {}; //////////////////////////////////////////////////////////////////////////////////////////////////// // Inverse implementation. -template -struct inverse...>> { - using type = magnitude...>; +template +using base_power_inverse = base_power; + +template +struct inverse> { + using type = magnitude...>; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -129,13 +153,13 @@ struct inverse...>> { // Convenience utility to prepend a base_power to a magnitude. // // Assumes that the prepended power has a smaller base than every base power in the magnitude. -template +template struct prepend_base; -template -using prepend_base_t = typename prepend_base::type; -template -struct prepend_base> { - using type = magnitude; +template +using prepend_base_t = typename prepend_base::type; +template +struct prepend_base> { + using type = magnitude; }; // Nullary case. @@ -151,46 +175,36 @@ template struct product> { using type = M; }; // Binary case, where left argument is null magnitude, and right is non-null. -template -struct product, magnitude> { using type = magnitude; }; +template +struct product, magnitude> { using type = magnitude; }; -// Binary case, with distinct heads. -template < - typename base1, - ratio pow1, - typename... tail1, - typename base2, - ratio pow2, - typename... tail2> -struct product, tail1...>, - magnitude, tail2...>> +// Binary case, with distinct and non-null heads. +template +struct product, magnitude> { - using mag1 = magnitude, tail1...>; - using mag2 = magnitude, tail2...>; - using type = std::conditional_t< - (base1::value < base2::value), - prepend_base_t, product_t, mag2>>, - prepend_base_t, product_t>>>; + (Head1::base::value < Head2::base::value), + prepend_base_t, magnitude>>, + prepend_base_t, magnitude>>>; }; // Binary case, same head. -template -struct product, tail1...>, - magnitude, tail2...>> +template +struct product, Tail1...>, + magnitude, Tail2...>> { - using tail_product = product_t, magnitude>; + using tail_product = product_t, magnitude>; using type = std::conditional_t< - ((pow1 + pow2).num == 0), + ((Pow1 + Pow2).num == 0), tail_product, - prepend_base_t, tail_product>>; + prepend_base_t, tail_product>>; }; // N-ary case (N > 2). -template -struct product +template +struct product { - using type = product_t, tail...>; + using type = product_t, Tail...>; }; } // namespace units::mag diff --git a/test/unit_test/runtime/magnitude_test.cpp b/test/unit_test/runtime/magnitude_test.cpp index 8553fd73..a3561561 100644 --- a/test/unit_test/runtime/magnitude_test.cpp +++ b/test/unit_test/runtime/magnitude_test.cpp @@ -115,6 +115,43 @@ TEST_CASE("Magnitude supports products") } } +TEST_CASE("is_base_power detects well formed base powers") +{ + SECTION ("Arbitrary other types are not base powers") + { + CHECK(!is_base_power_v); + CHECK(!is_base_power_v); + CHECK(!is_base_power_v>>); + } + + SECTION ("int_base_power forms base powers") + { + CHECK(is_base_power_v>); + CHECK(is_base_power_v>); + CHECK(is_base_power_v>); + } + + SECTION ("base_power forms base powers with pi and ratio") + { + CHECK(is_base_power_v>); + CHECK(is_base_power_v>); + CHECK(is_base_power_v>); + } + + SECTION ("base_power disqualified by negative or zero base") + { + CHECK(!is_base_power_v>); + CHECK(!is_base_power_v>); + } + + SECTION ("base_power disqualified by base without value") + { + CHECK(!is_base_power_v>); + CHECK(!is_base_power_v>); + CHECK(!is_base_power_v>); + } +} + TEST_CASE("is_magnitude detects well formed magnitudes") { SECTION ("Arbitrary other types are not magnitudes")