Coverage Report

Created: 2026-09-01 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/simdutf/src/haswell/implementation.cpp
Line
Count
Source
1
#include "simdutf/haswell/begin.h"
2
3
namespace simdutf {
4
namespace SIMDUTF_IMPLEMENTATION {
5
namespace {
6
#ifndef SIMDUTF_HASWELL_H
7
  #error "haswell.h must be included"
8
#endif
9
using namespace simd;
10
11
#if SIMDUTF_FEATURE_ASCII || SIMDUTF_FEATURE_DETECT_ENCODING ||                \
12
    SIMDUTF_FEATURE_UTF8
13
619k
simdutf_really_inline bool is_ascii(const simd8x64<uint8_t> &input) {
14
619k
  return input.reduce_or().is_ascii();
15
619k
}
16
#endif // SIMDUTF_FEATURE_ASCII || SIMDUTF_FEATURE_DETECT_ENCODING ||
17
       // SIMDUTF_FEATURE_UTF8
18
19
#if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
20
simdutf_really_inline simd8<bool>
21
must_be_2_3_continuation(const simd8<uint8_t> prev2,
22
660k
                         const simd8<uint8_t> prev3) {
23
660k
  simd8<uint8_t> is_third_byte =
24
660k
      prev2.saturating_sub(0xe0u - 0x80); // Only 111_____ will be > 0x80
25
660k
  simd8<uint8_t> is_fourth_byte =
26
660k
      prev3.saturating_sub(0xf0u - 0x80); // Only 1111____ will be > 0x80
27
660k
  return simd8<bool>(is_third_byte | is_fourth_byte);
28
660k
}
29
#endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
30
31
#if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
32
namespace utf16 {
33
  #include "haswell/avx2_validate_utf16.cpp"
34
}
35
#endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
36
37
#if SIMDUTF_FEATURE_UTF16
38
  #include "haswell/avx2_utf16fix.cpp"
39
#endif // SIMDUTF_FEATURE_UTF16
40
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
41
  #include "haswell/avx2_convert_latin1_to_utf8.cpp"
42
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
43
44
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
45
  #include "haswell/avx2_convert_latin1_to_utf16.cpp"
46
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
47
48
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
49
  #include "haswell/avx2_convert_latin1_to_utf32.cpp"
50
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
51
52
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
53
  #include "haswell/avx2_convert_utf8_to_utf16.cpp"
54
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
55
56
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
57
  #include "haswell/avx2_convert_utf8_to_utf32.cpp"
58
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
59
60
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
61
  #include "haswell/avx2_convert_utf16_to_latin1.cpp"
62
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
63
64
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
65
  #include "haswell/avx2_convert_utf16_to_utf8.cpp"
66
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
67
68
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
69
  #include "haswell/avx2_convert_utf16_to_utf32.cpp"
70
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
71
72
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
73
  #include "haswell/avx2_convert_utf32_to_latin1.cpp"
74
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
75
76
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
77
  #include "haswell/avx2_convert_utf32_to_utf8.cpp"
78
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
79
80
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
81
  #include "haswell/avx2_convert_utf32_to_utf16.cpp"
82
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
83
84
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
85
  #include "haswell/avx2_convert_utf8_to_latin1.cpp"
86
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
87
88
#if SIMDUTF_FEATURE_BASE64
89
  #include "haswell/avx2_base64.cpp"
90
#endif // SIMDUTF_FEATURE_BASE64
91
92
} // unnamed namespace
93
} // namespace SIMDUTF_IMPLEMENTATION
94
} // namespace simdutf
95
96
#include "generic/buf_block_reader.h"
97
#if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
98
  #include "generic/utf8_validation/utf8_lookup4_algorithm.h"
99
  #include "generic/utf8_validation/utf8_validator.h"
100
#endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
101
102
#if SIMDUTF_FEATURE_ASCII
103
  #include "generic/ascii_validation.h"
104
#endif // SIMDUTF_FEATURE_ASCII
105
106
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
107
  // transcoding from UTF-8 to UTF-16
108
  #include "generic/utf8_to_utf16/valid_utf8_to_utf16.h"
109
  #include "generic/utf8_to_utf16/utf8_to_utf16.h"
110
  #include "generic/utf8/utf16_length_from_utf8_bytemask.h"
111
  // transcoding from UTF-16 to UTF-8
112
  #include "generic/utf16_to_utf8/utf16_to_utf8_with_replacement.h"
113
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
114
115
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
116
  // transcoding from UTF-8 to UTF-32
117
  #include "generic/utf8_to_utf32/valid_utf8_to_utf32.h"
118
  #include "generic/utf8_to_utf32/utf8_to_utf32.h"
119
  #include "generic/utf32.h"
120
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
121
122
// other functions
123
#if SIMDUTF_FEATURE_UTF8
124
  #include "generic/utf8.h"
125
#endif // SIMDUTF_FEATURE_UTF8
126
127
#if SIMDUTF_FEATURE_UTF16
128
  #include "generic/utf16.h"
129
  #include "generic/utf16/utf8_length_from_utf16_bytemask.h"
130
#endif // SIMDUTF_FEATURE_UTF16
131
#if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
132
  #include "generic/validate_utf16.h"
133
#endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
134
135
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
136
  // transcoding from UTF-8 to Latin 1
137
  #include "generic/utf8_to_latin1/utf8_to_latin1.h"
138
  #include "generic/utf8_to_latin1/valid_utf8_to_latin1.h"
139
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
140
141
#if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
142
  #include "generic/validate_utf32.h"
143
#endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
144
145
#if SIMDUTF_FEATURE_BASE64
146
  #include "generic/base64.h"
147
  #include "generic/find.h"
148
#endif // SIMDUTF_FEATURE_BASE64
149
150
namespace simdutf {
151
namespace SIMDUTF_IMPLEMENTATION {
152
153
#if SIMDUTF_FEATURE_DETECT_ENCODING
154
simdutf_warn_unused int
155
implementation::detect_encodings(const char *input,
156
652
                                 size_t length) const noexcept {
157
  // If there is a BOM, then we trust it.
158
652
  auto bom_encoding = simdutf::BOM::check_bom(input, length);
159
652
  if (bom_encoding != encoding_type::unspecified) {
160
41
    return bom_encoding;
161
41
  }
162
163
611
  int out = 0;
164
611
  uint32_t utf16_err = (length % 2);
165
611
  uint32_t utf32_err = (length % 4);
166
611
  uint32_t ends_with_high = 0;
167
611
  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
168
611
  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
169
611
  const auto v_fc = simd8<uint8_t>::splat(0xfc);
170
611
  const auto v_dc = simd8<uint8_t>::splat(0xdc);
171
611
  const __m256i standardmax = _mm256_set1_epi32(0x10ffff);
172
611
  const __m256i offset = _mm256_set1_epi32(0xffff2000);
173
611
  const __m256i standardoffsetmax = _mm256_set1_epi32(0xfffff7ff);
174
611
  __m256i currentmax = _mm256_setzero_si256();
175
611
  __m256i currentoffsetmax = _mm256_setzero_si256();
176
177
611
  utf8_checker c{};
178
611
  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
179
212k
  while (reader.has_full_block()) {
180
211k
    simd::simd8x64<uint8_t> in(reader.full_block());
181
    // utf8 checks
182
211k
    c.check_next_input(in);
183
184
    // utf16le checks
185
211k
    auto in0 = simd16<uint16_t>(in.chunks[0]);
186
211k
    auto in1 = simd16<uint16_t>(in.chunks[1]);
187
211k
    const auto t0 = in0.shr<8>();
188
211k
    const auto t1 = in1.shr<8>();
189
211k
    const auto in2 = simd16<uint16_t>::pack(t0, t1);
190
211k
    const auto surrogates_wordmask = (in2 & v_f8) == v_d8;
191
211k
    const uint32_t surrogates_bitmask = surrogates_wordmask.to_bitmask();
192
211k
    const auto vL = (in2 & v_fc) == v_dc;
193
211k
    const uint32_t L = vL.to_bitmask();
194
211k
    const uint32_t H = L ^ surrogates_bitmask;
195
211k
    utf16_err |= (((H << 1) | ends_with_high) != L);
196
211k
    ends_with_high = (H & 0x80000000) != 0;
197
198
    // utf32le checks
199
211k
    currentmax = _mm256_max_epu32(in.chunks[0], currentmax);
200
211k
    currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[0], offset),
201
211k
                                        currentoffsetmax);
202
211k
    currentmax = _mm256_max_epu32(in.chunks[1], currentmax);
203
211k
    currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[1], offset),
204
211k
                                        currentoffsetmax);
