1#ifndef SIMDUTF_UTF8_TO_UTF32_H
2#define SIMDUTF_UTF8_TO_UTF32_H
9namespace utf8_to_utf32 {
11template <
typename InputPtr>
12#if SIMDUTF_CPLUSPLUS20
13 requires simdutf::detail::indexes_into_byte_like<InputPtr>
15simdutf_constexpr23
size_t convert(InputPtr data,
size_t len,
16 char32_t *utf32_output) {
18 char32_t *start{utf32_output};
20#if SIMDUTF_CPLUSPLUS23
25 if (pos + 16 <= len) {
28 ::memcpy(&v1, data + pos,
sizeof(uint64_t));
30 ::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
32 if ((v & 0x8080808080808080) == 0) {
33 size_t final_pos = pos + 16;
34 while (pos < final_pos) {
35 *utf32_output++ = uint8_t(data[pos]);
42 auto leading_byte = uint8_t(data[pos]);
43 if (leading_byte < 0b10000000) {
45 *utf32_output++ = char32_t(leading_byte);
47 }
else if ((leading_byte & 0b11100000) == 0b11000000) {
52 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
56 uint32_t code_point = (leading_byte & 0b00011111) << 6 |
57 (uint8_t(data[pos + 1]) & 0b00111111);
58 if (code_point < 0x80) {
61 *utf32_output++ = char32_t(code_point);
63 }
else if ((leading_byte & 0b11110000) == 0b11100000) {
69 if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) {
72 if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) {
76 uint32_t code_point = (leading_byte & 0b00001111) << 12 |
77 (uint8_t(data[pos + 1]) & 0b00111111) << 6 |
78 (uint8_t(data[pos + 2]) & 0b00111111);
79 if (code_point < 0x800 || (0xd7ff < code_point && code_point < 0xe000)) {
82 *utf32_output++ = char32_t(code_point);
84 }
else if ((leading_byte & 0b11111000) == 0b11110000) {
89 if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) {
92 if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) {
95 if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) {
100 uint32_t code_point = (leading_byte & 0b00000111) << 18 |
101 (uint8_t(data[pos + 1]) & 0b00111111) << 12 |
102 (uint8_t(data[pos + 2]) & 0b00111111) << 6 |
103 (uint8_t(data[pos + 3]) & 0b00111111);
104 if (code_point <= 0xffff || 0x10ffff < code_point) {
107 *utf32_output++ = char32_t(code_point);
113 return utf32_output - start;
116template <
typename InputPtr>
117#if SIMDUTF_CPLUSPLUS20
118 requires simdutf::detail::indexes_into_byte_like<InputPtr>
120simdutf_constexpr23 result convert_with_errors(InputPtr data,
size_t len,
121 char32_t *utf32_output) {
123 char32_t *start{utf32_output};
125#if SIMDUTF_CPLUSPLUS23
130 if (pos + 16 <= len) {
133 ::memcpy(&v1, data + pos,
sizeof(uint64_t));
135 ::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
137 if ((v & 0x8080808080808080) == 0) {
138 size_t final_pos = pos + 16;
139 while (pos < final_pos) {
140 *utf32_output++ = uint8_t(data[pos]);
147 auto leading_byte = uint8_t(data[pos]);
148 if (leading_byte < 0b10000000) {
150 *utf32_output++ = char32_t(leading_byte);
152 }
else if ((leading_byte & 0b11100000) == 0b11000000) {
154 if (pos + 1 >= len) {
155 return result(error_code::TOO_SHORT, pos);
157 if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) {
158 return result(error_code::TOO_SHORT, pos);
161 uint32_t code_point = (leading_byte & 0b00011111) << 6 |
162 (uint8_t(data[pos + 1]) & 0b00111111);
163 if (code_point < 0x80) {
164 return result(error_code::OVERLONG, pos);
166 *utf32_output++ = char32_t(code_point);
168 }
else if ((leading_byte & 0b11110000) == 0b11100000) {
170 if (pos + 2 >= len) {
171 return result(error_code::TOO_SHORT, pos);
174 if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) {
175 return result(error_code::TOO_SHORT, pos);
177 if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) {
178 return result(error_code::TOO_SHORT, pos);
181 uint32_t code_point = (leading_byte & 0b00001111) << 12 |
182 (uint8_t(data[pos + 1]) & 0b00111111) << 6 |
183 (uint8_t(data[pos + 2]) & 0b00111111);
184 if (code_point < 0x800) {
185 return result(error_code::OVERLONG, pos);
187 if (0xd7ff < code_point && code_point < 0xe000) {
188 return result(error_code::SURROGATE, pos);
190 *utf32_output++ = char32_t(code_point);
192 }
else if ((leading_byte & 0b11111000) == 0b11110000) {
194 if (pos + 3 >= len) {
195 return result(error_code::TOO_SHORT, pos);
197 if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) {
198 return result(error_code::TOO_SHORT, pos);
200 if ((uint8_t(data[pos + 2]) & 0b11000000) != 0b10000000) {
201 return result(error_code::TOO_SHORT, pos);
203 if ((uint8_t(data[pos + 3]) & 0b11000000) != 0b10000000) {
204 return result(error_code::TOO_SHORT, pos);
208 uint32_t code_point = (leading_byte & 0b00000111) << 18 |
209 (uint8_t(data[pos + 1]) & 0b00111111) << 12 |
210 (uint8_t(data[pos + 2]) & 0b00111111) << 6 |
211 (uint8_t(data[pos + 3]) & 0b00111111);
212 if (code_point <= 0xffff) {
213 return result(error_code::OVERLONG, pos);
215 if (0x10ffff < code_point) {
216 return result(error_code::TOO_LARGE, pos);
218 *utf32_output++ = char32_t(code_point);
222 if ((leading_byte & 0b11000000) == 0b10000000) {
223 return result(error_code::TOO_LONG, pos);
225 return result(error_code::HEADER_BITS, pos);
229 return result(error_code::SUCCESS, utf32_output - start);
247inline result rewind_and_convert_with_errors(
size_t prior_bytes,
248 const char *buf,
size_t len,
249 char32_t *utf32_output) {
252 size_t how_far_back = 3;
253 if (how_far_back > prior_bytes) {
254 how_far_back = prior_bytes;
256 bool found_leading_bytes{
false};
258 for (
size_t i = 0; i <= how_far_back; i++) {
259 unsigned char byte = buf[-
static_cast<std::ptrdiff_t
>(i)];
260 found_leading_bytes = ((
byte & 0b11000000) != 0b10000000);
261 if (found_leading_bytes) {
262 if (i > 0 &&
byte < 128) {
265 return result(error_code::TOO_LONG, 0 - i + 1);
280 if (!found_leading_bytes) {
285 return result(error_code::TOO_LONG, 0 - how_far_back);
288 result res = convert_with_errors(buf, len + extra_len, utf32_output);
290 res.count -= extra_len;
helpers placed in namespace detail are not a part of the public API