#ifndef SIMDUTF_IMPLEMENTATION_H #define SIMDUTF_IMPLEMENTATION_H #if !defined(SIMDUTF_NO_THREADS) #include #endif #ifdef SIMDUTF_INTERNAL_TESTS #include #endif #include "simdutf/common_defs.h" #include "simdutf/compiler_check.h" #include "simdutf/encoding_types.h" #include "simdutf/error.h" #include "simdutf/internal/isadetection.h" #include #if SIMDUTF_SPAN #include #include #include #include #include // for std::unreachable #endif // The following defines are conditionally enabled/disabled during amalgamation. // By default all features are enabled, regular code shouldn't check them. Only // when user code really relies of a selected subset, it's good to verify these // flags, like: // // #if !SIMDUTF_FEATURE_UTF16 // # error("Please amalgamate simdutf with UTF-16 support") // #endif // #ifndef SIMDUTF_FEATURE_DETECT_ENCODING #define SIMDUTF_FEATURE_DETECT_ENCODING 1 #endif #ifndef SIMDUTF_FEATURE_ASCII #define SIMDUTF_FEATURE_ASCII 1 #endif #ifndef SIMDUTF_FEATURE_LATIN1 #define SIMDUTF_FEATURE_LATIN1 1 #endif #ifndef SIMDUTF_FEATURE_UTF8 #define SIMDUTF_FEATURE_UTF8 1 #endif #ifndef SIMDUTF_FEATURE_UTF16 #define SIMDUTF_FEATURE_UTF16 1 #endif #ifndef SIMDUTF_FEATURE_UTF32 #define SIMDUTF_FEATURE_UTF32 1 #endif #ifndef SIMDUTF_FEATURE_BASE64 #define SIMDUTF_FEATURE_BASE64 1 #endif /// helpers placed in namespace detail are not a part of the public API namespace simdutf { namespace detail { namespace { // this is to avoid including just for min constexpr std::size_t min(std::size_t a, std::size_t b) { return a < b ? a : b; } template constexpr std::size_t min(const T &a, const U &b) = delete; } // namespace } // namespace detail } // namespace simdutf #if SIMDUTF_CPLUSPLUS23 #include #endif #if SIMDUTF_SPAN /// helpers placed in namespace detail are not a part of the public API namespace simdutf { namespace detail { /** * matches a byte, in the many ways C++ allows. note that these * are all distinct types. */ template concept byte_like = std::is_same_v || // std::is_same_v || // std::is_same_v || // std::is_same_v || // std::is_same_v; template concept is_byte_like = byte_like>; template concept is_pointer = std::is_pointer_v; /** * matches anything that behaves like std::span and points to character-like * data such as: std::byte, char, unsigned char, signed char, std::int8_t, * std::uint8_t */ template concept input_span_of_byte_like = requires(const T &t) { { t.size() } noexcept -> std::convertible_to; { t.data() } noexcept -> is_pointer; { *t.data() } noexcept -> is_byte_like; }; template concept is_mutable = !std::is_const_v>; /** * like span_of_byte_like, but for an output span (intended to be written to) */ template concept output_span_of_byte_like = requires(T &t) { { t.size() } noexcept -> std::convertible_to; { t.data() } noexcept -> is_pointer; { *t.data() } noexcept -> is_byte_like; { *t.data() } noexcept -> is_mutable; }; /** * a pointer like object, when indexed, results in a byte like result. * valid examples: char*, const char*, std::array * invalid examples: int*, std::array */ template concept indexes_into_byte_like = requires(InputPtr p) { { std::decay_t{} } -> simdutf::detail::byte_like; }; template concept indexes_into_utf16 = requires(InputPtr p) { { std::decay_t{} } -> std::same_as; }; template concept indexes_into_utf32 = requires(InputPtr p) { { std::decay_t{} } -> std::same_as; }; template concept index_assignable_from_char = requires(InputPtr p, char s) { { p[0] = s }; }; /** * a pointer like object that results in a uint32_t when indexed. * valid examples: uint32_t* */ template concept indexes_into_uint32 = requires(InputPtr p) { { std::decay_t{} } -> std::same_as; }; } // namespace detail } // namespace simdutf #endif // SIMDUTF_SPAN // these includes are needed for constexpr support. they are // not part of the public api. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace simdutf { constexpr size_t default_line_length = 76; ///< default line length for base64 encoding with lines #if SIMDUTF_FEATURE_DETECT_ENCODING /** * Autodetect the encoding of the input, a single encoding is recommended. * E.g., the function might return simdutf::encoding_type::UTF8, * simdutf::encoding_type::UTF16_LE, simdutf::encoding_type::UTF16_BE, or * simdutf::encoding_type::UTF32_LE. * * @param input the string to analyze. * @param length the length of the string in bytes. * @return the detected encoding type */ simdutf_warn_unused simdutf::encoding_type autodetect_encoding(const char *input, size_t length) noexcept; simdutf_really_inline simdutf_warn_unused simdutf::encoding_type autodetect_encoding(const uint8_t *input, size_t length) noexcept { return autodetect_encoding(reinterpret_cast(input), length); } #if SIMDUTF_SPAN /** * Autodetect the encoding of the input, a single encoding is recommended. * E.g., the function might return simdutf::encoding_type::UTF8, * simdutf::encoding_type::UTF16_LE, simdutf::encoding_type::UTF16_BE, or * simdutf::encoding_type::UTF32_LE. * * @param input the string to analyze. can be a anything span-like that has a * data() and size() that points to character data: std::string, * std::string_view, std::vector, std::span etc. * @return the detected encoding type */ simdutf_really_inline simdutf_warn_unused simdutf::encoding_type autodetect_encoding( const detail::input_span_of_byte_like auto &input) noexcept { return autodetect_encoding(reinterpret_cast(input.data()), input.size()); } #endif // SIMDUTF_SPAN /** * Autodetect the possible encodings of the input in one pass. * E.g., if the input might be UTF-16LE or UTF-8, this function returns * the value (simdutf::encoding_type::UTF8 | simdutf::encoding_type::UTF16_LE). * * Overridden by each implementation. * * @param input the string to analyze. * @param length the length of the string in bytes. * @return the detected encoding type */ simdutf_warn_unused int detect_encodings(const char *input, size_t length) noexcept; simdutf_really_inline simdutf_warn_unused int detect_encodings(const uint8_t *input, size_t length) noexcept { return detect_encodings(reinterpret_cast(input), length); } #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused int detect_encodings(const detail::input_span_of_byte_like auto &input) noexcept { return detect_encodings(reinterpret_cast(input.data()), input.size()); } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING /** * Validate the UTF-8 string. This function may be best when you expect * the input to be almost always valid. Otherwise, consider using * validate_utf8_with_errors. * * Overridden by each implementation. * * @param buf the UTF-8 string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid UTF-8. */ simdutf_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_constexpr23 simdutf_really_inline simdutf_warn_unused bool validate_utf8(const detail::input_span_of_byte_like auto &input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8::validate( detail::constexpr_cast_ptr(input.data()), input.size()); } else #endif { return validate_utf8(reinterpret_cast(input.data()), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 /** * Validate the UTF-8 string and stop on error. * * Overridden by each implementation. * * @param buf the UTF-8 string to validate. * @param len the length of the string in bytes. * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated if * successful. */ simdutf_warn_unused result validate_utf8_with_errors(const char *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result validate_utf8_with_errors( const detail::input_span_of_byte_like auto &input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8::validate_with_errors( detail::constexpr_cast_ptr(input.data()), input.size()); } else #endif { return validate_utf8_with_errors( reinterpret_cast(input.data()), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_ASCII /** * Validate the ASCII string. * * Overridden by each implementation. * * @param buf the ASCII string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ simdutf_warn_unused bool validate_ascii(const char *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool validate_ascii(const detail::input_span_of_byte_like auto &input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::ascii::validate( detail::constexpr_cast_ptr(input.data()), input.size()); } else #endif { return validate_ascii(reinterpret_cast(input.data()), input.size()); } } #endif // SIMDUTF_SPAN /** * Validate the ASCII string and stop on error. It might be faster than * validate_utf8 when an error is expected to occur early. * * Overridden by each implementation. * * @param buf the ASCII string to validate. * @param len the length of the string in bytes. * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated if * successful. */ simdutf_warn_unused result validate_ascii_with_errors(const char *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result validate_ascii_with_errors( const detail::input_span_of_byte_like auto &input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::ascii::validate_with_errors( detail::constexpr_cast_ptr(input.data()), input.size()); } else #endif { return validate_ascii_with_errors( reinterpret_cast(input.data()), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII /** * Validate the ASCII string as a UTF-16 sequence. * An UTF-16 sequence is considered an ASCII sequence * if it could be converted to an ASCII string losslessly. * * Overridden by each implementation. * * @param buf the UTF-16 string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ simdutf_warn_unused bool validate_utf16_as_ascii(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool validate_utf16_as_ascii(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate_as_ascii(input.data(), input.size()); } else #endif { return validate_utf16_as_ascii(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Validate the ASCII string as a UTF-16BE sequence. * An UTF-16 sequence is considered an ASCII sequence * if it could be converted to an ASCII string losslessly. * * Overridden by each implementation. * * @param buf the UTF-16BE string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ simdutf_warn_unused bool validate_utf16be_as_ascii(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool validate_utf16be_as_ascii(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate_as_ascii(input.data(), input.size()); } else #endif { return validate_utf16be_as_ascii(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Validate the ASCII string as a UTF-16LE sequence. * An UTF-16 sequence is considered an ASCII sequence * if it could be converted to an ASCII string losslessly. * * Overridden by each implementation. * * @param buf the UTF-16LE string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ simdutf_warn_unused bool validate_utf16le_as_ascii(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool validate_utf16le_as_ascii(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate_as_ascii(input.data(), input.size()); } else #endif { return validate_utf16le_as_ascii(input.data(), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 /** * Using native endianness; Validate the UTF-16 string. * This function may be best when you expect the input to be almost always * valid. Otherwise, consider using validate_utf16_with_errors. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16 string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return true if and only if the string is valid UTF-16. */ simdutf_warn_unused bool validate_utf16(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool validate_utf16(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate(input.data(), input.size()); } else #endif { return validate_utf16(input.data(), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING /** * Validate the UTF-16LE string. This function may be best when you expect * the input to be almost always valid. Otherwise, consider using * validate_utf16le_with_errors. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16LE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return true if and only if the string is valid UTF-16LE. */ simdutf_warn_unused bool validate_utf16le(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused bool validate_utf16le(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate(input.data(), input.size()); } else #endif { return validate_utf16le(input.data(), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF16 /** * Validate the UTF-16BE string. This function may be best when you expect * the input to be almost always valid. Otherwise, consider using * validate_utf16be_with_errors. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16BE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return true if and only if the string is valid UTF-16BE. */ simdutf_warn_unused bool validate_utf16be(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool validate_utf16be(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate(input.data(), input.size()); } else #endif { return validate_utf16be(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Using native endianness; Validate the UTF-16 string and stop on error. * It might be faster than validate_utf16 when an error is expected to occur * early. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16 string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated if * successful. */ simdutf_warn_unused result validate_utf16_with_errors(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result validate_utf16_with_errors(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate_with_errors( input.data(), input.size()); } else #endif { return validate_utf16_with_errors(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Validate the UTF-16LE string and stop on error. It might be faster than * validate_utf16le when an error is expected to occur early. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16LE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated if * successful. */ simdutf_warn_unused result validate_utf16le_with_errors(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result validate_utf16le_with_errors(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate_with_errors( input.data(), input.size()); } else #endif { return validate_utf16le_with_errors(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Validate the UTF-16BE string and stop on error. It might be faster than * validate_utf16be when an error is expected to occur early. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16BE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated if * successful. */ simdutf_warn_unused result validate_utf16be_with_errors(const char16_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result validate_utf16be_with_errors(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::validate_with_errors(input.data(), input.size()); } else #endif { return validate_utf16be_with_errors(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Fixes an ill-formed UTF-16LE string by replacing mismatched surrogates with * the Unicode replacement character U+FFFD. If input and output points to * different memory areas, the procedure copies string, and it's expected that * output memory is at least as big as the input. It's also possible to set * input equal output, that makes replacements an in-place operation. * * @param input the UTF-16LE string to correct. * @param len the length of the string in number of 2-byte code units * (char16_t). * @param output the output buffer. */ void to_well_formed_utf16le(const char16_t *input, size_t len, char16_t *output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 void to_well_formed_utf16le(std::span input, std::span output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { scalar::utf16::to_well_formed_utf16( input.data(), input.size(), output.data()); } else #endif { to_well_formed_utf16le(input.data(), input.size(), output.data()); } } #endif // SIMDUTF_SPAN /** * Fixes an ill-formed UTF-16BE string by replacing mismatched surrogates with * the Unicode replacement character U+FFFD. If input and output points to * different memory areas, the procedure copies string, and it's expected that * output memory is at least as big as the input. It's also possible to set * input equal output, that makes replacements an in-place operation. * * @param input the UTF-16BE string to correct. * @param len the length of the string in number of 2-byte code units * (char16_t). * @param output the output buffer. */ void to_well_formed_utf16be(const char16_t *input, size_t len, char16_t *output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 void to_well_formed_utf16be(std::span input, std::span output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { scalar::utf16::to_well_formed_utf16( input.data(), input.size(), output.data()); } else #endif { to_well_formed_utf16be(input.data(), input.size(), output.data()); } } #endif // SIMDUTF_SPAN /** * Fixes an ill-formed UTF-16 string by replacing mismatched surrogates with the * Unicode replacement character U+FFFD. If input and output points to different * memory areas, the procedure copies string, and it's expected that output * memory is at least as big as the input. It's also possible to set input equal * output, that makes replacements an in-place operation. * * @param input the UTF-16 string to correct. * @param len the length of the string in number of 2-byte code units * (char16_t). * @param output the output buffer. */ void to_well_formed_utf16(const char16_t *input, size_t len, char16_t *output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 void to_well_formed_utf16(std::span input, std::span output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { scalar::utf16::to_well_formed_utf16( input.data(), input.size(), output.data()); } else #endif { to_well_formed_utf16(input.data(), input.size(), output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING /** * Validate the UTF-32 string. This function may be best when you expect * the input to be almost always valid. Otherwise, consider using * validate_utf32_with_errors. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-32 string to validate. * @param len the length of the string in number of 4-byte code units * (char32_t). * @return true if and only if the string is valid UTF-32. */ simdutf_warn_unused bool validate_utf32(const char32_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 bool validate_utf32(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32::validate( detail::constexpr_cast_ptr(input.data()), input.size()); } else #endif { return validate_utf32(input.data(), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF32 /** * Validate the UTF-32 string and stop on error. It might be faster than * validate_utf32 when an error is expected to occur early. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-32 string to validate. * @param len the length of the string in number of 4-byte code units * (char32_t). * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated if * successful. */ simdutf_warn_unused result validate_utf32_with_errors(const char32_t *buf, size_t len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result validate_utf32_with_errors(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32::validate_with_errors( detail::constexpr_cast_ptr(input.data()), input.size()); } else #endif { return validate_utf32_with_errors(input.data(), input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Convert Latin1 string into UTF-8 string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf8_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_latin1_to_utf8(const char *input, size_t length, char *utf8_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_latin1_to_utf8( const detail::input_span_of_byte_like auto &latin1_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf8::convert( detail::constexpr_cast_ptr(latin1_input.data()), latin1_input.size(), detail::constexpr_cast_writeptr(utf8_output.data())); } else #endif { return convert_latin1_to_utf8( reinterpret_cast(latin1_input.data()), latin1_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert Latin1 string into UTF-8 string with output limit. * * This function is suitable to work with inputs from untrusted sources. * * We write as many characters as possible. * * Using convert_latin1_to_utf8_safe instead of convert_latin1_to_utf8 comes * with a significant penalty in some cases, being up to four times slower, * especially on short inputs. If you have allocated the output buffer so that * it contains utf8_length_from_latin1(input, length) bytes, then prefer * convert_latin1_to_utf8. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf8_output the pointer to buffer that can hold conversion result * @param utf8_len the maximum output length * @return the number of written char; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_latin1_to_utf8_safe(const char *input, size_t length, char *utf8_output, size_t utf8_len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_latin1_to_utf8_safe( const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { // implementation note: outputspan is a forwarding ref to avoid copying // and allow both lvalues and rvalues. std::span can be copied without // problems, but std::vector should not, and this function should accept // both. it will allow using an owning rvalue ref (example: passing a // temporary std::string) as output, but the user will quickly find out // that he has no way of getting the data out of the object in that case. #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf8::convert_safe_constexpr( input.data(), input.size(), utf8_output.data(), utf8_output.size()); } else #endif { return convert_latin1_to_utf8_safe( reinterpret_cast(input.data()), input.size(), reinterpret_cast(utf8_output.data()), utf8_output.size()); } } #endif // SIMDUTF_SPAN /** * Convert a Latin1 string into a size-limited UTF-8 buffer and report how much * input was consumed and output was written. * * We write as many complete characters as possible. The returned error is * SUCCESS if all input was consumed, or OUTPUT_BUFFER_TOO_SMALL otherwise. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf8_output the pointer to the output buffer * @param utf8_len the maximum output length * @return a full_result with error, input_count and output_count */ simdutf_warn_unused full_result convert_latin1_to_utf8_safe_with_details( const char *input, size_t length, char *utf8_output, size_t utf8_len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result convert_latin1_to_utf8_safe_with_details( const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf8::convert_safe_with_details_constexpr( input.data(), input.size(), utf8_output.data(), utf8_output.size()); } else #endif { return convert_latin1_to_utf8_safe_with_details( reinterpret_cast(input.data()), input.size(), reinterpret_cast(utf8_output.data()), utf8_output.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly Latin1 string into UTF-16LE string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_latin1_to_utf16le( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_latin1_to_utf16le( const detail::input_span_of_byte_like auto &latin1_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf16::convert( latin1_input.data(), latin1_input.size(), utf16_output.data()); } else #endif { return convert_latin1_to_utf16le( reinterpret_cast(latin1_input.data()), latin1_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert Latin1 string into UTF-16BE string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_latin1_to_utf16be( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_latin1_to_utf16be(const detail::input_span_of_byte_like auto &input, std::span output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf16::convert( input.data(), input.size(), output.data()); } else #endif { return convert_latin1_to_utf16be( reinterpret_cast(input.data()), input.size(), output.data()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16 string would require in Latin1 * format. * * @param length the length of the string in Latin1 code units (char) * @return the length of the string in Latin1 code units (char) required to * encode the UTF-16 string as Latin1 */ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t latin1_length_from_utf16(size_t length) noexcept { return length; } /** * Compute the number of code units that this Latin1 string would require in * UTF-16 format. * * @param length the length of the string in Latin1 code units (char) * @return the length of the string in 2-byte code units (char16_t) required to * encode the Latin1 string as UTF-16 */ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf16_length_from_latin1(size_t length) noexcept { return length; } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 /** * Convert Latin1 string into UTF-32 string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_latin1_to_utf32( const char *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_latin1_to_utf32( const detail::input_span_of_byte_like auto &latin1_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf32::convert( latin1_input.data(), latin1_input.size(), utf32_output.data()); } else #endif { return convert_latin1_to_utf32( reinterpret_cast(latin1_input.data()), latin1_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly broken UTF-8 string into latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param latin1_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if the input was not valid UTF-8 string * or if it cannot be represented as Latin1 */ simdutf_warn_unused size_t convert_utf8_to_latin1(const char *input, size_t length, char *latin1_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf8_to_latin1( const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_latin1::convert(input.data(), input.size(), output.data()); } else #endif { return convert_utf8_to_latin1(reinterpret_cast(input.data()), input.size(), reinterpret_cast(output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Using native endianness, convert possibly broken UTF-8 string into a UTF-16 * string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused size_t convert_utf8_to_utf16( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf8_to_utf16(const detail::input_span_of_byte_like auto &input, std::span output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert( input.data(), input.size(), output.data()); } else #endif { return convert_utf8_to_utf16(reinterpret_cast(input.data()), input.size(), output.data()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-8 * format even when the UTF-16LE content contains mismatched surrogates * that have to be replaced by the replacement character (0xFFFD). * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return a result pair struct (of type simdutf::result containing the two * fields error and count) where the count is the number of bytes required to * encode the UTF-16LE string as UTF-8, and the error code is either SUCCESS or * SURROGATE. The count is correct regardless of the error field. * When SURROGATE is returned, it does not indicate an error in the case of this * function: it indicates that at least one surrogate has been encountered: the * surrogates may be matched or not (thus this function does not validate). If * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf8_length_from_utf16_with_replacement< endianness::LITTLE>(valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf8_length_from_utf16le_with_replacement(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-8 * format even when the UTF-16BE content contains mismatched surrogates * that have to be replaced by the replacement character (0xFFFD). * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return a result pair struct (of type simdutf::result containing the two * fields error and count) where the count is the number of bytes required to * encode the UTF-16BE string as UTF-8, and the error code is either SUCCESS or * SURROGATE. The count is correct regardless of the error field. * When SURROGATE is returned, it does not indicate an error in the case of this * function: it indicates that at least one surrogate has been encountered: the * surrogates may be matched or not (thus this function does not validate). If * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result utf8_length_from_utf16be_with_replacement( std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf8_length_from_utf16_with_replacement< endianness::BIG>(valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf8_length_from_utf16be_with_replacement(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Using native endianness, convert a Latin1 string into a UTF-16 string. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t. */ simdutf_warn_unused size_t convert_latin1_to_utf16( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_latin1_to_utf16(const detail::input_span_of_byte_like auto &input, std::span output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf16::convert( input.data(), input.size(), output.data()); } else #endif { return convert_latin1_to_utf16(reinterpret_cast(input.data()), input.size(), output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Convert possibly broken UTF-8 string into UTF-16LE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused size_t convert_utf8_to_utf16le( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf8_to_utf16le(const detail::input_span_of_byte_like auto &utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert( utf8_input.data(), utf8_input.size(), utf16_output.data()); } else #endif { return convert_utf8_to_utf16le( reinterpret_cast(utf8_input.data()), utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16BE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused size_t convert_utf8_to_utf16be( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf8_to_utf16be(const detail::input_span_of_byte_like auto &utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert( utf8_input.data(), utf8_input.size(), utf16_output.data()); } else #endif { return convert_utf8_to_utf16be( reinterpret_cast(utf8_input.data()), utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly broken UTF-8 string into latin1 string with errors. * If the string cannot be represented as Latin1, an error * code is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param latin1_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated if * successful. */ simdutf_warn_unused result convert_utf8_to_latin1_with_errors( const char *input, size_t length, char *latin1_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf8_to_latin1_with_errors( const detail::input_span_of_byte_like auto &utf8_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_latin1::convert_with_errors( utf8_input.data(), utf8_input.size(), latin1_output.data()); } else #endif { return convert_utf8_to_latin1_with_errors( reinterpret_cast(utf8_input.data()), utf8_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Using native endianness, convert possibly broken UTF-8 string into UTF-16 * string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused result convert_utf8_to_utf16_with_errors( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf8_to_utf16_with_errors( const detail::input_span_of_byte_like auto &utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert_with_errors( utf8_input.data(), utf8_input.size(), utf16_output.data()); } else #endif { return convert_utf8_to_utf16_with_errors( reinterpret_cast(utf8_input.data()), utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16LE string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused result convert_utf8_to_utf16le_with_errors( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf8_to_utf16le_with_errors( const detail::input_span_of_byte_like auto &utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert_with_errors( utf8_input.data(), utf8_input.size(), utf16_output.data()); } else #endif { return convert_utf8_to_utf16le_with_errors( reinterpret_cast(utf8_input.data()), utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-16BE string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused result convert_utf8_to_utf16be_with_errors( const char *input, size_t length, char16_t *utf16_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf8_to_utf16be_with_errors( const detail::input_span_of_byte_like auto &utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert_with_errors( utf8_input.data(), utf8_input.size(), utf16_output.data()); } else #endif { return convert_utf8_to_utf16be_with_errors( reinterpret_cast(utf8_input.data()), utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Convert possibly broken UTF-8 string into UTF-32 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf32_output the pointer to buffer that can hold conversion result * @return the number of written char32_t; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused size_t convert_utf8_to_utf32( const char *input, size_t length, char32_t *utf32_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf8_to_utf32(const detail::input_span_of_byte_like auto &utf8_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf32::convert(utf8_input.data(), utf8_input.size(), utf32_output.data()); } else #endif { return convert_utf8_to_utf32( reinterpret_cast(utf8_input.data()), utf8_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf32_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char32_t written if * successful. */ simdutf_warn_unused result convert_utf8_to_utf32_with_errors( const char *input, size_t length, char32_t *utf32_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf8_to_utf32_with_errors( const detail::input_span_of_byte_like auto &utf8_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf32::convert_with_errors( utf8_input.data(), utf8_input.size(), utf32_output.data()); } else #endif { return convert_utf8_to_utf32_with_errors( reinterpret_cast(utf8_input.data()), utf8_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Convert valid UTF-8 string into latin1 string. * * This function assumes that the input string is valid UTF-8 and that it can be * represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf8_to_latin1 instead. The function may be removed from the library * in the future. * * This function is not BOM-aware. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param latin1_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if the input was not valid UTF-8 string */ simdutf_warn_unused size_t convert_valid_utf8_to_latin1( const char *input, size_t length, char *latin1_output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf8_to_latin1( const detail::input_span_of_byte_like auto &valid_utf8_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_latin1::convert_valid( valid_utf8_input.data(), valid_utf8_input.size(), latin1_output.data()); } else #endif { return convert_valid_utf8_to_latin1( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size(), latin1_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Using native endianness, convert valid UTF-8 string into a UTF-16 string. * * This function assumes that the input string is valid UTF-8. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ simdutf_warn_unused size_t convert_valid_utf8_to_utf16( const char *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf8_to_utf16( const detail::input_span_of_byte_like auto &valid_utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert_valid( valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); } else #endif { return convert_valid_utf8_to_utf16( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-8 string into UTF-16LE string. * * This function assumes that the input string is valid UTF-8. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ simdutf_warn_unused size_t convert_valid_utf8_to_utf16le( const char *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf8_to_utf16le( const detail::input_span_of_byte_like auto &valid_utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert_valid( valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); } else #endif { return convert_valid_utf8_to_utf16le( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-8 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-8. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ simdutf_warn_unused size_t convert_valid_utf8_to_utf16be( const char *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf8_to_utf16be( const detail::input_span_of_byte_like auto &valid_utf8_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf16::convert_valid( valid_utf8_input.data(), valid_utf8_input.size(), utf16_output.data()); } else #endif { return convert_valid_utf8_to_utf16be( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Convert valid UTF-8 string into UTF-32 string. * * This function assumes that the input string is valid UTF-8. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t */ simdutf_warn_unused size_t convert_valid_utf8_to_utf32( const char *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf8_to_utf32( const detail::input_span_of_byte_like auto &valid_utf8_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8_to_utf32::convert_valid( valid_utf8_input.data(), valid_utf8_input.size(), utf32_output.data()); } else #endif { return convert_valid_utf8_to_utf32( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Return the number of bytes that this Latin1 string would require in UTF-8 * format. * * @param input the Latin1 string to convert * @param length the length of the string bytes * @return the number of bytes required to encode the Latin1 string as UTF-8 */ simdutf_warn_unused size_t utf8_length_from_latin1(const char *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf8_length_from_latin1( const detail::input_span_of_byte_like auto &latin1_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::latin1_to_utf8::utf8_length_from_latin1(latin1_input.data(), latin1_input.size()); } else #endif { return utf8_length_from_latin1( reinterpret_cast(latin1_input.data()), latin1_input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-8 string would require in Latin1 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-8 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-8 string to convert * @param length the length of the string in byte * @return the number of bytes required to encode the UTF-8 string as Latin1 */ simdutf_warn_unused size_t latin1_length_from_utf8(const char *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t latin1_length_from_utf8( const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8::count_code_points(valid_utf8_input.data(), valid_utf8_input.size()); } else #endif { return latin1_length_from_utf8( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Compute the number of 2-byte code units that this UTF-8 string would require * in UTF-16LE format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-8 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-8 string to process * @param length the length of the string in bytes * @return the number of char16_t code units required to encode the UTF-8 string * as UTF-16LE */ simdutf_warn_unused size_t utf16_length_from_utf8(const char *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf16_length_from_utf8( const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8::utf16_length_from_utf8(valid_utf8_input.data(), valid_utf8_input.size()); } else #endif { return utf16_length_from_utf8( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Compute the number of 4-byte code units that this UTF-8 string would require * in UTF-32 format. * * This function is equivalent to count_utf8 * * This function does not validate the input. It is acceptable to pass invalid * UTF-8 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-8 string to process * @param length the length of the string in bytes * @return the number of char32_t code units required to encode the UTF-8 string * as UTF-32 */ simdutf_warn_unused size_t utf32_length_from_utf8(const char *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf32_length_from_utf8( const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8::count_code_points(valid_utf8_input.data(), valid_utf8_input.size()); } else #endif { return utf32_length_from_utf8( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Using native endianness, convert possibly broken UTF-16 string into UTF-8 * string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused size_t convert_utf16_to_utf8(const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16_to_utf8( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16_to_utf8(utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-16 string into UTF-8 * string with output limit. * * We write as many characters as possible into the output buffer, * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * Using convert_utf16_to_utf8_safe instead of convert_utf16_to_utf8 comes with * a significant penalty in some cases, being up to three times slower, * especially on short inputs. If you have allocated the output buffer so that * it contains utf8_length_from_utf16(input, length) bytes, then prefer * convert_utf16_to_utf8. * * @param input the UTF-16 string to convert * @param length the length of the string in 16-bit code units (char16_t) * @param utf8_output the pointer to buffer that can hold conversion result * @param utf8_len the maximum output length * @return the number of written char; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_utf16_to_utf8_safe(const char16_t *input, size_t length, char *utf8_output, size_t utf8_len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16_to_utf8_safe( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { // implementation note: outputspan is a forwarding ref to avoid copying // and allow both lvalues and rvalues. std::span can be copied without // problems, but std::vector should not, and this function should accept // both. it will allow using an owning rvalue ref (example: passing a // temporary std::string) as output, but the user will quickly find out // that he has no way of getting the data out of the object in that case. #if SIMDUTF_CPLUSPLUS23 if consteval { const full_result r = scalar::utf16_to_utf8::convert_with_errors( utf16_input.data(), utf16_input.size(), utf8_output.data(), utf8_output.size()); if (r.error != error_code::SUCCESS && r.error != error_code::OUTPUT_BUFFER_TOO_SMALL) { return 0; } return r.output_count; } else #endif { return convert_utf16_to_utf8_safe( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data()), utf8_output.size()); } } #endif // SIMDUTF_SPAN /** * Convert a possibly broken UTF-16 string into a size-limited UTF-8 buffer and * report how much input was consumed and output was written. * * We write as many complete characters as possible while validating the input. * The returned error is SUCCESS if all input was consumed, * OUTPUT_BUFFER_TOO_SMALL if the next character does not fit, or SURROGATE if * an unpaired surrogate was found. * * @param input the UTF-16 string to convert * @param length the length in 16-bit code units * @param utf8_output the pointer to the output buffer * @param utf8_len the maximum output length * @return a full_result with error, input_count and output_count */ simdutf_warn_unused full_result convert_utf16_to_utf8_safe_with_details( const char16_t *input, size_t length, char *utf8_output, size_t utf8_len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result convert_utf16_to_utf8_safe_with_details( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { if (utf16_input.empty()) { return full_result(error_code::SUCCESS, 0, 0); } return scalar::utf16_to_utf8::convert_with_errors( utf16_input.data(), utf16_input.size(), utf8_output.data(), utf8_output.size()); } else #endif { return convert_utf16_to_utf8_safe_with_details( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data()), utf8_output.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Using native endianness, convert possibly broken UTF-16 string into Latin1 * string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16 string * or if it cannot be represented as Latin1 */ simdutf_warn_unused size_t convert_utf16_to_latin1( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16_to_latin1( std::span utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert( utf16_input.data(), utf16_input.size(), latin1_output.data()); } else #endif { return convert_utf16_to_latin1( utf16_input.data(), utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string or if it cannot be represented as Latin1 */ simdutf_warn_unused size_t convert_utf16le_to_latin1( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16le_to_latin1( std::span utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert( utf16_input.data(), utf16_input.size(), latin1_output.data()); } else #endif { return convert_utf16le_to_latin1( utf16_input.data(), utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into Latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16BE * string or if it cannot be represented as Latin1 */ simdutf_warn_unused size_t convert_utf16be_to_latin1( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16be_to_latin1( std::span utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert( utf16_input.data(), utf16_input.size(), latin1_output.data()); } else #endif { return convert_utf16be_to_latin1( utf16_input.data(), utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Convert possibly broken UTF-16LE string into UTF-8 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused size_t convert_utf16le_to_utf8(const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16le_to_utf8( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16le_to_utf8( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused size_t convert_utf16be_to_utf8(const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16be_to_utf8( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16be_to_utf8( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Using native endianness, convert possibly broken UTF-16 string into Latin1 * string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf16_to_latin1_with_errors( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16_to_latin1_with_errors( std::span utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert_with_errors( utf16_input.data(), utf16_input.size(), latin1_output.data()); } else #endif { return convert_utf16_to_latin1_with_errors( utf16_input.data(), utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into Latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf16le_to_latin1_with_errors( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16le_to_latin1_with_errors( std::span utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert_with_errors( utf16_input.data(), utf16_input.size(), latin1_output.data()); } else #endif { return convert_utf16le_to_latin1_with_errors( utf16_input.data(), utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf16be_to_latin1_with_errors( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16be_to_latin1_with_errors( std::span utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert_with_errors( utf16_input.data(), utf16_input.size(), latin1_output.data()); } else #endif { return convert_utf16be_to_latin1_with_errors( utf16_input.data(), utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Using native endianness, convert possibly broken UTF-16 string into UTF-8 * string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf16_to_utf8_with_errors( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16_to_utf8_with_errors( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_with_errors( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16_to_utf8_with_errors( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-8 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf16le_to_utf8_with_errors( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16le_to_utf8_with_errors( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_with_errors( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16le_to_utf8_with_errors( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf16be_to_utf8_with_errors( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16be_to_utf8_with_errors( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_with_errors( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16be_to_utf8_with_errors( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * * This function always succeeds: unpaired surrogates are replaced with * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ simdutf_warn_unused size_t convert_utf16le_to_utf8_with_replacement( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16le_to_utf8_with_replacement( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_with_replacement( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16le_to_utf8_with_replacement( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * * This function always succeeds: unpaired surrogates are replaced with * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ simdutf_warn_unused size_t convert_utf16be_to_utf8_with_replacement( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16be_to_utf8_with_replacement( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_with_replacement( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16be_to_utf8_with_replacement( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16 string (native endianness) into UTF-8 string, * replacing unpaired surrogates with the Unicode replacement character U+FFFD. * * This function always succeeds: unpaired surrogates are replaced with * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ simdutf_warn_unused size_t convert_utf16_to_utf8_with_replacement( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16_to_utf8_with_replacement( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_with_replacement( utf16_input.data(), utf16_input.size(), utf8_output.data()); } else #endif { return convert_utf16_to_utf8_with_replacement( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert a possibly broken UTF-16 string into a size-limited UTF-8 buffer, * replacing unpaired surrogates with U+FFFD and reporting how much input was * consumed and output was written. * * We write as many complete characters as possible. The returned error is * SUCCESS if all input was consumed, or OUTPUT_BUFFER_TOO_SMALL if the next * character or replacement does not fit. * * @param input the UTF-16 string to convert * @param length the length in 16-bit code units * @param utf8_output the pointer to the output buffer * @param utf8_len the maximum output length * @return a full_result with error, input_count and output_count */ simdutf_warn_unused full_result convert_utf16_to_utf8_with_replacement_safe( const char16_t *input, size_t length, char *utf8_output, size_t utf8_len) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result convert_utf16_to_utf8_with_replacement_safe( std::span utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_with_replacement_safe< endianness::NATIVE>(utf16_input.data(), utf16_input.size(), utf8_output.data(), utf8_output.size()); } else #endif { return convert_utf16_to_utf8_with_replacement_safe( utf16_input.data(), utf16_input.size(), reinterpret_cast(utf8_output.data()), utf8_output.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Using native endianness, convert valid UTF-16 string into UTF-8 string. * * This function assumes that the input string is valid UTF-16. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16_to_utf8( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf16_to_utf8( std::span valid_utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_valid( valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); } else #endif { return convert_valid_utf16_to_utf8( valid_utf16_input.data(), valid_utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Using native endianness, convert UTF-16 string into Latin1 string. * * This function assumes that the input string is valid UTF-16 and that it can * be represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf16_to_latin1 instead. The function may be removed from the library * in the future. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16_to_latin1( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf16_to_latin1( std::span valid_utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert_valid_impl( detail::constexpr_cast_ptr(valid_utf16_input.data()), valid_utf16_input.size(), detail::constexpr_cast_writeptr(latin1_output.data())); } else #endif { return convert_valid_utf16_to_latin1( valid_utf16_input.data(), valid_utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-16LE string into Latin1 string. * * This function assumes that the input string is valid UTF-16LE and that it can * be represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf16le_to_latin1 instead. The function may be removed from the * library in the future. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16le_to_latin1( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t convert_valid_utf16le_to_latin1( std::span valid_utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert_valid_impl( detail::constexpr_cast_ptr(valid_utf16_input.data()), valid_utf16_input.size(), detail::constexpr_cast_writeptr(latin1_output.data())); } else #endif { return convert_valid_utf16le_to_latin1( valid_utf16_input.data(), valid_utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into Latin1 string. * * This function assumes that the input string is valid UTF-16BE and that it can * be represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf16be_to_latin1 instead. The function may be removed from the * library in the future. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16be_to_latin1( const char16_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t convert_valid_utf16be_to_latin1( std::span valid_utf16_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_latin1::convert_valid_impl( detail::constexpr_cast_ptr(valid_utf16_input.data()), valid_utf16_input.size(), detail::constexpr_cast_writeptr(latin1_output.data())); } else #endif { return convert_valid_utf16be_to_latin1( valid_utf16_input.data(), valid_utf16_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Convert valid UTF-16LE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16LE * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16le_to_utf8( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf16le_to_utf8( std::span valid_utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_valid( valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); } else #endif { return convert_valid_utf16le_to_utf8( valid_utf16_input.data(), valid_utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16BE. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf8_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16be_to_utf8( const char16_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf16be_to_utf8( std::span valid_utf16_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf8::convert_valid( valid_utf16_input.data(), valid_utf16_input.size(), utf8_output.data()); } else #endif { return convert_valid_utf16be_to_utf8( valid_utf16_input.data(), valid_utf16_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Using native endianness, convert possibly broken UTF-16 string into UTF-32 * string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused size_t convert_utf16_to_utf32( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16_to_utf32(std::span utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert( utf16_input.data(), utf16_input.size(), utf32_output.data()); } else #endif { return convert_utf16_to_utf32(utf16_input.data(), utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-32 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused size_t convert_utf16le_to_utf32( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16le_to_utf32(std::span utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert( utf16_input.data(), utf16_input.size(), utf32_output.data()); } else #endif { return convert_utf16le_to_utf32(utf16_input.data(), utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-32 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused size_t convert_utf16be_to_utf32( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf16be_to_utf32(std::span utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert( utf16_input.data(), utf16_input.size(), utf32_output.data()); } else #endif { return convert_utf16be_to_utf32(utf16_input.data(), utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-16 string into * UTF-32 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char32_t written if * successful. */ simdutf_warn_unused result convert_utf16_to_utf32_with_errors( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16_to_utf32_with_errors(std::span utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert_with_errors( utf16_input.data(), utf16_input.size(), utf32_output.data()); } else #endif { return convert_utf16_to_utf32_with_errors( utf16_input.data(), utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16LE string into UTF-32 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char32_t written if * successful. */ simdutf_warn_unused result convert_utf16le_to_utf32_with_errors( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16le_to_utf32_with_errors( std::span utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert_with_errors( utf16_input.data(), utf16_input.size(), utf32_output.data()); } else #endif { return convert_utf16le_to_utf32_with_errors( utf16_input.data(), utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-16BE string into UTF-32 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char32_t written if * successful. */ simdutf_warn_unused result convert_utf16be_to_utf32_with_errors( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf16be_to_utf32_with_errors( std::span utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert_with_errors( utf16_input.data(), utf16_input.size(), utf32_output.data()); } else #endif { return convert_utf16be_to_utf32_with_errors( utf16_input.data(), utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Using native endianness, convert valid UTF-16 string into UTF-32 string. * * This function assumes that the input string is valid UTF-16 (native * endianness). * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16_to_utf32( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf16_to_utf32(std::span valid_utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert_valid( valid_utf16_input.data(), valid_utf16_input.size(), utf32_output.data()); } else #endif { return convert_valid_utf16_to_utf32(valid_utf16_input.data(), valid_utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-16LE string into UTF-32 string. * * This function assumes that the input string is valid UTF-16LE. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16le_to_utf32( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf16le_to_utf32(std::span valid_utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert_valid( valid_utf16_input.data(), valid_utf16_input.size(), utf32_output.data()); } else #endif { return convert_valid_utf16le_to_utf32(valid_utf16_input.data(), valid_utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-16BE string into UTF-32 string. * * This function assumes that the input string is valid UTF-16LE. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @param utf32_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf16be_to_utf32( const char16_t *input, size_t length, char32_t *utf32_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf16be_to_utf32(std::span valid_utf16_input, std::span utf32_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16_to_utf32::convert_valid( valid_utf16_input.data(), valid_utf16_input.size(), utf32_output.data()); } else #endif { return convert_valid_utf16be_to_utf32(valid_utf16_input.data(), valid_utf16_input.size(), utf32_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Using native endianness; Compute the number of bytes that this UTF-16 * string would require in UTF-8 format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ simdutf_warn_unused size_t utf8_length_from_utf16(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf8_length_from_utf16(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf8_length_from_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf8_length_from_utf16(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Using native endianness; compute the number of bytes that this UTF-16 * string would require in UTF-8 format even when the UTF-16LE content contains * mismatched surrogates that have to be replaced by the replacement character * (0xFFFD). * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return a result pair struct (of type simdutf::result containing the two * fields error and count) where the count is the number of bytes required to * encode the UTF-16 string as UTF-8, and the error code is either SUCCESS or * SURROGATE. The count is correct regardless of the error field. * When SURROGATE is returned, it does not indicate an error in the case of this * function: it indicates that at least one surrogate has been encountered: the * surrogates may be matched or not (thus this function does not validate). If * the returned error code is SUCCESS, then the input contains no surrogate, is * in the Basic Multilingual Plane, and is necessarily valid. */ simdutf_warn_unused result utf8_length_from_utf16_with_replacement( const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result utf8_length_from_utf16_with_replacement( std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf8_length_from_utf16_with_replacement< endianness::NATIVE>(valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf8_length_from_utf16_with_replacement(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-8 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ simdutf_warn_unused size_t utf8_length_from_utf16le(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t utf8_length_from_utf16le(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf8_length_from_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf8_length_from_utf16le(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-8 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-8 */ simdutf_warn_unused size_t utf8_length_from_utf16be(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf8_length_from_utf16be(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf8_length_from_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf8_length_from_utf16be(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Convert possibly broken UTF-32 string into UTF-8 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ simdutf_warn_unused size_t convert_utf32_to_utf8(const char32_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf32_to_utf8( std::span utf32_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf8::convert( utf32_input.data(), utf32_input.size(), utf8_output.data()); } else #endif { return convert_utf32_to_utf8(utf32_input.data(), utf32_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf32_to_utf8_with_errors( const char32_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf32_to_utf8_with_errors( std::span utf32_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf8::convert_with_errors( utf32_input.data(), utf32_input.size(), utf8_output.data()); } else #endif { return convert_utf32_to_utf8_with_errors( utf32_input.data(), utf32_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-8 string. * * This function assumes that the input string is valid UTF-32. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf8_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf32_to_utf8( const char32_t *input, size_t length, char *utf8_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf32_to_utf8( std::span valid_utf32_input, detail::output_span_of_byte_like auto &&utf8_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf8::convert_valid( valid_utf32_input.data(), valid_utf32_input.size(), utf8_output.data()); } else #endif { return convert_valid_utf32_to_utf8( valid_utf32_input.data(), valid_utf32_input.size(), reinterpret_cast(utf8_output.data())); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Using native endianness, convert possibly broken UTF-32 string into a UTF-16 * string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ simdutf_warn_unused size_t convert_utf32_to_utf16( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf32_to_utf16(std::span utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert( utf32_input.data(), utf32_input.size(), utf16_output.data()); } else #endif { return convert_utf32_to_utf16(utf32_input.data(), utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16LE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ simdutf_warn_unused size_t convert_utf32_to_utf16le( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf32_to_utf16le(std::span utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert( utf32_input.data(), utf32_input.size(), utf16_output.data()); } else #endif { return convert_utf32_to_utf16le(utf32_input.data(), utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly broken UTF-32 string into Latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string * or if it cannot be represented as Latin1 */ simdutf_warn_unused size_t convert_utf32_to_latin1( const char32_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf32_to_latin1( std::span utf32_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_latin1::convert( utf32_input.data(), utf32_input.size(), latin1_output.data()); } else #endif { return convert_utf32_to_latin1( utf32_input.data(), utf32_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into Latin1 string and stop on error. * If the string cannot be represented as Latin1, an error is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param latin1_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused result convert_utf32_to_latin1_with_errors( const char32_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf32_to_latin1_with_errors( std::span utf32_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_latin1::convert_with_errors( utf32_input.data(), utf32_input.size(), latin1_output.data()); } else #endif { return convert_utf32_to_latin1_with_errors( utf32_input.data(), utf32_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into Latin1 string. * * This function assumes that the input string is valid UTF-32 and that it can * be represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf32_to_latin1 instead. The function may be removed from the library * in the future. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param latin1_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf32_to_latin1( const char32_t *input, size_t length, char *latin1_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused size_t convert_valid_utf32_to_latin1( std::span valid_utf32_input, detail::output_span_of_byte_like auto &&latin1_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_latin1::convert_valid( detail::constexpr_cast_ptr(valid_utf32_input.data()), valid_utf32_input.size(), detail::constexpr_cast_writeptr(latin1_output.data())); } #endif { return convert_valid_utf32_to_latin1( valid_utf32_input.data(), valid_utf32_input.size(), reinterpret_cast(latin1_output.data())); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-32 string would require in Latin1 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-32 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t latin1_length_from_utf32(size_t length) noexcept { return length; } /** * Compute the number of bytes that this Latin1 string would require in UTF-32 * format. * * @param length the length of the string in Latin1 code units (char) * @return the length of the string in 4-byte code units (char32_t) required to * encode the Latin1 string as UTF-32 */ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 size_t utf32_length_from_latin1(size_t length) noexcept { return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Convert possibly broken UTF-32 string into UTF-16BE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 string */ simdutf_warn_unused size_t convert_utf32_to_utf16be( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_utf32_to_utf16be(std::span utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert( utf32_input.data(), utf32_input.size(), utf16_output.data()); } else #endif { return convert_utf32_to_utf16be(utf32_input.data(), utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Using native endianness, convert possibly broken UTF-32 string into UTF-16 * string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused result convert_utf32_to_utf16_with_errors( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf32_to_utf16_with_errors(std::span utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert_with_errors( utf32_input.data(), utf32_input.size(), utf16_output.data()); } else #endif { return convert_utf32_to_utf16_with_errors( utf32_input.data(), utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16LE string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused result convert_utf32_to_utf16le_with_errors( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf32_to_utf16le_with_errors( std::span utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert_with_errors( utf32_input.data(), utf32_input.size(), utf16_output.data()); } else #endif { return convert_utf32_to_utf16le_with_errors( utf32_input.data(), utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert possibly broken UTF-32 string into UTF-16BE string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused result convert_utf32_to_utf16be_with_errors( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result convert_utf32_to_utf16be_with_errors( std::span utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert_with_errors( utf32_input.data(), utf32_input.size(), utf16_output.data()); } else #endif { return convert_utf32_to_utf16be_with_errors( utf32_input.data(), utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Using native endianness, convert valid UTF-32 string into a UTF-16 string. * * This function assumes that the input string is valid UTF-32. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf32_to_utf16( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf32_to_utf16(std::span valid_utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert_valid( valid_utf32_input.data(), valid_utf32_input.size(), utf16_output.data()); } else #endif { return convert_valid_utf32_to_utf16(valid_utf32_input.data(), valid_utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-16LE string. * * This function assumes that the input string is valid UTF-32. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf32_to_utf16le( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf32_to_utf16le(std::span valid_utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert_valid( valid_utf32_input.data(), valid_utf32_input.size(), utf16_output.data()); } else #endif { return convert_valid_utf32_to_utf16le(valid_utf32_input.data(), valid_utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN /** * Convert valid UTF-32 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-32. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @param utf16_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused size_t convert_valid_utf32_to_utf16be( const char32_t *input, size_t length, char16_t *utf16_buffer) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t convert_valid_utf32_to_utf16be(std::span valid_utf32_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32_to_utf16::convert_valid( valid_utf32_input.data(), valid_utf32_input.size(), utf16_output.data()); } else #endif { return convert_valid_utf32_to_utf16be(valid_utf32_input.data(), valid_utf32_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 /** * Change the endianness of the input. Can be used to go from UTF-16LE to * UTF-16BE or from UTF-16BE to UTF-16LE. * * This function does not validate the input. * * This function is not BOM-aware. * * @param input the UTF-16 string to process * @param length the length of the string in 2-byte code units (char16_t) * @param output the pointer to a buffer that can hold the conversion * result */ void change_endianness_utf16(const char16_t *input, size_t length, char16_t *output) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_constexpr23 void change_endianness_utf16(std::span utf16_input, std::span utf16_output) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::change_endianness_utf16( utf16_input.data(), utf16_input.size(), utf16_output.data()); } else #endif { return change_endianness_utf16(utf16_input.data(), utf16_input.size(), utf16_output.data()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Compute the number of bytes that this UTF-32 string would require in UTF-8 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-32 strings but in such cases the result is implementation defined. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-8 */ simdutf_warn_unused size_t utf8_length_from_utf32(const char32_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf8_length_from_utf32(std::span valid_utf32_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32::utf8_length_from_utf32(valid_utf32_input.data(), valid_utf32_input.size()); } else #endif { return utf8_length_from_utf32(valid_utf32_input.data(), valid_utf32_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Compute the number of two-byte code units that this UTF-32 string would * require in UTF-16 format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-32 strings but in such cases the result is implementation defined. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-16 */ simdutf_warn_unused size_t utf16_length_from_utf32(const char32_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf16_length_from_utf32(std::span valid_utf32_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf32::utf16_length_from_utf32(valid_utf32_input.data(), valid_utf32_input.size()); } else #endif { return utf16_length_from_utf32(valid_utf32_input.data(), valid_utf32_input.size()); } } #endif // SIMDUTF_SPAN /** * Using native endianness; Compute the number of bytes that this UTF-16 * string would require in UTF-32 format. * * This function is equivalent to count_utf16. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16 string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-32 */ simdutf_warn_unused size_t utf32_length_from_utf16(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf32_length_from_utf16(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf32_length_from_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf32_length_from_utf16(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16LE string would require in UTF-32 * format. * * This function is equivalent to count_utf16le. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-32 */ simdutf_warn_unused size_t utf32_length_from_utf16le(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf32_length_from_utf16le( std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf32_length_from_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf32_length_from_utf16le(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the number of bytes that this UTF-16BE string would require in UTF-32 * format. * * This function is equivalent to count_utf16be. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-32 */ simdutf_warn_unused size_t utf32_length_from_utf16be(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t utf32_length_from_utf16be( std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::utf32_length_from_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return utf32_length_from_utf16be(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 /** * Count the number of code points (characters) in the string assuming that * it is valid. * * This function assumes that the input string is valid UTF-16 (native * endianness). It is acceptable to pass invalid UTF-16 strings but in such * cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16 string to process * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ simdutf_warn_unused size_t count_utf16(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf16(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::count_code_points( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return count_utf16(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Count the number of code points (characters) in the string assuming that * it is valid. * * This function assumes that the input string is valid UTF-16LE. * It is acceptable to pass invalid UTF-16 strings but in such cases * the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16LE string to process * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ simdutf_warn_unused size_t count_utf16le(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf16le(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::count_code_points( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return count_utf16le(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Count the number of code points (characters) in the string assuming that * it is valid. * * This function assumes that the input string is valid UTF-16BE. * It is acceptable to pass invalid UTF-16 strings but in such cases * the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16BE string to process * @param length the length of the string in 2-byte code units (char16_t) * @return number of code points */ simdutf_warn_unused size_t count_utf16be(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf16be(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::count_code_points( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return count_utf16be(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 /** * Count the number of code points (characters) in the string assuming that * it is valid. * * This function assumes that the input string is valid UTF-8. * It is acceptable to pass invalid UTF-8 strings but in such cases * the result is implementation defined. * * @param input the UTF-8 string to process * @param length the length of the string in bytes * @return number of code points */ simdutf_warn_unused size_t count_utf8(const char *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t count_utf8( const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8::count_code_points(valid_utf8_input.data(), valid_utf8_input.size()); } else #endif { return count_utf8(reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size()); } } #endif // SIMDUTF_SPAN /** * Given a valid UTF-8 string having a possibly truncated last character, * this function checks the end of string. If the last character is truncated * (or partial), then it returns a shorter length (shorter by 1 to 3 bytes) so * that the short UTF-8 strings only contain complete characters. If there is no * truncated character, the original length is returned. * * This function assumes that the input string is valid UTF-8, but possibly * truncated. * * @param input the UTF-8 string to process * @param length the length of the string in bytes * @return the length of the string in bytes, possibly shorter by 1 to 3 bytes */ simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length); #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t trim_partial_utf8( const detail::input_span_of_byte_like auto &valid_utf8_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf8::trim_partial_utf8(valid_utf8_input.data(), valid_utf8_input.size()); } else #endif { return trim_partial_utf8( reinterpret_cast(valid_utf8_input.data()), valid_utf8_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_UTF16 /** * Given a valid UTF-16BE string having a possibly truncated last character, * this function checks the end of string. If the last character is truncated * (or partial), then it returns a shorter length (shorter by 1 unit) so that * the short UTF-16BE strings only contain complete characters. If there is no * truncated character, the original length is returned. * * This function assumes that the input string is valid UTF-16BE, but possibly * truncated. * * @param input the UTF-16BE string to process * @param length the length of the string in bytes * @return the length of the string in bytes, possibly shorter by 1 unit */ simdutf_warn_unused size_t trim_partial_utf16be(const char16_t *input, size_t length); #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t trim_partial_utf16be(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::trim_partial_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return trim_partial_utf16be(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Given a valid UTF-16LE string having a possibly truncated last character, * this function checks the end of string. If the last character is truncated * (or partial), then it returns a shorter length (shorter by 1 unit) so that * the short UTF-16LE strings only contain complete characters. If there is no * truncated character, the original length is returned. * * This function assumes that the input string is valid UTF-16LE, but possibly * truncated. * * @param input the UTF-16LE string to process * @param length the length of the string in bytes * @return the length of the string in unit, possibly shorter by 1 unit */ simdutf_warn_unused size_t trim_partial_utf16le(const char16_t *input, size_t length); #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t trim_partial_utf16le(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::trim_partial_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return trim_partial_utf16le(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN /** * Given a valid UTF-16 string having a possibly truncated last character, * this function checks the end of string. If the last character is truncated * (or partial), then it returns a shorter length (shorter by 1 unit) so that * the short UTF-16 strings only contain complete characters. If there is no * truncated character, the original length is returned. * * This function assumes that the input string is valid UTF-16, but possibly * truncated. We use the native endianness. * * @param input the UTF-16 string to process * @param length the length of the string in bytes * @return the length of the string in unit, possibly shorter by 1 unit */ simdutf_warn_unused size_t trim_partial_utf16(const char16_t *input, size_t length); #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t trim_partial_utf16(std::span valid_utf16_input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::utf16::trim_partial_utf16( valid_utf16_input.data(), valid_utf16_input.size()); } else #endif { return trim_partial_utf16(valid_utf16_input.data(), valid_utf16_input.size()); } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 || \ SIMDUTF_FEATURE_DETECT_ENCODING #ifndef SIMDUTF_NEED_TRAILING_ZEROES #define SIMDUTF_NEED_TRAILING_ZEROES 1 #endif #endif // SIMDUTF_FEATURE_BASE64 || SIMDUTF_FEATURE_UTF16 || // SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_BASE64 // base64_options are used to specify the base64 encoding options. // ASCII spaces are ' ', '\t', '\n', '\r', '\f' // garbage characters are characters that are not part of the base64 alphabet // nor ASCII spaces. constexpr uint64_t base64_reverse_padding = 2; /* modifier for base64_default and base64_url */ enum base64_options : uint64_t { base64_default = 0, /* standard base64 format (with padding) */ base64_url = 1, /* base64url format (no padding) */ base64_default_no_padding = base64_default | base64_reverse_padding, /* standard base64 format without padding */ base64_url_with_padding = base64_url | base64_reverse_padding, /* base64url with padding */ base64_default_accept_garbage = 4, /* standard base64 format accepting garbage characters, the input stops with the first '=' if any */ base64_url_accept_garbage = 5, /* base64url format accepting garbage characters, the input stops with the first '=' if any */ base64_default_or_url = 8, /* standard/base64url hybrid format (only meaningful for decoding!) */ base64_default_or_url_accept_garbage = 12, /* standard/base64url hybrid format accepting garbage characters (only meaningful for decoding!), the input stops with the first '=' if any */ }; // last_chunk_handling_options are used to specify the handling of the last // chunk in base64 decoding. // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 enum last_chunk_handling_options : uint64_t { loose = 0, /* standard base64 format, decode partial final chunk */ strict = 1, /* error when the last chunk is partial, 2 or 3 chars, and unpadded, or non-zero bit padding */ stop_before_partial = 2, /* if the last chunk is partial, ignore it (no error) */ only_full_chunks = 3 /* only decode full blocks (4 base64 characters, no padding) */ }; inline simdutf_constexpr23 bool is_partial(last_chunk_handling_options options) { return (options == stop_before_partial) || (options == only_full_chunks); } namespace detail { simdutf_warn_unused const char *find(const char *start, const char *end, char character) noexcept; simdutf_warn_unused const char16_t * find(const char16_t *start, const char16_t *end, char16_t character) noexcept; } // namespace detail /** * Find the first occurrence of a character in a string. If the character is * not found, return a pointer to the end of the string. * @param start the start of the string * @param end the end of the string * @param character the character to find * @return a pointer to the first occurrence of the character in the string, * or a pointer to the end of the string if the character is not found. * */ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char * find(const char *start, const char *end, char character) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { for (; start != end; ++start) if (*start == character) return start; return end; } else #endif { return detail::find(start, end, character); } } simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 const char16_t * find(const char16_t *start, const char16_t *end, char16_t character) noexcept { // implementation note: this is repeated instead of a template, to ensure // the api is still a function and compiles without concepts #if SIMDUTF_CPLUSPLUS23 if consteval { for (; start != end; ++start) if (*start == character) return start; return end; } else #endif { return detail::find(start, end, character); } } } // We include base64_tables once. #include #include namespace simdutf { inline std::string_view to_string(base64_options options) { switch (options) { case base64_default: return "base64_default"; case base64_url: return "base64_url"; case base64_reverse_padding: return "base64_reverse_padding"; case base64_url_with_padding: return "base64_url_with_padding"; case base64_default_accept_garbage: return "base64_default_accept_garbage"; case base64_url_accept_garbage: return "base64_url_accept_garbage"; case base64_default_or_url: return "base64_default_or_url"; case base64_default_or_url_accept_garbage: return "base64_default_or_url_accept_garbage"; } return ""; } inline std::string_view to_string(last_chunk_handling_options options) { switch (options) { case loose: return "loose"; case strict: return "strict"; case stop_before_partial: return "stop_before_partial"; case only_full_chunks: return "only_full_chunks"; } return ""; } /** * Provide the maximal binary length in bytes given the base64 input. * As long as the input does not contain ignorable characters (e.g., ASCII * spaces or linefeed characters), the result is exact. In particular, the * function checks for padding characters. * * The function is fast (constant time). It checks up to two characters at * the end of the string. The input is not otherwise validated or read. * * @param input the base64 input to process * @param length the length of the base64 input in bytes * @return maximum number of binary bytes */ simdutf_warn_unused size_t maximal_binary_length_from_base64(const char *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t maximal_binary_length_from_base64( const detail::input_span_of_byte_like auto &input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::maximal_binary_length_from_base64( detail::constexpr_cast_ptr(input.data()), input.size()); } else #endif { return maximal_binary_length_from_base64( reinterpret_cast(input.data()), input.size()); } } #endif // SIMDUTF_SPAN /** * Provide the maximal binary length in bytes given the base64 input. * As long as the input does not contain ignorable characters (e.g., ASCII * spaces or linefeed characters), the result is exact. In particular, the * function checks for padding characters. * * The function is fast (constant time). It checks up to two characters at * the end of the string. The input is not otherwise validated or read. * * @param input the base64 input to process, in ASCII stored as 16-bit * units * @param length the length of the base64 input in 16-bit units * @return maximal number of binary bytes */ simdutf_warn_unused size_t maximal_binary_length_from_base64( const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t maximal_binary_length_from_base64(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::maximal_binary_length_from_base64(input.data(), input.size()); } else #endif { return maximal_binary_length_from_base64(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the binary length from a base64 input. * This function is useful for base64 inputs that may contain ASCII whitespaces * (such as line breaks). For such inputs, the result is exact, and for any * inputs the result can be used to size the output buffer passed to * `base64_to_binary`. * * The function ignores whitespace and does not require padding characters * ('='). * * @param input the base64 input to process * @param length the length of the base64 input in bytes * @return number of binary bytes */ simdutf_warn_unused size_t binary_length_from_base64(const char *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t binary_length_from_base64( const detail::input_span_of_byte_like auto &input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::binary_length_from_base64(input.data(), input.size()); } else #endif { return binary_length_from_base64( reinterpret_cast(input.data()), input.size()); } } #endif // SIMDUTF_SPAN /** * Compute the binary length from a base64 input. * This function is useful for base64 inputs that may contain ASCII whitespaces * (such as line breaks). For such inputs, the result is exact, and for any * inputs the result can be used to size the output buffer passed to * `base64_to_binary`. * * The function ignores whitespace and does not require padding characters * ('='). * * @param input the base64 input to process, in ASCII stored as 16-bit * units * @param length the length of the base64 input in 16-bit units * @return number of binary bytes */ simdutf_warn_unused size_t binary_length_from_base64(const char16_t *input, size_t length) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t binary_length_from_base64(std::span input) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::binary_length_from_base64(input.data(), input.size()); } else #endif { return binary_length_from_base64(input.data(), input.size()); } } #endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output. * * This function follows the WHATWG forgiving-base64 format, which means that it * will ignore any ASCII spaces in the input. You may provide a padded input * (with one or two equal signs at the end) or an unpadded input (without any * equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * This function will fail in case of invalid input. When last_chunk_options = * loose, there are two possible reasons for failure: the input contains a * number of base64 characters that when divided by 4, leaves a single remainder * character (BASE64_INPUT_REMAINDER), or the input contains a character that is * not a valid base64 character (INVALID_BASE64_CHARACTER). * * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the * input where the invalid character was found. When the error is * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded. * * The default option (simdutf::base64_default) expects the characters `+` and * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the * characters `-` and `_` as part of its alphabet. * * The padding (`=`) is validated if present. There may be at most two padding * characters at the end of the input. If there are any padding characters, the * total number of characters (excluding spaces but including padding * characters) must be divisible by four. * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you fail to * provide that much space, the function may cause a buffer overflow. * * Advanced users may want to tailor how the last chunk is handled. By default, * we use a loose (forgiving) approach but we also support a strict approach * as well as a stop_before_partial approach, as per the following proposal: * * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 * * @param input the base64 string to process * @param length the length of the string in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, usually base64_default or * base64_url, and base64_default by default. * @param last_chunk_options the last chunk handling options, * last_chunk_handling_options::loose by default * but can also be last_chunk_handling_options::strict or * last_chunk_handling_options::stop_before_partial. * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in bytes) if any, or the number of bytes written if successful. */ simdutf_warn_unused result base64_to_binary( const char *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result base64_to_binary( const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::base64_to_binary_details_impl( input.data(), input.size(), binary_output.data(), options, last_chunk_options); } else #endif { return base64_to_binary(reinterpret_cast(input.data()), input.size(), reinterpret_cast(binary_output.data()), options, last_chunk_options); } } #endif // SIMDUTF_SPAN /** * Provide the base64 length in bytes given the length of a binary input. * * @param length the length of the input in bytes * @param options the base64 options to use (default: base64_default) * @return number of base64 bytes */ inline simdutf_warn_unused simdutf_constexpr23 size_t base64_length_from_binary( size_t length, base64_options options = base64_default) noexcept { return scalar::base64::base64_length_from_binary(length, options); } /** * Provide the base64 length in bytes given the length of a binary input, * taking into account line breaks. * * @param length the length of the input in bytes * @param options the base64 options to use (default: base64_default) * @param line_length the length of lines, must be at least 4 (otherwise it is * interpreted as 4), * @return number of base64 bytes */ inline simdutf_warn_unused simdutf_constexpr23 size_t base64_length_from_binary_with_lines( size_t length, base64_options options = base64_default, size_t line_length = default_line_length) noexcept { return scalar::base64::base64_length_from_binary_with_lines(length, options, line_length); } /** * Convert a binary input to a base64 output. * * The default option (simdutf::base64_default) uses the characters `+` and `/` * as part of its alphabet. Further, it adds padding (`=`) at the end of the * output to ensure that the output length is a multiple of four. * * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part * of its alphabet. No padding is added at the end of the output. * * This function always succeeds. * * @param input the binary to process * @param length the length of the input in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least base64_length_from_binary(length) bytes long) * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ size_t binary_to_base64(const char *input, size_t length, char *output, base64_options options = base64_default) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t binary_to_base64(const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::tail_encode_base64( binary_output.data(), input.data(), input.size(), options); } else #endif { return binary_to_base64( reinterpret_cast(input.data()), input.size(), reinterpret_cast(binary_output.data()), options); } } #endif // SIMDUTF_SPAN /** * Convert a binary input to a base64 output with line breaks. * * The default option (simdutf::base64_default) uses the characters `+` and `/` * as part of its alphabet. Further, it adds padding (`=`) at the end of the * output to ensure that the output length is a multiple of four. * * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part * of its alphabet. No padding is added at the end of the output. * * This function always succeeds. * * @param input the binary to process * @param length the length of the input in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least base64_length_from_binary_with_lines(length, * options, line_length) bytes long) * @param line_length the length of lines, must be at least 4 (otherwise it is * interpreted as 4), * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @return number of written bytes, will be equal to * base64_length_from_binary_with_lines(length, options) */ size_t binary_to_base64_with_lines(const char *input, size_t length, char *output, size_t line_length = simdutf::default_line_length, base64_options options = base64_default) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 size_t binary_to_base64_with_lines( const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&binary_output, size_t line_length = simdutf::default_line_length, base64_options options = base64_default) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::tail_encode_base64_impl( binary_output.data(), input.data(), input.size(), options, line_length); } else #endif { return binary_to_base64_with_lines( reinterpret_cast(input.data()), input.size(), reinterpret_cast(binary_output.data()), line_length, options); } } #endif // SIMDUTF_SPAN #if SIMDUTF_ATOMIC_REF /** * Convert a binary input to a base64 output, using atomic accesses. * This function comes with a potentially significant performance * penalty, but it may be useful in some cases where the input * buffers are shared between threads, to avoid undefined * behavior in case of data races. * * The function is for advanced users. Its main use case is when * to silence sanitizer warnings. We have no documented use case * where this function is actually necessary in terms of practical correctness. * * This function is only available when simdutf is compiled with * C++20 support and __cpp_lib_atomic_ref >= 201806L. You may check * the availability of this function by checking the macro * SIMDUTF_ATOMIC_REF. * * The default option (simdutf::base64_default) uses the characters `+` and `/` * as part of its alphabet. Further, it adds padding (`=`) at the end of the * output to ensure that the output length is a multiple of four. * * The URL option (simdutf::base64_url) uses the characters `-` and `_` as part * of its alphabet. No padding is added at the end of the output. * * This function always succeeds. * * This function is considered experimental. It is not tested by default * (see the CMake option SIMDUTF_ATOMIC_BASE64_TESTS) nor is it fuzz tested. * It is not documented in the public API documentation (README). It is * offered on a best effort basis. We rely on the community for further * testing and feedback. * * @brief atomic_binary_to_base64 * @param input the binary to process * @param length the length of the input in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least base64_length_from_binary(length) bytes long) * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ size_t atomic_binary_to_base64(const char *input, size_t length, char *output, base64_options options = base64_default) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused size_t atomic_binary_to_base64(const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default) noexcept { return atomic_binary_to_base64( reinterpret_cast(input.data()), input.size(), reinterpret_cast(binary_output.data()), options); } #endif // SIMDUTF_SPAN #endif // SIMDUTF_ATOMIC_REF /** * Convert a base64 input to a binary output. * * This function follows the WHATWG forgiving-base64 format, which means that it * will ignore any ASCII spaces in the input. You may provide a padded input * (with one or two equal signs at the end) or an unpadded input (without any * equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * This function will fail in case of invalid input. When last_chunk_options = * loose, there are two possible reasons for failure: the input contains a * number of base64 characters that when divided by 4, leaves a single remainder * character (BASE64_INPUT_REMAINDER), or the input contains a character that is * not a valid base64 character (INVALID_BASE64_CHARACTER). * * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the * input where the invalid character was found. When the error is * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded. * * The default option (simdutf::base64_default) expects the characters `+` and * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the * characters `-` and `_` as part of its alphabet. * * The padding (`=`) is validated if present. There may be at most two padding * characters at the end of the input. If there are any padding characters, the * total number of characters (excluding spaces but including padding * characters) must be divisible by four. * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you fail * to provide that much space, the function may cause a buffer overflow. * * Advanced users may want to tailor how the last chunk is handled. By default, * we use a loose (forgiving) approach but we also support a strict approach * as well as a stop_before_partial approach, as per the following proposal: * * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 * * @param input the base64 string to process, in ASCII stored as 16-bit * units * @param length the length of the string in 16-bit units * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the last chunk handling options, * last_chunk_handling_options::loose by default * but can also be last_chunk_handling_options::strict or * last_chunk_handling_options::stop_before_partial. * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and position of the * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number * of bytes written if successful. */ simdutf_warn_unused result base64_to_binary(const char16_t *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 result base64_to_binary( std::span input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::base64_to_binary_details_impl( input.data(), input.size(), binary_output.data(), options, last_chunk_options); } else #endif { return base64_to_binary(input.data(), input.size(), reinterpret_cast(binary_output.data()), options, last_chunk_options); } } #endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output while returning more details * than base64_to_binary. * * This function follows the WHATWG forgiving-base64 format, which means that it * will ignore any ASCII spaces in the input. You may provide a padded input * (with one or two equal signs at the end) or an unpadded input (without any * equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * Unlike base64_to_binary, this function returns a full_result with both * input_count and output_count, so you always know how much input was consumed * and how much output was written. There are three cases where the input may * not be fully consumed: * * 1. stop_before_partial: When last_chunk_options is set to * stop_before_partial, any incomplete 4-character group at the end of the * input is left unconsumed. This is useful for streaming/chunked decoding * where you can carry over the unconsumed input to the next chunk. * * 2. INVALID_BASE64_CHARACTER: The input contains a character that is not a * valid base64 character. In this case, input_count indicates where the * invalid character was found. * * 3. BASE64_INPUT_REMAINDER: When last_chunk_options is loose, the input * contains a number of base64 characters that, when divided by 4, leaves * a single remainder character (which cannot encode any bytes). * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you fail to * provide that much space, the function may cause a buffer overflow. * * @param input the base64 string to process * @param length the length of the string in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the last chunk handling options, * last_chunk_handling_options::loose by default * but can also be last_chunk_handling_options::strict or * last_chunk_handling_options::stop_before_partial. * @return a full_result struct (of type simdutf::full_result containing the * three fields error, input_count and output_count). */ simdutf_warn_unused full_result base64_to_binary_details(const char *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result base64_to_binary_details( const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::base64_to_binary_details_impl( input.data(), input.size(), binary_output.data(), options, last_chunk_options); } else #endif { return base64_to_binary_details( reinterpret_cast(input.data()), input.size(), reinterpret_cast(binary_output.data()), options, last_chunk_options); } } #endif // SIMDUTF_SPAN /** * Convert a base64 input to a binary output while returning more details * than base64_to_binary. * * This function follows the WHATWG forgiving-base64 format, which means that it * will ignore any ASCII spaces in the input. You may provide a padded input * (with one or two equal signs at the end) or an unpadded input (without any * equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * Unlike base64_to_binary, this function returns a full_result with both * input_count and output_count, so you always know how much input was consumed * and how much output was written. There are three cases where the input may * not be fully consumed: * * 1. stop_before_partial: When last_chunk_options is set to * stop_before_partial, any incomplete 4-character group at the end of the * input is left unconsumed. This is useful for streaming/chunked decoding * where you can carry over the unconsumed input to the next chunk. * * 2. INVALID_BASE64_CHARACTER: The input contains a character that is not a * valid base64 character. In this case, input_count indicates where the * invalid character was found. * * 3. BASE64_INPUT_REMAINDER: When last_chunk_options is loose, the input * contains a number of base64 characters that, when divided by 4, leaves * a single remainder character (which cannot encode any bytes). * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you fail to * provide that much space, the function may cause a buffer overflow. * * @param input the base64 string to process, in ASCII stored as 16-bit * units * @param length the length of the string in 16-bit units * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the last chunk handling options, * last_chunk_handling_options::loose by default * but can also be last_chunk_handling_options::strict or * last_chunk_handling_options::stop_before_partial. * @return a full_result struct (of type simdutf::full_result containing the * three fields error, input_count and output_count). */ simdutf_warn_unused full_result base64_to_binary_details(const char16_t *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose) noexcept; #if SIMDUTF_SPAN simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 full_result base64_to_binary_details( std::span input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose) noexcept { #if SIMDUTF_CPLUSPLUS23 if consteval { return scalar::base64::base64_to_binary_details_impl( input.data(), input.size(), binary_output.data(), options, last_chunk_options); } else #endif { return base64_to_binary_details( input.data(), input.size(), reinterpret_cast(binary_output.data()), options, last_chunk_options); } } #endif // SIMDUTF_SPAN /** * Check if a character is an ignorable base64 character. * Checking a large input, character by character, is not computationally * efficient. * * @param input the character to check * @param options the base64 options to use, is base64_default by default. * @return true if the character is an ignorable base64 character, false * otherwise. */ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool base64_ignorable(char input, base64_options options = base64_default) noexcept { return scalar::base64::is_ignorable(input, options); } simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool base64_ignorable(char16_t input, base64_options options = base64_default) noexcept { return scalar::base64::is_ignorable(input, options); } /** * Check if a character is a valid base64 character. * Checking a large input, character by character, is not computationally * efficient. * Note that padding characters are not considered valid base64 characters in * this context, nor are spaces. * * @param input the character to check * @param options the base64 options to use, is base64_default by default. * @return true if the character is a base64 character, false otherwise. */ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool base64_valid(char input, base64_options options = base64_default) noexcept { return scalar::base64::is_base64(input, options); } simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool base64_valid(char16_t input, base64_options options = base64_default) noexcept { return scalar::base64::is_base64(input, options); } /** * Check if a character is a valid base64 character or the padding character * ('='). Checking a large input, character by character, is not computationally * efficient. * * @param input the character to check * @param options the base64 options to use, is base64_default by default. * @return true if the character is a base64 character, false otherwise. */ simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool base64_valid_or_padding(char input, base64_options options = base64_default) noexcept { return scalar::base64::is_base64_or_padding(input, options); } simdutf_warn_unused simdutf_really_inline simdutf_constexpr23 bool base64_valid_or_padding(char16_t input, base64_options options = base64_default) noexcept { return scalar::base64::is_base64_or_padding(input, options); } /** * Convert a base64 input to a binary output. * * This function follows the WHATWG forgiving-base64 format, which means that it * will ignore any ASCII spaces in the input. You may provide a padded input * (with one or two equal signs at the end) or an unpadded input (without any * equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * This function will fail in case of invalid input. When last_chunk_options = * loose, there are three possible reasons for failure: the input contains a * number of base64 characters that when divided by 4, leaves a single remainder * character (BASE64_INPUT_REMAINDER), the input contains a character that is * not a valid base64 character (INVALID_BASE64_CHARACTER), or the output buffer * is too small (OUTPUT_BUFFER_TOO_SMALL). * * When OUTPUT_BUFFER_TOO_SMALL, we return both the number of bytes written * and the number of units processed, see description of the parameters and * returned value. * * When the error is INVALID_BASE64_CHARACTER, r.count contains the index in the * input where the invalid character was found. When the error is * BASE64_INPUT_REMAINDER, then r.count contains the number of bytes decoded. * * The default option (simdutf::base64_default) expects the characters `+` and * `/` as part of its alphabet. The URL option (simdutf::base64_url) expects the * characters `-` and `_` as part of its alphabet. * * The padding (`=`) is validated if present. There may be at most two padding * characters at the end of the input. If there are any padding characters, the * total number of characters (excluding spaces but including padding * characters) must be divisible by four. * * The INVALID_BASE64_CHARACTER cases are considered fatal and you are expected * to discard the output unless the parameter decode_up_to_bad_char is set to * true. In that case, the function will decode up to the first invalid * character. Extra padding characters ('=') are considered invalid characters. * * Advanced users may want to tailor how the last chunk is handled. By default, * we use a loose (forgiving) approach but we also support a strict approach * as well as a stop_before_partial approach, as per the following proposal: * * https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 * * The base64_to_binary_safe function has negligible overhead compared with * base64_to_binary in the absence of ignorable characters; however, on short * inputs containing ignorable characters, it can be up to three times slower. * * @param input the base64 string to process, in ASCII stored as 8-bit * or 16-bit units * @param length the length of the string in 8-bit or 16-bit units. * @param output the pointer to a buffer that can hold the conversion * result. * @param outlen the number of bytes that can be written in the output * buffer. Upon return, it is modified to reflect how many bytes were written. * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the last chunk handling options, * last_chunk_handling_options::loose by default * but can also be last_chunk_handling_options::strict or * last_chunk_handling_options::stop_before_partial. * @param decode_up_to_bad_char if true, the function will decode up to the * first invalid character. By default (false), it is assumed that the output * buffer is to be discarded. When there are multiple errors in the input, * using decode_up_to_bad_char might trigger a different error. * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and position of the * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the number * of units processed if successful. */ simdutf_warn_unused result base64_to_binary_safe(const char *input, size_t length, char *output, size_t &outlen, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose, bool decode_up_to_bad_char = false) noexcept; // the span overload has moved to the bottom of the file simdutf_warn_unused result base64_to_binary_safe(const char16_t *input, size_t length, char *output, size_t &outlen, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose, bool decode_up_to_bad_char = false) noexcept; // span overload moved to bottom of file #if SIMDUTF_ATOMIC_REF /** * Convert a base64 input to a binary output with a size limit and using atomic * operations. * * Like `base64_to_binary_safe` but using atomic operations, this function is * thread-safe for concurrent memory access, allowing the output * buffers to be shared between threads without undefined behavior in case of * data races. * * This function comes with a potentially significant performance penalty, but * is useful when thread safety is needed during base64 decoding. * * This function is only available when simdutf is compiled with * C++20 support and __cpp_lib_atomic_ref >= 201806L. You may check * the availability of this function by checking the macro * SIMDUTF_ATOMIC_REF. * * This function is considered experimental. It is not tested by default * (see the CMake option SIMDUTF_ATOMIC_BASE64_TESTS) nor is it fuzz tested. * It is not documented in the public API documentation (README). It is * offered on a best effort basis. We rely on the community for further * testing and feedback. * * @param input the base64 input to decode * @param length the length of the input in bytes * @param output the pointer to buffer that can hold the conversion * result * @param outlen the number of bytes that can be written in the output * buffer. Upon return, it is modified to reflect how many bytes were written. * @param options the base64 options to use (default, url, etc.) * @param last_chunk_options the last chunk handling options (loose, strict, * stop_before_partial) * @param decode_up_to_bad_char if true, the function will decode up to the * first invalid character. By default (false), it is assumed that the output * buffer is to be discarded. When there are multiple errors in the input, * using decode_up_to_bad_char might trigger a different error. * @return a result struct with an error code and count indicating error * position or success */ simdutf_warn_unused result atomic_base64_to_binary_safe( const char *input, size_t length, char *output, size_t &outlen, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose, bool decode_up_to_bad_char = false) noexcept; simdutf_warn_unused result atomic_base64_to_binary_safe( const char16_t *input, size_t length, char *output, size_t &outlen, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose, bool decode_up_to_bad_char = false) noexcept; #if SIMDUTF_SPAN /** * @brief span overload * @return a tuple of result and outlen */ simdutf_really_inline simdutf_warn_unused std::tuple atomic_base64_to_binary_safe( const detail::input_span_of_byte_like auto &binary_input, detail::output_span_of_byte_like auto &&output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose, bool decode_up_to_bad_char = false) noexcept { size_t outlen = output.size(); auto ret = atomic_base64_to_binary_safe( reinterpret_cast(binary_input.data()), binary_input.size(), reinterpret_cast(output.data()), outlen, options, last_chunk_options, decode_up_to_bad_char); return {ret, outlen}; } /** * @brief span overload * @return a tuple of result and outlen */ simdutf_warn_unused std::tuple atomic_base64_to_binary_safe( std::span base64_input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose, bool decode_up_to_bad_char = false) noexcept { size_t outlen = binary_output.size(); auto ret = atomic_base64_to_binary_safe( base64_input.data(), base64_input.size(), reinterpret_cast(binary_output.data()), outlen, options, last_chunk_options, decode_up_to_bad_char); return {ret, outlen}; } #endif // SIMDUTF_SPAN #endif // SIMDUTF_ATOMIC_REF #endif // SIMDUTF_FEATURE_BASE64 /** * An implementation of simdutf for a particular CPU architecture. * * Also used to maintain the currently active implementation. The active * implementation is automatically initialized on first use to the most advanced * implementation supported by the host. */ class implementation { public: /** * The name of this implementation. * * const implementation *impl = simdutf::active_implementation; * cout << "simdutf is optimized for " << impl->name() << "(" << * impl->description() << ")" << endl; * * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" */ virtual std::string_view name() const noexcept { return _name; } /** * The description of this implementation. * * const implementation *impl = simdutf::active_implementation; * cout << "simdutf is optimized for " << impl->name() << "(" << * impl->description() << ")" << endl; * * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" */ virtual std::string_view description() const noexcept { return _description; } /** * The instruction sets this implementation is compiled against * and the current CPU match. This function may poll the current CPU/system * and should therefore not be called too often if performance is a concern. * * * @return true if the implementation can be safely used on the current system * (determined at runtime) */ bool supported_by_runtime_system() const; #if SIMDUTF_FEATURE_DETECT_ENCODING /** * This function will try to detect the encoding * @param input the string to identify * @param length the length of the string in bytes. * @return the encoding type detected */ virtual encoding_type autodetect_encoding(const char *input, size_t length) const noexcept; /** * This function will try to detect the possible encodings in one pass * @param input the string to identify * @param length the length of the string in bytes. * @return the encoding type detected */ virtual int detect_encodings(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_DETECT_ENCODING /** * @private For internal implementation use * * The instruction sets this implementation is compiled against. * * @return a mask of all required `internal::instruction_set::` values */ virtual uint32_t required_instruction_sets() const { return _required_instruction_sets; } #if SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING /** * Validate the UTF-8 string. * * Overridden by each implementation. * * @param buf the UTF-8 string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid UTF-8. */ simdutf_warn_unused virtual bool validate_utf8(const char *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF8 /** * Validate the UTF-8 string and stop on errors. * * Overridden by each implementation. * * @param buf the UTF-8 string to validate. * @param len the length of the string in bytes. * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result validate_utf8_with_errors(const char *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_ASCII /** * Validate the ASCII string. * * Overridden by each implementation. * * @param buf the ASCII string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ simdutf_warn_unused virtual bool validate_ascii(const char *buf, size_t len) const noexcept = 0; /** * Validate the ASCII string and stop on error. * * Overridden by each implementation. * * @param buf the ASCII string to validate. * @param len the length of the string in bytes. * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result validate_ascii_with_errors(const char *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII /** * Validate the ASCII string as a UTF-16BE sequence. * An UTF-16 sequence is considered an ASCII sequence * if it could be converted to an ASCII string losslessly. * * Overridden by each implementation. * * @param buf the UTF-16BE string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ simdutf_warn_unused virtual bool validate_utf16be_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; /** * Validate the ASCII string as a UTF-16LE sequence. * An UTF-16 sequence is considered an ASCII sequence * if it could be converted to an ASCII string losslessly. * * Overridden by each implementation. * * @param buf the UTF-16LE string to validate. * @param len the length of the string in bytes. * @return true if and only if the string is valid ASCII. */ simdutf_warn_unused virtual bool validate_utf16le_as_ascii(const char16_t *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_ASCII #if SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING /** * Validate the UTF-16LE string.This function may be best when you expect * the input to be almost always valid. Otherwise, consider using * validate_utf16le_with_errors. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16LE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return true if and only if the string is valid UTF-16LE. */ simdutf_warn_unused virtual bool validate_utf16le(const char16_t *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF16 /** * Validate the UTF-16BE string. This function may be best when you expect * the input to be almost always valid. Otherwise, consider using * validate_utf16be_with_errors. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16BE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return true if and only if the string is valid UTF-16BE. */ simdutf_warn_unused virtual bool validate_utf16be(const char16_t *buf, size_t len) const noexcept = 0; /** * Validate the UTF-16LE string and stop on error. It might be faster than * validate_utf16le when an error is expected to occur early. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16LE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result validate_utf16le_with_errors(const char16_t *buf, size_t len) const noexcept = 0; /** * Validate the UTF-16BE string and stop on error. It might be faster than * validate_utf16be when an error is expected to occur early. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-16BE string to validate. * @param len the length of the string in number of 2-byte code units * (char16_t). * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result validate_utf16be_with_errors(const char16_t *buf, size_t len) const noexcept = 0; /** * Copies the UTF-16LE string while replacing mismatched surrogates with the * Unicode replacement character U+FFFD. We allow the input and output to be * the same buffer so that the correction is done in-place. * * Overridden by each implementation. * * @param input the UTF-16LE string to correct. * @param len the length of the string in number of 2-byte code units * (char16_t). * @param output the output buffer. */ virtual void to_well_formed_utf16le(const char16_t *input, size_t len, char16_t *output) const noexcept = 0; /** * Copies the UTF-16BE string while replacing mismatched surrogates with the * Unicode replacement character U+FFFD. We allow the input and output to be * the same buffer so that the correction is done in-place. * * Overridden by each implementation. * * @param input the UTF-16BE string to correct. * @param len the length of the string in number of 2-byte code units * (char16_t). * @param output the output buffer. */ virtual void to_well_formed_utf16be(const char16_t *input, size_t len, char16_t *output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING /** * Validate the UTF-32 string. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-32 string to validate. * @param len the length of the string in number of 4-byte code units * (char32_t). * @return true if and only if the string is valid UTF-32. */ simdutf_warn_unused virtual bool validate_utf32(const char32_t *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 || SIMDUTF_FEATURE_DETECT_ENCODING #if SIMDUTF_FEATURE_UTF32 /** * Validate the UTF-32 string and stop on error. * * Overridden by each implementation. * * This function is not BOM-aware. * * @param buf the UTF-32 string to validate. * @param len the length of the string in number of 4-byte code units * (char32_t). * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result validate_utf32_with_errors(const char32_t *buf, size_t len) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Convert Latin1 string into UTF-8 string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf8_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_latin1_to_utf8(const char *input, size_t length, char *utf8_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly Latin1 string into UTF-16LE string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_latin1_to_utf16le(const char *input, size_t length, char16_t *utf16_output) const noexcept = 0; /** * Convert Latin1 string into UTF-16BE string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_latin1_to_utf16be(const char *input, size_t length, char16_t *utf16_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 /** * Convert Latin1 string into UTF-32 string. * * This function is suitable to work with inputs from untrusted sources. * * @param input the Latin1 string to convert * @param length the length of the string in bytes * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_latin1_to_utf32(const char *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly broken UTF-8 string into latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param latin1_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if the input was not valid UTF-8 * string or if it cannot be represented as Latin1 */ simdutf_warn_unused virtual size_t convert_utf8_to_latin1(const char *input, size_t length, char *latin1_output) const noexcept = 0; /** * Convert possibly broken UTF-8 string into latin1 string with errors. * If the string cannot be represented as Latin1, an error * code is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param latin1_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result convert_utf8_to_latin1_with_errors(const char *input, size_t length, char *latin1_output) const noexcept = 0; /** * Convert valid UTF-8 string into latin1 string. * * This function assumes that the input string is valid UTF-8 and that it can * be represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf8_to_latin1 instead. * * This function is not BOM-aware. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param latin1_output the pointer to buffer that can hold conversion result * @return the number of written char; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused virtual size_t convert_valid_utf8_to_latin1(const char *input, size_t length, char *latin1_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Convert possibly broken UTF-8 string into UTF-16LE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused virtual size_t convert_utf8_to_utf16le(const char *input, size_t length, char16_t *utf16_output) const noexcept = 0; /** * Convert possibly broken UTF-8 string into UTF-16BE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused virtual size_t convert_utf8_to_utf16be(const char *input, size_t length, char16_t *utf16_output) const noexcept = 0; /** * Convert possibly broken UTF-8 string into UTF-16LE string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result convert_utf8_to_utf16le_with_errors( const char *input, size_t length, char16_t *utf16_output) const noexcept = 0; /** * Convert possibly broken UTF-8 string into UTF-16BE string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of code units validated * if successful. */ simdutf_warn_unused virtual result convert_utf8_to_utf16be_with_errors( const char *input, size_t length, char16_t *utf16_output) const noexcept = 0; /** * Compute the number of bytes that this UTF-16LE string would require in * UTF-8 format even when the UTF-16LE content contains mismatched * surrogates that have to be replaced by the replacement character (0xFFFD). * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @return a result pair struct (of type simdutf::result containing the two * fields error and count) where the count is the number of bytes required to * encode the UTF-16LE string as UTF-8, and the error code is either SUCCESS * or SURROGATE. The count is correct regardless of the error field. * When SURROGATE is returned, it does not indicate an error in the case of * this function: it indicates that at least one surrogate has been * encountered: the surrogates may be matched or not (thus this function does * not validate). If the returned error code is SUCCESS, then the input * contains no surrogate, is in the Basic Multilingual Plane, and is * necessarily valid. */ virtual simdutf_warn_unused result utf8_length_from_utf16le_with_replacement( const char16_t *input, size_t length) const noexcept = 0; /** * Compute the number of bytes that this UTF-16BE string would require in * UTF-8 format even when the UTF-16BE content contains mismatched * surrogates that have to be replaced by the replacement character (0xFFFD). * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @return a result pair struct (of type simdutf::result containing the two * fields error and count) where the count is the number of bytes required to * encode the UTF-16BE string as UTF-8, and the error code is either SUCCESS * or SURROGATE. The count is correct regardless of the error field. * When SURROGATE is returned, it does not indicate an error in the case of * this function: it indicates that at least one surrogate has been * encountered: the surrogates may be matched or not (thus this function does * not validate). If the returned error code is SUCCESS, then the input * contains no surrogate, is in the Basic Multilingual Plane, and is * necessarily valid. */ virtual simdutf_warn_unused result utf8_length_from_utf16be_with_replacement( const char16_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Convert possibly broken UTF-8 string into UTF-32 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf32_output the pointer to buffer that can hold conversion result * @return the number of written char16_t; 0 if the input was not valid UTF-8 * string */ simdutf_warn_unused virtual size_t convert_utf8_to_utf32(const char *input, size_t length, char32_t *utf32_output) const noexcept = 0; /** * Convert possibly broken UTF-8 string into UTF-32 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf32_output the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char32_t written if * successful. */ simdutf_warn_unused virtual result convert_utf8_to_utf32_with_errors(const char *input, size_t length, char32_t *utf32_output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Convert valid UTF-8 string into UTF-16LE string. * * This function assumes that the input string is valid UTF-8. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ simdutf_warn_unused virtual size_t convert_valid_utf8_to_utf16le(const char *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; /** * Convert valid UTF-8 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-8. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf16_buffer the pointer to buffer that can hold conversion result * @return the number of written char16_t */ simdutf_warn_unused virtual size_t convert_valid_utf8_to_utf16be(const char *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Convert valid UTF-8 string into UTF-32 string. * * This function assumes that the input string is valid UTF-8. * * @param input the UTF-8 string to convert * @param length the length of the string in bytes * @param utf32_buffer the pointer to buffer that can hold conversion result * @return the number of written char32_t */ simdutf_warn_unused virtual size_t convert_valid_utf8_to_utf32(const char *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Compute the number of 2-byte code units that this UTF-8 string would * require in UTF-16LE format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-8 strings but in such cases the result is implementation defined. * * @param input the UTF-8 string to process * @param length the length of the string in bytes * @return the number of char16_t code units required to encode the UTF-8 * string as UTF-16LE */ simdutf_warn_unused virtual size_t utf16_length_from_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Compute the number of 4-byte code units that this UTF-8 string would * require in UTF-32 format. * * This function is equivalent to count_utf8. It is acceptable to pass invalid * UTF-8 strings but in such cases the result is implementation defined. * * This function does not validate the input. * * @param input the UTF-8 string to process * @param length the length of the string in bytes * @return the number of char32_t code units required to encode the UTF-8 * string as UTF-32 */ simdutf_warn_unused virtual size_t utf32_length_from_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly broken UTF-16LE string into Latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return number of written code units; 0 if input is not a valid UTF-16LE * string or if it cannot be represented as Latin1 */ simdutf_warn_unused virtual size_t convert_utf16le_to_latin1(const char16_t *input, size_t length, char *latin1_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16BE string into Latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return number of written code units; 0 if input is not a valid UTF-16BE * string or if it cannot be represented as Latin1 */ simdutf_warn_unused virtual size_t convert_utf16be_to_latin1(const char16_t *input, size_t length, char *latin1_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16LE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused virtual result convert_utf16le_to_latin1_with_errors(const char16_t *input, size_t length, char *latin1_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16BE string into Latin1 string. * If the string cannot be represented as Latin1, an error * is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused virtual result convert_utf16be_to_latin1_with_errors(const char16_t *input, size_t length, char *latin1_buffer) const noexcept = 0; /** * Convert valid UTF-16LE string into Latin1 string. * * This function assumes that the input string is valid UTF-L16LE and that it * can be represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf16le_to_latin1 instead. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf16le_to_latin1(const char16_t *input, size_t length, char *latin1_buffer) const noexcept = 0; /** * Convert valid UTF-16BE string into Latin1 string. * * This function assumes that the input string is valid UTF16-BE and that it * can be represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf16be_to_latin1 instead. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf16be_to_latin1(const char16_t *input, size_t length, char *latin1_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Convert possibly broken UTF-16LE string into UTF-8 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused virtual size_t convert_utf16le_to_utf8(const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16BE string into UTF-8 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16BE * string */ simdutf_warn_unused virtual size_t convert_utf16be_to_utf8(const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16LE string into UTF-8 string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused virtual result convert_utf16le_to_utf8_with_errors(const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16BE string into UTF-8 string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused virtual result convert_utf16be_to_utf8_with_errors(const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16LE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * * This function always succeeds: unpaired surrogates are replaced with * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ simdutf_warn_unused virtual size_t convert_utf16le_to_utf8_with_replacement( const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16BE string into UTF-8 string, replacing * unpaired surrogates with the Unicode replacement character U+FFFD. * * This function always succeeds: unpaired surrogates are replaced with * U+FFFD (3 bytes in UTF-8: 0xEF 0xBF 0xBD). * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units */ simdutf_warn_unused virtual size_t convert_utf16be_to_utf8_with_replacement( const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert valid UTF-16LE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16LE. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf16le_to_utf8(const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert valid UTF-16BE string into UTF-8 string. * * This function assumes that the input string is valid UTF-16BE. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf8_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf16be_to_utf8(const char16_t *input, size_t length, char *utf8_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Convert possibly broken UTF-16LE string into UTF-32 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16LE * string */ simdutf_warn_unused virtual size_t convert_utf16le_to_utf32(const char16_t *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16BE string into UTF-32 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-16BE * string */ simdutf_warn_unused virtual size_t convert_utf16be_to_utf32(const char16_t *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16LE string into UTF-32 string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char32_t written if * successful. */ simdutf_warn_unused virtual result convert_utf16le_to_utf32_with_errors( const char16_t *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; /** * Convert possibly broken UTF-16BE string into UTF-32 string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf32_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char32_t written if * successful. */ simdutf_warn_unused virtual result convert_utf16be_to_utf32_with_errors( const char16_t *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; /** * Convert valid UTF-16LE string into UTF-32 string. * * This function assumes that the input string is valid UTF-16LE. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf32_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf16le_to_utf32(const char16_t *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; /** * Convert valid UTF-16LE string into UTF-32BE string. * * This function assumes that the input string is valid UTF-16BE. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @param utf32_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf16be_to_utf32(const char16_t *input, size_t length, char32_t *utf32_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 /** * Compute the number of bytes that this UTF-16LE string would require in * UTF-8 format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @return the number of bytes required to encode the UTF-16LE string as UTF-8 */ simdutf_warn_unused virtual size_t utf8_length_from_utf16le(const char16_t *input, size_t length) const noexcept = 0; /** * Compute the number of bytes that this UTF-16BE string would require in * UTF-8 format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @return the number of bytes required to encode the UTF-16BE string as UTF-8 */ simdutf_warn_unused virtual size_t utf8_length_from_utf16be(const char16_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly broken UTF-32 string into Latin1 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return number of written code units; 0 if input is not a valid UTF-32 * string */ simdutf_warn_unused virtual size_t convert_utf32_to_latin1(const char32_t *input, size_t length, char *latin1_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 /** * Convert possibly broken UTF-32 string into Latin1 string and stop on error. * If the string cannot be represented as Latin1, an error is returned. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param latin1_buffer the pointer to buffer that can hold conversion * result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused virtual result convert_utf32_to_latin1_with_errors(const char32_t *input, size_t length, char *latin1_buffer) const noexcept = 0; /** * Convert valid UTF-32 string into Latin1 string. * * This function assumes that the input string is valid UTF-32 and can be * represented as Latin1. If you violate this assumption, the result is * implementation defined and may include system-dependent behavior such as * crashes. * * This function is for expert users only and not part of our public API. Use * convert_utf32_to_latin1 instead. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param latin1_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf32_to_latin1(const char32_t *input, size_t length, char *latin1_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Convert possibly broken UTF-32 string into UTF-8 string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 * string */ simdutf_warn_unused virtual size_t convert_utf32_to_utf8(const char32_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert possibly broken UTF-32 string into UTF-8 string and stop on error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf8_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char written if * successful. */ simdutf_warn_unused virtual result convert_utf32_to_utf8_with_errors(const char32_t *input, size_t length, char *utf8_buffer) const noexcept = 0; /** * Convert valid UTF-32 string into UTF-8 string. * * This function assumes that the input string is valid UTF-32. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf8_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf32_to_utf8(const char32_t *input, size_t length, char *utf8_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Return the number of bytes that this UTF-16 string would require in Latin1 * format. * * * @param length the length of the string in 2-byte code units * (char16_t) * @return the number of bytes required to encode the UTF-16 string as Latin1 */ simdutf_warn_unused virtual size_t utf16_length_from_latin1(size_t length) const noexcept { return length; } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Convert possibly broken UTF-32 string into UTF-16LE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 * string */ simdutf_warn_unused virtual size_t convert_utf32_to_utf16le(const char32_t *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; /** * Convert possibly broken UTF-32 string into UTF-16BE string. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return number of written code units; 0 if input is not a valid UTF-32 * string */ simdutf_warn_unused virtual size_t convert_utf32_to_utf16be(const char32_t *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; /** * Convert possibly broken UTF-32 string into UTF-16LE string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused virtual result convert_utf32_to_utf16le_with_errors( const char32_t *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; /** * Convert possibly broken UTF-32 string into UTF-16BE string and stop on * error. * * During the conversion also validation of the input string is done. * This function is suitable to work with inputs from untrusted sources. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf16_buffer the pointer to buffer that can hold conversion result * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in code units) if any, or the number of char16_t written if * successful. */ simdutf_warn_unused virtual result convert_utf32_to_utf16be_with_errors( const char32_t *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; /** * Convert valid UTF-32 string into UTF-16LE string. * * This function assumes that the input string is valid UTF-32. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf16_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf32_to_utf16le(const char32_t *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; /** * Convert valid UTF-32 string into UTF-16BE string. * * This function assumes that the input string is valid UTF-32. * * This function is not BOM-aware. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @param utf16_buffer the pointer to a buffer that can hold the conversion * result * @return number of written code units; 0 if conversion is not possible */ simdutf_warn_unused virtual size_t convert_valid_utf32_to_utf16be(const char32_t *input, size_t length, char16_t *utf16_buffer) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 /** * Change the endianness of the input. Can be used to go from UTF-16LE to * UTF-16BE or from UTF-16BE to UTF-16LE. * * This function does not validate the input. * * This function is not BOM-aware. * * @param input the UTF-16 string to process * @param length the length of the string in 2-byte code units * (char16_t) * @param output the pointer to a buffer that can hold the conversion * result */ virtual void change_endianness_utf16(const char16_t *input, size_t length, char16_t *output) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Return the number of bytes that this Latin1 string would require in UTF-8 * format. * * @param input the Latin1 string to convert * @param length the length of the string bytes * @return the number of bytes required to encode the Latin1 string as UTF-8 */ simdutf_warn_unused virtual size_t utf8_length_from_latin1(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 /** * Compute the number of bytes that this UTF-32 string would require in UTF-8 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-32 strings but in such cases the result is implementation defined. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-8 */ simdutf_warn_unused virtual size_t utf8_length_from_utf32(const char32_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 /** * Compute the number of bytes that this UTF-32 string would require in Latin1 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-32 strings but in such cases the result is implementation defined. * * @param length the length of the string in 4-byte code units * (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ simdutf_warn_unused virtual size_t latin1_length_from_utf32(size_t length) const noexcept { return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 /** * Compute the number of bytes that this UTF-8 string would require in Latin1 * format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-8 strings but in such cases the result is implementation defined. * * @param input the UTF-8 string to convert * @param length the length of the string in byte * @return the number of bytes required to encode the UTF-8 string as Latin1 */ simdutf_warn_unused virtual size_t latin1_length_from_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 /** * Compute the number of bytes that this UTF-16LE/BE string would require in * Latin1 format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param length the length of the string in 2-byte code units * (char16_t) * @return the number of bytes required to encode the UTF-16LE string as * Latin1 */ simdutf_warn_unused virtual size_t latin1_length_from_utf16(size_t length) const noexcept { return length; } #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Compute the number of two-byte code units that this UTF-32 string would * require in UTF-16 format. * * This function does not validate the input. It is acceptable to pass invalid * UTF-32 strings but in such cases the result is implementation defined. * * @param input the UTF-32 string to convert * @param length the length of the string in 4-byte code units * (char32_t) * @return the number of bytes required to encode the UTF-32 string as UTF-16 */ simdutf_warn_unused virtual size_t utf16_length_from_utf32(const char32_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 /** * Return the number of bytes that this UTF-32 string would require in Latin1 * format. * * @param length the length of the string in 4-byte code units * (char32_t) * @return the number of bytes required to encode the UTF-32 string as Latin1 */ simdutf_warn_unused virtual size_t utf32_length_from_latin1(size_t length) const noexcept { return length; } #endif // SIMDUTF_FEATURE_UTF32 && SIMDUTF_FEATURE_LATIN1 #if SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 /** * Compute the number of bytes that this UTF-16LE string would require in * UTF-32 format. * * This function is equivalent to count_utf16le. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16LE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @return the number of bytes required to encode the UTF-16LE string as * UTF-32 */ simdutf_warn_unused virtual size_t utf32_length_from_utf16le(const char16_t *input, size_t length) const noexcept = 0; /** * Compute the number of bytes that this UTF-16BE string would require in * UTF-32 format. * * This function is equivalent to count_utf16be. * * This function does not validate the input. It is acceptable to pass invalid * UTF-16 strings but in such cases the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16BE string to convert * @param length the length of the string in 2-byte code units * (char16_t) * @return the number of bytes required to encode the UTF-16BE string as * UTF-32 */ simdutf_warn_unused virtual size_t utf32_length_from_utf16be(const char16_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 && SIMDUTF_FEATURE_UTF32 #if SIMDUTF_FEATURE_UTF16 /** * Count the number of code points (characters) in the string assuming that * it is valid. * * This function assumes that the input string is valid UTF-16LE. * It is acceptable to pass invalid UTF-16 strings but in such cases * the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16LE string to process * @param length the length of the string in 2-byte code units * (char16_t) * @return number of code points */ simdutf_warn_unused virtual size_t count_utf16le(const char16_t *input, size_t length) const noexcept = 0; /** * Count the number of code points (characters) in the string assuming that * it is valid. * * This function assumes that the input string is valid UTF-16BE. * It is acceptable to pass invalid UTF-16 strings but in such cases * the result is implementation defined. * * This function is not BOM-aware. * * @param input the UTF-16BE string to process * @param length the length of the string in 2-byte code units * (char16_t) * @return number of code points */ simdutf_warn_unused virtual size_t count_utf16be(const char16_t *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF16 #if SIMDUTF_FEATURE_UTF8 /** * Count the number of code points (characters) in the string assuming that * it is valid. * * This function assumes that the input string is valid UTF-8. * It is acceptable to pass invalid UTF-8 strings but in such cases * the result is implementation defined. * * @param input the UTF-8 string to process * @param length the length of the string in bytes * @return number of code points */ simdutf_warn_unused virtual size_t count_utf8(const char *input, size_t length) const noexcept = 0; #endif // SIMDUTF_FEATURE_UTF8 #if SIMDUTF_FEATURE_BASE64 /** * Provide the maximal binary length in bytes given the base64 input. * As long as the input does not contain ignorable characters (e.g., ASCII * spaces or linefeed characters), the result is exact. In particular, the * function checks for padding characters. * * The function is fast (constant time). It checks up to two characters at * the end of the string. The input is not otherwise validated or read.. * * @param input the base64 input to process * @param length the length of the base64 input in bytes * @return maximal number of binary bytes */ simdutf_warn_unused size_t maximal_binary_length_from_base64( const char *input, size_t length) const noexcept; /** * Provide the maximal binary length in bytes given the base64 input. * As long as the input does not contain ignorable characters (e.g., ASCII * spaces or linefeed characters), the result is exact. In particular, the * function checks for padding characters. * * The function is fast (constant time). It checks up to two characters at * the end of the string. The input is not otherwise validated or read. * * @param input the base64 input to process, in ASCII stored as 16-bit * units * @param length the length of the base64 input in 16-bit units * @return maximal number of binary bytes */ simdutf_warn_unused size_t maximal_binary_length_from_base64( const char16_t *input, size_t length) const noexcept; /** * Compute the binary length from a base64 input with ASCII spaces. * This function is useful for well-formed base64 inputs that may contain * ASCII spaces (such as line breaks). For such inputs, the result is exact. * * The function counts non-whitespace characters (ASCII value > 0x20) and * subtracts padding characters ('=') found at the end. * * @param input the base64 input to process * @param length the length of the base64 input in bytes * @return number of binary bytes */ simdutf_warn_unused virtual size_t binary_length_from_base64(const char *input, size_t length) const noexcept; /** * Compute the binary length from a base64 input with ASCII spaces. * This function is useful for well-formed base64 inputs that may contain * ASCII spaces (such as line breaks). For such inputs, the result is exact. * * The function counts non-whitespace characters (ASCII value > 0x20) and * subtracts padding characters ('=') found at the end. * * @param input the base64 input to process, in ASCII stored as 16-bit * units * @param length the length of the base64 input in 16-bit units * @return number of binary bytes */ simdutf_warn_unused virtual size_t binary_length_from_base64(const char16_t *input, size_t length) const noexcept; /** * Convert a base64 input to a binary output. * * This function follows the WHATWG forgiving-base64 format, which means that * it will ignore any ASCII spaces in the input. You may provide a padded * input (with one or two equal signs at the end) or an unpadded input * (without any equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * This function will fail in case of invalid input. When last_chunk_options = * loose, there are two possible reasons for failure: the input contains a * number of base64 characters that when divided by 4, leaves a single * remainder character (BASE64_INPUT_REMAINDER), or the input contains a * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you fail to * provide that much space, the function may cause a buffer overflow. * * @param input the base64 string to process * @param length the length of the string in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the handling of the last chunk (default: loose) * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and either position of the error * (in the input in bytes) if any, or the number of bytes written if * successful. */ simdutf_warn_unused virtual result base64_to_binary(const char *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose) const noexcept = 0; /** * Convert a base64 input to a binary output while returning more details * than base64_to_binary. * * This function follows the WHATWG forgiving-base64 format, which means that * it will ignore any ASCII spaces in the input. You may provide a padded * input (with one or two equal signs at the end) or an unpadded input * (without any equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * This function will fail in case of invalid input. When last_chunk_options = * loose, there are two possible reasons for failure: the input contains a * number of base64 characters that when divided by 4, leaves a single * remainder character (BASE64_INPUT_REMAINDER), or the input contains a * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you fail to * provide that much space, the function may cause a buffer overflow. * * @param input the base64 string to process * @param length the length of the string in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the handling of the last chunk (default: loose) * @return a full_result pair struct (of type simdutf::result containing the * three fields error, input_count and output_count). */ simdutf_warn_unused virtual full_result base64_to_binary_details( const char *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose) const noexcept = 0; /** * Convert a base64 input to a binary output. * * This function follows the WHATWG forgiving-base64 format, which means that * it will ignore any ASCII spaces in the input. You may provide a padded * input (with one or two equal signs at the end) or an unpadded input * (without any equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * This function will fail in case of invalid input. When last_chunk_options = * loose, there are two possible reasons for failure: the input contains a * number of base64 characters that when divided by 4, leaves a single * remainder character (BASE64_INPUT_REMAINDER), or the input contains a * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you * fail to provide that much space, the function may cause a buffer overflow. * * @param input the base64 string to process, in ASCII stored as * 16-bit units * @param length the length of the string in 16-bit units * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the handling of the last chunk (default: loose) * @return a result pair struct (of type simdutf::result containing the two * fields error and count) with an error code and position of the * INVALID_BASE64_CHARACTER error (in the input in units) if any, or the * number of bytes written if successful. */ simdutf_warn_unused virtual result base64_to_binary(const char16_t *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose) const noexcept = 0; /** * Convert a base64 input to a binary output while returning more details * than base64_to_binary. * * This function follows the WHATWG forgiving-base64 format, which means that * it will ignore any ASCII spaces in the input. You may provide a padded * input (with one or two equal signs at the end) or an unpadded input * (without any equal signs at the end). * * See https://infra.spec.whatwg.org/#forgiving-base64-decode * * This function will fail in case of invalid input. When last_chunk_options = * loose, there are two possible reasons for failure: the input contains a * number of base64 characters that when divided by 4, leaves a single * remainder character (BASE64_INPUT_REMAINDER), or the input contains a * character that is not a valid base64 character (INVALID_BASE64_CHARACTER). * * You should call this function with a buffer that is at least * maximal_binary_length_from_base64(input, length) bytes long. If you fail to * provide that much space, the function may cause a buffer overflow. * * @param input the base64 string to process * @param length the length of the string in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least maximal_binary_length_from_base64(input, length) * bytes long). * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @param last_chunk_options the handling of the last chunk (default: loose) * @return a full_result pair struct (of type simdutf::result containing the * three fields error, input_count and output_count). */ simdutf_warn_unused virtual full_result base64_to_binary_details( const char16_t *input, size_t length, char *output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = last_chunk_handling_options::loose) const noexcept = 0; /** * Provide the base64 length in bytes given the length of a binary input. * * @param length the length of the input in bytes * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @return number of base64 bytes */ simdutf_warn_unused size_t base64_length_from_binary( size_t length, base64_options options = base64_default) const noexcept; /** * Convert a binary input to a base64 output. * * The default option (simdutf::base64_default) uses the characters `+` and * `/` as part of its alphabet. Further, it adds padding (`=`) at the end of * the output to ensure that the output length is a multiple of four. * * The URL option (simdutf::base64_url) uses the characters `-` and `_` as * part of its alphabet. No padding is added at the end of the output. * * This function always succeeds. * * @param input the binary to process * @param length the length of the input in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least base64_length_from_binary(length) bytes long) * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @return number of written bytes, will be equal to * base64_length_from_binary(length, options) */ virtual size_t binary_to_base64(const char *input, size_t length, char *output, base64_options options = base64_default) const noexcept = 0; /** * Convert a binary input to a base64 output with lines of given length. * Lines are separated by a single linefeed character. * * The default option (simdutf::base64_default) uses the characters `+` and * `/` as part of its alphabet. Further, it adds padding (`=`) at the end of * the output to ensure that the output length is a multiple of four. * * The URL option (simdutf::base64_url) uses the characters `-` and `_` as * part of its alphabet. No padding is added at the end of the output. * * This function always succeeds. * * @param input the binary to process * @param length the length of the input in bytes * @param output the pointer to a buffer that can hold the conversion * result (should be at least base64_length_from_binary_with_lines(length, * options, line_length) bytes long) * @param line_length the length of each line, values smaller than 4 are * interpreted as 4 * @param options the base64 options to use, can be base64_default or * base64_url, is base64_default by default. * @return number of written bytes, will be equal to * base64_length_from_binary_with_lines(length, options, line_length) */ virtual size_t binary_to_base64_with_lines( const char *input, size_t length, char *output, size_t line_length = simdutf::default_line_length, base64_options options = base64_default) const noexcept = 0; /** * Find the first occurrence of a character in a string. If the character is * not found, return a pointer to the end of the string. * @param start the start of the string * @param end the end of the string * @param character the character to find * @return a pointer to the first occurrence of the character in the string, * or a pointer to the end of the string if the character is not found. * */ virtual const char *find(const char *start, const char *end, char character) const noexcept = 0; virtual const char16_t *find(const char16_t *start, const char16_t *end, char16_t character) const noexcept = 0; #endif // SIMDUTF_FEATURE_BASE64 #ifdef SIMDUTF_INTERNAL_TESTS // This method is exported only in developer mode, its purpose // is to expose some internal test procedures from the given // implementation and then use them through our standard test // framework. // // Regular users should not use it, the tests of the public // API are enough. struct TestProcedure { // display name std::string_view name; // procedure should return whether given test pass or not void (*procedure)(const implementation &); }; virtual std::vector internal_tests() const; #endif protected: /** @private Construct an implementation with the given name and description. * For subclasses. * @param name the name of this implementation * @param description a description of this implementation * @param required_instruction_sets the instruction sets this implementation * requires */ simdutf_really_inline implementation(const char *name, const char *description, uint32_t required_instruction_sets) : _name(name), _description(description), _required_instruction_sets(required_instruction_sets) {} protected: ~implementation() = default; private: /** * The name of this implementation. */ const char *_name; /** * The description of this implementation. */ const char *_description; /** * Instruction sets required for this implementation. */ const uint32_t _required_instruction_sets; }; /** @private */ namespace internal { /** * The list of available implementations compiled into simdutf. */ class available_implementation_list { public: /** Get the list of available implementations compiled into simdutf */ simdutf_really_inline available_implementation_list() {} /** Number of implementations */ size_t size() const noexcept; /** STL const begin() iterator */ const implementation *const *begin() const noexcept; /** STL const end() iterator */ const implementation *const *end() const noexcept; /** * Get the implementation with the given name. * * Case sensitive. * * const implementation *impl = * simdutf::available_implementations["westmere"]; if (!impl) { exit(1); } if * (!imp->supported_by_runtime_system()) { exit(1); } * simdutf::active_implementation = impl; * * @param name the implementation to find, e.g. "westmere", "haswell", "arm64" * @return the implementation, or nullptr if the parse failed. */ const implementation *operator[](std::string_view name) const noexcept { for (const implementation *impl : *this) { if (impl->name() == name) { return impl; } } return nullptr; } /** * Detect the most advanced implementation supported by the current host. * * This is used to initialize the implementation on startup. * * const implementation *impl = * simdutf::available_implementation::detect_best_supported(); * simdutf::active_implementation = impl; * * @return the most advanced supported implementation for the current host, or * an implementation that returns UNSUPPORTED_ARCHITECTURE if there is no * supported implementation. Will never return nullptr. */ const implementation *detect_best_supported() const noexcept; }; template class atomic_ptr { public: atomic_ptr(T *_ptr) : ptr{_ptr} {} #if defined(SIMDUTF_NO_THREADS) operator const T *() const { return ptr; } const T &operator*() const { return *ptr; } const T *operator->() const { return ptr; } operator T *() { return ptr; } T &operator*() { return *ptr; } T *operator->() { return ptr; } atomic_ptr &operator=(T *_ptr) { ptr = _ptr; return *this; } #else operator const T *() const { return ptr.load(); } const T &operator*() const { return *ptr; } const T *operator->() const { return ptr.load(); } operator T *() { return ptr.load(); } T &operator*() { return *ptr; } T *operator->() { return ptr.load(); } atomic_ptr &operator=(T *_ptr) { ptr = _ptr; return *this; } #endif private: #if defined(SIMDUTF_NO_THREADS) T *ptr; #else std::atomic ptr; #endif }; class detect_best_supported_implementation_on_first_use; } // namespace internal /** * The list of available implementations compiled into simdutf. */ extern SIMDUTF_DLLIMPORTEXPORT const internal::available_implementation_list & get_available_implementations(); /** * The active implementation. * * Automatically initialized on first use to the most advanced implementation * supported by this hardware. */ extern SIMDUTF_DLLIMPORTEXPORT internal::atomic_ptr & get_active_implementation(); } // namespace simdutf #if SIMDUTF_FEATURE_BASE64 // this header is not part of the public api #include namespace simdutf { #if SIMDUTF_SPAN /** * @brief span overload * @return a tuple of result and outlen */ simdutf_really_inline simdutf_constexpr23 simdutf_warn_unused std::tuple base64_to_binary_safe( const detail::input_span_of_byte_like auto &input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose, bool decode_up_to_bad_char = false) noexcept { size_t outlen = binary_output.size(); #if SIMDUTF_CPLUSPLUS23 if consteval { using CInput = std::decay_t; static_assert(std::is_same_v, "sorry, the constexpr implementation is for now limited to " "input of type char"); using COutput = std::decay_t; static_assert(std::is_same_v, "sorry, the constexpr implementation is for now limited to " "output of type char"); auto r = base64_to_binary_safe_impl( input.data(), input.size(), binary_output.data(), outlen, options, last_chunk_options, decode_up_to_bad_char); return {r, outlen}; } else #endif { auto r = base64_to_binary_safe_impl( reinterpret_cast(input.data()), input.size(), reinterpret_cast(binary_output.data()), outlen, options, last_chunk_options, decode_up_to_bad_char); return {r, outlen}; } } #if SIMDUTF_SPAN /** * @brief span overload * @return a tuple of result and outlen */ simdutf_really_inline simdutf_warn_unused simdutf_constexpr23 std::tuple base64_to_binary_safe( std::span input, detail::output_span_of_byte_like auto &&binary_output, base64_options options = base64_default, last_chunk_handling_options last_chunk_options = loose, bool decode_up_to_bad_char = false) noexcept { size_t outlen = binary_output.size(); #if SIMDUTF_CPLUSPLUS23 if consteval { auto r = base64_to_binary_safe_impl( input.data(), input.size(), binary_output.data(), outlen, options, last_chunk_options, decode_up_to_bad_char); return {r, outlen}; } else #endif { auto r = base64_to_binary_safe( input.data(), input.size(), reinterpret_cast(binary_output.data()), outlen, options, last_chunk_options, decode_up_to_bad_char); return {r, outlen}; } } #endif // SIMDUTF_SPAN #endif // SIMDUTF_SPAN } // namespace simdutf #endif // SIMDUTF_FEATURE_BASE64 #if SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 namespace simdutf { namespace literals { namespace detail { // the detail namespace is not part of the public api template struct base64_literal_helper { std::array storage{}; static constexpr std::size_t size() noexcept { return N - 1; } consteval base64_literal_helper(const char (&str)[N]) { for (std::size_t i = 0; i < size(); i++) { storage[i] = str[i]; } } }; template struct base64_decode_result { static constexpr std::size_t max_out = (InputLen + 3) / 4 * 3; std::array buffer{}; std::size_t output_count{}; }; template consteval auto base64_decode_literal(const char *str) { base64_decode_result result{}; auto r = scalar::base64::base64_to_binary_details_impl( str, InputLen, result.buffer.data(), base64_default, loose); if (r.error != error_code::SUCCESS) { #if __cpp_lib_unreachable >= 202202L std::unreachable(); // invalid base64 input in _base64 literal #else // workaround for older stdlib throw "invalid base64 input in _base64 literal"; #endif } result.output_count = r.output_count; return result; } template consteval auto base64_make_array() { constexpr auto decoded = base64_decode_literal(a.storage.data()); std::array ret{}; for (std::size_t i = 0; i < decoded.output_count; i++) { ret[i] = decoded.buffer[i]; } return ret; } } // namespace detail /** * User-defined literal for compile-time base64 decoding. * * Usage: * using namespace simdutf::literals; * constexpr auto decoded = "SGVsbG8gV29ybGQh"_base64; * // decoded is a std::array containing "Hello World!" * * The input must be valid base64. Whitepace is allowed and ignored. * A compilation error occurs if the input is invalid. */ template consteval auto operator""_base64() { return detail::base64_make_array(); } } // namespace literals } // namespace simdutf #endif // SIMDUTF_CPLUSPLUS23 && SIMDUTF_FEATURE_BASE64 #endif // SIMDUTF_IMPLEMENTATION_H