mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-02 11:54:27 +02:00
refactor: compile-time optimizations reverted
This commit is contained in:
@@ -34,25 +34,24 @@ template<AssociatedUnit U>
|
||||
template<typename U, auto... Vs>
|
||||
[[nodiscard]] consteval auto all_are_kinds(power<U, Vs...>)
|
||||
{
|
||||
return decltype(all_are_kinds(U{})){};
|
||||
return all_are_kinds(U{});
|
||||
}
|
||||
|
||||
template<typename... Nums, typename... Dens>
|
||||
[[nodiscard]] consteval auto all_are_kinds(type_list<Nums...>, type_list<Dens...>)
|
||||
[[nodiscard]] consteval bool all_are_kinds(type_list<Nums...>, type_list<Dens...>)
|
||||
{
|
||||
return std::bool_constant<((... && decltype(all_are_kinds(Nums{}))::value) &&
|
||||
(... && decltype(all_are_kinds(Dens{}))::value))>{};
|
||||
return (... && all_are_kinds(Nums{})) && (... && all_are_kinds(Dens{}));
|
||||
}
|
||||
|
||||
template<AssociatedUnit U>
|
||||
[[nodiscard]] consteval auto all_are_kinds(U)
|
||||
{
|
||||
if constexpr (requires { U::quantity_spec; })
|
||||
return std::bool_constant<QuantityKindSpec<std::remove_const_t<decltype(U::quantity_spec)>>>{};
|
||||
return QuantityKindSpec<std::remove_const_t<decltype(U::quantity_spec)>>;
|
||||
else if constexpr (requires { U::reference_unit; })
|
||||
return decltype(all_are_kinds(U::reference_unit)){};
|
||||
return all_are_kinds(U::reference_unit);
|
||||
else if constexpr (requires { typename U::_num_; }) {
|
||||
return decltype(all_are_kinds(typename U::_num_{}, typename U::_den_{})){};
|
||||
return all_are_kinds(typename U::_num_{}, typename U::_den_{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,21 +67,20 @@ template<AssociatedUnit U>
|
||||
if constexpr (requires { U::quantity_spec; })
|
||||
return remove_kind(U::quantity_spec);
|
||||
else if constexpr (requires { U::reference_unit; })
|
||||
return decltype(get_associated_quantity_impl(U::reference_unit)){};
|
||||
return get_associated_quantity_impl(U::reference_unit);
|
||||
else if constexpr (requires { typename U::_num_; }) {
|
||||
return decltype(expr_map<to_quantity_spec, derived_quantity_spec, struct dimensionless,
|
||||
type_list_of_quantity_spec_less>(u)){};
|
||||
return expr_map<to_quantity_spec, derived_quantity_spec, struct dimensionless, type_list_of_quantity_spec_less>(u);
|
||||
}
|
||||
}
|
||||
|
||||
template<AssociatedUnit U>
|
||||
[[nodiscard]] consteval auto get_associated_quantity(U u)
|
||||
{
|
||||
constexpr bool all_kinds = decltype(all_are_kinds(u)){};
|
||||
constexpr bool all_kinds = all_are_kinds(u);
|
||||
if constexpr (all_kinds)
|
||||
return kind_of<decltype(get_associated_quantity_impl(u)){}>;
|
||||
return kind_of<get_associated_quantity_impl(u)>;
|
||||
else
|
||||
return decltype(get_associated_quantity_impl(u)){};
|
||||
return get_associated_quantity_impl(u);
|
||||
}
|
||||
|
||||
} // namespace mp_units::detail
|
||||
|
@@ -26,12 +26,12 @@
|
||||
|
||||
namespace mp_units::detail {
|
||||
|
||||
[[nodiscard]] consteval auto hierarchy_path_length(QuantitySpec auto q)
|
||||
[[nodiscard]] consteval std::size_t hierarchy_path_length(QuantitySpec auto q)
|
||||
{
|
||||
if constexpr (requires { q._parent_; })
|
||||
return std::integral_constant<std::size_t, decltype(hierarchy_path_length(q._parent_))::value + 1>{};
|
||||
return hierarchy_path_length(q._parent_) + 1;
|
||||
else
|
||||
return std::integral_constant<std::size_t, 1>{};
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<std::size_t Offset>
|
||||
@@ -41,67 +41,65 @@ template<std::size_t Offset>
|
||||
if constexpr (Offset == 0)
|
||||
return q;
|
||||
else if constexpr (requires { q._parent_; })
|
||||
return decltype(hierarchy_path_advance<Offset - 1>(q._parent_)){};
|
||||
return hierarchy_path_advance<Offset - 1>(q._parent_);
|
||||
}
|
||||
|
||||
template<QuantitySpec A, QuantitySpec B>
|
||||
[[nodiscard]] consteval auto have_common_base_in_hierarchy_of_equal_length(A a, B b)
|
||||
[[nodiscard]] consteval bool have_common_base_in_hierarchy_of_equal_length(A a, B b)
|
||||
{
|
||||
if constexpr (is_same_v<A, B>)
|
||||
return std::true_type{};
|
||||
return true;
|
||||
else if constexpr (requires { a._parent_; })
|
||||
return decltype(have_common_base_in_hierarchy_of_equal_length(a._parent_, b._parent_)){};
|
||||
return have_common_base_in_hierarchy_of_equal_length(a._parent_, b._parent_);
|
||||
else
|
||||
return std::false_type{};
|
||||
return false;
|
||||
}
|
||||
|
||||
template<QuantitySpec A, QuantitySpec B>
|
||||
[[nodiscard]] consteval auto have_common_base(A a, B b)
|
||||
[[nodiscard]] consteval bool have_common_base(A a, B b)
|
||||
{
|
||||
constexpr std::size_t a_length = decltype(hierarchy_path_length(A{}))::value;
|
||||
constexpr std::size_t b_length = decltype(hierarchy_path_length(B{}))::value;
|
||||
constexpr std::size_t a_length = hierarchy_path_length(A{});
|
||||
constexpr std::size_t b_length = hierarchy_path_length(B{});
|
||||
if constexpr (a_length > b_length)
|
||||
return decltype(have_common_base_in_hierarchy_of_equal_length(
|
||||
decltype(hierarchy_path_advance<a_length - b_length>(a)){}, b)){};
|
||||
return have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b);
|
||||
else
|
||||
return decltype(have_common_base_in_hierarchy_of_equal_length(
|
||||
a, decltype(hierarchy_path_advance<b_length - a_length>(b)){})){};
|
||||
return have_common_base_in_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b));
|
||||
}
|
||||
|
||||
template<QuantitySpec A, QuantitySpec B>
|
||||
requires(decltype(have_common_base_in_hierarchy_of_equal_length(A{}, B{}))::value)
|
||||
requires(have_common_base_in_hierarchy_of_equal_length(A{}, B{}))
|
||||
[[nodiscard]] consteval QuantitySpec auto get_common_base_for_hierarchy_of_equal_length(A a, B b)
|
||||
{
|
||||
if constexpr (is_same_v<A, B>)
|
||||
return a;
|
||||
else
|
||||
return decltype(get_common_base_for_hierarchy_of_equal_length(a._parent_, b._parent_)){};
|
||||
return get_common_base_for_hierarchy_of_equal_length(a._parent_, b._parent_);
|
||||
}
|
||||
|
||||
template<QuantitySpec A, QuantitySpec B>
|
||||
requires(decltype(have_common_base(A{}, B{}))::value)
|
||||
requires(have_common_base(A{}, B{}))
|
||||
[[nodiscard]] consteval QuantitySpec auto get_common_base(A a, B b)
|
||||
{
|
||||
constexpr std::size_t a_length = decltype(hierarchy_path_length(A{}))::value;
|
||||
constexpr std::size_t b_length = decltype(hierarchy_path_length(B{}))::value;
|
||||
constexpr std::size_t a_length = hierarchy_path_length(A{});
|
||||
constexpr std::size_t b_length = hierarchy_path_length(B{});
|
||||
if constexpr (a_length > b_length)
|
||||
return decltype(get_common_base_for_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b)){};
|
||||
return get_common_base_for_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b);
|
||||
else
|
||||
return decltype(get_common_base_for_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b))){};
|
||||
return get_common_base_for_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b));
|
||||
}
|
||||
|
||||
template<QuantitySpec Child, QuantitySpec Parent>
|
||||
[[nodiscard]] consteval auto is_child_of(Child ch, Parent)
|
||||
[[nodiscard]] consteval bool is_child_of(Child ch, Parent p)
|
||||
{
|
||||
if constexpr (Child{} == Parent{})
|
||||
return std::true_type{};
|
||||
else {
|
||||
constexpr std::size_t child_length = decltype(hierarchy_path_length(Child{}))::value;
|
||||
constexpr std::size_t parent_length = decltype(hierarchy_path_length(Parent{}))::value;
|
||||
constexpr std::size_t child_length = hierarchy_path_length(Child{});
|
||||
constexpr std::size_t parent_length = hierarchy_path_length(Parent{});
|
||||
if constexpr (parent_length > child_length)
|
||||
return std::false_type{};
|
||||
return false;
|
||||
else
|
||||
return std::bool_constant<hierarchy_path_advance<child_length - parent_length>(ch) == Parent{}>{};
|
||||
return hierarchy_path_advance<child_length - parent_length>(ch) == p;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -64,11 +64,10 @@ template<Quantity To, typename From>
|
||||
// warnings on conversions
|
||||
} else {
|
||||
// scale the number
|
||||
constexpr Magnitude auto c_mag =
|
||||
decltype(decltype(get_canonical_unit(q_unit))::mag / decltype(get_canonical_unit(To::unit))::mag){};
|
||||
constexpr Magnitude auto num = decltype(numerator(c_mag)){};
|
||||
constexpr Magnitude auto den = decltype(denominator(c_mag)){};
|
||||
constexpr Magnitude auto irr = decltype(c_mag * decltype(den / num){}){};
|
||||
constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / 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);
|
||||
using c_rep_type = maybe_common_type<typename std::remove_reference_t<From>::rep, typename To::rep>;
|
||||
using c_mag_type = common_magnitude_type<c_mag>;
|
||||
using multiplier_type = conditional<
|
||||
|
@@ -157,30 +157,22 @@ struct wheel_factorizer {
|
||||
static constexpr auto coprimes_in_first_wheel =
|
||||
coprimes_up_to<num_coprimes_up_to(wheel_size, basis)>(wheel_size, basis);
|
||||
|
||||
template<std::size_t N>
|
||||
[[nodiscard]] static consteval auto find_first_factor()
|
||||
[[nodiscard]] static consteval std::uintmax_t find_first_factor(std::uintmax_t n)
|
||||
{
|
||||
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(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); }))
|
||||
[&](auto p) { return first_factor_maybe(n, p); }))
|
||||
return *k;
|
||||
|
||||
for (std::size_t wheel = wheel_size; wheel < N; wheel += wheel_size)
|
||||
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); }))
|
||||
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<std::uintmax_t, res>{};
|
||||
return n;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
[[nodiscard]] static consteval auto is_prime()
|
||||
{
|
||||
return std::bool_constant<(N > 1 && decltype(find_first_factor<N>())::value == N)>{};
|
||||
}
|
||||
[[nodiscard]] static consteval bool is_prime(std::size_t n) { return (n > 1) && find_first_factor(n) == n; }
|
||||
};
|
||||
|
||||
} // namespace mp_units::detail
|
||||
|
@@ -159,15 +159,15 @@ struct is_dimension_one<struct dimension_one> : std::true_type {};
|
||||
MP_UNITS_EXPORT template<Dimension Lhs, Dimension Rhs>
|
||||
[[nodiscard]] consteval Dimension auto operator*(Lhs, Rhs)
|
||||
{
|
||||
return decltype(detail::expr_multiply<derived_dimension, struct dimension_one,
|
||||
detail::type_list_of_base_dimension_less>(Lhs{}, Rhs{})){};
|
||||
return detail::expr_multiply<derived_dimension, struct dimension_one, detail::type_list_of_base_dimension_less>(
|
||||
Lhs{}, Rhs{});
|
||||
}
|
||||
|
||||
MP_UNITS_EXPORT template<Dimension Lhs, Dimension Rhs>
|
||||
[[nodiscard]] consteval Dimension auto operator/(Lhs, Rhs)
|
||||
{
|
||||
return decltype(detail::expr_divide<derived_dimension, struct dimension_one,
|
||||
detail::type_list_of_base_dimension_less>(Lhs{}, Rhs{})){};
|
||||
return detail::expr_divide<derived_dimension, struct dimension_one, detail::type_list_of_base_dimension_less>(Lhs{},
|
||||
Rhs{});
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -191,7 +191,7 @@ template<Dimension Lhs, Dimension Rhs>
|
||||
return is_same_v<Lhs, Rhs> || detail::derived_from_the_same_base_dimension(lhs, rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval Dimension auto inverse(Dimension auto d) { return decltype(dimension_one / d){}; }
|
||||
[[nodiscard]] consteval Dimension auto inverse(Dimension auto d) { return dimension_one / d; }
|
||||
|
||||
/**
|
||||
* @brief Computes the value of a dimension raised to the `Num/Den` power
|
||||
@@ -212,8 +212,8 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
else
|
||||
return derived_dimension<power<D, Num, Den>>{};
|
||||
} else
|
||||
return decltype(detail::expr_pow<Num, Den, derived_dimension, struct dimension_one,
|
||||
detail::type_list_of_base_dimension_less>(d)){};
|
||||
return detail::expr_pow<Num, Den, derived_dimension, struct dimension_one,
|
||||
detail::type_list_of_base_dimension_less>(d);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +223,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
*
|
||||
* @return Dimension The result of computation
|
||||
*/
|
||||
[[nodiscard]] consteval Dimension auto sqrt(Dimension auto d) { return decltype(pow<1, 2>(d)){}; }
|
||||
[[nodiscard]] consteval Dimension auto sqrt(Dimension auto d) { return pow<1, 2>(d); }
|
||||
|
||||
/**
|
||||
* @brief Computes the cubic root of a dimension
|
||||
@@ -232,7 +232,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
*
|
||||
* @return Dimension The result of computation
|
||||
*/
|
||||
[[nodiscard]] consteval Dimension auto cbrt(Dimension auto d) { return decltype(pow<1, 3>(d)){}; }
|
||||
[[nodiscard]] consteval Dimension auto cbrt(Dimension auto d) { return pow<1, 3>(d); }
|
||||
|
||||
|
||||
struct dimension_symbol_formatting {
|
||||
|
@@ -362,7 +362,7 @@ template<typename NumList, typename DenList, typename OneType, template<typename
|
||||
using simple = expr_simplify<num_list, den_list, Pred>;
|
||||
// the usage of `std::identity` below helps to resolve an using alias identifier to the actual
|
||||
// type identifier in the clang compile-time errors
|
||||
return std::identity{}(decltype(expr_make_spec_impl<typename simple::num, typename simple::den, OneType, To>()){});
|
||||
return std::identity{}(expr_make_spec_impl<typename simple::num, typename simple::den, OneType, To>());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,19 +384,19 @@ template<template<typename...> typename To, typename OneType, template<typename,
|
||||
return Lhs{};
|
||||
} else if constexpr (is_specialization_of<Lhs, To> && is_specialization_of<Rhs, To>) {
|
||||
// two derived dimensions
|
||||
return decltype(get_optimized_expression<type_list_merge_sorted<typename Lhs::_num_, typename Rhs::_num_, Pred>,
|
||||
type_list_merge_sorted<typename Lhs::_den_, typename Rhs::_den_, Pred>,
|
||||
OneType, Pred, To>()){};
|
||||
return get_optimized_expression<type_list_merge_sorted<typename Lhs::_num_, typename Rhs::_num_, Pred>,
|
||||
type_list_merge_sorted<typename Lhs::_den_, typename Rhs::_den_, Pred>, OneType,
|
||||
Pred, To>();
|
||||
} else if constexpr (is_specialization_of<Lhs, To>) {
|
||||
return decltype(get_optimized_expression<type_list_merge_sorted<typename Lhs::_num_, type_list<Rhs>, Pred>,
|
||||
typename Lhs::_den_, OneType, Pred, To>()){};
|
||||
return get_optimized_expression<type_list_merge_sorted<typename Lhs::_num_, type_list<Rhs>, Pred>,
|
||||
typename Lhs::_den_, OneType, Pred, To>();
|
||||
} else if constexpr (is_specialization_of<Rhs, To>) {
|
||||
return decltype(get_optimized_expression<type_list_merge_sorted<typename Rhs::_num_, type_list<Lhs>, Pred>,
|
||||
typename Rhs::_den_, OneType, Pred, To>()){};
|
||||
return get_optimized_expression<type_list_merge_sorted<typename Rhs::_num_, type_list<Lhs>, Pred>,
|
||||
typename Rhs::_den_, OneType, Pred, To>();
|
||||
} else {
|
||||
// two base dimensions
|
||||
return decltype(get_optimized_expression<type_list_merge_sorted<type_list<Lhs>, type_list<Rhs>, Pred>, type_list<>,
|
||||
OneType, Pred, To>()){};
|
||||
return get_optimized_expression<type_list_merge_sorted<type_list<Lhs>, type_list<Rhs>, Pred>, type_list<>, OneType,
|
||||
Pred, To>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,19 +418,18 @@ template<template<typename...> typename To, typename OneType, template<typename,
|
||||
} else if constexpr (is_same_v<Rhs, OneType>) {
|
||||
return lhs;
|
||||
} else if constexpr (is_same_v<Lhs, OneType>) {
|
||||
return decltype(expr_divide<To, OneType, Pred>(To<>{}, rhs)){};
|
||||
return expr_divide<To, OneType, Pred>(To<>{}, rhs);
|
||||
} else if constexpr (is_specialization_of<Lhs, To> && is_specialization_of<Rhs, To>) {
|
||||
// two derived entities
|
||||
return decltype(get_optimized_expression<type_list_merge_sorted<typename Lhs::_num_, typename Rhs::_den_, Pred>,
|
||||
type_list_merge_sorted<typename Lhs::_den_, typename Rhs::_num_, Pred>,
|
||||
OneType, Pred, To>()){};
|
||||
return get_optimized_expression<type_list_merge_sorted<typename Lhs::_num_, typename Rhs::_den_, Pred>,
|
||||
type_list_merge_sorted<typename Lhs::_den_, typename Rhs::_num_, Pred>, OneType,
|
||||
Pred, To>();
|
||||
} else if constexpr (is_specialization_of<Lhs, To>) {
|
||||
return decltype(get_optimized_expression<typename Lhs::_num_,
|
||||
type_list_merge_sorted<typename Lhs::_den_, type_list<Rhs>, Pred>, OneType,
|
||||
Pred, To>()){};
|
||||
return get_optimized_expression<
|
||||
typename Lhs::_num_, type_list_merge_sorted<typename Lhs::_den_, type_list<Rhs>, Pred>, OneType, Pred, To>();
|
||||
} else if constexpr (is_specialization_of<Rhs, To>) {
|
||||
return decltype(get_optimized_expression<type_list_merge_sorted<typename Rhs::_den_, type_list<Lhs>, Pred>,
|
||||
typename Rhs::_num_, OneType, Pred, To>()){};
|
||||
return get_optimized_expression<type_list_merge_sorted<typename Rhs::_den_, type_list<Lhs>, Pred>,
|
||||
typename Rhs::_num_, OneType, Pred, To>();
|
||||
} else {
|
||||
// two named entities
|
||||
return To<Lhs, per<Rhs>>{};
|
||||
@@ -450,7 +449,7 @@ template<template<typename...> typename To, typename OneType, typename T>
|
||||
if constexpr (is_specialization_of<T, To>)
|
||||
// the usage of `std::identity` below helps to resolve an using alias identifier to the actual
|
||||
// type identifier in the clang compile-time errors
|
||||
return std::identity{}(decltype(expr_make_spec_impl<typename T::_den_, typename T::_num_, OneType, To>()){});
|
||||
return std::identity{}(expr_make_spec_impl<typename T::_den_, typename T::_num_, OneType, To>());
|
||||
else
|
||||
return To<OneType, per<T>>{};
|
||||
}
|
||||
@@ -461,9 +460,8 @@ template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval auto expr_pow_impl(type_list<Nums...>, type_list<Dens...>)
|
||||
{
|
||||
return decltype(detail::get_optimized_expression<type_list<power_or_T<Nums, ratio{Num, Den}>...>,
|
||||
type_list<power_or_T<Dens, ratio{Num, Den}>...>, OneType, Pred,
|
||||
To>()){};
|
||||
return detail::get_optimized_expression<type_list<power_or_T<Nums, ratio{Num, Den}>...>,
|
||||
type_list<power_or_T<Dens, ratio{Num, Den}>...>, OneType, Pred, To>();
|
||||
}
|
||||
|
||||
|
||||
@@ -482,7 +480,7 @@ template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval auto expr_pow(T)
|
||||
{
|
||||
return decltype(expr_pow_impl<Num, Den, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{})){};
|
||||
return expr_pow_impl<Num, Den, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{});
|
||||
}
|
||||
|
||||
|
||||
@@ -529,7 +527,7 @@ template<typename T>
|
||||
template<typename T, auto... Ints>
|
||||
[[nodiscard]] consteval auto map_power(power<T, Ints...>)
|
||||
{
|
||||
return decltype(pow<Ints...>(T{})){};
|
||||
return pow<Ints...>(T{});
|
||||
}
|
||||
|
||||
template<template<typename> typename Proj, template<typename...> typename To, typename OneType,
|
||||
@@ -537,8 +535,8 @@ template<template<typename> typename Proj, template<typename...> typename To, ty
|
||||
expr_type_projectable<Proj>... Dens>
|
||||
[[nodiscard]] consteval auto expr_map_impl(type_list<Nums...>, type_list<Dens...>)
|
||||
{
|
||||
return decltype(decltype((OneType{} * ... * map_power(typename expr_type_map<Nums, Proj>::type{}))){} /
|
||||
decltype((OneType{} * ... * map_power(typename expr_type_map<Dens, Proj>::type{}))){}){};
|
||||
return (OneType{} * ... * map_power(typename expr_type_map<Nums, Proj>::type{})) /
|
||||
(OneType{} * ... * map_power(typename expr_type_map<Dens, Proj>::type{}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,7 +555,7 @@ template<template<typename> typename Proj, template<typename...> typename To, ty
|
||||
if constexpr (type_list_size<typename T::_num_> + type_list_size<typename T::_den_> == 0)
|
||||
return OneType{};
|
||||
else
|
||||
return decltype(expr_map_impl<Proj, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{})){};
|
||||
return expr_map_impl<Proj, To, OneType, Pred>(typename T::_num_{}, typename T::_den_{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
@@ -476,16 +476,16 @@ namespace detail {
|
||||
template<MagnitudeSpec auto... Ms>
|
||||
// requires detail::is_element_pack_valid<Ms...>
|
||||
struct magnitude {
|
||||
[[nodiscard]] friend consteval auto is_integral(const magnitude&)
|
||||
[[nodiscard]] friend consteval bool is_integral(const magnitude&)
|
||||
{
|
||||
using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec
|
||||
return std::bool_constant<(is_integral(Ms) && ...)>{};
|
||||
return (is_integral(Ms) && ...);
|
||||
}
|
||||
|
||||
[[nodiscard]] friend consteval auto is_rational(const magnitude&)
|
||||
[[nodiscard]] friend consteval bool is_rational(const magnitude&)
|
||||
{
|
||||
using namespace detail; // needed for recursive case when magnitudes are in the MagnitudeSpec
|
||||
return std::bool_constant<(is_rational(Ms) && ...)>{};
|
||||
return (is_rational(Ms) && ...);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -508,13 +508,12 @@ inline constexpr bool is_specialization_of_magnitude<magnitude<Ms...>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
/**
|
||||
* @brief The value of a Magnitude in a desired type T.
|
||||
*/
|
||||
template<typename T, auto... Ms>
|
||||
requires(decltype(is_integral(magnitude<Ms...>{}))::value) || treat_as_floating_point<T>
|
||||
requires(is_integral(magnitude<Ms...>{})) || treat_as_floating_point<T>
|
||||
constexpr T get_value(const magnitude<Ms...>&)
|
||||
{
|
||||
// Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow.
|
||||
@@ -522,6 +521,8 @@ constexpr T get_value(const magnitude<Ms...>&)
|
||||
return result;
|
||||
}
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
/**
|
||||
* @brief A convenient Magnitude constant for pi, which we can manipulate like a regular number.
|
||||
*/
|
||||
@@ -556,21 +557,21 @@ template<std::intmax_t Num, std::intmax_t Den = 1, auto... Ms>
|
||||
if constexpr (Num == 0) {
|
||||
return magnitude<>{};
|
||||
} else {
|
||||
return decltype(magnitude<detail::power_v_or_T<detail::get_base(Ms),
|
||||
detail::get_exponent(Ms) * detail::ratio{Num, Den}>()...>{}){};
|
||||
return magnitude<
|
||||
detail::power_v_or_T<detail::get_base(Ms), detail::get_exponent(Ms) * detail::ratio{Num, Den}>()...>{};
|
||||
}
|
||||
}
|
||||
|
||||
template<auto... Ms>
|
||||
[[nodiscard]] consteval auto sqrt(magnitude<Ms...> m)
|
||||
{
|
||||
return decltype(pow<1, 2>(m)){};
|
||||
return pow<1, 2>(m);
|
||||
}
|
||||
|
||||
template<auto... Ms>
|
||||
[[nodiscard]] consteval auto cbrt(magnitude<Ms...> m)
|
||||
{
|
||||
return decltype(pow<1, 3>(m)){};
|
||||
return pow<1, 3>(m);
|
||||
}
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
@@ -613,13 +614,13 @@ template<auto H1, auto... T1, auto H2, auto... T2>
|
||||
// Shortcut for the "pure prepend" case, which makes it easier to implement some of the other cases.
|
||||
return magnitude<H1, H2, T2...>{};
|
||||
} else {
|
||||
return decltype(magnitude<H1>{} * (decltype(magnitude<T1...>{} * magnitude<H2, T2...>{}){})){};
|
||||
return magnitude<H1>{} * (magnitude<T1...>{} * magnitude<H2, T2...>{});
|
||||
}
|
||||
} else if constexpr (less(H2, H1)) {
|
||||
return decltype(magnitude<H2>{} * (decltype(magnitude<H1, T1...>{} * magnitude<T2...>{}){})){};
|
||||
return magnitude<H2>{} * (magnitude<H1, T1...>{} * magnitude<T2...>{});
|
||||
} else {
|
||||
if constexpr (is_same_v<decltype(get_base(H1)), decltype(get_base(H2))>) {
|
||||
constexpr auto partial_product = decltype(magnitude<T1...>{} * magnitude<T2...>{}){};
|
||||
constexpr auto partial_product = magnitude<T1...>{} * magnitude<T2...>{};
|
||||
if constexpr (get_exponent(H1) + get_exponent(H2) == 0) {
|
||||
return partial_product;
|
||||
} else {
|
||||
@@ -629,13 +630,13 @@ template<auto H1, auto... T1, auto H2, auto... T2>
|
||||
if constexpr (get_exponent(new_head) == 0) {
|
||||
return partial_product;
|
||||
} else {
|
||||
return decltype(magnitude<new_head>{} * partial_product){};
|
||||
return magnitude<new_head>{} * partial_product;
|
||||
}
|
||||
}
|
||||
} else if constexpr (is_named_magnitude<decltype(get_base(H1))>) {
|
||||
return decltype(magnitude<H1>{} * decltype((magnitude<T1...>{} * magnitude<H2, T2...>{})){}){};
|
||||
return magnitude<H1>{} * (magnitude<T1...>{} * magnitude<H2, T2...>{});
|
||||
} else {
|
||||
return decltype(magnitude<H2>{} * decltype((magnitude<H1, T1...>{} * magnitude<T2...>{})){}){};
|
||||
return magnitude<H2>{} * (magnitude<H1, T1...>{} * magnitude<T2...>{});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -643,7 +644,7 @@ template<auto H1, auto... T1, auto H2, auto... T2>
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Magnitude quotient implementation.
|
||||
|
||||
[[nodiscard]] consteval auto operator/(Magnitude auto l, Magnitude auto r) { return decltype(l * pow<-1>(r)){}; }
|
||||
[[nodiscard]] consteval auto operator/(Magnitude auto l, Magnitude auto r) { return l * pow<-1>(r); }
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
@@ -670,10 +671,10 @@ template<auto M>
|
||||
template<auto... Ms>
|
||||
[[nodiscard]] consteval auto numerator(magnitude<Ms...>)
|
||||
{
|
||||
return decltype((decltype(detail::integer_part(magnitude<Ms>{})){} * ... * magnitude<>{})){};
|
||||
return (detail::integer_part(magnitude<Ms>{}) * ... * magnitude<>{});
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval auto denominator(Magnitude auto m) { return decltype(numerator(pow<-1>(m))){}; }
|
||||
[[nodiscard]] consteval auto denominator(Magnitude auto m) { return numerator(pow<-1>(m)); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Common Magnitude.
|
||||
@@ -713,11 +714,11 @@ template<auto... Ms>
|
||||
[[nodiscard]] consteval auto common_magnitude(magnitude<>, magnitude<>) { return magnitude<>{}; }
|
||||
[[nodiscard]] consteval auto common_magnitude(magnitude<>, Magnitude auto m)
|
||||
{
|
||||
return decltype(detail::remove_positive_powers(m)){};
|
||||
return detail::remove_positive_powers(m);
|
||||
}
|
||||
[[nodiscard]] consteval auto common_magnitude(Magnitude auto m, magnitude<>)
|
||||
{
|
||||
return decltype(detail::remove_positive_powers(m)){};
|
||||
return detail::remove_positive_powers(m);
|
||||
}
|
||||
|
||||
// Recursive case for the common Magnitude of any two non-identity Magnitudes.
|
||||
@@ -728,19 +729,17 @@ template<auto H1, auto... T1, auto H2, auto... T2>
|
||||
|
||||
if constexpr (detail::get_base_value(H1) < detail::get_base_value(H2)) {
|
||||
// When H1 has the smaller base, prepend to result from recursion.
|
||||
return decltype(decltype(remove_positive_power(magnitude<H1>{})){} *
|
||||
decltype(common_magnitude(magnitude<T1...>{}, magnitude<H2, T2...>{})){}){};
|
||||
return remove_positive_power(magnitude<H1>{}) * common_magnitude(magnitude<T1...>{}, magnitude<H2, T2...>{});
|
||||
} 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 decltype(decltype(remove_positive_power(magnitude<H2>{})){} *
|
||||
decltype(common_magnitude(magnitude<H1, T1...>{}, magnitude<T2...>{})){}){};
|
||||
return remove_positive_power(magnitude<H2>{}) * common_magnitude(magnitude<H1, T1...>{}, magnitude<T2...>{});
|
||||
} else {
|
||||
// When the bases are equal, pick whichever has the lower power.
|
||||
constexpr auto common_tail = decltype(common_magnitude(magnitude<T1...>{}, magnitude<T2...>{})){};
|
||||
constexpr auto common_tail = common_magnitude(magnitude<T1...>{}, magnitude<T2...>{});
|
||||
if constexpr (detail::get_exponent(H1) < detail::get_exponent(H2)) {
|
||||
return decltype(magnitude<H1>{} * common_tail){};
|
||||
return magnitude<H1>{} * common_tail;
|
||||
} else {
|
||||
return decltype(magnitude<H2>{} * common_tail){};
|
||||
return magnitude<H2>{} * common_tail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -781,7 +780,7 @@ struct prime_factorization {
|
||||
if constexpr (opt.has_value()) {
|
||||
return opt.value(); // NOLINT(bugprone-unchecked-optional-access)
|
||||
} else {
|
||||
return static_cast<std::intmax_t>(decltype(factorizer::find_first_factor<N>())::value);
|
||||
return static_cast<std::intmax_t>(factorizer::find_first_factor(N));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,15 +815,14 @@ inline constexpr Magnitude auto mag = detail::prime_factorization_v<V>;
|
||||
|
||||
MP_UNITS_EXPORT template<std::intmax_t N, std::intmax_t D>
|
||||
requires detail::gt_zero<N>
|
||||
inline constexpr Magnitude auto mag_ratio =
|
||||
decltype(detail::prime_factorization_v<N> / detail::prime_factorization_v<D>){};
|
||||
inline constexpr Magnitude auto mag_ratio = detail::prime_factorization_v<N> / detail::prime_factorization_v<D>;
|
||||
|
||||
/**
|
||||
* @brief Create a Magnitude which is some rational number raised to a rational power.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<std::intmax_t Base, std::intmax_t Pow>
|
||||
requires detail::gt_zero<Base>
|
||||
inline constexpr Magnitude auto mag_power = decltype(pow<Pow>(mag<Base>)){};
|
||||
inline constexpr Magnitude auto mag_power = pow<Pow>(mag<Base>);
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -853,14 +851,14 @@ template<Magnitude auto M>
|
||||
{
|
||||
constexpr auto exp10 = extract_power_of_10(M);
|
||||
|
||||
using base = decltype(M / mag_power<10, exp10>);
|
||||
using num = decltype(numerator(base{}));
|
||||
using den = decltype(denominator(base{}));
|
||||
constexpr Magnitude auto base = M / mag_power<10, exp10>;
|
||||
constexpr Magnitude auto num = numerator(base);
|
||||
constexpr Magnitude auto den = 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<std::intmax_t>(num{});
|
||||
constexpr auto den_value = get_value<std::intmax_t>(den{});
|
||||
constexpr auto num_value = get_value<std::intmax_t>(num);
|
||||
constexpr auto den_value = get_value<std::intmax_t>(den);
|
||||
|
||||
if constexpr (num_value == 1 && den_value == 1 && exp10 != 0) {
|
||||
return base_multiplier + superscript<exp10>();
|
||||
|
@@ -52,8 +52,7 @@ template<Unit UFrom, Unit UTo>
|
||||
if constexpr (is_same_v<UFrom, UTo>)
|
||||
return true;
|
||||
else
|
||||
return decltype(is_integral(
|
||||
decltype(decltype(get_canonical_unit(from))::mag / decltype(get_canonical_unit(to))::mag){}))::value;
|
||||
return is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag);
|
||||
}
|
||||
|
||||
template<typename QFrom, typename QTo>
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -126,12 +126,11 @@ MP_UNITS_EXPORT template<QuantitySpec Q>
|
||||
namespace detail {
|
||||
|
||||
template<QuantitySpec Child, QuantitySpec Parent>
|
||||
[[nodiscard]] consteval auto is_child_of(Child ch, Parent);
|
||||
[[nodiscard]] consteval bool is_child_of(Child ch, Parent p);
|
||||
|
||||
template<auto To, auto From>
|
||||
concept NestedQuantityKindSpecOf =
|
||||
QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> && get_kind(From) != get_kind(To) &&
|
||||
decltype(is_child_of(To, get_kind(From)._quantity_spec_))::value;
|
||||
concept NestedQuantityKindSpecOf = QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> &&
|
||||
get_kind(From) != get_kind(To) && is_child_of(To, get_kind(From)._quantity_spec_);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
@@ -46,7 +46,7 @@ MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
[[nodiscard]] consteval QuantitySpec auto get_quantity_spec(AssociatedUnit auto u)
|
||||
{
|
||||
return decltype(detail::get_associated_quantity(u)){};
|
||||
return detail::get_associated_quantity(u);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -206,7 +206,7 @@ struct named_unit<Symbol, U, PO> : decltype(U)::_base_type_ {
|
||||
* @tparam QuantitySpec a specification of a quantity to be measured with this unit
|
||||
*/
|
||||
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS>
|
||||
requires(!Symbol.empty()) && (QS.dimension == decltype(detail::get_associated_quantity(U))::dimension)
|
||||
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
|
||||
struct named_unit<Symbol, U, QS> : decltype(U)::_base_type_ {
|
||||
using _base_type_ = named_unit; // exposition only
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
@@ -214,7 +214,7 @@ struct named_unit<Symbol, U, QS> : decltype(U)::_base_type_ {
|
||||
};
|
||||
|
||||
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS, PointOrigin auto PO>
|
||||
requires(!Symbol.empty()) && (QS.dimension == decltype(detail::get_associated_quantity(U))::dimension)
|
||||
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
|
||||
struct named_unit<Symbol, U, QS, PO> : decltype(U)::_base_type_ {
|
||||
using _base_type_ = named_unit; // exposition only
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
@@ -339,12 +339,19 @@ struct is_one<struct one> : std::true_type {};
|
||||
* @tparam U a unit to use as a `reference_unit`
|
||||
* @tparam M a Magnitude representing an absolute scaling factor of this unit
|
||||
*/
|
||||
template<Magnitude auto M, Unit auto U>
|
||||
template<Magnitude M, Unit U>
|
||||
struct canonical_unit {
|
||||
static constexpr auto mag = M;
|
||||
static constexpr auto reference_unit = U;
|
||||
M mag;
|
||||
U reference_unit;
|
||||
};
|
||||
|
||||
#if MP_UNITS_COMP_CLANG
|
||||
|
||||
template<Magnitude M, Unit U>
|
||||
canonical_unit(M, U) -> canonical_unit<M, U>;
|
||||
|
||||
#endif
|
||||
|
||||
template<Unit T, symbol_text Symbol, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&);
|
||||
|
||||
@@ -360,61 +367,58 @@ template<Unit T, typename... Expr>
|
||||
template<Unit T, auto M, typename U>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit_impl<M, U>&)
|
||||
{
|
||||
using base = decltype(get_canonical_unit_impl(U{}, U{}));
|
||||
return canonical_unit<decltype(M * base::mag){}, base::reference_unit>{};
|
||||
auto base = get_canonical_unit_impl(U{}, U{});
|
||||
return canonical_unit{M * base.mag, base.reference_unit};
|
||||
}
|
||||
|
||||
template<Unit T, symbol_text Symbol, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, Args...>&)
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&)
|
||||
{
|
||||
return canonical_unit<mag<1>, T{}>{};
|
||||
return canonical_unit{mag<1>, t};
|
||||
}
|
||||
|
||||
template<Unit T, symbol_text Symbol, Unit auto U, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, U, Args...>&)
|
||||
{
|
||||
return decltype(get_canonical_unit_impl(U, U)){};
|
||||
return get_canonical_unit_impl(U, U);
|
||||
}
|
||||
|
||||
template<typename F, int Num, int... Den, typename... Us>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(const power<F, Num, Den...>&, const type_list<Us...>&)
|
||||
{
|
||||
using mag = decltype((mp_units::mag<1> * ... * pow<Num, Den...>(decltype(get_canonical_unit_impl(Us{}, Us{}))::mag)));
|
||||
using u = decltype((one * ... * pow<Num, Den...>(decltype(get_canonical_unit_impl(Us{}, Us{}))::reference_unit)));
|
||||
return canonical_unit<mag{}, u{}>{};
|
||||
auto mag = (mp_units::mag<1> * ... * pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).mag));
|
||||
auto u = (one * ... * pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).reference_unit));
|
||||
return canonical_unit{mag, u};
|
||||
}
|
||||
|
||||
template<typename T, typename F, int Num, int... Den>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const power<F, Num, Den...>&)
|
||||
{
|
||||
using base = decltype(get_canonical_unit_impl(F{}, F{}));
|
||||
if constexpr (requires { typename decltype(base::reference_unit)::_num_; }) {
|
||||
using num =
|
||||
decltype(get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base::reference_unit)::_num_{}));
|
||||
using den =
|
||||
decltype(get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base::reference_unit)::_den_{}));
|
||||
return canonical_unit<decltype(decltype(pow<Num, Den...>(base::mag) * num::mag){} / den::mag){},
|
||||
decltype(num::reference_unit / den::reference_unit){}>{};
|
||||
auto base = get_canonical_unit_impl(F{}, F{});
|
||||
if constexpr (requires { typename decltype(base.reference_unit)::_num_; }) {
|
||||
auto num = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_num_{});
|
||||
auto den = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_den_{});
|
||||
return canonical_unit{pow<Num, Den...>(base.mag) * num.mag / den.mag, num.reference_unit / den.reference_unit};
|
||||
} else {
|
||||
return canonical_unit<decltype(pow<Num, Den...>(base::mag)){},
|
||||
derived_unit<power<std::remove_const_t<decltype(base::reference_unit)>, Num, Den...>>{}>{};
|
||||
return canonical_unit{pow<Num, Den...>(base.mag),
|
||||
derived_unit<power<decltype(base.reference_unit), Num, Den...>>{}};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Us>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(const type_list<Us...>&)
|
||||
{
|
||||
using m = decltype((mp_units::mag<1> * ... * decltype(get_canonical_unit_impl(Us{}, Us{}))::mag));
|
||||
using u = decltype((one * ... * decltype(get_canonical_unit_impl(Us{}, Us{}))::reference_unit));
|
||||
return canonical_unit<m{}, u{}>{};
|
||||
auto m = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag);
|
||||
auto u = (one * ... * get_canonical_unit_impl(Us{}, Us{}).reference_unit);
|
||||
return canonical_unit{m, u};
|
||||
}
|
||||
|
||||
template<Unit T, typename... Expr>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit_impl<Expr...>&)
|
||||
{
|
||||
using num = decltype(get_canonical_unit_impl(typename derived_unit_impl<Expr...>::_num_{}));
|
||||
using den = decltype(get_canonical_unit_impl(typename derived_unit_impl<Expr...>::_den_{}));
|
||||
return canonical_unit<decltype(num::mag / den::mag){}, decltype(num::reference_unit / den::reference_unit){}>{};
|
||||
auto num = get_canonical_unit_impl(typename derived_unit<Expr...>::_num_{});
|
||||
auto den = get_canonical_unit_impl(typename derived_unit<Expr...>::_den_{});
|
||||
return canonical_unit{num.mag / den.mag, num.reference_unit / den.reference_unit};
|
||||
}
|
||||
|
||||
template<Unit Lhs, Unit Rhs>
|
||||
@@ -427,10 +431,7 @@ using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
|
||||
|
||||
// TODO this should really be in the `details` namespace but is used in `chrono.h` (a part of mp_units.systems)
|
||||
// Even though it is not exported, it is visible to the other module via ADL
|
||||
[[nodiscard]] consteval auto get_canonical_unit(Unit auto u)
|
||||
{
|
||||
return decltype(detail::get_canonical_unit_impl(u, u)){};
|
||||
}
|
||||
[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) { return detail::get_canonical_unit_impl(u, u); }
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
@@ -456,7 +457,7 @@ template<Magnitude M, Unit U>
|
||||
template<Magnitude M, Unit U>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, U u)
|
||||
{
|
||||
return decltype(mag * inverse(u)){};
|
||||
return mag * inverse(u);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,13 +469,13 @@ template<Unit Lhs, Unit Rhs>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(Lhs lhs, Rhs rhs)
|
||||
{
|
||||
if constexpr (detail::is_specialization_of_scaled_unit<Lhs> && detail::is_specialization_of_scaled_unit<Rhs>)
|
||||
return decltype(Lhs::mag * Rhs::mag){} * decltype(Lhs::reference_unit * Rhs::reference_unit){};
|
||||
return (Lhs::mag * Rhs::mag) * (Lhs::reference_unit * Rhs::reference_unit);
|
||||
else if constexpr (detail::is_specialization_of_scaled_unit<Lhs>)
|
||||
return decltype(Lhs::mag * decltype(Lhs::reference_unit * rhs){}){};
|
||||
return Lhs::mag * (Lhs::reference_unit * rhs);
|
||||
else if constexpr (detail::is_specialization_of_scaled_unit<Rhs>)
|
||||
return decltype(Rhs::mag * decltype(lhs * Rhs::reference_unit){}){};
|
||||
return Rhs::mag * (lhs * Rhs::reference_unit);
|
||||
else
|
||||
return decltype(detail::expr_multiply<derived_unit, struct one, detail::type_list_of_unit_less>(lhs, rhs)){};
|
||||
return detail::expr_multiply<derived_unit, struct one, detail::type_list_of_unit_less>(lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,44 +487,39 @@ template<Unit Lhs, Unit Rhs>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(Lhs lhs, Rhs rhs)
|
||||
{
|
||||
if constexpr (detail::is_specialization_of_scaled_unit<Lhs> && detail::is_specialization_of_scaled_unit<Rhs>)
|
||||
return decltype(Lhs::mag / Rhs::mag){} * decltype(Lhs::reference_unit / Rhs::reference_unit){};
|
||||
return (Lhs::mag / Rhs::mag) * (Lhs::reference_unit / Rhs::reference_unit);
|
||||
else if constexpr (detail::is_specialization_of_scaled_unit<Lhs>)
|
||||
return Lhs::mag * decltype(Lhs::reference_unit / rhs){};
|
||||
return Lhs::mag * (Lhs::reference_unit / rhs);
|
||||
else if constexpr (detail::is_specialization_of_scaled_unit<Rhs>)
|
||||
return decltype(mag<1> / Rhs::mag){} * decltype(lhs / Rhs::reference_unit){};
|
||||
return mag<1> / Rhs::mag * (lhs / Rhs::reference_unit);
|
||||
else
|
||||
return detail::expr_divide<derived_unit, struct one, detail::type_list_of_unit_less>(lhs, rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto inverse(Unit auto u) { return decltype(one / u){}; }
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto inverse(Unit auto u) { return one / u; }
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval auto have_same_canonical_reference_unit(U1 u1, U2 u2)
|
||||
[[nodiscard]] consteval bool have_same_canonical_reference_unit(U1 u1, U2 u2)
|
||||
{
|
||||
if constexpr (is_same_v<U1, U2>)
|
||||
return std::true_type{};
|
||||
else {
|
||||
using canonical_lhs = decltype(get_canonical_unit(u1));
|
||||
using canonical_rhs = decltype(get_canonical_unit(u2));
|
||||
return std::is_same<decltype(canonical_lhs::reference_unit), decltype(canonical_rhs::reference_unit)>{};
|
||||
}
|
||||
return true;
|
||||
else
|
||||
return is_same_v<decltype(get_canonical_unit(u1).reference_unit), decltype(get_canonical_unit(u2).reference_unit)>;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
MP_UNITS_EXPORT template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval bool operator==(U1 lhs, U2 rhs)
|
||||
MP_UNITS_EXPORT [[nodiscard]] consteval bool operator==(Unit auto lhs, Unit auto rhs)
|
||||
{
|
||||
if constexpr (is_same_v<U1, U2>)
|
||||
return true;
|
||||
else
|
||||
return decltype(detail::have_same_canonical_reference_unit(lhs, rhs))::value &&
|
||||
decltype(get_canonical_unit(lhs))::mag == decltype(get_canonical_unit(rhs))::mag;
|
||||
auto canonical_lhs = get_canonical_unit(lhs);
|
||||
auto canonical_rhs = get_canonical_unit(rhs);
|
||||
return detail::have_same_canonical_reference_unit(canonical_lhs.reference_unit, canonical_rhs.reference_unit) &&
|
||||
canonical_lhs.mag == canonical_rhs.mag;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -558,7 +554,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
else if constexpr (detail::is_specialization_of_scaled_unit<U>)
|
||||
return scaled_unit<pow<Num, Den>(U::mag), decltype(pow<Num, Den>(U::reference_unit))>{};
|
||||
else if constexpr (detail::is_specialization_of_derived_unit<U>)
|
||||
return decltype(detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u)){};
|
||||
return detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u);
|
||||
else if constexpr (Den == 1)
|
||||
return derived_unit<power<U, Num>>{};
|
||||
else
|
||||
@@ -572,7 +568,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
*
|
||||
* @return Unit The result of computation
|
||||
*/
|
||||
[[nodiscard]] consteval Unit auto sqrt(Unit auto u) { return decltype(pow<1, 2>(u)){}; }
|
||||
[[nodiscard]] consteval Unit auto sqrt(Unit auto u) { return pow<1, 2>(u); }
|
||||
|
||||
/**
|
||||
* @brief Computes the cubic root of a unit
|
||||
@@ -581,7 +577,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
*
|
||||
* @return Unit The result of computation
|
||||
*/
|
||||
[[nodiscard]] consteval Unit auto cbrt(Unit auto u) { return decltype(pow<1, 3>(u)){}; }
|
||||
[[nodiscard]] consteval Unit auto cbrt(Unit auto u) { return pow<1, 3>(u); }
|
||||
|
||||
/**
|
||||
* @brief Computes the square power of a unit
|
||||
@@ -590,7 +586,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
*
|
||||
* @return Unit The result of computation
|
||||
*/
|
||||
[[nodiscard]] consteval Unit auto square(Unit auto u) { return decltype(pow<2>(u)){}; }
|
||||
[[nodiscard]] consteval Unit auto square(Unit auto u) { return pow<2>(u); }
|
||||
|
||||
/**
|
||||
* @brief Computes the cubic power of a unit
|
||||
@@ -599,7 +595,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
*
|
||||
* @return Unit The result of computation
|
||||
*/
|
||||
[[nodiscard]] consteval Unit auto cubic(Unit auto u) { return decltype(pow<3>(u)){}; }
|
||||
[[nodiscard]] consteval Unit auto cubic(Unit auto u) { return pow<3>(u); }
|
||||
|
||||
|
||||
// common dimensionless units
|
||||
@@ -618,7 +614,7 @@ template<Unit U1, Unit U2>
|
||||
if constexpr (is_same_v<U1, U2>)
|
||||
return true;
|
||||
else
|
||||
return decltype(detail::have_same_canonical_reference_unit(from, to))::value;
|
||||
return detail::have_same_canonical_reference_unit(from, to);
|
||||
}
|
||||
|
||||
// Common unit
|
||||
@@ -626,7 +622,7 @@ template<Unit U1, Unit U2>
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval Unit auto common_unit(U1 u1, U2 u2)
|
||||
requires(decltype(detail::have_same_canonical_reference_unit(u1, u2))::value)
|
||||
requires(detail::have_same_canonical_reference_unit(u1, u2))
|
||||
{
|
||||
if constexpr (is_same_v<U1, U2>)
|
||||
return u1;
|
||||
@@ -637,18 +633,18 @@ template<Unit U1, Unit U2>
|
||||
return u2;
|
||||
else
|
||||
// TODO Check if there is a better choice here
|
||||
return decltype(detail::better_type_name(u1, u2)){};
|
||||
return detail::better_type_name(u1, u2);
|
||||
} else {
|
||||
using canonical_lhs = decltype(get_canonical_unit(U1{}));
|
||||
using canonical_rhs = decltype(get_canonical_unit(U2{}));
|
||||
constexpr auto canonical_lhs = get_canonical_unit(U1{});
|
||||
constexpr auto canonical_rhs = get_canonical_unit(U2{});
|
||||
|
||||
if constexpr (decltype(is_integral(decltype(canonical_lhs::mag / canonical_rhs::mag){}))::value)
|
||||
if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag))
|
||||
return u2;
|
||||
else if constexpr (decltype(is_integral(decltype(canonical_rhs::mag / canonical_lhs::mag){}))::value)
|
||||
else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag))
|
||||
return u1;
|
||||
else {
|
||||
constexpr auto cm = decltype(detail::common_magnitude(canonical_lhs::mag, canonical_rhs::mag)){};
|
||||
return scaled_unit<cm, std::remove_const_t<decltype(canonical_lhs::reference_unit)>>{};
|
||||
constexpr auto cm = detail::common_magnitude(canonical_lhs.mag, canonical_rhs.mag);
|
||||
return scaled_unit<cm, decltype(canonical_lhs.reference_unit)>{};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,7 +652,7 @@ template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval Unit 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 decltype(common_unit(common_unit(u1, u2), u3, rest...)){};
|
||||
return common_unit(common_unit(u1, u2), u3, rest...);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -191,7 +191,7 @@ concept UnitOf =
|
||||
namespace detail {
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval auto have_same_canonical_reference_unit(U1 u1, U2 u2);
|
||||
[[nodiscard]] consteval bool have_same_canonical_reference_unit(U1 u1, U2 u2);
|
||||
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ template<Unit U1, Unit U2>
|
||||
MP_UNITS_EXPORT template<typename U, auto U2, auto QS>
|
||||
concept UnitCompatibleWith =
|
||||
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(U2))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
(!AssociatedUnit<U> || UnitOf<U, QS>)&&decltype(detail::have_same_canonical_reference_unit(U{}, U2))::value;
|
||||
(!AssociatedUnit<U> || UnitOf<U, QS>)&&(detail::have_same_canonical_reference_unit(U{}, U2));
|
||||
|
||||
|
||||
} // namespace mp_units
|
||||
|
@@ -115,8 +115,8 @@ struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::durati
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr auto as_ratio(Magnitude auto m)
|
||||
requires(decltype(is_rational(decltype(m){}))::value)
|
||||
[[nodiscard]] constexpr auto as_ratio(Magnitude auto m)
|
||||
requires(is_rational(m))
|
||||
{
|
||||
return std::ratio<get_value<std::intmax_t>(numerator(m)), get_value<std::intmax_t>(denominator(m))>{};
|
||||
}
|
||||
@@ -126,8 +126,7 @@ constexpr auto as_ratio(Magnitude auto m)
|
||||
template<QuantityOf<isq::time> Q>
|
||||
[[nodiscard]] constexpr auto to_chrono_duration(const Q& q)
|
||||
{
|
||||
return std::chrono::duration<typename Q::rep, decltype(detail::as_ratio(decltype(get_canonical_unit(Q::unit))::mag))>{
|
||||
q};
|
||||
return std::chrono::duration<typename Q::rep, decltype(detail::as_ratio(get_canonical_unit(Q::unit).mag))>{q};
|
||||
}
|
||||
|
||||
template<QuantityPointOf<isq::time> QP>
|
||||
@@ -136,8 +135,9 @@ template<QuantityPointOf<isq::time> QP>
|
||||
{
|
||||
using clock = MP_UNITS_TYPENAME decltype(QP::absolute_point_origin)::clock;
|
||||
using rep = MP_UNITS_TYPENAME QP::rep;
|
||||
using ret_type = std::chrono::time_point<
|
||||
clock, std::chrono::duration<rep, decltype(detail::as_ratio(decltype(get_canonical_unit(QP::unit))::mag))>>;
|
||||
using ret_type =
|
||||
std::chrono::time_point<clock,
|
||||
std::chrono::duration<rep, decltype(detail::as_ratio(get_canonical_unit(QP::unit).mag))>>;
|
||||
return ret_type(to_chrono_duration(qp - qp.absolute_point_origin));
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,7 @@ namespace {
|
||||
template<std::size_t BasisSize, std::size_t... Is>
|
||||
constexpr bool check_primes(std::index_sequence<Is...>)
|
||||
{
|
||||
return ((Is < 2 || wheel_factorizer<BasisSize>::template is_prime<Is>() == is_prime_by_trial_division(Is)) && ...);
|
||||
return ((Is < 2 || wheel_factorizer<BasisSize>::is_prime(Is) == 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
|
||||
|
Reference in New Issue
Block a user