From 9322aa25e471721f22d8ea5f8170a94b80f15a0f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 16 May 2023 16:41:51 +0200 Subject: [PATCH] Revert "feat: runtime conversion factors between units support added" This reverts commit cc8a088013f995fed4e1dd29c5290694a68ac797. --- example/currency.cpp | 27 ++++++------ src/core/include/mp_units/bits/sudo_cast.h | 51 +++++++++------------- src/core/include/mp_units/quantity.h | 9 +++- src/core/include/mp_units/unit.h | 14 +----- 4 files changed, 42 insertions(+), 59 deletions(-) diff --git a/example/currency.cpp b/example/currency.cpp index 3d9221fb..c1527b6e 100644 --- a/example/currency.cpp +++ b/example/currency.cpp @@ -39,6 +39,8 @@ inline constexpr struct great_british_pound : named_unit<"GBP", kind_of> {} japanese_jen; // clang-format on +static_assert(!std::equality_comparable_with, quantity>); + #if 0 // if you have only a few currencies to handle @@ -52,11 +54,6 @@ template #else -template - requires(get_quantity_spec(From) == currency && get_quantity_spec(To) == currency) -inline constexpr is_unit_convertible_result mp_units::is_unit_convertible = - is_unit_convertible_result::non_integral_factor; - [[nodiscard]] std::string_view to_string_view(Unit auto u) { return u.symbol.ascii().c_str(); } template @@ -72,21 +69,23 @@ template #endif -template -[[nodiscard]] Rep scale_quantity_number(Rep v, From from, To to) - requires(get_quantity_spec(from) == currency && get_quantity_spec(to) == currency) +template auto To, ReferenceOf auto From, typename Rep> +quantity exchange_to(quantity q) { - return static_cast(exchange_rate() * v); + return static_cast(exchange_rate() * q.number()) * To; } -static_assert(!std::equality_comparable_with, quantity>); +template auto To, ReferenceOf auto From, auto PO, typename Rep> +quantity_point exchange_to(quantity_point q) +{ + return static_cast(exchange_rate() * q.absolute().number()) * To; +} int main() { - auto price_usd = quantity_point{100. * us_dollar}; - auto price_euro = quantity_point{price_usd[euro]}; + auto price_usd = quantity_point{100 * us_dollar}; + auto price_euro = quantity_point{exchange_to(price_usd)}; std::cout << price_usd.absolute() << " -> " << price_euro.absolute() << "\n"; // std::cout << price_usd.absolute() + price_euro.absolute() << "\n"; // does not compile - // std::cout << price_euro.absolute() + price_usd.absolute() << "\n"; // does not compile -} +} \ No newline at end of file diff --git a/src/core/include/mp_units/bits/sudo_cast.h b/src/core/include/mp_units/bits/sudo_cast.h index 9825c815..1d4b9bf1 100644 --- a/src/core/include/mp_units/bits/sudo_cast.h +++ b/src/core/include/mp_units/bits/sudo_cast.h @@ -35,32 +35,6 @@ class quantity; namespace detail { -// The default implementation for the number scaling customization point -template -[[nodiscard]] constexpr auto scale_quantity_number(Rep v, From from, To to) - requires(have_same_canonical_reference_unit(from, to)) -{ - using multiplier_type = decltype([] { - // widen the type to prevent overflows - using wider_type = decltype(Rep{} * std::intmax_t{}); - // check if `wider_type` supports scaling operations - if constexpr (requires(wider_type v) { v* v / v; }) - // if the `wider_type` can handle scaling operations then use it to improve accuracy - return wider_type{}; - else - // needed for example for linear algebra where `op/` on matrix types is not available - return std::intmax_t{}; - }()); - - constexpr Magnitude auto c_mag = detail::get_canonical_unit(from).mag / detail::get_canonical_unit(to).mag; - constexpr Magnitude auto num = numerator(c_mag); - constexpr Magnitude auto den = denominator(c_mag); - constexpr Magnitude auto irr = c_mag * (den / num); - - constexpr auto val = [](Magnitude auto m) { return get_value(m); }; - return v * val(num) / val(den) * val(irr); -} - /** * @brief Explicit cast of entire quantity * @@ -71,7 +45,7 @@ template template requires(castable(get_quantity_spec(R), To::quantity_spec)) && ((get_unit(R) == To::unit && std::constructible_from) || - (get_unit(R) != To::unit && convertible(get_unit(R), To::unit))) // && scalable_with_)) + (get_unit(R) != To::unit)) // && scalable_with_)) // TODO how to constrain the second part here? [[nodiscard]] constexpr Quantity auto sudo_cast(const quantity& q) { @@ -92,11 +66,26 @@ template else return Rep{}; }()); + using multiplier_type = decltype([] { + // widen the type to prevent overflows + using wider_type = decltype(rep_type{} * std::intmax_t{}); + // check if `wider_type` supports scaling operations + if constexpr (requires(wider_type v) { v* v / v; }) + // if the `wider_type` can handle scaling operations then use it to improve accuracy + return wider_type{}; + else + // needed for example for linear algebra where `op/` on matrix types is not available + return std::intmax_t{}; + }()); - // `scale_quantity_number` is a customization point - // Will be found only via ADL (if provided) for user-defined units - return static_cast( - scale_quantity_number(static_cast(q.number()), get_unit(R), To::unit)) * + constexpr Magnitude auto c_mag = + detail::get_canonical_unit(get_unit(R)).mag / detail::get_canonical_unit(To::unit).mag; + constexpr Magnitude auto num = numerator(c_mag); + constexpr Magnitude auto den = denominator(c_mag); + constexpr Magnitude auto irr = c_mag * (den / num); + + constexpr auto val = [](Magnitude auto m) { return get_value(m); }; + return static_cast(static_cast(q.number()) * val(num) / val(den) * val(irr)) * To::reference; } } diff --git a/src/core/include/mp_units/quantity.h b/src/core/include/mp_units/quantity.h index 36bdcbe8..4862870e 100644 --- a/src/core/include/mp_units/quantity.h +++ b/src/core/include/mp_units/quantity.h @@ -50,13 +50,18 @@ template concept RepSafeConstructibleFrom = // exposition only std::constructible_from && (treat_as_floating_point || !treat_as_floating_point); +// UFrom ratio is an exact multiple of UTo +template +concept Harmonic = // exposition only + Unit && Unit && + is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag); + template concept QuantityConvertibleTo = // exposition only Quantity && Quantity && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) && convertible(QFrom::unit, QTo::unit) && requires(QFrom q) { detail::sudo_cast(q); } && (treat_as_floating_point || - (!treat_as_floating_point && - is_unit_convertible == is_unit_convertible_result::integral_factor)); + (!treat_as_floating_point && Harmonic)); template concept InvokeResultOf = std::regular_invocable && RepresentationOf, Ch>; diff --git a/src/core/include/mp_units/unit.h b/src/core/include/mp_units/unit.h index 50c4583e..da4d324a 100644 --- a/src/core/include/mp_units/unit.h +++ b/src/core/include/mp_units/unit.h @@ -594,21 +594,11 @@ inline constexpr struct percent : named_unit<"%", mag * one> {} p inline constexpr struct per_mille : named_unit * one> {} per_mille; // clang-format on -// is_unit_convertible customization point -enum class is_unit_convertible_result { no, integral_factor, non_integral_factor }; -template -inline constexpr is_unit_convertible_result is_unit_convertible = - detail::have_same_canonical_reference_unit(From, To) - ? (is_integral(detail::get_canonical_unit(From).mag / detail::get_canonical_unit(To).mag) - ? is_unit_convertible_result::integral_factor - : is_unit_convertible_result::non_integral_factor) - : is_unit_convertible_result::no; - -// convertible +// convertible_to [[nodiscard]] consteval bool convertible(Unit auto from, Unit auto to) { - return is_unit_convertible != is_unit_convertible_result::no; + return detail::have_same_canonical_reference_unit(from, to); } // Common unit