Coverage Report

Created: 2026-10-17 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/include/simdutf/implementation.h
Line
Count
Source
1
#ifndef SIMDUTF_IMPLEMENTATION_H
2
#define SIMDUTF_IMPLEMENTATION_H
3
#if !defined(SIMDUTF_NO_THREADS)
4
  #include <atomic>
5
#endif
6
#ifdef SIMDUTF_INTERNAL_TESTS
7
  #include <vector>
8
#endif
9
#include "simdutf/common_defs.h"
10
#include "simdutf/compiler_check.h"
11
#include "simdutf/encoding_types.h"
12
#include "simdutf/error.h"
13
#include "simdutf/internal/isadetection.h"
14
15
#include <string_view>
16
#if SIMDUTF_SPAN
17
  #include <concepts>
18
  #include <type_traits>
19
  #include <span>
20
  #include <tuple>
21
  #include <utility> // for std::unreachable
22
#endif
23
// The following defines are conditionally enabled/disabled during amalgamation.
24
// By default all features are enabled, regular code shouldn't check them. Only
25
// when user code really relies of a selected subset, it's good to verify these
26
// flags, like:
27
//
28
//      #if !SIMDUTF_FEATURE_UTF16
29
//      #   error("Please amalgamate simdutf with UTF-16 support")
30
//      #endif
31
//
32
#ifndef SIMDUTF_FEATURE_DETECT_ENCODING
33
  #define SIMDUTF_FEATURE_DETECT_ENCODING 1
34
#endif
35
#ifndef SIMDUTF_FEATURE_ASCII
36
  #define SIMDUTF_FEATURE_ASCII 1
37
#endif
38
#ifndef SIMDUTF_FEATURE_LATIN1
39
  #define SIMDUTF_FEATURE_LATIN1 1
40
#endif
41
#ifndef SIMDUTF_FEATURE_UTF8
42
  #define SIMDUTF_FEATURE_UTF8 1
43
#endif
44
#ifndef SIMDUTF_FEATURE_UTF16
45
  #define SIMDUTF_FEATURE_UTF16 1
46
#endif
47
#ifndef SIMDUTF_FEATURE_UTF32
48
  #define SIMDUTF_FEATURE_UTF32 1
49
#endif
50
#ifndef SIMDUTF_FEATURE_BASE64
51
  #define SIMDUTF_FEATURE_BASE64 1
52
#endif
53
54
/// helpers placed in namespace detail are not a part of the public API
55
namespace simdutf {
56
namespace detail {
57
namespace {
58
// this is to avoid including <algorithm> just for min
59
0
constexpr std::size_t min(std::size_t a, std::size_t b) {
60
0
  return a < b ? a : b;
61
0
}
62
template <typename T, typename U>
63
constexpr std::size_t min(const T &a, const U &b) = delete;
64
} // namespace
65
} // namespace detail
66
} // namespace simdutf
67
68
#if SIMDUTF_CPLUSPLUS23
69
  #include <simdutf/constexpr_ptr.h>
70
#endif
71
72
#if SIMDUTF_SPAN
73
/// helpers placed in namespace detail are not a part of the public API
74
namespace simdutf {
75
namespace detail {
76
/**
77
 * matches a byte, in the many ways C++ allows. note that these
78
 * are all distinct types.
79
 */
80
template <typename T>
81
concept byte_like = std::is_same_v<T, std::byte> ||     //
82
                    std::is_same_v<T, char> ||          //
83
                    std::is_same_v<T, signed char> ||   //
84
                    std::is_same_v<T, unsigned char> || //
85
                    std::is_same_v<T, char8_t>;
86
87
template <typename T>
88
concept is_byte_like = byte_like<std::remove_cvref_t<T>>;
89
90
template <typename T>
91
concept is_pointer = std::is_pointer_v<T>;
92
93
/**
94
 * matches anything that behaves like std::span and points to character-like
95
 * data such as: std::byte, char, unsigned char, signed char, std::int8_t,
96
 * std::uint8_t
97
 */
98
template <typename T>
99
concept input_span_of_byte_like = requires(const T &t) {
100
  { t.size() } noexcept -> std::convertible_to<std::size_t>;
101
  { t.data() } noexcept -> is_pointer;
102
  { *t.data() } noexcept -> is_byte_like;
103
};
104
105
template <typename T>
106
concept is_mutable = !std::is_const_v<std::remove_reference_t<T>>;
107
108
/**
109
 * like span_of_byte_like, but for an output span (intended to be written to)
110
 */
111
template <typename T>
112
concept output_span_of_byte_like = requires(T &t) {
113
  { t.size() } noexcept -> std::convertible_to<std::size_t>;
114
  { t.data() } noexcept -> is_pointer;
115
  { *t.data() } noexcept -> is_byte_like;
116
  { *t.data() } noexcept -> is_mutable;
117
};
118
119
/**
120
 * a pointer like object, when indexed, results in a byte like result.
121
 * valid examples: char*, const char*, std::array<char,10>
122
 * invalid examples: int*, std::array<int,10>
123
 */
124
template <class InputPtr>
125
concept indexes_into_byte_like = requires(InputPtr p) {
126
  { std::decay_t<decltype(p[0])>{} } -> simdutf::detail::byte_like;
127
};
128
template <class InputPtr>
129
concept indexes_into_utf16 = requires(InputPtr p) {
130
  { std::decay_t<decltype(p[0])>{} } -> std::same_as<char16_t>;
131
};
132
template <class InputPtr>
133
concept indexes_into_utf32 = requires(InputPtr p) {
134
  { std::decay_t<decltype(p[0])>{} } -> std::same_as<char32_t>;
135
};
136
137
template <class InputPtr>
138
concept index_assignable_from_char = requires(InputPtr p, char s) {
139
  { p[0] = s };
140
};
141
142
/**
143
 * a pointer like object that results in a uint32_t when indexed.
144
 * valid examples: uint32_t*
145
 */
146
template <class InputPtr>
147
concept indexes_into_uint32 = requires(InputPtr p) {
148
  { std::decay_t<decltype(p[0])>{} } -> std::same_as<std::uint32_t>;
149
};
150
} // namespace detail
151
} // namespace simdutf
152
#endif // SIMDUTF_SPAN
153
154
// these includes are needed for constexpr support. they are
155
// not part of the public api.
156
#include <simdutf/scalar/swap_bytes.h>
157
#include <simdutf/scalar/ascii.h>
158
#include <simdutf/scalar/atomic_util.h>
159
#include <simdutf/scalar/latin1.h>
160
#include <simdutf/scalar/latin1_to_utf16/latin1_to_utf16.h>
161
#include <simdutf/scalar/latin1_to_utf32/latin1_to_utf32.h>
162
#include <simdutf/scalar/latin1_to_utf8/latin1_to_utf8.h>
163
#include <simdutf/scalar/utf16.h>
164
#include <simdutf/scalar/utf16_to_latin1/utf16_to_latin1.h>
165
#include <simdutf/scalar/utf16_to_latin1/valid_utf16_to_latin1.h>
166
#include <simdutf/scalar/utf16_to_utf32/utf16_to_utf32.h>
167
#include <simdutf/scalar/utf16_to_utf32/valid_utf16_to_utf32.h>
168
#include <simdutf/scalar/utf16_to_utf8/utf16_to_utf8.h>
169
#include <simdutf/scalar/utf16_to_utf8/valid_utf16_to_utf8.h>
170
#include <simdutf/scalar/utf32.h>
171
#include <simdutf/scalar/utf32_to_latin1/utf32_to_latin1.h>
172
#include <simdutf/scalar/utf32_to_latin1/valid_utf32_to_latin1.h>
173
#include <simdutf/scalar/utf32_to_utf16/utf32_to_utf16.h>
174
#include <simdutf/scalar/utf32_to_utf16/valid_utf32_to_utf16.h>
175
#include <simdutf/scalar/utf32_to_utf8/utf32_to_utf8.h>
176
#include <simdutf/scalar/utf32_to_utf8/valid_utf32_to_utf8.h>
177
#include <simdutf/scalar/utf8.h>
178
#include <simdutf/scalar/utf8_to_latin1/utf8_to_latin1.h>
179
#include <simdutf/scalar/utf8_to_latin1/valid_utf8_to_latin1.h>
180
#include <simdutf/scalar/utf8_to_utf16/utf8_to_utf16.h>
181
#include <simdutf/scalar/utf8_to_utf16/utf8_to_utf16_with_replacement.h>
182
#include <simdutf/scalar/utf8_to_utf16/valid_utf8_to_utf16.h>
183
#include <simdutf/scalar/utf8_to_utf32/utf8_to_utf32.h>
184
#include <simdutf/scalar/utf8_to_utf32/valid_utf8_to_utf32.h>
185
186
namespace simdutf {
187
188
constexpr size_t default_line_length =
189
    76; ///< default line length for base64 encoding with lines
190
191
#if SIMDUTF_FEATURE_DETECT_ENCODING
192
/**
193
 * Autodetect the encoding of the input, a single encoding is recommended.
194
 * E.g., the function might return simdutf::encoding_type::UTF8,
195
 * simdutf::encoding_type::UTF16_LE, simdutf::encoding_type::UTF16_BE, or
196
 * simdutf::encoding_type::UTF32_LE.
197
 *
198
 * @param input the string to analyze.
199
 * @param length the length of the string in bytes.
200
 * @return the detected encoding type
201
 */
202
simdutf_warn_unused simdutf::encoding_type
203
autodetect_encoding(const char *input, size_t length) noexcept;
204
simdutf_really_inline simdutf_warn_unused simdutf::encoding_type
205
0
autodetect_encoding(const uint8_t *input, size_t length) noexcept {
206
0
  return autodetect_encoding(reinterpret_cast<const char *>(input), length);
207
0
}
208
  #if SIMDUTF_SPAN
209
/**
210
 * Autodetect the encoding of the input, a single encoding is recommended.
211
 * E.g., the function might return simdutf::encoding_type::UTF8,
212
 * simdutf::encoding_type::UTF16_LE, simdutf::encoding_type::UTF16_BE, or
213
 * simdutf::encoding_type::UTF32_LE.
214
 *
215
 * @param input the string to analyze. can be a anything span-like that has a
216
 * data() and size() that points to character data: std::string,
217
 * std::string_view, std::vector<char>, std::span<const std::byte> etc.
218
 * @return the detected encoding type
219
 */
220
simdutf_really_inline simdutf_warn_unused simdutf::encoding_type
221
autodetect_encoding(
222
    const detail::input_span_of_byte_like auto &input) noexcept {
223
  return autodetect_encoding(reinterpret_cast<const char *>(input.data()),
224
                             input.size());
225
}
226
  #endif // SIMDUTF_SPAN
227
228
/**
229
 * Autodetect the possible encodings of the input in one pass.
230
 * E.g., if the input might be UTF-16LE or UTF-8, this function returns
231
 * the value (simdutf::encoding_type::UTF8 | simdutf::encoding_type::UTF16_LE).
232
 *
233
 * Overridden by each implementation.
234
 *
235
 * @param input the string to analyze.
236
 * @param length the length of the string in bytes.
237
 * @return the detected encoding type
238
 */
239
simdutf_warn_unused int detect_encodings(const char *input,
240
                                         size_t length) noexcept;
241
simdutf_really_inline simdutf_warn_unused int
242
0
detect_encodings(const uint8_t *input, size_t length) noexcept {
243
0
  return detect_encodings(reinterpret_cast<const char *>(input), length);
244
0
}
245
  #if SIMDUTF_SPAN
246
simdutf_really_inline simdutf_warn_unused int
247
detect_encodings(const detail::input_span_of_byte_like auto &input) noexcept {
248
  return detect_encodings(reinterpret_cast<const char *>(input.data()),
249
                          input.size());
250
}
251
  #endif // SIMDUTF_SPAN
252
#endif   // SIMDUTF_FEATURE_DETECT_ENCODING
253
254
#if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
255
/**
256
 * Validate the UTF-8 string. This function may be best when you expect
257
 * the input to be almost always valid. Otherwise, consider using
258
 * validate_utf8_with_errors.
259
 *
260
 * Overridden by each implementation.
261
 *
262
 * @param buf the UTF-8 string to validate.
263
 * @param len the length of the string in bytes.
264
 * @return true if and only if the string is valid UTF-8.
265
 */
266
simdutf_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept;
267
  #if SIMDUTF_SPAN
268
simdutf_constexpr23 simdutf_really_inline simdutf_warn_unused bool
269
validate_utf8(const detail::input_span_of_byte_like auto &input) noexcept {
270
    #if SIMDUTF_CPLUSPLUS23
271
  if consteval {
272
    return scalar::utf8::validate(
273
        detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size());
274
  } else
275
    #endif
276
  {
277
    return validate_utf8(reinterpret_cast<const char *>(input.data()),
278
                         input.size());
279
  }
280
}
281
  #endif // SIMDUTF_SPAN
282
#endif   // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
283
284
#if SIMDUTF_FEATURE_UTF8
285
/**
286
 * Validate the UTF-8 string and stop on error.
287
 *
288
 * Overridden by each implementation.
289
 *
290
 * @param buf the UTF-8 string to validate.
291
 * @param len the length of the string in bytes.
292
 * @return a result pair struct (of type simdutf::result containing the two
293
 * fields error and count) with an error code and either position of the error
294
 * (in the input in code units) if any, or the number of code units validated if
295
 * successful.
296
 */
297
simdutf_warn_unused result validate_utf8_with_errors(const char *buf,
298
                                                     size_t len) noexcept;
299
  #if SIMDUTF_SPAN
300
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result
301
validate_utf8_with_errors(
302
    const detail::input_span_of_byte_like auto &input) noexcept {
303
    #if SIMDUTF_CPLUSPLUS23
304
  if consteval {
305
    return scalar::utf8::validate_with_errors(
306
        detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size());
307
  } else
308
    #endif
309
  {
310
    return validate_utf8_with_errors(
311
        reinterpret_cast<const char *>(input.data()), input.size());
312
  }
313
}
314
  #endif // SIMDUTF_SPAN
315
#endif   // SIMDUTF_FEATURE_UTF8
316
317
#if SIMDUTF_FEATURE_UTF8
318
/**
319
 * Validate the UTF-8 string and stop on error, while counting the number of
320
 * continuation bytes and of four-byte sequences in the valid prefix.
321
 *
322
 * Overridden by each implementation.
323
 *
324
 * These two counts are enough to derive, without a second pass over the input,
325
 * both the number of code points (input_count - continuation_count) and the
326
 * number of UTF-16 code units (input_count - continuation_count +
327
 * four_byte_count) of the valid prefix. The utf32_length() and utf16_length()
328
 * helpers return them.
329
 *
330
 * @param buf the UTF-8 string to validate.
331
 * @param len the length of the string in bytes.
332
 * @return a utf8_result struct with an error code, the number of bytes in the
333
 * valid prefix (input_count), and the counts of continuation bytes and of
334
 * four-byte sequences within it.
335
 */
336
simdutf_warn_unused utf8_result validate_utf8_with_counts(const char *buf,
337
                                                          size_t len) noexcept;
338
  #if SIMDUTF_SPAN
339
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused utf8_result
340
validate_utf8_with_counts(
341
    const detail::input_span_of_byte_like auto &input) noexcept {
342
    #if SIMDUTF_CPLUSPLUS23
343
  if consteval {
344
    return scalar::utf8::validate_with_counts(
345
        detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size());
346
  } else
347
    #endif
348
  {
349
    return validate_utf8_with_counts(
350
        reinterpret_cast<const char *>(input.data()), input.size());
351
  }
352
}
353
  #endif // SIMDUTF_SPAN
354
#endif   // SIMDUTF_FEATURE_UTF8
355
356
#if SIMDUTF_FEATURE_ASCII
357
/**
358
 * Validate the ASCII string.
359
 *
360
 * Overridden by each implementation.
361
 *
362
 * @param buf the ASCII string to validate.
363
 * @param len the length of the string in bytes.
364
 * @return true if and only if the string is valid ASCII.
365
 */
366
simdutf_warn_unused bool validate_ascii(const char *buf, size_t len) noexcept;
367
  #if SIMDUTF_SPAN
368
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool
369
validate_ascii(const detail::input_span_of_byte_like auto &input) noexcept {
370
    #if SIMDUTF_CPLUSPLUS23
371
  if consteval {
372
    return scalar::ascii::validate(
373
        detail::constexpr_cast_ptr<std::uint8_t>(input.data()), input.size());
374
  } else
375
    #endif
376
  {
377
    return validate_ascii(reinterpret_cast<const char *>(input.data()),
378
                          input.size());
379
  }
380
}
381
  #endif // SIMDUTF_SPAN
382
383
/**
384
 * Validate the ASCII string and stop on error. It might be faster than
385
 * validate_utf8 when an error is expected to occur early.
386
 *
387
 * Overridden by each implementation.
388
 *
389
 * @param buf the ASCII string to validate.
390
 * @param len the length of the string in bytes.
391
 * @return a result pair struct (of type simdutf::result containing the two
392
 * fields error and count) with an error code and either position of the error
393
 * (in the input in code units) if any, or the number of code units validated if
394
 * successful.
395
 */
396
simdutf_warn_unused result validate_ascii_with_errors(const char *buf,
397
                                                      size_t len) noexcept;
398
  #if SIMDUTF_SPAN
399
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
400
validate_ascii_with_errors(
401
    const detail::input_span_of_byte_like auto &input) noexcept {
402
    #if SIMDUTF_CPLUSPLUS23
403
  if consteval {
404
    return scalar::ascii::validate_with_errors(
405
        detail::constexpr_cast_ptr<std::uint8_t>(input.data()), input.size());
406
  } else
407
    #endif
408
  {
409
    return validate_ascii_with_errors(
410
        reinterpret_cast<const char *>(input.data()), input.size());
411
  }
412
}
413
  #endif // SIMDUTF_SPAN
414
#endif   // SIMDUTF_FEATURE_ASCII
415
416
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII
417
/**
418
 * Validate the ASCII string as a UTF-16 sequence.
419
 * An UTF-16 sequence is considered an ASCII sequence
420
 * if it could be converted to an ASCII string losslessly.
421
 *
422
 * Overridden by each implementation.
423
 *
424
 * @param buf the UTF-16 string to validate.
425
 * @param len the length of the string in bytes.
426
 * @return true if and only if the string is valid ASCII.
427
 */
428
simdutf_warn_unused bool validate_utf16_as_ascii(const char16_t *buf,
429
                                                 size_t len) noexcept;
430
  #if SIMDUTF_SPAN
431
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool
432
0
validate_utf16_as_ascii(std::span<const char16_t> input) noexcept {
433
0
    #if SIMDUTF_CPLUSPLUS23
434
0
  if consteval {
435
0
    return scalar::utf16::validate_as_ascii<endianness::NATIVE>(input.data(),
436
0
                                                                input.size());
437
0
  } else
438
0
    #endif
439
0
  {
440
0
    return validate_utf16_as_ascii(input.data(), input.size());
441
0
  }
442
0
}
443
  #endif // SIMDUTF_SPAN
444
445
/**
446
 * Validate the ASCII string as a UTF-16BE sequence.
447
 * An UTF-16 sequence is considered an ASCII sequence
448
 * if it could be converted to an ASCII string losslessly.
449
 *
450
 * Overridden by each implementation.
451
 *
452
 * @param buf the UTF-16BE string to validate.
453
 * @param len the length of the string in bytes.
454
 * @return true if and only if the string is valid ASCII.
455
 */
456
simdutf_warn_unused bool validate_utf16be_as_ascii(const char16_t *buf,
457
                                                   size_t len) noexcept;
458
  #if SIMDUTF_SPAN
459
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool
460
0
validate_utf16be_as_ascii(std::span<const char16_t> input) noexcept {
461
0
    #if SIMDUTF_CPLUSPLUS23
462
0
  if consteval {
463
0
    return scalar::utf16::validate_as_ascii<endianness::BIG>(input.data(),
464
0
                                                             input.size());
465
0
  } else
466
0
    #endif
467
0
  {
468
0
    return validate_utf16be_as_ascii(input.data(), input.size());
469
0
  }
470
0
}
471
  #endif // SIMDUTF_SPAN
472
473
/**
474
 * Validate the ASCII string as a UTF-16LE sequence.
475
 * An UTF-16 sequence is considered an ASCII sequence
476
 * if it could be converted to an ASCII string losslessly.
477
 *
478
 * Overridden by each implementation.
479
 *
480
 * @param buf the UTF-16LE string to validate.
481
 * @param len the length of the string in bytes.
482
 * @return true if and only if the string is valid ASCII.
483
 */
484
simdutf_warn_unused bool validate_utf16le_as_ascii(const char16_t *buf,
485
                                                   size_t len) noexcept;
486
  #if SIMDUTF_SPAN
487
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool
488
0
validate_utf16le_as_ascii(std::span<const char16_t> input) noexcept {
489
0
    #if SIMDUTF_CPLUSPLUS23
490
0
  if consteval {
491
0
    return scalar::utf16::validate_as_ascii<endianness::LITTLE>(input.data(),
492
0
                                                                input.size());
493
0
  } else
494
0
    #endif
495
0
  {
496
0
    return validate_utf16le_as_ascii(input.data(), input.size());
497
0
  }
498
0
}
499
  #endif // SIMDUTF_SPAN
500
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII
501
502
#if SIMDUTF_FEATURE_UTF16
503
/**
504
 * Using native endianness; Validate the UTF-16 string.
505
 * This function may be best when you expect the input to be almost always
506
 * valid. Otherwise, consider using validate_utf16_with_errors.
507
 *
508
 * Overridden by each implementation.
509
 *
510
 * This function is not BOM-aware.
511
 *
512
 * @param buf the UTF-16 string to validate.
513
 * @param len the length of the string in number of 2-byte code units
514
 * (char16_t).
515
 * @return true if and only if the string is valid UTF-16.
516
 */
517
simdutf_warn_unused bool validate_utf16(const char16_t *buf,
518
                                        size_t len) noexcept;
519
  #if SIMDUTF_SPAN
520
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool
521
0
validate_utf16(std::span<const char16_t> input) noexcept {
522
0
    #if SIMDUTF_CPLUSPLUS23
523
0
  if consteval {
524
0
    return scalar::utf16::validate<endianness::NATIVE>(input.data(),
525
0
                                                       input.size());
526
0
  } else
527
0
    #endif
528
0
  {
529
0
    return validate_utf16(input.data(), input.size());
530
0
  }
531
0
}
532
  #endif // SIMDUTF_SPAN
533
#endif   // SIMDUTF_FEATURE_UTF16
534
535
#if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
536
/**
537
 * Validate the UTF-16LE string. This function may be best when you expect
538
 * the input to be almost always valid. Otherwise, consider using
539
 * validate_utf16le_with_errors.
540
 *
541
 * Overridden by each implementation.
542
 *
543
 * This function is not BOM-aware.
544
 *
545
 * @param buf the UTF-16LE string to validate.
546
 * @param len the length of the string in number of 2-byte code units
547
 * (char16_t).
548
 * @return true if and only if the string is valid UTF-16LE.
549
 */
550
simdutf_warn_unused bool validate_utf16le(const char16_t *buf,
551
                                          size_t len) noexcept;
552
  #if SIMDUTF_SPAN
553
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused bool
554
0
validate_utf16le(std::span<const char16_t> input) noexcept {
555
0
    #if SIMDUTF_CPLUSPLUS23
556
0
  if consteval {
557
0
    return scalar::utf16::validate<endianness::LITTLE>(input.data(),
558
0
                                                       input.size());
559
0
  } else
560
0
    #endif
561
0
  {
562
0
    return validate_utf16le(input.data(), input.size());
563
0
  }
564
0
}
565
  #endif // SIMDUTF_SPAN
566
#endif   // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
567
568
#if SIMDUTF_FEATURE_UTF16
569
/**
570
 * Validate the UTF-16BE string. This function may be best when you expect
571
 * the input to be almost always valid. Otherwise, consider using
572
 * validate_utf16be_with_errors.
573
 *
574
 * Overridden by each implementation.
575
 *
576
 * This function is not BOM-aware.
577
 *
578
 * @param buf the UTF-16BE string to validate.
579
 * @param len the length of the string in number of 2-byte code units
580
 * (char16_t).
581
 * @return true if and only if the string is valid UTF-16BE.
582
 */
583
simdutf_warn_unused bool validate_utf16be(const char16_t *buf,
584
                                          size_t len) noexcept;
585
  #if SIMDUTF_SPAN
586
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool
587
0
validate_utf16be(std::span<const char16_t> input) noexcept {
588
0
    #if SIMDUTF_CPLUSPLUS23
589
0
  if consteval {
590
0
    return scalar::utf16::validate<endianness::BIG>(input.data(), input.size());
591
0
  } else
592
0
    #endif
593
0
  {
594
0
    return validate_utf16be(input.data(), input.size());
595
0
  }
596
0
}
597
  #endif // SIMDUTF_SPAN
598
599
/**
600
 * Using native endianness; Validate the UTF-16 string and stop on error.
601
 * It might be faster than validate_utf16 when an error is expected to occur
602
 * early.
603
 *
604
 * Overridden by each implementation.
605
 *
606
 * This function is not BOM-aware.
607
 *
608
 * @param buf the UTF-16 string to validate.
609
 * @param len the length of the string in number of 2-byte code units
610
 * (char16_t).
611
 * @return a result pair struct (of type simdutf::result containing the two
612
 * fields error and count) with an error code and either position of the error
613
 * (in the input in code units) if any, or the number of code units validated if
614
 * successful.
615
 */
616
simdutf_warn_unused result validate_utf16_with_errors(const char16_t *buf,
617
                                                      size_t len) noexcept;
618
  #if SIMDUTF_SPAN
619
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
620
0
validate_utf16_with_errors(std::span<const char16_t> input) noexcept {
621
0
    #if SIMDUTF_CPLUSPLUS23
622
0
  if consteval {
623
0
    return scalar::utf16::validate_with_errors<endianness::NATIVE>(
624
0
        input.data(), input.size());
625
0
  } else
626
0
    #endif
627
0
  {
628
0
    return validate_utf16_with_errors(input.data(), input.size());
629
0
  }
630
0
}
631
  #endif // SIMDUTF_SPAN
632
633
/**
634
 * Validate the UTF-16LE string and stop on error. It might be faster than
635
 * validate_utf16le when an error is expected to occur early.
636
 *
637
 * Overridden by each implementation.
638
 *
639
 * This function is not BOM-aware.
640
 *
641
 * @param buf the UTF-16LE string to validate.
642
 * @param len the length of the string in number of 2-byte code units
643
 * (char16_t).
644
 * @return a result pair struct (of type simdutf::result containing the two
645
 * fields error and count) with an error code and either position of the error
646
 * (in the input in code units) if any, or the number of code units validated if
647
 * successful.
648
 */
649
simdutf_warn_unused result validate_utf16le_with_errors(const char16_t *buf,
650
                                                        size_t len) noexcept;
651
  #if SIMDUTF_SPAN
652
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
653
0
validate_utf16le_with_errors(std::span<const char16_t> input) noexcept {
654
0
    #if SIMDUTF_CPLUSPLUS23
655
0
  if consteval {
656
0
    return scalar::utf16::validate_with_errors<endianness::LITTLE>(
657
0
        input.data(), input.size());
658
0
  } else
659
0
    #endif
660
0
  {
661
0
    return validate_utf16le_with_errors(input.data(), input.size());
662
0
  }
663
0
}
664
  #endif // SIMDUTF_SPAN
665
666
/**
667
 * Validate the UTF-16BE string and stop on error. It might be faster than
668
 * validate_utf16be when an error is expected to occur early.
669
 *
670
 * Overridden by each implementation.
671
 *
672
 * This function is not BOM-aware.
673
 *
674
 * @param buf the UTF-16BE string to validate.
675
 * @param len the length of the string in number of 2-byte code units
676
 * (char16_t).
677
 * @return a result pair struct (of type simdutf::result containing the two
678
 * fields error and count) with an error code and either position of the error
679
 * (in the input in code units) if any, or the number of code units validated if
680
 * successful.
681
 */
682
simdutf_warn_unused result validate_utf16be_with_errors(const char16_t *buf,
683
                                                        size_t len) noexcept;
684
  #if SIMDUTF_SPAN
685
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
686
0
validate_utf16be_with_errors(std::span<const char16_t> input) noexcept {
687
0
    #if SIMDUTF_CPLUSPLUS23
688
0
  if consteval {
689
0
    return scalar::utf16::validate_with_errors<endianness::BIG>(input.data(),
690
0
                                                                input.size());
691
0
  } else
692
0
    #endif
693
0
  {
694
0
    return validate_utf16be_with_errors(input.data(), input.size());
695
0
  }
696
0
}
697
  #endif // SIMDUTF_SPAN
698
699
/**
700
 * Fixes an ill-formed UTF-16LE string by replacing mismatched surrogates with
701
 * the Unicode replacement character U+FFFD. If input and output points to
702
 * different memory areas, the procedure copies string, and it's expected that
703
 * output memory is at least as big as the input. It's also possible to set
704
 * input equal output, that makes replacements an in-place operation.
705
 *
706
 * @param input the UTF-16LE string to correct.
707
 * @param len the length of the string in number of 2-byte code units
708
 * (char16_t).
709
 * @param output the output buffer.
710
 */
711
void to_well_formed_utf16le(const char16_t *input, size_t len,
712
                            char16_t *output) noexcept;
713
  #if SIMDUTF_SPAN
714
simdutf_really_inline simdutf_constexpr23 void
715
to_well_formed_utf16le(std::span<const char16_t> input,
716
0
                       std::span<char16_t> output) noexcept {
717
0
    #if SIMDUTF_CPLUSPLUS23
718
0
  if consteval {
719
0
    scalar::utf16::to_well_formed_utf16<endianness::LITTLE>(
720
0
        input.data(), input.size(), output.data());
721
0
  } else
722
0
    #endif
723
0
  {
724
0
    to_well_formed_utf16le(input.data(), input.size(), output.data());
725
0
  }
726
0
}
727
  #endif // SIMDUTF_SPAN
728
729
/**
730
 * Fixes an ill-formed UTF-16BE string by replacing mismatched surrogates with
731
 * the Unicode replacement character U+FFFD. If input and output points to
732
 * different memory areas, the procedure copies string, and it's expected that
733
 * output memory is at least as big as the input. It's also possible to set
734
 * input equal output, that makes replacements an in-place operation.
735
 *
736
 * @param input the UTF-16BE string to correct.
737
 * @param len the length of the string in number of 2-byte code units
738
 * (char16_t).
739
 * @param output the output buffer.
740
 */
741
void to_well_formed_utf16be(const char16_t *input, size_t len,
742
                            char16_t *output) noexcept;
743
  #if SIMDUTF_SPAN
744
simdutf_really_inline simdutf_constexpr23 void
745
to_well_formed_utf16be(std::span<const char16_t> input,
746
0
                       std::span<char16_t> output) noexcept {
747
0
    #if SIMDUTF_CPLUSPLUS23
748
0
  if consteval {
749
0
    scalar::utf16::to_well_formed_utf16<endianness::BIG>(
750
0
        input.data(), input.size(), output.data());
751
0
  } else
752
0
    #endif
753
0
  {
754
0
    to_well_formed_utf16be(input.data(), input.size(), output.data());
755
0
  }
756
0
}
757
  #endif // SIMDUTF_SPAN
758
759
/**
760
 * Fixes an ill-formed UTF-16 string by replacing mismatched surrogates with the
761
 * Unicode replacement character U+FFFD. If input and output points to different
762
 * memory areas, the procedure copies string, and it's expected that output
763
 * memory is at least as big as the input. It's also possible to set input equal
764
 * output, that makes replacements an in-place operation.
765
 *
766
 * @param input the UTF-16 string to correct.
767
 * @param len the length of the string in number of 2-byte code units
768
 * (char16_t).
769
 * @param output the output buffer.
770
 */
771
void to_well_formed_utf16(const char16_t *input, size_t len,
772
                          char16_t *output) noexcept;
773
  #if SIMDUTF_SPAN
774
simdutf_really_inline simdutf_constexpr23 void
775
to_well_formed_utf16(std::span<const char16_t> input,
776
0
                     std::span<char16_t> output) noexcept {
777
0
    #if SIMDUTF_CPLUSPLUS23
778
0
  if consteval {
779
0
    scalar::utf16::to_well_formed_utf16<endianness::NATIVE>(
780
0
        input.data(), input.size(), output.data());
781
0
  } else
782
0
    #endif
783
0
  {
784
0
    to_well_formed_utf16(input.data(), input.size(), output.data());
785
0
  }
786
0
}
787
  #endif // SIMDUTF_SPAN
788
789
#endif // SIMDUTF_FEATURE_UTF16
790
791
#if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
792
/**
793
 * Validate the UTF-32 string. This function may be best when you expect
794
 * the input to be almost always valid. Otherwise, consider using
795
 * validate_utf32_with_errors.
796
 *
797
 * Overridden by each implementation.
798
 *
799
 * This function is not BOM-aware.
800
 *
801
 * @param buf the UTF-32 string to validate.
802
 * @param len the length of the string in number of 4-byte code units
803
 * (char32_t).
804
 * @return true if and only if the string is valid UTF-32.
805
 */
806
simdutf_warn_unused bool validate_utf32(const char32_t *buf,
807
                                        size_t len) noexcept;
808
  #if SIMDUTF_SPAN
809
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool
810
0
validate_utf32(std::span<const char32_t> input) noexcept {
811
0
    #if SIMDUTF_CPLUSPLUS23
812
0
  if consteval {
813
0
    return scalar::utf32::validate(
814
0
        detail::constexpr_cast_ptr<std::uint32_t>(input.data()), input.size());
815
0
  } else
816
0
    #endif
817
0
  {
818
0
    return validate_utf32(input.data(), input.size());
819
0
  }
820
0
}
821
  #endif // SIMDUTF_SPAN
822
#endif   // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
823
824
#if SIMDUTF_FEATURE_UTF32
825
/**
826
 * Validate the UTF-32 string and stop on error. It might be faster than
827
 * validate_utf32 when an error is expected to occur early.
828
 *
829
 * Overridden by each implementation.
830
 *
831
 * This function is not BOM-aware.
832
 *
833
 * @param buf the UTF-32 string to validate.
834
 * @param len the length of the string in number of 4-byte code units
835
 * (char32_t).
836
 * @return a result pair struct (of type simdutf::result containing the two
837
 * fields error and count) with an error code and either position of the error
838
 * (in the input in code units) if any, or the number of code units validated if
839
 * successful.
840
 */
841
simdutf_warn_unused result validate_utf32_with_errors(const char32_t *buf,
842
                                                      size_t len) noexcept;
843
  #if SIMDUTF_SPAN
844
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
845
0
validate_utf32_with_errors(std::span<const char32_t> input) noexcept {
846
0
    #if SIMDUTF_CPLUSPLUS23
847
0
  if consteval {
848
0
    return scalar::utf32::validate_with_errors(
849
0
        detail::constexpr_cast_ptr<std::uint32_t>(input.data()), input.size());
850
0
  } else
851
0
    #endif
852
0
  {
853
0
    return validate_utf32_with_errors(input.data(), input.size());
854
0
  }
855
0
}
856
  #endif // SIMDUTF_SPAN
857
#endif   // SIMDUTF_FEATURE_UTF32
858
859
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
860
/**
861
 * Convert Latin1 string into UTF-8 string.
862
 *
863
 * This function is suitable to work with inputs from untrusted sources.
864
 *
865
 * @param input         the Latin1 string to convert
866
 * @param length        the length of the string in bytes
867
 * @param utf8_output   the pointer to buffer that can hold conversion result
868
 * @return the number of written char; 0 if conversion is not possible
869
 */
870
simdutf_warn_unused size_t convert_latin1_to_utf8(const char *input,
871
                                                  size_t length,
872
                                                  char *utf8_output) noexcept;
873
  #if SIMDUTF_SPAN
874
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
875
convert_latin1_to_utf8(
876
    const detail::input_span_of_byte_like auto &latin1_input,
877
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
878
    #if SIMDUTF_CPLUSPLUS23
879
  if consteval {
880
    return scalar::latin1_to_utf8::convert(
881
        detail::constexpr_cast_ptr<char>(latin1_input.data()),
882
        latin1_input.size(),
883
        detail::constexpr_cast_writeptr<char>(utf8_output.data()));
884
  } else
885
    #endif
886
  {
887
    return convert_latin1_to_utf8(
888
        reinterpret_cast<const char *>(latin1_input.data()),
889
        latin1_input.size(), reinterpret_cast<char *>(utf8_output.data()));
890
  }
891
}
892
  #endif // SIMDUTF_SPAN
893
894
/**
895
 * Convert Latin1 string into UTF-8 string with output limit.
896
 *
897
 * This function is suitable to work with inputs from untrusted sources.
898
 *
899
 * We write as many characters as possible.
900
 *
901
 * Using convert_latin1_to_utf8_safe instead of convert_latin1_to_utf8 comes
902
 * with a significant penalty in some cases, being up to four times slower,
903
 * especially on short inputs. If you have allocated the output buffer so that
904
 * it contains utf8_length_from_latin1(input, length) bytes, then prefer
905
 * convert_latin1_to_utf8.
906
 *
907
 * @param input         the Latin1 string to convert
908
 * @param length        the length of the string in bytes
909
 * @param utf8_output   the pointer to buffer that can hold conversion result
910
 * @param utf8_len      the maximum output length
911
 * @return the number of written char; 0 if conversion is not possible
912
 */
913
simdutf_warn_unused size_t
914
convert_latin1_to_utf8_safe(const char *input, size_t length, char *utf8_output,
915
                            size_t utf8_len) noexcept;
916
  #if SIMDUTF_SPAN
917
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
918
convert_latin1_to_utf8_safe(
919
    const detail::input_span_of_byte_like auto &input,
920
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
921
      // implementation note: outputspan is a forwarding ref to avoid copying
922
      // and allow both lvalues and rvalues. std::span can be copied without
923
      // problems, but std::vector should not, and this function should accept
924
      // both. it will allow using an owning rvalue ref (example: passing a
925
      // temporary std::string) as output, but the user will quickly find out
926
      // that he has no way of getting the data out of the object in that case.
927
    #if SIMDUTF_CPLUSPLUS23
928
  if consteval {
929
    return scalar::latin1_to_utf8::convert_safe_constexpr(
930
        input.data(), input.size(), utf8_output.data(), utf8_output.size());
931
  } else
932
    #endif
933
  {
934
    return convert_latin1_to_utf8_safe(
935
        reinterpret_cast<const char *>(input.data()), input.size(),
936
        reinterpret_cast<char *>(utf8_output.data()), utf8_output.size());
937
  }
938
}
939
  #endif // SIMDUTF_SPAN
940
941
/**
942
 * Convert a Latin1 string into a size-limited UTF-8 buffer and report how much
943
 * input was consumed and output was written.
944
 *
945
 * We write as many complete characters as possible. The returned error is
946
 * SUCCESS if all input was consumed, or OUTPUT_BUFFER_TOO_SMALL otherwise.
947
 *
948
 * @param input         the Latin1 string to convert
949
 * @param length        the length of the string in bytes
950
 * @param utf8_output   the pointer to the output buffer
951
 * @param utf8_len      the maximum output length
952
 * @return a full_result with error, input_count and output_count
953
 */
954
simdutf_warn_unused full_result convert_latin1_to_utf8_safe_with_details(
955
    const char *input, size_t length, char *utf8_output,
956
    size_t utf8_len) noexcept;
957
  #if SIMDUTF_SPAN
958
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result
959
convert_latin1_to_utf8_safe_with_details(
960
    const detail::input_span_of_byte_like auto &input,
961
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
962
    #if SIMDUTF_CPLUSPLUS23
963
  if consteval {
964
    return scalar::latin1_to_utf8::convert_safe_with_details_constexpr(
965
        input.data(), input.size(), utf8_output.data(), utf8_output.size());
966
  } else
967
    #endif
968
  {
969
    return convert_latin1_to_utf8_safe_with_details(
970
        reinterpret_cast<const char *>(input.data()), input.size(),
971
        reinterpret_cast<char *>(utf8_output.data()), utf8_output.size());
972
  }
973
}
974
  #endif // SIMDUTF_SPAN
975
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
976
977
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
978
/**
979
 * Convert possibly Latin1 string into UTF-16LE string.
980
 *
981
 * This function is suitable to work with inputs from untrusted sources.
982
 *
983
 * @param input         the Latin1 string to convert
984
 * @param length        the length of the string in bytes
985
 * @param utf16_output  the pointer to buffer that can hold conversion result
986
 * @return the number of written char16_t; 0 if conversion is not possible
987
 */
988
simdutf_warn_unused size_t convert_latin1_to_utf16le(
989
    const char *input, size_t length, char16_t *utf16_output) noexcept;
990
  #if SIMDUTF_SPAN
991
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
992
convert_latin1_to_utf16le(
993
    const detail::input_span_of_byte_like auto &latin1_input,
994
    std::span<char16_t> utf16_output) noexcept {
995
    #if SIMDUTF_CPLUSPLUS23
996
  if consteval {
997
    return scalar::latin1_to_utf16::convert<endianness::LITTLE>(
998
        latin1_input.data(), latin1_input.size(), utf16_output.data());
999
  } else
1000
    #endif
1001
  {
1002
    return convert_latin1_to_utf16le(
1003
        reinterpret_cast<const char *>(latin1_input.data()),
1004
        latin1_input.size(), utf16_output.data());
1005
  }
1006
}
1007
  #endif // SIMDUTF_SPAN
1008
1009
/**
1010
 * Convert Latin1 string into UTF-16BE string.
1011
 *
1012
 * This function is suitable to work with inputs from untrusted sources.
1013
 *
1014
 * @param input         the Latin1 string to convert
1015
 * @param length        the length of the string in bytes
1016
 * @param utf16_output  the pointer to buffer that can hold conversion result
1017
 * @return the number of written char16_t; 0 if conversion is not possible
1018
 */
1019
simdutf_warn_unused size_t convert_latin1_to_utf16be(
1020
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1021
  #if SIMDUTF_SPAN
1022
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1023
convert_latin1_to_utf16be(const detail::input_span_of_byte_like auto &input,
1024
                          std::span<char16_t> output) noexcept {
1025
    #if SIMDUTF_CPLUSPLUS23
1026
  if consteval {
1027
    return scalar::latin1_to_utf16::convert<endianness::BIG>(
1028
        input.data(), input.size(), output.data());
1029
  } else
1030
    #endif
1031
  {
1032
    return convert_latin1_to_utf16be(
1033
        reinterpret_cast<const char *>(input.data()), input.size(),
1034
        output.data());
1035
  }
1036
}
1037
  #endif // SIMDUTF_SPAN
1038
/**
1039
 * Compute the number of bytes that this UTF-16 string would require in Latin1
1040
 * format.
1041
 *
1042
 * @param length        the length of the string in Latin1 code units (char)
1043
 * @return the length of the string in Latin1 code units (char) required to
1044
 * encode the UTF-16 string as Latin1
1045
 */
1046
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1047
latin1_length_from_utf16(size_t length) noexcept {
1048
  return length;
1049
}
1050
1051
/**
1052
 * Compute the number of code units that this Latin1 string would require in
1053
 * UTF-16 format.
1054
 *
1055
 * @param length        the length of the string in Latin1 code units (char)
1056
 * @return the length of the string in 2-byte code units (char16_t) required to
1057
 * encode the Latin1 string as UTF-16
1058
 */
1059
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1060
0
utf16_length_from_latin1(size_t length) noexcept {
1061
0
  return length;
1062
0
}
1063
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
1064
1065
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
1066
/**
1067
 * Convert Latin1 string into UTF-32 string.
1068
 *
1069
 * This function is suitable to work with inputs from untrusted sources.
1070
 *
1071
 * @param input         the Latin1 string to convert
1072
 * @param length        the length of the string in bytes
1073
 * @param utf32_buffer  the pointer to buffer that can hold conversion result
1074
 * @return the number of written char32_t; 0 if conversion is not possible
1075
 */
1076
simdutf_warn_unused size_t convert_latin1_to_utf32(
1077
    const char *input, size_t length, char32_t *utf32_buffer) noexcept;
1078
  #if SIMDUTF_SPAN
1079
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1080
convert_latin1_to_utf32(
1081
    const detail::input_span_of_byte_like auto &latin1_input,
1082
    std::span<char32_t> utf32_output) noexcept {
1083
    #if SIMDUTF_CPLUSPLUS23
1084
  if consteval {
1085
    return scalar::latin1_to_utf32::convert(
1086
        latin1_input.data(), latin1_input.size(), utf32_output.data());
1087
  } else
1088
    #endif
1089
  {
1090
    return convert_latin1_to_utf32(
1091
        reinterpret_cast<const char *>(latin1_input.data()),
1092
        latin1_input.size(), utf32_output.data());
1093
  }
1094
}
1095
  #endif // SIMDUTF_SPAN
1096
#endif   // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
1097
1098
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1099
/**
1100
 * Convert possibly broken UTF-8 string into latin1 string.
1101
 *
1102
 * During the conversion also validation of the input string is done.
1103
 * This function is suitable to work with inputs from untrusted sources.
1104
 *
1105
 * @param input         the UTF-8 string to convert
1106
 * @param length        the length of the string in bytes
1107
 * @param latin1_output  the pointer to buffer that can hold conversion result
1108
 * @return the number of written char; 0 if the input was not valid UTF-8 string
1109
 * or if it cannot be represented as Latin1
1110
 */
1111
simdutf_warn_unused size_t convert_utf8_to_latin1(const char *input,
1112
                                                  size_t length,
1113
                                                  char *latin1_output) noexcept;
1114
  #if SIMDUTF_SPAN
1115
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1116
convert_utf8_to_latin1(
1117
    const detail::input_span_of_byte_like auto &input,
1118
    detail::output_span_of_byte_like auto &&output) noexcept {
1119
    #if SIMDUTF_CPLUSPLUS23
1120
  if consteval {
1121
    return scalar::utf8_to_latin1::convert(input.data(), input.size(),
1122
                                           output.data());
1123
  } else
1124
    #endif
1125
  {
1126
    return convert_utf8_to_latin1(reinterpret_cast<const char *>(input.data()),
1127
                                  input.size(),
1128
                                  reinterpret_cast<char *>(output.data()));
1129
  }
1130
}
1131
  #endif // SIMDUTF_SPAN
1132
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1133
1134
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1135
/**
1136
 * Using native endianness, convert possibly broken UTF-8 string into a UTF-16
1137
 * string.
1138
 *
1139
 * During the conversion also validation of the input string is done.
1140
 * This function is suitable to work with inputs from untrusted sources.
1141
 *
1142
 * @param input         the UTF-8 string to convert
1143
 * @param length        the length of the string in bytes
1144
 * @param utf16_output  the pointer to buffer that can hold conversion result
1145
 * @return the number of written char16_t; 0 if the input was not valid UTF-8
1146
 * string
1147
 */
1148
simdutf_warn_unused size_t convert_utf8_to_utf16(
1149
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1150
  #if SIMDUTF_SPAN
1151
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1152
convert_utf8_to_utf16(const detail::input_span_of_byte_like auto &input,
1153
                      std::span<char16_t> output) noexcept {
1154
    #if SIMDUTF_CPLUSPLUS23
1155
  if consteval {
1156
    return scalar::utf8_to_utf16::convert<endianness::NATIVE>(
1157
        input.data(), input.size(), output.data());
1158
  } else
1159
    #endif
1160
  {
1161
    return convert_utf8_to_utf16(reinterpret_cast<const char *>(input.data()),
1162
                                 input.size(), output.data());
1163
  }
1164
}
1165
  #endif // SIMDUTF_SPAN
1166
1167
/**
1168
 * Compute the number of bytes that this UTF-16LE string would require in UTF-8
1169
 * format even when the UTF-16LE content contains mismatched surrogates
1170
 * that have to be replaced by the replacement character (0xFFFD).
1171
 *
1172
 * @param input         the UTF-16LE string to convert
1173
 * @param length        the length of the string in 2-byte code units (char16_t)
1174
 * @return a result pair struct (of type simdutf::result containing the two
1175
 * fields error and count) where the count is the number of bytes required to
1176
 * encode the UTF-16LE string as UTF-8, and the error code is either SUCCESS or
1177
 * SURROGATE. The count is correct regardless of the error field.
1178
 * When SURROGATE is returned, it does not indicate an error in the case of this
1179
 * function: it indicates that at least one surrogate has been encountered: the
1180
 * surrogates may be matched or not (thus this function does not validate). If
1181
 * the returned error code is SUCCESS, then the input contains no surrogate, is
1182
 * in the Basic Multilingual Plane, and is necessarily valid.
1183
 */
1184
simdutf_warn_unused result utf8_length_from_utf16le_with_replacement(
1185
    const char16_t *input, size_t length) noexcept;
1186
  #if SIMDUTF_SPAN
1187
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result
1188
utf8_length_from_utf16le_with_replacement(
1189
0
    std::span<const char16_t> valid_utf16_input) noexcept {
1190
0
    #if SIMDUTF_CPLUSPLUS23
1191
0
  if consteval {
1192
0
    return scalar::utf16::utf8_length_from_utf16_with_replacement<
1193
0
        endianness::LITTLE>(valid_utf16_input.data(), valid_utf16_input.size());
1194
0
  } else
1195
0
    #endif
1196
0
  {
1197
0
    return utf8_length_from_utf16le_with_replacement(valid_utf16_input.data(),
1198
0
                                                     valid_utf16_input.size());
1199
0
  }
1200
0
}
1201
  #endif // SIMDUTF_SPAN
1202
1203
/**
1204
 * Compute the number of bytes that this UTF-16BE string would require in UTF-8
1205
 * format even when the UTF-16BE content contains mismatched surrogates
1206
 * that have to be replaced by the replacement character (0xFFFD).
1207
 *
1208
 * @param input         the UTF-16BE string to convert
1209
 * @param length        the length of the string in 2-byte code units (char16_t)
1210
 * @return a result pair struct (of type simdutf::result containing the two
1211
 * fields error and count) where the count is the number of bytes required to
1212
 * encode the UTF-16BE string as UTF-8, and the error code is either SUCCESS or
1213
 * SURROGATE. The count is correct regardless of the error field.
1214
 * When SURROGATE is returned, it does not indicate an error in the case of this
1215
 * function: it indicates that at least one surrogate has been encountered: the
1216
 * surrogates may be matched or not (thus this function does not validate). If
1217
 * the returned error code is SUCCESS, then the input contains no surrogate, is
1218
 * in the Basic Multilingual Plane, and is necessarily valid.
1219
 */
1220
simdutf_warn_unused result utf8_length_from_utf16be_with_replacement(
1221
    const char16_t *input, size_t length) noexcept;
1222
  #if SIMDUTF_SPAN
1223
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
1224
utf8_length_from_utf16be_with_replacement(
1225
0
    std::span<const char16_t> valid_utf16_input) noexcept {
1226
0
    #if SIMDUTF_CPLUSPLUS23
1227
0
  if consteval {
1228
0
    return scalar::utf16::utf8_length_from_utf16_with_replacement<
1229
0
        endianness::BIG>(valid_utf16_input.data(), valid_utf16_input.size());
1230
0
  } else
1231
0
    #endif
1232
0
  {
1233
0
    return utf8_length_from_utf16be_with_replacement(valid_utf16_input.data(),
1234
0
                                                     valid_utf16_input.size());
1235
0
  }
1236
0
}
1237
  #endif // SIMDUTF_SPAN
1238
1239
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1240
1241
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
1242
/**
1243
 * Using native endianness, convert a Latin1 string into a UTF-16 string.
1244
 *
1245
 * @param input         the Latin1 string to convert
1246
 * @param length        the length of the string in bytes
1247
 * @param utf16_output  the pointer to buffer that can hold conversion result
1248
 * @return the number of written char16_t.
1249
 */
1250
simdutf_warn_unused size_t convert_latin1_to_utf16(
1251
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1252
  #if SIMDUTF_SPAN
1253
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1254
convert_latin1_to_utf16(const detail::input_span_of_byte_like auto &input,
1255
                        std::span<char16_t> output) noexcept {
1256
    #if SIMDUTF_CPLUSPLUS23
1257
  if consteval {
1258
    return scalar::latin1_to_utf16::convert<endianness::NATIVE>(
1259
        input.data(), input.size(), output.data());
1260
  } else
1261
    #endif
1262
  {
1263
    return convert_latin1_to_utf16(reinterpret_cast<const char *>(input.data()),
1264
                                   input.size(), output.data());
1265
  }
1266
}
1267
  #endif // SIMDUTF_SPAN
1268
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
1269
1270
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1271
/**
1272
 * Convert possibly broken UTF-8 string into UTF-16LE string.
1273
 *
1274
 * During the conversion also validation of the input string is done.
1275
 * This function is suitable to work with inputs from untrusted sources.
1276
 *
1277
 * @param input         the UTF-8 string to convert
1278
 * @param length        the length of the string in bytes
1279
 * @param utf16_output  the pointer to buffer that can hold conversion result
1280
 * @return the number of written char16_t; 0 if the input was not valid UTF-8
1281
 * string
1282
 */
1283
simdutf_warn_unused size_t convert_utf8_to_utf16le(
1284
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1285
  #if SIMDUTF_SPAN
1286
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1287
convert_utf8_to_utf16le(const detail::input_span_of_byte_like auto &utf8_input,
1288
                        std::span<char16_t> utf16_output) noexcept {
1289
    #if SIMDUTF_CPLUSPLUS23
1290
  if consteval {
1291
    return scalar::utf8_to_utf16::convert<endianness::LITTLE>(
1292
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1293
  } else
1294
    #endif
1295
  {
1296
    return convert_utf8_to_utf16le(
1297
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1298
        utf16_output.data());
1299
  }
1300
}
1301
  #endif // SIMDUTF_SPAN
1302
1303
/**
1304
 * Convert possibly broken UTF-8 string into UTF-16BE string.
1305
 *
1306
 * During the conversion also validation of the input string is done.
1307
 * This function is suitable to work with inputs from untrusted sources.
1308
 *
1309
 * @param input         the UTF-8 string to convert
1310
 * @param length        the length of the string in bytes
1311
 * @param utf16_output  the pointer to buffer that can hold conversion result
1312
 * @return the number of written char16_t; 0 if the input was not valid UTF-8
1313
 * string
1314
 */
1315
simdutf_warn_unused size_t convert_utf8_to_utf16be(
1316
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1317
  #if SIMDUTF_SPAN
1318
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1319
convert_utf8_to_utf16be(const detail::input_span_of_byte_like auto &utf8_input,
1320
                        std::span<char16_t> utf16_output) noexcept {
1321
1322
    #if SIMDUTF_CPLUSPLUS23
1323
  if consteval {
1324
    return scalar::utf8_to_utf16::convert<endianness::BIG>(
1325
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1326
  } else
1327
    #endif
1328
  {
1329
    return convert_utf8_to_utf16be(
1330
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1331
        utf16_output.data());
1332
  }
1333
}
1334
  #endif // SIMDUTF_SPAN
1335
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1336
1337
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1338
/**
1339
 * Convert possibly broken UTF-8 string into latin1 string with errors.
1340
 * If the string cannot be represented as Latin1, an error
1341
 * code is returned.
1342
 *
1343
 * During the conversion also validation of the input string is done.
1344
 * This function is suitable to work with inputs from untrusted sources.
1345
 *
1346
 * @param input         the UTF-8 string to convert
1347
 * @param length        the length of the string in bytes
1348
 * @param latin1_output  the pointer to buffer that can hold conversion result
1349
 * @return a result pair struct (of type simdutf::result containing the two
1350
 * fields error and count) with an error code and either position of the error
1351
 * (in the input in code units) if any, or the number of code units validated if
1352
 * successful.
1353
 */
1354
simdutf_warn_unused result convert_utf8_to_latin1_with_errors(
1355
    const char *input, size_t length, char *latin1_output) noexcept;
1356
  #if SIMDUTF_SPAN
1357
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
1358
convert_utf8_to_latin1_with_errors(
1359
    const detail::input_span_of_byte_like auto &utf8_input,
1360
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
1361
    #if SIMDUTF_CPLUSPLUS23
1362
  if consteval {
1363
    return scalar::utf8_to_latin1::convert_with_errors(
1364
        utf8_input.data(), utf8_input.size(), latin1_output.data());
1365
  } else
1366
    #endif
1367
  {
1368
    return convert_utf8_to_latin1_with_errors(
1369
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1370
        reinterpret_cast<char *>(latin1_output.data()));
1371
  }
1372
}
1373
  #endif // SIMDUTF_SPAN
1374
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1375
1376
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1377
/**
1378
 * Using native endianness, convert possibly broken UTF-8 string into UTF-16
1379
 * string and stop on error.
1380
 *
1381
 * During the conversion also validation of the input string is done.
1382
 * This function is suitable to work with inputs from untrusted sources.
1383
 *
1384
 * @param input         the UTF-8 string to convert
1385
 * @param length        the length of the string in bytes
1386
 * @param utf16_output  the pointer to buffer that can hold conversion result
1387
 * @return a result pair struct (of type simdutf::result containing the two
1388
 * fields error and count) with an error code and either position of the error
1389
 * (in the input in code units) if any, or the number of char16_t written if
1390
 * successful.
1391
 */
1392
simdutf_warn_unused result convert_utf8_to_utf16_with_errors(
1393
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1394
  #if SIMDUTF_SPAN
1395
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
1396
convert_utf8_to_utf16_with_errors(
1397
    const detail::input_span_of_byte_like auto &utf8_input,
1398
    std::span<char16_t> utf16_output) noexcept {
1399
    #if SIMDUTF_CPLUSPLUS23
1400
  if consteval {
1401
    return scalar::utf8_to_utf16::convert_with_errors<endianness::NATIVE>(
1402
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1403
  } else
1404
    #endif
1405
  {
1406
    return convert_utf8_to_utf16_with_errors(
1407
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1408
        utf16_output.data());
1409
  }
1410
}
1411
  #endif // SIMDUTF_SPAN
1412
1413
/**
1414
 * Convert possibly broken UTF-8 string into UTF-16LE string and stop on error.
1415
 *
1416
 * During the conversion also validation of the input string is done.
1417
 * This function is suitable to work with inputs from untrusted sources.
1418
 *
1419
 * @param input         the UTF-8 string to convert
1420
 * @param length        the length of the string in bytes
1421
 * @param utf16_output  the pointer to buffer that can hold conversion result
1422
 * @return a result pair struct (of type simdutf::result containing the two
1423
 * fields error and count) with an error code and either position of the error
1424
 * (in the input in code units) if any, or the number of char16_t written if
1425
 * successful.
1426
 */
1427
simdutf_warn_unused result convert_utf8_to_utf16le_with_errors(
1428
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1429
  #if SIMDUTF_SPAN
1430
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
1431
convert_utf8_to_utf16le_with_errors(
1432
    const detail::input_span_of_byte_like auto &utf8_input,
1433
    std::span<char16_t> utf16_output) noexcept {
1434
    #if SIMDUTF_CPLUSPLUS23
1435
  if consteval {
1436
    return scalar::utf8_to_utf16::convert_with_errors<endianness::LITTLE>(
1437
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1438
  } else
1439
    #endif
1440
  {
1441
    return convert_utf8_to_utf16le_with_errors(
1442
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1443
        utf16_output.data());
1444
  }
1445
}
1446
  #endif // SIMDUTF_SPAN
1447
1448
/**
1449
 * Convert possibly broken UTF-8 string into UTF-16BE string and stop on error.
1450
 *
1451
 * During the conversion also validation of the input string is done.
1452
 * This function is suitable to work with inputs from untrusted sources.
1453
 *
1454
 * @param input         the UTF-8 string to convert
1455
 * @param length        the length of the string in bytes
1456
 * @param utf16_output  the pointer to buffer that can hold conversion result
1457
 * @return a result pair struct (of type simdutf::result containing the two
1458
 * fields error and count) with an error code and either position of the error
1459
 * (in the input in code units) if any, or the number of char16_t written if
1460
 * successful.
1461
 */
1462
simdutf_warn_unused result convert_utf8_to_utf16be_with_errors(
1463
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1464
  #if SIMDUTF_SPAN
1465
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
1466
convert_utf8_to_utf16be_with_errors(
1467
    const detail::input_span_of_byte_like auto &utf8_input,
1468
    std::span<char16_t> utf16_output) noexcept {
1469
    #if SIMDUTF_CPLUSPLUS23
1470
  if consteval {
1471
    return scalar::utf8_to_utf16::convert_with_errors<endianness::BIG>(
1472
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1473
  } else
1474
    #endif
1475
  {
1476
    return convert_utf8_to_utf16be_with_errors(
1477
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1478
        utf16_output.data());
1479
  }
1480
}
1481
  #endif // SIMDUTF_SPAN
1482
1483
/**
1484
 * Convert a possibly ill-formed UTF-8 string into a UTF-16 string (native
1485
 * endianness), replacing each ill-formed subsequence with U+FFFD.
1486
 *
1487
 * Substitution follows Unicode maximal subparts (the WHATWG rule): each
1488
 * maximal subpart of an ill-formed sequence becomes one U+FFFD code unit.
1489
 * The function always succeeds. The output buffer must hold
1490
 * utf16_length_from_utf8_with_replacement(...).count char16_t. A buffer of
1491
 * `length` char16_t is always large enough. Pass that result to the overload
1492
 * that takes it, so the recorded error locations are not discovered again.
1493
 *
1494
 * This function is not BOM-aware.
1495
 *
1496
 * @param input         the UTF-8 string to convert
1497
 * @param length        the length of the string in bytes
1498
 * @param utf16_output  the pointer to buffer that can hold the conversion
1499
 * result
1500
 * @return the number of written char16_t
1501
 */
1502
simdutf_warn_unused size_t convert_utf8_to_utf16_with_replacement(
1503
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1504
  #if SIMDUTF_SPAN
1505
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1506
convert_utf8_to_utf16_with_replacement(
1507
    const detail::input_span_of_byte_like auto &utf8_input,
1508
    std::span<char16_t> utf16_output) noexcept {
1509
    #if SIMDUTF_CPLUSPLUS23
1510
  if consteval {
1511
    return scalar::utf8_to_utf16::convert_with_replacement<endianness::NATIVE>(
1512
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1513
  } else
1514
    #endif
1515
  {
1516
    return convert_utf8_to_utf16_with_replacement(
1517
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1518
        utf16_output.data());
1519
  }
1520
}
1521
  #endif // SIMDUTF_SPAN
1522
1523
/**
1524
 * Convert a possibly ill-formed UTF-8 string into a UTF-16 string (native
1525
 * endianness), replacing each ill-formed subsequence with U+FFFD, using error
1526
 * locations already computed for this same input.
1527
 *
1528
 * locations must be the value returned by
1529
 * utf16_length_from_utf8_with_replacement for these bytes. When
1530
 * locations.more_errors is false, every ill-formed subsequence is in
1531
 * locations.error_offset and the gaps are valid UTF-8. When it is true, the
1532
 * input has further ill-formed subsequences, and the tail past the stored
1533
 * locations is scanned during conversion. The function always succeeds.
1534
 *
1535
 * @param input         the UTF-8 string to convert
1536
 * @param length        the length of the string in bytes
1537
 * @param utf16_output  the pointer to buffer that can hold the conversion
1538
 * result
1539
 * @param locations     result of utf16_length_from_utf8_with_replacement
1540
 * @return the number of written char16_t, equal to locations.count when
1541
 * locations describes this input
1542
 */
1543
simdutf_warn_unused size_t convert_utf8_to_utf16_with_replacement(
1544
    const char *input, size_t length, char16_t *utf16_output,
1545
    const utf8_to_utf16_result &locations) noexcept;
1546
  #if SIMDUTF_SPAN
1547
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1548
convert_utf8_to_utf16_with_replacement(
1549
    const detail::input_span_of_byte_like auto &utf8_input,
1550
    std::span<char16_t> utf16_output,
1551
    const utf8_to_utf16_result &locations) noexcept {
1552
    #if SIMDUTF_CPLUSPLUS23
1553
  if consteval {
1554
    (void)locations;
1555
    return scalar::utf8_to_utf16::convert_with_replacement<endianness::NATIVE>(
1556
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1557
  } else
1558
    #endif
1559
  {
1560
    return convert_utf8_to_utf16_with_replacement(
1561
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1562
        utf16_output.data(), locations);
1563
  }
1564
}
1565
  #endif // SIMDUTF_SPAN
1566
1567
/**
1568
 * Convert a possibly ill-formed UTF-8 string into a UTF-16LE string, replacing
1569
 * each ill-formed subsequence with U+FFFD.
1570
 *
1571
 * Substitution follows Unicode maximal subparts (the WHATWG rule): each
1572
 * maximal subpart of an ill-formed sequence becomes one U+FFFD code unit.
1573
 * The function always succeeds. The output buffer must hold
1574
 * utf16_length_from_utf8_with_replacement(...).count char16_t. A buffer of
1575
 * `length` char16_t is always large enough. Pass that result to the overload
1576
 * that takes it, so the recorded error locations are not discovered again.
1577
 *
1578
 * This function is not BOM-aware.
1579
 *
1580
 * @param input         the UTF-8 string to convert
1581
 * @param length        the length of the string in bytes
1582
 * @param utf16_output  the pointer to buffer that can hold the conversion
1583
 * result
1584
 * @return the number of written char16_t
1585
 */
1586
simdutf_warn_unused size_t convert_utf8_to_utf16le_with_replacement(
1587
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1588
  #if SIMDUTF_SPAN
1589
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1590
convert_utf8_to_utf16le_with_replacement(
1591
    const detail::input_span_of_byte_like auto &utf8_input,
1592
    std::span<char16_t> utf16_output) noexcept {
1593
    #if SIMDUTF_CPLUSPLUS23
1594
  if consteval {
1595
    return scalar::utf8_to_utf16::convert_with_replacement<endianness::LITTLE>(
1596
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1597
  } else
1598
    #endif
1599
  {
1600
    return convert_utf8_to_utf16le_with_replacement(
1601
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1602
        utf16_output.data());
1603
  }
1604
}
1605
  #endif // SIMDUTF_SPAN
1606
1607
/**
1608
 * Convert a possibly ill-formed UTF-8 string into a UTF-16LE string, using
1609
 * error locations already computed for this same input. See
1610
 * convert_utf8_to_utf16_with_replacement.
1611
 *
1612
 * @param input         the UTF-8 string to convert
1613
 * @param length        the length of the string in bytes
1614
 * @param utf16_output  the pointer to buffer that can hold the conversion
1615
 * result
1616
 * @param locations     result of utf16_length_from_utf8_with_replacement
1617
 * @return the number of written char16_t
1618
 */
1619
simdutf_warn_unused size_t convert_utf8_to_utf16le_with_replacement(
1620
    const char *input, size_t length, char16_t *utf16_output,
1621
    const utf8_to_utf16_result &locations) noexcept;
1622
  #if SIMDUTF_SPAN
1623
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1624
convert_utf8_to_utf16le_with_replacement(
1625
    const detail::input_span_of_byte_like auto &utf8_input,
1626
    std::span<char16_t> utf16_output,
1627
    const utf8_to_utf16_result &locations) noexcept {
1628
    #if SIMDUTF_CPLUSPLUS23
1629
  if consteval {
1630
    (void)locations;
1631
    return scalar::utf8_to_utf16::convert_with_replacement<endianness::LITTLE>(
1632
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1633
  } else
1634
    #endif
1635
  {
1636
    return convert_utf8_to_utf16le_with_replacement(
1637
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1638
        utf16_output.data(), locations);
1639
  }
1640
}
1641
  #endif // SIMDUTF_SPAN
1642
1643
/**
1644
 * Convert a possibly ill-formed UTF-8 string into a UTF-16BE string, replacing
1645
 * each ill-formed subsequence with U+FFFD.
1646
 *
1647
 * Substitution follows Unicode maximal subparts (the WHATWG rule): each
1648
 * maximal subpart of an ill-formed sequence becomes one U+FFFD code unit.
1649
 * The function always succeeds. The output buffer must hold
1650
 * utf16_length_from_utf8_with_replacement(...).count char16_t. A buffer of
1651
 * `length` char16_t is always large enough. Pass that result to the overload
1652
 * that takes it, so the recorded error locations are not discovered again.
1653
 *
1654
 * This function is not BOM-aware.
1655
 *
1656
 * @param input         the UTF-8 string to convert
1657
 * @param length        the length of the string in bytes
1658
 * @param utf16_output  the pointer to buffer that can hold the conversion
1659
 * result
1660
 * @return the number of written char16_t
1661
 */
1662
simdutf_warn_unused size_t convert_utf8_to_utf16be_with_replacement(
1663
    const char *input, size_t length, char16_t *utf16_output) noexcept;
1664
  #if SIMDUTF_SPAN
1665
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1666
convert_utf8_to_utf16be_with_replacement(
1667
    const detail::input_span_of_byte_like auto &utf8_input,
1668
    std::span<char16_t> utf16_output) noexcept {
1669
    #if SIMDUTF_CPLUSPLUS23
1670
  if consteval {
1671
    return scalar::utf8_to_utf16::convert_with_replacement<endianness::BIG>(
1672
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1673
  } else
1674
    #endif
1675
  {
1676
    return convert_utf8_to_utf16be_with_replacement(
1677
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1678
        utf16_output.data());
1679
  }
1680
}
1681
  #endif // SIMDUTF_SPAN
1682
1683
/**
1684
 * Convert a possibly ill-formed UTF-8 string into a UTF-16BE string, using
1685
 * error locations already computed for this same input. See
1686
 * convert_utf8_to_utf16_with_replacement.
1687
 *
1688
 * @param input         the UTF-8 string to convert
1689
 * @param length        the length of the string in bytes
1690
 * @param utf16_output  the pointer to buffer that can hold the conversion
1691
 * result
1692
 * @param locations     result of utf16_length_from_utf8_with_replacement
1693
 * @return the number of written char16_t
1694
 */
1695
simdutf_warn_unused size_t convert_utf8_to_utf16be_with_replacement(
1696
    const char *input, size_t length, char16_t *utf16_output,
1697
    const utf8_to_utf16_result &locations) noexcept;
1698
  #if SIMDUTF_SPAN
1699
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1700
convert_utf8_to_utf16be_with_replacement(
1701
    const detail::input_span_of_byte_like auto &utf8_input,
1702
    std::span<char16_t> utf16_output,
1703
    const utf8_to_utf16_result &locations) noexcept {
1704
    #if SIMDUTF_CPLUSPLUS23
1705
  if consteval {
1706
    (void)locations;
1707
    return scalar::utf8_to_utf16::convert_with_replacement<endianness::BIG>(
1708
        utf8_input.data(), utf8_input.size(), utf16_output.data());
1709
  } else
1710
    #endif
1711
  {
1712
    return convert_utf8_to_utf16be_with_replacement(
1713
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1714
        utf16_output.data(), locations);
1715
  }
1716
}
1717
  #endif // SIMDUTF_SPAN
1718
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1719
1720
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1721
/**
1722
 * Convert possibly broken UTF-8 string into UTF-32 string.
1723
 *
1724
 * During the conversion also validation of the input string is done.
1725
 * This function is suitable to work with inputs from untrusted sources.
1726
 *
1727
 * @param input         the UTF-8 string to convert
1728
 * @param length        the length of the string in bytes
1729
 * @param utf32_output  the pointer to buffer that can hold conversion result
1730
 * @return the number of written char32_t; 0 if the input was not valid UTF-8
1731
 * string
1732
 */
1733
simdutf_warn_unused size_t convert_utf8_to_utf32(
1734
    const char *input, size_t length, char32_t *utf32_output) noexcept;
1735
  #if SIMDUTF_SPAN
1736
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1737
convert_utf8_to_utf32(const detail::input_span_of_byte_like auto &utf8_input,
1738
                      std::span<char32_t> utf32_output) noexcept {
1739
    #if SIMDUTF_CPLUSPLUS23
1740
  if consteval {
1741
    return scalar::utf8_to_utf32::convert(utf8_input.data(), utf8_input.size(),
1742
                                          utf32_output.data());
1743
  } else
1744
    #endif
1745
  {
1746
    return convert_utf8_to_utf32(
1747
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1748
        utf32_output.data());
1749
  }
1750
}
1751
  #endif // SIMDUTF_SPAN
1752
1753
/**
1754
 * Convert possibly broken UTF-8 string into UTF-32 string and stop on error.
1755
 *
1756
 * During the conversion also validation of the input string is done.
1757
 * This function is suitable to work with inputs from untrusted sources.
1758
 *
1759
 * @param input         the UTF-8 string to convert
1760
 * @param length        the length of the string in bytes
1761
 * @param utf32_output  the pointer to buffer that can hold conversion result
1762
 * @return a result pair struct (of type simdutf::result containing the two
1763
 * fields error and count) with an error code and either position of the error
1764
 * (in the input in code units) if any, or the number of char32_t written if
1765
 * successful.
1766
 */
1767
simdutf_warn_unused result convert_utf8_to_utf32_with_errors(
1768
    const char *input, size_t length, char32_t *utf32_output) noexcept;
1769
  #if SIMDUTF_SPAN
1770
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
1771
convert_utf8_to_utf32_with_errors(
1772
    const detail::input_span_of_byte_like auto &utf8_input,
1773
    std::span<char32_t> utf32_output) noexcept {
1774
    #if SIMDUTF_CPLUSPLUS23
1775
  if consteval {
1776
    return scalar::utf8_to_utf32::convert_with_errors(
1777
        utf8_input.data(), utf8_input.size(), utf32_output.data());
1778
  } else
1779
    #endif
1780
  {
1781
    return convert_utf8_to_utf32_with_errors(
1782
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size(),
1783
        utf32_output.data());
1784
  }
1785
}
1786
  #endif // SIMDUTF_SPAN
1787
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1788
1789
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1790
/**
1791
 * Convert valid UTF-8 string into latin1 string.
1792
 *
1793
 * This function assumes that the input string is valid UTF-8 and that it can be
1794
 * represented as Latin1. If you violate this assumption, the result is
1795
 * implementation defined and may include system-dependent behavior such as
1796
 * crashes.
1797
 *
1798
 * This function is for expert users only and not part of our public API. Use
1799
 * convert_utf8_to_latin1 instead. The function may be removed from the library
1800
 * in the future.
1801
 *
1802
 * This function is not BOM-aware.
1803
 *
1804
 * @param input         the UTF-8 string to convert
1805
 * @param length        the length of the string in bytes
1806
 * @param latin1_output  the pointer to buffer that can hold conversion result
1807
 * @return the number of written char; 0 if the input was not valid UTF-8 string
1808
 */
1809
simdutf_warn_unused size_t convert_valid_utf8_to_latin1(
1810
    const char *input, size_t length, char *latin1_output) noexcept;
1811
  #if SIMDUTF_SPAN
1812
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1813
convert_valid_utf8_to_latin1(
1814
    const detail::input_span_of_byte_like auto &valid_utf8_input,
1815
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
1816
    #if SIMDUTF_CPLUSPLUS23
1817
  if consteval {
1818
    return scalar::utf8_to_latin1::convert_valid(
1819
        valid_utf8_input.data(), valid_utf8_input.size(), latin1_output.data());
1820
  } else
1821
    #endif
1822
  {
1823
    return convert_valid_utf8_to_latin1(
1824
        reinterpret_cast<const char *>(valid_utf8_input.data()),
1825
        valid_utf8_input.size(), latin1_output.data());
1826
  }
1827
}
1828
  #endif // SIMDUTF_SPAN
1829
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1830
1831
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1832
/**
1833
 * Using native endianness, convert valid UTF-8 string into a UTF-16 string.
1834
 *
1835
 * This function assumes that the input string is valid UTF-8.
1836
 *
1837
 * @param input         the UTF-8 string to convert
1838
 * @param length        the length of the string in bytes
1839
 * @param utf16_buffer  the pointer to buffer that can hold conversion result
1840
 * @return the number of written char16_t
1841
 */
1842
simdutf_warn_unused size_t convert_valid_utf8_to_utf16(
1843
    const char *input, size_t length, char16_t *utf16_buffer) noexcept;
1844
  #if SIMDUTF_SPAN
1845
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1846
convert_valid_utf8_to_utf16(
1847
    const detail::input_span_of_byte_like auto &valid_utf8_input,
1848
    std::span<char16_t> utf16_output) noexcept {
1849
    #if SIMDUTF_CPLUSPLUS23
1850
  if consteval {
1851
    return scalar::utf8_to_utf16::convert_valid<endianness::NATIVE>(
1852
        valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data());
1853
  } else
1854
    #endif
1855
  {
1856
    return convert_valid_utf8_to_utf16(
1857
        reinterpret_cast<const char *>(valid_utf8_input.data()),
1858
        valid_utf8_input.size(), utf16_output.data());
1859
  }
1860
}
1861
  #endif // SIMDUTF_SPAN
1862
1863
/**
1864
 * Convert valid UTF-8 string into UTF-16LE string.
1865
 *
1866
 * This function assumes that the input string is valid UTF-8.
1867
 *
1868
 * @param input         the UTF-8 string to convert
1869
 * @param length        the length of the string in bytes
1870
 * @param utf16_buffer  the pointer to buffer that can hold conversion result
1871
 * @return the number of written char16_t
1872
 */
1873
simdutf_warn_unused size_t convert_valid_utf8_to_utf16le(
1874
    const char *input, size_t length, char16_t *utf16_buffer) noexcept;
1875
  #if SIMDUTF_SPAN
1876
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1877
convert_valid_utf8_to_utf16le(
1878
    const detail::input_span_of_byte_like auto &valid_utf8_input,
1879
    std::span<char16_t> utf16_output) noexcept {
1880
1881
    #if SIMDUTF_CPLUSPLUS23
1882
  if consteval {
1883
    return scalar::utf8_to_utf16::convert_valid<endianness::LITTLE>(
1884
        valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data());
1885
  } else
1886
    #endif
1887
  {
1888
    return convert_valid_utf8_to_utf16le(
1889
        reinterpret_cast<const char *>(valid_utf8_input.data()),
1890
        valid_utf8_input.size(), utf16_output.data());
1891
  }
1892
}
1893
  #endif // SIMDUTF_SPAN
1894
1895
/**
1896
 * Convert valid UTF-8 string into UTF-16BE string.
1897
 *
1898
 * This function assumes that the input string is valid UTF-8.
1899
 *
1900
 * @param input         the UTF-8 string to convert
1901
 * @param length        the length of the string in bytes
1902
 * @param utf16_buffer  the pointer to buffer that can hold conversion result
1903
 * @return the number of written char16_t
1904
 */
1905
simdutf_warn_unused size_t convert_valid_utf8_to_utf16be(
1906
    const char *input, size_t length, char16_t *utf16_buffer) noexcept;
1907
  #if SIMDUTF_SPAN
1908
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1909
convert_valid_utf8_to_utf16be(
1910
    const detail::input_span_of_byte_like auto &valid_utf8_input,
1911
    std::span<char16_t> utf16_output) noexcept {
1912
    #if SIMDUTF_CPLUSPLUS23
1913
  if consteval {
1914
    return scalar::utf8_to_utf16::convert_valid<endianness::BIG>(
1915
        valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data());
1916
  } else
1917
    #endif
1918
  {
1919
    return convert_valid_utf8_to_utf16be(
1920
        reinterpret_cast<const char *>(valid_utf8_input.data()),
1921
        valid_utf8_input.size(), utf16_output.data());
1922
  }
1923
}
1924
  #endif // SIMDUTF_SPAN
1925
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
1926
1927
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1928
/**
1929
 * Convert valid UTF-8 string into UTF-32 string.
1930
 *
1931
 * This function assumes that the input string is valid UTF-8.
1932
 *
1933
 * @param input         the UTF-8 string to convert
1934
 * @param length        the length of the string in bytes
1935
 * @param utf32_buffer  the pointer to buffer that can hold conversion result
1936
 * @return the number of written char32_t
1937
 */
1938
simdutf_warn_unused size_t convert_valid_utf8_to_utf32(
1939
    const char *input, size_t length, char32_t *utf32_buffer) noexcept;
1940
  #if SIMDUTF_SPAN
1941
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1942
convert_valid_utf8_to_utf32(
1943
    const detail::input_span_of_byte_like auto &valid_utf8_input,
1944
    std::span<char32_t> utf32_output) noexcept {
1945
    #if SIMDUTF_CPLUSPLUS23
1946
  if consteval {
1947
    return scalar::utf8_to_utf32::convert_valid(
1948
        valid_utf8_input.data(), valid_utf8_input.size(), utf32_output.data());
1949
  } else
1950
    #endif
1951
  {
1952
    return convert_valid_utf8_to_utf32(
1953
        reinterpret_cast<const char *>(valid_utf8_input.data()),
1954
        valid_utf8_input.size(), utf32_output.data());
1955
  }
1956
}
1957
  #endif // SIMDUTF_SPAN
1958
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
1959
1960
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
1961
/**
1962
 * Return the number of bytes that this Latin1 string would require in UTF-8
1963
 * format.
1964
 *
1965
 * @param input         the Latin1 string to convert
1966
 * @param length        the length of the string bytes
1967
 * @return the number of bytes required to encode the Latin1 string as UTF-8
1968
 */
1969
simdutf_warn_unused size_t utf8_length_from_latin1(const char *input,
1970
                                                   size_t length) noexcept;
1971
  #if SIMDUTF_SPAN
1972
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
1973
utf8_length_from_latin1(
1974
    const detail::input_span_of_byte_like auto &latin1_input) noexcept {
1975
    #if SIMDUTF_CPLUSPLUS23
1976
  if consteval {
1977
    return scalar::latin1_to_utf8::utf8_length_from_latin1(latin1_input.data(),
1978
                                                           latin1_input.size());
1979
  } else
1980
    #endif
1981
  {
1982
    return utf8_length_from_latin1(
1983
        reinterpret_cast<const char *>(latin1_input.data()),
1984
        latin1_input.size());
1985
  }
1986
}
1987
  #endif // SIMDUTF_SPAN
1988
1989
/**
1990
 * Compute the number of bytes that this UTF-8 string would require in Latin1
1991
 * format.
1992
 *
1993
 * This function does not validate the input. It is acceptable to pass invalid
1994
 * UTF-8 strings but in such cases the result is implementation defined.
1995
 *
1996
 * This function is not BOM-aware.
1997
 *
1998
 * @param input         the UTF-8 string to convert
1999
 * @param length        the length of the string in byte
2000
 * @return the number of bytes required to encode the UTF-8 string as Latin1
2001
 */
2002
simdutf_warn_unused size_t latin1_length_from_utf8(const char *input,
2003
                                                   size_t length) noexcept;
2004
  #if SIMDUTF_SPAN
2005
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2006
latin1_length_from_utf8(
2007
    const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept {
2008
    #if SIMDUTF_CPLUSPLUS23
2009
  if consteval {
2010
    return scalar::utf8::count_code_points(valid_utf8_input.data(),
2011
                                           valid_utf8_input.size());
2012
  } else
2013
    #endif
2014
  {
2015
    return latin1_length_from_utf8(
2016
        reinterpret_cast<const char *>(valid_utf8_input.data()),
2017
        valid_utf8_input.size());
2018
  }
2019
}
2020
  #endif // SIMDUTF_SPAN
2021
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
2022
2023
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2024
/**
2025
 * Compute the number of 2-byte code units that this UTF-8 string would require
2026
 * in UTF-16LE format.
2027
 *
2028
 * This function does not validate the input. It is acceptable to pass invalid
2029
 * UTF-8 strings but in such cases the result is implementation defined.
2030
 *
2031
 * This function is not BOM-aware.
2032
 *
2033
 * @param input         the UTF-8 string to process
2034
 * @param length        the length of the string in bytes
2035
 * @return the number of char16_t code units required to encode the UTF-8 string
2036
 * as UTF-16LE
2037
 */
2038
simdutf_warn_unused size_t utf16_length_from_utf8(const char *input,
2039
                                                  size_t length) noexcept;
2040
  #if SIMDUTF_SPAN
2041
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2042
utf16_length_from_utf8(
2043
    const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept {
2044
    #if SIMDUTF_CPLUSPLUS23
2045
  if consteval {
2046
    return scalar::utf8::utf16_length_from_utf8(valid_utf8_input.data(),
2047
                                                valid_utf8_input.size());
2048
  } else
2049
    #endif
2050
  {
2051
    return utf16_length_from_utf8(
2052
        reinterpret_cast<const char *>(valid_utf8_input.data()),
2053
        valid_utf8_input.size());
2054
  }
2055
}
2056
  #endif // SIMDUTF_SPAN
2057
2058
/**
2059
 * Compute the number of char16_t that this UTF-8 string requires in UTF-16
2060
 * when ill-formed subsequences are replaced by U+FFFD, and record where those
2061
 * subsequences are.
2062
 *
2063
 * Substitution follows Unicode maximal subparts (the WHATWG rule): each
2064
 * maximal subpart becomes one U+FFFD. count is always the number of char16_t
2065
 * that convert_utf8_to_utf16_with_replacement writes, and it is at most
2066
 * `length`. The count does not depend on endianness.
2067
 *
2068
 * error is SUCCESS when the input is valid UTF-8. Otherwise it is the error
2069
 * code of the first ill-formed sequence (HEADER_BITS, TOO_SHORT, TOO_LONG,
2070
 * OVERLONG, TOO_LARGE, or SURROGATE). count stays correct either way.
2071
 *
2072
 * error_offset holds the first error_count byte indexes, at most
2073
 * utf8_to_utf16_result::max_errors (16), counting from the start of input.
2074
 * more_errors is true when the input has further ill-formed subsequences.
2075
 * Pass the whole result to convert_utf8_to_utf16_with_replacement on these
2076
 * same bytes. A complete list (more_errors false) lets that conversion skip a
2077
 * second scan.
2078
 *
2079
 * When the input is known to be valid, utf16_length_from_utf8 is the faster
2080
 * length function: it only counts, whereas this one validates.
2081
 *
2082
 * This function is not BOM-aware.
2083
 *
2084
 * @param input         the UTF-8 string to process
2085
 * @param length        the length of the string in bytes
2086
 * @return a utf8_to_utf16_result
2087
 */
2088
simdutf_warn_unused utf8_to_utf16_result
2089
utf16_length_from_utf8_with_replacement(const char *input,
2090
                                        size_t length) noexcept;
2091
  #if SIMDUTF_SPAN
2092
simdutf_really_inline
2093
    simdutf_warn_unused simdutf_constexpr23 utf8_to_utf16_result
2094
    utf16_length_from_utf8_with_replacement(
2095
        const detail::input_span_of_byte_like auto &utf8_input) noexcept {
2096
    #if SIMDUTF_CPLUSPLUS23
2097
  if consteval {
2098
    return scalar::utf8_to_utf16::utf16_length_from_utf8_with_replacement(
2099
        utf8_input.data(), utf8_input.size());
2100
  } else
2101
    #endif
2102
  {
2103
    return utf16_length_from_utf8_with_replacement(
2104
        reinterpret_cast<const char *>(utf8_input.data()), utf8_input.size());
2105
  }
2106
}
2107
  #endif // SIMDUTF_SPAN
2108
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2109
2110
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
2111
/**
2112
 * Compute the number of 4-byte code units that this UTF-8 string would require
2113
 * in UTF-32 format.
2114
 *
2115
 * This function is equivalent to count_utf8
2116
 *
2117
 * This function does not validate the input. It is acceptable to pass invalid
2118
 * UTF-8 strings but in such cases the result is implementation defined.
2119
 *
2120
 * This function is not BOM-aware.
2121
 *
2122
 * @param input         the UTF-8 string to process
2123
 * @param length        the length of the string in bytes
2124
 * @return the number of char32_t code units required to encode the UTF-8 string
2125
 * as UTF-32
2126
 */
2127
simdutf_warn_unused size_t utf32_length_from_utf8(const char *input,
2128
                                                  size_t length) noexcept;
2129
  #if SIMDUTF_SPAN
2130
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2131
utf32_length_from_utf8(
2132
    const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept {
2133
2134
    #if SIMDUTF_CPLUSPLUS23
2135
  if consteval {
2136
    return scalar::utf8::count_code_points(valid_utf8_input.data(),
2137
                                           valid_utf8_input.size());
2138
  } else
2139
    #endif
2140
  {
2141
    return utf32_length_from_utf8(
2142
        reinterpret_cast<const char *>(valid_utf8_input.data()),
2143
        valid_utf8_input.size());
2144
  }
2145
}
2146
  #endif // SIMDUTF_SPAN
2147
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
2148
2149
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2150
/**
2151
 * Using native endianness, convert possibly broken UTF-16 string into UTF-8
2152
 * string.
2153
 *
2154
 * During the conversion also validation of the input string is done.
2155
 * This function is suitable to work with inputs from untrusted sources.
2156
 *
2157
 * This function is not BOM-aware.
2158
 *
2159
 * @param input         the UTF-16 string to convert
2160
 * @param length        the length of the string in 2-byte code units (char16_t)
2161
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2162
 * @return number of written code units; 0 if input is not a valid UTF-16LE
2163
 * string
2164
 */
2165
simdutf_warn_unused size_t convert_utf16_to_utf8(const char16_t *input,
2166
                                                 size_t length,
2167
                                                 char *utf8_buffer) noexcept;
2168
  #if SIMDUTF_SPAN
2169
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2170
convert_utf16_to_utf8(
2171
    std::span<const char16_t> utf16_input,
2172
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2173
    #if SIMDUTF_CPLUSPLUS23
2174
  if consteval {
2175
    return scalar::utf16_to_utf8::convert<endianness::NATIVE>(
2176
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2177
  } else
2178
    #endif
2179
  {
2180
    return convert_utf16_to_utf8(utf16_input.data(), utf16_input.size(),
2181
                                 reinterpret_cast<char *>(utf8_output.data()));
2182
  }
2183
}
2184
  #endif // SIMDUTF_SPAN
2185
2186
/**
2187
 * Using native endianness, convert possibly broken UTF-16 string into UTF-8
2188
 * string with output limit.
2189
 *
2190
 * We write as many characters as possible into the output buffer,
2191
 *
2192
 * During the conversion also validation of the input string is done.
2193
 * This function is suitable to work with inputs from untrusted sources.
2194
 *
2195
 * This function is not BOM-aware.
2196
 *
2197
 * Using convert_utf16_to_utf8_safe instead of convert_utf16_to_utf8 comes with
2198
 * a significant penalty in some cases, being up to three times slower,
2199
 * especially on short inputs. If you have allocated the output buffer so that
2200
 * it contains utf8_length_from_utf16(input, length) bytes, then prefer
2201
 * convert_utf16_to_utf8.
2202
 *
2203
 * @param input         the UTF-16 string to convert
2204
 * @param length        the length of the string in 16-bit code units (char16_t)
2205
 * @param utf8_output   the pointer to buffer that can hold conversion result
2206
 * @param utf8_len      the maximum output length
2207
 * @return the number of written char; 0 if conversion is not possible
2208
 */
2209
simdutf_warn_unused size_t convert_utf16_to_utf8_safe(const char16_t *input,
2210
                                                      size_t length,
2211
                                                      char *utf8_output,
2212
                                                      size_t utf8_len) noexcept;
2213
  #if SIMDUTF_SPAN
2214
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2215
convert_utf16_to_utf8_safe(
2216
    std::span<const char16_t> utf16_input,
2217
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2218
      // implementation note: outputspan is a forwarding ref to avoid copying
2219
      // and allow both lvalues and rvalues. std::span can be copied without
2220
      // problems, but std::vector should not, and this function should accept
2221
      // both. it will allow using an owning rvalue ref (example: passing a
2222
      // temporary std::string) as output, but the user will quickly find out
2223
      // that he has no way of getting the data out of the object in that case.
2224
    #if SIMDUTF_CPLUSPLUS23
2225
  if consteval {
2226
    const full_result r =
2227
        scalar::utf16_to_utf8::convert_with_errors<endianness::NATIVE, true>(
2228
            utf16_input.data(), utf16_input.size(), utf8_output.data(),
2229
            utf8_output.size());
2230
    if (r.error != error_code::SUCCESS &&
2231
        r.error != error_code::OUTPUT_BUFFER_TOO_SMALL) {
2232
      return 0;
2233
    }
2234
    return r.output_count;
2235
  } else
2236
    #endif
2237
  {
2238
    return convert_utf16_to_utf8_safe(
2239
        utf16_input.data(), utf16_input.size(),
2240
        reinterpret_cast<char *>(utf8_output.data()), utf8_output.size());
2241
  }
2242
}
2243
  #endif // SIMDUTF_SPAN
2244
2245
/**
2246
 * Convert a possibly broken UTF-16 string into a size-limited UTF-8 buffer and
2247
 * report how much input was consumed and output was written.
2248
 *
2249
 * We write as many complete characters as possible while validating the input.
2250
 * The returned error is SUCCESS if all input was consumed,
2251
 * OUTPUT_BUFFER_TOO_SMALL if the next character does not fit, or SURROGATE if
2252
 * an unpaired surrogate was found.
2253
 *
2254
 * @param input         the UTF-16 string to convert
2255
 * @param length        the length in 16-bit code units
2256
 * @param utf8_output   the pointer to the output buffer
2257
 * @param utf8_len      the maximum output length
2258
 * @return a full_result with error, input_count and output_count
2259
 */
2260
simdutf_warn_unused full_result convert_utf16_to_utf8_safe_with_details(
2261
    const char16_t *input, size_t length, char *utf8_output,
2262
    size_t utf8_len) noexcept;
2263
  #if SIMDUTF_SPAN
2264
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result
2265
convert_utf16_to_utf8_safe_with_details(
2266
    std::span<const char16_t> utf16_input,
2267
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2268
    #if SIMDUTF_CPLUSPLUS23
2269
  if consteval {
2270
    if (utf16_input.empty()) {
2271
      return full_result(error_code::SUCCESS, 0, 0);
2272
    }
2273
    return scalar::utf16_to_utf8::convert_with_errors<endianness::NATIVE, true>(
2274
        utf16_input.data(), utf16_input.size(), utf8_output.data(),
2275
        utf8_output.size());
2276
  } else
2277
    #endif
2278
  {
2279
    return convert_utf16_to_utf8_safe_with_details(
2280
        utf16_input.data(), utf16_input.size(),
2281
        reinterpret_cast<char *>(utf8_output.data()), utf8_output.size());
2282
  }
2283
}
2284
  #endif // SIMDUTF_SPAN
2285
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2286
2287
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
2288
/**
2289
 * Using native endianness, convert possibly broken UTF-16 string into Latin1
2290
 * string.
2291
 *
2292
 * During the conversion also validation of the input string is done.
2293
 * This function is suitable to work with inputs from untrusted sources.
2294
 *
2295
 * This function is not BOM-aware.
2296
 *
2297
 * @param input         the UTF-16 string to convert
2298
 * @param length        the length of the string in 2-byte code units (char16_t)
2299
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2300
 * @return number of written code units; 0 if input is not a valid UTF-16 string
2301
 * or if it cannot be represented as Latin1
2302
 */
2303
simdutf_warn_unused size_t convert_utf16_to_latin1(
2304
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2305
  #if SIMDUTF_SPAN
2306
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2307
convert_utf16_to_latin1(
2308
    std::span<const char16_t> utf16_input,
2309
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2310
    #if SIMDUTF_CPLUSPLUS23
2311
  if consteval {
2312
    return scalar::utf16_to_latin1::convert<endianness::NATIVE>(
2313
        utf16_input.data(), utf16_input.size(), latin1_output.data());
2314
  } else
2315
    #endif
2316
  {
2317
    return convert_utf16_to_latin1(
2318
        utf16_input.data(), utf16_input.size(),
2319
        reinterpret_cast<char *>(latin1_output.data()));
2320
  }
2321
}
2322
  #endif // SIMDUTF_SPAN
2323
2324
/**
2325
 * Convert possibly broken UTF-16LE string into Latin1 string.
2326
 * If the string cannot be represented as Latin1, an error
2327
 * is returned.
2328
 *
2329
 * During the conversion also validation of the input string is done.
2330
 * This function is suitable to work with inputs from untrusted sources.
2331
 *
2332
 * This function is not BOM-aware.
2333
 *
2334
 * @param input         the UTF-16LE string to convert
2335
 * @param length        the length of the string in 2-byte code units (char16_t)
2336
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2337
 * @return number of written code units; 0 if input is not a valid UTF-16LE
2338
 * string or if it cannot be represented as Latin1
2339
 */
2340
simdutf_warn_unused size_t convert_utf16le_to_latin1(
2341
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2342
  #if SIMDUTF_SPAN
2343
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2344
convert_utf16le_to_latin1(
2345
    std::span<const char16_t> utf16_input,
2346
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2347
    #if SIMDUTF_CPLUSPLUS23
2348
  if consteval {
2349
    return scalar::utf16_to_latin1::convert<endianness::LITTLE>(
2350
        utf16_input.data(), utf16_input.size(), latin1_output.data());
2351
  } else
2352
    #endif
2353
  {
2354
    return convert_utf16le_to_latin1(
2355
        utf16_input.data(), utf16_input.size(),
2356
        reinterpret_cast<char *>(latin1_output.data()));
2357
  }
2358
}
2359
  #endif // SIMDUTF_SPAN
2360
2361
/**
2362
 * Convert possibly broken UTF-16BE string into Latin1 string.
2363
 *
2364
 * During the conversion also validation of the input string is done.
2365
 * This function is suitable to work with inputs from untrusted sources.
2366
 *
2367
 * This function is not BOM-aware.
2368
 *
2369
 * @param input         the UTF-16BE string to convert
2370
 * @param length        the length of the string in 2-byte code units (char16_t)
2371
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2372
 * @return number of written code units; 0 if input is not a valid UTF-16BE
2373
 * string or if it cannot be represented as Latin1
2374
 */
2375
simdutf_warn_unused size_t convert_utf16be_to_latin1(
2376
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2377
  #if SIMDUTF_SPAN
2378
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2379
convert_utf16be_to_latin1(
2380
    std::span<const char16_t> utf16_input,
2381
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2382
    #if SIMDUTF_CPLUSPLUS23
2383
  if consteval {
2384
    return scalar::utf16_to_latin1::convert<endianness::BIG>(
2385
        utf16_input.data(), utf16_input.size(), latin1_output.data());
2386
  } else
2387
    #endif
2388
  {
2389
    return convert_utf16be_to_latin1(
2390
        utf16_input.data(), utf16_input.size(),
2391
        reinterpret_cast<char *>(latin1_output.data()));
2392
  }
2393
}
2394
  #endif // SIMDUTF_SPAN
2395
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
2396
2397
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2398
/**
2399
 * Convert possibly broken UTF-16LE string into UTF-8 string.
2400
 *
2401
 * During the conversion also validation of the input string is done.
2402
 * This function is suitable to work with inputs from untrusted sources.
2403
 *
2404
 * This function is not BOM-aware.
2405
 *
2406
 * @param input         the UTF-16LE string to convert
2407
 * @param length        the length of the string in 2-byte code units (char16_t)
2408
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2409
 * @return number of written code units; 0 if input is not a valid UTF-16LE
2410
 * string
2411
 */
2412
simdutf_warn_unused size_t convert_utf16le_to_utf8(const char16_t *input,
2413
                                                   size_t length,
2414
                                                   char *utf8_buffer) noexcept;
2415
  #if SIMDUTF_SPAN
2416
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2417
convert_utf16le_to_utf8(
2418
    std::span<const char16_t> utf16_input,
2419
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2420
    #if SIMDUTF_CPLUSPLUS23
2421
  if consteval {
2422
    return scalar::utf16_to_utf8::convert<endianness::LITTLE>(
2423
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2424
  } else
2425
    #endif
2426
  {
2427
    return convert_utf16le_to_utf8(
2428
        utf16_input.data(), utf16_input.size(),
2429
        reinterpret_cast<char *>(utf8_output.data()));
2430
  }
2431
}
2432
  #endif // SIMDUTF_SPAN
2433
2434
/**
2435
 * Convert possibly broken UTF-16BE string into UTF-8 string.
2436
 *
2437
 * During the conversion also validation of the input string is done.
2438
 * This function is suitable to work with inputs from untrusted sources.
2439
 *
2440
 * This function is not BOM-aware.
2441
 *
2442
 * @param input         the UTF-16BE string to convert
2443
 * @param length        the length of the string in 2-byte code units (char16_t)
2444
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2445
 * @return number of written code units; 0 if input is not a valid UTF-16LE
2446
 * string
2447
 */
2448
simdutf_warn_unused size_t convert_utf16be_to_utf8(const char16_t *input,
2449
                                                   size_t length,
2450
                                                   char *utf8_buffer) noexcept;
2451
  #if SIMDUTF_SPAN
2452
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2453
convert_utf16be_to_utf8(
2454
    std::span<const char16_t> utf16_input,
2455
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2456
    #if SIMDUTF_CPLUSPLUS23
2457
  if consteval {
2458
    return scalar::utf16_to_utf8::convert<endianness::BIG>(
2459
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2460
  } else
2461
    #endif
2462
  {
2463
    return convert_utf16be_to_utf8(
2464
        utf16_input.data(), utf16_input.size(),
2465
        reinterpret_cast<char *>(utf8_output.data()));
2466
  }
2467
}
2468
  #endif // SIMDUTF_SPAN
2469
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2470
2471
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
2472
/**
2473
 * Using native endianness, convert possibly broken UTF-16 string into Latin1
2474
 * string.
2475
 *
2476
 * During the conversion also validation of the input string is done.
2477
 * This function is suitable to work with inputs from untrusted sources.
2478
 * This function is not BOM-aware.
2479
 *
2480
 * @param input         the UTF-16 string to convert
2481
 * @param length        the length of the string in 2-byte code units (char16_t)
2482
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2483
 * @return a result pair struct (of type simdutf::result containing the two
2484
 * fields error and count) with an error code and either position of the error
2485
 * (in the input in code units) if any, or the number of char written if
2486
 * successful.
2487
 */
2488
simdutf_warn_unused result convert_utf16_to_latin1_with_errors(
2489
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2490
  #if SIMDUTF_SPAN
2491
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
2492
convert_utf16_to_latin1_with_errors(
2493
    std::span<const char16_t> utf16_input,
2494
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2495
    #if SIMDUTF_CPLUSPLUS23
2496
  if consteval {
2497
    return scalar::utf16_to_latin1::convert_with_errors<endianness::NATIVE>(
2498
        utf16_input.data(), utf16_input.size(), latin1_output.data());
2499
  } else
2500
    #endif
2501
  {
2502
    return convert_utf16_to_latin1_with_errors(
2503
        utf16_input.data(), utf16_input.size(),
2504
        reinterpret_cast<char *>(latin1_output.data()));
2505
  }
2506
}
2507
  #endif // SIMDUTF_SPAN
2508
2509
/**
2510
 * Convert possibly broken UTF-16LE string into Latin1 string.
2511
 *
2512
 * During the conversion also validation of the input string is done.
2513
 * This function is suitable to work with inputs from untrusted sources.
2514
 * This function is not BOM-aware.
2515
 *
2516
 * @param input         the UTF-16LE string to convert
2517
 * @param length        the length of the string in 2-byte code units (char16_t)
2518
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2519
 * @return a result pair struct (of type simdutf::result containing the two
2520
 * fields error and count) with an error code and either position of the error
2521
 * (in the input in code units) if any, or the number of char written if
2522
 * successful.
2523
 */
2524
simdutf_warn_unused result convert_utf16le_to_latin1_with_errors(
2525
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2526
  #if SIMDUTF_SPAN
2527
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
2528
convert_utf16le_to_latin1_with_errors(
2529
    std::span<const char16_t> utf16_input,
2530
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2531
    #if SIMDUTF_CPLUSPLUS23
2532
  if consteval {
2533
    return scalar::utf16_to_latin1::convert_with_errors<endianness::LITTLE>(
2534
        utf16_input.data(), utf16_input.size(), latin1_output.data());
2535
  } else
2536
    #endif
2537
  {
2538
    return convert_utf16le_to_latin1_with_errors(
2539
        utf16_input.data(), utf16_input.size(),
2540
        reinterpret_cast<char *>(latin1_output.data()));
2541
  }
2542
}
2543
  #endif // SIMDUTF_SPAN
2544
2545
/**
2546
 * Convert possibly broken UTF-16BE string into Latin1 string.
2547
 * If the string cannot be represented as Latin1, an error
2548
 * is returned.
2549
 *
2550
 * During the conversion also validation of the input string is done.
2551
 * This function is suitable to work with inputs from untrusted sources.
2552
 * This function is not BOM-aware.
2553
 *
2554
 * @param input         the UTF-16BE string to convert
2555
 * @param length        the length of the string in 2-byte code units (char16_t)
2556
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2557
 * @return a result pair struct (of type simdutf::result containing the two
2558
 * fields error and count) with an error code and either position of the error
2559
 * (in the input in code units) if any, or the number of char written if
2560
 * successful.
2561
 */
2562
simdutf_warn_unused result convert_utf16be_to_latin1_with_errors(
2563
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2564
  #if SIMDUTF_SPAN
2565
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
2566
convert_utf16be_to_latin1_with_errors(
2567
    std::span<const char16_t> utf16_input,
2568
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2569
    #if SIMDUTF_CPLUSPLUS23
2570
  if consteval {
2571
    return scalar::utf16_to_latin1::convert_with_errors<endianness::BIG>(
2572
        utf16_input.data(), utf16_input.size(), latin1_output.data());
2573
  } else
2574
    #endif
2575
  {
2576
    return convert_utf16be_to_latin1_with_errors(
2577
        utf16_input.data(), utf16_input.size(),
2578
        reinterpret_cast<char *>(latin1_output.data()));
2579
  }
2580
}
2581
  #endif // SIMDUTF_SPAN
2582
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
2583
2584
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2585
/**
2586
 * Using native endianness, convert possibly broken UTF-16 string into UTF-8
2587
 * string and stop on error.
2588
 *
2589
 * During the conversion also validation of the input string is done.
2590
 * This function is suitable to work with inputs from untrusted sources.
2591
 *
2592
 * This function is not BOM-aware.
2593
 *
2594
 * @param input         the UTF-16 string to convert
2595
 * @param length        the length of the string in 2-byte code units (char16_t)
2596
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2597
 * @return a result pair struct (of type simdutf::result containing the two
2598
 * fields error and count) with an error code and either position of the error
2599
 * (in the input in code units) if any, or the number of char written if
2600
 * successful.
2601
 */
2602
simdutf_warn_unused result convert_utf16_to_utf8_with_errors(
2603
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
2604
  #if SIMDUTF_SPAN
2605
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
2606
convert_utf16_to_utf8_with_errors(
2607
    std::span<const char16_t> utf16_input,
2608
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2609
    #if SIMDUTF_CPLUSPLUS23
2610
  if consteval {
2611
    return scalar::utf16_to_utf8::convert_with_errors<endianness::NATIVE>(
2612
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2613
  } else
2614
    #endif
2615
  {
2616
    return convert_utf16_to_utf8_with_errors(
2617
        utf16_input.data(), utf16_input.size(),
2618
        reinterpret_cast<char *>(utf8_output.data()));
2619
  }
2620
}
2621
  #endif // SIMDUTF_SPAN
2622
2623
/**
2624
 * Convert possibly broken UTF-16LE string into UTF-8 string and stop on error.
2625
 *
2626
 * During the conversion also validation of the input string is done.
2627
 * This function is suitable to work with inputs from untrusted sources.
2628
 *
2629
 * This function is not BOM-aware.
2630
 *
2631
 * @param input         the UTF-16LE string to convert
2632
 * @param length        the length of the string in 2-byte code units (char16_t)
2633
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2634
 * @return a result pair struct (of type simdutf::result containing the two
2635
 * fields error and count) with an error code and either position of the error
2636
 * (in the input in code units) if any, or the number of char written if
2637
 * successful.
2638
 */
2639
simdutf_warn_unused result convert_utf16le_to_utf8_with_errors(
2640
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
2641
  #if SIMDUTF_SPAN
2642
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
2643
convert_utf16le_to_utf8_with_errors(
2644
    std::span<const char16_t> utf16_input,
2645
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2646
    #if SIMDUTF_CPLUSPLUS23
2647
  if consteval {
2648
    return scalar::utf16_to_utf8::convert_with_errors<endianness::LITTLE>(
2649
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2650
  } else
2651
    #endif
2652
  {
2653
    return convert_utf16le_to_utf8_with_errors(
2654
        utf16_input.data(), utf16_input.size(),
2655
        reinterpret_cast<char *>(utf8_output.data()));
2656
  }
2657
}
2658
  #endif // SIMDUTF_SPAN
2659
2660
/**
2661
 * Convert possibly broken UTF-16BE string into UTF-8 string and stop on error.
2662
 *
2663
 * During the conversion also validation of the input string is done.
2664
 * This function is suitable to work with inputs from untrusted sources.
2665
 *
2666
 * This function is not BOM-aware.
2667
 *
2668
 * @param input         the UTF-16BE string to convert
2669
 * @param length        the length of the string in 2-byte code units (char16_t)
2670
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2671
 * @return a result pair struct (of type simdutf::result containing the two
2672
 * fields error and count) with an error code and either position of the error
2673
 * (in the input in code units) if any, or the number of char written if
2674
 * successful.
2675
 */
2676
simdutf_warn_unused result convert_utf16be_to_utf8_with_errors(
2677
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
2678
  #if SIMDUTF_SPAN
2679
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
2680
convert_utf16be_to_utf8_with_errors(
2681
    std::span<const char16_t> utf16_input,
2682
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2683
    #if SIMDUTF_CPLUSPLUS23
2684
  if consteval {
2685
    return scalar::utf16_to_utf8::convert_with_errors<endianness::BIG>(
2686
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2687
  } else
2688
    #endif
2689
  {
2690
    return convert_utf16be_to_utf8_with_errors(
2691
        utf16_input.data(), utf16_input.size(),
2692
        reinterpret_cast<char *>(utf8_output.data()));
2693
  }
2694
}
2695
  #endif // SIMDUTF_SPAN
2696
2697
/**
2698
 * Convert possibly broken UTF-16LE string into UTF-8 string, replacing
2699
 * unpaired surrogates with the Unicode replacement character U+FFFD.
2700
 *
2701
 * This function always succeeds: unpaired surrogates are replaced with
2702
 * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD).
2703
 *
2704
 * This function is not BOM-aware.
2705
 *
2706
 * @param input         the UTF-16LE string to convert
2707
 * @param length        the length of the string in 2-byte code units (char16_t)
2708
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2709
 * @return number of written code units
2710
 */
2711
simdutf_warn_unused size_t convert_utf16le_to_utf8_with_replacement(
2712
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
2713
  #if SIMDUTF_SPAN
2714
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2715
convert_utf16le_to_utf8_with_replacement(
2716
    std::span<const char16_t> utf16_input,
2717
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2718
    #if SIMDUTF_CPLUSPLUS23
2719
  if consteval {
2720
    return scalar::utf16_to_utf8::convert_with_replacement<endianness::LITTLE>(
2721
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2722
  } else
2723
    #endif
2724
  {
2725
    return convert_utf16le_to_utf8_with_replacement(
2726
        utf16_input.data(), utf16_input.size(),
2727
        reinterpret_cast<char *>(utf8_output.data()));
2728
  }
2729
}
2730
  #endif // SIMDUTF_SPAN
2731
2732
/**
2733
 * Convert possibly broken UTF-16BE string into UTF-8 string, replacing
2734
 * unpaired surrogates with the Unicode replacement character U+FFFD.
2735
 *
2736
 * This function always succeeds: unpaired surrogates are replaced with
2737
 * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD).
2738
 *
2739
 * This function is not BOM-aware.
2740
 *
2741
 * @param input         the UTF-16BE string to convert
2742
 * @param length        the length of the string in 2-byte code units (char16_t)
2743
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2744
 * @return number of written code units
2745
 */
2746
simdutf_warn_unused size_t convert_utf16be_to_utf8_with_replacement(
2747
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
2748
  #if SIMDUTF_SPAN
2749
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2750
convert_utf16be_to_utf8_with_replacement(
2751
    std::span<const char16_t> utf16_input,
2752
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2753
    #if SIMDUTF_CPLUSPLUS23
2754
  if consteval {
2755
    return scalar::utf16_to_utf8::convert_with_replacement<endianness::BIG>(
2756
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2757
  } else
2758
    #endif
2759
  {
2760
    return convert_utf16be_to_utf8_with_replacement(
2761
        utf16_input.data(), utf16_input.size(),
2762
        reinterpret_cast<char *>(utf8_output.data()));
2763
  }
2764
}
2765
  #endif // SIMDUTF_SPAN
2766
2767
/**
2768
 * Convert possibly broken UTF-16 string (native endianness) into UTF-8 string,
2769
 * replacing unpaired surrogates with the Unicode replacement character U+FFFD.
2770
 *
2771
 * This function always succeeds: unpaired surrogates are replaced with
2772
 * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD).
2773
 *
2774
 * This function is not BOM-aware.
2775
 *
2776
 * @param input         the UTF-16 string to convert
2777
 * @param length        the length of the string in 2-byte code units (char16_t)
2778
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
2779
 * @return number of written code units
2780
 */
2781
simdutf_warn_unused size_t convert_utf16_to_utf8_with_replacement(
2782
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
2783
  #if SIMDUTF_SPAN
2784
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2785
convert_utf16_to_utf8_with_replacement(
2786
    std::span<const char16_t> utf16_input,
2787
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2788
    #if SIMDUTF_CPLUSPLUS23
2789
  if consteval {
2790
    return scalar::utf16_to_utf8::convert_with_replacement<endianness::NATIVE>(
2791
        utf16_input.data(), utf16_input.size(), utf8_output.data());
2792
  } else
2793
    #endif
2794
  {
2795
    return convert_utf16_to_utf8_with_replacement(
2796
        utf16_input.data(), utf16_input.size(),
2797
        reinterpret_cast<char *>(utf8_output.data()));
2798
  }
2799
}
2800
  #endif // SIMDUTF_SPAN
2801
2802
/**
2803
 * Convert a possibly broken UTF-16 string into a size-limited UTF-8 buffer,
2804
 * replacing unpaired surrogates with U+FFFD and reporting how much input was
2805
 * consumed and output was written.
2806
 *
2807
 * We write as many complete characters as possible. The returned error is
2808
 * SUCCESS if all input was consumed, or OUTPUT_BUFFER_TOO_SMALL if the next
2809
 * character or replacement does not fit.
2810
 *
2811
 * @param input         the UTF-16 string to convert
2812
 * @param length        the length in 16-bit code units
2813
 * @param utf8_output   the pointer to the output buffer
2814
 * @param utf8_len      the maximum output length
2815
 * @return a full_result with error, input_count and output_count
2816
 */
2817
simdutf_warn_unused full_result convert_utf16_to_utf8_with_replacement_safe(
2818
    const char16_t *input, size_t length, char *utf8_output,
2819
    size_t utf8_len) noexcept;
2820
  #if SIMDUTF_SPAN
2821
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result
2822
convert_utf16_to_utf8_with_replacement_safe(
2823
    std::span<const char16_t> utf16_input,
2824
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2825
    #if SIMDUTF_CPLUSPLUS23
2826
  if consteval {
2827
    return scalar::utf16_to_utf8::convert_with_replacement_safe<
2828
        endianness::NATIVE>(utf16_input.data(), utf16_input.size(),
2829
                            utf8_output.data(), utf8_output.size());
2830
  } else
2831
    #endif
2832
  {
2833
    return convert_utf16_to_utf8_with_replacement_safe(
2834
        utf16_input.data(), utf16_input.size(),
2835
        reinterpret_cast<char *>(utf8_output.data()), utf8_output.size());
2836
  }
2837
}
2838
  #endif // SIMDUTF_SPAN
2839
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2840
2841
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2842
/**
2843
 * Using native endianness, convert valid UTF-16 string into UTF-8 string.
2844
 *
2845
 * This function assumes that the input string is valid UTF-16.
2846
 *
2847
 * This function is not BOM-aware.
2848
 *
2849
 * @param input         the UTF-16 string to convert
2850
 * @param length        the length of the string in 2-byte code units (char16_t)
2851
 * @param utf8_buffer   the pointer to a buffer that can hold the conversion
2852
 * result
2853
 * @return number of written code units; 0 if conversion is not possible
2854
 */
2855
simdutf_warn_unused size_t convert_valid_utf16_to_utf8(
2856
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
2857
  #if SIMDUTF_SPAN
2858
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2859
convert_valid_utf16_to_utf8(
2860
    std::span<const char16_t> valid_utf16_input,
2861
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
2862
    #if SIMDUTF_CPLUSPLUS23
2863
  if consteval {
2864
    return scalar::utf16_to_utf8::convert_valid<endianness::NATIVE>(
2865
        valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data());
2866
  } else
2867
    #endif
2868
  {
2869
    return convert_valid_utf16_to_utf8(
2870
        valid_utf16_input.data(), valid_utf16_input.size(),
2871
        reinterpret_cast<char *>(utf8_output.data()));
2872
  }
2873
}
2874
  #endif // SIMDUTF_SPAN
2875
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
2876
2877
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
2878
/**
2879
 * Using native endianness, convert UTF-16 string into Latin1 string.
2880
 *
2881
 * This function assumes that the input string is valid UTF-16 and that it can
2882
 * be represented as Latin1. If you violate this assumption, the result is
2883
 * implementation defined and may include system-dependent behavior such as
2884
 * crashes.
2885
 *
2886
 * This function is for expert users only and not part of our public API. Use
2887
 * convert_utf16_to_latin1 instead. The function may be removed from the library
2888
 * in the future.
2889
 *
2890
 * This function is not BOM-aware.
2891
 *
2892
 * @param input         the UTF-16 string to convert
2893
 * @param length        the length of the string in 2-byte code units (char16_t)
2894
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2895
 * @return number of written code units; 0 if conversion is not possible
2896
 */
2897
simdutf_warn_unused size_t convert_valid_utf16_to_latin1(
2898
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2899
  #if SIMDUTF_SPAN
2900
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
2901
convert_valid_utf16_to_latin1(
2902
    std::span<const char16_t> valid_utf16_input,
2903
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2904
    #if SIMDUTF_CPLUSPLUS23
2905
  if consteval {
2906
    return scalar::utf16_to_latin1::convert_valid_impl<endianness::NATIVE>(
2907
        detail::constexpr_cast_ptr<uint16_t>(valid_utf16_input.data()),
2908
        valid_utf16_input.size(),
2909
        detail::constexpr_cast_writeptr<char>(latin1_output.data()));
2910
  } else
2911
    #endif
2912
  {
2913
    return convert_valid_utf16_to_latin1(
2914
        valid_utf16_input.data(), valid_utf16_input.size(),
2915
        reinterpret_cast<char *>(latin1_output.data()));
2916
  }
2917
}
2918
  #endif // SIMDUTF_SPAN
2919
2920
/**
2921
 * Convert valid UTF-16LE string into Latin1 string.
2922
 *
2923
 * This function assumes that the input string is valid UTF-16LE and that it can
2924
 * be represented as Latin1. If you violate this assumption, the result is
2925
 * implementation defined and may include system-dependent behavior such as
2926
 * crashes.
2927
 *
2928
 * This function is for expert users only and not part of our public API. Use
2929
 * convert_utf16le_to_latin1 instead. The function may be removed from the
2930
 * library in the future.
2931
 *
2932
 * This function is not BOM-aware.
2933
 *
2934
 * @param input         the UTF-16LE string to convert
2935
 * @param length        the length of the string in 2-byte code units (char16_t)
2936
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2937
 * @return number of written code units; 0 if conversion is not possible
2938
 */
2939
simdutf_warn_unused size_t convert_valid_utf16le_to_latin1(
2940
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2941
  #if SIMDUTF_SPAN
2942
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t
2943
convert_valid_utf16le_to_latin1(
2944
    std::span<const char16_t> valid_utf16_input,
2945
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2946
    #if SIMDUTF_CPLUSPLUS23
2947
  if consteval {
2948
    return scalar::utf16_to_latin1::convert_valid_impl<endianness::LITTLE>(
2949
        detail::constexpr_cast_ptr<uint16_t>(valid_utf16_input.data()),
2950
        valid_utf16_input.size(),
2951
        detail::constexpr_cast_writeptr<char>(latin1_output.data()));
2952
  } else
2953
    #endif
2954
  {
2955
    return convert_valid_utf16le_to_latin1(
2956
        valid_utf16_input.data(), valid_utf16_input.size(),
2957
        reinterpret_cast<char *>(latin1_output.data()));
2958
  }
2959
}
2960
  #endif // SIMDUTF_SPAN
2961
2962
/**
2963
 * Convert valid UTF-16BE string into Latin1 string.
2964
 *
2965
 * This function assumes that the input string is valid UTF-16BE and that it can
2966
 * be represented as Latin1. If you violate this assumption, the result is
2967
 * implementation defined and may include system-dependent behavior such as
2968
 * crashes.
2969
 *
2970
 * This function is for expert users only and not part of our public API. Use
2971
 * convert_utf16be_to_latin1 instead. The function may be removed from the
2972
 * library in the future.
2973
 *
2974
 * This function is not BOM-aware.
2975
 *
2976
 * @param input         the UTF-16BE string to convert
2977
 * @param length        the length of the string in 2-byte code units (char16_t)
2978
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
2979
 * @return number of written code units; 0 if conversion is not possible
2980
 */
2981
simdutf_warn_unused size_t convert_valid_utf16be_to_latin1(
2982
    const char16_t *input, size_t length, char *latin1_buffer) noexcept;
2983
  #if SIMDUTF_SPAN
2984
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t
2985
convert_valid_utf16be_to_latin1(
2986
    std::span<const char16_t> valid_utf16_input,
2987
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
2988
    #if SIMDUTF_CPLUSPLUS23
2989
  if consteval {
2990
    return scalar::utf16_to_latin1::convert_valid_impl<endianness::BIG>(
2991
        detail::constexpr_cast_ptr<uint16_t>(valid_utf16_input.data()),
2992
        valid_utf16_input.size(),
2993
        detail::constexpr_cast_writeptr<char>(latin1_output.data()));
2994
  } else
2995
    #endif
2996
  {
2997
    return convert_valid_utf16be_to_latin1(
2998
        valid_utf16_input.data(), valid_utf16_input.size(),
2999
        reinterpret_cast<char *>(latin1_output.data()));
3000
  }
3001
}
3002
  #endif // SIMDUTF_SPAN
3003
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
3004
3005
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
3006
/**
3007
 * Convert valid UTF-16LE string into UTF-8 string.
3008
 *
3009
 * This function assumes that the input string is valid UTF-16LE
3010
 *
3011
 * This function is not BOM-aware.
3012
 *
3013
 * @param input         the UTF-16LE string to convert
3014
 * @param length        the length of the string in 2-byte code units (char16_t)
3015
 * @param utf8_buffer   the pointer to a buffer that can hold the conversion
3016
 * result
3017
 * @return number of written code units; 0 if conversion is not possible
3018
 */
3019
simdutf_warn_unused size_t convert_valid_utf16le_to_utf8(
3020
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
3021
  #if SIMDUTF_SPAN
3022
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3023
convert_valid_utf16le_to_utf8(
3024
    std::span<const char16_t> valid_utf16_input,
3025
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
3026
    #if SIMDUTF_CPLUSPLUS23
3027
  if consteval {
3028
    return scalar::utf16_to_utf8::convert_valid<endianness::NATIVE>(
3029
        valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data());
3030
  } else
3031
    #endif
3032
  {
3033
    return convert_valid_utf16le_to_utf8(
3034
        valid_utf16_input.data(), valid_utf16_input.size(),
3035
        reinterpret_cast<char *>(utf8_output.data()));
3036
  }
3037
}
3038
  #endif // SIMDUTF_SPAN
3039
3040
/**
3041
 * Convert valid UTF-16BE string into UTF-8 string.
3042
 *
3043
 * This function assumes that the input string is valid UTF-16BE.
3044
 *
3045
 * This function is not BOM-aware.
3046
 *
3047
 * @param input         the UTF-16BE string to convert
3048
 * @param length        the length of the string in 2-byte code units (char16_t)
3049
 * @param utf8_buffer   the pointer to a buffer that can hold the conversion
3050
 * result
3051
 * @return number of written code units; 0 if conversion is not possible
3052
 */
3053
simdutf_warn_unused size_t convert_valid_utf16be_to_utf8(
3054
    const char16_t *input, size_t length, char *utf8_buffer) noexcept;
3055
  #if SIMDUTF_SPAN
3056
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3057
convert_valid_utf16be_to_utf8(
3058
    std::span<const char16_t> valid_utf16_input,
3059
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
3060
    #if SIMDUTF_CPLUSPLUS23
3061
  if consteval {
3062
    return scalar::utf16_to_utf8::convert_valid<endianness::BIG>(
3063
        valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data());
3064
  } else
3065
    #endif
3066
  {
3067
    return convert_valid_utf16be_to_utf8(
3068
        valid_utf16_input.data(), valid_utf16_input.size(),
3069
        reinterpret_cast<char *>(utf8_output.data()));
3070
  }
3071
}
3072
  #endif // SIMDUTF_SPAN
3073
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
3074
3075
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
3076
/**
3077
 * Using native endianness, convert possibly broken UTF-16 string into UTF-32
3078
 * string.
3079
 *
3080
 * During the conversion also validation of the input string is done.
3081
 * This function is suitable to work with inputs from untrusted sources.
3082
 *
3083
 * This function is not BOM-aware.
3084
 *
3085
 * @param input         the UTF-16 string to convert
3086
 * @param length        the length of the string in 2-byte code units (char16_t)
3087
 * @param utf32_buffer   the pointer to buffer that can hold conversion result
3088
 * @return number of written code units; 0 if input is not a valid UTF-16LE
3089
 * string
3090
 */
3091
simdutf_warn_unused size_t convert_utf16_to_utf32(
3092
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3093
  #if SIMDUTF_SPAN
3094
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3095
convert_utf16_to_utf32(std::span<const char16_t> utf16_input,
3096
0
                       std::span<char32_t> utf32_output) noexcept {
3097
0
3098
0
    #if SIMDUTF_CPLUSPLUS23
3099
0
  if consteval {
3100
0
    return scalar::utf16_to_utf32::convert<endianness::NATIVE>(
3101
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3102
0
  } else
3103
0
    #endif
3104
0
  {
3105
0
    return convert_utf16_to_utf32(utf16_input.data(), utf16_input.size(),
3106
0
                                  utf32_output.data());
3107
0
  }
3108
0
}
3109
  #endif // SIMDUTF_SPAN
3110
3111
/**
3112
 * Convert possibly broken UTF-16LE string into UTF-32 string.
3113
 *
3114
 * During the conversion also validation of the input string is done.
3115
 * This function is suitable to work with inputs from untrusted sources.
3116
 *
3117
 * This function is not BOM-aware.
3118
 *
3119
 * @param input         the UTF-16LE string to convert
3120
 * @param length        the length of the string in 2-byte code units (char16_t)
3121
 * @param utf32_buffer   the pointer to buffer that can hold conversion result
3122
 * @return number of written code units; 0 if input is not a valid UTF-16LE
3123
 * string
3124
 */
3125
simdutf_warn_unused size_t convert_utf16le_to_utf32(
3126
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3127
  #if SIMDUTF_SPAN
3128
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3129
convert_utf16le_to_utf32(std::span<const char16_t> utf16_input,
3130
0
                         std::span<char32_t> utf32_output) noexcept {
3131
0
    #if SIMDUTF_CPLUSPLUS23
3132
0
  if consteval {
3133
0
    return scalar::utf16_to_utf32::convert<endianness::LITTLE>(
3134
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3135
0
  } else
3136
0
    #endif
3137
0
  {
3138
0
    return convert_utf16le_to_utf32(utf16_input.data(), utf16_input.size(),
3139
0
                                    utf32_output.data());
3140
0
  }
3141
0
}
3142
  #endif // SIMDUTF_SPAN
3143
3144
/**
3145
 * Convert possibly broken UTF-16BE string into UTF-32 string.
3146
 *
3147
 * During the conversion also validation of the input string is done.
3148
 * This function is suitable to work with inputs from untrusted sources.
3149
 *
3150
 * This function is not BOM-aware.
3151
 *
3152
 * @param input         the UTF-16BE string to convert
3153
 * @param length        the length of the string in 2-byte code units (char16_t)
3154
 * @param utf32_buffer   the pointer to buffer that can hold conversion result
3155
 * @return number of written code units; 0 if input is not a valid UTF-16LE
3156
 * string
3157
 */
3158
simdutf_warn_unused size_t convert_utf16be_to_utf32(
3159
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3160
  #if SIMDUTF_SPAN
3161
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3162
convert_utf16be_to_utf32(std::span<const char16_t> utf16_input,
3163
0
                         std::span<char32_t> utf32_output) noexcept {
3164
0
    #if SIMDUTF_CPLUSPLUS23
3165
0
  if consteval {
3166
0
    return scalar::utf16_to_utf32::convert<endianness::BIG>(
3167
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3168
0
  } else
3169
0
    #endif
3170
0
  {
3171
0
    return convert_utf16be_to_utf32(utf16_input.data(), utf16_input.size(),
3172
0
                                    utf32_output.data());
3173
0
  }
3174
0
}
3175
  #endif // SIMDUTF_SPAN
3176
3177
/**
3178
 * Using native endianness, convert possibly broken UTF-16 string into
3179
 * UTF-32 string and stop on error.
3180
 *
3181
 * During the conversion also validation of the input string is done.
3182
 * This function is suitable to work with inputs from untrusted sources.
3183
 *
3184
 * This function is not BOM-aware.
3185
 *
3186
 * @param input         the UTF-16 string to convert
3187
 * @param length        the length of the string in 2-byte code units (char16_t)
3188
 * @param utf32_buffer   the pointer to buffer that can hold conversion result
3189
 * @return a result pair struct (of type simdutf::result containing the two
3190
 * fields error and count) with an error code and either position of the error
3191
 * (in the input in code units) if any, or the number of char32_t written if
3192
 * successful.
3193
 */
3194
simdutf_warn_unused result convert_utf16_to_utf32_with_errors(
3195
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3196
  #if SIMDUTF_SPAN
3197
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3198
convert_utf16_to_utf32_with_errors(std::span<const char16_t> utf16_input,
3199
0
                                   std::span<char32_t> utf32_output) noexcept {
3200
0
    #if SIMDUTF_CPLUSPLUS23
3201
0
  if consteval {
3202
0
    return scalar::utf16_to_utf32::convert_with_errors<endianness::NATIVE>(
3203
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3204
0
  } else
3205
0
    #endif
3206
0
  {
3207
0
    return convert_utf16_to_utf32_with_errors(
3208
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3209
0
  }
3210
0
}
3211
  #endif // SIMDUTF_SPAN
3212
3213
/**
3214
 * Convert possibly broken UTF-16LE string into UTF-32 string and stop on error.
3215
 *
3216
 * During the conversion also validation of the input string is done.
3217
 * This function is suitable to work with inputs from untrusted sources.
3218
 *
3219
 * This function is not BOM-aware.
3220
 *
3221
 * @param input         the UTF-16LE string to convert
3222
 * @param length        the length of the string in 2-byte code units (char16_t)
3223
 * @param utf32_buffer   the pointer to buffer that can hold conversion result
3224
 * @return a result pair struct (of type simdutf::result containing the two
3225
 * fields error and count) with an error code and either position of the error
3226
 * (in the input in code units) if any, or the number of char32_t written if
3227
 * successful.
3228
 */
3229
simdutf_warn_unused result convert_utf16le_to_utf32_with_errors(
3230
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3231
  #if SIMDUTF_SPAN
3232
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3233
convert_utf16le_to_utf32_with_errors(
3234
    std::span<const char16_t> utf16_input,
3235
0
    std::span<char32_t> utf32_output) noexcept {
3236
0
    #if SIMDUTF_CPLUSPLUS23
3237
0
  if consteval {
3238
0
    return scalar::utf16_to_utf32::convert_with_errors<endianness::LITTLE>(
3239
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3240
0
  } else
3241
0
    #endif
3242
0
  {
3243
0
    return convert_utf16le_to_utf32_with_errors(
3244
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3245
0
  }
3246
0
}
3247
  #endif // SIMDUTF_SPAN
3248
3249
/**
3250
 * Convert possibly broken UTF-16BE string into UTF-32 string and stop on error.
3251
 *
3252
 * During the conversion also validation of the input string is done.
3253
 * This function is suitable to work with inputs from untrusted sources.
3254
 *
3255
 * This function is not BOM-aware.
3256
 *
3257
 * @param input         the UTF-16BE string to convert
3258
 * @param length        the length of the string in 2-byte code units (char16_t)
3259
 * @param utf32_buffer   the pointer to buffer that can hold conversion result
3260
 * @return a result pair struct (of type simdutf::result containing the two
3261
 * fields error and count) with an error code and either position of the error
3262
 * (in the input in code units) if any, or the number of char32_t written if
3263
 * successful.
3264
 */
3265
simdutf_warn_unused result convert_utf16be_to_utf32_with_errors(
3266
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3267
  #if SIMDUTF_SPAN
3268
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3269
convert_utf16be_to_utf32_with_errors(
3270
    std::span<const char16_t> utf16_input,
3271
0
    std::span<char32_t> utf32_output) noexcept {
3272
0
    #if SIMDUTF_CPLUSPLUS23
3273
0
  if consteval {
3274
0
    return scalar::utf16_to_utf32::convert_with_errors<endianness::BIG>(
3275
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3276
0
  } else
3277
0
    #endif
3278
0
  {
3279
0
    return convert_utf16be_to_utf32_with_errors(
3280
0
        utf16_input.data(), utf16_input.size(), utf32_output.data());
3281
0
  }
3282
0
}
3283
  #endif // SIMDUTF_SPAN
3284
3285
/**
3286
 * Using native endianness, convert valid UTF-16 string into UTF-32 string.
3287
 *
3288
 * This function assumes that the input string is valid UTF-16 (native
3289
 * endianness).
3290
 *
3291
 * This function is not BOM-aware.
3292
 *
3293
 * @param input         the UTF-16 string to convert
3294
 * @param length        the length of the string in 2-byte code units (char16_t)
3295
 * @param utf32_buffer   the pointer to a buffer that can hold the conversion
3296
 * result
3297
 * @return number of written code units; 0 if conversion is not possible
3298
 */
3299
simdutf_warn_unused size_t convert_valid_utf16_to_utf32(
3300
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3301
  #if SIMDUTF_SPAN
3302
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3303
convert_valid_utf16_to_utf32(std::span<const char16_t> valid_utf16_input,
3304
0
                             std::span<char32_t> utf32_output) noexcept {
3305
0
    #if SIMDUTF_CPLUSPLUS23
3306
0
  if consteval {
3307
0
    return scalar::utf16_to_utf32::convert_valid<endianness::NATIVE>(
3308
0
        valid_utf16_input.data(), valid_utf16_input.size(),
3309
0
        utf32_output.data());
3310
0
  } else
3311
0
    #endif
3312
0
  {
3313
0
    return convert_valid_utf16_to_utf32(valid_utf16_input.data(),
3314
0
                                        valid_utf16_input.size(),
3315
0
                                        utf32_output.data());
3316
0
  }
3317
0
}
3318
  #endif // SIMDUTF_SPAN
3319
3320
/**
3321
 * Convert valid UTF-16LE string into UTF-32 string.
3322
 *
3323
 * This function assumes that the input string is valid UTF-16LE.
3324
 *
3325
 * This function is not BOM-aware.
3326
 *
3327
 * @param input         the UTF-16LE string to convert
3328
 * @param length        the length of the string in 2-byte code units (char16_t)
3329
 * @param utf32_buffer   the pointer to a buffer that can hold the conversion
3330
 * result
3331
 * @return number of written code units; 0 if conversion is not possible
3332
 */
3333
simdutf_warn_unused size_t convert_valid_utf16le_to_utf32(
3334
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3335
  #if SIMDUTF_SPAN
3336
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3337
convert_valid_utf16le_to_utf32(std::span<const char16_t> valid_utf16_input,
3338
0
                               std::span<char32_t> utf32_output) noexcept {
3339
0
    #if SIMDUTF_CPLUSPLUS23
3340
0
  if consteval {
3341
0
    return scalar::utf16_to_utf32::convert_valid<endianness::LITTLE>(
3342
0
        valid_utf16_input.data(), valid_utf16_input.size(),
3343
0
        utf32_output.data());
3344
0
  } else
3345
0
    #endif
3346
0
  {
3347
0
    return convert_valid_utf16le_to_utf32(valid_utf16_input.data(),
3348
0
                                          valid_utf16_input.size(),
3349
0
                                          utf32_output.data());
3350
0
  }
3351
0
}
3352
  #endif // SIMDUTF_SPAN
3353
3354
/**
3355
 * Convert valid UTF-16BE string into UTF-32 string.
3356
 *
3357
 * This function assumes that the input string is valid UTF-16LE.
3358
 *
3359
 * This function is not BOM-aware.
3360
 *
3361
 * @param input         the UTF-16BE string to convert
3362
 * @param length        the length of the string in 2-byte code units (char16_t)
3363
 * @param utf32_buffer   the pointer to a buffer that can hold the conversion
3364
 * result
3365
 * @return number of written code units; 0 if conversion is not possible
3366
 */
3367
simdutf_warn_unused size_t convert_valid_utf16be_to_utf32(
3368
    const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept;
3369
  #if SIMDUTF_SPAN
3370
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3371
convert_valid_utf16be_to_utf32(std::span<const char16_t> valid_utf16_input,
3372
0
                               std::span<char32_t> utf32_output) noexcept {
3373
0
    #if SIMDUTF_CPLUSPLUS23
3374
0
  if consteval {
3375
0
    return scalar::utf16_to_utf32::convert_valid<endianness::BIG>(
3376
0
        valid_utf16_input.data(), valid_utf16_input.size(),
3377
0
        utf32_output.data());
3378
0
  } else
3379
0
    #endif
3380
0
  {
3381
0
    return convert_valid_utf16be_to_utf32(valid_utf16_input.data(),
3382
0
                                          valid_utf16_input.size(),
3383
0
                                          utf32_output.data());
3384
0
  }
3385
0
}
3386
  #endif // SIMDUTF_SPAN
3387
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
3388
3389
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
3390
/**
3391
 * Using native endianness; Compute the number of bytes that this UTF-16
3392
 * string would require in UTF-8 format.
3393
 *
3394
 * This function does not validate the input. It is acceptable to pass invalid
3395
 * UTF-16 strings but in such cases the result is implementation defined.
3396
 *
3397
 * @param input         the UTF-16 string to convert
3398
 * @param length        the length of the string in 2-byte code units (char16_t)
3399
 * @return the number of bytes required to encode the UTF-16LE string as UTF-8
3400
 */
3401
simdutf_warn_unused size_t utf8_length_from_utf16(const char16_t *input,
3402
                                                  size_t length) noexcept;
3403
  #if SIMDUTF_SPAN
3404
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3405
0
utf8_length_from_utf16(std::span<const char16_t> valid_utf16_input) noexcept {
3406
0
    #if SIMDUTF_CPLUSPLUS23
3407
0
  if consteval {
3408
0
    return scalar::utf16::utf8_length_from_utf16<endianness::NATIVE>(
3409
0
        valid_utf16_input.data(), valid_utf16_input.size());
3410
0
  } else
3411
0
    #endif
3412
0
  {
3413
0
    return utf8_length_from_utf16(valid_utf16_input.data(),
3414
0
                                  valid_utf16_input.size());
3415
0
  }
3416
0
}
3417
  #endif // SIMDUTF_SPAN
3418
3419
/**
3420
 * Using native endianness; compute the number of bytes that this UTF-16
3421
 * string would require in UTF-8 format even when the UTF-16LE content contains
3422
 * mismatched surrogates that have to be replaced by the replacement character
3423
 * (0xFFFD).
3424
 *
3425
 * @param input         the UTF-16 string to convert
3426
 * @param length        the length of the string in 2-byte code units (char16_t)
3427
 * @return a result pair struct (of type simdutf::result containing the two
3428
 * fields error and count) where the count is the number of bytes required to
3429
 * encode the UTF-16 string as UTF-8, and the error code is either SUCCESS or
3430
 * SURROGATE. The count is correct regardless of the error field.
3431
 * When SURROGATE is returned, it does not indicate an error in the case of this
3432
 * function: it indicates that at least one surrogate has been encountered: the
3433
 * surrogates may be matched or not (thus this function does not validate). If
3434
 * the returned error code is SUCCESS, then the input contains no surrogate, is
3435
 * in the Basic Multilingual Plane, and is necessarily valid.
3436
 */
3437
simdutf_warn_unused result utf8_length_from_utf16_with_replacement(
3438
    const char16_t *input, size_t length) noexcept;
3439
  #if SIMDUTF_SPAN
3440
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3441
utf8_length_from_utf16_with_replacement(
3442
0
    std::span<const char16_t> valid_utf16_input) noexcept {
3443
0
    #if SIMDUTF_CPLUSPLUS23
3444
0
  if consteval {
3445
0
    return scalar::utf16::utf8_length_from_utf16_with_replacement<
3446
0
        endianness::NATIVE>(valid_utf16_input.data(), valid_utf16_input.size());
3447
0
  } else
3448
0
    #endif
3449
0
  {
3450
0
    return utf8_length_from_utf16_with_replacement(valid_utf16_input.data(),
3451
0
                                                   valid_utf16_input.size());
3452
0
  }
3453
0
}
3454
  #endif // SIMDUTF_SPAN
3455
3456
/**
3457
 * Compute the number of bytes that this UTF-16LE string would require in UTF-8
3458
 * format.
3459
 *
3460
 * This function does not validate the input. It is acceptable to pass invalid
3461
 * UTF-16 strings but in such cases the result is implementation defined.
3462
 *
3463
 * @param input         the UTF-16LE string to convert
3464
 * @param length        the length of the string in 2-byte code units (char16_t)
3465
 * @return the number of bytes required to encode the UTF-16LE string as UTF-8
3466
 */
3467
simdutf_warn_unused size_t utf8_length_from_utf16le(const char16_t *input,
3468
                                                    size_t length) noexcept;
3469
  #if SIMDUTF_SPAN
3470
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t
3471
0
utf8_length_from_utf16le(std::span<const char16_t> valid_utf16_input) noexcept {
3472
0
    #if SIMDUTF_CPLUSPLUS23
3473
0
  if consteval {
3474
0
    return scalar::utf16::utf8_length_from_utf16<endianness::LITTLE>(
3475
0
        valid_utf16_input.data(), valid_utf16_input.size());
3476
0
  } else
3477
0
    #endif
3478
0
  {
3479
0
    return utf8_length_from_utf16le(valid_utf16_input.data(),
3480
0
                                    valid_utf16_input.size());
3481
0
  }
3482
0
}
3483
  #endif // SIMDUTF_SPAN
3484
3485
/**
3486
 * Compute the number of bytes that this UTF-16BE string would require in UTF-8
3487
 * format.
3488
 *
3489
 * This function does not validate the input. It is acceptable to pass invalid
3490
 * UTF-16 strings but in such cases the result is implementation defined.
3491
 *
3492
 * @param input         the UTF-16BE string to convert
3493
 * @param length        the length of the string in 2-byte code units (char16_t)
3494
 * @return the number of bytes required to encode the UTF-16BE string as UTF-8
3495
 */
3496
simdutf_warn_unused size_t utf8_length_from_utf16be(const char16_t *input,
3497
                                                    size_t length) noexcept;
3498
  #if SIMDUTF_SPAN
3499
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3500
0
utf8_length_from_utf16be(std::span<const char16_t> valid_utf16_input) noexcept {
3501
0
    #if SIMDUTF_CPLUSPLUS23
3502
0
  if consteval {
3503
0
    return scalar::utf16::utf8_length_from_utf16<endianness::BIG>(
3504
0
        valid_utf16_input.data(), valid_utf16_input.size());
3505
0
  } else
3506
0
    #endif
3507
0
  {
3508
0
    return utf8_length_from_utf16be(valid_utf16_input.data(),
3509
0
                                    valid_utf16_input.size());
3510
0
  }
3511
0
}
3512
  #endif // SIMDUTF_SPAN
3513
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
3514
3515
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
3516
/**
3517
 * Convert possibly broken UTF-32 string into UTF-8 string.
3518
 *
3519
 * During the conversion also validation of the input string is done.
3520
 * This function is suitable to work with inputs from untrusted sources.
3521
 *
3522
 * This function is not BOM-aware.
3523
 *
3524
 * @param input         the UTF-32 string to convert
3525
 * @param length        the length of the string in 4-byte code units (char32_t)
3526
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
3527
 * @return number of written code units; 0 if input is not a valid UTF-32 string
3528
 */
3529
simdutf_warn_unused size_t convert_utf32_to_utf8(const char32_t *input,
3530
                                                 size_t length,
3531
                                                 char *utf8_buffer) noexcept;
3532
  #if SIMDUTF_SPAN
3533
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3534
convert_utf32_to_utf8(
3535
    std::span<const char32_t> utf32_input,
3536
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
3537
    #if SIMDUTF_CPLUSPLUS23
3538
  if consteval {
3539
    return scalar::utf32_to_utf8::convert(
3540
        utf32_input.data(), utf32_input.size(), utf8_output.data());
3541
  } else
3542
    #endif
3543
  {
3544
    return convert_utf32_to_utf8(utf32_input.data(), utf32_input.size(),
3545
                                 reinterpret_cast<char *>(utf8_output.data()));
3546
  }
3547
}
3548
  #endif // SIMDUTF_SPAN
3549
3550
/**
3551
 * Convert possibly broken UTF-32 string into UTF-8 string and stop on error.
3552
 *
3553
 * During the conversion also validation of the input string is done.
3554
 * This function is suitable to work with inputs from untrusted sources.
3555
 *
3556
 * This function is not BOM-aware.
3557
 *
3558
 * @param input         the UTF-32 string to convert
3559
 * @param length        the length of the string in 4-byte code units (char32_t)
3560
 * @param utf8_buffer   the pointer to buffer that can hold conversion result
3561
 * @return a result pair struct (of type simdutf::result containing the two
3562
 * fields error and count) with an error code and either position of the error
3563
 * (in the input in code units) if any, or the number of char written if
3564
 * successful.
3565
 */
3566
simdutf_warn_unused result convert_utf32_to_utf8_with_errors(
3567
    const char32_t *input, size_t length, char *utf8_buffer) noexcept;
3568
  #if SIMDUTF_SPAN
3569
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3570
convert_utf32_to_utf8_with_errors(
3571
    std::span<const char32_t> utf32_input,
3572
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
3573
    #if SIMDUTF_CPLUSPLUS23
3574
  if consteval {
3575
    return scalar::utf32_to_utf8::convert_with_errors(
3576
        utf32_input.data(), utf32_input.size(), utf8_output.data());
3577
  } else
3578
    #endif
3579
  {
3580
    return convert_utf32_to_utf8_with_errors(
3581
        utf32_input.data(), utf32_input.size(),
3582
        reinterpret_cast<char *>(utf8_output.data()));
3583
  }
3584
}
3585
  #endif // SIMDUTF_SPAN
3586
3587
/**
3588
 * Convert valid UTF-32 string into UTF-8 string.
3589
 *
3590
 * This function assumes that the input string is valid UTF-32.
3591
 *
3592
 * This function is not BOM-aware.
3593
 *
3594
 * @param input         the UTF-32 string to convert
3595
 * @param length        the length of the string in 4-byte code units (char32_t)
3596
 * @param utf8_buffer   the pointer to a buffer that can hold the conversion
3597
 * result
3598
 * @return number of written code units; 0 if conversion is not possible
3599
 */
3600
simdutf_warn_unused size_t convert_valid_utf32_to_utf8(
3601
    const char32_t *input, size_t length, char *utf8_buffer) noexcept;
3602
  #if SIMDUTF_SPAN
3603
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3604
convert_valid_utf32_to_utf8(
3605
    std::span<const char32_t> valid_utf32_input,
3606
    detail::output_span_of_byte_like auto &&utf8_output) noexcept {
3607
    #if SIMDUTF_CPLUSPLUS23
3608
  if consteval {
3609
    return scalar::utf32_to_utf8::convert_valid(
3610
        valid_utf32_input.data(), valid_utf32_input.size(), utf8_output.data());
3611
  } else
3612
    #endif
3613
  {
3614
    return convert_valid_utf32_to_utf8(
3615
        valid_utf32_input.data(), valid_utf32_input.size(),
3616
        reinterpret_cast<char *>(utf8_output.data()));
3617
  }
3618
}
3619
  #endif // SIMDUTF_SPAN
3620
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
3621
3622
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
3623
/**
3624
 * Using native endianness, convert possibly broken UTF-32 string into a UTF-16
3625
 * string.
3626
 *
3627
 * During the conversion also validation of the input string is done.
3628
 * This function is suitable to work with inputs from untrusted sources.
3629
 *
3630
 * This function is not BOM-aware.
3631
 *
3632
 * @param input         the UTF-32 string to convert
3633
 * @param length        the length of the string in 4-byte code units (char32_t)
3634
 * @param utf16_buffer   the pointer to buffer that can hold conversion result
3635
 * @return number of written code units; 0 if input is not a valid UTF-32 string
3636
 */
3637
simdutf_warn_unused size_t convert_utf32_to_utf16(
3638
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
3639
  #if SIMDUTF_SPAN
3640
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3641
convert_utf32_to_utf16(std::span<const char32_t> utf32_input,
3642
0
                       std::span<char16_t> utf16_output) noexcept {
3643
0
    #if SIMDUTF_CPLUSPLUS23
3644
0
  if consteval {
3645
0
    return scalar::utf32_to_utf16::convert<endianness::NATIVE>(
3646
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3647
0
  } else
3648
0
    #endif
3649
0
  {
3650
0
    return convert_utf32_to_utf16(utf32_input.data(), utf32_input.size(),
3651
0
                                  utf16_output.data());
3652
0
  }
3653
0
}
3654
  #endif // SIMDUTF_SPAN
3655
3656
/**
3657
 * Convert possibly broken UTF-32 string into UTF-16LE string.
3658
 *
3659
 * During the conversion also validation of the input string is done.
3660
 * This function is suitable to work with inputs from untrusted sources.
3661
 *
3662
 * This function is not BOM-aware.
3663
 *
3664
 * @param input         the UTF-32 string to convert
3665
 * @param length        the length of the string in 4-byte code units (char32_t)
3666
 * @param utf16_buffer   the pointer to buffer that can hold conversion result
3667
 * @return number of written code units; 0 if input is not a valid UTF-32 string
3668
 */
3669
simdutf_warn_unused size_t convert_utf32_to_utf16le(
3670
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
3671
  #if SIMDUTF_SPAN
3672
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3673
convert_utf32_to_utf16le(std::span<const char32_t> utf32_input,
3674
0
                         std::span<char16_t> utf16_output) noexcept {
3675
0
    #if SIMDUTF_CPLUSPLUS23
3676
0
  if consteval {
3677
0
    return scalar::utf32_to_utf16::convert<endianness::LITTLE>(
3678
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3679
0
  } else
3680
0
    #endif
3681
0
  {
3682
0
    return convert_utf32_to_utf16le(utf32_input.data(), utf32_input.size(),
3683
0
                                    utf16_output.data());
3684
0
  }
3685
0
}
3686
  #endif // SIMDUTF_SPAN
3687
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
3688
3689
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
3690
/**
3691
 * Convert possibly broken UTF-32 string into Latin1 string.
3692
 *
3693
 * During the conversion also validation of the input string is done.
3694
 * This function is suitable to work with inputs from untrusted sources.
3695
 *
3696
 * This function is not BOM-aware.
3697
 *
3698
 * @param input         the UTF-32 string to convert
3699
 * @param length        the length of the string in 4-byte code units (char32_t)
3700
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
3701
 * @return number of written code units; 0 if input is not a valid UTF-32 string
3702
 * or if it cannot be represented as Latin1
3703
 */
3704
simdutf_warn_unused size_t convert_utf32_to_latin1(
3705
    const char32_t *input, size_t length, char *latin1_buffer) noexcept;
3706
  #if SIMDUTF_SPAN
3707
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3708
convert_utf32_to_latin1(
3709
    std::span<const char32_t> utf32_input,
3710
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
3711
    #if SIMDUTF_CPLUSPLUS23
3712
  if consteval {
3713
    return scalar::utf32_to_latin1::convert(
3714
        utf32_input.data(), utf32_input.size(), latin1_output.data());
3715
  } else
3716
    #endif
3717
  {
3718
    return convert_utf32_to_latin1(
3719
        utf32_input.data(), utf32_input.size(),
3720
        reinterpret_cast<char *>(latin1_output.data()));
3721
  }
3722
}
3723
  #endif // SIMDUTF_SPAN
3724
3725
/**
3726
 * Convert possibly broken UTF-32 string into Latin1 string and stop on error.
3727
 * If the string cannot be represented as Latin1, an error is returned.
3728
 *
3729
 * During the conversion also validation of the input string is done.
3730
 * This function is suitable to work with inputs from untrusted sources.
3731
 *
3732
 * This function is not BOM-aware.
3733
 *
3734
 * @param input         the UTF-32 string to convert
3735
 * @param length        the length of the string in 4-byte code units (char32_t)
3736
 * @param latin1_buffer   the pointer to buffer that can hold conversion result
3737
 * @return a result pair struct (of type simdutf::result containing the two
3738
 * fields error and count) with an error code and either position of the error
3739
 * (in the input in code units) if any, or the number of char written if
3740
 * successful.
3741
 */
3742
simdutf_warn_unused result convert_utf32_to_latin1_with_errors(
3743
    const char32_t *input, size_t length, char *latin1_buffer) noexcept;
3744
  #if SIMDUTF_SPAN
3745
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3746
convert_utf32_to_latin1_with_errors(
3747
    std::span<const char32_t> utf32_input,
3748
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
3749
    #if SIMDUTF_CPLUSPLUS23
3750
  if consteval {
3751
    return scalar::utf32_to_latin1::convert_with_errors(
3752
        utf32_input.data(), utf32_input.size(), latin1_output.data());
3753
  } else
3754
    #endif
3755
  {
3756
    return convert_utf32_to_latin1_with_errors(
3757
        utf32_input.data(), utf32_input.size(),
3758
        reinterpret_cast<char *>(latin1_output.data()));
3759
  }
3760
}
3761
  #endif // SIMDUTF_SPAN
3762
3763
/**
3764
 * Convert valid UTF-32 string into Latin1 string.
3765
 *
3766
 * This function assumes that the input string is valid UTF-32 and that it can
3767
 * be represented as Latin1. If you violate this assumption, the result is
3768
 * implementation defined and may include system-dependent behavior such as
3769
 * crashes.
3770
 *
3771
 * This function is for expert users only and not part of our public API. Use
3772
 * convert_utf32_to_latin1 instead. The function may be removed from the library
3773
 * in the future.
3774
 *
3775
 * This function is not BOM-aware.
3776
 *
3777
 * @param input         the UTF-32 string to convert
3778
 * @param length        the length of the string in 4-byte code units (char32_t)
3779
 * @param latin1_buffer   the pointer to a buffer that can hold the conversion
3780
 * result
3781
 * @return number of written code units; 0 if conversion is not possible
3782
 */
3783
simdutf_warn_unused size_t convert_valid_utf32_to_latin1(
3784
    const char32_t *input, size_t length, char *latin1_buffer) noexcept;
3785
  #if SIMDUTF_SPAN
3786
simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t
3787
convert_valid_utf32_to_latin1(
3788
    std::span<const char32_t> valid_utf32_input,
3789
    detail::output_span_of_byte_like auto &&latin1_output) noexcept {
3790
    #if SIMDUTF_CPLUSPLUS23
3791
  if consteval {
3792
    return scalar::utf32_to_latin1::convert_valid(
3793
        detail::constexpr_cast_ptr<uint32_t>(valid_utf32_input.data()),
3794
        valid_utf32_input.size(),
3795
        detail::constexpr_cast_writeptr<char>(latin1_output.data()));
3796
  }
3797
    #endif
3798
  {
3799
    return convert_valid_utf32_to_latin1(
3800
        valid_utf32_input.data(), valid_utf32_input.size(),
3801
        reinterpret_cast<char *>(latin1_output.data()));
3802
  }
3803
}
3804
  #endif // SIMDUTF_SPAN
3805
3806
/**
3807
 * Compute the number of bytes that this UTF-32 string would require in Latin1
3808
 * format.
3809
 *
3810
 * This function does not validate the input. It is acceptable to pass invalid
3811
 * UTF-32 strings but in such cases the result is implementation defined.
3812
 *
3813
 * This function is not BOM-aware.
3814
 *
3815
 * @param length        the length of the string in 4-byte code units (char32_t)
3816
 * @return the number of bytes required to encode the UTF-32 string as Latin1
3817
 */
3818
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t
3819
latin1_length_from_utf32(size_t length) noexcept {
3820
  return length;
3821
}
3822
3823
/**
3824
 * Compute the number of bytes that this Latin1 string would require in UTF-32
3825
 * format.
3826
 *
3827
 * @param length        the length of the string in Latin1 code units (char)
3828
 * @return the length of the string in 4-byte code units (char32_t) required to
3829
 * encode the Latin1 string as UTF-32
3830
 */
3831
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t
3832
0
utf32_length_from_latin1(size_t length) noexcept {
3833
0
  return length;
3834
0
}
3835
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
3836
3837
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
3838
/**
3839
 * Convert possibly broken UTF-32 string into UTF-16BE string.
3840
 *
3841
 * During the conversion also validation of the input string is done.
3842
 * This function is suitable to work with inputs from untrusted sources.
3843
 *
3844
 * This function is not BOM-aware.
3845
 *
3846
 * @param input         the UTF-32 string to convert
3847
 * @param length        the length of the string in 4-byte code units (char32_t)
3848
 * @param utf16_buffer   the pointer to buffer that can hold conversion result
3849
 * @return number of written code units; 0 if input is not a valid UTF-32 string
3850
 */
3851
simdutf_warn_unused size_t convert_utf32_to_utf16be(
3852
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
3853
  #if SIMDUTF_SPAN
3854
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3855
convert_utf32_to_utf16be(std::span<const char32_t> utf32_input,
3856
0
                         std::span<char16_t> utf16_output) noexcept {
3857
0
    #if SIMDUTF_CPLUSPLUS23
3858
0
  if consteval {
3859
0
    return scalar::utf32_to_utf16::convert<endianness::BIG>(
3860
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3861
0
  } else
3862
0
    #endif
3863
0
  {
3864
0
    return convert_utf32_to_utf16be(utf32_input.data(), utf32_input.size(),
3865
0
                                    utf16_output.data());
3866
0
  }
3867
0
}
3868
  #endif // SIMDUTF_SPAN
3869
3870
/**
3871
 * Using native endianness, convert possibly broken UTF-32 string into UTF-16
3872
 * string and stop on error.
3873
 *
3874
 * During the conversion also validation of the input string is done.
3875
 * This function is suitable to work with inputs from untrusted sources.
3876
 *
3877
 * This function is not BOM-aware.
3878
 *
3879
 * @param input         the UTF-32 string to convert
3880
 * @param length        the length of the string in 4-byte code units (char32_t)
3881
 * @param utf16_buffer   the pointer to buffer that can hold conversion result
3882
 * @return a result pair struct (of type simdutf::result containing the two
3883
 * fields error and count) with an error code and either position of the error
3884
 * (in the input in code units) if any, or the number of char16_t written if
3885
 * successful.
3886
 */
3887
simdutf_warn_unused result convert_utf32_to_utf16_with_errors(
3888
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
3889
  #if SIMDUTF_SPAN
3890
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3891
convert_utf32_to_utf16_with_errors(std::span<const char32_t> utf32_input,
3892
0
                                   std::span<char16_t> utf16_output) noexcept {
3893
0
    #if SIMDUTF_CPLUSPLUS23
3894
0
  if consteval {
3895
0
    return scalar::utf32_to_utf16::convert_with_errors<endianness::NATIVE>(
3896
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3897
0
  } else
3898
0
    #endif
3899
0
  {
3900
0
    return convert_utf32_to_utf16_with_errors(
3901
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3902
0
  }
3903
0
}
3904
  #endif // SIMDUTF_SPAN
3905
3906
/**
3907
 * Convert possibly broken UTF-32 string into UTF-16LE string and stop on error.
3908
 *
3909
 * During the conversion also validation of the input string is done.
3910
 * This function is suitable to work with inputs from untrusted sources.
3911
 *
3912
 * This function is not BOM-aware.
3913
 *
3914
 * @param input         the UTF-32 string to convert
3915
 * @param length        the length of the string in 4-byte code units (char32_t)
3916
 * @param utf16_buffer   the pointer to buffer that can hold conversion result
3917
 * @return a result pair struct (of type simdutf::result containing the two
3918
 * fields error and count) with an error code and either position of the error
3919
 * (in the input in code units) if any, or the number of char16_t written if
3920
 * successful.
3921
 */
3922
simdutf_warn_unused result convert_utf32_to_utf16le_with_errors(
3923
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
3924
  #if SIMDUTF_SPAN
3925
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3926
convert_utf32_to_utf16le_with_errors(
3927
    std::span<const char32_t> utf32_input,
3928
0
    std::span<char16_t> utf16_output) noexcept {
3929
0
    #if SIMDUTF_CPLUSPLUS23
3930
0
  if consteval {
3931
0
    return scalar::utf32_to_utf16::convert_with_errors<endianness::LITTLE>(
3932
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3933
0
  } else
3934
0
    #endif
3935
0
  {
3936
0
    return convert_utf32_to_utf16le_with_errors(
3937
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3938
0
  }
3939
0
}
3940
  #endif // SIMDUTF_SPAN
3941
3942
/**
3943
 * Convert possibly broken UTF-32 string into UTF-16BE string and stop on error.
3944
 *
3945
 * During the conversion also validation of the input string is done.
3946
 * This function is suitable to work with inputs from untrusted sources.
3947
 *
3948
 * This function is not BOM-aware.
3949
 *
3950
 * @param input         the UTF-32 string to convert
3951
 * @param length        the length of the string in 4-byte code units (char32_t)
3952
 * @param utf16_buffer   the pointer to buffer that can hold conversion result
3953
 * @return a result pair struct (of type simdutf::result containing the two
3954
 * fields error and count) with an error code and either position of the error
3955
 * (in the input in code units) if any, or the number of char16_t written if
3956
 * successful.
3957
 */
3958
simdutf_warn_unused result convert_utf32_to_utf16be_with_errors(
3959
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
3960
  #if SIMDUTF_SPAN
3961
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
3962
convert_utf32_to_utf16be_with_errors(
3963
    std::span<const char32_t> utf32_input,
3964
0
    std::span<char16_t> utf16_output) noexcept {
3965
0
    #if SIMDUTF_CPLUSPLUS23
3966
0
  if consteval {
3967
0
    return scalar::utf32_to_utf16::convert_with_errors<endianness::BIG>(
3968
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3969
0
  } else
3970
0
    #endif
3971
0
  {
3972
0
    return convert_utf32_to_utf16be_with_errors(
3973
0
        utf32_input.data(), utf32_input.size(), utf16_output.data());
3974
0
  }
3975
0
}
3976
  #endif // SIMDUTF_SPAN
3977
3978
/**
3979
 * Using native endianness, convert valid UTF-32 string into a UTF-16 string.
3980
 *
3981
 * This function assumes that the input string is valid UTF-32.
3982
 *
3983
 * This function is not BOM-aware.
3984
 *
3985
 * @param input         the UTF-32 string to convert
3986
 * @param length        the length of the string in 4-byte code units (char32_t)
3987
 * @param utf16_buffer   the pointer to a buffer that can hold the conversion
3988
 * result
3989
 * @return number of written code units; 0 if conversion is not possible
3990
 */
3991
simdutf_warn_unused size_t convert_valid_utf32_to_utf16(
3992
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
3993
  #if SIMDUTF_SPAN
3994
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
3995
convert_valid_utf32_to_utf16(std::span<const char32_t> valid_utf32_input,
3996
0
                             std::span<char16_t> utf16_output) noexcept {
3997
0
3998
0
    #if SIMDUTF_CPLUSPLUS23
3999
0
  if consteval {
4000
0
    return scalar::utf32_to_utf16::convert_valid<endianness::NATIVE>(
4001
0
        valid_utf32_input.data(), valid_utf32_input.size(),
4002
0
        utf16_output.data());
4003
0
  } else
4004
0
    #endif
4005
0
  {
4006
0
    return convert_valid_utf32_to_utf16(valid_utf32_input.data(),
4007
0
                                        valid_utf32_input.size(),
4008
0
                                        utf16_output.data());
4009
0
  }
4010
0
}
4011
  #endif // SIMDUTF_SPAN
4012
4013
/**
4014
 * Convert valid UTF-32 string into UTF-16LE string.
4015
 *
4016
 * This function assumes that the input string is valid UTF-32.
4017
 *
4018
 * This function is not BOM-aware.
4019
 *
4020
 * @param input         the UTF-32 string to convert
4021
 * @param length        the length of the string in 4-byte code units (char32_t)
4022
 * @param utf16_buffer   the pointer to a buffer that can hold the conversion
4023
 * result
4024
 * @return number of written code units; 0 if conversion is not possible
4025
 */
4026
simdutf_warn_unused size_t convert_valid_utf32_to_utf16le(
4027
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
4028
  #if SIMDUTF_SPAN
4029
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4030
convert_valid_utf32_to_utf16le(std::span<const char32_t> valid_utf32_input,
4031
0
                               std::span<char16_t> utf16_output) noexcept {
4032
0
    #if SIMDUTF_CPLUSPLUS23
4033
0
  if consteval {
4034
0
    return scalar::utf32_to_utf16::convert_valid<endianness::LITTLE>(
4035
0
        valid_utf32_input.data(), valid_utf32_input.size(),
4036
0
        utf16_output.data());
4037
0
  } else
4038
0
    #endif
4039
0
  {
4040
0
    return convert_valid_utf32_to_utf16le(valid_utf32_input.data(),
4041
0
                                          valid_utf32_input.size(),
4042
0
                                          utf16_output.data());
4043
0
  }
4044
0
}
4045
  #endif // SIMDUTF_SPAN
4046
4047
/**
4048
 * Convert valid UTF-32 string into UTF-16BE string.
4049
 *
4050
 * This function assumes that the input string is valid UTF-32.
4051
 *
4052
 * This function is not BOM-aware.
4053
 *
4054
 * @param input         the UTF-32 string to convert
4055
 * @param length        the length of the string in 4-byte code units (char32_t)
4056
 * @param utf16_buffer   the pointer to a buffer that can hold the conversion
4057
 * result
4058
 * @return number of written code units; 0 if conversion is not possible
4059
 */
4060
simdutf_warn_unused size_t convert_valid_utf32_to_utf16be(
4061
    const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept;
4062
  #if SIMDUTF_SPAN
4063
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4064
convert_valid_utf32_to_utf16be(std::span<const char32_t> valid_utf32_input,
4065
0
                               std::span<char16_t> utf16_output) noexcept {
4066
0
    #if SIMDUTF_CPLUSPLUS23
4067
0
  if consteval {
4068
0
    return scalar::utf32_to_utf16::convert_valid<endianness::BIG>(
4069
0
        valid_utf32_input.data(), valid_utf32_input.size(),
4070
0
        utf16_output.data());
4071
0
  } else
4072
0
    #endif
4073
0
  {
4074
0
    return convert_valid_utf32_to_utf16be(valid_utf32_input.data(),
4075
0
                                          valid_utf32_input.size(),
4076
0
                                          utf16_output.data());
4077
0
  }
4078
0
}
4079
  #endif // SIMDUTF_SPAN
4080
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
4081
4082
#if SIMDUTF_FEATURE_UTF16
4083
/**
4084
 * Change the endianness of the input. Can be used to go from UTF-16LE to
4085
 * UTF-16BE or from UTF-16BE to UTF-16LE.
4086
 *
4087
 * This function does not validate the input.
4088
 *
4089
 * This function is not BOM-aware.
4090
 *
4091
 * @param input         the UTF-16 string to process
4092
 * @param length        the length of the string in 2-byte code units (char16_t)
4093
 * @param output        the pointer to a buffer that can hold the conversion
4094
 * result
4095
 */
4096
void change_endianness_utf16(const char16_t *input, size_t length,
4097
                             char16_t *output) noexcept;
4098
  #if SIMDUTF_SPAN
4099
simdutf_really_inline simdutf_constexpr23 void
4100
change_endianness_utf16(std::span<const char16_t> utf16_input,
4101
0
                        std::span<char16_t> utf16_output) noexcept {
4102
0
    #if SIMDUTF_CPLUSPLUS23
4103
0
  if consteval {
4104
0
    return scalar::utf16::change_endianness_utf16(
4105
0
        utf16_input.data(), utf16_input.size(), utf16_output.data());
4106
0
  } else
4107
0
    #endif
4108
0
  {
4109
0
    return change_endianness_utf16(utf16_input.data(), utf16_input.size(),
4110
0
                                   utf16_output.data());
4111
0
  }
4112
0
}
4113
  #endif // SIMDUTF_SPAN
4114
#endif   // SIMDUTF_FEATURE_UTF16
4115
4116
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
4117
/**
4118
 * Compute the number of bytes that this UTF-32 string would require in UTF-8
4119
 * format.
4120
 *
4121
 * This function does not validate the input. It is acceptable to pass invalid
4122
 * UTF-32 strings but in such cases the result is implementation defined.
4123
 *
4124
 * @param input         the UTF-32 string to convert
4125
 * @param length        the length of the string in 4-byte code units (char32_t)
4126
 * @return the number of bytes required to encode the UTF-32 string as UTF-8
4127
 */
4128
simdutf_warn_unused size_t utf8_length_from_utf32(const char32_t *input,
4129
                                                  size_t length) noexcept;
4130
  #if SIMDUTF_SPAN
4131
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4132
0
utf8_length_from_utf32(std::span<const char32_t> valid_utf32_input) noexcept {
4133
0
    #if SIMDUTF_CPLUSPLUS23
4134
0
  if consteval {
4135
0
    return scalar::utf32::utf8_length_from_utf32(valid_utf32_input.data(),
4136
0
                                                 valid_utf32_input.size());
4137
0
  } else
4138
0
    #endif
4139
0
  {
4140
0
    return utf8_length_from_utf32(valid_utf32_input.data(),
4141
0
                                  valid_utf32_input.size());
4142
0
  }
4143
0
}
4144
  #endif // SIMDUTF_SPAN
4145
#endif   // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
4146
4147
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
4148
/**
4149
 * Compute the number of two-byte code units that this UTF-32 string would
4150
 * require in UTF-16 format.
4151
 *
4152
 * This function does not validate the input. It is acceptable to pass invalid
4153
 * UTF-32 strings but in such cases the result is implementation defined.
4154
 *
4155
 * @param input         the UTF-32 string to convert
4156
 * @param length        the length of the string in 4-byte code units (char32_t)
4157
 * @return the number of bytes required to encode the UTF-32 string as UTF-16
4158
 */
4159
simdutf_warn_unused size_t utf16_length_from_utf32(const char32_t *input,
4160
                                                   size_t length) noexcept;
4161
  #if SIMDUTF_SPAN
4162
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4163
0
utf16_length_from_utf32(std::span<const char32_t> valid_utf32_input) noexcept {
4164
0
    #if SIMDUTF_CPLUSPLUS23
4165
0
  if consteval {
4166
0
    return scalar::utf32::utf16_length_from_utf32(valid_utf32_input.data(),
4167
0
                                                  valid_utf32_input.size());
4168
0
  } else
4169
0
    #endif
4170
0
  {
4171
0
    return utf16_length_from_utf32(valid_utf32_input.data(),
4172
0
                                   valid_utf32_input.size());
4173
0
  }
4174
0
}
4175
  #endif // SIMDUTF_SPAN
4176
4177
/**
4178
 * Using native endianness; Compute the number of bytes that this UTF-16
4179
 * string would require in UTF-32 format.
4180
 *
4181
 * This function is equivalent to count_utf16.
4182
 *
4183
 * This function does not validate the input. It is acceptable to pass invalid
4184
 * UTF-16 strings but in such cases the result is implementation defined.
4185
 *
4186
 * This function is not BOM-aware.
4187
 *
4188
 * @param input         the UTF-16 string to convert
4189
 * @param length        the length of the string in 2-byte code units (char16_t)
4190
 * @return the number of bytes required to encode the UTF-16LE string as UTF-32
4191
 */
4192
simdutf_warn_unused size_t utf32_length_from_utf16(const char16_t *input,
4193
                                                   size_t length) noexcept;
4194
  #if SIMDUTF_SPAN
4195
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4196
0
utf32_length_from_utf16(std::span<const char16_t> valid_utf16_input) noexcept {
4197
0
    #if SIMDUTF_CPLUSPLUS23
4198
0
  if consteval {
4199
0
    return scalar::utf16::utf32_length_from_utf16<endianness::NATIVE>(
4200
0
        valid_utf16_input.data(), valid_utf16_input.size());
4201
0
  } else
4202
0
    #endif
4203
0
  {
4204
0
    return utf32_length_from_utf16(valid_utf16_input.data(),
4205
0
                                   valid_utf16_input.size());
4206
0
  }
4207
0
}
4208
  #endif // SIMDUTF_SPAN
4209
4210
/**
4211
 * Compute the number of bytes that this UTF-16LE string would require in UTF-32
4212
 * format.
4213
 *
4214
 * This function is equivalent to count_utf16le.
4215
 *
4216
 * This function does not validate the input. It is acceptable to pass invalid
4217
 * UTF-16 strings but in such cases the result is implementation defined.
4218
 *
4219
 * This function is not BOM-aware.
4220
 *
4221
 * @param input         the UTF-16LE string to convert
4222
 * @param length        the length of the string in 2-byte code units (char16_t)
4223
 * @return the number of bytes required to encode the UTF-16LE string as UTF-32
4224
 */
4225
simdutf_warn_unused size_t utf32_length_from_utf16le(const char16_t *input,
4226
                                                     size_t length) noexcept;
4227
  #if SIMDUTF_SPAN
4228
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4229
utf32_length_from_utf16le(
4230
0
    std::span<const char16_t> valid_utf16_input) noexcept {
4231
0
    #if SIMDUTF_CPLUSPLUS23
4232
0
  if consteval {
4233
0
    return scalar::utf16::utf32_length_from_utf16<endianness::LITTLE>(
4234
0
        valid_utf16_input.data(), valid_utf16_input.size());
4235
0
  } else
4236
0
    #endif
4237
0
  {
4238
0
    return utf32_length_from_utf16le(valid_utf16_input.data(),
4239
0
                                     valid_utf16_input.size());
4240
0
  }
4241
0
}
4242
  #endif // SIMDUTF_SPAN
4243
4244
/**
4245
 * Compute the number of bytes that this UTF-16BE string would require in UTF-32
4246
 * format.
4247
 *
4248
 * This function is equivalent to count_utf16be.
4249
 *
4250
 * This function does not validate the input. It is acceptable to pass invalid
4251
 * UTF-16 strings but in such cases the result is implementation defined.
4252
 *
4253
 * This function is not BOM-aware.
4254
 *
4255
 * @param input         the UTF-16BE string to convert
4256
 * @param length        the length of the string in 2-byte code units (char16_t)
4257
 * @return the number of bytes required to encode the UTF-16BE string as UTF-32
4258
 */
4259
simdutf_warn_unused size_t utf32_length_from_utf16be(const char16_t *input,
4260
                                                     size_t length) noexcept;
4261
  #if SIMDUTF_SPAN
4262
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4263
utf32_length_from_utf16be(
4264
0
    std::span<const char16_t> valid_utf16_input) noexcept {
4265
0
    #if SIMDUTF_CPLUSPLUS23
4266
0
  if consteval {
4267
0
    return scalar::utf16::utf32_length_from_utf16<endianness::BIG>(
4268
0
        valid_utf16_input.data(), valid_utf16_input.size());
4269
0
  } else
4270
0
    #endif
4271
0
  {
4272
0
    return utf32_length_from_utf16be(valid_utf16_input.data(),
4273
0
                                     valid_utf16_input.size());
4274
0
  }
4275
0
}
4276
  #endif // SIMDUTF_SPAN
4277
#endif   // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
4278
4279
#if SIMDUTF_FEATURE_UTF16
4280
/**
4281
 * Count the number of code points (characters) in the string assuming that
4282
 * it is valid.
4283
 *
4284
 * This function assumes that the input string is valid UTF-16 (native
4285
 * endianness). It is acceptable to pass invalid UTF-16 strings but in such
4286
 * cases the result is implementation defined.
4287
 *
4288
 * This function is not BOM-aware.
4289
 *
4290
 * @param input         the UTF-16 string to process
4291
 * @param length        the length of the string in 2-byte code units (char16_t)
4292
 * @return number of code points
4293
 */
4294
simdutf_warn_unused size_t count_utf16(const char16_t *input,
4295
                                       size_t length) noexcept;
4296
  #if SIMDUTF_SPAN
4297
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4298
0
count_utf16(std::span<const char16_t> valid_utf16_input) noexcept {
4299
0
    #if SIMDUTF_CPLUSPLUS23
4300
0
  if consteval {
4301
0
    return scalar::utf16::count_code_points<endianness::NATIVE>(
4302
0
        valid_utf16_input.data(), valid_utf16_input.size());
4303
0
  } else
4304
0
    #endif
4305
0
  {
4306
0
    return count_utf16(valid_utf16_input.data(), valid_utf16_input.size());
4307
0
  }
4308
0
}
4309
  #endif // SIMDUTF_SPAN
4310
4311
/**
4312
 * Count the number of code points (characters) in the string assuming that
4313
 * it is valid.
4314
 *
4315
 * This function assumes that the input string is valid UTF-16LE.
4316
 * It is acceptable to pass invalid UTF-16 strings but in such cases
4317
 * the result is implementation defined.
4318
 *
4319
 * This function is not BOM-aware.
4320
 *
4321
 * @param input         the UTF-16LE string to process
4322
 * @param length        the length of the string in 2-byte code units (char16_t)
4323
 * @return number of code points
4324
 */
4325
simdutf_warn_unused size_t count_utf16le(const char16_t *input,
4326
                                         size_t length) noexcept;
4327
  #if SIMDUTF_SPAN
4328
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4329
0
count_utf16le(std::span<const char16_t> valid_utf16_input) noexcept {
4330
0
    #if SIMDUTF_CPLUSPLUS23
4331
0
  if consteval {
4332
0
    return scalar::utf16::count_code_points<endianness::LITTLE>(
4333
0
        valid_utf16_input.data(), valid_utf16_input.size());
4334
0
  } else
4335
0
    #endif
4336
0
  {
4337
0
    return count_utf16le(valid_utf16_input.data(), valid_utf16_input.size());
4338
0
  }
4339
0
}
4340
  #endif // SIMDUTF_SPAN
4341
4342
/**
4343
 * Count the number of code points (characters) in the string assuming that
4344
 * it is valid.
4345
 *
4346
 * This function assumes that the input string is valid UTF-16BE.
4347
 * It is acceptable to pass invalid UTF-16 strings but in such cases
4348
 * the result is implementation defined.
4349
 *
4350
 * This function is not BOM-aware.
4351
 *
4352
 * @param input         the UTF-16BE string to process
4353
 * @param length        the length of the string in 2-byte code units (char16_t)
4354
 * @return number of code points
4355
 */
4356
simdutf_warn_unused size_t count_utf16be(const char16_t *input,
4357
                                         size_t length) noexcept;
4358
  #if SIMDUTF_SPAN
4359
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4360
0
count_utf16be(std::span<const char16_t> valid_utf16_input) noexcept {
4361
0
    #if SIMDUTF_CPLUSPLUS23
4362
0
  if consteval {
4363
0
    return scalar::utf16::count_code_points<endianness::BIG>(
4364
0
        valid_utf16_input.data(), valid_utf16_input.size());
4365
0
  } else
4366
0
    #endif
4367
0
  {
4368
0
    return count_utf16be(valid_utf16_input.data(), valid_utf16_input.size());
4369
0
  }
4370
0
}
4371
  #endif // SIMDUTF_SPAN
4372
#endif   // SIMDUTF_FEATURE_UTF16
4373
4374
#if SIMDUTF_FEATURE_UTF8
4375
/**
4376
 * Count the number of code points (characters) in the string assuming that
4377
 * it is valid.
4378
 *
4379
 * This function assumes that the input string is valid UTF-8.
4380
 * It is acceptable to pass invalid UTF-8 strings but in such cases
4381
 * the result is implementation defined.
4382
 *
4383
 * @param input         the UTF-8 string to process
4384
 * @param length        the length of the string in bytes
4385
 * @return number of code points
4386
 */
4387
simdutf_warn_unused size_t count_utf8(const char *input,
4388
                                      size_t length) noexcept;
4389
  #if SIMDUTF_SPAN
4390
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf8(
4391
    const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept {
4392
    #if SIMDUTF_CPLUSPLUS23
4393
  if consteval {
4394
    return scalar::utf8::count_code_points(valid_utf8_input.data(),
4395
                                           valid_utf8_input.size());
4396
  } else
4397
    #endif
4398
  {
4399
    return count_utf8(reinterpret_cast<const char *>(valid_utf8_input.data()),
4400
                      valid_utf8_input.size());
4401
  }
4402
}
4403
  #endif // SIMDUTF_SPAN
4404
4405
/**
4406
 * Given a valid UTF-8 string having a possibly truncated last character,
4407
 * this function checks the end of string. If the last character is truncated
4408
 * (or partial), then it returns a shorter length (shorter by 1 to 3 bytes) so
4409
 * that the short UTF-8 strings only contain complete characters. If there is no
4410
 * truncated character, the original length is returned.
4411
 *
4412
 * This function assumes that the input string is valid UTF-8, but possibly
4413
 * truncated.
4414
 *
4415
 * @param input         the UTF-8 string to process
4416
 * @param length        the length of the string in bytes
4417
 * @return the length of the string in bytes, possibly shorter by 1 to 3 bytes
4418
 */
4419
simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length);
4420
  #if SIMDUTF_SPAN
4421
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4422
trim_partial_utf8(
4423
    const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept {
4424
    #if SIMDUTF_CPLUSPLUS23
4425
  if consteval {
4426
    return scalar::utf8::trim_partial_utf8(valid_utf8_input.data(),
4427
                                           valid_utf8_input.size());
4428
  } else
4429
    #endif
4430
  {
4431
    return trim_partial_utf8(
4432
        reinterpret_cast<const char *>(valid_utf8_input.data()),
4433
        valid_utf8_input.size());
4434
  }
4435
}
4436
  #endif // SIMDUTF_SPAN
4437
#endif   // SIMDUTF_FEATURE_UTF8
4438
4439
#if SIMDUTF_FEATURE_UTF16
4440
/**
4441
 * Given a valid UTF-16BE string having a possibly truncated last character,
4442
 * this function checks the end of string. If the last character is truncated
4443
 * (or partial), then it returns a shorter length (shorter by 1 unit) so that
4444
 * the short UTF-16BE strings only contain complete characters. If there is no
4445
 * truncated character, the original length is returned.
4446
 *
4447
 * This function assumes that the input string is valid UTF-16BE, but possibly
4448
 * truncated.
4449
 *
4450
 * @param input         the UTF-16BE string to process
4451
 * @param length        the length of the string in bytes
4452
 * @return the length of the string in bytes, possibly shorter by 1 unit
4453
 */
4454
simdutf_warn_unused size_t trim_partial_utf16be(const char16_t *input,
4455
                                                size_t length);
4456
  #if SIMDUTF_SPAN
4457
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4458
0
trim_partial_utf16be(std::span<const char16_t> valid_utf16_input) noexcept {
4459
0
    #if SIMDUTF_CPLUSPLUS23
4460
0
  if consteval {
4461
0
    return scalar::utf16::trim_partial_utf16<endianness::BIG>(
4462
0
        valid_utf16_input.data(), valid_utf16_input.size());
4463
0
  } else
4464
0
    #endif
4465
0
  {
4466
0
    return trim_partial_utf16be(valid_utf16_input.data(),
4467
0
                                valid_utf16_input.size());
4468
0
  }
4469
0
}
4470
  #endif // SIMDUTF_SPAN
4471
4472
/**
4473
 * Given a valid UTF-16LE string having a possibly truncated last character,
4474
 * this function checks the end of string. If the last character is truncated
4475
 * (or partial), then it returns a shorter length (shorter by 1 unit) so that
4476
 * the short UTF-16LE strings only contain complete characters. If there is no
4477
 * truncated character, the original length is returned.
4478
 *
4479
 * This function assumes that the input string is valid UTF-16LE, but possibly
4480
 * truncated.
4481
 *
4482
 * @param input         the UTF-16LE string to process
4483
 * @param length        the length of the string in bytes
4484
 * @return the length of the string in unit, possibly shorter by 1 unit
4485
 */
4486
simdutf_warn_unused size_t trim_partial_utf16le(const char16_t *input,
4487
                                                size_t length);
4488
  #if SIMDUTF_SPAN
4489
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4490
0
trim_partial_utf16le(std::span<const char16_t> valid_utf16_input) noexcept {
4491
0
    #if SIMDUTF_CPLUSPLUS23
4492
0
  if consteval {
4493
0
    return scalar::utf16::trim_partial_utf16<endianness::LITTLE>(
4494
0
        valid_utf16_input.data(), valid_utf16_input.size());
4495
0
  } else
4496
0
    #endif
4497
0
  {
4498
0
    return trim_partial_utf16le(valid_utf16_input.data(),
4499
0
                                valid_utf16_input.size());
4500
0
  }
4501
0
}
4502
  #endif // SIMDUTF_SPAN
4503
4504
/**
4505
 * Given a valid UTF-16 string having a possibly truncated last character,
4506
 * this function checks the end of string. If the last character is truncated
4507
 * (or partial), then it returns a shorter length (shorter by 1 unit) so that
4508
 * the short UTF-16 strings only contain complete characters. If there is no
4509
 * truncated character, the original length is returned.
4510
 *
4511
 * This function assumes that the input string is valid UTF-16, but possibly
4512
 * truncated. We use the native endianness.
4513
 *
4514
 * @param input         the UTF-16 string to process
4515
 * @param length        the length of the string in bytes
4516
 * @return the length of the string in unit, possibly shorter by 1 unit
4517
 */
4518
simdutf_warn_unused size_t trim_partial_utf16(const char16_t *input,
4519
                                              size_t length);
4520
  #if SIMDUTF_SPAN
4521
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4522
0
trim_partial_utf16(std::span<const char16_t> valid_utf16_input) noexcept {
4523
0
    #if SIMDUTF_CPLUSPLUS23
4524
0
  if consteval {
4525
0
    return scalar::utf16::trim_partial_utf16<endianness::NATIVE>(
4526
0
        valid_utf16_input.data(), valid_utf16_input.size());
4527
0
  } else
4528
0
    #endif
4529
0
  {
4530
0
    return trim_partial_utf16(valid_utf16_input.data(),
4531
0
                              valid_utf16_input.size());
4532
0
  }
4533
0
}
4534
  #endif // SIMDUTF_SPAN
4535
#endif   // SIMDUTF_FEATURE_UTF16
4536
4537
#if SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 ||                         \
4538
    SIMDUTF_FEATURE_DETECT_ENCODING
4539
  #ifndef SIMDUTF_NEED_TRAILING_ZEROES
4540
    #define SIMDUTF_NEED_TRAILING_ZEROES 1
4541
  #endif
4542
#endif // SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 ||
4543
       // SIMDUTF_FEATURE_DETECT_ENCODING
4544
4545
#if SIMDUTF_FEATURE_BASE64
4546
// base64_options are used to specify the base64 encoding options.
4547
// ASCII spaces are ' ', '\t', '\n', '\r', '\f'
4548
// garbage characters are characters that are not part of the base64 alphabet
4549
// nor ASCII spaces.
4550
constexpr uint64_t base64_reverse_padding =
4551
    2; /* modifier for base64_default and base64_url */
4552
enum base64_options : uint64_t {
4553
  base64_default = 0, /* standard base64 format (with padding) */
4554
  base64_url = 1,     /* base64url format (no padding) */
4555
  base64_default_no_padding =
4556
      base64_default |
4557
      base64_reverse_padding, /* standard base64 format without padding */
4558
  base64_url_with_padding =
4559
      base64_url | base64_reverse_padding, /* base64url with padding */
4560
  base64_default_accept_garbage =
4561
      4, /* standard base64 format accepting garbage characters, the input stops
4562
            with the first '=' if any */
4563
  base64_url_accept_garbage =
4564
      5, /* base64url format accepting garbage characters, the input stops with
4565
            the first '=' if any */
4566
  base64_default_or_url =
4567
      8, /* standard/base64url hybrid format (only meaningful for decoding!) */
4568
  base64_default_or_url_accept_garbage =
4569
      12, /* standard/base64url hybrid format accepting garbage characters
4570
             (only meaningful for decoding!), the input stops with the first '='
4571
             if any */
4572
};
4573
4574
// last_chunk_handling_options are used to specify the handling of the last
4575
// chunk in base64 decoding.
4576
// https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
4577
enum last_chunk_handling_options : uint64_t {
4578
  loose = 0,  /* standard base64 format, decode partial final chunk */
4579
  strict = 1, /* error when the last chunk is partial, 2 or 3 chars, and
4580
                 unpadded, or non-zero bit padding */
4581
  stop_before_partial =
4582
      2, /* if the last chunk is partial, ignore it (no error) */
4583
  only_full_chunks =
4584
      3 /* only decode full blocks (4 base64 characters, no padding) */
4585
};
4586
4587
inline simdutf_constexpr23 bool
4588
is_partial(last_chunk_handling_options options) {
4589
  return (options == stop_before_partial) || (options == only_full_chunks);
4590
}
4591
4592
namespace detail {
4593
simdutf_warn_unused const char *find(const char *start, const char *end,
4594
                                     char character) noexcept;
4595
simdutf_warn_unused const char16_t *
4596
find(const char16_t *start, const char16_t *end, char16_t character) noexcept;
4597
} // namespace detail
4598
4599
/**
4600
 * Find the first occurrence of a character in a string. If the character is
4601
 * not found, return a pointer to the end of the string.
4602
 * @param start        the start of the string
4603
 * @param end          the end of the string
4604
 * @param character    the character to find
4605
 * @return a pointer to the first occurrence of the character in the string,
4606
 * or a pointer to the end of the string if the character is not found.
4607
 *
4608
 */
4609
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char *
4610
find(const char *start, const char *end, char character) noexcept {
4611
  #if SIMDUTF_CPLUSPLUS23
4612
  if consteval {
4613
    for (; start != end; ++start)
4614
      if (*start == character)
4615
        return start;
4616
    return end;
4617
  } else
4618
  #endif
4619
  {
4620
    return detail::find(start, end, character);
4621
  }
4622
}
4623
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char16_t *
4624
find(const char16_t *start, const char16_t *end, char16_t character) noexcept {
4625
    // implementation note: this is repeated instead of a template, to ensure
4626
    // the api is still a function and compiles without concepts
4627
  #if SIMDUTF_CPLUSPLUS23
4628
  if consteval {
4629
    for (; start != end; ++start)
4630
      if (*start == character)
4631
        return start;
4632
    return end;
4633
  } else
4634
  #endif
4635
  {
4636
    return detail::find(start, end, character);
4637
  }
4638
}
4639
}
4640
  // We include base64_tables once.
4641
  #include <simdutf/base64_tables.h>
4642
  #include <simdutf/scalar/base64.h>
4643
4644
namespace simdutf {
4645
4646
0
inline std::string_view to_string(base64_options options) {
4647
0
  switch (options) {
4648
0
  case base64_default:
4649
0
    return "base64_default";
4650
0
  case base64_url:
4651
0
    return "base64_url";
4652
0
  case base64_reverse_padding:
4653
0
    return "base64_reverse_padding";
4654
0
  case base64_url_with_padding:
4655
0
    return "base64_url_with_padding";
4656
0
  case base64_default_accept_garbage:
4657
0
    return "base64_default_accept_garbage";
4658
0
  case base64_url_accept_garbage:
4659
0
    return "base64_url_accept_garbage";
4660
0
  case base64_default_or_url:
4661
0
    return "base64_default_or_url";
4662
0
  case base64_default_or_url_accept_garbage:
4663
0
    return "base64_default_or_url_accept_garbage";
4664
0
  }
4665
0
  return "<unknown>";
4666
0
}
4667
4668
0
inline std::string_view to_string(last_chunk_handling_options options) {
4669
0
  switch (options) {
4670
0
  case loose:
4671
0
    return "loose";
4672
0
  case strict:
4673
0
    return "strict";
4674
0
  case stop_before_partial:
4675
0
    return "stop_before_partial";
4676
0
  case only_full_chunks:
4677
0
    return "only_full_chunks";
4678
0
  }
4679
0
  return "<unknown>";
4680
0
}
4681
4682
/**
4683
 * Provide the maximal binary length in bytes given the base64 input.
4684
 * As long as the input does not contain ignorable characters (e.g., ASCII
4685
 * spaces or linefeed characters), the result is exact. In particular, the
4686
 * function checks for padding characters.
4687
 *
4688
 * The function is fast (constant time). It checks up to two characters at
4689
 * the end of the string. The input is not otherwise validated or read.
4690
 *
4691
 * @param input         the base64 input to process
4692
 * @param length        the length of the base64 input in bytes
4693
 * @return maximum number of binary bytes
4694
 */
4695
simdutf_warn_unused size_t
4696
maximal_binary_length_from_base64(const char *input, size_t length) noexcept;
4697
  #if SIMDUTF_SPAN
4698
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4699
maximal_binary_length_from_base64(
4700
    const detail::input_span_of_byte_like auto &input) noexcept {
4701
    #if SIMDUTF_CPLUSPLUS23
4702
  if consteval {
4703
    return scalar::base64::maximal_binary_length_from_base64(
4704
        detail::constexpr_cast_ptr<uint8_t>(input.data()), input.size());
4705
  } else
4706
    #endif
4707
  {
4708
    return maximal_binary_length_from_base64(
4709
        reinterpret_cast<const char *>(input.data()), input.size());
4710
  }
4711
}
4712
  #endif // SIMDUTF_SPAN
4713
4714
/**
4715
 * Provide the maximal binary length in bytes given the base64 input.
4716
 * As long as the input does not contain ignorable characters (e.g., ASCII
4717
 * spaces or linefeed characters), the result is exact. In particular, the
4718
 * function checks for padding characters.
4719
 *
4720
 * The function is fast (constant time). It checks up to two characters at
4721
 * the end of the string. The input is not otherwise validated or read.
4722
 *
4723
 * @param input         the base64 input to process, in ASCII stored as 16-bit
4724
 * units
4725
 * @param length        the length of the base64 input in 16-bit units
4726
 * @return maximal number of binary bytes
4727
 */
4728
simdutf_warn_unused size_t maximal_binary_length_from_base64(
4729
    const char16_t *input, size_t length) noexcept;
4730
  #if SIMDUTF_SPAN
4731
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4732
0
maximal_binary_length_from_base64(std::span<const char16_t> input) noexcept {
4733
0
    #if SIMDUTF_CPLUSPLUS23
4734
0
  if consteval {
4735
0
    return scalar::base64::maximal_binary_length_from_base64(input.data(),
4736
0
                                                             input.size());
4737
0
  } else
4738
0
    #endif
4739
0
  {
4740
0
    return maximal_binary_length_from_base64(input.data(), input.size());
4741
0
  }
4742
0
}
4743
  #endif // SIMDUTF_SPAN
4744
4745
/**
4746
 * Compute the binary length from a base64 input.
4747
 * This function is useful for base64 inputs that may contain ASCII whitespaces
4748
 * (such as line breaks). For such inputs, the result is exact, and for any
4749
 * inputs the result can be used to size the output buffer passed to
4750
 * `base64_to_binary`.
4751
 *
4752
 * The function ignores whitespace and does not require padding characters
4753
 * ('=').
4754
 *
4755
 * @param input         the base64 input to process
4756
 * @param length        the length of the base64 input in bytes
4757
 * @return number of binary bytes
4758
 */
4759
simdutf_warn_unused size_t binary_length_from_base64(const char *input,
4760
                                                     size_t length) noexcept;
4761
  #if SIMDUTF_SPAN
4762
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4763
binary_length_from_base64(
4764
    const detail::input_span_of_byte_like auto &input) noexcept {
4765
    #if SIMDUTF_CPLUSPLUS23
4766
  if consteval {
4767
    return scalar::base64::binary_length_from_base64(input.data(),
4768
                                                     input.size());
4769
  } else
4770
    #endif
4771
  {
4772
    return binary_length_from_base64(
4773
        reinterpret_cast<const char *>(input.data()), input.size());
4774
  }
4775
}
4776
  #endif // SIMDUTF_SPAN
4777
4778
/**
4779
 * Compute the binary length from a base64 input.
4780
 * This function is useful for base64 inputs that may contain ASCII whitespaces
4781
 * (such as line breaks). For such inputs, the result is exact, and for any
4782
 * inputs the result can be used to size the output buffer passed to
4783
 * `base64_to_binary`.
4784
 *
4785
 * The function ignores whitespace and does not require padding characters
4786
 * ('=').
4787
 *
4788
 * @param input         the base64 input to process, in ASCII stored as 16-bit
4789
 * units
4790
 * @param length        the length of the base64 input in 16-bit units
4791
 * @return number of binary bytes
4792
 */
4793
simdutf_warn_unused size_t binary_length_from_base64(const char16_t *input,
4794
                                                     size_t length) noexcept;
4795
  #if SIMDUTF_SPAN
4796
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4797
0
binary_length_from_base64(std::span<const char16_t> input) noexcept {
4798
0
    #if SIMDUTF_CPLUSPLUS23
4799
0
  if consteval {
4800
0
    return scalar::base64::binary_length_from_base64(input.data(),
4801
0
                                                     input.size());
4802
0
  } else
4803
0
    #endif
4804
0
  {
4805
0
    return binary_length_from_base64(input.data(), input.size());
4806
0
  }
4807
0
}
4808
  #endif // SIMDUTF_SPAN
4809
4810
/**
4811
 * Convert a base64 input to a binary output.
4812
 *
4813
 * This function follows the WHATWG forgiving-base64 format, which means that it
4814
 * will ignore any ASCII spaces in the input. You may provide a padded input
4815
 * (with one or two equal signs at the end) or an unpadded input (without any
4816
 * equal signs at the end).
4817
 *
4818
 * See https://infra.spec.whatwg.org/#forgiving-base64-decode
4819
 *
4820
 * This function will fail in case of invalid input. When last_chunk_options =
4821
 * loose, there are two possible reasons for failure: the input contains a
4822
 * number of base64 characters that when divided by 4, leaves a single remainder
4823
 * character (BASE64_INPUT_REMAINDER), or the input contains a character that is
4824
 * not a valid base64 character (INVALID_BASE64_CHARACTER).
4825
 *
4826
 * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the
4827
 * input where the invalid character was found. When the error is
4828
 * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded.
4829
 *
4830
 * The default option (simdutf::base64_default) expects the characters `+` and
4831
 * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the
4832
 * characters `-` and `_` as part of its alphabet.
4833
 *
4834
 * The padding (`=`) is validated if present. There may be at most two padding
4835
 * characters at the end of the input. If there are any padding characters, the
4836
 * total number of characters (excluding spaces but including padding
4837
 * characters) must be divisible by four.
4838
 *
4839
 * You should call this function with a buffer that is at least
4840
 * maximal_binary_length_from_base64(input, length) bytes long. If you fail to
4841
 * provide that much space, the function may cause a buffer overflow.
4842
 *
4843
 * Advanced users may want to tailor how the last chunk is handled. By default,
4844
 * we use a loose (forgiving) approach but we also support a strict approach
4845
 * as well as a stop_before_partial approach, as per the following proposal:
4846
 *
4847
 * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
4848
 *
4849
 * @param input         the base64 string to process
4850
 * @param length        the length of the string in bytes
4851
 * @param output        the pointer to a buffer that can hold the conversion
4852
 * result (should be at least maximal_binary_length_from_base64(input, length)
4853
 * bytes long).
4854
 * @param options       the base64 options to use, usually base64_default or
4855
 * base64_url, and base64_default by default.
4856
 * @param last_chunk_options the last chunk handling options,
4857
 * last_chunk_handling_options::loose by default
4858
 * but can also be last_chunk_handling_options::strict or
4859
 * last_chunk_handling_options::stop_before_partial.
4860
 * @return a result pair struct (of type simdutf::result containing the two
4861
 * fields error and count) with an error code and either position of the error
4862
 * (in the input in bytes) if any, or the number of bytes written if successful.
4863
 */
4864
simdutf_warn_unused result base64_to_binary(
4865
    const char *input, size_t length, char *output,
4866
    base64_options options = base64_default,
4867
    last_chunk_handling_options last_chunk_options = loose) noexcept;
4868
  #if SIMDUTF_SPAN
4869
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
4870
base64_to_binary(
4871
    const detail::input_span_of_byte_like auto &input,
4872
    detail::output_span_of_byte_like auto &&binary_output,
4873
    base64_options options = base64_default,
4874
    last_chunk_handling_options last_chunk_options = loose) noexcept {
4875
    #if SIMDUTF_CPLUSPLUS23
4876
  if consteval {
4877
    return scalar::base64::base64_to_binary_details_impl(
4878
        input.data(), input.size(), binary_output.data(), options,
4879
        last_chunk_options);
4880
  } else
4881
    #endif
4882
  {
4883
    return base64_to_binary(reinterpret_cast<const char *>(input.data()),
4884
                            input.size(),
4885
                            reinterpret_cast<char *>(binary_output.data()),
4886
                            options, last_chunk_options);
4887
  }
4888
}
4889
  #endif // SIMDUTF_SPAN
4890
4891
/**
4892
 * Provide the base64 length in bytes given the length of a binary input.
4893
 *
4894
 * @param length        the length of the input in bytes
4895
 * @param options       the base64 options to use (default: base64_default)
4896
 * @return number of base64 bytes
4897
 */
4898
inline simdutf_warn_unused simdutf_constexpr23 size_t base64_length_from_binary(
4899
    size_t length, base64_options options = base64_default) noexcept {
4900
  return scalar::base64::base64_length_from_binary(length, options);
4901
}
4902
4903
/**
4904
 * Provide the base64 length in bytes given the length of a binary input,
4905
 * taking into account line breaks.
4906
 *
4907
 * @param length        the length of the input in bytes
4908
 * @param options       the base64 options to use (default: base64_default)
4909
 * @param line_length   the length of lines, must be at least 4 (otherwise it is
4910
 * interpreted as 4),
4911
 * @return number of base64 bytes
4912
 */
4913
inline simdutf_warn_unused simdutf_constexpr23 size_t
4914
base64_length_from_binary_with_lines(
4915
    size_t length, base64_options options = base64_default,
4916
    size_t line_length = default_line_length) noexcept {
4917
  return scalar::base64::base64_length_from_binary_with_lines(length, options,
4918
                                                              line_length);
4919
}
4920
4921
/**
4922
 * Convert a binary input to a base64 output.
4923
 *
4924
 * The default option (simdutf::base64_default) uses the characters `+` and `/`
4925
 * as part of its alphabet. Further, it adds padding (`=`) at the end of the
4926
 * output to ensure that the output length is a multiple of four.
4927
 *
4928
 * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part
4929
 * of its alphabet. No padding is added at the end of the output.
4930
 *
4931
 * This function always succeeds.
4932
 *
4933
 * @param input         the binary to process
4934
 * @param length        the length of the input in bytes
4935
 * @param output        the pointer to a buffer that can hold the conversion
4936
 * result (should be at least base64_length_from_binary(length) bytes long)
4937
 * @param options       the base64 options to use, can be base64_default or
4938
 * base64_url, is base64_default by default.
4939
 * @return number of written bytes, will be equal to
4940
 * base64_length_from_binary(length, options)
4941
 */
4942
size_t binary_to_base64(const char *input, size_t length, char *output,
4943
                        base64_options options = base64_default) noexcept;
4944
  #if SIMDUTF_SPAN
4945
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4946
binary_to_base64(const detail::input_span_of_byte_like auto &input,
4947
                 detail::output_span_of_byte_like auto &&binary_output,
4948
                 base64_options options = base64_default) noexcept {
4949
    #if SIMDUTF_CPLUSPLUS23
4950
  if consteval {
4951
    return scalar::base64::tail_encode_base64(
4952
        binary_output.data(), input.data(), input.size(), options);
4953
  } else
4954
    #endif
4955
  {
4956
    return binary_to_base64(
4957
        reinterpret_cast<const char *>(input.data()), input.size(),
4958
        reinterpret_cast<char *>(binary_output.data()), options);
4959
  }
4960
}
4961
  #endif // SIMDUTF_SPAN
4962
4963
/**
4964
 * Convert a binary input to a base64 output with line breaks.
4965
 *
4966
 * The default option (simdutf::base64_default) uses the characters `+` and `/`
4967
 * as part of its alphabet. Further, it adds padding (`=`) at the end of the
4968
 * output to ensure that the output length is a multiple of four.
4969
 *
4970
 * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part
4971
 * of its alphabet. No padding is added at the end of the output.
4972
 *
4973
 * This function always succeeds.
4974
 *
4975
 * @param input         the binary to process
4976
 * @param length        the length of the input in bytes
4977
 * @param output        the pointer to a buffer that can hold the conversion
4978
 * result (should be at least base64_length_from_binary_with_lines(length,
4979
 * options, line_length) bytes long)
4980
 * @param line_length   the length of lines, must be at least 4 (otherwise it is
4981
 * interpreted as 4),
4982
 * @param options       the base64 options to use, can be base64_default or
4983
 * base64_url, is base64_default by default.
4984
 * @return number of written bytes, will be equal to
4985
 * base64_length_from_binary_with_lines(length, options)
4986
 */
4987
size_t
4988
binary_to_base64_with_lines(const char *input, size_t length, char *output,
4989
                            size_t line_length = simdutf::default_line_length,
4990
                            base64_options options = base64_default) noexcept;
4991
  #if SIMDUTF_SPAN
4992
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t
4993
binary_to_base64_with_lines(
4994
    const detail::input_span_of_byte_like auto &input,
4995
    detail::output_span_of_byte_like auto &&binary_output,
4996
    size_t line_length = simdutf::default_line_length,
4997
    base64_options options = base64_default) noexcept {
4998
    #if SIMDUTF_CPLUSPLUS23
4999
  if consteval {
5000
    return scalar::base64::tail_encode_base64_impl<true>(
5001
        binary_output.data(), input.data(), input.size(), options, line_length);
5002
  } else
5003
    #endif
5004
  {
5005
    return binary_to_base64_with_lines(
5006
        reinterpret_cast<const char *>(input.data()), input.size(),
5007
        reinterpret_cast<char *>(binary_output.data()), line_length, options);
5008
  }
5009
}
5010
  #endif // SIMDUTF_SPAN
5011
5012
  #if SIMDUTF_ATOMIC_REF
5013
/**
5014
 * Convert a binary input to a base64 output, using atomic accesses.
5015
 * This function comes with a potentially significant performance
5016
 * penalty, but it may be useful in some cases where the input
5017
 * buffers are shared between threads, to avoid undefined
5018
 * behavior in case of data races.
5019
 *
5020
 * The function is for advanced users. Its main use case is when
5021
 * to silence sanitizer warnings. We have no documented use case
5022
 * where this function is actually necessary in terms of practical correctness.
5023
 *
5024
 * This function is only available when simdutf is compiled with
5025
 * C++20 support and __cpp_lib_atomic_ref >= 201806L. You may check
5026
 * the availability of this function by checking the macro
5027
 * SIMDUTF_ATOMIC_REF.
5028
 *
5029
 * The default option (simdutf::base64_default) uses the characters `+` and `/`
5030
 * as part of its alphabet. Further, it adds padding (`=`) at the end of the
5031
 * output to ensure that the output length is a multiple of four.
5032
 *
5033
 * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part
5034
 * of its alphabet. No padding is added at the end of the output.
5035
 *
5036
 * This function always succeeds.
5037
 *
5038
 * This function is considered experimental. It is not tested by default
5039
 * (see the CMake option SIMDUTF_ATOMIC_BASE64_TESTS) nor is it fuzz tested.
5040
 * It is not documented in the public API documentation (README). It is
5041
 * offered on a best effort basis. We rely on the community for further
5042
 * testing and feedback.
5043
 *
5044
 * @brief atomic_binary_to_base64
5045
 * @param input         the binary to process
5046
 * @param length        the length of the input in bytes
5047
 * @param output        the pointer to a buffer that can hold the conversion
5048
 * result (should be at least base64_length_from_binary(length) bytes long)
5049
 * @param options       the base64 options to use, can be base64_default or
5050
 * base64_url, is base64_default by default.
5051
 * @return number of written bytes, will be equal to
5052
 * base64_length_from_binary(length, options)
5053
 */
5054
size_t
5055
atomic_binary_to_base64(const char *input, size_t length, char *output,
5056
                        base64_options options = base64_default) noexcept;
5057
    #if SIMDUTF_SPAN
5058
simdutf_really_inline simdutf_warn_unused size_t
5059
atomic_binary_to_base64(const detail::input_span_of_byte_like auto &input,
5060
                        detail::output_span_of_byte_like auto &&binary_output,
5061
                        base64_options options = base64_default) noexcept {
5062
  return atomic_binary_to_base64(
5063
      reinterpret_cast<const char *>(input.data()), input.size(),
5064
      reinterpret_cast<char *>(binary_output.data()), options);
5065
}
5066
    #endif // SIMDUTF_SPAN
5067
  #endif   // SIMDUTF_ATOMIC_REF
5068
5069
/**
5070
 * Convert a base64 input to a binary output.
5071
 *
5072
 * This function follows the WHATWG forgiving-base64 format, which means that it
5073
 * will ignore any ASCII spaces in the input. You may provide a padded input
5074
 * (with one or two equal signs at the end) or an unpadded input (without any
5075
 * equal signs at the end).
5076
 *
5077
 * See https://infra.spec.whatwg.org/#forgiving-base64-decode
5078
 *
5079
 * This function will fail in case of invalid input. When last_chunk_options =
5080
 * loose, there are two possible reasons for failure: the input contains a
5081
 * number of base64 characters that when divided by 4, leaves a single remainder
5082
 * character (BASE64_INPUT_REMAINDER), or the input contains a character that is
5083
 * not a valid base64 character (INVALID_BASE64_CHARACTER).
5084
 *
5085
 * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the
5086
 * input where the invalid character was found. When the error is
5087
 * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded.
5088
 *
5089
 * The default option (simdutf::base64_default) expects the characters `+` and
5090
 * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the
5091
 * characters `-` and `_` as part of its alphabet.
5092
 *
5093
 * The padding (`=`) is validated if present. There may be at most two padding
5094
 * characters at the end of the input. If there are any padding characters, the
5095
 * total number of characters (excluding spaces but including padding
5096
 * characters) must be divisible by four.
5097
 *
5098
 * You should call this function with a buffer that is at least
5099
 * maximal_binary_length_from_base64(input, length) bytes long. If you fail
5100
 * to provide that much space, the function may cause a buffer overflow.
5101
 *
5102
 * Advanced users may want to tailor how the last chunk is handled. By default,
5103
 * we use a loose (forgiving) approach but we also support a strict approach
5104
 * as well as a stop_before_partial approach, as per the following proposal:
5105
 *
5106
 * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
5107
 *
5108
 * @param input         the base64 string to process, in ASCII stored as 16-bit
5109
 * units
5110
 * @param length        the length of the string in 16-bit units
5111
 * @param output        the pointer to a buffer that can hold the conversion
5112
 * result (should be at least maximal_binary_length_from_base64(input, length)
5113
 * bytes long).
5114
 * @param options       the base64 options to use, can be base64_default or
5115
 * base64_url, is base64_default by default.
5116
 * @param last_chunk_options the last chunk handling options,
5117
 * last_chunk_handling_options::loose by default
5118
 * but can also be last_chunk_handling_options::strict or
5119
 * last_chunk_handling_options::stop_before_partial.
5120
 * @return a result pair struct (of type simdutf::result containing the two
5121
 * fields error and count) with an error code and position of the
5122
 * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number
5123
 * of bytes written if successful.
5124
 */
5125
simdutf_warn_unused result
5126
base64_to_binary(const char16_t *input, size_t length, char *output,
5127
                 base64_options options = base64_default,
5128
                 last_chunk_handling_options last_chunk_options =
5129
                     last_chunk_handling_options::loose) noexcept;
5130
  #if SIMDUTF_SPAN
5131
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result
5132
base64_to_binary(
5133
    std::span<const char16_t> input,
5134
    detail::output_span_of_byte_like auto &&binary_output,
5135
    base64_options options = base64_default,
5136
    last_chunk_handling_options last_chunk_options = loose) noexcept {
5137
    #if SIMDUTF_CPLUSPLUS23
5138
  if consteval {
5139
    return scalar::base64::base64_to_binary_details_impl(
5140
        input.data(), input.size(), binary_output.data(), options,
5141
        last_chunk_options);
5142
  } else
5143
    #endif
5144
  {
5145
    return base64_to_binary(input.data(), input.size(),
5146
                            reinterpret_cast<char *>(binary_output.data()),
5147
                            options, last_chunk_options);
5148
  }
5149
}
5150
  #endif // SIMDUTF_SPAN
5151
5152
/**
5153
 * Convert a base64 input to a binary output while returning more details
5154
 * than base64_to_binary.
5155
 *
5156
 * This function follows the WHATWG forgiving-base64 format, which means that it
5157
 * will ignore any ASCII spaces in the input. You may provide a padded input
5158
 * (with one or two equal signs at the end) or an unpadded input (without any
5159
 * equal signs at the end).
5160
 *
5161
 * See https://infra.spec.whatwg.org/#forgiving-base64-decode
5162
 *
5163
 * Unlike base64_to_binary, this function returns a full_result with both
5164
 * input_count and output_count, so you always know how much input was consumed
5165
 * and how much output was written. There are three cases where the input may
5166
 * not be fully consumed:
5167
 *
5168
 * 1. stop_before_partial: When last_chunk_options is set to
5169
 *    stop_before_partial, any incomplete 4-character group at the end of the
5170
 *    input is left unconsumed. This is useful for streaming/chunked decoding
5171
 *    where you can carry over the unconsumed input to the next chunk.
5172
 *
5173
 * 2. INVALID_BASE64_CHARACTER: The input contains a character that is not a
5174
 *    valid base64 character. In this case, input_count indicates where the
5175
 *    invalid character was found.
5176
 *
5177
 * 3. BASE64_INPUT_REMAINDER: When last_chunk_options is loose, the input
5178
 *    contains a number of base64 characters that, when divided by 4, leaves
5179
 *    a single remainder character (which cannot encode any bytes).
5180
 *
5181
 * You should call this function with a buffer that is at least
5182
 * maximal_binary_length_from_base64(input, length) bytes long. If you fail to
5183
 * provide that much space, the function may cause a buffer overflow.
5184
 *
5185
 * @param input         the base64 string to process
5186
 * @param length        the length of the string in bytes
5187
 * @param output        the pointer to a buffer that can hold the conversion
5188
 * result (should be at least maximal_binary_length_from_base64(input, length)
5189
 * bytes long).
5190
 * @param options       the base64 options to use, can be base64_default or
5191
 * base64_url, is base64_default by default.
5192
 * @param last_chunk_options the last chunk handling options,
5193
 * last_chunk_handling_options::loose by default
5194
 * but can also be last_chunk_handling_options::strict or
5195
 * last_chunk_handling_options::stop_before_partial.
5196
 * @return a full_result struct (of type simdutf::full_result containing the
5197
 * three fields error, input_count and output_count).
5198
 */
5199
simdutf_warn_unused full_result
5200
base64_to_binary_details(const char *input, size_t length, char *output,
5201
                         base64_options options = base64_default,
5202
                         last_chunk_handling_options last_chunk_options =
5203
                             last_chunk_handling_options::loose) noexcept;
5204
  #if SIMDUTF_SPAN
5205
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result
5206
base64_to_binary_details(
5207
    const detail::input_span_of_byte_like auto &input,
5208
    detail::output_span_of_byte_like auto &&binary_output,
5209
    base64_options options = base64_default,
5210
    last_chunk_handling_options last_chunk_options = loose) noexcept {
5211
    #if SIMDUTF_CPLUSPLUS23
5212
  if consteval {
5213
    return scalar::base64::base64_to_binary_details_impl(
5214
        input.data(), input.size(), binary_output.data(), options,
5215
        last_chunk_options);
5216
  } else
5217
    #endif
5218
  {
5219
    return base64_to_binary_details(
5220
        reinterpret_cast<const char *>(input.data()), input.size(),
5221
        reinterpret_cast<char *>(binary_output.data()), options,
5222
        last_chunk_options);
5223
  }
5224
}
5225
  #endif // SIMDUTF_SPAN
5226
5227
/**
5228
 * Convert a base64 input to a binary output while returning more details
5229
 * than base64_to_binary.
5230
 *
5231
 * This function follows the WHATWG forgiving-base64 format, which means that it
5232
 * will ignore any ASCII spaces in the input. You may provide a padded input
5233
 * (with one or two equal signs at the end) or an unpadded input (without any
5234
 * equal signs at the end).
5235
 *
5236
 * See https://infra.spec.whatwg.org/#forgiving-base64-decode
5237
 *
5238
 * Unlike base64_to_binary, this function returns a full_result with both
5239
 * input_count and output_count, so you always know how much input was consumed
5240
 * and how much output was written. There are three cases where the input may
5241
 * not be fully consumed:
5242
 *
5243
 * 1. stop_before_partial: When last_chunk_options is set to
5244
 *    stop_before_partial, any incomplete 4-character group at the end of the
5245
 *    input is left unconsumed. This is useful for streaming/chunked decoding
5246
 *    where you can carry over the unconsumed input to the next chunk.
5247
 *
5248
 * 2. INVALID_BASE64_CHARACTER: The input contains a character that is not a
5249
 *    valid base64 character. In this case, input_count indicates where the
5250
 *    invalid character was found.
5251
 *
5252
 * 3. BASE64_INPUT_REMAINDER: When last_chunk_options is loose, the input
5253
 *    contains a number of base64 characters that, when divided by 4, leaves
5254
 *    a single remainder character (which cannot encode any bytes).
5255
 *
5256
 * You should call this function with a buffer that is at least
5257
 * maximal_binary_length_from_base64(input, length) bytes long. If you fail to
5258
 * provide that much space, the function may cause a buffer overflow.
5259
 *
5260
 * @param input         the base64 string to process, in ASCII stored as 16-bit
5261
 * units
5262
 * @param length        the length of the string in 16-bit units
5263
 * @param output        the pointer to a buffer that can hold the conversion
5264
 * result (should be at least maximal_binary_length_from_base64(input, length)
5265
 * bytes long).
5266
 * @param options       the base64 options to use, can be base64_default or
5267
 * base64_url, is base64_default by default.
5268
 * @param last_chunk_options the last chunk handling options,
5269
 * last_chunk_handling_options::loose by default
5270
 * but can also be last_chunk_handling_options::strict or
5271
 * last_chunk_handling_options::stop_before_partial.
5272
 * @return a full_result struct (of type simdutf::full_result containing the
5273
 * three fields error, input_count and output_count).
5274
 */
5275
simdutf_warn_unused full_result
5276
base64_to_binary_details(const char16_t *input, size_t length, char *output,
5277
                         base64_options options = base64_default,
5278
                         last_chunk_handling_options last_chunk_options =
5279
                             last_chunk_handling_options::loose) noexcept;
5280
  #if SIMDUTF_SPAN
5281
simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result
5282
base64_to_binary_details(
5283
    std::span<const char16_t> input,
5284
    detail::output_span_of_byte_like auto &&binary_output,
5285
    base64_options options = base64_default,
5286
    last_chunk_handling_options last_chunk_options = loose) noexcept {
5287
    #if SIMDUTF_CPLUSPLUS23
5288
  if consteval {
5289
    return scalar::base64::base64_to_binary_details_impl(
5290
        input.data(), input.size(), binary_output.data(), options,
5291
        last_chunk_options);
5292
  } else
5293
    #endif
5294
  {
5295
    return base64_to_binary_details(
5296
        input.data(), input.size(),
5297
        reinterpret_cast<char *>(binary_output.data()), options,
5298
        last_chunk_options);
5299
  }
5300
}
5301
  #endif // SIMDUTF_SPAN
5302
5303
/**
5304
 * Check if a character is an ignorable base64 character.
5305
 * Checking a large input, character by character, is not computationally
5306
 * efficient.
5307
 *
5308
 * @param input         the character to check
5309
 * @param options       the base64 options to use, is base64_default by default.
5310
 * @return true if the character is an ignorable base64 character, false
5311
 * otherwise.
5312
 */
5313
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool
5314
base64_ignorable(char input, base64_options options = base64_default) noexcept {
5315
  return scalar::base64::is_ignorable(input, options);
5316
}
5317
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool
5318
base64_ignorable(char16_t input,
5319
                 base64_options options = base64_default) noexcept {
5320
  return scalar::base64::is_ignorable(input, options);
5321
}
5322
5323
/**
5324
 * Check if a character is a valid base64 character.
5325
 * Checking a large input, character by character, is not computationally
5326
 * efficient.
5327
 * Note that padding characters are not considered valid base64 characters in
5328
 * this context, nor are spaces.
5329
 *
5330
 * @param input         the character to check
5331
 * @param options       the base64 options to use, is base64_default by default.
5332
 * @return true if the character is a base64 character, false otherwise.
5333
 */
5334
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool
5335
base64_valid(char input, base64_options options = base64_default) noexcept {
5336
  return scalar::base64::is_base64(input, options);
5337
}
5338
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool
5339
base64_valid(char16_t input, base64_options options = base64_default) noexcept {
5340
  return scalar::base64::is_base64(input, options);
5341
}
5342
5343
/**
5344
 * Check if a character is a valid base64 character or the padding character
5345
 * ('='). Checking a large input, character by character, is not computationally
5346
 * efficient.
5347
 *
5348
 * @param input         the character to check
5349
 * @param options       the base64 options to use, is base64_default by default.
5350
 * @return true if the character is a base64 character, false otherwise.
5351
 */
5352
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool
5353
base64_valid_or_padding(char input,
5354
0
                        base64_options options = base64_default) noexcept {
5355
0
  return scalar::base64::is_base64_or_padding(input, options);
5356
0
}
5357
simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool
5358
base64_valid_or_padding(char16_t input,
5359
0
                        base64_options options = base64_default) noexcept {
5360
0
  return scalar::base64::is_base64_or_padding(input, options);
5361
0
}
5362
5363
/**
5364
 * Convert a base64 input to a binary output.
5365
 *
5366
 * This function follows the WHATWG forgiving-base64 format, which means that it
5367
 * will ignore any ASCII spaces in the input. You may provide a padded input
5368
 * (with one or two equal signs at the end) or an unpadded input (without any
5369
 * equal signs at the end).
5370
 *
5371
 * See https://infra.spec.whatwg.org/#forgiving-base64-decode
5372
 *
5373
 * This function will fail in case of invalid input. When last_chunk_options =
5374
 * loose, there are three possible reasons for failure: the input contains a
5375
 * number of base64 characters that when divided by 4, leaves a single remainder
5376
 * character (BASE64_INPUT_REMAINDER), the input contains a character that is
5377
 * not a valid base64 character (INVALID_BASE64_CHARACTER), or the output buffer
5378
 * is too small (OUTPUT_BUFFER_TOO_SMALL).
5379
 *
5380
 * When OUTPUT_BUFFER_TOO_SMALL, we return both the number of bytes written
5381
 * and the number of units processed, see description of the parameters and
5382
 * returned value.
5383
 *
5384
 * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the
5385
 * input where the invalid character was found. When the error is
5386
 * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded.
5387
 *
5388
 * The default option (simdutf::base64_default) expects the characters `+` and
5389
 * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the
5390
 * characters `-` and `_` as part of its alphabet.
5391
 *
5392
 * The padding (`=`) is validated if present. There may be at most two padding
5393
 * characters at the end of the input. If there are any padding characters, the
5394
 * total number of characters (excluding spaces but including padding
5395
 * characters) must be divisible by four.
5396
 *
5397
 * The INVALID_BASE64_CHARACTER cases are considered fatal and you are expected
5398
 * to discard the output unless the parameter decode_up_to_bad_char is set to
5399
 * true. In that case, the function will decode up to the first invalid
5400
 * character. Extra padding characters ('=') are considered invalid characters.
5401
 *
5402
 * Advanced users may want to tailor how the last chunk is handled. By default,
5403
 * we use a loose (forgiving) approach but we also support a strict approach
5404
 * as well as a stop_before_partial approach, as per the following proposal:
5405
 *
5406
 * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
5407
 *
5408
 * The base64_to_binary_safe function has negligible overhead compared with
5409
 * base64_to_binary in the absence of ignorable characters; however, on short
5410
 * inputs containing ignorable characters, it can be up to three times slower.
5411
 *
5412
 * @param input         the base64 string to process, in ASCII stored as 8-bit
5413
 * or 16-bit units
5414
 * @param length        the length of the string in 8-bit or 16-bit units.
5415
 * @param output        the pointer to a buffer that can hold the conversion
5416
 * result.
5417
 * @param outlen        the number of bytes that can be written in the output
5418
 * buffer. Upon return, it is modified to reflect how many bytes were written.
5419
 * @param options       the base64 options to use, can be base64_default or
5420
 * base64_url, is base64_default by default.
5421
 * @param last_chunk_options the last chunk handling options,
5422
 * last_chunk_handling_options::loose by default
5423
 * but can also be last_chunk_handling_options::strict or
5424
 * last_chunk_handling_options::stop_before_partial.
5425
 * @param decode_up_to_bad_char if true, the function will decode up to the
5426
 * first invalid character. By default (false), it is assumed that the output
5427
 * buffer is to be discarded. When there are multiple errors in the input,
5428
 * using decode_up_to_bad_char might trigger a different error.
5429
 * @return a result pair struct (of type simdutf::result containing the two
5430
 * fields error and count) with an error code and position of the
5431
 * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number
5432
 * of units processed if successful.
5433
 */
5434
simdutf_warn_unused result
5435
base64_to_binary_safe(const char *input, size_t length, char *output,
5436
                      size_t &outlen, base64_options options = base64_default,
5437
                      last_chunk_handling_options last_chunk_options =
5438
                          last_chunk_handling_options::loose,
5439
                      bool decode_up_to_bad_char = false) noexcept;
5440
// the span overload has moved to the bottom of the file
5441
5442
simdutf_warn_unused result
5443
base64_to_binary_safe(const char16_t *input, size_t length, char *output,
5444
                      size_t &outlen, base64_options options = base64_default,
5445
                      last_chunk_handling_options last_chunk_options =
5446
                          last_chunk_handling_options::loose,
5447
                      bool decode_up_to_bad_char = false) noexcept;
5448
  // span overload moved to bottom of file
5449
5450
  #if SIMDUTF_ATOMIC_REF
5451
/**
5452
 * Convert a base64 input to a binary output with a size limit and using atomic
5453
 * operations.
5454
 *
5455
 * Like `base64_to_binary_safe` but using atomic operations, this function is
5456
 * thread-safe for concurrent memory access, allowing the output
5457
 * buffers to be shared between threads without undefined behavior in case of
5458
 * data races.
5459
 *
5460
 * This function comes with a potentially significant performance penalty, but
5461
 * is useful when thread safety is needed during base64 decoding.
5462
 *
5463
 * This function is only available when simdutf is compiled with
5464
 * C++20 support and __cpp_lib_atomic_ref >= 201806L. You may check
5465
 * the availability of this function by checking the macro
5466
 * SIMDUTF_ATOMIC_REF.
5467
 *
5468
 * This function is considered experimental. It is not tested by default
5469
 * (see the CMake option SIMDUTF_ATOMIC_BASE64_TESTS) nor is it fuzz tested.
5470
 * It is not documented in the public API documentation (README). It is
5471
 * offered on a best effort basis. We rely on the community for further
5472
 * testing and feedback.
5473
 *
5474
 * @param input         the base64 input to decode
5475
 * @param length        the length of the input in bytes
5476
 * @param output        the pointer to buffer that can hold the conversion
5477
 * result
5478
 * @param outlen        the number of bytes that can be written in the output
5479
 * buffer. Upon return, it is modified to reflect how many bytes were written.
5480
 * @param options       the base64 options to use (default, url, etc.)
5481
 * @param last_chunk_options the last chunk handling options (loose, strict,
5482
 * stop_before_partial)
5483
 * @param decode_up_to_bad_char if true, the function will decode up to the
5484
 * first invalid character. By default (false), it is assumed that the output
5485
 * buffer is to be discarded. When there are multiple errors in the input,
5486
 * using decode_up_to_bad_char might trigger a different error.
5487
 * @return a result struct with an error code and count indicating error
5488
 * position or success
5489
 */
5490
simdutf_warn_unused result atomic_base64_to_binary_safe(
5491
    const char *input, size_t length, char *output, size_t &outlen,
5492
    base64_options options = base64_default,
5493
    last_chunk_handling_options last_chunk_options =
5494
        last_chunk_handling_options::loose,
5495
    bool decode_up_to_bad_char = false) noexcept;
5496
simdutf_warn_unused result atomic_base64_to_binary_safe(
5497
    const char16_t *input, size_t length, char *output, size_t &outlen,
5498
    base64_options options = base64_default,
5499
    last_chunk_handling_options last_chunk_options = loose,
5500
    bool decode_up_to_bad_char = false) noexcept;
5501
    #if SIMDUTF_SPAN
5502
/**
5503
 * @brief span overload
5504
 * @return a tuple of result and outlen
5505
 */
5506
simdutf_really_inline simdutf_warn_unused std::tuple<result, std::size_t>
5507
atomic_base64_to_binary_safe(
5508
    const detail::input_span_of_byte_like auto &binary_input,
5509
    detail::output_span_of_byte_like auto &&output,
5510
    base64_options options = base64_default,
5511
    last_chunk_handling_options last_chunk_options =
5512
        last_chunk_handling_options::loose,
5513
    bool decode_up_to_bad_char = false) noexcept {
5514
  size_t outlen = output.size();
5515
  auto ret = atomic_base64_to_binary_safe(
5516
      reinterpret_cast<const char *>(binary_input.data()), binary_input.size(),
5517
      reinterpret_cast<char *>(output.data()), outlen, options,
5518
      last_chunk_options, decode_up_to_bad_char);
5519
  return {ret, outlen};
5520
}
5521
/**
5522
 * @brief span overload
5523
 * @return a tuple of result and outlen
5524
 */
5525
simdutf_warn_unused std::tuple<result, std::size_t>
5526
atomic_base64_to_binary_safe(
5527
    std::span<const char16_t> base64_input,
5528
    detail::output_span_of_byte_like auto &&binary_output,
5529
    base64_options options = base64_default,
5530
    last_chunk_handling_options last_chunk_options = loose,
5531
    bool decode_up_to_bad_char = false) noexcept {
5532
  size_t outlen = binary_output.size();
5533
  auto ret = atomic_base64_to_binary_safe(
5534
      base64_input.data(), base64_input.size(),
5535
      reinterpret_cast<char *>(binary_output.data()), outlen, options,
5536
      last_chunk_options, decode_up_to_bad_char);
5537
  return {ret, outlen};
5538
}
5539
    #endif // SIMDUTF_SPAN
5540
  #endif   // SIMDUTF_ATOMIC_REF
5541
5542
#endif // SIMDUTF_FEATURE_BASE64
5543
5544
/**
5545
 * An implementation of simdutf for a particular CPU architecture.
5546
 *
5547
 * Also used to maintain the currently active implementation. The active
5548
 * implementation is automatically initialized on first use to the most advanced
5549
 * implementation supported by the host.
5550
 */
5551
class implementation {
5552
public:
5553
  /**
5554
   * The name of this implementation.
5555
   *
5556
   *     const implementation *impl = simdutf::active_implementation;
5557
   *     cout << "simdutf is optimized for " << impl->name() << "(" <<
5558
   * impl->description() << ")" << endl;
5559
   *
5560
   * @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
5561
   */
5562
  virtual std::string_view name() const noexcept { return _name; }
5563
5564
  /**
5565
   * The description of this implementation.
5566
   *
5567
   *     const implementation *impl = simdutf::active_implementation;
5568
   *     cout << "simdutf is optimized for " << impl->name() << "(" <<
5569
   * impl->description() << ")" << endl;
5570
   *
5571
   * @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
5572
   */
5573
  virtual std::string_view description() const noexcept { return _description; }
5574
5575
  /**
5576
   * The instruction sets this implementation is compiled against
5577
   * and the current CPU match. This function may poll the current CPU/system
5578
   * and should therefore not be called too often if performance is a concern.
5579
   *
5580
   *
5581
   * @return true if the implementation can be safely used on the current system
5582
   * (determined at runtime)
5583
   */
5584
  bool supported_by_runtime_system() const;
5585
5586
#if SIMDUTF_FEATURE_DETECT_ENCODING
5587
  /**
5588
   * This function will try to detect the encoding
5589
   * @param input the string to identify
5590
   * @param length the length of the string in bytes.
5591
   * @return the encoding type detected
5592
   */
5593
  virtual encoding_type autodetect_encoding(const char *input,
5594
                                            size_t length) const noexcept;
5595
5596
  /**
5597
   * This function will try to detect the possible encodings in one pass
5598
   * @param input the string to identify
5599
   * @param length the length of the string in bytes.
5600
   * @return the encoding type detected
5601
   */
5602
  virtual int detect_encodings(const char *input,
5603
                               size_t length) const noexcept = 0;
5604
#endif // SIMDUTF_FEATURE_DETECT_ENCODING
5605
5606
  /**
5607
   * @private For internal implementation use
5608
   *
5609
   * The instruction sets this implementation is compiled against.
5610
   *
5611
   * @return a mask of all required `internal::instruction_set::` values
5612
   */
5613
  virtual uint32_t required_instruction_sets() const {
5614
    return _required_instruction_sets;
5615
  }
5616
5617
#if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
5618
  /**
5619
   * Validate the UTF-8 string.
5620
   *
5621
   * Overridden by each implementation.
5622
   *
5623
   * @param buf the UTF-8 string to validate.
5624
   * @param len the length of the string in bytes.
5625
   * @return true if and only if the string is valid UTF-8.
5626
   */
5627
  simdutf_warn_unused virtual bool validate_utf8(const char *buf,
5628
                                                 size_t len) const noexcept = 0;
5629
#endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING
5630
5631
#if SIMDUTF_FEATURE_UTF8
5632
  /**
5633
   * Validate the UTF-8 string and stop on errors.
5634
   *
5635
   * Overridden by each implementation.
5636
   *
5637
   * @param buf the UTF-8 string to validate.
5638
   * @param len the length of the string in bytes.
5639
   * @return a result pair struct (of type simdutf::result containing the two
5640
   * fields error and count) with an error code and either position of the error
5641
   * (in the input in code units) if any, or the number of code units validated
5642
   * if successful.
5643
   */
5644
  simdutf_warn_unused virtual result
5645
  validate_utf8_with_errors(const char *buf, size_t len) const noexcept = 0;
5646
  /**
5647
   * Finds the pointer to the first byte of invalid utf8 while counting
5648
   continuation bytes and four-byte sequences.
5649
5650
   * @param buf the UTF-8 string to validate.
5651
   * @param len the length of the string in bytes.
5652
   * @return a utf8_result struct. It contains the length of the valid utf8
5653
   segment, the error code and the count of continuation bytes and four-byte
5654
   sequences.
5655
   *
5656
   * Returns a utf8_result
5657
   */
5658
  virtual simdutf_warn_unused utf8_result
5659
  validate_utf8_with_counts(const char *buf, size_t len) const noexcept = 0;
5660
5661
#endif // SIMDUTF_FEATURE_UTF8
5662
5663
#if SIMDUTF_FEATURE_ASCII
5664
  /**
5665
   * Validate the ASCII string.
5666
   *
5667
   * Overridden by each implementation.
5668
   *
5669
   * @param buf the ASCII string to validate.
5670
   * @param len the length of the string in bytes.
5671
   * @return true if and only if the string is valid ASCII.
5672
   */
5673
  simdutf_warn_unused virtual bool
5674
  validate_ascii(const char *buf, size_t len) const noexcept = 0;
5675
5676
  /**
5677
   * Validate the ASCII string and stop on error.
5678
   *
5679
   * Overridden by each implementation.
5680
   *
5681
   * @param buf the ASCII string to validate.
5682
   * @param len the length of the string in bytes.
5683
   * @return a result pair struct (of type simdutf::result containing the two
5684
   * fields error and count) with an error code and either position of the error
5685
   * (in the input in code units) if any, or the number of code units validated
5686
   * if successful.
5687
   */
5688
  simdutf_warn_unused virtual result
5689
  validate_ascii_with_errors(const char *buf, size_t len) const noexcept = 0;
5690
5691
#endif // SIMDUTF_FEATURE_ASCII
5692
5693
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII
5694
  /**
5695
   * Validate the ASCII string as a UTF-16BE sequence.
5696
   * An UTF-16 sequence is considered an ASCII sequence
5697
   * if it could be converted to an ASCII string losslessly.
5698
   *
5699
   * Overridden by each implementation.
5700
   *
5701
   * @param buf the UTF-16BE string to validate.
5702
   * @param len the length of the string in bytes.
5703
   * @return true if and only if the string is valid ASCII.
5704
   */
5705
  simdutf_warn_unused virtual bool
5706
  validate_utf16be_as_ascii(const char16_t *buf, size_t len) const noexcept = 0;
5707
5708
  /**
5709
   * Validate the ASCII string as a UTF-16LE sequence.
5710
   * An UTF-16 sequence is considered an ASCII sequence
5711
   * if it could be converted to an ASCII string losslessly.
5712
   *
5713
   * Overridden by each implementation.
5714
   *
5715
   * @param buf the UTF-16LE string to validate.
5716
   * @param len the length of the string in bytes.
5717
   * @return true if and only if the string is valid ASCII.
5718
   */
5719
  simdutf_warn_unused virtual bool
5720
  validate_utf16le_as_ascii(const char16_t *buf, size_t len) const noexcept = 0;
5721
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII
5722
5723
#if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
5724
  /**
5725
   * Validate the UTF-16LE string.This function may be best when you expect
5726
   * the input to be almost always valid. Otherwise, consider using
5727
   * validate_utf16le_with_errors.
5728
   *
5729
   * Overridden by each implementation.
5730
   *
5731
   * This function is not BOM-aware.
5732
   *
5733
   * @param buf the UTF-16LE string to validate.
5734
   * @param len the length of the string in number of 2-byte code units
5735
   * (char16_t).
5736
   * @return true if and only if the string is valid UTF-16LE.
5737
   */
5738
  simdutf_warn_unused virtual bool
5739
  validate_utf16le(const char16_t *buf, size_t len) const noexcept = 0;
5740
#endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING
5741
5742
#if SIMDUTF_FEATURE_UTF16
5743
  /**
5744
   * Validate the UTF-16BE string. This function may be best when you expect
5745
   * the input to be almost always valid. Otherwise, consider using
5746
   * validate_utf16be_with_errors.
5747
   *
5748
   * Overridden by each implementation.
5749
   *
5750
   * This function is not BOM-aware.
5751
   *
5752
   * @param buf the UTF-16BE string to validate.
5753
   * @param len the length of the string in number of 2-byte code units
5754
   * (char16_t).
5755
   * @return true if and only if the string is valid UTF-16BE.
5756
   */
5757
  simdutf_warn_unused virtual bool
5758
  validate_utf16be(const char16_t *buf, size_t len) const noexcept = 0;
5759
5760
  /**
5761
   * Validate the UTF-16LE string and stop on error.  It might be faster than
5762
   * validate_utf16le when an error is expected to occur early.
5763
   *
5764
   * Overridden by each implementation.
5765
   *
5766
   * This function is not BOM-aware.
5767
   *
5768
   * @param buf the UTF-16LE string to validate.
5769
   * @param len the length of the string in number of 2-byte code units
5770
   * (char16_t).
5771
   * @return a result pair struct (of type simdutf::result containing the two
5772
   * fields error and count) with an error code and either position of the error
5773
   * (in the input in code units) if any, or the number of code units validated
5774
   * if successful.
5775
   */
5776
  simdutf_warn_unused virtual result
5777
  validate_utf16le_with_errors(const char16_t *buf,
5778
                               size_t len) const noexcept = 0;
5779
5780
  /**
5781
   * Validate the UTF-16BE string and stop on error. It might be faster than
5782
   * validate_utf16be when an error is expected to occur early.
5783
   *
5784
   * Overridden by each implementation.
5785
   *
5786
   * This function is not BOM-aware.
5787
   *
5788
   * @param buf the UTF-16BE string to validate.
5789
   * @param len the length of the string in number of 2-byte code units
5790
   * (char16_t).
5791
   * @return a result pair struct (of type simdutf::result containing the two
5792
   * fields error and count) with an error code and either position of the error
5793
   * (in the input in code units) if any, or the number of code units validated
5794
   * if successful.
5795
   */
5796
  simdutf_warn_unused virtual result
5797
  validate_utf16be_with_errors(const char16_t *buf,
5798
                               size_t len) const noexcept = 0;
5799
  /**
5800
   * Copies the UTF-16LE string while replacing mismatched surrogates with the
5801
   * Unicode replacement character U+FFFD. We allow the input and output to be
5802
   * the same buffer so that the correction is done in-place.
5803
   *
5804
   * Overridden by each implementation.
5805
   *
5806
   * @param input the UTF-16LE string to correct.
5807
   * @param len the length of the string in number of 2-byte code units
5808
   * (char16_t).
5809
   * @param output the output buffer.
5810
   */
5811
  virtual void to_well_formed_utf16le(const char16_t *input, size_t len,
5812
                                      char16_t *output) const noexcept = 0;
5813
  /**
5814
   * Copies the UTF-16BE string while replacing mismatched surrogates with the
5815
   * Unicode replacement character U+FFFD. We allow the input and output to be
5816
   * the same buffer so that the correction is done in-place.
5817
   *
5818
   * Overridden by each implementation.
5819
   *
5820
   * @param input the UTF-16BE string to correct.
5821
   * @param len the length of the string in number of 2-byte code units
5822
   * (char16_t).
5823
   * @param output the output buffer.
5824
   */
5825
  virtual void to_well_formed_utf16be(const char16_t *input, size_t len,
5826
                                      char16_t *output) const noexcept = 0;
5827
#endif // SIMDUTF_FEATURE_UTF16
5828
5829
#if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
5830
  /**
5831
   * Validate the UTF-32 string.
5832
   *
5833
   * Overridden by each implementation.
5834
   *
5835
   * This function is not BOM-aware.
5836
   *
5837
   * @param buf the UTF-32 string to validate.
5838
   * @param len the length of the string in number of 4-byte code units
5839
   * (char32_t).
5840
   * @return true if and only if the string is valid UTF-32.
5841
   */
5842
  simdutf_warn_unused virtual bool
5843
  validate_utf32(const char32_t *buf, size_t len) const noexcept = 0;
5844
#endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING
5845
5846
#if SIMDUTF_FEATURE_UTF32
5847
  /**
5848
   * Validate the UTF-32 string and stop on error.
5849
   *
5850
   * Overridden by each implementation.
5851
   *
5852
   * This function is not BOM-aware.
5853
   *
5854
   * @param buf the UTF-32 string to validate.
5855
   * @param len the length of the string in number of 4-byte code units
5856
   * (char32_t).
5857
   * @return a result pair struct (of type simdutf::result containing the two
5858
   * fields error and count) with an error code and either position of the error
5859
   * (in the input in code units) if any, or the number of code units validated
5860
   * if successful.
5861
   */
5862
  simdutf_warn_unused virtual result
5863
  validate_utf32_with_errors(const char32_t *buf,
5864
                             size_t len) const noexcept = 0;
5865
#endif // SIMDUTF_FEATURE_UTF32
5866
5867
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
5868
  /**
5869
   * Convert Latin1 string into UTF-8 string.
5870
   *
5871
   * This function is suitable to work with inputs from untrusted sources.
5872
   *
5873
   * @param input         the Latin1 string to convert
5874
   * @param length        the length of the string in bytes
5875
   * @param utf8_output  the pointer to buffer that can hold conversion result
5876
   * @return the number of written char; 0 if conversion is not possible
5877
   */
5878
  simdutf_warn_unused virtual size_t
5879
  convert_latin1_to_utf8(const char *input, size_t length,
5880
                         char *utf8_output) const noexcept = 0;
5881
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
5882
5883
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
5884
  /**
5885
   * Convert possibly Latin1 string into UTF-16LE string.
5886
   *
5887
   * This function is suitable to work with inputs from untrusted sources.
5888
   *
5889
   * @param input         the Latin1  string to convert
5890
   * @param length        the length of the string in bytes
5891
   * @param utf16_output  the pointer to buffer that can hold conversion result
5892
   * @return the number of written char16_t; 0 if conversion is not possible
5893
   */
5894
  simdutf_warn_unused virtual size_t
5895
  convert_latin1_to_utf16le(const char *input, size_t length,
5896
                            char16_t *utf16_output) const noexcept = 0;
5897
5898
  /**
5899
   * Convert Latin1 string into UTF-16BE string.
5900
   *
5901
   * This function is suitable to work with inputs from untrusted sources.
5902
   *
5903
   * @param input         the Latin1 string to convert
5904
   * @param length        the length of the string in bytes
5905
   * @param utf16_output  the pointer to buffer that can hold conversion result
5906
   * @return the number of written char16_t; 0 if conversion is not possible
5907
   */
5908
  simdutf_warn_unused virtual size_t
5909
  convert_latin1_to_utf16be(const char *input, size_t length,
5910
                            char16_t *utf16_output) const noexcept = 0;
5911
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
5912
5913
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
5914
  /**
5915
   * Convert Latin1 string into UTF-32 string.
5916
   *
5917
   * This function is suitable to work with inputs from untrusted sources.
5918
   *
5919
   * @param input         the Latin1 string to convert
5920
   * @param length        the length of the string in bytes
5921
   * @param utf32_buffer  the pointer to buffer that can hold conversion result
5922
   * @return the number of written char32_t; 0 if conversion is not possible
5923
   */
5924
  simdutf_warn_unused virtual size_t
5925
  convert_latin1_to_utf32(const char *input, size_t length,
5926
                          char32_t *utf32_buffer) const noexcept = 0;
5927
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
5928
5929
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
5930
  /**
5931
   * Convert possibly broken UTF-8 string into latin1 string.
5932
   *
5933
   * During the conversion also validation of the input string is done.
5934
   * This function is suitable to work with inputs from untrusted sources.
5935
   *
5936
   * @param input         the UTF-8 string to convert
5937
   * @param length        the length of the string in bytes
5938
   * @param latin1_output  the pointer to buffer that can hold conversion result
5939
   * @return the number of written char; 0 if the input was not valid UTF-8
5940
   * string or if it cannot be represented as Latin1
5941
   */
5942
  simdutf_warn_unused virtual size_t
5943
  convert_utf8_to_latin1(const char *input, size_t length,
5944
                         char *latin1_output) const noexcept = 0;
5945
5946
  /**
5947
   * Convert possibly broken UTF-8 string into latin1 string with errors.
5948
   * If the string cannot be represented as Latin1, an error
5949
   * code is returned.
5950
   *
5951
   * During the conversion also validation of the input string is done.
5952
   * This function is suitable to work with inputs from untrusted sources.
5953
   *
5954
   * @param input         the UTF-8 string to convert
5955
   * @param length        the length of the string in bytes
5956
   * @param latin1_output  the pointer to buffer that can hold conversion result
5957
   * @return a result pair struct (of type simdutf::result containing the two
5958
   * fields error and count) with an error code and either position of the error
5959
   * (in the input in code units) if any, or the number of code units validated
5960
   * if successful.
5961
   */
5962
  simdutf_warn_unused virtual result
5963
  convert_utf8_to_latin1_with_errors(const char *input, size_t length,
5964
                                     char *latin1_output) const noexcept = 0;
5965
5966
  /**
5967
   * Convert valid UTF-8 string into latin1 string.
5968
   *
5969
   * This function assumes that the input string is valid UTF-8 and that it can
5970
   * be represented as Latin1. If you violate this assumption, the result is
5971
   * implementation defined and may include system-dependent behavior such as
5972
   * crashes.
5973
   *
5974
   * This function is for expert users only and not part of our public API. Use
5975
   * convert_utf8_to_latin1 instead.
5976
   *
5977
   * This function is not BOM-aware.
5978
   *
5979
   * @param input         the UTF-8 string to convert
5980
   * @param length        the length of the string in bytes
5981
   * @param latin1_output  the pointer to buffer that can hold conversion result
5982
   * @return the number of written char; 0 if the input was not valid UTF-8
5983
   * string
5984
   */
5985
  simdutf_warn_unused virtual size_t
5986
  convert_valid_utf8_to_latin1(const char *input, size_t length,
5987
                               char *latin1_output) const noexcept = 0;
5988
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
5989
5990
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
5991
  /**
5992
   * Convert possibly broken UTF-8 string into UTF-16LE string.
5993
   *
5994
   * During the conversion also validation of the input string is done.
5995
   * This function is suitable to work with inputs from untrusted sources.
5996
   *
5997
   * @param input         the UTF-8 string to convert
5998
   * @param length        the length of the string in bytes
5999
   * @param utf16_output  the pointer to buffer that can hold conversion result
6000
   * @return the number of written char16_t; 0 if the input was not valid UTF-8
6001
   * string
6002
   */
6003
  simdutf_warn_unused virtual size_t
6004
  convert_utf8_to_utf16le(const char *input, size_t length,
6005
                          char16_t *utf16_output) const noexcept = 0;
6006
6007
  /**
6008
   * Convert possibly broken UTF-8 string into UTF-16BE string.
6009
   *
6010
   * During the conversion also validation of the input string is done.
6011
   * This function is suitable to work with inputs from untrusted sources.
6012
   *
6013
   * @param input         the UTF-8 string to convert
6014
   * @param length        the length of the string in bytes
6015
   * @param utf16_output  the pointer to buffer that can hold conversion result
6016
   * @return the number of written char16_t; 0 if the input was not valid UTF-8
6017
   * string
6018
   */
6019
  simdutf_warn_unused virtual size_t
6020
  convert_utf8_to_utf16be(const char *input, size_t length,
6021
                          char16_t *utf16_output) const noexcept = 0;
6022
6023
  /**
6024
   * Convert possibly broken UTF-8 string into UTF-16LE string and stop on
6025
   * error.
6026
   *
6027
   * During the conversion also validation of the input string is done.
6028
   * This function is suitable to work with inputs from untrusted sources.
6029
   *
6030
   * @param input         the UTF-8 string to convert
6031
   * @param length        the length of the string in bytes
6032
   * @param utf16_output  the pointer to buffer that can hold conversion result
6033
   * @return a result pair struct (of type simdutf::result containing the two
6034
   * fields error and count) with an error code and either position of the error
6035
   * (in the input in code units) if any, or the number of code units validated
6036
   * if successful.
6037
   */
6038
  simdutf_warn_unused virtual result convert_utf8_to_utf16le_with_errors(
6039
      const char *input, size_t length,
6040
      char16_t *utf16_output) const noexcept = 0;
6041
6042
  /**
6043
   * Convert possibly broken UTF-8 string into UTF-16BE string and stop on
6044
   * error.
6045
   *
6046
   * During the conversion also validation of the input string is done.
6047
   * This function is suitable to work with inputs from untrusted sources.
6048
   *
6049
   * @param input         the UTF-8 string to convert
6050
   * @param length        the length of the string in bytes
6051
   * @param utf16_output  the pointer to buffer that can hold conversion result
6052
   * @return a result pair struct (of type simdutf::result containing the two
6053
   * fields error and count) with an error code and either position of the error
6054
   * (in the input in code units) if any, or the number of code units validated
6055
   * if successful.
6056
   */
6057
  simdutf_warn_unused virtual result convert_utf8_to_utf16be_with_errors(
6058
      const char *input, size_t length,
6059
      char16_t *utf16_output) const noexcept = 0;
6060
  /**
6061
   * Compute the number of bytes that this UTF-16LE string would require in
6062
   * UTF-8 format even when the UTF-16LE content contains mismatched
6063
   * surrogates that have to be replaced by the replacement character (0xFFFD).
6064
   *
6065
   * @param input         the UTF-16LE string to convert
6066
   * @param length        the length of the string in 2-byte code units
6067
   * (char16_t)
6068
   * @return a result pair struct (of type simdutf::result containing the two
6069
   * fields error and count) where the count is the number of bytes required to
6070
   * encode the UTF-16LE string as UTF-8, and the error code is either SUCCESS
6071
   * or SURROGATE. The count is correct regardless of the error field.
6072
   * When SURROGATE is returned, it does not indicate an error in the case of
6073
   * this function: it indicates that at least one surrogate has been
6074
   * encountered: the surrogates may be matched or not (thus this function does
6075
   * not validate). If the returned error code is SUCCESS, then the input
6076
   * contains no surrogate, is in the Basic Multilingual Plane, and is
6077
   * necessarily valid.
6078
   */
6079
  virtual simdutf_warn_unused result utf8_length_from_utf16le_with_replacement(
6080
      const char16_t *input, size_t length) const noexcept = 0;
6081
6082
  /**
6083
   * Compute the number of bytes that this UTF-16BE string would require in
6084
   * UTF-8 format even when the UTF-16BE content contains mismatched
6085
   * surrogates that have to be replaced by the replacement character (0xFFFD).
6086
   *
6087
   * @param input         the UTF-16BE string to convert
6088
   * @param length        the length of the string in 2-byte code units
6089
   * (char16_t)
6090
   * @return a result pair struct (of type simdutf::result containing the two
6091
   * fields error and count) where the count is the number of bytes required to
6092
   * encode the UTF-16BE string as UTF-8, and the error code is either SUCCESS
6093
   * or SURROGATE. The count is correct regardless of the error field.
6094
   * When SURROGATE is returned, it does not indicate an error in the case of
6095
   * this function: it indicates that at least one surrogate has been
6096
   * encountered: the surrogates may be matched or not (thus this function does
6097
   * not validate). If the returned error code is SUCCESS, then the input
6098
   * contains no surrogate, is in the Basic Multilingual Plane, and is
6099
   * necessarily valid.
6100
   */
6101
  virtual simdutf_warn_unused result utf8_length_from_utf16be_with_replacement(
6102
      const char16_t *input, size_t length) const noexcept = 0;
6103
6104
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6105
6106
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6107
  /**
6108
   * Convert possibly broken UTF-8 string into UTF-32 string.
6109
   *
6110
   * During the conversion also validation of the input string is done.
6111
   * This function is suitable to work with inputs from untrusted sources.
6112
   *
6113
   * @param input         the UTF-8 string to convert
6114
   * @param length        the length of the string in bytes
6115
   * @param utf32_output  the pointer to buffer that can hold conversion result
6116
   * @return the number of written char16_t; 0 if the input was not valid UTF-8
6117
   * string
6118
   */
6119
  simdutf_warn_unused virtual size_t
6120
  convert_utf8_to_utf32(const char *input, size_t length,
6121
                        char32_t *utf32_output) const noexcept = 0;
6122
6123
  /**
6124
   * Convert possibly broken UTF-8 string into UTF-32 string and stop on error.
6125
   *
6126
   * During the conversion also validation of the input string is done.
6127
   * This function is suitable to work with inputs from untrusted sources.
6128
   *
6129
   * @param input         the UTF-8 string to convert
6130
   * @param length        the length of the string in bytes
6131
   * @param utf32_output  the pointer to buffer that can hold conversion result
6132
   * @return a result pair struct (of type simdutf::result containing the two
6133
   * fields error and count) with an error code and either position of the error
6134
   * (in the input in code units) if any, or the number of char32_t written if
6135
   * successful.
6136
   */
6137
  simdutf_warn_unused virtual result
6138
  convert_utf8_to_utf32_with_errors(const char *input, size_t length,
6139
                                    char32_t *utf32_output) const noexcept = 0;
6140
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6141
6142
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6143
  /**
6144
   * Convert valid UTF-8 string into UTF-16LE string.
6145
   *
6146
   * This function assumes that the input string is valid UTF-8.
6147
   *
6148
   * @param input         the UTF-8 string to convert
6149
   * @param length        the length of the string in bytes
6150
   * @param utf16_buffer  the pointer to buffer that can hold conversion result
6151
   * @return the number of written char16_t
6152
   */
6153
  simdutf_warn_unused virtual size_t
6154
  convert_valid_utf8_to_utf16le(const char *input, size_t length,
6155
                                char16_t *utf16_buffer) const noexcept = 0;
6156
6157
  /**
6158
   * Convert valid UTF-8 string into UTF-16BE string.
6159
   *
6160
   * This function assumes that the input string is valid UTF-8.
6161
   *
6162
   * @param input         the UTF-8 string to convert
6163
   * @param length        the length of the string in bytes
6164
   * @param utf16_buffer  the pointer to buffer that can hold conversion result
6165
   * @return the number of written char16_t
6166
   */
6167
  simdutf_warn_unused virtual size_t
6168
  convert_valid_utf8_to_utf16be(const char *input, size_t length,
6169
                                char16_t *utf16_buffer) const noexcept = 0;
6170
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6171
6172
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6173
  /**
6174
   * Convert valid UTF-8 string into UTF-32 string.
6175
   *
6176
   * This function assumes that the input string is valid UTF-8.
6177
   *
6178
   * @param input         the UTF-8 string to convert
6179
   * @param length        the length of the string in bytes
6180
   * @param utf32_buffer  the pointer to buffer that can hold conversion result
6181
   * @return the number of written char32_t
6182
   */
6183
  simdutf_warn_unused virtual size_t
6184
  convert_valid_utf8_to_utf32(const char *input, size_t length,
6185
                              char32_t *utf32_buffer) const noexcept = 0;
6186
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6187
6188
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6189
  /**
6190
   * Compute the number of 2-byte code units that this UTF-8 string would
6191
   * require in UTF-16LE format.
6192
   *
6193
   * This function does not validate the input. It is acceptable to pass invalid
6194
   * UTF-8 strings but in such cases the result is implementation defined.
6195
   *
6196
   * @param input         the UTF-8 string to process
6197
   * @param length        the length of the string in bytes
6198
   * @return the number of char16_t code units required to encode the UTF-8
6199
   * string as UTF-16LE
6200
   */
6201
  simdutf_warn_unused virtual size_t
6202
  utf16_length_from_utf8(const char *input, size_t length) const noexcept = 0;
6203
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6204
6205
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6206
  /**
6207
   * Compute the number of 4-byte code units that this UTF-8 string would
6208
   * require in UTF-32 format.
6209
   *
6210
   * This function is equivalent to count_utf8. It is acceptable to pass invalid
6211
   * UTF-8 strings but in such cases the result is implementation defined.
6212
   *
6213
   * This function does not validate the input.
6214
   *
6215
   * @param input         the UTF-8 string to process
6216
   * @param length        the length of the string in bytes
6217
   * @return the number of char32_t code units required to encode the UTF-8
6218
   * string as UTF-32
6219
   */
6220
  simdutf_warn_unused virtual size_t
6221
  utf32_length_from_utf8(const char *input, size_t length) const noexcept = 0;
6222
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6223
6224
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
6225
  /**
6226
   * Convert possibly broken UTF-16LE string into Latin1 string.
6227
   *
6228
   * During the conversion also validation of the input string is done.
6229
   * This function is suitable to work with inputs from untrusted sources.
6230
   *
6231
   * This function is not BOM-aware.
6232
   *
6233
   * @param input         the UTF-16LE string to convert
6234
   * @param length        the length of the string in 2-byte code units
6235
   * (char16_t)
6236
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6237
   * result
6238
   * @return number of written code units; 0 if input is not a valid UTF-16LE
6239
   * string or if it cannot be represented as Latin1
6240
   */
6241
  simdutf_warn_unused virtual size_t
6242
  convert_utf16le_to_latin1(const char16_t *input, size_t length,
6243
                            char *latin1_buffer) const noexcept = 0;
6244
6245
  /**
6246
   * Convert possibly broken UTF-16BE string into Latin1 string.
6247
   *
6248
   * During the conversion also validation of the input string is done.
6249
   * This function is suitable to work with inputs from untrusted sources.
6250
   *
6251
   * This function is not BOM-aware.
6252
   *
6253
   * @param input         the UTF-16BE string to convert
6254
   * @param length        the length of the string in 2-byte code units
6255
   * (char16_t)
6256
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6257
   * result
6258
   * @return number of written code units; 0 if input is not a valid UTF-16BE
6259
   * string or if it cannot be represented as Latin1
6260
   */
6261
  simdutf_warn_unused virtual size_t
6262
  convert_utf16be_to_latin1(const char16_t *input, size_t length,
6263
                            char *latin1_buffer) const noexcept = 0;
6264
6265
  /**
6266
   * Convert possibly broken UTF-16LE string into Latin1 string.
6267
   * If the string cannot be represented as Latin1, an error
6268
   * is returned.
6269
   *
6270
   * During the conversion also validation of the input string is done.
6271
   * This function is suitable to work with inputs from untrusted sources.
6272
   * This function is not BOM-aware.
6273
   *
6274
   * @param input         the UTF-16LE string to convert
6275
   * @param length        the length of the string in 2-byte code units
6276
   * (char16_t)
6277
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6278
   * result
6279
   * @return a result pair struct (of type simdutf::result containing the two
6280
   * fields error and count) with an error code and either position of the error
6281
   * (in the input in code units) if any, or the number of char written if
6282
   * successful.
6283
   */
6284
  simdutf_warn_unused virtual result
6285
  convert_utf16le_to_latin1_with_errors(const char16_t *input, size_t length,
6286
                                        char *latin1_buffer) const noexcept = 0;
6287
6288
  /**
6289
   * Convert possibly broken UTF-16BE string into Latin1 string.
6290
   * If the string cannot be represented as Latin1, an error
6291
   * is returned.
6292
   *
6293
   * During the conversion also validation of the input string is done.
6294
   * This function is suitable to work with inputs from untrusted sources.
6295
   * This function is not BOM-aware.
6296
   *
6297
   * @param input         the UTF-16BE string to convert
6298
   * @param length        the length of the string in 2-byte code units
6299
   * (char16_t)
6300
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6301
   * result
6302
   * @return a result pair struct (of type simdutf::result containing the two
6303
   * fields error and count) with an error code and either position of the error
6304
   * (in the input in code units) if any, or the number of char written if
6305
   * successful.
6306
   */
6307
  simdutf_warn_unused virtual result
6308
  convert_utf16be_to_latin1_with_errors(const char16_t *input, size_t length,
6309
                                        char *latin1_buffer) const noexcept = 0;
6310
6311
  /**
6312
   * Convert valid UTF-16LE string into Latin1 string.
6313
   *
6314
   * This function assumes that the input string is valid UTF-L16LE and that it
6315
   * can be represented as Latin1. If you violate this assumption, the result is
6316
   * implementation defined and may include system-dependent behavior such as
6317
   * crashes.
6318
   *
6319
   * This function is for expert users only and not part of our public API. Use
6320
   * convert_utf16le_to_latin1 instead.
6321
   *
6322
   * This function is not BOM-aware.
6323
   *
6324
   * @param input         the UTF-16LE string to convert
6325
   * @param length        the length of the string in 2-byte code units
6326
   * (char16_t)
6327
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6328
   * result
6329
   * @return number of written code units; 0 if conversion is not possible
6330
   */
6331
  simdutf_warn_unused virtual size_t
6332
  convert_valid_utf16le_to_latin1(const char16_t *input, size_t length,
6333
                                  char *latin1_buffer) const noexcept = 0;
6334
6335
  /**
6336
   * Convert valid UTF-16BE string into Latin1 string.
6337
   *
6338
   * This function assumes that the input string is valid UTF16-BE and that it
6339
   * can be represented as Latin1. If you violate this assumption, the result is
6340
   * implementation defined and may include system-dependent behavior such as
6341
   * crashes.
6342
   *
6343
   * This function is for expert users only and not part of our public API. Use
6344
   * convert_utf16be_to_latin1 instead.
6345
   *
6346
   * This function is not BOM-aware.
6347
   *
6348
   * @param input         the UTF-16BE string to convert
6349
   * @param length        the length of the string in 2-byte code units
6350
   * (char16_t)
6351
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6352
   * result
6353
   * @return number of written code units; 0 if conversion is not possible
6354
   */
6355
  simdutf_warn_unused virtual size_t
6356
  convert_valid_utf16be_to_latin1(const char16_t *input, size_t length,
6357
                                  char *latin1_buffer) const noexcept = 0;
6358
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
6359
6360
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6361
  /**
6362
   * Convert possibly broken UTF-16LE string into UTF-8 string.
6363
   *
6364
   * During the conversion also validation of the input string is done.
6365
   * This function is suitable to work with inputs from untrusted sources.
6366
   *
6367
   * This function is not BOM-aware.
6368
   *
6369
   * @param input         the UTF-16LE string to convert
6370
   * @param length        the length of the string in 2-byte code units
6371
   * (char16_t)
6372
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6373
   * @return number of written code units; 0 if input is not a valid UTF-16LE
6374
   * string
6375
   */
6376
  simdutf_warn_unused virtual size_t
6377
  convert_utf16le_to_utf8(const char16_t *input, size_t length,
6378
                          char *utf8_buffer) const noexcept = 0;
6379
6380
  /**
6381
   * Convert possibly broken UTF-16BE string into UTF-8 string.
6382
   *
6383
   * During the conversion also validation of the input string is done.
6384
   * This function is suitable to work with inputs from untrusted sources.
6385
   *
6386
   * This function is not BOM-aware.
6387
   *
6388
   * @param input         the UTF-16BE string to convert
6389
   * @param length        the length of the string in 2-byte code units
6390
   * (char16_t)
6391
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6392
   * @return number of written code units; 0 if input is not a valid UTF-16BE
6393
   * string
6394
   */
6395
  simdutf_warn_unused virtual size_t
6396
  convert_utf16be_to_utf8(const char16_t *input, size_t length,
6397
                          char *utf8_buffer) const noexcept = 0;
6398
6399
  /**
6400
   * Convert possibly broken UTF-16LE string into UTF-8 string and stop on
6401
   * error.
6402
   *
6403
   * During the conversion also validation of the input string is done.
6404
   * This function is suitable to work with inputs from untrusted sources.
6405
   *
6406
   * This function is not BOM-aware.
6407
   *
6408
   * @param input         the UTF-16LE string to convert
6409
   * @param length        the length of the string in 2-byte code units
6410
   * (char16_t)
6411
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6412
   * @return a result pair struct (of type simdutf::result containing the two
6413
   * fields error and count) with an error code and either position of the error
6414
   * (in the input in code units) if any, or the number of char written if
6415
   * successful.
6416
   */
6417
  simdutf_warn_unused virtual result
6418
  convert_utf16le_to_utf8_with_errors(const char16_t *input, size_t length,
6419
                                      char *utf8_buffer) const noexcept = 0;
6420
6421
  /**
6422
   * Convert possibly broken UTF-16BE string into UTF-8 string and stop on
6423
   * error.
6424
   *
6425
   * During the conversion also validation of the input string is done.
6426
   * This function is suitable to work with inputs from untrusted sources.
6427
   *
6428
   * This function is not BOM-aware.
6429
   *
6430
   * @param input         the UTF-16BE string to convert
6431
   * @param length        the length of the string in 2-byte code units
6432
   * (char16_t)
6433
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6434
   * @return a result pair struct (of type simdutf::result containing the two
6435
   * fields error and count) with an error code and either position of the error
6436
   * (in the input in code units) if any, or the number of char written if
6437
   * successful.
6438
   */
6439
  simdutf_warn_unused virtual result
6440
  convert_utf16be_to_utf8_with_errors(const char16_t *input, size_t length,
6441
                                      char *utf8_buffer) const noexcept = 0;
6442
6443
  /**
6444
   * Convert possibly broken UTF-16LE string into UTF-8 string, replacing
6445
   * unpaired surrogates with the Unicode replacement character U+FFFD.
6446
   *
6447
   * This function always succeeds: unpaired surrogates are replaced with
6448
   * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD).
6449
   *
6450
   * This function is not BOM-aware.
6451
   *
6452
   * @param input         the UTF-16LE string to convert
6453
   * @param length        the length of the string in 2-byte code units
6454
   * (char16_t)
6455
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6456
   * @return number of written code units
6457
   */
6458
  simdutf_warn_unused virtual size_t convert_utf16le_to_utf8_with_replacement(
6459
      const char16_t *input, size_t length,
6460
      char *utf8_buffer) const noexcept = 0;
6461
6462
  /**
6463
   * Convert possibly broken UTF-16BE string into UTF-8 string, replacing
6464
   * unpaired surrogates with the Unicode replacement character U+FFFD.
6465
   *
6466
   * This function always succeeds: unpaired surrogates are replaced with
6467
   * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD).
6468
   *
6469
   * This function is not BOM-aware.
6470
   *
6471
   * @param input         the UTF-16BE string to convert
6472
   * @param length        the length of the string in 2-byte code units
6473
   * (char16_t)
6474
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6475
   * @return number of written code units
6476
   */
6477
  simdutf_warn_unused virtual size_t convert_utf16be_to_utf8_with_replacement(
6478
      const char16_t *input, size_t length,
6479
      char *utf8_buffer) const noexcept = 0;
6480
6481
  /**
6482
   * Convert valid UTF-16LE string into UTF-8 string.
6483
   *
6484
   * This function assumes that the input string is valid UTF-16LE.
6485
   *
6486
   * This function is not BOM-aware.
6487
   *
6488
   * @param input         the UTF-16LE string to convert
6489
   * @param length        the length of the string in 2-byte code units
6490
   * (char16_t)
6491
   * @param utf8_buffer   the pointer to a buffer that can hold the conversion
6492
   * result
6493
   * @return number of written code units; 0 if conversion is not possible
6494
   */
6495
  simdutf_warn_unused virtual size_t
6496
  convert_valid_utf16le_to_utf8(const char16_t *input, size_t length,
6497
                                char *utf8_buffer) const noexcept = 0;
6498
6499
  /**
6500
   * Convert valid UTF-16BE string into UTF-8 string.
6501
   *
6502
   * This function assumes that the input string is valid UTF-16BE.
6503
   *
6504
   * This function is not BOM-aware.
6505
   *
6506
   * @param input         the UTF-16BE string to convert
6507
   * @param length        the length of the string in 2-byte code units
6508
   * (char16_t)
6509
   * @param utf8_buffer   the pointer to a buffer that can hold the conversion
6510
   * result
6511
   * @return number of written code units; 0 if conversion is not possible
6512
   */
6513
  simdutf_warn_unused virtual size_t
6514
  convert_valid_utf16be_to_utf8(const char16_t *input, size_t length,
6515
                                char *utf8_buffer) const noexcept = 0;
6516
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6517
6518
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
6519
  /**
6520
   * Convert possibly broken UTF-16LE string into UTF-32 string.
6521
   *
6522
   * During the conversion also validation of the input string is done.
6523
   * This function is suitable to work with inputs from untrusted sources.
6524
   *
6525
   * This function is not BOM-aware.
6526
   *
6527
   * @param input         the UTF-16LE string to convert
6528
   * @param length        the length of the string in 2-byte code units
6529
   * (char16_t)
6530
   * @param utf32_buffer   the pointer to buffer that can hold conversion result
6531
   * @return number of written code units; 0 if input is not a valid UTF-16LE
6532
   * string
6533
   */
6534
  simdutf_warn_unused virtual size_t
6535
  convert_utf16le_to_utf32(const char16_t *input, size_t length,
6536
                           char32_t *utf32_buffer) const noexcept = 0;
6537
6538
  /**
6539
   * Convert possibly broken UTF-16BE string into UTF-32 string.
6540
   *
6541
   * During the conversion also validation of the input string is done.
6542
   * This function is suitable to work with inputs from untrusted sources.
6543
   *
6544
   * This function is not BOM-aware.
6545
   *
6546
   * @param input         the UTF-16BE string to convert
6547
   * @param length        the length of the string in 2-byte code units
6548
   * (char16_t)
6549
   * @param utf32_buffer   the pointer to buffer that can hold conversion result
6550
   * @return number of written code units; 0 if input is not a valid UTF-16BE
6551
   * string
6552
   */
6553
  simdutf_warn_unused virtual size_t
6554
  convert_utf16be_to_utf32(const char16_t *input, size_t length,
6555
                           char32_t *utf32_buffer) const noexcept = 0;
6556
6557
  /**
6558
   * Convert possibly broken UTF-16LE string into UTF-32 string and stop on
6559
   * error.
6560
   *
6561
   * During the conversion also validation of the input string is done.
6562
   * This function is suitable to work with inputs from untrusted sources.
6563
   *
6564
   * This function is not BOM-aware.
6565
   *
6566
   * @param input         the UTF-16LE string to convert
6567
   * @param length        the length of the string in 2-byte code units
6568
   * (char16_t)
6569
   * @param utf32_buffer   the pointer to buffer that can hold conversion result
6570
   * @return a result pair struct (of type simdutf::result containing the two
6571
   * fields error and count) with an error code and either position of the error
6572
   * (in the input in code units) if any, or the number of char32_t written if
6573
   * successful.
6574
   */
6575
  simdutf_warn_unused virtual result convert_utf16le_to_utf32_with_errors(
6576
      const char16_t *input, size_t length,
6577
      char32_t *utf32_buffer) const noexcept = 0;
6578
6579
  /**
6580
   * Convert possibly broken UTF-16BE string into UTF-32 string and stop on
6581
   * error.
6582
   *
6583
   * During the conversion also validation of the input string is done.
6584
   * This function is suitable to work with inputs from untrusted sources.
6585
   *
6586
   * This function is not BOM-aware.
6587
   *
6588
   * @param input         the UTF-16BE string to convert
6589
   * @param length        the length of the string in 2-byte code units
6590
   * (char16_t)
6591
   * @param utf32_buffer   the pointer to buffer that can hold conversion result
6592
   * @return a result pair struct (of type simdutf::result containing the two
6593
   * fields error and count) with an error code and either position of the error
6594
   * (in the input in code units) if any, or the number of char32_t written if
6595
   * successful.
6596
   */
6597
  simdutf_warn_unused virtual result convert_utf16be_to_utf32_with_errors(
6598
      const char16_t *input, size_t length,
6599
      char32_t *utf32_buffer) const noexcept = 0;
6600
6601
  /**
6602
   * Convert valid UTF-16LE string into UTF-32 string.
6603
   *
6604
   * This function assumes that the input string is valid UTF-16LE.
6605
   *
6606
   * This function is not BOM-aware.
6607
   *
6608
   * @param input         the UTF-16LE string to convert
6609
   * @param length        the length of the string in 2-byte code units
6610
   * (char16_t)
6611
   * @param utf32_buffer   the pointer to a buffer that can hold the conversion
6612
   * result
6613
   * @return number of written code units; 0 if conversion is not possible
6614
   */
6615
  simdutf_warn_unused virtual size_t
6616
  convert_valid_utf16le_to_utf32(const char16_t *input, size_t length,
6617
                                 char32_t *utf32_buffer) const noexcept = 0;
6618
6619
  /**
6620
   * Convert valid UTF-16LE string into UTF-32BE string.
6621
   *
6622
   * This function assumes that the input string is valid UTF-16BE.
6623
   *
6624
   * This function is not BOM-aware.
6625
   *
6626
   * @param input         the UTF-16BE string to convert
6627
   * @param length        the length of the string in 2-byte code units
6628
   * (char16_t)
6629
   * @param utf32_buffer   the pointer to a buffer that can hold the conversion
6630
   * result
6631
   * @return number of written code units; 0 if conversion is not possible
6632
   */
6633
  simdutf_warn_unused virtual size_t
6634
  convert_valid_utf16be_to_utf32(const char16_t *input, size_t length,
6635
                                 char32_t *utf32_buffer) const noexcept = 0;
6636
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
6637
6638
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6639
  /**
6640
   * Compute the number of bytes that this UTF-16LE string would require in
6641
   * UTF-8 format.
6642
   *
6643
   * This function does not validate the input. It is acceptable to pass invalid
6644
   * UTF-16 strings but in such cases the result is implementation defined.
6645
   *
6646
   * This function is not BOM-aware.
6647
   *
6648
   * @param input         the UTF-16LE string to convert
6649
   * @param length        the length of the string in 2-byte code units
6650
   * (char16_t)
6651
   * @return the number of bytes required to encode the UTF-16LE string as UTF-8
6652
   */
6653
  simdutf_warn_unused virtual size_t
6654
  utf8_length_from_utf16le(const char16_t *input,
6655
                           size_t length) const noexcept = 0;
6656
6657
  /**
6658
   * Compute the number of bytes that this UTF-16BE string would require in
6659
   * UTF-8 format.
6660
   *
6661
   * This function does not validate the input. It is acceptable to pass invalid
6662
   * UTF-16 strings but in such cases the result is implementation defined.
6663
   *
6664
   * This function is not BOM-aware.
6665
   *
6666
   * @param input         the UTF-16BE string to convert
6667
   * @param length        the length of the string in 2-byte code units
6668
   * (char16_t)
6669
   * @return the number of bytes required to encode the UTF-16BE string as UTF-8
6670
   */
6671
  simdutf_warn_unused virtual size_t
6672
  utf8_length_from_utf16be(const char16_t *input,
6673
                           size_t length) const noexcept = 0;
6674
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16
6675
6676
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
6677
  /**
6678
   * Convert possibly broken UTF-32 string into Latin1 string.
6679
   *
6680
   * During the conversion also validation of the input string is done.
6681
   * This function is suitable to work with inputs from untrusted sources.
6682
   *
6683
   * This function is not BOM-aware.
6684
   *
6685
   * @param input         the UTF-32 string to convert
6686
   * @param length        the length of the string in 4-byte code units
6687
   * (char32_t)
6688
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6689
   * result
6690
   * @return number of written code units; 0 if input is not a valid UTF-32
6691
   * string
6692
   */
6693
  simdutf_warn_unused virtual size_t
6694
  convert_utf32_to_latin1(const char32_t *input, size_t length,
6695
                          char *latin1_buffer) const noexcept = 0;
6696
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
6697
6698
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
6699
  /**
6700
   * Convert possibly broken UTF-32 string into Latin1 string and stop on error.
6701
   * If the string cannot be represented as Latin1, an error is returned.
6702
   *
6703
   * During the conversion also validation of the input string is done.
6704
   * This function is suitable to work with inputs from untrusted sources.
6705
   *
6706
   * This function is not BOM-aware.
6707
   *
6708
   * @param input         the UTF-32 string to convert
6709
   * @param length        the length of the string in 4-byte code units
6710
   * (char32_t)
6711
   * @param latin1_buffer   the pointer to buffer that can hold conversion
6712
   * result
6713
   * @return a result pair struct (of type simdutf::result containing the two
6714
   * fields error and count) with an error code and either position of the error
6715
   * (in the input in code units) if any, or the number of char written if
6716
   * successful.
6717
   */
6718
  simdutf_warn_unused virtual result
6719
  convert_utf32_to_latin1_with_errors(const char32_t *input, size_t length,
6720
                                      char *latin1_buffer) const noexcept = 0;
6721
6722
  /**
6723
   * Convert valid UTF-32 string into Latin1 string.
6724
   *
6725
   * This function assumes that the input string is valid UTF-32 and can be
6726
   * represented as Latin1. If you violate this assumption, the result is
6727
   * implementation defined and may include system-dependent behavior such as
6728
   * crashes.
6729
   *
6730
   * This function is for expert users only and not part of our public API. Use
6731
   * convert_utf32_to_latin1 instead.
6732
   *
6733
   * This function is not BOM-aware.
6734
   *
6735
   * @param input         the UTF-32 string to convert
6736
   * @param length        the length of the string in 4-byte code units
6737
   * (char32_t)
6738
   * @param latin1_buffer   the pointer to a buffer that can hold the conversion
6739
   * result
6740
   * @return number of written code units; 0 if conversion is not possible
6741
   */
6742
  simdutf_warn_unused virtual size_t
6743
  convert_valid_utf32_to_latin1(const char32_t *input, size_t length,
6744
                                char *latin1_buffer) const noexcept = 0;
6745
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
6746
6747
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6748
  /**
6749
   * Convert possibly broken UTF-32 string into UTF-8 string.
6750
   *
6751
   * During the conversion also validation of the input string is done.
6752
   * This function is suitable to work with inputs from untrusted sources.
6753
   *
6754
   * This function is not BOM-aware.
6755
   *
6756
   * @param input         the UTF-32 string to convert
6757
   * @param length        the length of the string in 4-byte code units
6758
   * (char32_t)
6759
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6760
   * @return number of written code units; 0 if input is not a valid UTF-32
6761
   * string
6762
   */
6763
  simdutf_warn_unused virtual size_t
6764
  convert_utf32_to_utf8(const char32_t *input, size_t length,
6765
                        char *utf8_buffer) const noexcept = 0;
6766
6767
  /**
6768
   * Convert possibly broken UTF-32 string into UTF-8 string and stop on error.
6769
   *
6770
   * During the conversion also validation of the input string is done.
6771
   * This function is suitable to work with inputs from untrusted sources.
6772
   *
6773
   * This function is not BOM-aware.
6774
   *
6775
   * @param input         the UTF-32 string to convert
6776
   * @param length        the length of the string in 4-byte code units
6777
   * (char32_t)
6778
   * @param utf8_buffer   the pointer to buffer that can hold conversion result
6779
   * @return a result pair struct (of type simdutf::result containing the two
6780
   * fields error and count) with an error code and either position of the error
6781
   * (in the input in code units) if any, or the number of char written if
6782
   * successful.
6783
   */
6784
  simdutf_warn_unused virtual result
6785
  convert_utf32_to_utf8_with_errors(const char32_t *input, size_t length,
6786
                                    char *utf8_buffer) const noexcept = 0;
6787
6788
  /**
6789
   * Convert valid UTF-32 string into UTF-8 string.
6790
   *
6791
   * This function assumes that the input string is valid UTF-32.
6792
   *
6793
   * This function is not BOM-aware.
6794
   *
6795
   * @param input         the UTF-32 string to convert
6796
   * @param length        the length of the string in 4-byte code units
6797
   * (char32_t)
6798
   * @param utf8_buffer   the pointer to a buffer that can hold the conversion
6799
   * result
6800
   * @return number of written code units; 0 if conversion is not possible
6801
   */
6802
  simdutf_warn_unused virtual size_t
6803
  convert_valid_utf32_to_utf8(const char32_t *input, size_t length,
6804
                              char *utf8_buffer) const noexcept = 0;
6805
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6806
6807
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
6808
  /**
6809
   * Return the number of bytes that this UTF-16 string would require in Latin1
6810
   * format.
6811
   *
6812
   *
6813
   * @param length        the length of the string in 2-byte code units
6814
   * (char16_t)
6815
   * @return the number of bytes required to encode the UTF-16 string as Latin1
6816
   */
6817
  simdutf_warn_unused virtual size_t
6818
  utf16_length_from_latin1(size_t length) const noexcept {
6819
    return length;
6820
  }
6821
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
6822
6823
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
6824
  /**
6825
   * Convert possibly broken UTF-32 string into UTF-16LE string.
6826
   *
6827
   * During the conversion also validation of the input string is done.
6828
   * This function is suitable to work with inputs from untrusted sources.
6829
   *
6830
   * This function is not BOM-aware.
6831
   *
6832
   * @param input         the UTF-32 string to convert
6833
   * @param length        the length of the string in 4-byte code units
6834
   * (char32_t)
6835
   * @param utf16_buffer   the pointer to buffer that can hold conversion result
6836
   * @return number of written code units; 0 if input is not a valid UTF-32
6837
   * string
6838
   */
6839
  simdutf_warn_unused virtual size_t
6840
  convert_utf32_to_utf16le(const char32_t *input, size_t length,
6841
                           char16_t *utf16_buffer) const noexcept = 0;
6842
6843
  /**
6844
   * Convert possibly broken UTF-32 string into UTF-16BE string.
6845
   *
6846
   * During the conversion also validation of the input string is done.
6847
   * This function is suitable to work with inputs from untrusted sources.
6848
   *
6849
   * This function is not BOM-aware.
6850
   *
6851
   * @param input         the UTF-32 string to convert
6852
   * @param length        the length of the string in 4-byte code units
6853
   * (char32_t)
6854
   * @param utf16_buffer   the pointer to buffer that can hold conversion result
6855
   * @return number of written code units; 0 if input is not a valid UTF-32
6856
   * string
6857
   */
6858
  simdutf_warn_unused virtual size_t
6859
  convert_utf32_to_utf16be(const char32_t *input, size_t length,
6860
                           char16_t *utf16_buffer) const noexcept = 0;
6861
6862
  /**
6863
   * Convert possibly broken UTF-32 string into UTF-16LE string and stop on
6864
   * error.
6865
   *
6866
   * During the conversion also validation of the input string is done.
6867
   * This function is suitable to work with inputs from untrusted sources.
6868
   *
6869
   * This function is not BOM-aware.
6870
   *
6871
   * @param input         the UTF-32 string to convert
6872
   * @param length        the length of the string in 4-byte code units
6873
   * (char32_t)
6874
   * @param utf16_buffer   the pointer to buffer that can hold conversion result
6875
   * @return a result pair struct (of type simdutf::result containing the two
6876
   * fields error and count) with an error code and either position of the error
6877
   * (in the input in code units) if any, or the number of char16_t written if
6878
   * successful.
6879
   */
6880
  simdutf_warn_unused virtual result convert_utf32_to_utf16le_with_errors(
6881
      const char32_t *input, size_t length,
6882
      char16_t *utf16_buffer) const noexcept = 0;
6883
6884
  /**
6885
   * Convert possibly broken UTF-32 string into UTF-16BE string and stop on
6886
   * error.
6887
   *
6888
   * During the conversion also validation of the input string is done.
6889
   * This function is suitable to work with inputs from untrusted sources.
6890
   *
6891
   * This function is not BOM-aware.
6892
   *
6893
   * @param input         the UTF-32 string to convert
6894
   * @param length        the length of the string in 4-byte code units
6895
   * (char32_t)
6896
   * @param utf16_buffer   the pointer to buffer that can hold conversion result
6897
   * @return a result pair struct (of type simdutf::result containing the two
6898
   * fields error and count) with an error code and either position of the error
6899
   * (in the input in code units) if any, or the number of char16_t written if
6900
   * successful.
6901
   */
6902
  simdutf_warn_unused virtual result convert_utf32_to_utf16be_with_errors(
6903
      const char32_t *input, size_t length,
6904
      char16_t *utf16_buffer) const noexcept = 0;
6905
6906
  /**
6907
   * Convert valid UTF-32 string into UTF-16LE string.
6908
   *
6909
   * This function assumes that the input string is valid UTF-32.
6910
   *
6911
   * This function is not BOM-aware.
6912
   *
6913
   * @param input         the UTF-32 string to convert
6914
   * @param length        the length of the string in 4-byte code units
6915
   * (char32_t)
6916
   * @param utf16_buffer   the pointer to a buffer that can hold the conversion
6917
   * result
6918
   * @return number of written code units; 0 if conversion is not possible
6919
   */
6920
  simdutf_warn_unused virtual size_t
6921
  convert_valid_utf32_to_utf16le(const char32_t *input, size_t length,
6922
                                 char16_t *utf16_buffer) const noexcept = 0;
6923
6924
  /**
6925
   * Convert valid UTF-32 string into UTF-16BE string.
6926
   *
6927
   * This function assumes that the input string is valid UTF-32.
6928
   *
6929
   * This function is not BOM-aware.
6930
   *
6931
   * @param input         the UTF-32 string to convert
6932
   * @param length        the length of the string in 4-byte code units
6933
   * (char32_t)
6934
   * @param utf16_buffer   the pointer to a buffer that can hold the conversion
6935
   * result
6936
   * @return number of written code units; 0 if conversion is not possible
6937
   */
6938
  simdutf_warn_unused virtual size_t
6939
  convert_valid_utf32_to_utf16be(const char32_t *input, size_t length,
6940
                                 char16_t *utf16_buffer) const noexcept = 0;
6941
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
6942
6943
#if SIMDUTF_FEATURE_UTF16
6944
  /**
6945
   * Change the endianness of the input. Can be used to go from UTF-16LE to
6946
   * UTF-16BE or from UTF-16BE to UTF-16LE.
6947
   *
6948
   * This function does not validate the input.
6949
   *
6950
   * This function is not BOM-aware.
6951
   *
6952
   * @param input         the UTF-16 string to process
6953
   * @param length        the length of the string in 2-byte code units
6954
   * (char16_t)
6955
   * @param output        the pointer to a buffer that can hold the conversion
6956
   * result
6957
   */
6958
  virtual void change_endianness_utf16(const char16_t *input, size_t length,
6959
                                       char16_t *output) const noexcept = 0;
6960
#endif // SIMDUTF_FEATURE_UTF16
6961
6962
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
6963
  /**
6964
   * Return the number of bytes that this Latin1 string would require in UTF-8
6965
   * format.
6966
   *
6967
   * @param input         the Latin1 string to convert
6968
   * @param length        the length of the string bytes
6969
   * @return the number of bytes required to encode the Latin1 string as UTF-8
6970
   */
6971
  simdutf_warn_unused virtual size_t
6972
  utf8_length_from_latin1(const char *input, size_t length) const noexcept = 0;
6973
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
6974
6975
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6976
  /**
6977
   * Compute the number of bytes that this UTF-32 string would require in UTF-8
6978
   * format.
6979
   *
6980
   * This function does not validate the input. It is acceptable to pass invalid
6981
   * UTF-32 strings but in such cases the result is implementation defined.
6982
   *
6983
   * @param input         the UTF-32 string to convert
6984
   * @param length        the length of the string in 4-byte code units
6985
   * (char32_t)
6986
   * @return the number of bytes required to encode the UTF-32 string as UTF-8
6987
   */
6988
  simdutf_warn_unused virtual size_t
6989
  utf8_length_from_utf32(const char32_t *input,
6990
                         size_t length) const noexcept = 0;
6991
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32
6992
6993
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
6994
  /**
6995
   * Compute the number of bytes that this UTF-32 string would require in Latin1
6996
   * format.
6997
   *
6998
   * This function does not validate the input. It is acceptable to pass invalid
6999
   * UTF-32 strings but in such cases the result is implementation defined.
7000
   *
7001
   * @param length        the length of the string in 4-byte code units
7002
   * (char32_t)
7003
   * @return the number of bytes required to encode the UTF-32 string as Latin1
7004
   */
7005
  simdutf_warn_unused virtual size_t
7006
  latin1_length_from_utf32(size_t length) const noexcept {
7007
    return length;
7008
  }
7009
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
7010
7011
#if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
7012
  /**
7013
   * Compute the number of bytes that this UTF-8 string would require in Latin1
7014
   * format.
7015
   *
7016
   * This function does not validate the input. It is acceptable to pass invalid
7017
   * UTF-8 strings but in such cases the result is implementation defined.
7018
   *
7019
   * @param input         the UTF-8 string to convert
7020
   * @param length        the length of the string in byte
7021
   * @return the number of bytes required to encode the UTF-8 string as Latin1
7022
   */
7023
  simdutf_warn_unused virtual size_t
7024
  latin1_length_from_utf8(const char *input, size_t length) const noexcept = 0;
7025
#endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1
7026
7027
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
7028
  /**
7029
   * Compute the number of bytes that this UTF-16LE/BE string would require in
7030
   * Latin1 format.
7031
   *
7032
   * This function does not validate the input. It is acceptable to pass invalid
7033
   * UTF-16 strings but in such cases the result is implementation defined.
7034
   *
7035
   * This function is not BOM-aware.
7036
   *
7037
   * @param length        the length of the string in 2-byte code units
7038
   * (char16_t)
7039
   * @return the number of bytes required to encode the UTF-16LE string as
7040
   * Latin1
7041
   */
7042
  simdutf_warn_unused virtual size_t
7043
  latin1_length_from_utf16(size_t length) const noexcept {
7044
    return length;
7045
  }
7046
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1
7047
7048
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
7049
  /**
7050
   * Compute the number of two-byte code units that this UTF-32 string would
7051
   * require in UTF-16 format.
7052
   *
7053
   * This function does not validate the input. It is acceptable to pass invalid
7054
   * UTF-32 strings but in such cases the result is implementation defined.
7055
   *
7056
   * @param input         the UTF-32 string to convert
7057
   * @param length        the length of the string in 4-byte code units
7058
   * (char32_t)
7059
   * @return the number of bytes required to encode the UTF-32 string as UTF-16
7060
   */
7061
  simdutf_warn_unused virtual size_t
7062
  utf16_length_from_utf32(const char32_t *input,
7063
                          size_t length) const noexcept = 0;
7064
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
7065
7066
#if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
7067
  /**
7068
   * Return the number of bytes that this UTF-32 string would require in Latin1
7069
   * format.
7070
   *
7071
   * @param length        the length of the string in 4-byte code units
7072
   * (char32_t)
7073
   * @return the number of bytes required to encode the UTF-32 string as Latin1
7074
   */
7075
  simdutf_warn_unused virtual size_t
7076
  utf32_length_from_latin1(size_t length) const noexcept {
7077
    return length;
7078
  }
7079
#endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1
7080
7081
#if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
7082
  /**
7083
   * Compute the number of bytes that this UTF-16LE string would require in
7084
   * UTF-32 format.
7085
   *
7086
   * This function is equivalent to count_utf16le.
7087
   *
7088
   * This function does not validate the input. It is acceptable to pass invalid
7089
   * UTF-16 strings but in such cases the result is implementation defined.
7090
   *
7091
   * This function is not BOM-aware.
7092
   *
7093
   * @param input         the UTF-16LE string to convert
7094
   * @param length        the length of the string in 2-byte code units
7095
   * (char16_t)
7096
   * @return the number of bytes required to encode the UTF-16LE string as
7097
   * UTF-32
7098
   */
7099
  simdutf_warn_unused virtual size_t
7100
  utf32_length_from_utf16le(const char16_t *input,
7101
                            size_t length) const noexcept = 0;
7102
7103
  /**
7104
   * Compute the number of bytes that this UTF-16BE string would require in
7105
   * UTF-32 format.
7106
   *
7107
   * This function is equivalent to count_utf16be.
7108
   *
7109
   * This function does not validate the input. It is acceptable to pass invalid
7110
   * UTF-16 strings but in such cases the result is implementation defined.
7111
   *
7112
   * This function is not BOM-aware.
7113
   *
7114
   * @param input         the UTF-16BE string to convert
7115
   * @param length        the length of the string in 2-byte code units
7116
   * (char16_t)
7117
   * @return the number of bytes required to encode the UTF-16BE string as
7118
   * UTF-32
7119
   */
7120
  simdutf_warn_unused virtual size_t
7121
  utf32_length_from_utf16be(const char16_t *input,
7122
                            size_t length) const noexcept = 0;
7123
#endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32
7124
7125
#if SIMDUTF_FEATURE_UTF16
7126
  /**
7127
   * Count the number of code points (characters) in the string assuming that
7128
   * it is valid.
7129
   *
7130
   * This function assumes that the input string is valid UTF-16LE.
7131
   * It is acceptable to pass invalid UTF-16 strings but in such cases
7132
   * the result is implementation defined.
7133
   *
7134
   * This function is not BOM-aware.
7135
   *
7136
   * @param input         the UTF-16LE string to process
7137
   * @param length        the length of the string in 2-byte code units
7138
   * (char16_t)
7139
   * @return number of code points
7140
   */
7141
  simdutf_warn_unused virtual size_t
7142
  count_utf16le(const char16_t *input, size_t length) const noexcept = 0;
7143
7144
  /**
7145
   * Count the number of code points (characters) in the string assuming that
7146
   * it is valid.
7147
   *
7148
   * This function assumes that the input string is valid UTF-16BE.
7149
   * It is acceptable to pass invalid UTF-16 strings but in such cases
7150
   * the result is implementation defined.
7151
   *
7152
   * This function is not BOM-aware.
7153
   *
7154
   * @param input         the UTF-16BE string to process
7155
   * @param length        the length of the string in 2-byte code units
7156
   * (char16_t)
7157
   * @return number of code points
7158
   */
7159
  simdutf_warn_unused virtual size_t
7160
  count_utf16be(const char16_t *input, size_t length) const noexcept = 0;
7161
#endif // SIMDUTF_FEATURE_UTF16
7162
7163
#if SIMDUTF_FEATURE_UTF8
7164
  /**
7165
   * Count the number of code points (characters) in the string assuming that
7166
   * it is valid.
7167
   *
7168
   * This function assumes that the input string is valid UTF-8.
7169
   * It is acceptable to pass invalid UTF-8 strings but in such cases
7170
   * the result is implementation defined.
7171
   *
7172
   * @param input         the UTF-8 string to process
7173
   * @param length        the length of the string in bytes
7174
   * @return number of code points
7175
   */
7176
  simdutf_warn_unused virtual size_t
7177
  count_utf8(const char *input, size_t length) const noexcept = 0;
7178
#endif // SIMDUTF_FEATURE_UTF8
7179
7180
#if SIMDUTF_FEATURE_BASE64
7181
  /**
7182
   * Provide the maximal binary length in bytes given the base64 input.
7183
   * As long as the input does not contain ignorable characters (e.g., ASCII
7184
   * spaces or linefeed characters), the result is exact. In particular, the
7185
   * function checks for padding characters.
7186
   *
7187
   * The function is fast (constant time). It checks up to two characters at
7188
   * the end of the string. The input is not otherwise validated or read..
7189
   *
7190
   * @param input         the base64 input to process
7191
   * @param length        the length of the base64 input in bytes
7192
   * @return maximal number of binary bytes
7193
   */
7194
  simdutf_warn_unused size_t maximal_binary_length_from_base64(
7195
      const char *input, size_t length) const noexcept;
7196
7197
  /**
7198
   * Provide the maximal binary length in bytes given the base64 input.
7199
   * As long as the input does not contain ignorable characters (e.g., ASCII
7200
   * spaces or linefeed characters), the result is exact. In particular, the
7201
   * function checks for padding characters.
7202
   *
7203
   * The function is fast (constant time). It checks up to two characters at
7204
   * the end of the string. The input is not otherwise validated or read.
7205
   *
7206
   * @param input         the base64 input to process, in ASCII stored as 16-bit
7207
   * units
7208
   * @param length        the length of the base64 input in 16-bit units
7209
   * @return maximal number of binary bytes
7210
   */
7211
  simdutf_warn_unused size_t maximal_binary_length_from_base64(
7212
      const char16_t *input, size_t length) const noexcept;
7213
7214
  /**
7215
   * Compute the binary length from a base64 input with ASCII spaces.
7216
   * This function is useful for well-formed base64 inputs that may contain
7217
   * ASCII spaces (such as line breaks). For such inputs, the result is exact.
7218
   *
7219
   * The function counts non-whitespace characters (ASCII value > 0x20) and
7220
   * subtracts padding characters ('=') found at the end.
7221
   *
7222
   * @param input         the base64 input to process
7223
   * @param length        the length of the base64 input in bytes
7224
   * @return number of binary bytes
7225
   */
7226
  simdutf_warn_unused virtual size_t
7227
  binary_length_from_base64(const char *input, size_t length) const noexcept;
7228
7229
  /**
7230
   * Compute the binary length from a base64 input with ASCII spaces.
7231
   * This function is useful for well-formed base64 inputs that may contain
7232
   * ASCII spaces (such as line breaks). For such inputs, the result is exact.
7233
   *
7234
   * The function counts non-whitespace characters (ASCII value > 0x20) and
7235
   * subtracts padding characters ('=') found at the end.
7236
   *
7237
   * @param input         the base64 input to process, in ASCII stored as 16-bit
7238
   * units
7239
   * @param length        the length of the base64 input in 16-bit units
7240
   * @return number of binary bytes
7241
   */
7242
  simdutf_warn_unused virtual size_t
7243
  binary_length_from_base64(const char16_t *input,
7244
                            size_t length) const noexcept;
7245
7246
  /**
7247
   * Convert a base64 input to a binary output.
7248
   *
7249
   * This function follows the WHATWG forgiving-base64 format, which means that
7250
   * it will ignore any ASCII spaces in the input. You may provide a padded
7251
   * input (with one or two equal signs at the end) or an unpadded input
7252
   * (without any equal signs at the end).
7253
   *
7254
   * See https://infra.spec.whatwg.org/#forgiving-base64-decode
7255
   *
7256
   * This function will fail in case of invalid input. When last_chunk_options =
7257
   * loose, there are two possible reasons for failure: the input contains a
7258
   * number of base64 characters that when divided by 4, leaves a single
7259
   * remainder character (BASE64_INPUT_REMAINDER), or the input contains a
7260
   * character that is not a valid base64 character (INVALID_BASE64_CHARACTER).
7261
   *
7262
   * You should call this function with a buffer that is at least
7263
   * maximal_binary_length_from_base64(input, length) bytes long. If you fail to
7264
   * provide that much space, the function may cause a buffer overflow.
7265
   *
7266
   * @param input         the base64 string to process
7267
   * @param length        the length of the string in bytes
7268
   * @param output        the pointer to a buffer that can hold the conversion
7269
   * result (should be at least maximal_binary_length_from_base64(input, length)
7270
   * bytes long).
7271
   * @param options       the base64 options to use, can be base64_default or
7272
   * base64_url, is base64_default by default.
7273
   * @param last_chunk_options the handling of the last chunk (default: loose)
7274
   * @return a result pair struct (of type simdutf::result containing the two
7275
   * fields error and count) with an error code and either position of the error
7276
   * (in the input in bytes) if any, or the number of bytes written if
7277
   * successful.
7278
   */
7279
  simdutf_warn_unused virtual result
7280
  base64_to_binary(const char *input, size_t length, char *output,
7281
                   base64_options options = base64_default,
7282
                   last_chunk_handling_options last_chunk_options =
7283
                       last_chunk_handling_options::loose) const noexcept = 0;
7284
7285
  /**
7286
   * Convert a base64 input to a binary output while returning more details
7287
   * than base64_to_binary.
7288
   *
7289
   * This function follows the WHATWG forgiving-base64 format, which means that
7290
   * it will ignore any ASCII spaces in the input. You may provide a padded
7291
   * input (with one or two equal signs at the end) or an unpadded input
7292
   * (without any equal signs at the end).
7293
   *
7294
   * See https://infra.spec.whatwg.org/#forgiving-base64-decode
7295
   *
7296
   * This function will fail in case of invalid input. When last_chunk_options =
7297
   * loose, there are two possible reasons for failure: the input contains a
7298
   * number of base64 characters that when divided by 4, leaves a single
7299
   * remainder character (BASE64_INPUT_REMAINDER), or the input contains a
7300
   * character that is not a valid base64 character (INVALID_BASE64_CHARACTER).
7301
   *
7302
   * You should call this function with a buffer that is at least
7303
   * maximal_binary_length_from_base64(input, length) bytes long. If you fail to
7304
   * provide that much space, the function may cause a buffer overflow.
7305
   *
7306
   * @param input         the base64 string to process
7307
   * @param length        the length of the string in bytes
7308
   * @param output        the pointer to a buffer that can hold the conversion
7309
   * result (should be at least maximal_binary_length_from_base64(input, length)
7310
   * bytes long).
7311
   * @param options       the base64 options to use, can be base64_default or
7312
   * base64_url, is base64_default by default.
7313
   * @param last_chunk_options the handling of the last chunk (default: loose)
7314
   * @return a full_result pair struct (of type simdutf::result containing the
7315
   * three fields error, input_count and output_count).
7316
   */
7317
  simdutf_warn_unused virtual full_result base64_to_binary_details(
7318
      const char *input, size_t length, char *output,
7319
      base64_options options = base64_default,
7320
      last_chunk_handling_options last_chunk_options =
7321
          last_chunk_handling_options::loose) const noexcept = 0;
7322
7323
  /**
7324
   * Convert a base64 input to a binary output.
7325
   *
7326
   * This function follows the WHATWG forgiving-base64 format, which means that
7327
   * it will ignore any ASCII spaces in the input. You may provide a padded
7328
   * input (with one or two equal signs at the end) or an unpadded input
7329
   * (without any equal signs at the end).
7330
   *
7331
   * See https://infra.spec.whatwg.org/#forgiving-base64-decode
7332
   *
7333
   * This function will fail in case of invalid input. When last_chunk_options =
7334
   * loose, there are two possible reasons for failure: the input contains a
7335
   * number of base64 characters that when divided by 4, leaves a single
7336
   * remainder character (BASE64_INPUT_REMAINDER), or the input contains a
7337
   * character that is not a valid base64 character (INVALID_BASE64_CHARACTER).
7338
   *
7339
   * You should call this function with a buffer that is at least
7340
   * maximal_binary_length_from_base64(input, length) bytes long. If you
7341
   * fail to provide that much space, the function may cause a buffer overflow.
7342
   *
7343
   * @param input         the base64 string to process, in ASCII stored as
7344
   * 16-bit units
7345
   * @param length        the length of the string in 16-bit units
7346
   * @param output        the pointer to a buffer that can hold the conversion
7347
   * result (should be at least maximal_binary_length_from_base64(input, length)
7348
   * bytes long).
7349
   * @param options       the base64 options to use, can be base64_default or
7350
   * base64_url, is base64_default by default.
7351
   * @param last_chunk_options the handling of the last chunk (default: loose)
7352
   * @return a result pair struct (of type simdutf::result containing the two
7353
   * fields error and count) with an error code and position of the
7354
   * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the
7355
   * number of bytes written if successful.
7356
   */
7357
  simdutf_warn_unused virtual result
7358
  base64_to_binary(const char16_t *input, size_t length, char *output,
7359
                   base64_options options = base64_default,
7360
                   last_chunk_handling_options last_chunk_options =
7361
                       last_chunk_handling_options::loose) const noexcept = 0;
7362
7363
  /**
7364
   * Convert a base64 input to a binary output while returning more details
7365
   * than base64_to_binary.
7366
   *
7367
   * This function follows the WHATWG forgiving-base64 format, which means that
7368
   * it will ignore any ASCII spaces in the input. You may provide a padded
7369
   * input (with one or two equal signs at the end) or an unpadded input
7370
   * (without any equal signs at the end).
7371
   *
7372
   * See https://infra.spec.whatwg.org/#forgiving-base64-decode
7373
   *
7374
   * This function will fail in case of invalid input. When last_chunk_options =
7375
   * loose, there are two possible reasons for failure: the input contains a
7376
   * number of base64 characters that when divided by 4, leaves a single
7377
   * remainder character (BASE64_INPUT_REMAINDER), or the input contains a
7378
   * character that is not a valid base64 character (INVALID_BASE64_CHARACTER).
7379
   *
7380
   * You should call this function with a buffer that is at least
7381
   * maximal_binary_length_from_base64(input, length) bytes long. If you fail to
7382
   * provide that much space, the function may cause a buffer overflow.
7383
   *
7384
   * @param input         the base64 string to process
7385
   * @param length        the length of the string in bytes
7386
   * @param output        the pointer to a buffer that can hold the conversion
7387
   * result (should be at least maximal_binary_length_from_base64(input, length)
7388
   * bytes long).
7389
   * @param options       the base64 options to use, can be base64_default or
7390
   * base64_url, is base64_default by default.
7391
   * @param last_chunk_options the handling of the last chunk (default: loose)
7392
   * @return a full_result pair struct (of type simdutf::result containing the
7393
   * three fields error, input_count and output_count).
7394
   */
7395
  simdutf_warn_unused virtual full_result base64_to_binary_details(
7396
      const char16_t *input, size_t length, char *output,
7397
      base64_options options = base64_default,
7398
      last_chunk_handling_options last_chunk_options =
7399
          last_chunk_handling_options::loose) const noexcept = 0;
7400
7401
  /**
7402
   * Provide the base64 length in bytes given the length of a binary input.
7403
   *
7404
   * @param length        the length of the input in bytes
7405
   * @param options       the base64 options to use, can be base64_default or
7406
   * base64_url, is base64_default by default.
7407
   * @return number of base64 bytes
7408
   */
7409
  simdutf_warn_unused size_t base64_length_from_binary(
7410
      size_t length, base64_options options = base64_default) const noexcept;
7411
7412
  /**
7413
   * Convert a binary input to a base64 output.
7414
   *
7415
   * The default option (simdutf::base64_default) uses the characters `+` and
7416
   * `/` as part of its alphabet. Further, it adds padding (`=`) at the end of
7417
   * the output to ensure that the output length is a multiple of four.
7418
   *
7419
   * The URL option (simdutf::base64_url) uses the characters `-` and `_` as
7420
   * part of its alphabet. No padding is added at the end of the output.
7421
   *
7422
   * This function always succeeds.
7423
   *
7424
   * @param input         the binary to process
7425
   * @param length        the length of the input in bytes
7426
   * @param output        the pointer to a buffer that can hold the conversion
7427
   * result (should be at least base64_length_from_binary(length) bytes long)
7428
   * @param options       the base64 options to use, can be base64_default or
7429
   * base64_url, is base64_default by default.
7430
   * @return number of written bytes, will be equal to
7431
   * base64_length_from_binary(length, options)
7432
   */
7433
  virtual size_t
7434
  binary_to_base64(const char *input, size_t length, char *output,
7435
                   base64_options options = base64_default) const noexcept = 0;
7436
7437
  /**
7438
   * Convert a binary input to a base64 output with lines of given length.
7439
   * Lines are separated by a single linefeed character.
7440
   *
7441
   * The default option (simdutf::base64_default) uses the characters `+` and
7442
   * `/` as part of its alphabet. Further, it adds padding (`=`) at the end of
7443
   * the output to ensure that the output length is a multiple of four.
7444
   *
7445
   * The URL option (simdutf::base64_url) uses the characters `-` and `_` as
7446
   * part of its alphabet. No padding is added at the end of the output.
7447
   *
7448
   * This function always succeeds.
7449
   *
7450
   * @param input         the binary to process
7451
   * @param length        the length of the input in bytes
7452
   * @param output        the pointer to a buffer that can hold the conversion
7453
   * result (should be at least base64_length_from_binary_with_lines(length,
7454
   * options, line_length) bytes long)
7455
   * @param line_length   the length of each line, values smaller than 4 are
7456
   * interpreted as 4
7457
   * @param options       the base64 options to use, can be base64_default or
7458
   * base64_url, is base64_default by default.
7459
   * @return number of written bytes, will be equal to
7460
   * base64_length_from_binary_with_lines(length, options, line_length)
7461
   */
7462
  virtual size_t binary_to_base64_with_lines(
7463
      const char *input, size_t length, char *output,
7464
      size_t line_length = simdutf::default_line_length,
7465
      base64_options options = base64_default) const noexcept = 0;
7466
7467
  /**
7468
   * Find the first occurrence of a character in a string. If the character is
7469
   * not found, return a pointer to the end of the string.
7470
   * @param start        the start of the string
7471
   * @param end          the end of the string
7472
   * @param character    the character to find
7473
   * @return a pointer to the first occurrence of the character in the string,
7474
   * or a pointer to the end of the string if the character is not found.
7475
   *
7476
   */
7477
  virtual const char *find(const char *start, const char *end,
7478
                           char character) const noexcept = 0;
7479
  virtual const char16_t *find(const char16_t *start, const char16_t *end,
7480
                               char16_t character) const noexcept = 0;
7481
#endif // SIMDUTF_FEATURE_BASE64
7482
7483
#ifdef SIMDUTF_INTERNAL_TESTS
7484
  // This method is exported only in developer mode, its purpose
7485
  // is to expose some internal test procedures from the given
7486
  // implementation and then use them through our standard test
7487
  // framework.
7488
  //
7489
  // Regular users should not use it, the tests of the public
7490
  // API are enough.
7491
7492
  struct TestProcedure {
7493
    // display name
7494
    std::string_view name;
7495
7496
    // procedure should return whether given test pass or not
7497
    void (*procedure)(const implementation &);
7498
  };
7499
7500
  virtual std::vector<TestProcedure> internal_tests() const;
7501
#endif
7502
7503
protected:
7504
  /** @private Construct an implementation with the given name and description.
7505
   * For subclasses.
7506
   * @param name the name of this implementation
7507
   * @param description a description of this implementation
7508
   * @param required_instruction_sets the instruction sets this implementation
7509
   * requires
7510
   */
7511
  simdutf_really_inline implementation(const char *name,
7512
                                       const char *description,
7513
                                       uint32_t required_instruction_sets)
7514
      : _name(name), _description(description),
7515
        _required_instruction_sets(required_instruction_sets) {}
7516
7517
protected:
7518
  ~implementation() = default;
7519
7520
private:
7521
  /**
7522
   * The name of this implementation.
7523
   */
7524
  const char *_name;
7525
7526
  /**
7527
   * The description of this implementation.
7528
   */
7529
  const char *_description;
7530
7531
  /**
7532
   * Instruction sets required for this implementation.
7533
   */
7534
  const uint32_t _required_instruction_sets;
7535
};
7536
7537
/** @private */
7538
namespace internal {
7539
7540
/**
7541
 * The list of available implementations compiled into simdutf.
7542
 */
7543
class available_implementation_list {
7544
public:
7545
  /** Get the list of available implementations compiled into simdutf */
7546
  simdutf_really_inline available_implementation_list() {}
7547
  /** Number of implementations */
7548
  size_t size() const noexcept;
7549
  /** STL const begin() iterator */
7550
  const implementation *const *begin() const noexcept;
7551
  /** STL const end() iterator */
7552
  const implementation *const *end() const noexcept;
7553
7554
  /**
7555
   * Get the implementation with the given name.
7556
   *
7557
   * Case sensitive.
7558
   *
7559
   *     const implementation *impl =
7560
   * simdutf::available_implementations["westmere"]; if (!impl) { exit(1); } if
7561
   * (!imp->supported_by_runtime_system()) { exit(1); }
7562
   *     simdutf::active_implementation = impl;
7563
   *
7564
   * @param name the implementation to find, e.g. "westmere", "haswell", "arm64"
7565
   * @return the implementation, or nullptr if the parse failed.
7566
   */
7567
  const implementation *operator[](std::string_view name) const noexcept {
7568
    for (const implementation *impl : *this) {
7569
      if (impl->name() == name) {
7570
        return impl;
7571
      }
7572
    }
7573
    return nullptr;
7574
  }
7575
7576
  /**
7577
   * Detect the most advanced implementation supported by the current host.
7578
   *
7579
   * This is used to initialize the implementation on startup.
7580
   *
7581
   *     const implementation *impl =
7582
   * simdutf::available_implementation::detect_best_supported();
7583
   *     simdutf::active_implementation = impl;
7584
   *
7585
   * @return the most advanced supported implementation for the current host, or
7586
   * an implementation that returns UNSUPPORTED_ARCHITECTURE if there is no
7587
   * supported implementation. Will never return nullptr.
7588
   */
7589
  const implementation *detect_best_supported() const noexcept;
7590
};
7591
7592
template <typename T> class atomic_ptr {
7593
public:
7594
  atomic_ptr(T *_ptr) : ptr{_ptr} {}
7595
7596
#if defined(SIMDUTF_NO_THREADS)
7597
  operator const T *() const { return ptr; }
7598
  const T &operator*() const { return *ptr; }
7599
  const T *operator->() const { return ptr; }
7600
7601
  operator T *() { return ptr; }
7602
  T &operator*() { return *ptr; }
7603
  T *operator->() { return ptr; }
7604
  atomic_ptr &operator=(T *_ptr) {
7605
    ptr = _ptr;
7606
    return *this;
7607
  }
7608
7609
#else
7610
  operator const T *() const { return ptr.load(); }
7611
  const T &operator*() const { return *ptr; }
7612
  const T *operator->() const { return ptr.load(); }
7613
7614
  operator T *() { return ptr.load(); }
7615
  T &operator*() { return *ptr; }
7616
  T *operator->() { return ptr.load(); }
7617
  atomic_ptr &operator=(T *_ptr) {
7618
    ptr = _ptr;
7619
    return *this;
7620
  }
7621
7622
#endif
7623
7624
private:
7625
#if defined(SIMDUTF_NO_THREADS)
7626
  T *ptr;
7627
#else
7628
  std::atomic<T *> ptr;
7629
#endif
7630
};
7631
7632
class detect_best_supported_implementation_on_first_use;
7633
7634
} // namespace internal
7635
7636
/**
7637
 * The list of available implementations compiled into simdutf.
7638
 */
7639
extern SIMDUTF_DLLIMPORTEXPORT const internal::available_implementation_list &
7640
get_available_implementations();
7641
7642
/**
7643
 * The active implementation.
7644
 *
7645
 * Automatically initialized on first use to the most advanced implementation
7646
 * supported by this hardware.
7647
 */
7648
extern SIMDUTF_DLLIMPORTEXPORT internal::atomic_ptr<const implementation> &
7649
get_active_implementation();
7650
7651
} // namespace simdutf
7652
7653
#if SIMDUTF_FEATURE_BASE64
7654
  // this header is not part of the public api
7655
  #include <simdutf/base64_implementation.h>
7656
7657
namespace simdutf {
7658
  #if SIMDUTF_SPAN
7659
/**
7660
 * @brief span overload
7661
 * @return a tuple of result and outlen
7662
 */
7663
simdutf_really_inline
7664
    simdutf_constexpr23 simdutf_warn_unused std::tuple<result, std::size_t>
7665
    base64_to_binary_safe(
7666
        const detail::input_span_of_byte_like auto &input,
7667
        detail::output_span_of_byte_like auto &&binary_output,
7668
        base64_options options = base64_default,
7669
        last_chunk_handling_options last_chunk_options = loose,
7670
        bool decode_up_to_bad_char = false) noexcept {
7671
  size_t outlen = binary_output.size();
7672
    #if SIMDUTF_CPLUSPLUS23
7673
  if consteval {
7674
    using CInput = std::decay_t<decltype(*input.data())>;
7675
    static_assert(std::is_same_v<CInput, char>,
7676
                  "sorry, the constexpr implementation is for now limited to "
7677
                  "input of type char");
7678
    using COutput = std::decay_t<decltype(*binary_output.data())>;
7679
    static_assert(std::is_same_v<COutput, char>,
7680
                  "sorry, the constexpr implementation is for now limited to "
7681
                  "output of type char");
7682
    auto r = base64_to_binary_safe_impl(
7683
        input.data(), input.size(), binary_output.data(), outlen, options,
7684
        last_chunk_options, decode_up_to_bad_char);
7685
    return {r, outlen};
7686
  } else
7687
    #endif
7688
  {
7689
    auto r = base64_to_binary_safe_impl<char>(
7690
        reinterpret_cast<const char *>(input.data()), input.size(),
7691
        reinterpret_cast<char *>(binary_output.data()), outlen, options,
7692
        last_chunk_options, decode_up_to_bad_char);
7693
    return {r, outlen};
7694
  }
7695
}
7696
7697
    #if SIMDUTF_SPAN
7698
/**
7699
 * @brief span overload
7700
 * @return a tuple of result and outlen
7701
 */
7702
simdutf_really_inline
7703
    simdutf_warn_unused simdutf_constexpr23 std::tuple<result, std::size_t>
7704
    base64_to_binary_safe(
7705
        std::span<const char16_t> input,
7706
        detail::output_span_of_byte_like auto &&binary_output,
7707
        base64_options options = base64_default,
7708
        last_chunk_handling_options last_chunk_options = loose,
7709
        bool decode_up_to_bad_char = false) noexcept {
7710
  size_t outlen = binary_output.size();
7711
      #if SIMDUTF_CPLUSPLUS23
7712
  if consteval {
7713
    auto r = base64_to_binary_safe_impl(
7714
        input.data(), input.size(), binary_output.data(), outlen, options,
7715
        last_chunk_options, decode_up_to_bad_char);
7716
    return {r, outlen};
7717
  } else
7718
      #endif
7719
  {
7720
    auto r = base64_to_binary_safe(
7721
        input.data(), input.size(),
7722
        reinterpret_cast<char *>(binary_output.data()), outlen, options,
7723
        last_chunk_options, decode_up_to_bad_char);
7724
    return {r, outlen};
7725
  }
7726
}
7727
    #endif // SIMDUTF_SPAN
7728
7729
  #endif // SIMDUTF_SPAN
7730
} // namespace simdutf
7731
7732
#endif // SIMDUTF_FEATURE_BASE64
7733
7734
#if SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64
7735
7736
namespace simdutf {
7737
namespace literals {
7738
7739
namespace detail {
7740
7741
// the detail namespace is not part of the public api
7742
7743
template <std::size_t N> struct base64_literal_helper {
7744
  std::array<char, N - 1> storage{};
7745
  static constexpr std::size_t size() noexcept { return N - 1; }
7746
  consteval base64_literal_helper(const char (&str)[N]) {
7747
    for (std::size_t i = 0; i < size(); i++) {
7748
      storage[i] = str[i];
7749
    }
7750
  }
7751
};
7752
7753
template <std::size_t InputLen> struct base64_decode_result {
7754
  static constexpr std::size_t max_out = (InputLen + 3) / 4 * 3;
7755
  std::array<char, max_out> buffer{};
7756
  std::size_t output_count{};
7757
};
7758
7759
template <std::size_t InputLen>
7760
consteval auto base64_decode_literal(const char *str) {
7761
  base64_decode_result<InputLen> result{};
7762
  auto r = scalar::base64::base64_to_binary_details_impl(
7763
      str, InputLen, result.buffer.data(), base64_default, loose);
7764
  if (r.error != error_code::SUCCESS) {
7765
  #if __cpp_lib_unreachable >= 202202L
7766
    std::unreachable(); // invalid base64 input in _base64 literal
7767
  #else
7768
    // workaround for older stdlib
7769
    throw "invalid base64 input in _base64 literal";
7770
  #endif
7771
  }
7772
  result.output_count = r.output_count;
7773
  return result;
7774
}
7775
7776
template <base64_literal_helper a> consteval auto base64_make_array() {
7777
  constexpr auto decoded = base64_decode_literal<a.size()>(a.storage.data());
7778
  std::array<char, decoded.output_count> ret{};
7779
  for (std::size_t i = 0; i < decoded.output_count; i++) {
7780
    ret[i] = decoded.buffer[i];
7781
  }
7782
  return ret;
7783
}
7784
7785
} // namespace detail
7786
7787
/**
7788
 * User-defined literal for compile-time base64 decoding.
7789
 *
7790
 * Usage:
7791
 *   using namespace simdutf::literals;
7792
 *   constexpr auto decoded = "SGVsbG8gV29ybGQh"_base64;
7793
 *   // decoded is a std::array<char, 12> containing "Hello World!"
7794
 *
7795
 * The input must be valid base64. Whitepace is allowed and ignored.
7796
 * A compilation error occurs if the input is invalid.
7797
 */
7798
template <detail::base64_literal_helper a> consteval auto operator""_base64() {
7799
  return detail::base64_make_array<a>();
7800
}
7801
7802
} // namespace literals
7803
} // namespace simdutf
7804
7805
#endif // SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64
7806
7807
#endif // SIMDUTF_IMPLEMENTATION_H