simdutf 9.0.0
Unicode at GB/s.
Loading...
Searching...
No Matches
utf32_to_utf8.h
1#ifndef SIMDUTF_UTF32_TO_UTF8_H
2#define SIMDUTF_UTF32_TO_UTF8_H
3
4#include <cstring>
5
6namespace simdutf {
7namespace scalar {
8namespace {
9namespace utf32_to_utf8 {
10
11template <typename InputPtr, typename OutputPtr>
12#if SIMDUTF_CPLUSPLUS20
13 requires(simdutf::detail::indexes_into_utf32<InputPtr> &&
14 simdutf::detail::index_assignable_from_char<OutputPtr>)
15#endif
16simdutf_constexpr23 size_t convert(InputPtr data, size_t len,
17 OutputPtr utf8_output) {
18 size_t pos = 0;
19 auto start = utf8_output;
20 while (pos < len) {
21#if SIMDUTF_CPLUSPLUS23
22 if !consteval
23#endif
24 { // try to convert the next block of 2 ASCII characters
25 if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that
26 // they are ascii
27 uint64_t v;
28 ::memcpy(&v, data + pos, sizeof(uint64_t));
29 if ((v & 0xFFFFFF80FFFFFF80) == 0) {
30 *utf8_output++ = char(data[pos]);
31 *utf8_output++ = char(data[pos + 1]);
32 pos += 2;
33 continue;
34 }
35 }
36 }
37
38 uint32_t word = data[pos];
39 if ((word & 0xFFFFFF80) == 0) {
40 // will generate one UTF-8 bytes
41 *utf8_output++ = char(word);
42 pos++;
43 } else if ((word & 0xFFFFF800) == 0) {
44 // will generate two UTF-8 bytes
45 // we have 0b110XXXXX 0b10XXXXXX
46 *utf8_output++ = char((word >> 6) | 0b11000000);
47 *utf8_output++ = char((word & 0b111111) | 0b10000000);
48 pos++;
49 } else if ((word & 0xFFFF0000) == 0) {
50 // will generate three UTF-8 bytes
51 // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
52 if (word >= 0xD800 && word <= 0xDFFF) {
53 return 0;
54 }
55 *utf8_output++ = char((word >> 12) | 0b11100000);
56 *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
57 *utf8_output++ = char((word & 0b111111) | 0b10000000);
58 pos++;
59 } else {
60 // will generate four UTF-8 bytes
61 // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX
62 if (word > 0x10FFFF) {
63 return 0;
64 }
65 *utf8_output++ = char((word >> 18) | 0b11110000);
66 *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000);
67 *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
68 *utf8_output++ = char((word & 0b111111) | 0b10000000);
69 pos++;
70 }
71 }
72 return utf8_output - start;
73}
74
75template <typename InputPtr, typename OutputPtr>
76#if SIMDUTF_CPLUSPLUS20
77 requires(simdutf::detail::indexes_into_utf32<InputPtr> &&
78 simdutf::detail::index_assignable_from_char<OutputPtr>)
79#endif
80simdutf_constexpr23 result convert_with_errors(InputPtr data, size_t len,
81 OutputPtr utf8_output) {
82 size_t pos = 0;
83 auto start = utf8_output;
84 while (pos < len) {
85#if SIMDUTF_CPLUSPLUS23
86 if !consteval
87#endif
88 { // try to convert the next block of 2 ASCII characters
89 if (pos + 2 <= len) { // if it is safe to read 8 more bytes, check that
90 // they are ascii
91 uint64_t v;
92 ::memcpy(&v, data + pos, sizeof(uint64_t));
93 if ((v & 0xFFFFFF80FFFFFF80) == 0) {
94 *utf8_output++ = char(data[pos]);
95 *utf8_output++ = char(data[pos + 1]);
96 pos += 2;
97 continue;
98 }
99 }
100 }
101
102 uint32_t word = data[pos];
103 if ((word & 0xFFFFFF80) == 0) {
104 // will generate one UTF-8 bytes
105 *utf8_output++ = char(word);
106 pos++;
107 } else if ((word & 0xFFFFF800) == 0) {
108 // will generate two UTF-8 bytes
109 // we have 0b110XXXXX 0b10XXXXXX
110 *utf8_output++ = char((word >> 6) | 0b11000000);
111 *utf8_output++ = char((word & 0b111111) | 0b10000000);
112 pos++;
113 } else if ((word & 0xFFFF0000) == 0) {
114 // will generate three UTF-8 bytes
115 // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
116 if (word >= 0xD800 && word <= 0xDFFF) {
117 return result(error_code::SURROGATE, pos);
118 }
119 *utf8_output++ = char((word >> 12) | 0b11100000);
120 *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
121 *utf8_output++ = char((word & 0b111111) | 0b10000000);
122 pos++;
123 } else {
124 // will generate four UTF-8 bytes
125 // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX
126 if (word > 0x10FFFF) {
127 return result(error_code::TOO_LARGE, pos);
128 }
129 *utf8_output++ = char((word >> 18) | 0b11110000);
130 *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000);
131 *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
132 *utf8_output++ = char((word & 0b111111) | 0b10000000);
133 pos++;
134 }
135 }
136 return result(error_code::SUCCESS, utf8_output - start);
137}
138
139} // namespace utf32_to_utf8
140} // unnamed namespace
141} // namespace scalar
142} // namespace simdutf
143
144#endif
helpers placed in namespace detail are not a part of the public API