/src/simdutf/include/simdutf/scalar/utf16.h
Line | Count | Source |
1 | | #ifndef SIMDUTF_UTF16_H |
2 | | #define SIMDUTF_UTF16_H |
3 | | |
4 | | namespace simdutf { |
5 | | namespace scalar { |
6 | | namespace utf16 { |
7 | | |
8 | | template <endianness big_endian> |
9 | | simdutf_warn_unused simdutf_constexpr23 bool |
10 | 0 | validate_as_ascii(const char16_t *data, size_t len) noexcept { |
11 | 0 | for (size_t pos = 0; pos < len; pos++) { |
12 | 0 | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
13 | 0 | if (word >= 0x80) { |
14 | 0 | return false; |
15 | 0 | } |
16 | 0 | } |
17 | 0 | return true; |
18 | 0 | } Unexecuted instantiation: bool simdutf::scalar::utf16::validate_as_ascii<(simdutf::endianness)0>(char16_t const*, unsigned long) Unexecuted instantiation: bool simdutf::scalar::utf16::validate_as_ascii<(simdutf::endianness)1>(char16_t const*, unsigned long) |
19 | | |
20 | | template <endianness big_endian> |
21 | | inline simdutf_warn_unused simdutf_constexpr23 bool |
22 | 0 | validate(const char16_t *data, size_t len) noexcept { |
23 | 0 | uint64_t pos = 0; |
24 | 0 | while (pos < len) { |
25 | 0 | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
26 | 0 | if ((word & 0xF800) == 0xD800) { |
27 | 0 | if (pos + 1 >= len) { |
28 | 0 | return false; |
29 | 0 | } |
30 | 0 | char16_t diff = char16_t(word - 0xD800); |
31 | 0 | if (diff > 0x3FF) { |
32 | 0 | return false; |
33 | 0 | } |
34 | 0 | char16_t next_word = !match_system(big_endian) |
35 | 0 | ? u16_swap_bytes(data[pos + 1]) |
36 | 0 | : data[pos + 1]; |
37 | 0 | char16_t diff2 = char16_t(next_word - 0xDC00); |
38 | 0 | if (diff2 > 0x3FF) { |
39 | 0 | return false; |
40 | 0 | } |
41 | 0 | pos += 2; |
42 | 0 | } else { |
43 | 0 | pos++; |
44 | 0 | } |
45 | 0 | } |
46 | 0 | return true; |
47 | 0 | } Unexecuted instantiation: bool simdutf::scalar::utf16::validate<(simdutf::endianness)0>(char16_t const*, unsigned long) Unexecuted instantiation: bool simdutf::scalar::utf16::validate<(simdutf::endianness)1>(char16_t const*, unsigned long) |
48 | | |
49 | | template <endianness big_endian> |
50 | | inline simdutf_warn_unused simdutf_constexpr23 result |
51 | 0 | validate_with_errors(const char16_t *data, size_t len) noexcept { |
52 | 0 | size_t pos = 0; |
53 | 0 | while (pos < len) { |
54 | 0 | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
55 | 0 | if ((word & 0xF800) == 0xD800) { |
56 | 0 | if (pos + 1 >= len) { |
57 | 0 | return result(error_code::SURROGATE, pos); |
58 | 0 | } |
59 | 0 | char16_t diff = char16_t(word - 0xD800); |
60 | 0 | if (diff > 0x3FF) { |
61 | 0 | return result(error_code::SURROGATE, pos); |
62 | 0 | } |
63 | 0 | char16_t next_word = !match_system(big_endian) |
64 | 0 | ? u16_swap_bytes(data[pos + 1]) |
65 | 0 | : data[pos + 1]; |
66 | 0 | char16_t diff2 = uint16_t(next_word - 0xDC00); |
67 | 0 | if (diff2 > 0x3FF) { |
68 | 0 | return result(error_code::SURROGATE, pos); |
69 | 0 | } |
70 | 0 | pos += 2; |
71 | 0 | } else { |
72 | 0 | pos++; |
73 | 0 | } |
74 | 0 | } |
75 | 0 | return result(error_code::SUCCESS, pos); |
76 | 0 | } Unexecuted instantiation: simdutf::result simdutf::scalar::utf16::validate_with_errors<(simdutf::endianness)0>(char16_t const*, unsigned long) Unexecuted instantiation: simdutf::result simdutf::scalar::utf16::validate_with_errors<(simdutf::endianness)1>(char16_t const*, unsigned long) |
77 | | |
78 | | template <endianness big_endian> |
79 | 0 | simdutf_constexpr23 size_t count_code_points(const char16_t *p, size_t len) { |
80 | | // We are not BOM aware. |
81 | 0 | size_t counter{0}; |
82 | 0 | for (size_t i = 0; i < len; i++) { |
83 | 0 | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
84 | 0 | counter += ((word & 0xFC00) != 0xDC00); |
85 | 0 | } |
86 | 0 | return counter; |
87 | 0 | } Unexecuted instantiation: unsigned long simdutf::scalar::utf16::count_code_points<(simdutf::endianness)0>(char16_t const*, unsigned long) Unexecuted instantiation: unsigned long simdutf::scalar::utf16::count_code_points<(simdutf::endianness)1>(char16_t const*, unsigned long) |
88 | | |
89 | | template <endianness big_endian> |
90 | | simdutf_constexpr23 size_t utf8_length_from_utf16(const char16_t *p, |
91 | 0 | size_t len) { |
92 | | // We are not BOM aware. |
93 | 0 | size_t counter{0}; |
94 | 0 | for (size_t i = 0; i < len; i++) { |
95 | 0 | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
96 | 0 | counter++; // ASCII |
97 | 0 | counter += static_cast<size_t>( |
98 | 0 | word > |
99 | 0 | 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes |
100 | 0 | counter += static_cast<size_t>((word > 0x7FF && word <= 0xD7FF) || |
101 | 0 | (word >= 0xE000)); // three-byte |
102 | 0 | } |
103 | 0 | return counter; |
104 | 0 | } Unexecuted instantiation: unsigned long simdutf::scalar::utf16::utf8_length_from_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long) Unexecuted instantiation: unsigned long simdutf::scalar::utf16::utf8_length_from_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long) |
105 | | |
106 | | template <endianness big_endian> |
107 | | simdutf_constexpr23 size_t utf32_length_from_utf16(const char16_t *p, |
108 | 0 | size_t len) { |
109 | | // We are not BOM aware. |
110 | 0 | size_t counter{0}; |
111 | 0 | for (size_t i = 0; i < len; i++) { |
112 | 0 | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
113 | 0 | counter += ((word & 0xFC00) != 0xDC00); |
114 | 0 | } |
115 | 0 | return counter; |
116 | 0 | } Unexecuted instantiation: unsigned long simdutf::scalar::utf16::utf32_length_from_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long) Unexecuted instantiation: unsigned long simdutf::scalar::utf16::utf32_length_from_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long) |
117 | | |
118 | | simdutf_really_inline simdutf_constexpr23 void |
119 | 0 | change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) { |
120 | 0 | for (size_t i = 0; i < size; i++) { |
121 | 0 | *output++ = char16_t(input[i] >> 8 | input[i] << 8); |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | template <endianness big_endian> |
126 | | simdutf_warn_unused simdutf_constexpr23 size_t |
127 | 0 | trim_partial_utf16(const char16_t *input, size_t length) { |
128 | 0 | if (length == 0) { |
129 | 0 | return 0; |
130 | 0 | } |
131 | 0 | uint16_t last_word = uint16_t(input[length - 1]); |
132 | 0 | last_word = scalar::utf16::swap_if_needed<big_endian>(last_word); |
133 | 0 | length -= ((last_word & 0xFC00) == 0xD800); |
134 | 0 | return length; |
135 | 0 | } Unexecuted instantiation: unsigned long simdutf::scalar::utf16::trim_partial_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long) Unexecuted instantiation: unsigned long simdutf::scalar::utf16::trim_partial_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long) |
136 | | |
137 | 0 | template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) { |
138 | 0 | c = scalar::utf16::swap_if_needed<big_endian>(c); |
139 | 0 | return (0xd800 <= c && c <= 0xdbff); |
140 | 0 | } Unexecuted instantiation: bool simdutf::scalar::utf16::is_high_surrogate<(simdutf::endianness)0>(char16_t) Unexecuted instantiation: bool simdutf::scalar::utf16::is_high_surrogate<(simdutf::endianness)1>(char16_t) |
141 | | |
142 | 0 | template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) { |
143 | 0 | c = scalar::utf16::swap_if_needed<big_endian>(c); |
144 | 0 | return (0xdc00 <= c && c <= 0xdfff); |
145 | 0 | } Unexecuted instantiation: bool simdutf::scalar::utf16::is_low_surrogate<(simdutf::endianness)0>(char16_t) Unexecuted instantiation: bool simdutf::scalar::utf16::is_low_surrogate<(simdutf::endianness)1>(char16_t) |
146 | | |
147 | 0 | simdutf_unused simdutf_really_inline constexpr bool high_surrogate(char16_t c) { |
148 | 0 | return (0xd800 <= c && c <= 0xdbff); |
149 | 0 | } |
150 | | |
151 | | template <endianness big_endian> |
152 | | simdutf_constexpr23 result |
153 | 0 | utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) { |
154 | 0 | bool any_surrogates = false; |
155 | | // We are not BOM aware. |
156 | 0 | size_t counter{0}; |
157 | 0 | for (size_t i = 0; i < len; i++) { |
158 | 0 | if (is_high_surrogate<big_endian>(p[i])) { |
159 | 0 | any_surrogates = true; |
160 | | // surrogate pair |
161 | 0 | if (i + 1 < len && is_low_surrogate<big_endian>(p[i + 1])) { |
162 | 0 | counter += 4; |
163 | 0 | i++; // skip low surrogate |
164 | 0 | } else { |
165 | 0 | counter += 3; // unpaired high surrogate replaced by U+FFFD |
166 | 0 | } |
167 | 0 | continue; |
168 | 0 | } else if (is_low_surrogate<big_endian>(p[i])) { |
169 | 0 | any_surrogates = true; |
170 | 0 | counter += 3; // unpaired low surrogate replaced by U+FFFD |
171 | 0 | continue; |
172 | 0 | } |
173 | 0 | char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; |
174 | 0 | counter++; // at least 1 byte |
175 | 0 | counter += |
176 | 0 | static_cast<size_t>(word > 0x7F); // non-ASCII is at least 2 bytes |
177 | 0 | counter += static_cast<size_t>(word > 0x7FF); // three-byte |
178 | 0 | } |
179 | 0 | return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, |
180 | 0 | counter}; |
181 | 0 | } Unexecuted instantiation: simdutf::result simdutf::scalar::utf16::utf8_length_from_utf16_with_replacement<(simdutf::endianness)0>(char16_t const*, unsigned long) Unexecuted instantiation: simdutf::result simdutf::scalar::utf16::utf8_length_from_utf16_with_replacement<(simdutf::endianness)1>(char16_t const*, unsigned long) |
182 | | |
183 | | // variable templates are a C++14 extension |
184 | 0 | template <endianness big_endian> constexpr char16_t replacement() { |
185 | 0 | return !match_system(big_endian) ? scalar::u16_swap_bytes(0xfffd) : 0xfffd; |
186 | 0 | } Unexecuted instantiation: char16_t simdutf::scalar::utf16::replacement<(simdutf::endianness)0>() Unexecuted instantiation: char16_t simdutf::scalar::utf16::replacement<(simdutf::endianness)1>() |
187 | | |
188 | | template <endianness big_endian> |
189 | | simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, |
190 | 0 | char16_t *output) { |
191 | 0 | const char16_t replacement = utf16::replacement<big_endian>(); |
192 | 0 | bool high_surrogate_prev = false, high_surrogate, low_surrogate; |
193 | 0 | size_t i = 0; |
194 | 0 | for (; i < len; i++) { |
195 | 0 | char16_t c = input[i]; |
196 | 0 | high_surrogate = is_high_surrogate<big_endian>(c); |
197 | 0 | low_surrogate = is_low_surrogate<big_endian>(c); |
198 | 0 | if (high_surrogate_prev && !low_surrogate) { |
199 | 0 | output[i - 1] = replacement; |
200 | 0 | } |
201 | |
|
202 | 0 | if (!high_surrogate_prev && low_surrogate) { |
203 | 0 | output[i] = replacement; |
204 | 0 | } else { |
205 | 0 | output[i] = input[i]; |
206 | 0 | } |
207 | 0 | high_surrogate_prev = high_surrogate; |
208 | 0 | } |
209 | | |
210 | | /* string may not end with high surrogate */ |
211 | 0 | if (high_surrogate_prev) { |
212 | 0 | output[i - 1] = replacement; |
213 | 0 | } |
214 | 0 | } Unexecuted instantiation: void simdutf::scalar::utf16::to_well_formed_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long, char16_t*) Unexecuted instantiation: void simdutf::scalar::utf16::to_well_formed_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long, char16_t*) |
215 | | |
216 | | } // namespace utf16 |
217 | | } // namespace scalar |
218 | | } // namespace simdutf |
219 | | |
220 | | #endif |