simdutf 9.0.0
Unicode at GB/s.
Loading...
Searching...
No Matches
valid_utf8_to_utf16.h
1#ifndef SIMDUTF_VALID_UTF8_TO_UTF16_H
2#define SIMDUTF_VALID_UTF8_TO_UTF16_H
3
4#include <cstring>
5
6namespace simdutf {
7namespace scalar {
8namespace {
9namespace utf8_to_utf16 {
10
11template <endianness big_endian, 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 char16_t *utf16_output) {
17 size_t pos = 0;
18 char16_t *start{utf16_output};
19 while (pos < len) {
20#if SIMDUTF_CPLUSPLUS23
21 if !consteval
22#endif
23 { // try to convert the next block of 8 ASCII bytes
24 if (pos + 8 <= len) { // if it is safe to read 8 more bytes, check that
25 // they are ascii
26 uint64_t v;
27 ::memcpy(&v, data + pos, sizeof(uint64_t));
28 if ((v & 0x8080808080808080) == 0) {
29 size_t final_pos = pos + 8;
30 while (pos < final_pos) {
31 const char16_t byte = uint8_t(data[pos]);
32 *utf16_output++ =
33 !match_system(big_endian) ? u16_swap_bytes(byte) : byte;
34 pos++;
35 }
36 continue;
37 }
38 }
39 }
40
41 auto leading_byte = uint8_t(data[pos]); // leading byte
42 if (leading_byte < 0b10000000) {
43 // converting one ASCII byte !!!
44 *utf16_output++ = !match_system(big_endian)
45 ? char16_t(u16_swap_bytes(leading_byte))
46 : char16_t(leading_byte);
47 pos++;
48 } else if ((leading_byte & 0b11100000) == 0b11000000) {
49 // We have a two-byte UTF-8, it should become
50 // a single UTF-16 word.
51 if (pos + 1 >= len) {
52 break;
53 } // minimal bound checking
54 uint16_t code_point = uint16_t(((leading_byte & 0b00011111) << 6) |
55 (uint8_t(data[pos + 1]) & 0b00111111));
56 if constexpr (!match_system(big_endian)) {
57 code_point = u16_swap_bytes(uint16_t(code_point));
58 }
59 *utf16_output++ = char16_t(code_point);
60 pos += 2;
61 } else if ((leading_byte & 0b11110000) == 0b11100000) {
62 // We have a three-byte UTF-8, it should become
63 // a single UTF-16 word.
64 if (pos + 2 >= len) {
65 break;
66 } // minimal bound checking
67 uint16_t code_point =
68 uint16_t(((leading_byte & 0b00001111) << 12) |
69 ((uint8_t(data[pos + 1]) & 0b00111111) << 6) |
70 (uint8_t(data[pos + 2]) & 0b00111111));
71 if constexpr (!match_system(big_endian)) {
72 code_point = u16_swap_bytes(uint16_t(code_point));
73 }
74 *utf16_output++ = char16_t(code_point);
75 pos += 3;
76 } else if ((leading_byte & 0b11111000) == 0b11110000) { // 0b11110000
77 // we have a 4-byte UTF-8 word.
78 if (pos + 3 >= len) {
79 break;
80 } // minimal bound checking
81 uint32_t code_point = ((leading_byte & 0b00000111) << 18) |
82 ((uint8_t(data[pos + 1]) & 0b00111111) << 12) |
83 ((uint8_t(data[pos + 2]) & 0b00111111) << 6) |
84 (uint8_t(data[pos + 3]) & 0b00111111);
85 code_point -= 0x10000;
86 uint16_t high_surrogate = uint16_t(0xD800 + (code_point >> 10));
87 uint16_t low_surrogate = uint16_t(0xDC00 + (code_point & 0x3FF));
88 if constexpr (!match_system(big_endian)) {
89 high_surrogate = u16_swap_bytes(high_surrogate);
90 low_surrogate = u16_swap_bytes(low_surrogate);
91 }
92 *utf16_output++ = char16_t(high_surrogate);
93 *utf16_output++ = char16_t(low_surrogate);
94 pos += 4;
95 } else {
96 // we may have a continuation but we do not do error checking
97 return 0;
98 }
99 }
100 return utf16_output - start;
101}
102
103} // namespace utf8_to_utf16
104} // unnamed namespace
105} // namespace scalar
106} // namespace simdutf
107
108#endif
helpers placed in namespace detail are not a part of the public API