diff --git a/src/core/include/mp-units/ext/prime.h b/src/core/include/mp-units/ext/prime.h index 31d4f2cc..4d253cf2 100644 --- a/src/core/include/mp-units/ext/prime.h +++ b/src/core/include/mp-units/ext/prime.h @@ -157,22 +157,30 @@ struct wheel_factorizer { static constexpr auto coprimes_in_first_wheel = coprimes_up_to(wheel_size, basis); - [[nodiscard]] static consteval std::uintmax_t find_first_factor(std::uintmax_t n) + template + [[nodiscard]] static consteval auto find_first_factor() { - if (const auto k = detail::get_first_of(basis, [&](auto p) { return first_factor_maybe(n, p); })) return *k; + constexpr std::uintmax_t res = [] { + if (const auto k = detail::get_first_of(basis, [&](auto p) { return first_factor_maybe(N, p); })) return *k; - if (const auto k = detail::get_first_of(std::next(begin(coprimes_in_first_wheel)), end(coprimes_in_first_wheel), - [&](auto p) { return first_factor_maybe(n, p); })) - return *k; - - for (std::size_t wheel = wheel_size; wheel < n; wheel += wheel_size) - if (const auto k = - detail::get_first_of(coprimes_in_first_wheel, [&](auto p) { return first_factor_maybe(n, wheel + p); })) + if (const auto k = detail::get_first_of(std::next(begin(coprimes_in_first_wheel)), end(coprimes_in_first_wheel), + [&](auto p) { return first_factor_maybe(N, p); })) return *k; - return n; + + for (std::size_t wheel = wheel_size; wheel < N; wheel += wheel_size) + if (const auto k = + detail::get_first_of(coprimes_in_first_wheel, [&](auto p) { return first_factor_maybe(N, wheel + p); })) + return *k; + return N; + }(); + return std::integral_constant{}; } - [[nodiscard]] static consteval bool is_prime(std::size_t n) { return (n > 1) && find_first_factor(n) == n; } + template + [[nodiscard]] static consteval auto is_prime() + { + return std::bool_constant<(N > 1 && decltype(find_first_factor())::value == N)>{}; + } }; } // namespace mp_units::detail diff --git a/src/core/include/mp-units/framework/magnitude.h b/src/core/include/mp-units/framework/magnitude.h index 2b55017f..814b2e8c 100644 --- a/src/core/include/mp-units/framework/magnitude.h +++ b/src/core/include/mp-units/framework/magnitude.h @@ -476,16 +476,16 @@ namespace detail { template // requires detail::is_element_pack_valid struct magnitude { - [[nodiscard]] friend consteval bool is_integral(const magnitude&) + [[nodiscard]] friend consteval auto is_integral(const magnitude&) { using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec - return (is_integral(Ms) && ...); + return std::bool_constant<(is_integral(Ms) && ...)>{}; } - [[nodiscard]] friend consteval bool is_rational(const magnitude&) + [[nodiscard]] friend consteval auto is_rational(const magnitude&) { using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec - return (is_rational(Ms) && ...); + return std::bool_constant<(is_rational(Ms) && ...)>{}; } }; @@ -508,22 +508,20 @@ inline constexpr bool is_specialization_of_magnitude> = true; } // namespace detail +MP_UNITS_EXPORT_BEGIN /** * @brief The value of a Magnitude in a desired type T. */ template - requires(is_integral(magnitude{})) || treat_as_floating_point -constexpr T get_value(const magnitude&) + requires(decltype(is_integral(magnitude{}))::value) || treat_as_floating_point +constexpr auto get_value(const magnitude&) { // Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow. constexpr auto result = detail::checked_static_cast((detail::compute_base_power(Ms) * ... * T{1})); - - return result; + return std::integral_constant{}; } -MP_UNITS_EXPORT_BEGIN - /** * @brief A convenient Magnitude constant for pi, which we can manipulate like a regular number. */ @@ -558,21 +556,21 @@ template if constexpr (Num == 0) { return magnitude<>{}; } else { - return magnitude< - detail::power_v_or_T()...>{}; + return decltype(magnitude()...>{}){}; } } template [[nodiscard]] consteval auto sqrt(magnitude m) { - return pow<1, 2>(m); + return decltype(pow<1, 2>(m)){}; } template [[nodiscard]] consteval auto cbrt(magnitude m) { - return pow<1, 3>(m); + return decltype(pow<1, 3>(m)){}; } MP_UNITS_EXPORT_END @@ -615,13 +613,13 @@ template // Shortcut for the "pure prepend" case, which makes it easier to implement some of the other cases. return magnitude{}; } else { - return magnitude

