Coverage Report

Created: 2025-07-11 06:12

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