1#ifndef SIMDUTF_UTF8_TO_LATIN1_H
2#define SIMDUTF_UTF8_TO_LATIN1_H
9namespace utf8_to_latin1 {
11template <
typename InputPtr,
typename OutputPtr>
12#if SIMDUTF_CPLUSPLUS20
13 requires(simdutf::detail::indexes_into_byte_like<InputPtr> &&
14 simdutf::detail::indexes_into_byte_like<OutputPtr>)
16simdutf_constexpr23
size_t convert(InputPtr data,
size_t len,
17 OutputPtr latin_output) {
19 auto start = latin_output;
22#if SIMDUTF_CPLUSPLUS23
27 if (pos + 16 <= len) {
30 ::memcpy(&v1, data + pos,
sizeof(uint64_t));
32 ::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
35 if ((v & 0x8080808080808080) ==
38 size_t final_pos = pos + 16;
39 while (pos < final_pos) {
40 *latin_output++ = char(data[pos]);
49 uint8_t leading_byte = data[pos];
50 if (leading_byte < 0b10000000) {
52 *latin_output++ = char(leading_byte);
54 }
else if ((leading_byte & 0b11100000) ==
60 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
66 (leading_byte & 0b00011111) << 6 |
73 if (code_point < 0x80 || 0xFF < code_point) {
78 *latin_output++ = char(code_point);
84 return latin_output - start;
87template <
typename InputPtr>
88#if SIMDUTF_CPLUSPLUS20
89 requires simdutf::detail::indexes_into_byte_like<InputPtr>
91simdutf_constexpr23 result convert_with_errors(InputPtr data,
size_t len,
94 char *start{latin_output};
97#if SIMDUTF_CPLUSPLUS23
102 if (pos + 16 <= len) {
105 ::memcpy(&v1, data + pos,
sizeof(uint64_t));
107 ::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
110 if ((v & 0x8080808080808080) ==
113 size_t final_pos = pos + 16;
114 while (pos < final_pos) {
115 *latin_output++ = char(data[pos]);
123 uint8_t leading_byte = data[pos];
124 if (leading_byte < 0b10000000) {
126 *latin_output++ = char(leading_byte);
128 }
else if ((leading_byte & 0b11100000) ==
131 if (pos + 1 >= len) {
132 return result(error_code::TOO_SHORT, pos);
134 if ((data[pos + 1] & 0b11000000) != 0b10000000) {
135 return result(error_code::TOO_SHORT, pos);
139 uint32_t code_point =
140 (leading_byte & 0b00011111) << 6 |
147 if (code_point < 0x80) {
148 return result(error_code::OVERLONG, pos);
150 if (0xFF < code_point) {
151 return result(error_code::TOO_LARGE, pos);
154 *latin_output++ = char(code_point);
156 }
else if ((leading_byte & 0b11110000) == 0b11100000) {
158 return result(error_code::TOO_LARGE, pos);
159 }
else if ((leading_byte & 0b11111000) == 0b11110000) {
161 return result(error_code::TOO_LARGE, pos);
164 if ((leading_byte & 0b11000000) == 0b10000000) {
165 return result(error_code::TOO_LONG, pos);
168 return result(error_code::HEADER_BITS, pos);
171 return result(error_code::SUCCESS, latin_output - start);
174inline result rewind_and_convert_with_errors(
size_t prior_bytes,
175 const char *buf,
size_t len,
176 char *latin1_output) {
181 size_t how_far_back = prior_bytes;
184 bool found_leading_bytes{
false};
186 for (
size_t i = 0; i <= how_far_back; i++) {
187 unsigned char byte = buf[-
static_cast<std::ptrdiff_t
>(i)];
188 found_leading_bytes = ((
byte & 0b11000000) != 0b10000000);
189 if (found_leading_bytes) {
190 if (i > 0 &&
byte < 128) {
193 return result(error_code::TOO_LONG, 0 - i + 1);
208 if (!found_leading_bytes) {
213 return result(error_code::TOO_LONG, 0 - how_far_back);
215 result res = convert_with_errors(buf, len + extra_len, latin1_output);
217 res.count -= extra_len;
helpers placed in namespace detail are not a part of the public API