Coverage Report

Created: 2026-09-14 07:00

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