{} * (magnitude{} * magnitude{}); + return decltype(magnitude

{} * (decltype(magnitude{} * magnitude{}){})){}; } } else if constexpr (less(H2, H1)) { - return magnitude

{} * (magnitude{} * magnitude{}); + return decltype(magnitude

{} * (decltype(magnitude{} * magnitude{}){})){}; } else { if constexpr (is_same_v) { - constexpr auto partial_product = magnitude{} * magnitude{}; + constexpr auto partial_product = decltype(magnitude{} * magnitude{}){}; if constexpr (get_exponent(H1) + get_exponent(H2) == 0) { return partial_product; } else { @@ -631,13 +629,13 @@ template if constexpr (get_exponent(new_head) == 0) { return partial_product; } else { - return magnitude{} * partial_product; + return decltype(magnitude{} * partial_product){}; } } } else if constexpr (is_named_magnitude) { - return magnitude

{} * (magnitude{} * magnitude{}); + return decltype(magnitude

{} * decltype((magnitude{} * magnitude{})){}){}; } else { - return magnitude

{} * (magnitude{} * magnitude{}); + return decltype(magnitude

{} * decltype((magnitude{} * magnitude{})){}){}; } } } @@ -645,7 +643,7 @@ template //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Magnitude quotient implementation. -[[nodiscard]] consteval auto operator/(Magnitude auto l, Magnitude auto r) { return l * pow<-1>(r); } +[[nodiscard]] consteval auto operator/(Magnitude auto l, Magnitude auto r) { return decltype(l * pow<-1>(r)){}; } MP_UNITS_EXPORT_END @@ -672,20 +670,10 @@ template template [[nodiscard]] consteval auto numerator(magnitude) { - return (detail::integer_part(magnitude{}) * ... * magnitude<>{}); + return decltype((decltype(detail::integer_part(magnitude{})){} * ... * magnitude<>{})){}; } -[[nodiscard]] consteval auto denominator(Magnitude auto m) { return numerator(pow<-1>(m)); } - -// TODO This probably should not be exported but is used in chrono.h -MP_UNITS_EXPORT constexpr ratio as_ratio(Magnitude auto m) - requires(is_rational(decltype(m){})) -{ - return ratio{ - get_value(numerator(m)), - get_value(denominator(m)), - }; -} +[[nodiscard]] consteval auto denominator(Magnitude auto m) { return decltype(numerator(pow<-1>(m))){}; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Common Magnitude. @@ -725,11 +713,11 @@ template [[nodiscard]] consteval auto common_magnitude(magnitude<>, magnitude<>) { return magnitude<>{}; } [[nodiscard]] consteval auto common_magnitude(magnitude<>, Magnitude auto m) { - return detail::remove_positive_powers(m); + return decltype(detail::remove_positive_powers(m)){}; } [[nodiscard]] consteval auto common_magnitude(Magnitude auto m, magnitude<>) { - return detail::remove_positive_powers(m); + return decltype(detail::remove_positive_powers(m)){}; } // Recursive case for the common Magnitude of any two non-identity Magnitudes. @@ -740,17 +728,19 @@ template if constexpr (detail::get_base_value(H1) < detail::get_base_value(H2)) { // When H1 has the smaller base, prepend to result from recursion. - return remove_positive_power(magnitude

