From 5cbe322c82e4985f792be89a4ad8569f03f43511 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 30 Nov 2022 10:11:52 +0100 Subject: [PATCH] feat: `common_reference`, `common_dimension`, and `common_units` now take variadic list of arguments --- src/core/include/units/dimension.h | 29 ++++++++----- src/core/include/units/quantity.h | 12 +++--- src/core/include/units/reference.h | 12 +++--- src/core/include/units/unit.h | 69 ++++++++++++++++-------------- 4 files changed, 66 insertions(+), 56 deletions(-) diff --git a/src/core/include/units/dimension.h b/src/core/include/units/dimension.h index 9e292a9f..3c1a166b 100644 --- a/src/core/include/units/dimension.h +++ b/src/core/include/units/dimension.h @@ -328,6 +328,25 @@ template return std::derived_from || std::derived_from; } +[[nodiscard]] consteval auto common_dimension(Dimension auto d) { return d; } + +template +[[nodiscard]] consteval auto common_dimension(D1 d1, D2 d2) + requires(interconvertible(d1, d2)) +{ + if constexpr (std::derived_from) + return d1; + else + return d2; +} + +[[nodiscard]] consteval auto common_dimension(Dimension auto d1, Dimension auto d2, Dimension auto d3, + Dimension auto... rest) + requires requires { common_dimension(common_dimension(d1, d2), d3, rest...); } +{ + return common_dimension(common_dimension(d1, d2), d3, rest...); +} + /** * @brief Computes the value of a dimension raised to the `Num/Den` power * @@ -384,16 +403,6 @@ template requires requires { detail::get_dimension_for(U); } && (interconvertible(Dim, detail::get_dimension_for(U))) inline constexpr bool is_valid_unit_for_dimension = true; -template -[[nodiscard]] consteval auto common_dimension(D1 d1, D2 d2) - requires(interconvertible(d1, d2)) -{ - if constexpr (std::derived_from) - return d1; - else - return d2; -} - } // namespace detail // TODO consider adding the support for text output of the dimensional equation diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 6ce49556..7ecece09 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -481,7 +481,7 @@ template quantity_value_for_, typename Q1::rep, typename Q2::rep> [[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs) { - constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + constexpr auto ref = common_reference(Q1::reference, Q2::reference); using ret = quantity; return ret(ret(lhs).number() + ret(rhs).number()); } @@ -491,7 +491,7 @@ template quantity_value_for_, typename Q1::rep, typename Q2::rep> [[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs) { - constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + constexpr auto ref = common_reference(Q1::reference, Q2::reference); using ret = quantity; return ret(ret(lhs).number() - ret(rhs).number()); } @@ -528,7 +528,7 @@ template std::three_way_comparable_with [[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs) { - constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + constexpr auto ref = common_reference(Q1::reference, Q2::reference); return quantity_cast(lhs).number() <=> quantity_cast(rhs).number(); } @@ -537,7 +537,7 @@ template std::equality_comparable_with [[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs) { - constexpr auto ref = detail::common_reference(Q1::reference, Q2::reference); + constexpr auto ref = common_reference(Q1::reference, Q2::reference); return quantity_cast(lhs).number() == quantity_cast(rhs).number(); } @@ -548,13 +548,13 @@ namespace std { template requires requires { { - units::detail::common_reference(Q1::reference, Q2::reference) + units::common_reference(Q1::reference, Q2::reference) } -> units::Reference; typename common_type_t; } struct common_type { public: - using type = units::quantity>; }; diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index 334c335b..31cf14c9 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -107,20 +107,18 @@ template return interconvertible(R1::dimension, R2::dimension) && interconvertible(R1::unit, R2::unit); } -namespace detail { - -[[nodiscard]] consteval auto common_reference(Reference auto r1, Reference auto r2) +[[nodiscard]] consteval auto common_reference(Reference auto r1, Reference auto r2, Reference auto... rest) requires requires { { - common_dimension(r1.dimension, r2.dimension) + common_dimension(r1.dimension, r2.dimension, rest.dimension...) } -> Dimension; { - common_unit(r1.unit, r2.unit) + common_unit(r1.unit, r2.unit, rest.unit...) } -> Unit; } { - return reference{}; + return reference{}; } -} // namespace detail } // namespace units diff --git a/src/core/include/units/unit.h b/src/core/include/units/unit.h index 7a1f99b8..209c9b0c 100644 --- a/src/core/include/units/unit.h +++ b/src/core/include/units/unit.h @@ -586,16 +586,46 @@ template canonical_lhs.mag == canonical_rhs.mag; } - -// Convertible -template -[[nodiscard]] consteval bool interconvertible(Lhs lhs, Rhs rhs) +// Interconvertible +[[nodiscard]] consteval bool interconvertible(Unit auto u1, Unit auto u2) { - auto canonical_lhs = detail::get_canonical_unit(lhs); - auto canonical_rhs = detail::get_canonical_unit(rhs); + auto canonical_lhs = detail::get_canonical_unit(u1); + auto canonical_rhs = detail::get_canonical_unit(u2); return is_same_v; } +// Common unit +[[nodiscard]] consteval auto common_unit(Unit auto u) { return u; } + +template +[[nodiscard]] consteval auto common_unit(U1 u1, U2 u2) + requires(interconvertible(u1, u2)) +{ + if constexpr (U1{} == U2{}) { + if constexpr (std::derived_from) + return u1; + else + return u2; + } else { + constexpr auto canonical_lhs = detail::get_canonical_unit(U1{}); + constexpr auto canonical_rhs = detail::get_canonical_unit(U2{}); + + if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag)) + return u2; + else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag)) + return u1; + else { + constexpr auto cm = detail::common_magnitude(canonical_lhs.mag, canonical_rhs.mag); + return scaled_unit>{}; + } + } +} + +[[nodiscard]] consteval auto common_unit(Unit auto u1, Unit auto u2, Unit auto u3, Unit auto... rest) + requires requires { common_unit(common_unit(u1, u2), u3, rest...); } +{ + return common_unit(common_unit(u1, u2), u3, rest...); +} /** * @brief Computes the value of a unit raised to the `Num/Den` power @@ -814,31 +844,4 @@ template return buffer; } -namespace detail { - -template -[[nodiscard]] consteval auto common_unit(U1 u1, U2 u2) - requires(interconvertible(u1, u2)) -{ - if constexpr (U1{} == U2{}) { - if constexpr (std::derived_from) - return u1; - else - return u2; - } else { - constexpr auto canonical_lhs = detail::get_canonical_unit(U1{}); - constexpr auto canonical_rhs = detail::get_canonical_unit(U2{}); - - if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag)) - return u2; - else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag)) - return u1; - else { - constexpr auto cm = common_magnitude(canonical_lhs.mag, canonical_rhs.mag); - return scaled_unit>{}; - } - } -} - -} // namespace detail } // namespace units