205
206
211k
    reader.advance();
207
211k
  }
208
209
611
  uint8_t block[64]{};
210
611
  size_t idx = reader.block_index();
211
611
  std::memcpy(block, &input[idx], length - idx);
212
611
  simd::simd8x64<uint8_t> in(block);
213
611
  c.check_next_input(in);
214
215
  // utf16le last block check
216
611
  auto in0 = simd16<uint16_t>(in.chunks[0]);
217
611
  auto in1 = simd16<uint16_t>(in.chunks[1]);
218
611
  const auto t0 = in0.shr<8>();
219
611
  const auto t1 = in1.shr<8>();
220
611
  const auto in2 = simd16<uint16_t>::pack(t0, t1);
221
611
  const auto surrogates_wordmask = (in2 & v_f8) == v_d8;
222
611
  const uint32_t surrogates_bitmask = surrogates_wordmask.to_bitmask();
223
611
  const auto vL = (in2 & v_fc) == v_dc;
224
611
  const uint32_t L = vL.to_bitmask();
225
611
  const uint32_t H = L ^ surrogates_bitmask;
226
611
  utf16_err |= (((H << 1) | ends_with_high) != L);
227
  // this is required to check for last byte ending in high and end of input
228
  // is reached
229
611
  ends_with_high = (H & 0x80000000) != 0;
230
611
  utf16_err |= ends_with_high;
231
232
  // utf32le last block check
233
611
  currentmax = _mm256_max_epu32(in.chunks[0], currentmax);
234
611
  currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[0], offset),
235
611
                                      currentoffsetmax);
236
611
  currentmax = _mm256_max_epu32(in.chunks[1], currentmax);
237
611
  currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[1], offset),
238
611
                                      currentoffsetmax);
239
240
611
  reader.advance();
241
242
611
  c.check_eof();
243
611
  bool is_valid_utf8 = !c.errors();
244
611
  __m256i is_zero =
245
611
      _mm256_xor_si256(_mm256_max_epu32(currentmax, standardmax), standardmax);
246
611
  utf32_err |= (_mm256_testz_si256(is_zero, is_zero) == 0);
247
248
611
  is_zero = _mm256_xor_si256(
249
611
      _mm256_max_epu32(currentoffsetmax, standardoffsetmax), standardoffsetmax);
250
611
  utf32_err |= (_mm256_testz_si256(is_zero, is_zero) == 0);
251
611
  if (is_valid_utf8) {
252
87
    out |= encoding_type::UTF8;
253
87
  }
254
611
  if (utf16_err == 0) {
255
228
    out |= encoding_type::UTF16_LE;
256
228
  }
257
611
  if (utf32_err == 0) {
258
69
    out |= encoding_type::UTF32_LE;
259
69
  }
260
611
  return out;
