feat: ABI concerns resolved with introduction of u8 strings for symbols

This commit is contained in:
Mateusz Pusz committed 2024-02-16 22:13:13 +01:00
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>
+1 -1
View File
@@ -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()
+41 -26
View File
@@ -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
+13 -13
View File
@@ -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()
+10 -8
View File
@@ -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");