1#ifndef SIMDUTF_LATIN1_TO_UTF8_H
2#define SIMDUTF_LATIN1_TO_UTF8_H
9namespace latin1_to_utf8 {
11template <
typename InputPtr,
typename OutputPtr>
12#if SIMDUTF_CPLUSPLUS20
13 requires(simdutf::detail::indexes_into_byte_like<InputPtr> &&
14 simdutf::detail::index_assignable_from_char<OutputPtr>)
16simdutf_constexpr23
size_t convert(InputPtr data,
size_t len,
17 OutputPtr utf8_output) {
23#if SIMDUTF_CPLUSPLUS23
28 if (pos + 16 <= len) {
31 ::memcpy(&v1, data + pos,
sizeof(uint64_t));
33 ::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
37 if ((v & 0x8080808080808080) ==
40 size_t final_pos = pos + 16;
41 while (pos < final_pos) {
42 utf8_output[utf8_pos++] = char(data[pos]);
50 unsigned char byte = data[pos];
51 if ((
byte & 0x80) == 0) {
53 utf8_output[utf8_pos++] = char(
byte);
57 utf8_output[utf8_pos++] = char((
byte >> 6) | 0b11000000);
58 utf8_output[utf8_pos++] = char((
byte & 0b111111) | 0b10000000);
65simdutf_really_inline
size_t convert(
const char *buf,
size_t len,
67 return convert(
reinterpret_cast<const unsigned char *
>(buf), len,
71inline size_t convert_safe(
const char *buf,
size_t len,
char *utf8_output,
73 const unsigned char *data =
reinterpret_cast<const unsigned char *
>(buf);
77 while (pos < len && utf8_pos < utf8_len) {
79 if (pos >= skip_pos && pos + 16 <= len &&
80 utf8_pos + 16 <= utf8_len) {
83 ::memcpy(&v1, data + pos,
sizeof(uint64_t));
85 ::memcpy(&v2, data + pos +
sizeof(uint64_t),
sizeof(uint64_t));
89 if ((v & 0x8080808080808080) ==
92 ::memcpy(utf8_output + utf8_pos, buf + pos, 16);
101 const auto byte = data[pos];
102 if ((
byte & 0x80) == 0) {
104 utf8_output[utf8_pos++] = char(
byte);
106 }
else if (utf8_pos + 2 <= utf8_len) {
108 utf8_output[utf8_pos++] = char((
byte >> 6) | 0b11000000);
109 utf8_output[utf8_pos++] = char((
byte & 0b111111) | 0b10000000);
119inline full_result convert_safe_with_details(
const char *buf,
size_t len,
122 const size_t output_count = convert_safe(buf, len, utf8_output, utf8_len);
125 size_t input_count = 0;
126 size_t counted_output = 0;
127 while (input_count < len) {
129 uint8_t(buf[input_count]) < uint8_t(0x80) ? size_t(1) : size_t(2);
130 if (counted_output + width > output_count) {
134 counted_output += width;
136 return full_result(input_count == len ? error_code::SUCCESS
137 : error_code::OUTPUT_BUFFER_TOO_SMALL,
138 input_count, output_count);
141template <
typename InputPtr,
typename OutputPtr>
142#if SIMDUTF_CPLUSPLUS20
143 requires(simdutf::detail::indexes_into_byte_like<InputPtr> &&
144 simdutf::detail::index_assignable_from_char<OutputPtr>)
146simdutf_constexpr23
size_t convert_safe_constexpr(InputPtr data,
size_t len,
147 OutputPtr utf8_output,
151 while (pos < len && utf8_pos < utf8_len) {
152 const unsigned char byte = data[pos];
153 if ((
byte & 0x80) == 0) {
155 utf8_output[utf8_pos++] = char(
byte);
157 }
else if (utf8_pos + 2 <= utf8_len) {
159 utf8_output[utf8_pos++] = char((
byte >> 6) | 0b11000000);
160 utf8_output[utf8_pos++] = char((
byte & 0b111111) | 0b10000000);
169template <
typename InputPtr,
typename OutputPtr>
170#if SIMDUTF_CPLUSPLUS20
171 requires(simdutf::detail::indexes_into_byte_like<InputPtr> &&
172 simdutf::detail::index_assignable_from_char<OutputPtr>)
174simdutf_constexpr23 full_result convert_safe_with_details_constexpr(
175 InputPtr data,
size_t len, OutputPtr utf8_output,
size_t utf8_len) {
176 const size_t output_count =
177 convert_safe_constexpr(data, len, utf8_output, utf8_len);
178 size_t input_count = 0;
179 size_t counted_output = 0;
180 while (input_count < len) {
182 uint8_t(data[input_count]) < uint8_t(0x80) ? size_t(1) : size_t(2);
183 if (counted_output + width > output_count) {
187 counted_output += width;
189 return full_result(input_count == len ? error_code::SUCCESS
190 : error_code::OUTPUT_BUFFER_TOO_SMALL,
191 input_count, output_count);
194template <
typename InputPtr>
195#if SIMDUTF_CPLUSPLUS20
196 requires simdutf::detail::indexes_into_byte_like<InputPtr>
198simdutf_constexpr23 simdutf_warn_unused
size_t
200 size_t answer = length;
203#if SIMDUTF_CPLUSPLUS23
207 auto pop = [](uint64_t v) {
208 return (
size_t)(((v >> 7) & UINT64_C(0x0101010101010101)) *
209 UINT64_C(0x0101010101010101) >>
212 for (; i + 32 <= length; i += 32) {
214 memcpy(&v, input + i, 8);
216 memcpy(&v, input + i + 8,
sizeof(v));
218 memcpy(&v, input + i + 16,
sizeof(v));
220 memcpy(&v, input + i + 24,
sizeof(v));
223 for (; i + 8 <= length; i += 8) {
225 memcpy(&v, input + i,
sizeof(v));
229 for (; i + 1 <= length; i += 1) {
230 answer +=
static_cast<uint8_t
>(input[i]) >> 7;
helpers placed in namespace detail are not a part of the public API
simdutf_warn_unused size_t utf8_length_from_latin1(const char *input, size_t length) noexcept
Return the number of bytes that this Latin1 string would require in UTF-8 format.