1#ifndef SIMDUTF_UTF8_TO_UTF16_WITH_REPLACEMENT_H
2#define SIMDUTF_UTF8_TO_UTF16_WITH_REPLACEMENT_H
9namespace utf8_to_utf16 {
14template <
typename InputPtr>
struct utf8_byte_pointer {
16 simdutf_constexpr23 uint8_t operator*() const noexcept {
17 return uint8_t(
static_cast<unsigned char>(*p));
19 simdutf_constexpr23 uint8_t operator[](
size_t i)
const noexcept {
20 return uint8_t(
static_cast<unsigned char>(p[i]));
22 const uint8_t *operator+(
size_t i)
const noexcept {
23 return reinterpret_cast<const uint8_t *
>(
static_cast<const void *
>(p + i));
29template <
typename InputPtr>
30#if SIMDUTF_CPLUSPLUS20
31 requires simdutf::detail::indexes_into_byte_like<InputPtr>
33simdutf_constexpr23
size_t maximal_subpart(InputPtr ptr,
size_t n)
noexcept {
34 const uint8_t b = uint8_t(
static_cast<unsigned char>(ptr[0]));
40 }
else if (b < 0xE0) {
42 }
else if (b < 0xF0) {
46 }
else if (b == 0xED) {
49 }
else if (b < 0xF5) {
53 }
else if (b == 0xF4) {
59 if (n < 2 || uint8_t(
static_cast<unsigned char>(ptr[1])) < lo ||
60 uint8_t(
static_cast<unsigned char>(ptr[1])) > hi) {
64 while (i <= need && i < n &&
65 (uint8_t(
static_cast<unsigned char>(ptr[i])) & 0xC0) == 0x80) {
73template <endianness endian,
bool write,
typename InputPtr>
74#if SIMDUTF_CPLUSPLUS20
75 requires simdutf::detail::indexes_into_byte_like<InputPtr>
77simdutf_constexpr23
size_t transcode_with_replacement(
78 InputPtr data,
size_t len,
char16_t *utf16_output)
noexcept {
86 auto store = [&](uint32_t c) {
92 const uint16_t high = uint16_t(0xD800 + ((c >> 10) & 0x3FF));
93 const uint16_t low = uint16_t(0xDC00 + (c & 0x3FF));
94 if constexpr (write) {
95 utf16_output[written] =
96 char16_t(scalar::utf16::swap_if_needed<endian>(high));
97 utf16_output[written + 1] =
98 char16_t(scalar::utf16::swap_if_needed<endian>(low));
102 if constexpr (write) {
103 utf16_output[written] =
104 char16_t(scalar::utf16::swap_if_needed<endian>(uint16_t(c)));
110 if (needed == 0 && i + 16 <= len) {
111#if SIMDUTF_CPLUSPLUS23
116 std::memcpy(&v1, data + i,
sizeof(v1));
118 std::memcpy(&v2, data + i +
sizeof(v1),
sizeof(v2));
119 if (((v1 | v2) & 0x8080808080808080ULL) == 0) {
120 for (
size_t k = 0; k < 16; k++) {
121 store(uint8_t(
static_cast<unsigned char>(data[i + k])));
128 const uint8_t b = uint8_t(
static_cast<unsigned char>(data[i]));
135 }
else if (b <= 0xDF) {
142 }
else if (b <= 0xEF) {
145 }
else if (b == 0xED) {
150 }
else if (b <= 0xF4) {
153 }
else if (b == 0xF4) {
163 if (b < lo || b > hi) {
175 cp = (cp << 6) | uint32_t(b & 0x3F);
177 if (seen == needed) {
190template <endianness endian,
typename InputPtr>
191#if SIMDUTF_CPLUSPLUS20
192 requires simdutf::detail::indexes_into_byte_like<InputPtr>
194simdutf_constexpr23
size_t convert_with_replacement(
195 InputPtr data,
size_t len,
char16_t *utf16_output)
noexcept {
196 return transcode_with_replacement<endian, true>(data, len, utf16_output);
199template <
typename InputPtr>
200#if SIMDUTF_CPLUSPLUS20
201 requires simdutf::detail::indexes_into_byte_like<InputPtr>
203simdutf_constexpr23
size_t count_with_replacement(InputPtr data,
204 size_t len)
noexcept {
205 return transcode_with_replacement<endianness::LITTLE, false>(data, len,
209template <
typename InputPtr>
210#if SIMDUTF_CPLUSPLUS20
211 requires simdutf::detail::indexes_into_byte_like<InputPtr>
213simdutf_constexpr23 utf8_to_utf16_result
215 utf8_to_utf16_result out;
218 utf8_result validation;
219#if SIMDUTF_CPLUSPLUS23
221 validation = scalar::utf8::validate_with_counts(
222 utf8_byte_pointer<InputPtr>{data + pos}, len - pos);
226 validation = scalar::utf8::validate_with_counts(
227 reinterpret_cast<const uint8_t *
>(data + pos), len - pos);
229 if (validation.error == error_code::SUCCESS) {
230 out.count += validation.utf16_length();
233 if (validation.input_count >= len - pos) {
234 out.count += count_with_replacement(data + pos, len - pos);
235 out.more_errors =
true;
236 if (out.error == error_code::SUCCESS) {
237 out.error = validation.error;
241 out.count += validation.utf16_length() + 1;
242 if (out.error == error_code::SUCCESS) {
243 out.error = validation.error;
245 const size_t err = pos + validation.input_count;
246 const size_t skip = maximal_subpart(data + err, len - err);
247 if (out.error_count < utf8_to_utf16_result::max_errors) {
248 out.error_offset[out.error_count] = err;
249 out.error_count += 1;
251 out.more_errors =
true;
helpers placed in namespace detail are not a part of the public API
simdutf_warn_unused utf8_to_utf16_result utf16_length_from_utf8_with_replacement(const char *input, size_t length) noexcept
Compute the number of char16_t that this UTF-8 string requires in UTF-16 when ill-formed subsequences...