Coverage Report

Created: 2026-07-25 06:54

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