feat: ABI concerns resolved with introduction of u8 strings for symbols
This commit is contained in:
1 parent
54dbeea68b
commit
cb858f1e51
18 files changed
+112
-93
No files matched your search
@@ -143,6 +143,9 @@ basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) ->
|
||||
template<std::size_t N>
|
||||
using fixed_string = basic_fixed_string<char, N>;
|
||||
|
||||
template<std::size_t N>
|
||||
using fixed_u8string = basic_fixed_string<char8_t, N>;
|
||||
|
||||
} // namespace mp_units
|
||||
|
||||
template<typename CharT, std::size_t N>
|
||||
|
||||
@@ -850,7 +850,7 @@ template<typename T, auto... Ms>
|
||||
return integer_part((detail::abs(power_of_2) < detail::abs(power_of_5)) ? power_of_2 : power_of_5);
|
||||
}
|
||||
|
||||
inline constexpr basic_symbol_text base_multiplier("× 10", "x 10");
|
||||
inline constexpr basic_symbol_text base_multiplier(u8"× 10", "x 10");
|
||||
|
||||
template<Magnitude auto M>
|
||||
[[nodiscard]] consteval auto magnitude_text()
|
||||
|
||||
@@ -32,11 +32,21 @@
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
|
||||
#if __cpp_lib_text_encoding
|
||||
#include <text_encoding>
|
||||
static_assert(std::text_encoding::literal().mib() == std::text_encoding::id::UTF8);
|
||||
#endif
|
||||
|
||||
namespace mp_units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr void validate_ascii_char([[maybe_unused]] char c) noexcept { gsl_Expects((c & 0x80) == 0); }
|
||||
constexpr void validate_ascii_char([[maybe_unused]] char c) noexcept
|
||||
{
|
||||
// check if character belongs to basic character literal set
|
||||
// https://en.cppreference.com/w/cpp/language/charset
|
||||
gsl_Expects(c == 0x00 || (0x07 <= c && c <= 0x0D) || (0x20 <= c && c <= 0x7E));
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr void validate_ascii_string([[maybe_unused]] const char (&s)[N + 1]) noexcept
|
||||
@@ -47,6 +57,12 @@ constexpr void validate_ascii_string([[maybe_unused]] const char (&s)[N + 1]) no
|
||||
#endif
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr fixed_u8string<N> to_u8string(fixed_string<N> txt)
|
||||
{
|
||||
return std::bit_cast<fixed_u8string<N>>(txt);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -57,37 +73,37 @@ constexpr void validate_ascii_string([[maybe_unused]] const char (&s)[N + 1]) no
|
||||
* representation. In the libary it is used to define symbols of units and prefixes.
|
||||
* Each symbol can have two versions: Unicode and ASCI-only.
|
||||
*
|
||||
* @tparam UnicodeCharT Character type to be used for a Unicode representation
|
||||
* @tparam N The size of a Unicode symbol
|
||||
* @tparam M The size of the ASCII-only symbol
|
||||
*/
|
||||
template<typename UnicodeCharT, std::size_t N, std::size_t M>
|
||||
template<std::size_t N, std::size_t M>
|
||||
struct basic_symbol_text {
|
||||
basic_fixed_string<UnicodeCharT, N> unicode_;
|
||||
basic_fixed_string<char, M> ascii_;
|
||||
fixed_u8string<N> unicode_;
|
||||
fixed_string<M> ascii_;
|
||||
|
||||
constexpr explicit(false) basic_symbol_text(char txt) : unicode_(txt), ascii_(txt)
|
||||
constexpr explicit(false) basic_symbol_text(char txt) : unicode_(static_cast<char8_t>(txt)), ascii_(txt)
|
||||
{
|
||||
detail::validate_ascii_char(txt);
|
||||
}
|
||||
|
||||
constexpr explicit(false) basic_symbol_text(const char (&txt)[N + 1]) : unicode_(txt), ascii_(txt)
|
||||
constexpr explicit(false) basic_symbol_text(const char (&txt)[N + 1]) :
|
||||
unicode_(detail::to_u8string(basic_fixed_string{txt})), ascii_(txt)
|
||||
{
|
||||
detail::validate_ascii_string<N>(txt);
|
||||
}
|
||||
|
||||
constexpr explicit(false) basic_symbol_text(const basic_fixed_string<char, N>& txt) : unicode_(txt), ascii_(txt)
|
||||
constexpr explicit(false) basic_symbol_text(const fixed_string<N>& txt) :
|
||||
unicode_(detail::to_u8string(txt)), ascii_(txt)
|
||||
{
|
||||
detail::validate_ascii_string<N>(txt.data_);
|
||||
}
|
||||
|
||||
constexpr basic_symbol_text(const UnicodeCharT (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
|
||||
constexpr basic_symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
|
||||
{
|
||||
detail::validate_ascii_string<M>(a);
|
||||
}
|
||||
|
||||
constexpr basic_symbol_text(const basic_fixed_string<UnicodeCharT, N>& u, const basic_fixed_string<char, M>& a) :
|
||||
unicode_(u), ascii_(a)
|
||||
constexpr basic_symbol_text(const fixed_u8string<N>& u, const fixed_string<M>& a) : unicode_(u), ascii_(a)
|
||||
{
|
||||
detail::validate_ascii_string<M>(a.data_);
|
||||
}
|
||||
@@ -98,15 +114,15 @@ struct basic_symbol_text {
|
||||
[[nodiscard]] constexpr bool empty() const { return unicode().empty() && ascii().empty(); }
|
||||
|
||||
template<std::size_t N2, std::size_t M2>
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<UnicodeCharT, N + N2, M + M2> operator+(
|
||||
const basic_symbol_text& lhs, const basic_symbol_text<UnicodeCharT, N2, M2>& rhs)
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<N + N2, M + M2> operator+(const basic_symbol_text& lhs,
|
||||
const basic_symbol_text<N2, M2>& rhs)
|
||||
{
|
||||
return basic_symbol_text<UnicodeCharT, N + N2, M + M2>(lhs.unicode() + rhs.unicode(), lhs.ascii() + rhs.ascii());
|
||||
return basic_symbol_text<N + N2, M + M2>(lhs.unicode() + rhs.unicode(), lhs.ascii() + rhs.ascii());
|
||||
}
|
||||
|
||||
template<typename UnicodeCharT2, std::size_t N2, std::size_t M2>
|
||||
template<std::size_t N2, std::size_t M2>
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const basic_symbol_text& lhs,
|
||||
const basic_symbol_text<UnicodeCharT2, N2, M2>& rhs) noexcept
|
||||
const basic_symbol_text<N2, M2>& rhs) noexcept
|
||||
{
|
||||
MP_UNITS_DIAGNOSTIC_PUSH
|
||||
MP_UNITS_DIAGNOSTIC_IGNORE_ZERO_AS_NULLPOINTER_CONSTANT
|
||||
@@ -115,27 +131,26 @@ struct basic_symbol_text {
|
||||
return lhs.ascii() <=> rhs.ascii();
|
||||
}
|
||||
|
||||
template<typename UnicodeCharT2, std::size_t N2, std::size_t M2>
|
||||
template<std::size_t N2, std::size_t M2>
|
||||
[[nodiscard]] friend constexpr bool operator==(const basic_symbol_text& lhs,
|
||||
const basic_symbol_text<UnicodeCharT2, N2, M2>& rhs) noexcept
|
||||
const basic_symbol_text<N2, M2>& rhs) noexcept
|
||||
{
|
||||
return lhs.unicode() == rhs.unicode() && lhs.ascii() == rhs.ascii();
|
||||
}
|
||||
};
|
||||
|
||||
basic_symbol_text(char) -> basic_symbol_text<char, 1, 1>;
|
||||
basic_symbol_text(char) -> basic_symbol_text<1, 1>;
|
||||
|
||||
template<std::size_t N>
|
||||
basic_symbol_text(const char (&)[N]) -> basic_symbol_text<char, N - 1, N - 1>;
|
||||
basic_symbol_text(const char (&)[N]) -> basic_symbol_text<N - 1, N - 1>;
|
||||
|
||||
template<std::size_t N>
|
||||
basic_symbol_text(const basic_fixed_string<char, N>&) -> basic_symbol_text<char, N, N>;
|
||||
basic_symbol_text(const fixed_string<N>&) -> basic_symbol_text<N, N>;
|
||||
|
||||
template<typename UnicodeCharT, std::size_t N, std::size_t M>
|
||||
basic_symbol_text(const UnicodeCharT (&)[N], const char (&)[M]) -> basic_symbol_text<UnicodeCharT, N - 1, M - 1>;
|
||||
template<std::size_t N, std::size_t M>
|
||||
basic_symbol_text(const char8_t (&)[N], const char (&)[M]) -> basic_symbol_text<N - 1, M - 1>;
|
||||
|
||||
template<typename UnicodeCharT, std::size_t N, std::size_t M>
|
||||
basic_symbol_text(const basic_fixed_string<UnicodeCharT, N>&, const basic_fixed_string<char, M>&)
|
||||
-> basic_symbol_text<UnicodeCharT, N, M>;
|
||||
template<std::size_t N, std::size_t M>
|
||||
basic_symbol_text(const fixed_u8string<N>&, const fixed_string<M>&) -> basic_symbol_text<N, M>;
|
||||
|
||||
} // namespace mp_units
|
||||
@@ -29,32 +29,32 @@ namespace mp_units::detail {
|
||||
|
||||
template<std::intmax_t Value>
|
||||
requires(0 <= Value) && (Value < 10)
|
||||
inline constexpr basic_fixed_string superscript_number = "";
|
||||
inline constexpr basic_fixed_string superscript_number = u8"";
|
||||
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<0> = "\u2070";
|
||||
inline constexpr basic_fixed_string superscript_number<0> = u8"\u2070";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<1> = "\u00b9";
|
||||
inline constexpr basic_fixed_string superscript_number<1> = u8"\u00b9";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<2> = "\u00b2";
|
||||
inline constexpr basic_fixed_string superscript_number<2> = u8"\u00b2";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<3> = "\u00b3";
|
||||
inline constexpr basic_fixed_string superscript_number<3> = u8"\u00b3";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<4> = "\u2074";
|
||||
inline constexpr basic_fixed_string superscript_number<4> = u8"\u2074";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<5> = "\u2075";
|
||||
inline constexpr basic_fixed_string superscript_number<5> = u8"\u2075";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<6> = "\u2076";
|
||||
inline constexpr basic_fixed_string superscript_number<6> = u8"\u2076";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<7> = "\u2077";
|
||||
inline constexpr basic_fixed_string superscript_number<7> = u8"\u2077";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<8> = "\u2078";
|
||||
inline constexpr basic_fixed_string superscript_number<8> = u8"\u2078";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<9> = "\u2079";
|
||||
inline constexpr basic_fixed_string superscript_number<9> = u8"\u2079";
|
||||
|
||||
inline constexpr basic_symbol_text superscript_minus("\u207b", "-");
|
||||
inline constexpr basic_symbol_text superscript_minus(u8"\u207b", "-");
|
||||
|
||||
inline constexpr basic_symbol_text superscript_prefix("", "^");
|
||||
inline constexpr basic_symbol_text superscript_prefix(u8"", "^");
|
||||
|
||||
template<std::intmax_t Value>
|
||||
[[nodiscard]] consteval auto superscript_helper()
|
||||
|
||||
@@ -92,7 +92,7 @@ inline constexpr bool is_specialization_of_scaled_unit<scaled_unit<M, U>> = true
|
||||
* inline constexpr struct metre : named_unit<"m", length> {} metre;
|
||||
* inline constexpr struct hertz : named_unit<"Hz", inverse(second)> {} hertz;
|
||||
* inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
|
||||
* inline constexpr struct degree_Celsius : named_unit<basic_symbol_text{"°C", "`C"}, kelvin> {} degree_Celsius;
|
||||
* inline constexpr struct degree_Celsius : named_unit<{u8"°C", "`C"}, kelvin> {} degree_Celsius;
|
||||
* inline constexpr struct minute : named_unit<"min", mag<60> * second> {} minute;
|
||||
* @endcode
|
||||
*
|
||||
@@ -604,7 +604,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
// common dimensionless units
|
||||
// clang-format off
|
||||
inline constexpr struct percent : named_unit<"%", mag<ratio{1, 100}> * one> {} percent;
|
||||
inline constexpr struct per_mille : named_unit<basic_symbol_text{"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
|
||||
inline constexpr struct per_mille : named_unit<basic_symbol_text{u8"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
|
||||
inline constexpr struct parts_per_million : named_unit<"ppm", mag<ratio(1, 1'000'000)> * one> {} parts_per_million;
|
||||
inline constexpr auto ppm = parts_per_million;
|
||||
// clang-format on
|
||||
@@ -699,17 +699,19 @@ struct unit_symbol_formatting {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// TODO Should `basic_symbol_text` be fixed to use `char` type for both encodings?
|
||||
template<typename CharT, typename UnicodeCharT, std::size_t N, std::size_t M, std::output_iterator<CharT> Out>
|
||||
constexpr Out copy(const basic_symbol_text<UnicodeCharT, N, M>& txt, text_encoding encoding, Out out)
|
||||
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 (is_same_v<CharT, UnicodeCharT>)
|
||||
if constexpr (is_same_v<CharT, char8_t>)
|
||||
return copy(txt.unicode(), out).out;
|
||||
else
|
||||
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 (is_same_v<CharT, char>)
|
||||
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");
|
||||
|
||||
Reference in new issue
Block a user