12template <
class BytePtr>
13simdutf_constexpr23 simdutf_warn_unused
bool validate(BytePtr data,
14 size_t len)
noexcept {
16 std::is_same<
typename std::decay<
decltype(*data)>::type, uint8_t>::value,
17 "dereferencing the data pointer must result in a uint8_t");
19 uint32_t code_point = 0;
22#if SIMDUTF_CPLUSPLUS23
27 if (next_pos <= len) {
30 std::memcpy(&v1, data + pos,
sizeof(uint64_t));
32 std::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
34 if ((v & 0x8080808080808080) == 0) {
41 unsigned char byte = data[pos];
43 while (
byte < 0b10000000) {
50 if ((
byte & 0b11100000) == 0b11000000) {
55 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
59 code_point = (
byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
60 if (code_point < 0x80) {
63 }
else if ((
byte & 0b11110000) == 0b11100000) {
68 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
71 if ((data[pos + 2] & 0b11000000) != 0b10000000) {
75 code_point = (
byte & 0b00001111) << 12 |
76 (data[pos + 1] & 0b00111111) << 6 |
77 (data[pos + 2] & 0b00111111);
78 if ((code_point < 0x800) ||
79 (0xd7ff < code_point && code_point < 0xe000)) {
82 }
else if ((
byte & 0b11111000) == 0b11110000) {
87 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
90 if ((data[pos + 2] & 0b11000000) != 0b10000000) {
93 if ((data[pos + 3] & 0b11000000) != 0b10000000) {
98 (
byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 |
99 (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111);
100 if (code_point <= 0xffff || 0x10ffff < code_point) {
112simdutf_really_inline simdutf_warn_unused
bool validate(
const char *buf,
113 size_t len)
noexcept {
114 return validate(
reinterpret_cast<const uint8_t *
>(buf), len);
117template <
class BytePtr>
118simdutf_constexpr23 simdutf_warn_unused result
119validate_with_errors(BytePtr data,
size_t len)
noexcept {
121 std::is_same<
typename std::decay<
decltype(*data)>::type, uint8_t>::value,
122 "dereferencing the data pointer must result in a uint8_t");
124 uint32_t code_point = 0;
127 size_t next_pos = pos + 16;
131 std::memcpy(&v1, data + pos,
sizeof(uint64_t));
133 std::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
135 if ((v & 0x8080808080808080) == 0) {
140 unsigned char byte = data[pos];
142 while (
byte < 0b10000000) {
144 return result(error_code::SUCCESS, len);
149 if ((
byte & 0b11100000) == 0b11000000) {
151 if (next_pos > len) {
152 return result(error_code::TOO_SHORT, pos);
154 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
155 return result(error_code::TOO_SHORT, pos);
158 code_point = (
byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
159 if (code_point < 0x80) {
160 return result(error_code::OVERLONG, pos);
162 }
else if ((
byte & 0b11110000) == 0b11100000) {
164 if (next_pos > len) {
165 return result(error_code::TOO_SHORT, pos);
167 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
168 return result(error_code::TOO_SHORT, pos);
170 if ((data[pos + 2] & 0b11000000) != 0b10000000) {
171 return result(error_code::TOO_SHORT, pos);
174 code_point = (
byte & 0b00001111) << 12 |
175 (data[pos + 1] & 0b00111111) << 6 |
176 (data[pos + 2] & 0b00111111);
177 if (code_point < 0x800) {
178 return result(error_code::OVERLONG, pos);
180 if (0xd7ff < code_point && code_point < 0xe000) {
181 return result(error_code::SURROGATE, pos);
183 }
else if ((
byte & 0b11111000) == 0b11110000) {
185 if (next_pos > len) {
186 return result(error_code::TOO_SHORT, pos);
188 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
189 return result(error_code::TOO_SHORT, pos);
191 if ((data[pos + 2] & 0b11000000) != 0b10000000) {
192 return result(error_code::TOO_SHORT, pos);
194 if ((data[pos + 3] & 0b11000000) != 0b10000000) {
195 return result(error_code::TOO_SHORT, pos);
199 (
byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 |
200 (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111);
201 if (code_point <= 0xffff) {
202 return result(error_code::OVERLONG, pos);
204 if (0x10ffff < code_point) {
205 return result(error_code::TOO_LARGE, pos);
209 if ((
byte & 0b11000000) == 0b10000000) {
210 return result(error_code::TOO_LONG, pos);
212 return result(error_code::HEADER_BITS, pos);
217 return result(error_code::SUCCESS, len);
220simdutf_really_inline simdutf_warn_unused result
221validate_with_errors(
const char *buf,
size_t len)
noexcept {
222 return validate_with_errors(
reinterpret_cast<const uint8_t *
>(buf), len);
231inline simdutf_warn_unused result rewind_and_validate_with_errors(
232 const char *start,
const char *buf,
size_t len)
noexcept {
234 if ((*start & 0b11000000) == 0b10000000) {
235 return result(error_code::TOO_LONG, 0);
239 for (
int i = 0; i < 5; i++) {
240 unsigned char byte = *buf;
241 if ((
byte & 0b11000000) != 0b10000000) {
249 result res = validate_with_errors(buf, len + extra_len);
250 res.count -= extra_len;
255template <
class BytePtr>
256simdutf_constexpr23 simdutf_warn_unused utf8_result
257validate_with_counts(BytePtr data,
size_t len)
noexcept {
259 std::is_same<
typename std::decay<
decltype(*data)>::type, uint8_t>::value,
260 "dereferencing the data pointer must result in a uint8_t");
262 uint32_t code_point = 0;
263 size_t continuations = 0;
264 size_t four_byte = 0;
268#if SIMDUTF_CPLUSPLUS23
272 const size_t next_ascii_pos = pos + 16;
273 if (next_ascii_pos <= len) {
276 std::memcpy(&v1, data + pos,
sizeof(uint64_t));
278 std::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
280 if ((v & 0x8080808080808080) == 0) {
281 pos = next_ascii_pos;
288 unsigned char byte = data[pos];
290 while (
byte < 0b10000000) {
292 return utf8_result(error_code::SUCCESS, pos, continuations, four_byte);
297 if ((
byte & 0b11100000) == 0b11000000) {
299 if (next_pos > len) {
300 return utf8_result(error_code::TOO_SHORT, pos, continuations,
303 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
304 return utf8_result(error_code::TOO_SHORT, pos, continuations,
308 code_point = (
byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
309 if (code_point < 0x80) {
310 return utf8_result(error_code::OVERLONG, pos, continuations, four_byte);
313 }
else if ((
byte & 0b11110000) == 0b11100000) {
315 if (next_pos > len) {
316 return utf8_result(error_code::TOO_SHORT, pos, continuations,
319 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
320 return utf8_result(error_code::TOO_SHORT, pos, continuations,
323 if ((data[pos + 2] & 0b11000000) != 0b10000000) {
324 return utf8_result(error_code::TOO_SHORT, pos, continuations,
328 code_point = (
byte & 0b00001111) << 12 |
329 (data[pos + 1] & 0b00111111) << 6 |
330 (data[pos + 2] & 0b00111111);
331 if (code_point < 0x800) {
332 return utf8_result(error_code::OVERLONG, pos, continuations, four_byte);
333 }
else if (0xd7ff < code_point && code_point < 0xe000) {
334 return utf8_result(error_code::SURROGATE, pos, continuations,
338 }
else if ((
byte & 0b11111000) == 0b11110000) {
340 if (next_pos > len) {
341 return utf8_result(error_code::TOO_SHORT, pos, continuations,
344 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
345 return utf8_result(error_code::TOO_SHORT, pos, continuations,
348 if ((data[pos + 2] & 0b11000000) != 0b10000000) {
349 return utf8_result(error_code::TOO_SHORT, pos, continuations,
352 if ((data[pos + 3] & 0b11000000) != 0b10000000) {
353 return utf8_result(error_code::TOO_SHORT, pos, continuations,
358 (
byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 |
359 (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111);
360 if (code_point <= 0xffff) {
361 return utf8_result(error_code::OVERLONG, pos, continuations, four_byte);
362 }
else if (0x10ffff < code_point) {
363 return utf8_result(error_code::TOO_LARGE, pos, continuations,
370 if ((
byte & 0b11000000) == 0b10000000) {
371 return utf8_result(error_code::TOO_LONG, pos, continuations, four_byte);
373 return utf8_result(error_code::HEADER_BITS, pos, continuations,
379 return utf8_result(error_code::SUCCESS, pos, continuations, four_byte);
382simdutf_really_inline simdutf_warn_unused utf8_result
383validate_with_counts(
const char *buf,
size_t len)
noexcept {
384 return validate_with_counts(
reinterpret_cast<const uint8_t *
>(buf), len);
400inline simdutf_warn_unused utf8_result rewind_and_validate_with_counts(
401 const char *start,
const char *buf,
size_t len)
noexcept {
403 if ((*start & 0b11000000) == 0b10000000) {
404 return utf8_result(error_code::TOO_LONG, 0, 0, 0);
409 return validate_with_counts(buf, len);
414 size_t extra_continuations{0};
415 size_t extra_four_bytes{0};
423 for (
int i = 0; i < 4; i++) {
428 unsigned char byte = *buf;
431 if (
byte >= 0b10000000) {
432 if (
byte >= 0b11110000) {
433 extra_four_bytes += 1;
434 }
else if ((int8_t)
byte < -65 + 1) {
435 extra_continuations += 1;
438 if ((
byte & 0b11000000) != 0b10000000) {
443 utf8_result res = validate_with_counts(buf, len + extra_len);
444 res.input_count -= extra_len;
445 res.continuation_count -= extra_continuations;
446 res.four_byte_count -= extra_four_bytes;
450template <
typename InputPtr>
451#if SIMDUTF_CPLUSPLUS20
452 requires simdutf::detail::indexes_into_byte_like<InputPtr>
454simdutf_constexpr23
size_t count_code_points(InputPtr data,
size_t len) {
456 for (
size_t i = 0; i < len; i++) {
459 if (int8_t(data[i]) > -65) {
466template <
typename InputPtr>
467#if SIMDUTF_CPLUSPLUS20
468 requires simdutf::detail::indexes_into_byte_like<InputPtr>
472 for (
size_t i = 0; i < len; i++) {
473 if (int8_t(data[i]) > -65) {
476 if (uint8_t(data[i]) >= 240) {
483template <
typename InputPtr>
484#if SIMDUTF_CPLUSPLUS20
485 requires simdutf::detail::indexes_into_byte_like<InputPtr>
487simdutf_warn_unused simdutf_constexpr23
size_t
492 if (uint8_t(input[length - 1]) >= 0xc0) {
495 if (uint8_t(input[length - 2]) >= 0xe0) {
500 if (uint8_t(input[length - 1]) >= 0xc0) {
508 if (uint8_t(input[length - 1]) >= 0xc0) {
511 if (uint8_t(input[length - 2]) >= 0xe0) {
514 if (uint8_t(input[length - 3]) >= 0xf0) {
helpers placed in namespace detail are not a part of the public API
simdutf_warn_unused size_t utf16_length_from_utf8(const char *input, size_t length) noexcept
Compute the number of 2-byte code units that this UTF-8 string would require in UTF-16LE format.
simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length)
Given a valid UTF-8 string having a possibly truncated last character, this function checks the end o...