Coverage Report

Created: 2026-09-14 07:00

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