35 while (i < text.size())
37 const auto b0 =
static_cast<std::uint8_t
>(text[i]);
40 if (b0 < 0x80U) { ++i;
continue; }
41 if ((b0 & 0xE0U) == 0xC0U) { len = 2; cp = b0 & 0x1FU; }
42 else if ((b0 & 0xF0U) == 0xE0U) { len = 3; cp = b0 & 0x0FU; }
43 else if ((b0 & 0xF8U) == 0xF0U) { len = 4; cp = b0 & 0x07U; }
45 if (i + len > text.size())
return i;
46 for (std::size_t k = 1; k < len; ++k)
48 const auto b =
static_cast<std::uint8_t
>(text[i + k]);
49 if ((b & 0xC0U) != 0x80U)
return i;
50 cp = (cp << 6U) | (b & 0x3FU);
52 const bool overlong = (len == 2 && cp < 0x80U) ||
53 (len == 3 && cp < 0x800U) ||
54 (len == 4 && cp < 0x10000U);
55 if (overlong || (cp >= 0xD800U && cp <= 0xDFFFU) || cp > 0x10FFFFU)
61 return std::string_view::npos;
77[[nodiscard]]
inline std::string
to_utf8(std::wstring_view text)
80 out.reserve(text.size());
81 for (std::size_t i = 0; i < text.size(); ++i)
83 auto cp =
static_cast<std::uint32_t
>(text[i]);
84 if constexpr (
sizeof(wchar_t) == 2)
87 if (cp >= 0xD800U && cp <= 0xDBFFU && i + 1 < text.size())
89 const auto lo =
static_cast<std::uint32_t
>(text[i + 1]) & 0xFFFFU;
90 if (lo >= 0xDC00U && lo <= 0xDFFFU)
92 cp = 0x10000U + ((cp - 0xD800U) << 10U) + (lo - 0xDC00U);
97 if ((cp >= 0xD800U && cp <= 0xDFFFU) || cp > 0x10FFFFU)
99 throw std::invalid_argument(
"to_utf8: invalid code point");
103 out +=
static_cast<char>(cp);
105 else if (cp < 0x800U)
107 out +=
static_cast<char>(0xC0U | (cp >> 6U));
108 out +=
static_cast<char>(0x80U | (cp & 0x3FU));
110 else if (cp < 0x10000U)
112 out +=
static_cast<char>(0xE0U | (cp >> 12U));
113 out +=
static_cast<char>(0x80U | ((cp >> 6U) & 0x3FU));
114 out +=
static_cast<char>(0x80U | (cp & 0x3FU));
118 out +=
static_cast<char>(0xF0U | (cp >> 18U));
119 out +=
static_cast<char>(0x80U | ((cp >> 12U) & 0x3FU));
120 out +=
static_cast<char>(0x80U | ((cp >> 6U) & 0x3FU));
121 out +=
static_cast<char>(0x80U | (cp & 0x3FU));
131[[nodiscard]]
inline std::wstring
from_utf8(std::string_view text)
135 throw std::invalid_argument(
"from_utf8: invalid UTF-8 at byte " +
136 std::to_string(bad));
139 out.reserve(text.size());
141 while (i < text.size())
143 const auto b0 =
static_cast<std::uint8_t
>(text[i]);
144 std::uint32_t cp = 0;
146 if (b0 < 0x80U) { cp = b0; }
147 else if ((b0 & 0xE0U) == 0xC0U) { cp = b0 & 0x1FU; len = 2; }
148 else if ((b0 & 0xF0U) == 0xE0U) { cp = b0 & 0x0FU; len = 3; }
149 else { cp = b0 & 0x07U; len = 4; }
150 for (std::size_t k = 1; k < len; ++k)
152 cp = (cp << 6U) | (static_cast<std::uint8_t>(text[i + k]) & 0x3FU);
155 if constexpr (
sizeof(wchar_t) == 2)
160 out +=
static_cast<wchar_t>(0xD800U + (cp >> 10U));
161 out +=
static_cast<wchar_t>(0xDC00U + (cp & 0x3FFU));
165 out +=
static_cast<wchar_t>(cp);