added ASCII character validation; added ASCII-only superscripts, scientific notation, dot product

This commit is contained in:
Ramzi Sabra
2020-03-26 10:29:32 +02:00
committed by Mateusz Pusz
parent c610b04904
commit e0263c554d
5 changed files with 67 additions and 19 deletions

View File

@@ -45,7 +45,7 @@ constexpr auto operator_text()
return basic_fixed_string("/");
}
else {
return basic_fixed_string("");
return basic_symbol_text("", ".");
}
}
}

View File

@@ -23,6 +23,7 @@
#pragma once
#include <units/bits/external/fixed_string.h>
#include <units/symbol_text.h>
namespace units::detail {
@@ -41,26 +42,34 @@ template<> inline constexpr basic_fixed_string superscript_number<7> = "\u2077";
template<> inline constexpr basic_fixed_string superscript_number<8> = "\u2078";
template<> inline constexpr basic_fixed_string superscript_number<9> = "\u2079";
inline constexpr basic_fixed_string superscript_minus = "\u207b";
inline constexpr basic_symbol_text superscript_minus("\u207b", "-");
inline constexpr basic_symbol_text superscript_prefix("", "^");
template<std::intmax_t Value>
constexpr auto superscript_helper()
{
if constexpr(Value < 0)
return superscript_minus + superscript_helper<-Value>();
else if constexpr(Value < 10)
return basic_symbol_text(superscript_number<Value>, basic_fixed_string(static_cast<char>('0' + Value)));
else
return superscript_helper<Value / 10>() + superscript_helper<Value % 10>();
}
template<std::intmax_t Value>
constexpr auto superscript()
{
if constexpr(Value < 0)
return superscript_minus + superscript<-Value>();
else if constexpr(Value < 10)
return superscript_number<Value>;
else
return superscript<Value / 10>() + superscript<Value % 10>();
return superscript_prefix + superscript_helper<Value>();
}
template<std::intmax_t Value>
constexpr auto regular()
{
if constexpr (Value < 0)
return basic_fixed_string("-") + superscript<-Value>();
return basic_fixed_string("-") + superscript_helper<-Value>();
else if constexpr (Value < 10)
return basic_fixed_string(static_cast<char>('0' + Value));
return basic_symbol_text(static_cast<char>('0' + Value));
else
return regular<Value / 10>() + regular<Value % 10>();
}

View File

@@ -30,11 +30,13 @@
namespace units::detail {
inline constexpr basic_symbol_text base_multiplier("\u00D7 10", "x 10");
template<typename Ratio>
constexpr auto ratio_text()
{
if constexpr(Ratio::num == 1 && Ratio::den == 1 && Ratio::exp != 0) {
return basic_fixed_string("\u00D7 10") + superscript<Ratio::exp>() + basic_fixed_string(" ");
return base_multiplier + superscript<Ratio::exp>() + basic_fixed_string(" ");
}
else if constexpr(Ratio::num != 1 || Ratio::den != 1 || Ratio::exp != 0) {
auto txt = basic_fixed_string("[") + regular<Ratio::num>();
@@ -43,7 +45,7 @@ constexpr auto ratio_text()
return txt + basic_fixed_string("] ");
}
else {
return txt + basic_fixed_string(" \u00D7 10") + superscript<Ratio::exp>() +
return txt + " " + base_multiplier + superscript<Ratio::exp>() +
basic_fixed_string("] ");
}
}
@@ -54,7 +56,7 @@ constexpr auto ratio_text()
}
else {
return txt + basic_fixed_string("/") + regular<Ratio::den>() +
basic_fixed_string(" \u00D7 10") + superscript<Ratio::exp>() +
" " + base_multiplier + superscript<Ratio::exp>() +
basic_fixed_string("] ");
}
}

View File

@@ -10,12 +10,21 @@ struct basic_symbol_text {
basic_fixed_string<StandardCharT, N> standard_;
basic_fixed_string<char, M> ascii_;
constexpr basic_symbol_text(StandardCharT s) noexcept: standard_(s), ascii_(s) {}
constexpr basic_symbol_text(StandardCharT s, char a) noexcept: standard_(s), ascii_(a) {}
constexpr basic_symbol_text(const StandardCharT (&s)[N + 1]) noexcept: standard_(s), ascii_(s) {}
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s) noexcept: standard_(s), ascii_(s) {}
constexpr basic_symbol_text(const StandardCharT (&s)[N + 1], const StandardCharT (&a)[M + 1]) noexcept: standard_(s), ascii_(a) {}
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s, const basic_fixed_string<char, M>& a) noexcept: standard_(s), ascii_(a) {}
constexpr void validate_ascii_char(char c) noexcept { assert((c & 0x80) == 0); }
template<std::size_t P>
constexpr void validate_ascii_string(const char (&s)[P + 1]) noexcept
{
for (size_t i = 0; i < P; ++i)
validate_ascii_char(s[i]);
}
constexpr basic_symbol_text(StandardCharT s) noexcept: standard_(s), ascii_(s) { validate_ascii_char(s); }
constexpr basic_symbol_text(StandardCharT s, char a) noexcept: standard_(s), ascii_(a) { validate_ascii_char(a); }
constexpr basic_symbol_text(const StandardCharT (&s)[N + 1]) noexcept: standard_(s), ascii_(s) { validate_ascii_string<N>(s); }
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s) noexcept: standard_(s), ascii_(s) { validate_ascii_string<N>(s.data_); }
constexpr basic_symbol_text(const StandardCharT (&s)[N + 1], const char (&a)[M + 1]) noexcept: standard_(s), ascii_(a) { validate_ascii_string<M>(a); }
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& s, const basic_fixed_string<char, M>& a) noexcept: standard_(s), ascii_(a) { validate_ascii_string<M>(a.data_); }
[[nodiscard]] constexpr auto& standard() { return standard_; }
[[nodiscard]] constexpr const auto& standard() const { return standard_; }

