mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +02:00
@ -23,9 +23,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/external/fixed_string.h>
|
||||
#include <mp-units/bits/ratio.h>
|
||||
#include <mp-units/bits/symbol_text.h>
|
||||
|
||||
namespace mp_units::detail {
|
||||
namespace mp_units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<std::intmax_t Value>
|
||||
requires(0 <= Value) && (Value < 10)
|
||||
@ -84,4 +87,73 @@ template<std::intmax_t Value>
|
||||
return regular<Value / 10>() + regular<Value % 10>();
|
||||
}
|
||||
|
||||
} // namespace mp_units::detail
|
||||
} // namespace detail
|
||||
|
||||
enum class text_encoding : std::int8_t {
|
||||
unicode, // m³; µs
|
||||
ascii, // m^3; us
|
||||
default_encoding = unicode
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename CharT, std::size_t N, std::size_t M, std::output_iterator<CharT> Out>
|
||||
constexpr Out copy(const basic_symbol_text<N, M>& txt, text_encoding encoding, Out out)
|
||||
{
|
||||
if (encoding == text_encoding::unicode) {
|
||||
if constexpr (is_same_v<CharT, char8_t>)
|
||||
return copy(txt.unicode(), out).out;
|
||||
else if constexpr (is_same_v<CharT, char>) {
|
||||
for (char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
|
||||
return out;
|
||||
} else
|
||||
throw std::invalid_argument("Unicode text can't be copied to CharT output");
|
||||
} else {
|
||||
if constexpr (is_same_v<CharT, char>)
|
||||
return copy(txt.ascii(), out).out;
|
||||
else
|
||||
throw std::invalid_argument("ASCII text can't be copied to CharT output");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharT, std::size_t N, std::size_t M, std::output_iterator<CharT> Out>
|
||||
constexpr Out copy_symbol(const basic_symbol_text<N, M>& txt, text_encoding encoding, bool negative_power, Out out)
|
||||
{
|
||||
out = copy<CharT>(txt, encoding, out);
|
||||
if (negative_power) {
|
||||
constexpr auto exp = superscript<-1>();
|
||||
out = copy<CharT>(exp, encoding, out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename CharT, int Num, int... Den, std::output_iterator<CharT> Out>
|
||||
constexpr Out copy_symbol_exponent(text_encoding encoding, bool negative_power, Out out)
|
||||
{
|
||||
constexpr ratio r{Num, Den...};
|
||||
if constexpr (r.den != 1) {
|
||||
// add root part
|
||||
if (negative_power) {
|
||||
constexpr auto txt = basic_symbol_text("^-(") + regular<r.num>() + basic_symbol_text("/") + regular<r.den>() +
|
||||
basic_symbol_text(")");
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
} else {
|
||||
constexpr auto txt =
|
||||
basic_symbol_text("^(") + regular<r.num>() + basic_symbol_text("/") + regular<r.den>() + basic_symbol_text(")");
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
}
|
||||
} else if constexpr (r.num != 1) {
|
||||
// add exponent part
|
||||
if (negative_power) {
|
||||
constexpr auto txt = superscript<-r.num>();
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
} else {
|
||||
constexpr auto txt = superscript<r.num>();
|
||||
return copy<CharT>(txt, encoding, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mp_units
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <mp-units/bits/external/type_traits.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/bits/symbol_text.h>
|
||||
#include <mp-units/bits/text_tools.h>
|
||||
|
||||
namespace mp_units {
|
||||
|
||||
@ -164,13 +165,15 @@ template<auto Symbol>
|
||||
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT template<Dimension Lhs, Dimension Rhs>
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<Dimension Lhs, Dimension Rhs>
|
||||
[[nodiscard]] consteval bool operator==(Lhs lhs, Rhs rhs)
|
||||
{
|
||||
return is_same_v<Lhs, Rhs> || detail::derived_from_the_same_base_dimension(lhs, rhs);
|
||||
}
|
||||
|
||||
MP_UNITS_EXPORT [[nodiscard]] consteval Dimension auto inverse(Dimension auto d) { return 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
|
||||
@ -181,7 +184,7 @@ MP_UNITS_EXPORT [[nodiscard]] consteval Dimension auto inverse(Dimension auto d)
|
||||
*
|
||||
* @return Dimension The result of computation
|
||||
*/
|
||||
MP_UNITS_EXPORT template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval Dimension auto pow(D d)
|
||||
{
|
||||
@ -202,7 +205,7 @@ MP_UNITS_EXPORT template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
*
|
||||
* @return Dimension The result of computation
|
||||
*/
|
||||
MP_UNITS_EXPORT [[nodiscard]] consteval Dimension auto sqrt(Dimension auto d) { return 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
|
||||
@ -211,9 +214,107 @@ MP_UNITS_EXPORT [[nodiscard]] consteval Dimension auto sqrt(Dimension auto d) {
|
||||
*
|
||||
* @return Dimension The result of computation
|
||||
*/
|
||||
MP_UNITS_EXPORT [[nodiscard]] consteval Dimension auto cbrt(Dimension auto d) { return pow<1, 3>(d); }
|
||||
[[nodiscard]] consteval Dimension auto cbrt(Dimension auto d) { return pow<1, 3>(d); }
|
||||
|
||||
|
||||
// TODO consider adding the support for text output of the dimensional equation
|
||||
struct dimension_symbol_formatting {
|
||||
text_encoding encoding = text_encoding::default_encoding;
|
||||
};
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, Dimension D>
|
||||
requires requires { D::symbol; }
|
||||
constexpr Out dimension_symbol_impl(Out out, D, dimension_symbol_formatting fmt, bool negative_power)
|
||||
{
|
||||
return copy_symbol<CharT>(D::symbol, fmt.encoding, negative_power, out);
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename F, int Num, int... Den>
|
||||
constexpr auto dimension_symbol_impl(Out out, const power<F, Num, Den...>&, dimension_symbol_formatting fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
out = dimension_symbol_impl<CharT>(out, F{}, fmt, false); // negative power component will be added below if needed
|
||||
return copy_symbol_exponent<CharT, Num, Den...>(fmt.encoding, negative_power, out);
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedDimensionExpr... Ms>
|
||||
constexpr Out dimension_symbol_impl(Out out, const type_list<Ms...>&, dimension_symbol_formatting fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
return (..., (out = dimension_symbol_impl<CharT>(out, Ms{}, fmt, negative_power)));
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedDimensionExpr... Nums, DerivedDimensionExpr... Dens>
|
||||
constexpr Out dimension_symbol_impl(Out out, const type_list<Nums...>& nums, const type_list<Dens...>& dens,
|
||||
dimension_symbol_formatting fmt)
|
||||
{
|
||||
if constexpr (sizeof...(Nums) == 0 && sizeof...(Dens) == 0) {
|
||||
// dimensionless quantity
|
||||
*out++ = '1';
|
||||
return out;
|
||||
} else if constexpr (sizeof...(Dens) == 0) {
|
||||
// no denominator
|
||||
return dimension_symbol_impl<CharT>(out, nums, fmt, false);
|
||||
} else {
|
||||
if constexpr (sizeof...(Nums) > 0) out = dimension_symbol_impl<CharT>(out, nums, fmt, false);
|
||||
return dimension_symbol_impl<CharT>(out, dens, fmt, true);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
|
||||
constexpr Out dimension_symbol_impl(Out out, const derived_dimension<Expr...>&, dimension_symbol_formatting fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
gsl_Expects(negative_power == false);
|
||||
return dimension_symbol_impl<CharT>(out, typename derived_dimension<Expr...>::_num_{},
|
||||
typename derived_dimension<Expr...>::_den_{}, fmt);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT template<typename CharT = char, std::output_iterator<CharT> Out, Dimension D>
|
||||
constexpr Out dimension_symbol_to(Out out, D d, dimension_symbol_formatting fmt = dimension_symbol_formatting{})
|
||||
{
|
||||
return detail::dimension_symbol_impl<CharT>(out, d, fmt, false);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename CharT, std::size_t N, dimension_symbol_formatting fmt, Dimension D>
|
||||
[[nodiscard]] consteval std::array<CharT, N + 1> get_symbol_buffer(D)
|
||||
{
|
||||
std::array<CharT, N + 1> buffer{};
|
||||
dimension_symbol_to<CharT>(buffer.begin(), D{}, fmt);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
// TODO Refactor to `dimension_symbol(D, fmt)` when P1045: constexpr Function Parameters is available
|
||||
MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_formatting{}, typename CharT = char,
|
||||
Dimension D>
|
||||
[[nodiscard]] consteval auto dimension_symbol(D)
|
||||
{
|
||||
auto get_size = []() consteval {
|
||||
std::basic_string<CharT> buffer;
|
||||
dimension_symbol_to<CharT>(std::back_inserter(buffer), D{}, fmt);
|
||||
return buffer.size();
|
||||
};
|
||||
|
||||
#if __cpp_constexpr >= 202211L // Permitting static constexpr variables in constexpr functions
|
||||
static constexpr std::size_t size = get_size();
|
||||
static constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(D{});
|
||||
return std::string_view(buffer.data(), size);
|
||||
#else
|
||||
constexpr std::size_t size = get_size();
|
||||
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(D{});
|
||||
return basic_fixed_string(buffer.data(), std::integral_constant<std::size_t, size>{});
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mp_units
|
||||
|
@ -125,9 +125,80 @@ OutputIt format_global_buffer(OutputIt out, const fill_align_width_format_specs<
|
||||
// dimension-spec ::= [text-encoding]
|
||||
// text-encoding ::= 'U' | 'A'
|
||||
//
|
||||
template<mp_units::Dimension D, typename Char>
|
||||
class MP_UNITS_STD_FMT::formatter<D, Char> {
|
||||
struct format_specs : mp_units::detail::fill_align_width_format_specs<Char>, mp_units::dimension_symbol_formatting {};
|
||||
|
||||
// template<typename Char>
|
||||
// struct dimension_format_specs : fill_align_width_format_specs<Char>, dimension_symbol_formatting {};
|
||||
std::basic_string_view<Char> fill_align_width_format_str_;
|
||||
std::basic_string_view<Char> modifiers_format_str_;
|
||||
format_specs specs_{};
|
||||
|
||||
struct format_checker {
|
||||
using enum mp_units::text_encoding;
|
||||
mp_units::text_encoding encoding = unicode;
|
||||
constexpr void on_text_encoding(Char val) { encoding = (val == 'U') ? unicode : ascii; }
|
||||
};
|
||||
|
||||
struct unit_formatter {
|
||||
format_specs specs;
|
||||
using enum mp_units::text_encoding;
|
||||
constexpr void on_text_encoding(Char val) { specs.encoding = (val == 'U') ? unicode : ascii; }
|
||||
};
|
||||
|
||||
template<typename Handler>
|
||||
constexpr const Char* parse_dimension_specs(const Char* begin, const Char* end, Handler&& handler) const
|
||||
{
|
||||
auto it = begin;
|
||||
if (it == end || *it == '}') return begin;
|
||||
|
||||
constexpr auto valid_modifiers = std::string_view{"UA"};
|
||||
for (; it != end && *it != '}'; ++it) {
|
||||
if (valid_modifiers.find(*it) == std::string_view::npos)
|
||||
throw MP_UNITS_STD_FMT::format_error("invalid dimension modifier specified");
|
||||
}
|
||||
end = it;
|
||||
|
||||
if (it = mp_units::detail::at_most_one_of(begin, end, "UA"); it != end) handler.on_text_encoding(*it);
|
||||
return end;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr auto parse(MP_UNITS_STD_FMT::basic_format_parse_context<Char>& ctx) -> decltype(ctx.begin())
|
||||
{
|
||||
const auto begin = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
|
||||
auto it = parse_fill_align_width(ctx, begin, end, specs_);
|
||||
fill_align_width_format_str_ = {begin, it};
|
||||
if (it == end) return it;
|
||||
|
||||
format_checker checker;
|
||||
end = parse_dimension_specs(it, end, checker);
|
||||
modifiers_format_str_ = {it, end};
|
||||
return end;
|
||||
}
|
||||
|
||||
template<typename FormatContext>
|
||||
auto format(const D& d, FormatContext& ctx) const -> decltype(ctx.out())
|
||||
{
|
||||
unit_formatter f{specs_};
|
||||
mp_units::detail::handle_dynamic_spec<mp_units::detail::width_checker>(f.specs.width, f.specs.width_ref, ctx);
|
||||
|
||||
parse_dimension_specs(modifiers_format_str_.begin(), modifiers_format_str_.end(), f);
|
||||
|
||||
if (f.specs.width == 0) {
|
||||
// Avoid extra copying if width is not specified
|
||||
return mp_units::dimension_symbol_to<Char>(ctx.out(), d, f.specs);
|
||||
} else {
|
||||
std::basic_string<Char> unit_buffer;
|
||||
mp_units::dimension_symbol_to<Char>(std::back_inserter(unit_buffer), d, f.specs);
|
||||
|
||||
std::basic_string<Char> global_format_buffer = "{:" + std::basic_string<Char>{fill_align_width_format_str_} + "}";
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
MP_UNITS_STD_FMT::make_format_args(unit_buffer));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
@ -297,10 +368,9 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
|
||||
return on_replacement_field<Rep>(begin);
|
||||
else if (id == "U")
|
||||
return on_replacement_field<unit_t>(begin);
|
||||
else if (id == "D") {
|
||||
return begin;
|
||||
// on_replacement_field<dimension_t>(begin);
|
||||
} else
|
||||
else if (id == "D")
|
||||
return on_replacement_field<dimension_t>(begin);
|
||||
else
|
||||
throw MP_UNITS_STD_FMT::format_error("unknown replacement field '" + std::string(id) + "'");
|
||||
}
|
||||
|
||||
@ -337,7 +407,10 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
|
||||
{
|
||||
out = MP_UNITS_STD_FMT::vformat_to(out, locale, format_str, MP_UNITS_STD_FMT::make_format_args(q.unit));
|
||||
}
|
||||
void on_dimension(std::basic_string_view<Char>) {}
|
||||
void on_dimension(std::basic_string_view<Char> format_str)
|
||||
{
|
||||
out = MP_UNITS_STD_FMT::vformat_to(out, locale, format_str, MP_UNITS_STD_FMT::make_format_args(q.dimension));
|
||||
}
|
||||
void on_text(const Char* begin, const Char* end) const { std::copy(begin, end, out); }
|
||||
|
||||
constexpr const Char* on_replacement_field(std::basic_string_view<Char> id, const Char* begin)
|
||||
|
@ -35,14 +35,21 @@ namespace mp_units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename CharT, class Traits, Dimension D>
|
||||
void to_stream_impl(std::basic_ostream<CharT, Traits>& os, D d)
|
||||
{
|
||||
dimension_symbol_to<CharT>(std::ostream_iterator<CharT>(os), d);
|
||||
}
|
||||
|
||||
template<typename CharT, class Traits, Unit U>
|
||||
void to_stream(std::basic_ostream<CharT, Traits>& os, U u)
|
||||
void to_stream_impl(std::basic_ostream<CharT, Traits>& os, U u)
|
||||
{
|
||||
unit_symbol_to<CharT>(std::ostream_iterator<CharT>(os), u);
|
||||
}
|
||||
|
||||
template<typename CharT, class Traits, auto R, typename Rep>
|
||||
void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
|
||||
void to_stream_impl(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
|
||||
requires requires { os << q.numerical_value_ref_in(q.unit); }
|
||||
{
|
||||
if constexpr (is_same_v<Rep, std::uint8_t> || is_same_v<Rep, std::int8_t>)
|
||||
// promote the value to int
|
||||
@ -50,46 +57,36 @@ void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
|
||||
else
|
||||
os << q.numerical_value_ref_in(q.unit);
|
||||
if constexpr (space_before_unit_symbol<get_unit(R)>) os << " ";
|
||||
to_stream(os, get_unit(R));
|
||||
to_stream_impl(os, get_unit(R));
|
||||
}
|
||||
|
||||
template<typename CharT, class Traits, typename T>
|
||||
std::basic_ostream<CharT, Traits>& to_stream(std::basic_ostream<CharT, Traits>& os, const T& v)
|
||||
requires requires { detail::to_stream_impl(os, v); }
|
||||
{
|
||||
if (os.width()) {
|
||||
// std::setw() applies to the whole output so it has to be first put into std::string
|
||||
std::basic_ostringstream<CharT, Traits> oss;
|
||||
oss.flags(os.flags());
|
||||
oss.imbue(os.getloc());
|
||||
oss.precision(os.precision());
|
||||
detail::to_stream_impl(oss, v);
|
||||
return os << std::move(oss).str();
|
||||
}
|
||||
|
||||
detail::to_stream_impl(os, v);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<typename CharT, typename Traits, Unit U>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, U u)
|
||||
template<typename CharT, typename Traits, typename T>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const T& v)
|
||||
requires requires { detail::to_stream_impl(os, v); }
|
||||
{
|
||||
if (os.width()) {
|
||||
// std::setw() applies to the whole uni output so it has to be first put into std::string
|
||||
std::basic_ostringstream<CharT, Traits> oss;
|
||||
oss.flags(os.flags());
|
||||
oss.imbue(os.getloc());
|
||||
oss.precision(os.precision());
|
||||
detail::to_stream(oss, u);
|
||||
return os << std::move(oss).str();
|
||||
}
|
||||
|
||||
detail::to_stream(os, u);
|
||||
return os;
|
||||
}
|
||||
|
||||
template<typename CharT, typename Traits, auto R, typename Rep>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
|
||||
requires requires { os << q.numerical_value_ref_in(q.unit); }
|
||||
{
|
||||
if (os.width()) {
|
||||
// std::setw() applies to the whole quantity output so it has to be first put into std::string
|
||||
std::basic_ostringstream<CharT, Traits> oss;
|
||||
oss.flags(os.flags());
|
||||
oss.imbue(os.getloc());
|
||||
oss.precision(os.precision());
|
||||
detail::to_stream(oss, q);
|
||||
return os << std::move(oss).str();
|
||||
}
|
||||
|
||||
detail::to_stream(os, q);
|
||||
return os;
|
||||
return detail::to_stream(os, v);
|
||||
}
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
@ -682,12 +682,6 @@ inline constexpr bool space_before_unit_symbol<per_mille> = false;
|
||||
|
||||
// get_unit_symbol
|
||||
|
||||
enum class text_encoding : std::int8_t {
|
||||
unicode, // m³; µs
|
||||
ascii, // m^3; us
|
||||
default_encoding = unicode
|
||||
};
|
||||
|
||||
enum class unit_symbol_solidus : std::int8_t {
|
||||
one_denominator, // m/s; kg m⁻¹ s⁻¹
|
||||
always, // m/s; kg/(m s)
|
||||
@ -711,25 +705,6 @@ MP_UNITS_EXPORT_END
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename CharT, std::size_t N, std::size_t M, std::output_iterator<CharT> Out>
|
||||
constexpr Out copy(const basic_symbol_text<N, M>& txt, text_encoding encoding, Out out)
|
||||
{
|
||||
if (encoding == text_encoding::unicode) {
|
||||
if constexpr (is_same_v<CharT, char8_t>)
|
||||
return copy(txt.unicode(), out).out;
|
||||
else if constexpr (is_same_v<CharT, char>) {
|
||||
for (char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
|
||||
return out;
|
||||
} else
|
||||
throw std::invalid_argument("Unicode text can't be copied to CharT output");
|
||||
} else {
|
||||
if constexpr (is_same_v<CharT, char>)
|
||||
return copy(txt.ascii(), out).out;
|
||||
else
|
||||
throw std::invalid_argument("ASCII text can't be copied to CharT output");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out>
|
||||
constexpr Out print_separator(Out out, unit_symbol_formatting fmt)
|
||||
{
|
||||
@ -748,12 +723,7 @@ template<typename CharT, std::output_iterator<CharT> Out, Unit U>
|
||||
requires requires { U::symbol; }
|
||||
constexpr Out unit_symbol_impl(Out out, U, unit_symbol_formatting fmt, bool negative_power)
|
||||
{
|
||||
out = copy<CharT>(U::symbol, fmt.encoding, out);
|
||||
if (negative_power) {
|
||||
constexpr auto txt = superscript<-1>();
|
||||
out = copy<CharT>(txt, fmt.encoding, out);
|
||||
}
|
||||
return out;
|
||||
return copy_symbol<CharT>(U::symbol, fmt.encoding, negative_power, out);
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, auto M, typename U>
|
||||
@ -775,23 +745,7 @@ template<typename CharT, std::output_iterator<CharT> Out, typename F, int Num, i
|
||||
constexpr auto unit_symbol_impl(Out out, const power<F, Num, Den...>&, unit_symbol_formatting fmt, bool negative_power)
|
||||
{
|
||||
out = unit_symbol_impl<CharT>(out, F{}, fmt, false); // negative power component will be added below if needed
|
||||
|
||||
constexpr ratio r = power<F, Num, Den...>::exponent;
|
||||
if constexpr (r.den != 1) {
|
||||
// add root part
|
||||
constexpr auto txt =
|
||||
basic_symbol_text("^(") + regular<r.num>() + basic_symbol_text("/") + regular<r.den>() + basic_symbol_text(")");
|
||||
return copy<CharT>(txt, fmt.encoding, out);
|
||||
} else if constexpr (r.num != 1) {
|
||||
// add exponent part
|
||||
if (negative_power) {
|
||||
constexpr auto txt = superscript<-r.num>();
|
||||
return copy<CharT>(txt, fmt.encoding, out);
|
||||
} else {
|
||||
constexpr auto txt = superscript<r.num>();
|
||||
return copy<CharT>(txt, fmt.encoding, out);
|
||||
}
|
||||
}
|
||||
return copy_symbol_exponent<CharT, Num, Den...>(fmt.encoding, negative_power, out);
|
||||
}
|
||||
|
||||
template<typename CharT, std::output_iterator<CharT> Out, DerivedUnitExpr M>
|
||||
|
@ -38,6 +38,7 @@ add_library(
|
||||
# custom_rep_test_min_expl.cpp
|
||||
custom_rep_test_min_impl.cpp
|
||||
dimension_test.cpp
|
||||
dimension_symbol_test.cpp
|
||||
fixed_string_test.cpp
|
||||
fractional_exponent_quantity.cpp
|
||||
hep_test.cpp
|
||||
|
52
test/static/dimension_symbol_test.cpp
Normal file
52
test/static/dimension_symbol_test.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <mp-units/systems/isq/isq.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
using enum text_encoding;
|
||||
|
||||
static_assert(dimension_symbol(dimension_one) == "1");
|
||||
|
||||
// base dimensions
|
||||
static_assert(dimension_symbol(isq::dim_length) == "L");
|
||||
static_assert(dimension_symbol(isq::dim_thermodynamic_temperature) == "Θ");
|
||||
static_assert(dimension_symbol<dimension_symbol_formatting{.encoding = ascii}>(isq::dim_thermodynamic_temperature) ==
|
||||
"O");
|
||||
|
||||
// derived dimensions
|
||||
static_assert(dimension_symbol(isq::speed.dimension) == "LT⁻¹");
|
||||
static_assert(dimension_symbol<dimension_symbol_formatting{.encoding = ascii}>(isq::speed.dimension) == "LT^-1");
|
||||
static_assert(dimension_symbol(isq::power.dimension) == "L²MT⁻³");
|
||||
static_assert(dimension_symbol<dimension_symbol_formatting{.encoding = ascii}>(isq::power.dimension) == "L^2MT^-3");
|
||||
|
||||
static_assert(dimension_symbol(pow<123>(isq::dim_length)) == "L¹²³");
|
||||
static_assert(dimension_symbol(pow<1, 2>(isq::dim_length)) == "L^(1/2)");
|
||||
static_assert(dimension_symbol(pow<3, 5>(isq::dim_length)) == "L^(3/5)");
|
||||
static_assert(dimension_symbol(pow<123>(isq::speed.dimension)) == "L¹²³T⁻¹²³");
|
||||
static_assert(dimension_symbol(pow<1, 2>(isq::speed.dimension)) == "L^(1/2)T^-(1/2)");
|
||||
static_assert(dimension_symbol(pow<3, 5>(isq::speed.dimension)) == "L^(3/5)T^-(3/5)");
|
||||
|
||||
} // namespace
|
@ -30,8 +30,6 @@ using namespace mp_units;
|
||||
using namespace mp_units::si;
|
||||
using namespace mp_units::iec80000;
|
||||
|
||||
#if __cpp_lib_constexpr_string && (!defined MP_UNITS_COMP_GCC || MP_UNITS_COMP_GCC > 11)
|
||||
|
||||
using enum text_encoding;
|
||||
using enum unit_symbol_solidus;
|
||||
using enum unit_symbol_separator;
|
||||
@ -178,6 +176,7 @@ static_assert(unit_symbol(pow<123>(metre)) == "m¹²³");
|
||||
static_assert(unit_symbol(pow<1, 2>(metre)) == "m^(1/2)");
|
||||
static_assert(unit_symbol(pow<3, 5>(metre)) == "m^(3/5)");
|
||||
static_assert(unit_symbol(pow<1, 2>(metre / second)) == "m^(1/2)/s^(1/2)");
|
||||
static_assert(unit_symbol<unit_symbol_formatting{.solidus = never}>(pow<1, 2>(metre / second)) == "m^(1/2) s^-(1/2)");
|
||||
|
||||
// dimensionless unit
|
||||
static_assert(unit_symbol(radian) == "rad");
|
||||
@ -188,6 +187,4 @@ static_assert(unit_symbol(gram * standard_gravity * si2019::speed_of_light_in_va
|
||||
static_assert(unit_symbol(gram / standard_gravity) == "g/g₀");
|
||||
static_assert(unit_symbol(kilo<metre> / second / mega<iau::parsec>) == "km Mpc⁻¹ s⁻¹");
|
||||
|
||||
#endif // __cpp_lib_constexpr_string
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user