refactor: 💥 ascii -> portable, unicode -> utf8, 'A' -> 'P'

This commit is contained in:
Mateusz Pusz
2024-10-10 00:02:08 +02:00
parent cb424a79c0
commit 4eb63227e2
13 changed files with 158 additions and 150 deletions
+6 -6
View File
@@ -98,19 +98,19 @@ template<std::intmax_t Value>
template<typename CharT, std::size_t N, std::size_t M, std::output_iterator<CharT> Out>
constexpr Out copy(const symbol_text<N, M>& txt, text_encoding encoding, Out out)
{
if (encoding == text_encoding::unicode) {
if (encoding == text_encoding::utf8) {
if constexpr (is_same_v<CharT, char8_t>)
return ::mp_units::detail::copy(txt.unicode().begin(), txt.unicode().end(), out);
return ::mp_units::detail::copy(txt.utf8().begin(), txt.utf8().end(), out);
else if constexpr (is_same_v<CharT, char>) {
for (const char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
for (const char8_t ch : txt.utf8()) *out++ = static_cast<char>(ch);
return out;
} else
MP_UNITS_THROW(std::invalid_argument("Unicode text can't be copied to CharT output"));
MP_UNITS_THROW(std::invalid_argument("UTF-8 text can't be copied to CharT output"));
} else {
if constexpr (is_same_v<CharT, char>)
return ::mp_units::detail::copy(txt.ascii().begin(), txt.ascii().end(), out);
return ::mp_units::detail::copy(txt.portable().begin(), txt.portable().end(), out);
else
MP_UNITS_THROW(std::invalid_argument("ASCII text can't be copied to CharT output"));
MP_UNITS_THROW(std::invalid_argument("Portable text can't be copied to CharT output"));
}
}
+11 -9
View File
@@ -112,7 +112,7 @@ MP_UNITS_EXPORT_END
//
// dimension-format-spec = [fill-and-align], [width], [dimension-spec];
// dimension-spec = [text-encoding];
// text-encoding = 'U' | 'A';
// text-encoding = 'U' | 'P';
//
template<mp_units::Dimension D, typename Char>
class MP_UNITS_STD_FMT::formatter<D, Char> {
@@ -126,15 +126,16 @@ class MP_UNITS_STD_FMT::formatter<D, Char> {
auto it = begin;
if (it == end || *it == '}') return begin;
constexpr auto valid_modifiers = std::string_view{"UA"};
constexpr auto valid_modifiers = std::string_view{"UP"};
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)
specs_.encoding = (*it == 'U') ? mp_units::text_encoding::unicode : mp_units::text_encoding::ascii;
if (it = mp_units::detail::at_most_one_of(begin, end, "UAP"); it != end)
// TODO 'A' stands for an old and deprecated ASCII encoding
specs_.encoding = (*it == 'U') ? mp_units::text_encoding::utf8 : mp_units::text_encoding::portable;
return end;
}
@@ -198,15 +199,16 @@ class MP_UNITS_STD_FMT::formatter<U, Char> {
auto it = begin;
if (it == end || *it == '}') return begin;
constexpr auto valid_modifiers = std::string_view{"UA1ansd"};
constexpr auto valid_modifiers = std::string_view{"UAP1ansd"};
for (; it != end && *it != '}'; ++it) {
if (valid_modifiers.find(*it) == std::string_view::npos)
throw MP_UNITS_STD_FMT::format_error("invalid unit modifier specified");
}
end = it;
if (it = mp_units::detail::at_most_one_of(begin, end, "UA"); it != end)
specs_.encoding = (*it == 'U') ? mp_units::text_encoding::unicode : mp_units::text_encoding::ascii;
if (it = mp_units::detail::at_most_one_of(begin, end, "UAP"); it != end)
// TODO 'A' stands for an old and deprecated ASCII encoding
specs_.encoding = (*it == 'U') ? mp_units::text_encoding::utf8 : mp_units::text_encoding::portable;
if (it = mp_units::detail::at_most_one_of(begin, end, "1an"); it != end) {
switch (*it) {
case '1':
@@ -221,8 +223,8 @@ class MP_UNITS_STD_FMT::formatter<U, Char> {
}
}
if (it = mp_units::detail::at_most_one_of(begin, end, "sd"); it != end) {
if (*it == 'd' && specs_.encoding == mp_units::text_encoding::ascii)
throw MP_UNITS_STD_FMT::format_error("half_high_dot unit separator allowed only for Unicode encoding");
if (*it == 'd' && specs_.encoding == mp_units::text_encoding::portable)
throw MP_UNITS_STD_FMT::format_error("half_high_dot unit separator allowed only for UTF-8 encoding");
specs_.separator =
(*it == 's') ? mp_units::unit_symbol_separator::space : mp_units::unit_symbol_separator::half_high_dot;
}
@@ -310,9 +310,9 @@ template<typename CharT, std::output_iterator<CharT> Out>
constexpr Out print_separator(Out out, const unit_symbol_formatting& fmt)
{
if (fmt.separator == unit_symbol_separator::half_high_dot) {
if (fmt.encoding != text_encoding::unicode)
if (fmt.encoding != text_encoding::utf8)
MP_UNITS_THROW(
std::invalid_argument("'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::unicode'"));
std::invalid_argument("'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::utf8'"));
const std::string_view dot = "⋅";
out = detail::copy(dot.begin(), dot.end(), out);
} else {
@@ -56,9 +56,11 @@ namespace mp_units {
// NOLINTNEXTLINE(readability-enum-initial-value)
MP_UNITS_EXPORT enum class text_encoding : std::int8_t {
unicode, // µs; m³; L²MT⁻³
ascii, // us; m^3; L^2MT^-3
default_encoding = unicode
utf8, // µs; m³; L²MT⁻³
unicode [[deprecated("Use `utf8` instead")]] = utf8,
portable, // us; m^3; L^2MT^-3
ascii [[deprecated("Use `portable` instead")]] = portable,
default_encoding = utf8
};
namespace detail {
@@ -89,65 +91,67 @@ constexpr fixed_u8string<N> to_u8string(fixed_string<N> txt)
*
* This class template is responsible for definition and handling of a symbol text
* representation. In the libary it is used to define symbols of units and prefixes.
* Each symbol can have two versions: Unicode and ASCI-only.
* Each symbol can have two versions: UTF-8 and portable.
*
* @tparam N The size of a Unicode symbol
* @tparam M The size of the ASCII-only symbol
* @tparam N The size of a UTF-8 symbol
* @tparam M The size of the portable symbol
*/
MP_UNITS_EXPORT template<std::size_t N, std::size_t M>
class symbol_text {
public:
fixed_u8string<N> unicode_;
fixed_string<M> ascii_;
fixed_u8string<N> utf8_;
fixed_string<M> portable_;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(false) symbol_text(char ch) : unicode_(static_cast<char8_t>(ch)), ascii_(ch)
constexpr explicit(false) symbol_text(char ch) : utf8_(static_cast<char8_t>(ch)), portable_(ch)
{
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set_char(ch));
}
// NOLINTNEXTLINE(*-avoid-c-arrays, google-explicit-constructor, hicpp-explicit-conversions)
consteval explicit(false) symbol_text(const char (&txt)[N + 1]) :
unicode_(detail::to_u8string(basic_fixed_string{txt})), ascii_(txt)
utf8_(detail::to_u8string(basic_fixed_string{txt})), portable_(txt)
{
MP_UNITS_EXPECTS(txt[N] == char{});
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(txt));
}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(false) symbol_text(const fixed_string<N>& txt) : unicode_(detail::to_u8string(txt)), ascii_(txt)
constexpr explicit(false) symbol_text(const fixed_string<N>& txt) : utf8_(detail::to_u8string(txt)), portable_(txt)
{
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(txt.data_));
}
// NOLINTNEXTLINE(*-avoid-c-arrays)
consteval symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
consteval symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : utf8_(u), portable_(a)
{
MP_UNITS_EXPECTS(u[N] == char8_t{});
MP_UNITS_EXPECTS(a[M] == char{});
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(a));
}
constexpr symbol_text(const fixed_u8string<N>& unicode, const fixed_string<M>& ascii) :
unicode_(unicode), ascii_(ascii)
constexpr symbol_text(const fixed_u8string<N>& utf8, const fixed_string<M>& portable) :
utf8_(utf8), portable_(portable)
{
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(ascii.data_));
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(portable.data_));
}
[[nodiscard]] constexpr const auto& unicode() const { return unicode_; }
[[nodiscard]] constexpr const auto& ascii() const { return ascii_; }
[[nodiscard]] constexpr const auto& utf8() const { return utf8_; }
[[nodiscard]] constexpr const auto& portable() const { return portable_; }
[[deprecated("Use `utf8()` instead")]] constexpr const auto& unicode() const { return utf8(); }
[[deprecated("Use `portable()` instead")]] constexpr const auto& ascii() const { return portable(); }
[[nodiscard]] constexpr bool empty() const
{
MP_UNITS_ASSERT_DEBUG(unicode().empty() == ascii().empty());
return unicode().empty();
MP_UNITS_ASSERT_DEBUG(utf8().empty() == portable().empty());
return utf8().empty();
}
template<std::size_t N2, std::size_t M2>
[[nodiscard]] constexpr friend symbol_text<N + N2, M + M2> operator+(const symbol_text& lhs,
const symbol_text<N2, M2>& rhs)
{
return symbol_text<N + N2, M + M2>(lhs.unicode() + rhs.unicode(), lhs.ascii() + rhs.ascii());
return symbol_text<N + N2, M + M2>(lhs.utf8() + rhs.utf8(), lhs.portable() + rhs.portable());
}
template<std::size_t N2, std::size_t M2>
@@ -155,15 +159,15 @@ public:
{
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_ZERO_AS_NULLPOINTER_CONSTANT
if (const auto cmp = lhs.unicode() <=> rhs.unicode(); cmp != 0) return cmp;
if (const auto cmp = lhs.utf8() <=> rhs.utf8(); cmp != 0) return cmp;
MP_UNITS_DIAGNOSTIC_POP
return lhs.ascii() <=> rhs.ascii();
return lhs.portable() <=> rhs.portable();
}
template<std::size_t N2, std::size_t M2>
[[nodiscard]] friend constexpr bool operator==(const symbol_text& lhs, const symbol_text<N2, M2>& rhs) noexcept
{
return lhs.unicode() == rhs.unicode() && lhs.ascii() == rhs.ascii();
return lhs.utf8() == rhs.utf8() && lhs.portable() == rhs.portable();
}
};
@@ -48,7 +48,7 @@ enum class unit_symbol_solidus : std::int8_t {
// NOLINTNEXTLINE(readability-enum-initial-value)
enum class unit_symbol_separator : std::int8_t {
space, // kg m²/s²
half_high_dot, // kg⋅m²/s² (valid only for unicode encoding)
half_high_dot, // kg⋅m²/s² (valid only for utf8 encoding)
default_separator = space
};