View File

@@ -56,6 +56,8 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
CHECK(fmt::format("{}", 1q_ns) == "1 ns");
CHECK(fmt::format("{}", 1q_us) == "1 µs");
CHECK(fmt::format("{}", 1q_ms) == "1 ms");
CHECK(fmt::format("{:%Q %Aq}", 1q_us) == "1 us");
}
SECTION("length")
@@ -98,11 +100,18 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
CHECK(fmt::format("{}", 1q_cm2) == "1 cm²");
CHECK(fmt::format("{}", 1q_km2) == "1 km²");
CHECK(fmt::format("{}", 1q_ft2) == "1 ft²");
CHECK(fmt::format("{:%Q %Aq}", 1q_m2) == "1 m^2");
CHECK(fmt::format("{:%Q %Aq}", 1q_mm2) == "1 mm^2");
CHECK(fmt::format("{:%Q %Aq}", 1q_cm2) == "1 cm^2");
CHECK(fmt::format("{:%Q %Aq}", 1q_km2) == "1 km^2");
CHECK(fmt::format("{:%Q %Aq}", 1q_ft2) == "1 ft^2");
}
SECTION("density")
{
CHECK(fmt::format("{}", 1q_kg_per_m3) == "1 kg/m³");
CHECK(fmt::format("{:%Q %Aq}", 1q_kg_per_m3) == "1 kg/m^3");
}
SECTION("resistance")
@@ -111,6 +120,11 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
CHECK(fmt::format("{}", 1q_kR) == "1 kΩ");
CHECK(fmt::format("{}", 1q_mR) == "1 mΩ");
CHECK(fmt::format("{}", 1q_MR) == "1 MΩ");
CHECK(fmt::format("{:%Q %Aq}", 1q_R) == "1 ohm");
CHECK(fmt::format("{:%Q %Aq}", 1q_kR) == "1 kohm");
CHECK(fmt::format("{:%Q %Aq}", 1q_mR) == "1 mohm");
CHECK(fmt::format("{:%Q %Aq}", 1q_MR) == "1 Mohm");
}
SECTION("voltage")
@@ -120,6 +134,8 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
CHECK(fmt::format("{}", 1q_uV) == "1 µV");
CHECK(fmt::format("{}", 1q_nV) == "1 nV");
CHECK(fmt::format("{}", 1q_pV) == "1 pV");
CHECK(fmt::format("{:%Q %Aq}", 1q_uV) == "1 uV");
}
SECTION("volume")
@@ -129,6 +145,12 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
CHECK(fmt::format("{}", 1q_cm3) == "1 cm³");
CHECK(fmt::format("{}", 1q_km3) == "1 km³");
CHECK(fmt::format("{}", 1q_ft3) == "1 ft³");
CHECK(fmt::format("{:%Q %Aq}", 1q_m3) == "1 m^3");
CHECK(fmt::format("{:%Q %Aq}", 1q_mm3) == "1 mm^3");
CHECK(fmt::format("{:%Q %Aq}", 1q_cm3) == "1 cm^3");
CHECK(fmt::format("{:%Q %Aq}", 1q_km3) == "1 km^3");
CHECK(fmt::format("{:%Q %Aq}", 1q_ft3) == "1 ft^3");
}
SECTION("frequency")
@@ -150,11 +172,13 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
SECTION("acceleration")
{
CHECK(fmt::format("{}", 1q_m_per_s2) == "1 m/s²");
CHECK(fmt::format("{:%Q %Aq}", 1q_m_per_s2) == "1 m/s^2");
}
SECTION("momentum")
{
CHECK(fmt::format("{}", 1q_kg_m_per_s) == "1 kg⋅m/s");
CHECK(fmt::format("{:%Q %Aq}", 1q_kg_m_per_s) == "1 kg.m/s");
}
SECTION("energy")
@@ -187,10 +211,14 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
{
CHECK(fmt::format("{}", 1q_mi * 1q_mi * 1q_mi) == "1 [15900351812136/3814697265625 × 10⁹] m³");
CHECK(fmt::format("{}", 1q_au * 1q_au) == "1 [2237952291797391849 × 10⁴] m²");
CHECK(fmt::format("{:%Q %Aq}", 1q_mi * 1q_mi * 1q_mi) == "1 [15900351812136/3814697265625 x 10^9] m^3");
CHECK(fmt::format("{:%Q %Aq}", 1q_au * 1q_au) == "1 [2237952291797391849 x 10^4] m^2");
}
SECTION("unknown scaled unit with reference different than the dimension's coherent unit")
{
CHECK(fmt::format("{}", mass<units::scaled_unit<units::ratio<2, 3>, gram>>(1)) == "1 [2/3 × 10⁻³] kg");
CHECK(fmt::format("{:%Q %Aq}", mass<units::scaled_unit<units::ratio<2, 3>, gram>>(1)) == "1 [2/3 x 10^-3] kg");
}
}