mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-03 12:24:26 +02:00
feat: std::common_type
support for unit added
This commit is contained in:
@@ -679,6 +679,7 @@ template<auto... Ms>
|
|||||||
{
|
{
|
||||||
return (magnitude<>{} * ... * remove_positive_power(magnitude<Ms>{}));
|
return (magnitude<>{} * ... * remove_positive_power(magnitude<Ms>{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Base cases, for when either (or both) inputs are the identity.
|
// Base cases, for when either (or both) inputs are the identity.
|
||||||
@@ -698,16 +699,16 @@ template<auto H1, auto... T1, auto H2, auto... T2>
|
|||||||
{
|
{
|
||||||
using detail::remove_positive_power;
|
using detail::remove_positive_power;
|
||||||
|
|
||||||
if constexpr (get_base(H1) < get_base(H2)) {
|
if constexpr (detail::get_base(H1) < detail::get_base(H2)) {
|
||||||
// When H1 has the smaller base, prepend to result from recursion.
|
// When H1 has the smaller base, prepend to result from recursion.
|
||||||
return remove_positive_power(magnitude<H1>{}) * common_magnitude(magnitude<T1...>{}, magnitude<H2, T2...>{});
|
return remove_positive_power(magnitude<H1>{}) * common_magnitude(magnitude<T1...>{}, magnitude<H2, T2...>{});
|
||||||
} else if constexpr (get_base(H2) < get_base(H1)) {
|
} else if constexpr (detail::get_base(H2) < detail::get_base(H1)) {
|
||||||
// When H2 has the smaller base, prepend to result from recursion.
|
// When H2 has the smaller base, prepend to result from recursion.
|
||||||
return remove_positive_power(magnitude<H2>{}) * common_magnitude(magnitude<H1, T1...>{}, magnitude<T2...>{});
|
return remove_positive_power(magnitude<H2>{}) * common_magnitude(magnitude<H1, T1...>{}, magnitude<T2...>{});
|
||||||
} else {
|
} else {
|
||||||
// When the bases are equal, pick whichever has the lower power.
|
// When the bases are equal, pick whichever has the lower power.
|
||||||
constexpr auto common_tail = common_magnitude(magnitude<T1...>{}, magnitude<T2...>{});
|
constexpr auto common_tail = common_magnitude(magnitude<T1...>{}, magnitude<T2...>{});
|
||||||
if constexpr (get_exponent(H1) < get_exponent(H2)) {
|
if constexpr (detail::get_exponent(H1) < detail::get_exponent(H2)) {
|
||||||
return magnitude<H1>{} * common_tail;
|
return magnitude<H1>{} * common_tail;
|
||||||
} else {
|
} else {
|
||||||
return magnitude<H2>{} * common_tail;
|
return magnitude<H2>{} * common_tail;
|
||||||
|
@@ -395,12 +395,12 @@ using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
|
|||||||
* Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned.
|
* Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned.
|
||||||
*/
|
*/
|
||||||
template<Magnitude M, Unit U>
|
template<Magnitude M, Unit U>
|
||||||
[[nodiscard]] consteval Unit auto operator*(M mag, U u)
|
[[nodiscard]] consteval Unit auto operator*(M mag, const U u)
|
||||||
{
|
{
|
||||||
if constexpr (mag == units::mag<1>)
|
if constexpr (mag == units::mag<1>)
|
||||||
return u;
|
return u;
|
||||||
else
|
else
|
||||||
return scaled_unit<mag, std::remove_const_t<U>>{};
|
return scaled_unit<mag, U>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Magnitude M, Unit U>
|
template<Magnitude M, Unit U>
|
||||||
@@ -700,16 +700,42 @@ template<typename CharT = char, Unit U>
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
|
||||||
|
template<typename U1, typename U2>
|
||||||
|
[[nodiscard]] consteval auto common_type_impl(const U1 u1, const U2 u2)
|
||||||
|
{
|
||||||
|
if constexpr (U1{} == U2{}) {
|
||||||
|
if constexpr (std::derived_from<U1, U2>)
|
||||||
|
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<cm, std::remove_const_t<decltype(canonical_lhs.reference_unit)>>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
// TODO implement this
|
|
||||||
template<units::Unit U1, units::Unit U2>
|
template<units::Unit U1, units::Unit U2>
|
||||||
requires(units::convertible(U1{}, U2{}))
|
requires(units::convertible(U1{}, U2{}))
|
||||||
struct common_type<U1, U2> {
|
struct common_type<U1, U2> {
|
||||||
using type = ::units::conditional<std::derived_from<std::remove_const_t<U1>, std::remove_const_t<U2>>,
|
using type = std::remove_const_t<decltype(::units::detail::common_type_impl(U1{}, U2{}))>;
|
||||||
std::remove_const_t<U1>, std::remove_const_t<U2>>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
@@ -64,6 +64,10 @@ inline constexpr struct tonne_ : named_unit<"t", mag<1000> * kilogram> {} tonne;
|
|||||||
inline constexpr struct dalton_ : named_unit<"Da", mag<ratio{16'605'390'666'050, 10'000'000'000'000}> * mag_power<10, -27> * kilogram> {} dalton;
|
inline constexpr struct dalton_ : named_unit<"Da", mag<ratio{16'605'390'666'050, 10'000'000'000'000}> * mag_power<10, -27> * kilogram> {} dalton;
|
||||||
inline constexpr struct electronvolt_ : named_unit<"eV", mag<ratio{1'602'176'634, 1'000'000'000}> * mag_power<10, -19> * joule> {} electronvolt;
|
inline constexpr struct electronvolt_ : named_unit<"eV", mag<ratio{1'602'176'634, 1'000'000'000}> * mag_power<10, -19> * joule> {} electronvolt;
|
||||||
|
|
||||||
|
inline constexpr struct yard_ : named_unit<"yd", mag<ratio{9'144, 10'000}> * metre> {} yard;
|
||||||
|
inline constexpr struct foot_ : named_unit<"ft", mag<ratio(1, 3)> * yard> {} foot;
|
||||||
|
inline constexpr struct mile_ : named_unit<"mi", mag<1760> * yard> {} mile;
|
||||||
|
|
||||||
inline constexpr struct kilometre_ : decltype(si::kilo<metre>) {} kilometre;
|
inline constexpr struct kilometre_ : decltype(si::kilo<metre>) {} kilometre;
|
||||||
inline constexpr struct kilojoule_ : decltype(si::kilo<joule>) {} kilojoule;
|
inline constexpr struct kilojoule_ : decltype(si::kilo<joule>) {} kilojoule;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
@@ -353,6 +357,37 @@ static_assert(joule == newton * metre);
|
|||||||
static_assert(watt == joule / second);
|
static_assert(watt == joule / second);
|
||||||
static_assert(watt == kilogram * square<metre> / cubic<second>);
|
static_assert(watt == kilogram * square<metre> / cubic<second>);
|
||||||
|
|
||||||
|
// common_type
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(gram), decltype(gram)>, gram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(kilogram), decltype(kilogram)>, kilogram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(si::kilo<gram>), decltype(kilogram)>, kilogram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(kilogram), decltype(si::kilo<gram>)>, kilogram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(mag<1000> * gram), decltype(kilogram)>, kilogram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(kilogram), decltype(mag<1000> * gram)>, kilogram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(1 / second), decltype(hertz)>, hertz_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(hertz), decltype(1 / second)>, hertz_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(gram), decltype(kilogram)>, gram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(kilogram), decltype(gram)>, gram_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(second), decltype(hour)>, second_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(hour), decltype(second)>, second_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(minute), decltype(hour)>, minute_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(hour), decltype(minute)>, minute_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(si::kilo<metre>), decltype(si::milli<metre>)>,
|
||||||
|
std::remove_const_t<decltype(si::milli<metre>)>>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(si::milli<metre>), decltype(si::kilo<metre>)>,
|
||||||
|
std::remove_const_t<decltype(si::milli<metre>)>>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(yard), decltype(mile)>, yard_>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(mile), decltype(yard)>, yard_>);
|
||||||
|
// TODO The below have long/unreadable magnitude types
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(kilometre / hour), decltype(metre / second)>,
|
||||||
|
scaled_unit<mag<ratio{1, 18}>, derived_unit<metre_, per<second_>>>>);
|
||||||
|
static_assert(std::is_same_v<std::common_type_t<decltype(metre / second), decltype(kilometre / hour)>,
|
||||||
|
scaled_unit<mag<ratio{1, 18}>, derived_unit<metre_, per<second_>>>>);
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<std::common_type_t<decltype(kilometre), decltype(mile)>, scaled_unit<mag<ratio{8, 125}>, metre_>>);
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<std::common_type_t<decltype(mile), decltype(kilometre)>, scaled_unit<mag<ratio{8, 125}>, metre_>>);
|
||||||
|
|
||||||
// unit symbols
|
// unit symbols
|
||||||
#ifdef __cpp_lib_constexpr_string
|
#ifdef __cpp_lib_constexpr_string
|
||||||
|
|
||||||
@@ -379,6 +414,7 @@ static_assert(unit_symbol(mag<100> * metre, {.encoding = ascii}) == "x 10^2 m");
|
|||||||
static_assert(unit_symbol(mag<60> * second) == "[6 × 10¹] s");
|
static_assert(unit_symbol(mag<60> * second) == "[6 × 10¹] s");
|
||||||
static_assert(unit_symbol(mag<60> * second, {.encoding = ascii}) == "[6 x 10^1] s");
|
static_assert(unit_symbol(mag<60> * second, {.encoding = ascii}) == "[6 x 10^1] s");
|
||||||
|
|
||||||
|
// derived units
|
||||||
static_assert(unit_symbol(one) == "");
|
static_assert(unit_symbol(one) == "");
|
||||||
static_assert(unit_symbol(square<metre>) == "m²");
|
static_assert(unit_symbol(square<metre>) == "m²");
|
||||||
static_assert(unit_symbol(square<metre>, {.encoding = ascii}) == "m^2");
|
static_assert(unit_symbol(square<metre>, {.encoding = ascii}) == "m^2");
|
||||||
|
Reference in New Issue
Block a user