simdutf 9.0.0
Unicode at GB/s.
Loading...
Searching...
No Matches
valid_utf8_to_latin1.h
1#ifndef SIMDUTF_VALID_UTF8_TO_LATIN1_H
2#define SIMDUTF_VALID_UTF8_TO_LATIN1_H
3
4#include <cstring>
5
6namespace simdutf {
7namespace scalar {
8namespace {
9namespace utf8_to_latin1 {
10
11template <typename InputPtr>
12#if SIMDUTF_CPLUSPLUS20
13 requires simdutf::detail::indexes_into_byte_like<InputPtr>
14#endif
15simdutf_constexpr23 size_t convert_valid(InputPtr data, size_t len,
16 char *latin_output) {
17
18 size_t pos = 0;
19 char *start{latin_output};
20
21 while (pos < len) {
22#if SIMDUTF_CPLUSPLUS23
23 if !consteval
24#endif
25 {
26 // try to convert the next block of 16 ASCII bytes
27 if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that
28 // they are ascii
29 uint64_t v1;
30 ::memcpy(&v1, data + pos, sizeof(uint64_t));
31 uint64_t v2;
32 ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
33 uint64_t v{v1 |
34 v2}; // We are only interested in these bits: 1000 1000 1000
35 // 1000, so it makes sense to concatenate everything
36 if ((v & 0x8080808080808080) ==
37 0) { // if NONE of these are set, e.g. all of them are zero, then
38 // everything is ASCII
39 size_t final_pos = pos + 16;
40 while (pos < final_pos) {
41 *latin_output++ = uint8_t(data[pos]);
42 pos++;
43 }
44 continue;
45 }
46 }
47 }
48
49 // suppose it is not an all ASCII byte sequence
50 auto leading_byte = uint8_t(data[pos]); // leading byte
51 if (leading_byte < 0b10000000) {
52 // converting one ASCII byte !!!
53 *latin_output++ = char(leading_byte);
54 pos++;
55 } else if ((leading_byte & 0b11100000) ==
56 0b11000000) { // the first three bits indicate:
57 // We have a two-byte UTF-8
58 if (pos + 1 >= len) {
59 break;
60 } // minimal bound checking
61 if ((uint8_t(data[pos + 1]) & 0b11000000) != 0b10000000) {
62 return 0;
63 } // checks if the next byte is a valid continuation byte in UTF-8. A
64 // valid continuation byte starts with 10.
65 // range check -
66 uint32_t code_point =
67 (leading_byte & 0b00011111) << 6 |
68 (uint8_t(data[pos + 1]) &
69 0b00111111); // assembles the Unicode code point from the two bytes.
70 // It does this by discarding the leading 110 and 10
71 // bits from the two bytes, shifting the remaining bits
72 // of the first byte, and then combining the results
73 // with a bitwise OR operation.
74 *latin_output++ = char(code_point);
75 pos += 2;
76 } else {
77 // we may have a continuation but we do not do error checking
78 return 0;
79 }
80 }
81 return latin_output - start;
82}
83
84} // namespace utf8_to_latin1
85} // unnamed namespace
86} // namespace scalar
87} // namespace simdutf
88
89#endif
helpers placed in namespace detail are not a part of the public API