feat: scaled_unit symbol printing improved ([] around the entire unit, small magnitude values do not use a power of 10 anymore)

This commit is contained in:
Mateusz Pusz
2024-10-02 15:27:38 +02:00
parent 61817ae61f
commit d7309c8602
3 changed files with 72 additions and 51 deletions

View File

@@ -234,8 +234,6 @@ template<auto M>
template<auto M>
[[nodiscard]] consteval auto remove_positive_power(magnitude<M> m);
inline constexpr symbol_text base_multiplier(u8"× 10", "x 10");
template<std::intmax_t Base, std::intmax_t Pow>
requires detail::gt_zero<Base>
[[nodiscard]] consteval Magnitude auto mag_power_lazy();
@@ -316,6 +314,31 @@ struct magnitude_base<magnitude<H, T...>> {
}
};
template<auto num_value, auto den_value>
[[nodiscard]] consteval auto ratio_txt()
{
if constexpr (den_value == 1)
return detail::regular<num_value>();
else
return detail::regular<num_value>() + symbol_text("/") + detail::regular<den_value>();
};
template<auto num, auto den, auto exp10>
[[nodiscard]] consteval auto magnitude_text_impl()
{
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 symbol_text("10") + detail::superscript<exp10>();
} else {
if constexpr (exp10 == 0)
return ratio_txt<num_value, den_value>();
else
return ratio_txt<num_value, den_value>() + symbol_text(u8" × 10", " x 10") + detail::superscript<exp10>();
}
}
} // namespace detail
@@ -426,37 +449,28 @@ private:
[[nodiscard]] friend consteval auto _magnitude_text(magnitude)
{
constexpr auto exp10 = _extract_power_of_10(magnitude{});
constexpr Magnitude auto base = magnitude{} / detail::mag_power_lazy<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");
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 detail::base_multiplier + detail::superscript<exp10>();
} else if constexpr (num_value != 1 || den_value != 1 || exp10 != 0) {
auto txt = symbol_text("[") + detail::regular<num_value>();
if constexpr (den_value == 1) {
if constexpr (exp10 == 0) {
return txt + symbol_text("]");
} else {
return txt + symbol_text(" ") + detail::base_multiplier + detail::superscript<exp10>() + symbol_text("]");
}
} else {
if constexpr (exp10 == 0) {
return txt + symbol_text("/") + detail::regular<den_value>() + symbol_text("]");
} else {
return txt + symbol_text("/") + detail::regular<den_value>() + symbol_text(" ") + detail::base_multiplier +
detail::superscript<exp10>() + symbol_text("]");
}
}
} else {
if constexpr (magnitude{} == magnitude<1>{}) {
return symbol_text("");
} else {
constexpr auto exp10 = _extract_power_of_10(magnitude{});
if constexpr (detail::abs(exp10) < 3) {
// print the value as a regular number (without exponent)
constexpr Magnitude auto num = _numerator(magnitude{});
constexpr Magnitude auto den = _denominator(magnitude{});
// TODO address the below
static_assert(magnitude{} == num / den, "Printing rational powers, or irrational bases, not yet supported");
return detail::magnitude_text_impl<num, den, 0>();
} else {
// print the value as a number with exponent
// if user wanted a regular number for this magnitude then probably a better scaled unit should be used
constexpr Magnitude auto base = magnitude{} / detail::mag_power_lazy<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");
return detail::magnitude_text_impl<num, den, exp10>();
}
}
}
};

View File