{}) * common_magnitude(magnitude{}, magnitude{}); + return decltype(decltype(remove_positive_power(magnitude

{})){} * + decltype(common_magnitude(magnitude{}, magnitude{})){}){}; } else if constexpr (detail::get_base_value(H2) < detail::get_base_value(H1)) { // When H2 has the smaller base, prepend to result from recursion. - return remove_positive_power(magnitude

{}) * common_magnitude(magnitude{}, magnitude{}); + return decltype(decltype(remove_positive_power(magnitude

{})){} * + decltype(common_magnitude(magnitude{}, magnitude{})){}){}; } else { // When the bases are equal, pick whichever has the lower power. - constexpr auto common_tail = common_magnitude(magnitude{}, magnitude{}); + constexpr auto common_tail = decltype(common_magnitude(magnitude{}, magnitude{})){}; if constexpr (detail::get_exponent(H1) < detail::get_exponent(H2)) { - return magnitude

{} * common_tail; + return decltype(magnitude

{} * common_tail){}; } else { - return magnitude

{} * common_tail; + return decltype(magnitude

{} * common_tail){}; } } } @@ -758,7 +748,7 @@ template template [[nodiscard]] consteval auto common_magnitude_type_impl(magnitude) { - return (... * decltype(get_base_value(Ms)){}) * std::intmax_t{}; + return (std::intmax_t{} * ... * decltype(get_base_value(Ms)){}); } // Returns the most precise type to express the magnitude factor @@ -791,7 +781,7 @@ struct prime_factorization { if constexpr (opt.has_value()) { return opt.value(); // NOLINT(bugprone-unchecked-optional-access) } else { - return static_cast(factorizer::find_first_factor(N)); + return static_cast(decltype(factorizer::find_first_factor())::value); } } @@ -826,14 +816,15 @@ inline constexpr Magnitude auto mag = detail::prime_factorization_v; MP_UNITS_EXPORT template requires detail::gt_zero -inline constexpr Magnitude auto mag_ratio = detail::prime_factorization_v / detail::prime_factorization_v; +inline constexpr Magnitude auto mag_ratio = + decltype(detail::prime_factorization_v / detail::prime_factorization_v){}; /** * @brief Create a Magnitude which is some rational number raised to a rational power. */ MP_UNITS_EXPORT template requires detail::gt_zero -inline constexpr Magnitude auto mag_power = pow(mag); +inline constexpr Magnitude auto mag_power = decltype(pow(mag)){}; namespace detail { @@ -862,20 +853,20 @@ template { constexpr auto exp10 = extract_power_of_10(M); - constexpr Magnitude auto base = M / mag_power<10, exp10>; - constexpr Magnitude auto num = numerator(base); - constexpr Magnitude auto den = denominator(base); + using base = decltype(M / mag_power<10, exp10>); + using num = decltype(numerator(base{})); + using den = decltype(denominator(base{})); // TODO address the below - static_assert(base == num / den, "Printing rational powers, or irrational bases, not yet supported"); + static_assert(base{} == num{} / den{}, "Printing rational powers, or irrational bases, not yet supported"); - constexpr auto num_value = get_value(num); - constexpr auto den_value = get_value(den); + using num_value = decltype(get_value(num{})); + using den_value = decltype(get_value(den{})); - if constexpr (num_value == 1 && den_value == 1 && exp10 != 0) { + if constexpr (num_value{} == 1 && den_value{} == 1 && exp10 != 0) { return base_multiplier + superscript(); - } else if constexpr (num_value != 1 || den_value != 1 || exp10 != 0) { - auto txt = symbol_text("[") + regular(); - if constexpr (den_value == 1) { + } else if constexpr (num_value{} != 1 || den_value{} != 1 || exp10 != 0) { + auto txt = symbol_text("[") + regular(); + if constexpr (den_value{} == 1) { if constexpr (exp10 == 0) { return txt + symbol_text("]"); } else { @@ -883,9 +874,9 @@ template } } else { if constexpr (exp10 == 0) { - return txt + symbol_text("/") + regular() + symbol_text("]"); + return txt + symbol_text("/") + regular() + symbol_text("]"); } else { - return txt + symbol_text("/") + regular() + symbol_text(" ") + base_multiplier + + return txt + symbol_text("/") + regular() + symbol_text(" ") + base_multiplier + superscript() + symbol_text("]"); } } diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 2822ac87..b172727b 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -46,9 +46,9 @@ namespace mp_units { namespace detail { template -concept IntegralConversionFactor = - Unit && Unit && - is_integral(decltype(decltype(get_canonical_unit(UFrom))::mag / decltype(get_canonical_unit(UTo))::mag){}); +concept IntegralConversionFactor = Unit && Unit && + decltype(is_integral(decltype(decltype(get_canonical_unit(UFrom))::mag / + decltype(get_canonical_unit(UTo))::mag){}))::value; template concept QuantityConvertibleTo = diff --git a/src/core/include/mp-units/framework/unit.h b/src/core/include/mp-units/framework/unit.h index 5cc51d63..3299db0b 100644 --- a/src/core/include/mp-units/framework/unit.h +++ b/src/core/include/mp-units/framework/unit.h @@ -627,9 +627,9 @@ template using canonical_lhs = decltype(get_canonical_unit(U1{})); using canonical_rhs = decltype(get_canonical_unit(U2{})); - if constexpr (is_integral(decltype(canonical_lhs::mag / canonical_rhs::mag){})) + if constexpr (decltype(is_integral(decltype(canonical_lhs::mag / canonical_rhs::mag){}))::value) return u2; - else if constexpr (is_integral(decltype(canonical_rhs::mag / canonical_lhs::mag){})) + else if constexpr (decltype(is_integral(decltype(canonical_rhs::mag / canonical_lhs::mag){}))::value) return u1; else { constexpr auto cm = decltype(detail::common_magnitude(canonical_lhs::mag, canonical_rhs::mag)){}; diff --git a/src/systems/include/mp-units/systems/si/chrono.h b/src/systems/include/mp-units/systems/si/chrono.h index 6028e95c..f5ae45a7 100644 --- a/src/systems/include/mp-units/systems/si/chrono.h +++ b/src/systems/include/mp-units/systems/si/chrono.h @@ -113,11 +113,22 @@ struct quantity_point_like_traits(numerator(m))){}, + decltype(get_value(denominator(m))){}>{}; +} + +} // namespace detail + template Q> [[nodiscard]] constexpr auto to_chrono_duration(const Q& q) { - constexpr detail::ratio r = detail::as_ratio(decltype(get_canonical_unit(Q::unit))::mag); - return std::chrono::duration>{q}; + return std::chrono::duration{ + q}; } template QP> @@ -126,8 +137,8 @@ template QP> { using clock = MP_UNITS_TYPENAME decltype(QP::absolute_point_origin)::clock; using rep = MP_UNITS_TYPENAME QP::rep; - constexpr detail::ratio r = detail::as_ratio(decltype(get_canonical_unit(QP::unit))::mag); - using ret_type = std::chrono::time_point>>; + using ret_type = std::chrono::time_point< + clock, std::chrono::duration>; return ret_type(to_chrono_duration(qp - qp.absolute_point_origin)); } diff --git a/test/static/prime_test.cpp b/test/static/prime_test.cpp index 21a7b571..9f3502c0 100644 --- a/test/static/prime_test.cpp +++ b/test/static/prime_test.cpp @@ -32,7 +32,7 @@ namespace { template constexpr bool check_primes(std::index_sequence) { - return ((Is < 2 || wheel_factorizer::is_prime(Is) == is_prime_by_trial_division(Is)) && ...); + return ((Is < 2 || wheel_factorizer::template is_prime() == is_prime_by_trial_division(Is)) && ...); } static_assert(check_primes<2>(std::make_index_sequence<122>{})); @@ -45,7 +45,7 @@ static_assert(check_primes<2>(std::make_index_sequence<122>{})); // using numbers of the form (210 * n + 121) as trial divisors, which is a problem if any are prime. For n = 1, we have // a divisor of (210 + 121 = 331), which happens to be prime but will not be used. Thus, (331 * 331 = 109561) is a // composite number which could wrongly appear prime if we skip over 331. -static_assert(wheel_factorizer<4>::is_prime(109'561) == is_prime_by_trial_division(109'561)); +static_assert(wheel_factorizer<4>::is_prime<109'561>() == is_prime_by_trial_division(109'561)); static_assert(wheel_factorizer<1>::coprimes_in_first_wheel.size() == 1); static_assert(wheel_factorizer<2>::coprimes_in_first_wheel.size() == 2); @@ -62,16 +62,16 @@ static_assert(wheel_factorizer<3>::coprimes_in_first_wheel[5] == 19); static_assert(wheel_factorizer<3>::coprimes_in_first_wheel[6] == 23); static_assert(wheel_factorizer<3>::coprimes_in_first_wheel[7] == 29); -static_assert(!wheel_factorizer<1>::is_prime(0)); -static_assert(!wheel_factorizer<1>::is_prime(1)); -static_assert(wheel_factorizer<1>::is_prime(2)); +static_assert(!wheel_factorizer<1>::is_prime<0>()); +static_assert(!wheel_factorizer<1>::is_prime<1>()); +static_assert(wheel_factorizer<1>::is_prime<2>()); -static_assert(!wheel_factorizer<2>::is_prime(0)); -static_assert(!wheel_factorizer<2>::is_prime(1)); -static_assert(wheel_factorizer<2>::is_prime(2)); +static_assert(!wheel_factorizer<2>::is_prime<0>()); +static_assert(!wheel_factorizer<2>::is_prime<1>()); +static_assert(wheel_factorizer<2>::is_prime<2>()); -static_assert(!wheel_factorizer<3>::is_prime(0)); -static_assert(!wheel_factorizer<3>::is_prime(1)); -static_assert(wheel_factorizer<3>::is_prime(2)); +static_assert(!wheel_factorizer<3>::is_prime<0>()); +static_assert(!wheel_factorizer<3>::is_prime<1>()); +static_assert(wheel_factorizer<3>::is_prime<2>()); } // namespace