261
652
}
262
#endif // SIMDUTF_FEATURE_DETECT_ENCODING
263
264
#if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
265
simdutf_warn_unused bool
266
633
implementation::validate_utf8(const char *buf, size_t len) const noexcept {
267
633
  return haswell::utf8_validation::generic_validate_utf8(buf, len);
268
633
}
269
#endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
270
271
#if SIMDUTF_FEATURE_UTF8
272
simdutf_warn_unused result implementation::validate_utf8_with_errors(
273
0
    const char *buf, size_t len) const noexcept {
274
0
  return haswell::utf8_validation::generic_validate_utf8_with_errors(buf, len);
275
0
}
276
#endif // SIMDUTF_FEATURE_UTF8
277
278
#if SIMDUTF_FEATURE_ASCII
279
simdutf_warn_unused bool
280
212
implementation::validate_ascii(const char *buf, size_t len) const noexcept {
281
212
  return haswell::ascii_validation::generic_validate_ascii(buf, len);
282
212
}
283
284
simdutf_warn_unused result implementation::validate_ascii_with_errors(
285
256
    const char *buf, size_t len) const noexcept {
286
256
  return haswell::ascii_validation::generic_validate_ascii_with_errors(buf,
287
256
                                                                       len);
288
256
}
289
#endif // SIMDUTF_FEATURE_ASCII
290
291
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII
292
simdutf_warn_unused bool
293
implementation::validate_utf16le_as_ascii(const char16_t *buf,
294
226
                                          size_t len) const noexcept {
295
226
  return haswell::utf16::validate_utf16_as_ascii_with_errors<
296
226
             endianness::LITTLE>(buf, len)
297
226
             .error == SUCCESS;
298
226
}
299
300
simdutf_warn_unused bool
301
implementation::validate_utf16be_as_ascii(const char16_t *buf,
302
226
                                          size_t len) const noexcept {
303
226
  return haswell::utf16::validate_utf16_as_ascii_with_errors<endianness::BIG>(
304
226
             buf, len)
305
226
             .error == SUCCESS;
306
226
}
307
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII
308
309
#if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
310
simdutf_warn_unused bool
311
implementation::validate_utf16le(const char16_t *buf,
312
1.65k
                                 size_t len) const noexcept {
313
1.65k
  if (simdutf_unlikely(len == 0)) {
314
    // empty input is valid UTF-16. protect the implementation from
315
    // handling nullptr
316
4
    return true;
317
4
  }
318
1.65k
  const auto res =
319
1.65k
      haswell::utf16::validate_utf16_with_errors<endianness::LITTLE>(buf, len);
320
1.65k
  if (res.is_err()) {
321
237
    return false;
322
237
  }
323
324
1.41k
  if (res.count == len) {
325
0
    return true;
326
0
  }
327
328
1.41k
  return scalar::utf16::validate<endianness::LITTLE>(buf + res.count,
329
1.41k
                                                     len - res.count);
330
1.41k
}
331
#endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
332
333
#if SIMDUTF_FEATURE_UTF16
334
simdutf_warn_unused bool
335
implementation::validate_utf16be(const char16_t *buf,
336
1.28k
                                 size_t len) const noexcept {
337
1.28k
  if (simdutf_unlikely(len == 0)) {
338
    // empty input is valid UTF-16. protect the implementation from
339
    // handling nullptr
340
4
    return true;
341
4
  }
342
1.28k
  const auto res =
343
1.28k
      haswell::utf16::validate_utf16_with_errors<endianness::BIG>(buf, len);
344
1.28k
  if (res.is_err()) {
345
182
    return false;
346
182
  }
347
348
1.10k
  if (res.count == len) {
349
0
    return true;
350
0
  }
351
352
1.10k
  return scalar::utf16::validate<endianness::BIG>(buf + res.count,
353
1.10k
                                                  len - res.count);
354
1.10k
}
355
356
simdutf_warn_unused result implementation::validate_utf16le_with_errors(
357
0
    const char16_t *buf, size_t len) const noexcept {
358
359
0
  const result res =
360
0
      haswell::utf16::validate_utf16_with_errors<endianness::LITTLE>(buf, len);
361
0
  if (res.count != len) {
362
0
    const result scalar_res =
363
0
        scalar::utf16::validate_with_errors<endianness::LITTLE>(
364
0
            buf + res.count, len - res.count);
365
0
    return result(scalar_res.error, res.count + scalar_res.count);
366
0
  } else {
367
0
    return res;
368
0
  }
369
0
}
370
371
simdutf_warn_unused result implementation::validate_utf16be_with_errors(
372
0
    const char16_t *buf, size_t len) const noexcept {
373
0
  const result res =
374
0
      haswell::utf16::validate_utf16_with_errors<endianness::BIG>(buf, len);
375
0
  if (res.count != len) {
376
0
    const result scalar_res =
377
0
        scalar::utf16::validate_with_errors<endianness::BIG>(buf + res.count,
378
0
                                                             len - res.count);
379
0
    return result(scalar_res.error, res.count + scalar_res.count);
380
0
  } else {
381
0
    return res;
382
0
  }
383
0
}
384
385
void implementation::to_well_formed_utf16le(const char16_t *input, size_t len,
386
631
                                            char16_t *output) const noexcept {
387
631
  return utf16fix_avx<endianness::LITTLE>(input, len, output);
388
631
}
389
390
void implementation::to_well_formed_utf16be(const char16_t *input, size_t len,
391
631
                                            char16_t *output) const noexcept {
392
631
  return utf16fix_avx<endianness::BIG>(input, len, output);
393
631
}
394
#endif // SIMDUTF_FEATURE_UTF16
395
396
#if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
397
simdutf_warn_unused bool
398
241
implementation::validate_utf32(const char32_t *buf, size_t len) const noexcept {
399
241
  return utf32::validate(buf, len);
400
241
}
401
#endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
402
403
#if SIMDUTF_FEATURE_UTF32
404
simdutf_warn_unused result implementation::validate_utf32_with_errors(
405
0
    const char32_t *buf, size_t len) const noexcept {
406
0
  return utf32::validate_with_errors(buf, len);
407
0
}
408
#endif // SIMDUTF_FEATURE_UTF32
409
410
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
411
simdutf_warn_unused size_t implementation::convert_latin1_to_utf8(
412
544
    const char *buf, size_t len, char *utf8_output) const noexcept {
413
544
  std::pair<const char *, char *> ret =
414
544
      avx2_convert_latin1_to_utf8(buf, len, utf8_output);
415
544
  size_t converted_chars = ret.second - utf8_output;
416
417
544
  if (ret.first != buf + len) {
418
517
    const size_t scalar_converted_chars = scalar::latin1_to_utf8::convert(
419
517
        ret.first, len - (ret.first - buf), ret.second);
420
517
    converted_chars += scalar_converted_chars;
421
517
  }
422
423
544
  return converted_chars;
424
544
}
425
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
426
427
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
428
simdutf_warn_unused size_t implementation::convert_latin1_to_utf16le(
429
0
    const char *buf, size_t len, char16_t *utf16_output) const noexcept {
430
0
  std::pair<const char *, char16_t *> ret =
431
0
      avx2_convert_latin1_to_utf16<endianness::LITTLE>(buf, len, utf16_output);
432
0
  if (ret.first == nullptr) {
433
0
    return 0;
434
0
  }
435
0
  size_t converted_chars = ret.second - utf16_output;
436
0
  if (ret.first != buf + len) {
437
0
    const size_t scalar_converted_chars =
438
0
        scalar::latin1_to_utf16::convert<endianness::LITTLE>(
439
0
            ret.first, len - (ret.first - buf), ret.second);
440
0
    if (scalar_converted_chars == 0) {
441
0
      return 0;
442
0
    }
443
0
    converted_chars += scalar_converted_chars;
444
0
  }
445
0
  return converted_chars;
446
0
}
447
448
simdutf_warn_unused size_t implementation::convert_latin1_to_utf16be(
449
0
    const char *buf, size_t len, char16_t *utf16_output) const noexcept {
450
0
  std::pair<const char *, char16_t *> ret =
451
0
      avx2_convert_latin1_to_utf16<endianness::BIG>(buf, len, utf16_output);
452
0
  if (ret.first == nullptr) {
453
0
    return 0;
454
0
  }
455
0
  size_t converted_chars = ret.second - utf16_output;
456
0
  if (ret.first != buf + len) {
457
0
    const size_t scalar_converted_chars =
458
0
        scalar::latin1_to_utf16::convert<endianness::BIG>(
459
0
            ret.first, len - (ret.first - buf), ret.second);
460
0
    if (scalar_converted_chars == 0) {
461
0
      return 0;
462
0
    }
463
0
    converted_chars += scalar_converted_chars;
464
0
  }
465
0
  return converted_chars;
466
0
}
467
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
468
469
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
470
simdutf_warn_unused size_t implementation::convert_latin1_to_utf32(
471
0
    const char *buf, size_t len, char32_t *utf32_output) const noexcept {
472
0
  std::pair<const char *, char32_t *> ret =
473
0
      avx2_convert_latin1_to_utf32(buf, len, utf32_output);
474
0
  if (ret.first == nullptr) {
475
0
    return 0;
476
0
  }
477
0
  size_t converted_chars = ret.second - utf32_output;
478
0
  if (ret.first != buf + len) {
479
0
    const size_t scalar_converted_chars = scalar::latin1_to_utf32::convert(
480
0
        ret.first, len - (ret.first - buf), ret.second);
481
0
    if (scalar_converted_chars == 0) {
482
0
      return 0;
483
0
    }
484
0
    converted_chars += scalar_converted_chars;
485
0
  }
486
0
  return converted_chars;
487
0
}
488
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
489
490
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
491
simdutf_warn_unused size_t implementation::convert_utf8_to_latin1(
492
0
    const char *buf, size_t len, char *latin1_output) const noexcept {
493
0
  utf8_to_latin1::validating_transcoder converter;
494
0
  return converter.convert(buf, len, latin1_output);
495
0
}
496
497
simdutf_warn_unused result implementation::convert_utf8_to_latin1_with_errors(
498
0
    const char *buf, size_t len, char *latin1_output) const noexcept {
499
0
  utf8_to_latin1::validating_transcoder converter;
500
0
  return converter.convert_with_errors(buf, len, latin1_output);
501
0
}
502
503
simdutf_warn_unused size_t implementation::convert_valid_utf8_to_latin1(
504
0
    const char *input, size_t size, char *latin1_output) const noexcept {
505
0
  return utf8_to_latin1::convert_valid(input, size, latin1_output);
506
0
}
507
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
508
509
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
510
simdutf_warn_unused size_t implementation::convert_utf8_to_utf16le(
511
0
    const char *buf, size_t len, char16_t *utf16_output) const noexcept {
512
0
  utf8_to_utf16::validating_transcoder converter;
513
0
  return converter.convert<endianness::LITTLE>(buf, len, utf16_output);
514
0
}
515
516
simdutf_warn_unused size_t implementation::convert_utf8_to_utf16be(
517
0
    const char *buf, size_t len, char16_t *utf16_output) const noexcept {
518
0
  utf8_to_utf16::validating_transcoder converter;
519
0
  return converter.convert<endianness::BIG>(buf, len, utf16_output);
520
0
}
521
522
simdutf_warn_unused result implementation::convert_utf8_to_utf16le_with_errors(
523
0
    const char *buf, size_t len, char16_t *utf16_output) const noexcept {
524
0
  utf8_to_utf16::validating_transcoder converter;
525
0
  return converter.convert_with_errors<endianness::LITTLE>(buf, len,
526
0
                                                           utf16_output);
527
0
}
528
529
simdutf_warn_unused result implementation::convert_utf8_to_utf16be_with_errors(
530
0
    const char *buf, size_t len, char16_t *utf16_output) const noexcept {
531
0
  utf8_to_utf16::validating_transcoder converter;
532
0
  return converter.convert_with_errors<endianness::BIG>(buf, len, utf16_output);
533
0
}
534
535
simdutf_warn_unused size_t implementation::convert_valid_utf8_to_utf16le(
536
0
    const char *input, size_t size, char16_t *utf16_output) const noexcept {
537
0
  return utf8_to_utf16::convert_valid<endianness::LITTLE>(input, size,
538
0
                                                          utf16_output);
539
0
}
540
541
simdutf_warn_unused size_t implementation::convert_valid_utf8_to_utf16be(
542
0
    const char *input, size_t size, char16_t *utf16_output) const noexcept {
543
0
  return utf8_to_utf16::convert_valid<endianness::BIG>(input, size,
544
0
                                                       utf16_output);
545
0
}
546
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
547
548
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
549
simdutf_warn_unused size_t implementation::convert_utf8_to_utf32(
550
0
    const char *buf, size_t len, char32_t *utf32_output) const noexcept {
551
0
  utf8_to_utf32::validating_transcoder converter;
552
0
  return converter.convert(buf, len, utf32_output);
553
0
}
554
555
simdutf_warn_unused result implementation::convert_utf8_to_utf32_with_errors(
556
0
    const char *buf, size_t len, char32_t *utf32_output) const noexcept {
557
0
  utf8_to_utf32::validating_transcoder converter;
558
0
  return converter.convert_with_errors(buf, len, utf32_output);
559
0
}
560
561
simdutf_warn_unused size_t implementation::convert_valid_utf8_to_utf32(
562
0
    const char *input, size_t size, char32_t *utf32_output) const noexcept {
563
0
  return utf8_to_utf32::convert_valid(input, size, utf32_output);
564
0
}
565
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
566
567
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
568
simdutf_warn_unused size_t implementation::convert_utf16le_to_latin1(
569
0
    const char16_t *buf, size_t len, char *latin1_output) const noexcept {
570
0
  std::pair<const char16_t *, char *> ret =
571
0
      haswell::avx2_convert_utf16_to_latin1<endianness::LITTLE>(buf, len,
572
0
                                                                latin1_output);
573
0
  if (ret.first == nullptr) {
574
0
    return 0;
575
0
  }
576
0
  size_t saved_bytes = ret.second - latin1_output;
577
0
  if (ret.first != buf + len) {
578
0
    const size_t scalar_saved_bytes =
579
0
        scalar::utf16_to_latin1::convert<endianness::LITTLE>(
580
0
            ret.first, len - (ret.first - buf), ret.second);
581
0
    if (scalar_saved_bytes == 0) {
582
0
      return 0;
583
0
    }
584
0
    saved_bytes += scalar_saved_bytes;
585
0
  }
586
0
  return saved_bytes;
587
0
}
588
589
simdutf_warn_unused size_t implementation::convert_utf16be_to_latin1(
590
0
    const char16_t *buf, size_t len, char *latin1_output) const noexcept {
591
0
  std::pair<const char16_t *, char *> ret =
592
0
      haswell::avx2_convert_utf16_to_latin1<endianness::BIG>(buf, len,
593
0
                                                             latin1_output);
594
0
  if (ret.first == nullptr) {
595
0
    return 0;
596
0
  }
597
0
  size_t saved_bytes = ret.second - latin1_output;
598
0
  if (ret.first != buf + len) {
599
0
    const size_t scalar_saved_bytes =
600
0
        scalar::utf16_to_latin1::convert<endianness::BIG>(
601
0
            ret.first, len - (ret.first - buf), ret.second);
602
0
    if (scalar_saved_bytes == 0) {
603
0
      return 0;
604
0
    }
605
0
    saved_bytes += scalar_saved_bytes;
606
0
  }
607
0
  return saved_bytes;
608
0
}
609
610
simdutf_warn_unused result
611
implementation::convert_utf16le_to_latin1_with_errors(
612
0
    const char16_t *buf, size_t len, char *latin1_output) const noexcept {
613
0
  std::pair<result, char *> ret =
614
0
      avx2_convert_utf16_to_latin1_with_errors<endianness::LITTLE>(
615
0
          buf, len, latin1_output);
616
0
  if (ret.first.error) {
617
0
    return ret.first;
618
0
  } // Can return directly since scalar fallback already found correct
619
    // ret.first.count
620
0
  if (ret.first.count != len) { // All good so far, but not finished
621
0
    result scalar_res =
622
0
        scalar::utf16_to_latin1::convert_with_errors<endianness::LITTLE>(
623
0
            buf + ret.first.count, len - ret.first.count, ret.second);
624
0
    if (scalar_res.error) {
625
0
      scalar_res.count += ret.first.count;
626
0
      return scalar_res;
627
0
    } else {
628
0
      ret.second += scalar_res.count;
629
0
    }
630
0
  }
631
0
  ret.first.count =
632
0
      ret.second -
633
0
      latin1_output; // Set count to the number of 8-bit code units written
634
0
  return ret.first;
635
0
}
636
637
simdutf_warn_unused result
638
implementation::convert_utf16be_to_latin1_with_errors(
639
0
    const char16_t *buf, size_t len, char *latin1_output) const noexcept {
640
0
  std::pair<result, char *> ret =
641
0
      avx2_convert_utf16_to_latin1_with_errors<endianness::BIG>(buf, len,
642
0
                                                                latin1_output);
643
0
  if (ret.first.error) {
644
0
    return ret.first;
645
0
  } // Can return directly since scalar fallback already found correct
646
    // ret.first.count
647
0
  if (ret.first.count != len) { // All good so far, but not finished
648
0
    result scalar_res =
649
0
        scalar::utf16_to_latin1::convert_with_errors<endianness::BIG>(
650
0
            buf + ret.first.count, len - ret.first.count, ret.second);
651
0
    if (scalar_res.error) {
652
0
      scalar_res.count += ret.first.count;
653
0
      return scalar_res;
654
0
    } else {
655
0
      ret.second += scalar_res.count;
656
0
    }
657
0
  }
658
0
  ret.first.count =
659
0
      ret.second -
660
0
      latin1_output; // Set count to the number of 8-bit code units written
661
0
  return ret.first;
662
0
}
663
664
simdutf_warn_unused size_t implementation::convert_valid_utf16be_to_latin1(
665
0
    const char16_t *buf, size_t len, char *latin1_output) const noexcept {
666
  // optimization opportunity: implement a custom function
667
0
  return convert_utf16be_to_latin1(buf, len, latin1_output);
668
0
}
669
670
simdutf_warn_unused size_t implementation::convert_valid_utf16le_to_latin1(
671
0
    const char16_t *buf, size_t len, char *latin1_output) const noexcept {
672
  // optimization opportunity: implement a custom function
673
0
  return convert_utf16le_to_latin1(buf, len, latin1_output);
674
0
}
675
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
676
677
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
678
simdutf_warn_unused size_t implementation::convert_utf16le_to_utf8(
679
0
    const char16_t *buf, size_t len, char *utf8_output) const noexcept {
680
0
  std::pair<const char16_t *, char *> ret =
681
0
      haswell::avx2_convert_utf16_to_utf8<endianness::LITTLE>(buf, len,
682
0
                                                              utf8_output);
683
0
  if (ret.first == nullptr) {
684
0
    return 0;
685
0
  }
686
0
  size_t saved_bytes = ret.second - utf8_output;
687
0
  if (ret.first != buf + len) {
688
0
    const size_t scalar_saved_bytes =
689
0
        scalar::utf16_to_utf8::convert<endianness::LITTLE>(
690
0
            ret.first, len - (ret.first - buf), ret.second);
691
0
    if (scalar_saved_bytes == 0) {
692
0
      return 0;
693
0
    }
694
0
    saved_bytes += scalar_saved_bytes;
695
0
  }
696
0
  return saved_bytes;
697
0
}
698
699
simdutf_warn_unused size_t implementation::convert_utf16be_to_utf8(
700
0
    const char16_t *buf, size_t len, char *utf8_output) const noexcept {
701
0
  std::pair<const char16_t *, char *> ret =
702
0
      haswell::avx2_convert_utf16_to_utf8<endianness::BIG>(buf, len,
703
0
                                                           utf8_output);
704
0
  if (ret.first == nullptr) {
705
0
    return 0;
706
0
  }
707
0
  size_t saved_bytes = ret.second - utf8_output;
708
0
  if (ret.first != buf + len) {
709
0
    const size_t scalar_saved_bytes =
710
0
        scalar::utf16_to_utf8::convert<endianness::BIG>(
711
0
            ret.first, len - (ret.first - buf), ret.second);
712
0
    if (scalar_saved_bytes == 0) {
713
0
      return 0;
714
0
    }
715
0
    saved_bytes += scalar_saved_bytes;
716
0
  }
717
0
  return saved_bytes;
718
0
}
719
720
template <endianness big_endian>
721
simdutf_really_inline full_result convert_utf16_to_utf8_with_details(
722
0
    const char16_t *buf, size_t len, char *utf8_output) {
723
0
  std::pair<result, char *> ret =
724
0
      haswell::avx2_convert_utf16_to_utf8_with_errors<big_endian>(buf, len,
725
0
                                                                  utf8_output);
726
0
  if (ret.first.error) {
727
0
    return full_result(ret.first.error, ret.first.count,
728
0
                       size_t(ret.second - utf8_output));
729
0
  }
730
0
  if (ret.first.count != len) {
731
0
    full_result sres =
732
0
        scalar::utf16_to_utf8::convert_with_errors<big_endian, false>(
733
0
            buf + ret.first.count, len - ret.first.count, ret.second, 0);
734
0
    return full_result(sres.error, ret.first.count + sres.input_count,
735
0
                       size_t(ret.second - utf8_output) + sres.output_count);
736
0
  }
737
0
  return full_result(error_code::SUCCESS, len,
738
0
                     size_t(ret.second - utf8_output));
739
0
}
Unexecuted instantiation: simdutf::full_result simdutf::haswell::convert_utf16_to_utf8_with_details<(simdutf::endianness)0>(char16_t const*, unsigned long, char*)
Unexecuted instantiation: simdutf::full_result simdutf::haswell::convert_utf16_to_utf8_with_details<(simdutf::endianness)1>(char16_t const*, unsigned long, char*)
740
741
simdutf_warn_unused result implementation::convert_utf16le_to_utf8_with_errors(
742
0
    const char16_t *buf, size_t len, char *utf8_output) const noexcept {
743
0
  return convert_utf16_to_utf8_with_details<endianness::LITTLE>(buf, len,
744
0
                                                                utf8_output);
745
0
}
746
747
simdutf_warn_unused result implementation::convert_utf16be_to_utf8_with_errors(
748
0
    const char16_t *buf, size_t len, char *utf8_output) const noexcept {
749
0
  return convert_utf16_to_utf8_with_details<endianness::BIG>(buf, len,
750
0
                                                             utf8_output);
751
0
}
752
753
simdutf_warn_unused size_t implementation::convert_valid_utf16le_to_utf8(
754
0
    const char16_t *buf, size_t len, char *utf8_output) const noexcept {
755
0
  return convert_utf16le_to_utf8(buf, len, utf8_output);
756
0
}
757
758
simdutf_warn_unused size_t implementation::convert_valid_utf16be_to_utf8(
759
0
    const char16_t *buf, size_t len, char *utf8_output) const noexcept {
760
0
  return convert_utf16be_to_utf8(buf, len, utf8_output);
761
0
}
762
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
763
764
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
765
simdutf_warn_unused size_t implementation::convert_utf32_to_utf8(
766
0
    const char32_t *buf, size_t len, char *utf8_output) const noexcept {
767
0
  std::pair<const char32_t *, char *> ret =
768
0
      avx2_convert_utf32_to_utf8(buf, len, utf8_output);
769
0
  if (ret.first == nullptr) {
770
0
    return 0;
771
0
  }
772
0
  size_t saved_bytes = ret.second - utf8_output;
773
0
  if (ret.first != buf + len) {
774
0
    const size_t scalar_saved_bytes = scalar::utf32_to_utf8::convert(
775
0
        ret.first, len - (ret.first - buf), ret.second);
776
0
    if (scalar_saved_bytes == 0) {
777
0
      return 0;
778
0
    }
779
0
    saved_bytes += scalar_saved_bytes;
780
0
  }
781
0
  return saved_bytes;
782
0
}
783
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
784
785
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
786
simdutf_warn_unused size_t implementation::convert_utf32_to_latin1(
787
0
    const char32_t *buf, size_t len, char *latin1_output) const noexcept {
788
0
  std::pair<const char32_t *, char *> ret =
789
0
      avx2_convert_utf32_to_latin1(buf, len, latin1_output);
790
0
  if (ret.first == nullptr) {
791
0
    return 0;
792
0
  }
793
0
  size_t saved_bytes = ret.second - latin1_output;
794
0
  if (ret.first != buf + len) {
795
0
    const size_t scalar_saved_bytes = scalar::utf32_to_latin1::convert(
796
0
        ret.first, len - (ret.first - buf), ret.second);
797
0
    if (scalar_saved_bytes == 0) {
798
0
      return 0;
799
0
    }
800
0
    saved_bytes += scalar_saved_bytes;
801
0
  }
802
0
  return saved_bytes;
803
0
}
804
805
simdutf_warn_unused result implementation::convert_utf32_to_latin1_with_errors(
806
0
    const char32_t *buf, size_t len, char *latin1_output) const noexcept {
807
  // ret.first.count is always the position in the buffer, not the number of
808
  // code units written even if finished
809
0
  std::pair<result, char *> ret =
810
0
      avx2_convert_utf32_to_latin1_with_errors(buf, len, latin1_output);
811
0
  if (ret.first.count != len) {
812
0
    result scalar_res = scalar::utf32_to_latin1::convert_with_errors(
813
0
        buf + ret.first.count, len - ret.first.count, ret.second);
814
0
    if (scalar_res.error) {
815
0
      scalar_res.count += ret.first.count;
816
0
      return scalar_res;
817
0
    } else {
818
0
      ret.second += scalar_res.count;
819
0
    }
820
0
  }
821
0
  ret.first.count =
822
0
      ret.second -
823
0
      latin1_output; // Set count to the number of 8-bit code units written
824
0
  return ret.first;
825
0
}
826
827
simdutf_warn_unused size_t implementation::convert_valid_utf32_to_latin1(
828
0
    const char32_t *buf, size_t len, char *latin1_output) const noexcept {
829
0
  return convert_utf32_to_latin1(buf, len, latin1_output);
830
0
}
831
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
832
833
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
834
simdutf_warn_unused result implementation::convert_utf32_to_utf8_with_errors(
835
0
    const char32_t *buf, size_t len, char *utf8_output) const noexcept {
836
  // ret.first.count is always the position in the buffer, not the number of
837
  // code units written even if finished
838
0
  std::pair<result, char *> ret =
839
0
      haswell::avx2_convert_utf32_to_utf8_with_errors(buf, len, utf8_output);
840
0
  if (ret.first.count != len) {
841
0
    result scalar_res = scalar::utf32_to_utf8::convert_with_errors(
842
0
        buf + ret.first.count, len - ret.first.count, ret.second);
843
0
    if (scalar_res.error) {
844
0
      scalar_res.count += ret.first.count;
845
0
      return scalar_res;
846
0
    } else {
847
0
      ret.second += scalar_res.count;
848
0
    }
849
0
  }
850
0
  ret.first.count =
851
0
      ret.second -
852
0
      utf8_output; // Set count to the number of 8-bit code units written
853
0
  return ret.first;
854
0
}
855
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
856
857
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
858
simdutf_warn_unused size_t implementation::convert_utf16le_to_utf32(
859
0
    const char16_t *buf, size_t len, char32_t *utf32_output) const noexcept {
860
0
  std::pair<const char16_t *, char32_t *> ret =
861
0
      haswell::avx2_convert_utf16_to_utf32<endianness::LITTLE>(buf, len,
862
0
                                                               utf32_output);
863
0
  if (ret.first == nullptr) {
864
0
    return 0;
865
0
  }
866
0
  size_t saved_bytes = ret.second - utf32_output;
867
0
  if (ret.first != buf + len) {
868
0
    const size_t scalar_saved_bytes =
869
0
        scalar::utf16_to_utf32::convert<endianness::LITTLE>(
870
0
            ret.first, len - (ret.first - buf), ret.second);
871
0
    if (scalar_saved_bytes == 0) {
872
0
      return 0;
873
0
    }
874
0
    saved_bytes += scalar_saved_bytes;
875
0
  }
876
0
  return saved_bytes;
877
0
}
878
879
simdutf_warn_unused size_t implementation::convert_utf16be_to_utf32(
880
0
    const char16_t *buf, size_t len, char32_t *utf32_output) const noexcept {
881
0
  std::pair<const char16_t *, char32_t *> ret =
882
0
      haswell::avx2_convert_utf16_to_utf32<endianness::BIG>(buf, len,
883
0
                                                            utf32_output);
884
0
  if (ret.first == nullptr) {
885
0
    return 0;
886
0
  }
887
0
  size_t saved_bytes = ret.second - utf32_output;
888
0
  if (ret.first != buf + len) {
889
0
    const size_t scalar_saved_bytes =
890
0
        scalar::utf16_to_utf32::convert<endianness::BIG>(
891
0
            ret.first, len - (ret.first - buf), ret.second);
892
0
    if (scalar_saved_bytes == 0) {
893
0
      return 0;
894
0
    }
895
0
    saved_bytes += scalar_saved_bytes;
896
0
  }
897
0
  return saved_bytes;
898
0
}
899
900
simdutf_warn_unused result implementation::convert_utf16le_to_utf32_with_errors(
901
0
    const char16_t *buf, size_t len, char32_t *utf32_output) const noexcept {
902
  // ret.first.count is always the position in the buffer, not the number of
903
  // code units written even if finished
904
0
  std::pair<result, char32_t *> ret =
905
0
      haswell::avx2_convert_utf16_to_utf32_with_errors<endianness::LITTLE>(
906
0
          buf, len, utf32_output);
907
0
  if (ret.first.error) {
908
0
    return ret.first;
909
0
  } // Can return directly since scalar fallback already found correct
910
    // ret.first.count
911
0
  if (ret.first.count != len) { // All good so far, but not finished
912
0
    result scalar_res =
913
0
        scalar::utf16_to_utf32::convert_with_errors<endianness::LITTLE>(
914
0
            buf + ret.first.count, len - ret.first.count, ret.second);
915
0
    if (scalar_res.error) {
916
0
      scalar_res.count += ret.first.count;
917
0
      return scalar_res;
918
0
    } else {
919
0
      ret.second += scalar_res.count;
920
0
    }
921
0
  }
922
0
  ret.first.count =
923
0
      ret.second -
924
0
      utf32_output; // Set count to the number of 8-bit code units written
925
0
  return ret.first;
926
0
}
927
928
simdutf_warn_unused result implementation::convert_utf16be_to_utf32_with_errors(
929
0
    const char16_t *buf, size_t len, char32_t *utf32_output) const noexcept {
930
  // ret.first.count is always the position in the buffer, not the number of
931
  // code units written even if finished
932
0
  std::pair<result, char32_t *> ret =
933
0
      haswell::avx2_convert_utf16_to_utf32_with_errors<endianness::BIG>(
934
0
          buf, len, utf32_output);
935
0
  if (ret.first.error) {
936
0
    return ret.first;
937
0
  } // Can return directly since scalar fallback already found correct
938
    // ret.first.count
939
0
  if (ret.first.count != len) { // All good so far, but not finished
940
0
    result scalar_res =
941
0
        scalar::utf16_to_utf32::convert_with_errors<endianness::BIG>(
942
0
            buf + ret.first.count, len - ret.first.count, ret.second);
943
0
    if (scalar_res.error) {
944
0
      scalar_res.count += ret.first.count;
945
0
      return scalar_res;
946
0
    } else {
947
0
      ret.second += scalar_res.count;
948
0
    }
949
0
  }
950
0
  ret.first.count =
951
0
      ret.second -
952
0
      utf32_output; // Set count to the number of 8-bit code units written
953
0
  return ret.first;
954
0
}
955
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
956
957
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
958
simdutf_warn_unused size_t implementation::convert_valid_utf32_to_utf8(
959
0
    const char32_t *buf, size_t len, char *utf8_output) const noexcept {
960
0
  return convert_utf32_to_utf8(buf, len, utf8_output);
961
0
}
962
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
963
964
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
965
simdutf_warn_unused size_t implementation::convert_utf32_to_utf16le(
966
0
    const char32_t *buf, size_t len, char16_t *utf16_output) const noexcept {
967
0
  std::pair<const char32_t *, char16_t *> ret =
968
0
      avx2_convert_utf32_to_utf16<endianness::LITTLE>(buf, len, utf16_output);
969
0
  if (ret.first == nullptr) {
970
0
    return 0;
971
0
  }
972
0
  size_t saved_bytes = ret.second - utf16_output;
973
0
  if (ret.first != buf + len) {
974
0
    const size_t scalar_saved_bytes =
975
0
        scalar::utf32_to_utf16::convert<endianness::LITTLE>(
976
0
            ret.first, len - (ret.first - buf), ret.second);
977
0
    if (scalar_saved_bytes == 0) {
978
0
      return 0;
979
0
    }
980
0
    saved_bytes += scalar_saved_bytes;
981
0
  }
982
0
  return saved_bytes;
983
0
}
984
985
simdutf_warn_unused size_t implementation::convert_utf32_to_utf16be(
986
0
    const char32_t *buf, size_t len, char16_t *utf16_output) const noexcept {
987
0
  std::pair<const char32_t *, char16_t *> ret =
988
0
      avx2_convert_utf32_to_utf16<endianness::BIG>(buf, len, utf16_output);
989
0
  if (ret.first == nullptr) {
990
0
    return 0;
991
0
  }
992
0
  size_t saved_bytes = ret.second - utf16_output;
993
0
  if (ret.first != buf + len) {
994
0
    const size_t scalar_saved_bytes =
995
0
        scalar::utf32_to_utf16::convert<endianness::BIG>(
996
0
            ret.first, len - (ret.first - buf), ret.second);
997
0
    if (scalar_saved_bytes == 0) {
998
0
      return 0;
999
0
    }
1000
0
    saved_bytes += scalar_saved_bytes;
1001
0
  }
1002
0
  return saved_bytes;
1003
0
}
1004
1005
simdutf_warn_unused result implementation::convert_utf32_to_utf16le_with_errors(
1006
0
    const char32_t *buf, size_t len, char16_t *utf16_output) const noexcept {
1007
  // ret.first.count is always the position in the buffer, not the number of
1008
  // code units written even if finished
1009
0
  std::pair<result, char16_t *> ret =
1010
0
      haswell::avx2_convert_utf32_to_utf16_with_errors<endianness::LITTLE>(
1011
0
          buf, len, utf16_output);
1012
0
  if (ret.first.count != len) {
1013
0
    result scalar_res =
1014
0
        scalar::utf32_to_utf16::convert_with_errors<endianness::LITTLE>(
1015
0
            buf + ret.first.count, len - ret.first.count, ret.second);
1016
0
    if (scalar_res.error) {
1017
0
      scalar_res.count += ret.first.count;
1018
0
      return scalar_res;
1019
0
    } else {
1020
0
      ret.second += scalar_res.count;
1021
0
    }
1022
0
  }
1023
0
  ret.first.count =
1024
0
      ret.second -
1025
0
      utf16_output; // Set count to the number of 8-bit code units written
1026
0
  return ret.first;
1027
0
}
1028
1029
simdutf_warn_unused result implementation::convert_utf32_to_utf16be_with_errors(
1030
0
    const char32_t *buf, size_t len, char16_t *utf16_output) const noexcept {
1031
  // ret.first.count is always the position in the buffer, not the number of
1032
  // code units written even if finished
1033
0
  std::pair<result, char16_t *> ret =
1034
0
      haswell::avx2_convert_utf32_to_utf16_with_errors<endianness::BIG>(
1035
0
          buf, len, utf16_output);
1036
0
  if (ret.first.count != len) {
1037
0
    result scalar_res =
1038
0
        scalar::utf32_to_utf16::convert_with_errors<endianness::BIG>(
1039
0
            buf + ret.first.count, len - ret.first.count, ret.second);
1040
0
    if (scalar_res.error) {
1041
0
      scalar_res.count += ret.first.count;
1042
0
      return scalar_res;
1043
0
    } else {
1044
0
      ret.second += scalar_res.count;
1045
0
    }
1046
0
  }
1047
0
  ret.first.count =
1048
0
      ret.second -
1049
0
      utf16_output; // Set count to the number of 8-bit code units written
1050
0
  return ret.first;
1051
0
}
1052
1053
simdutf_warn_unused size_t implementation::convert_valid_utf32_to_utf16le(
1054
0
    const char32_t *buf, size_t len, char16_t *utf16_output) const noexcept {
1055
0
  return convert_utf32_to_utf16le(buf, len, utf16_output);
1056
0
}
1057
1058
simdutf_warn_unused size_t implementation::convert_valid_utf32_to_utf16be(
1059
0
    const char32_t *buf, size_t len, char16_t *utf16_output) const noexcept {
1060
0
  return convert_utf32_to_utf16be(buf, len, utf16_output);
1061
0
}
1062
1063
simdutf_warn_unused size_t implementation::convert_valid_utf16le_to_utf32(
1064
0
    const char16_t *buf, size_t len, char32_t *utf32_output) const noexcept {
1065
0
  return convert_utf16le_to_utf32(buf, len, utf32_output);
1066
0
}
1067
1068
simdutf_warn_unused size_t implementation::convert_valid_utf16be_to_utf32(
1069
0
    const char16_t *buf, size_t len, char32_t *utf32_output) const noexcept {
1070
0
  return convert_utf16be_to_utf32(buf, len, utf32_output);
1071
0
}
1072
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
1073
1074
#if SIMDUTF_FEATURE_UTF16
1075
void implementation::change_endianness_utf16(const char16_t *input,
1076
                                             size_t length,
1077
130
                                             char16_t *output) const noexcept {
1078
130
  utf16::change_endianness_utf16(input, length, output);
1079
130
}
1080
1081
simdutf_warn_unused size_t implementation::count_utf16le(
1082
0
    const char16_t *input, size_t length) const noexcept {
1083
0
  return utf16::count_code_points<endianness::LITTLE>(input, length);
1084
0
}
1085
1086
simdutf_warn_unused size_t implementation::count_utf16be(
1087
0
    const char16_t *input, size_t length) const noexcept {
1088
0
  return utf16::count_code_points<endianness::BIG>(input, length);
1089
0
}
1090
#endif // SIMDUTF_FEATURE_UTF16
1091
1092
#if SIMDUTF_FEATURE_UTF8
1093
simdutf_warn_unused size_t
1094
0
implementation::count_utf8(const char *in, size_t size) const noexcept {
1095
0
  return utf8::count_code_points_bytemask(in, size);
1096
0
}
1097
#endif // SIMDUTF_FEATURE_UTF8
1098
1099
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1100
simdutf_warn_unused size_t implementation::latin1_length_from_utf8(
1101
0
    const char *buf, size_t len) const noexcept {
1102
0
  return count_utf8(buf, len);
1103
0
}
1104
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1105
1106
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1107
simdutf_warn_unused size_t implementation::utf8_length_from_utf16le(
1108
0
    const char16_t *input, size_t length) const noexcept {
1109
0
  return utf16::utf8_length_from_utf16_bytemask<endianness::LITTLE>(input,
1110
0
                                                                    length);
1111
0
}
1112
1113
simdutf_warn_unused size_t implementation::utf8_length_from_utf16be(
1114
0
    const char16_t *input, size_t length) const noexcept {
1115
0
  return utf16::utf8_length_from_utf16_bytemask<endianness::BIG>(input, length);
1116
0
}
1117
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1118
1119
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
1120
simdutf_warn_unused size_t implementation::utf32_length_from_utf16le(
1121
0
    const char16_t *input, size_t length) const noexcept {
1122
0
  return utf16::utf32_length_from_utf16<endianness::LITTLE>(input, length);
1123
0
}
1124
1125
simdutf_warn_unused size_t implementation::utf32_length_from_utf16be(
1126
0
    const char16_t *input, size_t length) const noexcept {
1127
0
  return utf16::utf32_length_from_utf16<endianness::BIG>(input, length);
1128
0
}
1129
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
1130
1131
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1132
simdutf_warn_unused size_t implementation::utf16_length_from_utf8(
1133
0
    const char *input, size_t length) const noexcept {
1134
0
  return utf8::utf16_length_from_utf8_bytemask(input, length);
1135
0
}
1136
simdutf_warn_unused result
1137
implementation::utf8_length_from_utf16le_with_replacement(
1138
0
    const char16_t *input, size_t length) const noexcept {
1139
0
  return utf16::utf8_length_from_utf16_with_replacement<endianness::LITTLE>(
1140
0
      input, length);
1141
0
}
1142
1143
simdutf_warn_unused result
1144
implementation::utf8_length_from_utf16be_with_replacement(
1145
0
    const char16_t *input, size_t length) const noexcept {
1146
0
  return utf16::utf8_length_from_utf16_with_replacement<endianness::BIG>(
1147
0
      input, length);
1148
0
}
1149
1150
simdutf_warn_unused size_t
1151
implementation::convert_utf16le_to_utf8_with_replacement(
1152
0
    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
1153
0
  return utf16_to_utf8::convert_with_replacement_via(
1154
0
      [](const char16_t *b, size_t l, char *o) {
1155
0
        return convert_utf16_to_utf8_with_details<endianness::LITTLE>(b, l, o);
1156
0
      },
1157
0
      input, length, utf8_buffer);
1158
0
}
1159
1160
simdutf_warn_unused size_t
1161
implementation::convert_utf16be_to_utf8_with_replacement(
1162
0
    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
1163
0
  return utf16_to_utf8::convert_with_replacement_via(
1164
0
      [](const char16_t *b, size_t l, char *o) {
1165
0
        return convert_utf16_to_utf8_with_details<endianness::BIG>(b, l, o);
1166
0
      },
1167
0
      input, length, utf8_buffer);
1168
0
}
1169
1170
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1171
1172
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1173
simdutf_warn_unused size_t implementation::utf8_length_from_latin1(
1174
0
    const char *input, size_t len) const noexcept {
1175
0
  const uint8_t *data = reinterpret_cast<const uint8_t *>(input);
1176
0
  size_t answer = len / sizeof(__m256i) * sizeof(__m256i);
1177
0
  size_t i = 0;
1178
0
  if (answer >= 2048) { // long strings optimization
1179
0
    __m256i four_64bits = _mm256_setzero_si256();
1180
0
    while (i + sizeof(__m256i) <= len) {
1181
0
      __m256i runner = _mm256_setzero_si256();
1182
      // We can do up to 255 loops without overflow.
1183
0
      size_t iterations = (len - i) / sizeof(__m256i);
1184
0
      if (iterations > 255) {
1185
0
        iterations = 255;
1186
0
      }
1187
0
      size_t max_i = i + iterations * sizeof(__m256i) - sizeof(__m256i);
1188
0
      for (; i + 4 * sizeof(__m256i) <= max_i; i += 4 * sizeof(__m256i)) {
1189
0
        __m256i input1 = _mm256_loadu_si256((const __m256i *)(data + i));
1190
0
        __m256i input2 =
1191
0
            _mm256_loadu_si256((const __m256i *)(data + i + sizeof(__m256i)));
1192
0
        __m256i input3 = _mm256_loadu_si256(
1193
0
            (const __m256i *)(data + i + 2 * sizeof(__m256i)));
1194
0
        __m256i input4 = _mm256_loadu_si256(
1195
0
            (const __m256i *)(data + i + 3 * sizeof(__m256i)));
1196
0
        __m256i input12 =
1197
0
            _mm256_add_epi8(_mm256_cmpgt_epi8(_mm256_setzero_si256(), input1),
1198
0
                            _mm256_cmpgt_epi8(_mm256_setzero_si256(), input2));
1199
0
        __m256i input23 =
1200
0
            _mm256_add_epi8(_mm256_cmpgt_epi8(_mm256_setzero_si256(), input3),
1201
0
                            _mm256_cmpgt_epi8(_mm256_setzero_si256(), input4));
1202
0
        __m256i input1234 = _mm256_add_epi8(input12, input23);
1203
0
        runner = _mm256_sub_epi8(runner, input1234);
1204
0
      }
1205
0
      for (; i <= max_i; i += sizeof(__m256i)) {
1206
0
        __m256i input_256_chunk =
1207
0
            _mm256_loadu_si256((const __m256i *)(data + i));
1208
0
        runner = _mm256_sub_epi8(
1209
0
            runner, _mm256_cmpgt_epi8(_mm256_setzero_si256(), input_256_chunk));
1210
0
      }
1211
0
      four_64bits = _mm256_add_epi64(
1212
0
          four_64bits, _mm256_sad_epu8(runner, _mm256_setzero_si256()));
1213
0
    }
1214
0
    answer += _mm256_extract_epi64(four_64bits, 0) +
1215
0
              _mm256_extract_epi64(four_64bits, 1) +
1216
0
              _mm256_extract_epi64(four_64bits, 2) +
1217
0
              _mm256_extract_epi64(four_64bits, 3);
1218
0
  } else if (answer > 0) {
1219
0
    for (; i + sizeof(__m256i) <= len; i += sizeof(__m256i)) {
1220
0
      __m256i latin = _mm256_loadu_si256((const __m256i *)(data + i));
1221
0
      uint32_t non_ascii = _mm256_movemask_epi8(latin);
1222
0
      answer += count_ones(non_ascii);
1223
0
    }
1224
0
  }
1225
0
  return answer + scalar::latin1::utf8_length_from_latin1(
1226
0
                      reinterpret_cast<const char *>(data + i), len - i);
1227
0
}
1228
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1229
1230
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1231
simdutf_warn_unused size_t implementation::utf8_length_from_utf32(
1232
0
    const char32_t *input, size_t length) const noexcept {
1233
0
  return utf32::utf8_length_from_utf32(input, length);
1234
0
}
1235
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1236
1237
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
1238
simdutf_warn_unused size_t implementation::utf16_length_from_utf32(
1239
0
    const char32_t *input, size_t length) const noexcept {
1240
0
  const __m256i v_00000000 = _mm256_setzero_si256();
1241
0
  const __m256i v_ffff0000 = _mm256_set1_epi32((uint32_t)0xffff0000);
1242
0
  size_t pos = 0;
1243
0
  size_t count = 0;
1244
0
  for (; pos + 8 <= length; pos += 8) {
1245
0
    __m256i in = _mm256_loadu_si256((__m256i *)(input + pos));
1246
0
    const __m256i surrogate_bytemask =
1247
0
        _mm256_cmpeq_epi32(_mm256_and_si256(in, v_ffff0000), v_00000000);
1248
0
    const uint32_t surrogate_bitmask =
1249
0
        static_cast<uint32_t>(_mm256_movemask_epi8(surrogate_bytemask));
1250
0
    size_t surrogate_count = (32 - count_ones(surrogate_bitmask)) / 4;
1251
0
    count += 8 + surrogate_count;
1252
0
  }
1253
0
  return count +
1254
0
         scalar::utf32::utf16_length_from_utf32(input + pos, length - pos);
1255
0
}
1256
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
1257
1258
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1259
simdutf_warn_unused size_t implementation::utf32_length_from_utf8(
1260
0
    const char *input, size_t length) const noexcept {
1261
0
  return utf8::count_code_points(input, length);
1262
0
}
1263
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1264
1265
#if SIMDUTF_FEATURE_BASE64
1266
simdutf_warn_unused result implementation::base64_to_binary(
1267
    const char *input, size_t length, char *output, base64_options options,
1268
0
    last_chunk_handling_options last_chunk_options) const noexcept {
1269
0
  if (options & base64_default_or_url) {
1270
0
    if (options == base64_options::base64_default_or_url_accept_garbage) {
1271
0
      return base64::compress_decode_base64<false, true, true>(
1272
0
          output, input, length, options, last_chunk_options);
1273
0
    } else {
1274
0
      return base64::compress_decode_base64<false, false, true>(
1275
0
          output, input, length, options, last_chunk_options);
1276
0
    }
1277
0
  } else if (options & base64_url) {
1278
0
    if (options == base64_options::base64_url_accept_garbage) {
1279
0
      return base64::compress_decode_base64<true, true, false>(
1280
0
          output, input, length, options, last_chunk_options);
1281
0
    } else {
1282
0
      return base64::compress_decode_base64<true, false, false>(
1283
0
          output, input, length, options, last_chunk_options);
1284
0
    }
1285
0
  } else {
1286
0
    if (options == base64_options::base64_default_accept_garbage) {
1287
0
      return base64::compress_decode_base64<false, true, false>(
1288
0
          output, input, length, options, last_chunk_options);
1289
0
    } else {
1290
0
      return base64::compress_decode_base64<false, false, false>(
1291
0
          output, input, length, options, last_chunk_options);
1292
0
    }
1293
0
  }
1294
0
}
1295
1296
simdutf_warn_unused full_result implementation::base64_to_binary_details(
1297
    const char *input, size_t length, char *output, base64_options options,
1298
0
    last_chunk_handling_options last_chunk_options) const noexcept {
1299
0
  if (options & base64_default_or_url) {
1300
0
    if (options == base64_options::base64_default_or_url_accept_garbage) {
1301
0
      return base64::compress_decode_base64<false, true, true>(
1302
0
          output, input, length, options, last_chunk_options);
1303
0
    } else {
1304
0
      return base64::compress_decode_base64<false, false, true>(
1305
0
          output, input, length, options, last_chunk_options);
1306
0
    }
1307
0
  } else if (options & base64_url) {
1308
0
    if (options == base64_options::base64_url_accept_garbage) {
1309
0
      return base64::compress_decode_base64<true, true, false>(
1310
0
          output, input, length, options, last_chunk_options);
1311
0
    } else {
1312
0
      return base64::compress_decode_base64<true, false, false>(
1313
0
          output, input, length, options, last_chunk_options);
1314
0
    }
1315
0
  } else {
1316
0
    if (options == base64_options::base64_default_accept_garbage) {
1317
0
      return base64::compress_decode_base64<false, true, false>(
1318
0
          output, input, length, options, last_chunk_options);
1319
0
    } else {
1320
0
      return base64::compress_decode_base64<false, false, false>(
1321
0
          output, input, length, options, last_chunk_options);
1322
0
    }
1323
0
  }
1324
0
}
1325
1326
simdutf_warn_unused result implementation::base64_to_binary(
1327
    const char16_t *input, size_t length, char *output, base64_options options,
1328
0
    last_chunk_handling_options last_chunk_options) const noexcept {
1329
0
  if (options & base64_default_or_url) {
1330
0
    if (options == base64_options::base64_default_or_url_accept_garbage) {
1331
0
      return base64::compress_decode_base64<false, true, true>(
1332
0
          output, input, length, options, last_chunk_options);
1333
0
    } else {
1334
0
      return base64::compress_decode_base64<false, false, true>(
1335
0
          output, input, length, options, last_chunk_options);
1336
0
    }
1337
0
  } else if (options & base64_url) {
1338
0
    if (options == base64_options::base64_url_accept_garbage) {
1339
0
      return base64::compress_decode_base64<true, true, false>(
1340
0
          output, input, length, options, last_chunk_options);
1341
0
    } else {
1342
0
      return base64::compress_decode_base64<true, false, false>(
1343
0
          output, input, length, options, last_chunk_options);
1344
0
    }
1345
0
  } else {
1346
0
    if (options == base64_options::base64_default_accept_garbage) {
1347
0
      return base64::compress_decode_base64<false, true, false>(
1348
0
          output, input, length, options, last_chunk_options);
1349
0
    } else {
1350
0
      return base64::compress_decode_base64<false, false, false>(
1351
0
          output, input, length, options, last_chunk_options);
1352
0
    }
1353
0
  }
1354
0
}
1355
1356
simdutf_warn_unused full_result implementation::base64_to_binary_details(
1357
    const char16_t *input, size_t length, char *output, base64_options options,
1358
0
    last_chunk_handling_options last_chunk_options) const noexcept {
1359
0
  if (options & base64_default_or_url) {
1360
0
    if (options == base64_options::base64_default_or_url_accept_garbage) {
1361
0
      return base64::compress_decode_base64<false, true, true>(
1362
0
          output, input, length, options, last_chunk_options);
1363
0
    } else {
1364
0
      return base64::compress_decode_base64<false, false, true>(
1365
0
          output, input, length, options, last_chunk_options);
1366
0
    }
1367
0
  } else if (options & base64_url) {
1368
0
    if (options == base64_options::base64_url_accept_garbage) {
1369
0
      return base64::compress_decode_base64<true, true, false>(
1370
0
          output, input, length, options, last_chunk_options);
1371
0
    } else {
1372
0
      return base64::compress_decode_base64<true, false, false>(
1373
0
          output, input, length, options, last_chunk_options);
1374
0
    }
1375
0
  } else {
1376
0
    if (options == base64_options::base64_default_accept_garbage) {
1377
0
      return base64::compress_decode_base64<false, true, false>(
1378
0
          output, input, length, options, last_chunk_options);
1379
0
    } else {
1380
0
      return base64::compress_decode_base64<false, false, false>(
1381
0
          output, input, length, options, last_chunk_options);
1382
0
    }
1383
0
  }
1384
0
}
1385
1386
size_t implementation::binary_to_base64(const char *input, size_t length,
1387
                                        char *output,
1388
0
                                        base64_options options) const noexcept {
1389
0
  if (options & base64_url) {
1390
0
    return encode_base64<true>(output, input, length, options);
1391
0
  } else {
1392
0
    return encode_base64<false>(output, input, length, options);
1393
0
  }
1394
0
}
1395
1396
size_t implementation::binary_to_base64_with_lines(
1397
    const char *input, size_t length, char *output, size_t line_length,
1398
0
    base64_options options) const noexcept {
1399
0
  if (options & base64_url) {
1400
0
    return avx2_encode_base64_impl<true, true>(output, input, length, options,
1401
0
                                               line_length);
1402
0
  } else {
1403
0
    return avx2_encode_base64_impl<false, true>(output, input, length, options,
1404
0
                                                line_length);
1405
0
  }
1406
0
}
1407
1408
const char *implementation::find(const char *start, const char *end,
1409
0
                                 char character) const noexcept {
1410
0
  return util::find(start, end, character);
1411
0
}
1412
1413
const char16_t *implementation::find(const char16_t *start, const char16_t *end,
1414
0
                                     char16_t character) const noexcept {
1415
0
  return util::find(start, end, character);
1416
0
}
1417
1418
simdutf_warn_unused size_t implementation::binary_length_from_base64(
1419
0
    const char *input, size_t length) const noexcept {
1420
0
  return avx2_binary_length_from_base64(input, length);
1421
0
}
1422
1423
simdutf_warn_unused size_t implementation::binary_length_from_base64(
1424
0
    const char16_t *input, size_t length) const noexcept {
1425
0
  return avx2_binary_length_from_base64(input, length);
1426
0
}
1427
#endif // SIMDUTF_FEATURE_BASE64
1428
1429
} // namespace SIMDUTF_IMPLEMENTATION
1430
} // namespace simdutf
1431
1432
#include "simdutf/haswell/end.h"