@@ -830,16 +830,13 @@ template<typename CharT, std::output_iterator<CharT> Out, auto M, typename U>
constexpr Out unit_symbol_impl(Out out, const scaled_unit_impl<M, U>& u, const unit_symbol_formatting& fmt,
bool negative_power)
{
if constexpr (M == mag<1>) {
// no ratio/prefix
return unit_symbol_impl<CharT>(out, u.reference_unit, fmt, negative_power);
} else {
constexpr auto mag_txt = _magnitude_text(M);
out = copy<CharT>(mag_txt, fmt.encoding, out);
if constexpr (space_before_unit_symbol<scaled_unit<M, U>::reference_unit>) *out++ = ' ';
return unit_symbol_impl<CharT>(out, u.reference_unit, fmt, negative_power);
}
*out++ = '[';
constexpr auto mag_txt = _magnitude_text(M);
out = copy<CharT>(mag_txt, fmt.encoding, out);
if constexpr (space_before_unit_symbol<scaled_unit<M, U>::reference_unit>) *out++ = ' ';
unit_symbol_impl<CharT>(out, u.reference_unit, fmt, negative_power);
*out++ = ']';
return out;
}
template<typename... Us, Unit U>

View File

@@ -110,19 +110,29 @@ static_assert(unit_symbol(zebi<bit>) == "Zibit");
static_assert(unit_symbol(yobi<bit>) == "Yibit");
// scaled units
static_assert(unit_symbol(mag<100> * metre) == "× 10² m");
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag<100> * metre) == "x 10^2 m");
static_assert(unit_symbol(mag<60> * second) == "[6 × 10¹] s");
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag<60> * second) == "[6 x 10^1] s");
static_assert(unit_symbol(mag_ratio<1, 18> * metre / second) == "[1/18] m/s");
static_assert(unit_symbol(mag<100> * metre) == "[100 m]");
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag<100> * metre) == "[100 m]");
static_assert(unit_symbol(mag<1000> * metre) == "[10³ m]");
static_assert(unit_symbol(mag_power<10, 3> * metre) == "[10³ m]");
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag<1000> * metre) == "[10^3 m]");
static_assert(unit_symbol(mag<6000> * metre) == "[6 × 10³ m]");
static_assert(unit_symbol(mag<6> * mag_power<10, 3> * metre) == "[6 × 10³ m]");
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag<6000> * metre) == "[6 x 10^3 m]");
static_assert(unit_symbol(mag<10600> * metre) == "[10600 m]");
static_assert(unit_symbol(mag<60> * second) == "[60 s]");
static_assert(unit_symbol(mag_ratio<1, 18> * metre / second) == "[1/18 m/s]");
static_assert(unit_symbol(mag_ratio<1, 1800> * metre / second) == "[1/1800 m/s]");
static_assert(unit_symbol(mag_ratio<1, 18000> * metre / second) == "[1/18 × 10⁻³ m/s]");
static_assert(unit_symbol<unit_symbol_formatting{.encoding = ascii}>(mag_ratio<1, 18000> * metre / second) ==
"[1/18 x 10^-3 m/s]");
// common units
static_assert(unit_symbol(get_common_unit(kilo<metre>, mile)) == "EQUIV{[1/25146] mi, [1/15625] km}");
static_assert(unit_symbol(get_common_unit(kilo<metre> / hour, metre / second)) == "EQUIV{[1/5] km/h, [1/18] m/s}");
static_assert(unit_symbol(get_common_unit(kilo<metre>, mile)) == "EQUIV{[1/25146 mi], [1/15625 km]}");
static_assert(unit_symbol(get_common_unit(kilo<metre> / hour, metre / second)) == "EQUIV{[1/5 km/h], [1/18 m/s]}");
static_assert(unit_symbol(get_common_unit(kilo<metre> / hour, metre / second) / second) ==
"EQUIV{[1/5] km/h, [1/18] m/s}/s");
"EQUIV{[1/5 km/h], [1/18 m/s]}/s");
static_assert(unit_symbol(get_common_unit(kilo<metre> / hour, metre / second) * second) ==
"EQUIV{[1/5] km/h, [1/18] m/s} s");
"EQUIV{[1/5 km/h], [1/18 m/s]} s");
// derived units
static_assert(unit_symbol(one) == ""); // NOLINT(readability-container-size-empty)