4#include "Stroika/Foundation/StroikaPreComp.h"
8#include "Stroika/Foundation/Execution/Exceptions.h"
17 template <
typename FACET>
18 struct deletable_facet_ : FACET {
19 template <
typename... Args>
20 deletable_facet_ (Args&&... args)
21 : FACET{forward<Args> (args)...}
64 namespace UTFConvert_libutfxx_ {
68#if defined(__clang_major__) and (20 < __clang_major__)
69 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wcharacter-conversion\"")
73 static constexpr char32_t UNI_MAX_BMP = (char32_t)0x0000FFFF;
74 static constexpr char32_t UNI_MAX_UTF16 = (char32_t)0x0010FFFF;
75 static constexpr char32_t UNI_MAX_LEGAL_UTF32 = (char32_t)0x0010FFFF;
77 enum ConversionResult {
88 return UTFConvert::ConversionStatusFlag::ok;
90 return UTFConvert::ConversionStatusFlag::sourceExhausted;
93 return UTFConvert::ConversionStatusFlag::sourceIllegal;
95 return UTFConvert::ConversionStatusFlag::sourceIllegal;
98 return UTFConvert::ConversionStatusFlag::sourceIllegal;
102 constexpr int halfShift = 10;
104 constexpr char32_t halfBase = 0x0010000UL;
105 constexpr char32_t halfMask = 0x3FFUL;
112 constexpr char32_t offsetsFromUTF8[6] = {0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL};
121 constexpr char8_t firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
130 constexpr char trailingBytesForUTF8[256] = {
131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
136 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
148 bool isLegalUTF8_ (
const char8_t* source,
int length)
151 const char8_t* srcptr = source + length;
157 if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
160 if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
163 if ((a = (*--srcptr)) > 0xBF)
166 switch ((
unsigned char)*source) {
190 if (*source >= 0x80 && *source < 0xC2)
202 bool isLegalUTF8Prefix_ (
const char8_t* source,
const char8_t* end)
204 char8_t lead = *source;
205 if (lead < 0xC2 or lead > 0xF4) {
208 for (
const char8_t* p = source + 1; p < end; ++p) {
211 if (p == source + 1) {
227 if (*p < lo or *p > hi) {
234 inline ConversionResult ConvertUTF8toUTF16_ (
const char8_t** sourceStart,
const char8_t* sourceEnd,
char16_t** targetStart,
235 char16_t* targetEnd, optional<char32_t> missingCharacterReplacement)
237 ConversionResult result = conversionOK;
238 const char8_t* source = *sourceStart;
239 char16_t* target = *targetStart;
240 auto addMissing = [&] () {
244 *target++ = p.second;
247 *target++ =
static_cast<char16_t> (*missingCharacterReplacement);
250 while (source < sourceEnd) {
252 unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
253 bool cutShort = source + extraBytesToRead >= sourceEnd;
254 if (cutShort ? not isLegalUTF8Prefix_ (source, sourceEnd) : not isLegalUTF8_ (source, extraBytesToRead + 1)) {
255 if (not missingCharacterReplacement) {
256 result = sourceIllegal;
259 if (target >= targetEnd) [[unlikely]] {
260 result = targetExhausted;
268 result = sourceExhausted;
274 switch (extraBytesToRead) {
293 ch -= offsetsFromUTF8[extraBytesToRead];
295 if (target >= targetEnd) [[unlikely]] {
296 source -= (extraBytesToRead + 1);
297 result = targetExhausted;
300 if (ch <= UNI_MAX_BMP) {
302 if (ch >= Character::kUNICODESurrogate_High_Start && ch <= Character::kUNICODESurrogate_Low_End) {
303 if (missingCharacterReplacement) {
307 source -= (extraBytesToRead + 1);
308 result = sourceIllegal;
313 *target++ = (char16_t)ch;
316 else if (ch > UNI_MAX_UTF16) {
317 if (missingCharacterReplacement) {
321 result = sourceIllegal;
322 source -= (extraBytesToRead + 1);
328 if (target + 1 >= targetEnd) {
329 source -= (extraBytesToRead + 1);
330 result = targetExhausted;
334 *target++ = (char16_t)((ch >> halfShift) + Character::kUNICODESurrogate_High_Start);
335 *target++ = (char16_t)((ch & halfMask) + Character::kUNICODESurrogate_Low_Start);
338 *sourceStart = source;
339 *targetStart = target;
342 inline ConversionResult ConvertUTF16toUTF8_ (
const char16_t** sourceStart,
const char16_t* sourceEnd,
char8_t** targetStart,
343 char8_t* targetEnd, optional<char32_t> missingCharacterReplacement)
345 ConversionResult result = conversionOK;
346 const char16_t* source = *sourceStart;
347 char8_t* target = *targetStart;
348 while (source < sourceEnd) {
350 unsigned short bytesToWrite = 0;
351 constexpr char32_t byteMask = 0xBF;
352 constexpr char32_t byteMark = 0x80;
353 const char16_t* oldSource = source;
356 if (ch >= Character::kUNICODESurrogate_High_Start && ch <= Character::kUNICODESurrogate_High_End) [[unlikely]] {
358 if (source < sourceEnd) [[likely]] {
359 char32_t ch2 = *source;
361 if (ch2 >= Character::kUNICODESurrogate_Low_Start && ch2 <= Character::kUNICODESurrogate_Low_End) {
362 ch = ((ch - Character::kUNICODESurrogate_High_Start) << halfShift) + (ch2 - Character::kUNICODESurrogate_Low_Start) + halfBase;
365 else if (missingCharacterReplacement == nullopt) {
367 result = sourceIllegal;
373 result = sourceExhausted;
377 else if (missingCharacterReplacement == nullopt) {
379 if (ch >= Character::kUNICODESurrogate_Low_Start && ch <= Character::kUNICODESurrogate_Low_End) {
381 result = sourceIllegal;
386 if (ch < (
char32_t)0x80) {
389 else if (ch < (
char32_t)0x800) {
392 else if (ch < (
char32_t)0x10000) {
395 else if (ch < (
char32_t)0x110000) {
400 Assert (missingCharacterReplacement.has_value ());
401 ch = *missingCharacterReplacement;
404 target += bytesToWrite;
405 if (target > targetEnd) {
407 target -= bytesToWrite;
408 result = targetExhausted;
411 switch (bytesToWrite) {
413 *--target = (char8_t)((ch | byteMark) & byteMask);
416 *--target = (char8_t)((ch | byteMark) & byteMask);
419 *--target = (char8_t)((ch | byteMark) & byteMask);
422 *--target = (char8_t)(ch | firstByteMark[bytesToWrite]);
424 target += bytesToWrite;
426 *sourceStart = source;
427 *targetStart = target;
430 DISABLE_COMPILER_MSC_WARNING_START (4701)
431 inline ConversionResult ConvertUTF16toUTF32_ (const
char16_t** sourceStart, const
char16_t* sourceEnd,
char32_t** targetStart,
432 char32_t* targetEnd, optional<
char32_t> missingCharacterReplacement)
434 ConversionResult result = conversionOK;
435 const char16_t* source = *sourceStart;
436 char32_t* target = *targetStart;
438 while (source < sourceEnd) {
439 const char16_t* oldSource = source;
442 if (ch >= Character::kUNICODESurrogate_High_Start && ch <= Character::kUNICODESurrogate_High_End) [[unlikely]] {
444 if (source < sourceEnd) {
447 if (ch2 >= Character::kUNICODESurrogate_Low_Start && ch2 <= Character::kUNICODESurrogate_Low_End) {
448 ch = ((ch - Character::kUNICODESurrogate_High_Start) << halfShift) + (ch2 - Character::kUNICODESurrogate_Low_Start) + halfBase;
451 else if (missingCharacterReplacement == nullopt) {
453 result = sourceIllegal;
459 result = sourceExhausted;
463 else if (missingCharacterReplacement == nullopt) {
465 if (ch >= Character::kUNICODESurrogate_Low_Start && ch <= Character::kUNICODESurrogate_Low_End) {
467 result = sourceIllegal;
471 if (target >= targetEnd) {
473 result = targetExhausted;
478 *sourceStart = source;
479 *targetStart = target;
480 if (result == sourceIllegal) {
481 using namespace Characters::Literals;
482 DbgTrace (
"ConvertUTF16toUTF32 illegal seq 0x{:x},0x{:x}"_f,
static_cast<int> (ch),
static_cast<int> (ch2));
486 DISABLE_COMPILER_MSC_WARNING_END (4701)
487 inline ConversionResult ConvertUTF32toUTF16_ (const
char32_t** sourceStart, const
char32_t* sourceEnd,
char16_t** targetStart,
488 char16_t* targetEnd, optional<
char32_t> missingCharacterReplacement)
490 ConversionResult result = conversionOK;
491 const char32_t* source = *sourceStart;
492 char16_t* target = *targetStart;
493 auto addMissing = [&] () {
497 *target++ = p.second;
500 *target++ =
static_cast<char16_t> (*missingCharacterReplacement);
503 while (source < sourceEnd) {
505 if (target >= targetEnd) {
506 result = targetExhausted;
510 if (ch <= UNI_MAX_BMP) [[likely]] {
512 if (ch >= Character::kUNICODESurrogate_High_Start && ch <= Character::kUNICODESurrogate_Low_End) [[unlikely]] {
513 if (missingCharacterReplacement == nullopt) {
515 result = sourceIllegal;
523 *target++ = (char16_t)ch;
526 else if (ch > UNI_MAX_LEGAL_UTF32) {
527 if (missingCharacterReplacement) {
531 result = sourceIllegal;
536 if (target + 1 >= targetEnd) {
538 result = targetExhausted;
542 *target++ = (char16_t)((ch >> halfShift) + Character::kUNICODESurrogate_High_Start);
543 *target++ = (char16_t)((ch & halfMask) + Character::kUNICODESurrogate_Low_Start);
546 *sourceStart = source;
547 *targetStart = target;
550 inline ConversionResult ConvertUTF8toUTF32_ (
const char8_t** sourceStart,
const char8_t* sourceEnd,
char32_t** targetStart,
551 char32_t* targetEnd, optional<char32_t> missingCharacterReplacement)
553 ConversionResult result = conversionOK;
554 const char8_t* source = *sourceStart;
555 char32_t* target = *targetStart;
556 while (source < sourceEnd) {
558 unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
559 bool cutShort = source + extraBytesToRead >= sourceEnd;
560 if (cutShort ? not isLegalUTF8Prefix_ (source, sourceEnd) : not isLegalUTF8_ (source, extraBytesToRead + 1)) {
561 if (not missingCharacterReplacement) {
562 result = sourceIllegal;
565 if (target >= targetEnd) [[unlikely]] {
566 result = targetExhausted;
569 *target++ = *missingCharacterReplacement;
573 if (cutShort) [[unlikely]] {
574 result = sourceExhausted;
580 switch (extraBytesToRead) {
599 ch -= offsetsFromUTF8[extraBytesToRead];
601 if (target >= targetEnd) [[unlikely]] {
602 source -= (extraBytesToRead + 1);
603 result = targetExhausted;
606 if (ch <= UNI_MAX_LEGAL_UTF32) [[likely]] {
611 if (ch >= Character::kUNICODESurrogate_High_Start && ch <= Character::kUNICODESurrogate_Low_End) {
612 if (missingCharacterReplacement) {
613 *target++ = *missingCharacterReplacement;
616 source -= (extraBytesToRead + 1);
617 result = sourceIllegal;
626 if (missingCharacterReplacement) {
627 *target++ = *missingCharacterReplacement;
630 result = sourceIllegal;
635 *sourceStart = source;
636 *targetStart = target;
639 inline ConversionResult ConvertUTF32toUTF8_ (
const char32_t** sourceStart,
const char32_t* sourceEnd,
char8_t** targetStart,
640 char8_t* targetEnd, optional<char32_t> missingCharacterReplacement)
642 ConversionResult result = conversionOK;
643 const char32_t* source = *sourceStart;
644 char8_t* target = *targetStart;
645 while (source < sourceEnd) {
647 unsigned short bytesToWrite = 0;
648 const char32_t byteMask = 0xBF;
649 const char32_t byteMark = 0x80;
651 if (missingCharacterReplacement == nullopt) {
653 if (ch >= Character::kUNICODESurrogate_High_Start && ch <= Character::kUNICODESurrogate_Low_End) [[unlikely]] {
655 result = sourceIllegal;
663 if (ch < (
char32_t)0x80) {
666 else if (ch < (
char32_t)0x800) {
669 else if (ch < (
char32_t)0x10000) {
672 else if (ch <= UNI_MAX_LEGAL_UTF32) {
676 if (missingCharacterReplacement) {
677 ch = *missingCharacterReplacement;
681 result = sourceIllegal;
686 target += bytesToWrite;
687 if (target > targetEnd) {
689 target -= bytesToWrite;
690 result = targetExhausted;
693 switch (bytesToWrite) {
695 *--target = (char8_t)((ch | byteMark) & byteMask);
698 *--target = (char8_t)((ch | byteMark) & byteMask);
701 *--target = (char8_t)((ch | byteMark) & byteMask);
704 *--target = (char8_t)(ch | firstByteMark[bytesToWrite]);
706 target += bytesToWrite;
708 *sourceStart = source;
709 *targetStart = target;
713#if defined(__clang_major__) and (20 < __clang_major__)
714 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wcharacter-conversion\"")
720 namespace UTFConvert_codecvtSupport_ {
724 case codecvt_base::ok:
725 return UTFConvert::ConversionStatusFlag::ok;
726 case codecvt_base::error:
727 return UTFConvert::ConversionStatusFlag::sourceIllegal;
728 case codecvt_base::partial:
729 return UTFConvert::ConversionStatusFlag::sourceExhausted;
730 case codecvt_base::noconv:
731 return UTFConvert::ConversionStatusFlag::sourceIllegal;
734 return UTFConvert::ConversionStatusFlag::sourceIllegal;
738 char16_t** targetStart,
char16_t* targetEnd)
740 DISABLE_COMPILER_MSC_WARNING_START (4996)
741 static const deletable_facet_<codecvt<
char16_t,
char8_t, mbstate_t>> cvt;
742 mbstate_t ignoredMBState{};
743 const char8_t* sourceCursor = *sourceStart;
744 char16_t* outCursor = *targetStart;
745 codecvt_base::result rr = cvt.in (ignoredMBState, *sourceStart, sourceEnd, sourceCursor, *targetStart, targetEnd, outCursor);
746 *sourceStart =
reinterpret_cast<const char8_t*
> (sourceCursor);
747 *targetStart = outCursor;
748 return cvt_stdcodecvt_results_ (rr);
749 DISABLE_COMPILER_MSC_WARNING_END (4996)
752 char8_t** targetStart,
char8_t* targetEnd)
754 DISABLE_COMPILER_MSC_WARNING_START (4996)
755 static const deletable_facet_<codecvt<
char16_t,
char8_t, mbstate_t>> cvt;
756 mbstate_t ignoredMBState{};
757 const char16_t* sourceCursor = *sourceStart;
758 char8_t* outCursor = *targetStart;
759 codecvt_base::result rr = cvt.out (ignoredMBState, *sourceStart, sourceEnd, sourceCursor, *targetStart, targetEnd, outCursor);
760 *sourceStart =
reinterpret_cast<const char16_t*
> (sourceCursor);
761 *targetStart =
reinterpret_cast<char8_t*
> (outCursor);
762 return cvt_stdcodecvt_results_ (rr);
763 DISABLE_COMPILER_MSC_WARNING_END (4996)
766 char32_t** targetStart,
char32_t* targetEnd)
768 DISABLE_COMPILER_MSC_WARNING_START (4996)
769 static const deletable_facet_<codecvt<
char32_t,
char8_t, mbstate_t>> cvt;
770 mbstate_t ignoredState{};
772 const char8_t* sourceCursor = *sourceStart;
773 char32_t* outCursor = *targetStart;
774 codecvt_base::result rr = cvt.in (ignoredState, *sourceStart, sourceEnd, sourceCursor, *targetStart, targetEnd, outCursor);
775 *sourceStart =
reinterpret_cast<const char8_t*
> (sourceCursor);
776 *targetStart = outCursor;
777 return cvt_stdcodecvt_results_ (rr);
778 DISABLE_COMPILER_MSC_WARNING_END (4996)
781 char8_t** targetStart,
char8_t* targetEnd)
783 DISABLE_COMPILER_MSC_WARNING_START (4996)
784 static const deletable_facet_<codecvt<
char32_t,
char8_t, mbstate_t>> cvt;
785 mbstate_t ignoredState{};
786 const char32_t* sourceCursor = *sourceStart;
787 char8_t* outCursor = *targetStart;
788 codecvt_base::result rr = cvt.out (ignoredState, *sourceStart, sourceEnd, sourceCursor, *targetStart, targetEnd, outCursor);
789 *sourceStart =
reinterpret_cast<const char32_t*
> (sourceCursor);
790 *targetStart =
reinterpret_cast<char8_t*
> (outCursor);
791 return cvt_stdcodecvt_results_ (rr);
792 DISABLE_COMPILER_MSC_WARNING_END (4996)
803 using ConversionResultWithStatus = Characters::UTFConvert::ConversionResultWithStatus;
806 template <
typename IN_T,
typename OUT_T, regular_invocable<const IN_T**, const IN_T*, OUT_T**, OUT_T*, optional<
char32_t>> FUN2DO_REAL_WORK>
807 inline auto ConvertQuietly_StroikaPortable_helper_ (optional<Character> invalidCharacterReplacement, span<const IN_T> source,
808 span<OUT_T> target, FUN2DO_REAL_WORK&& realWork) -> ConversionResultWithStatus
810 using namespace UTFConvert_libutfxx_;
811 const IN_T* sourceStart = source.data ();
812 const IN_T* sourceEnd = sourceStart + source.size ();
813 OUT_T* targetStart = target.data ();
814 OUT_T* targetEnd = targetStart + target.size ();
817 realWork (&sourceStart, sourceEnd, &targetStart, targetEnd,
818 invalidCharacterReplacement.has_value () ? invalidCharacterReplacement->As<
char32_t> () : optional<char32_t>{});
819 return ConversionResultWithStatus{
820 {
static_cast<size_t> (sourceStart - source.data ()),
static_cast<size_t> (targetStart - target.data ())}, cvt_ (r)};
823auto UTFConvert::ConvertQuietly_StroikaPortable_ (optional<Character> invalidCharacterReplacement, span<const char8_t> source, span<char16_t> target)
824 -> ConversionResultWithStatus
826#if qCompilerAndStdLib_arm_ubsan_callDirectFunInsteadOfThruLamdba_Buggy
827 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
828 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target,
829 [] (
const char8_t** sourceStart,
const char8_t* sourceEnd,
char16_t** targetStart,
830 char16_t* targetEnd, optional<char32_t> missingCharacterReplacement) {
831 return UTFConvert_libutfxx_::ConvertUTF8toUTF16_ (
832 sourceStart, sourceEnd, targetStart, targetEnd, missingCharacterReplacement);
836 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target, UTFConvert_libutfxx_::ConvertUTF8toUTF16_);
838auto UTFConvert::ConvertQuietly_StroikaPortable_ (optional<Character> invalidCharacterReplacement, span<const char8_t> source, span<char32_t> target)
839 -> ConversionResultWithStatus
841#if qCompilerAndStdLib_arm_ubsan_callDirectFunInsteadOfThruLamdba_Buggy
842 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
843 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target,
844 [] (
const char8_t** sourceStart,
const char8_t* sourceEnd,
char32_t** targetStart,
845 char32_t* targetEnd, optional<char32_t> missingCharacterReplacement) {
846 return UTFConvert_libutfxx_::ConvertUTF8toUTF32_ (
847 sourceStart, sourceEnd, targetStart, targetEnd, missingCharacterReplacement);
851 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target, UTFConvert_libutfxx_::ConvertUTF8toUTF32_);
853auto UTFConvert::ConvertQuietly_StroikaPortable_ (optional<Character> invalidCharacterReplacement, span<const char16_t> source,
854 span<char32_t> target) -> ConversionResultWithStatus
856#if qCompilerAndStdLib_arm_ubsan_callDirectFunInsteadOfThruLamdba_Buggy
857 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
858 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target,
859 [] (
const char16_t** sourceStart,
const char16_t* sourceEnd,
char32_t** targetStart,
860 char32_t* targetEnd, optional<char32_t> missingCharacterReplacement) {
861 return UTFConvert_libutfxx_::ConvertUTF16toUTF32_ (
862 sourceStart, sourceEnd, targetStart, targetEnd, missingCharacterReplacement);
866 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target, UTFConvert_libutfxx_::ConvertUTF16toUTF32_);
868auto UTFConvert::ConvertQuietly_StroikaPortable_ (optional<Character> invalidCharacterReplacement, span<const char32_t> source,
869 span<char16_t> target) -> ConversionResultWithStatus
871#if qCompilerAndStdLib_arm_ubsan_callDirectFunInsteadOfThruLamdba_Buggy
872 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
873 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target,
874 [] (
const char32_t** sourceStart,
const char32_t* sourceEnd,
char16_t** targetStart,
875 char16_t* targetEnd, optional<char32_t> missingCharacterReplacement) {
876 return UTFConvert_libutfxx_::ConvertUTF32toUTF16_ (
877 sourceStart, sourceEnd, targetStart, targetEnd, missingCharacterReplacement);
881 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target, UTFConvert_libutfxx_::ConvertUTF32toUTF16_);
883auto UTFConvert::ConvertQuietly_StroikaPortable_ (optional<Character> invalidCharacterReplacement, span<const char32_t> source, span<char8_t> target)
884 -> ConversionResultWithStatus
886#if qCompilerAndStdLib_arm_ubsan_callDirectFunInsteadOfThruLamdba_Buggy
887 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
888 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target,
889 [] (
const char32_t** sourceStart,
const char32_t* sourceEnd,
char8_t** targetStart,
890 char8_t* targetEnd, optional<char32_t> missingCharacterReplacement) {
891 return UTFConvert_libutfxx_::ConvertUTF32toUTF8_ (
892 sourceStart, sourceEnd, targetStart, targetEnd, missingCharacterReplacement);
896 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target, UTFConvert_libutfxx_::ConvertUTF32toUTF8_);
898auto UTFConvert::ConvertQuietly_StroikaPortable_ (optional<Character> invalidCharacterReplacement, span<const char16_t> source, span<char8_t> target)
899 -> ConversionResultWithStatus
901#if qCompilerAndStdLib_arm_ubsan_callDirectFunInsteadOfThruLamdba_Buggy
902 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
903 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target,
904 [] (
const char16_t** sourceStart,
const char16_t* sourceEnd,
char8_t** targetStart,
905 char8_t* targetEnd, optional<char32_t> missingCharacterReplacement) {
906 return UTFConvert_libutfxx_::ConvertUTF16toUTF8_ (
907 sourceStart, sourceEnd, targetStart, targetEnd, missingCharacterReplacement);
911 return ConvertQuietly_StroikaPortable_helper_ (invalidCharacterReplacement, source, target, UTFConvert_libutfxx_::ConvertUTF16toUTF8_);
915 template <
typename IN_T,
typename OUT_T,
typename FUN2DO_REAL_WORK>
916 inline auto ConvertQuietly_codeCvt_helper_ (span<const IN_T> source,
const span<OUT_T> target, FUN2DO_REAL_WORK&& realWork) -> ConversionResultWithStatus
918 using namespace UTFConvert_codecvtSupport_;
919 const IN_T* sourceStart =
reinterpret_cast<const IN_T*
> (source.data ());
920 const IN_T* sourceEnd = sourceStart + source.size ();
921 OUT_T* targetStart =
reinterpret_cast<OUT_T*
> (target.data ());
922 OUT_T* targetEnd = targetStart + target.size ();
923 ConversionStatusFlag r = realWork (&sourceStart, sourceEnd, &targetStart, targetEnd);
924 if (r == ConversionStatusFlag::ok) {
925 return ConversionResultWithStatus{{
static_cast<size_t> (sourceStart -
reinterpret_cast<const IN_T*
> (source.data ())),
926 static_cast<size_t> (targetStart -
reinterpret_cast<const OUT_T*
> (target.data ()))},
927 ConversionStatusFlag::ok};
930 return ConversionResultWithStatus{{0, 0}, r};
934auto UTFConvert::ConvertQuietly_codeCvt_ (span<const char8_t> source, span<char16_t> target) -> ConversionResultWithStatus
936 return ConvertQuietly_codeCvt_helper_ (source, target, UTFConvert_codecvtSupport_::ConvertUTF8toUTF16_codecvt_);
938auto UTFConvert::ConvertQuietly_codeCvt_ (span<const char16_t> source, span<char8_t> target) -> ConversionResultWithStatus
940 return ConvertQuietly_codeCvt_helper_ (source, target, UTFConvert_codecvtSupport_::ConvertUTF16toUTF8_codecvt_);
942auto UTFConvert::ConvertQuietly_codeCvt_ (span<const char8_t> source, span<char32_t> target) -> ConversionResultWithStatus
944 return ConvertQuietly_codeCvt_helper_ (source, target, UTFConvert_codecvtSupport_::ConvertUTF8toUTF32_codecvt_);
946auto UTFConvert::ConvertQuietly_codeCvt_ (span<const char32_t> source, span<char8_t> target) -> ConversionResultWithStatus
948 return ConvertQuietly_codeCvt_helper_ (source, target, UTFConvert_codecvtSupport_::ConvertUTF32toUTF8_codecvt_);
951void UTFConvert::Throw (ConversionStatusFlag cr,
size_t errorAtSourceOffset)
#define RequireNotReached()
#define AssertNotReached()
An error occurred encoding or decoding a character
constexpr bool IsSurrogatePair() const
constexpr pair< char16_t, char16_t > GetSurrogatePair() const
ConversionStatusFlag
used for ConvertQuietly
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...