285 template <IStdBasicStringCompatibleCharacter CHAR_T>
286 inline String::String (
const basic_string<CHAR_T>& s)
287 : inherited{mk_ (span<const CHAR_T>{s.data (), s.size ()})}
290 template <IStdBasicStringCompatibleCharacter CHAR_T>
292 : inherited{CTORFromBasicStringView_ (s)}
295 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
298 : inherited{mk_ (src)}
302 : String{span{&c, 1}}
305 template <IStdBasicStringCompatibleCharacter CHAR_T>
307 : inherited{mk_ (forward<basic_string<CHAR_T>> (s))}
310 template <IStdPathLike2UNICODEString PATHLIKE_TOSTRINGABLE>
313 : String{mkSTR_ (forward<PATHLIKE_TOSTRINGABLE> (s))}
316 template <IStdPathLike2UNICODEString PATHLIKE_TOSTRINGABLE>
317 String String::mkSTR_ (PATHLIKE_TOSTRINGABLE&& s)
319 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
320 { t.wstring () } -> same_as<wstring>;
322 return String{forward<PATHLIKE_TOSTRINGABLE> (s).wstring ()};
324 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
325 { t.u8string () } -> same_as<u8string>;
327 return String{forward<PATHLIKE_TOSTRINGABLE> (s).u8string ()};
329 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
330 { t.u16string () } -> same_as<u16string>;
332 return String{forward<PATHLIKE_TOSTRINGABLE> (s).u16string ()};
334 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
335 { t.u32string () } -> same_as<u32string>;
337 return String{forward<PATHLIKE_TOSTRINGABLE> (s).u32string ()};
343 return FromNarrowString (span{from, ::strlen (from)}, l);
347 return FromNarrowString (span{from.c_str (), from.length ()}, l);
349 template <IStdBasicStringCompatibleCharacter CHAR_T>
352 return FromLatin1 (span{s.data (), s.size ()});
354 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
358 return FromLatin1 (span{cString, Private_::StrLen_ (cString)});
360 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
367 if constexpr (
sizeof (CHAR_T) == 1) {
368 return mk_ (span<const Latin1>{
reinterpret_cast<const Latin1*
> (s.data ()), s.size ()});
371 const CHAR_T* b =
reinterpret_cast<const CHAR_T*
> (s.data ());
372 const CHAR_T* e = b + s.
size ();
374 Latin1* pOut = buf.begin ();
375 for (
const CHAR_T* i = b; i != e; ++i, ++pOut) {
377 static const auto kException_ = out_of_range{
"Error converting non-iso-latin-1 text to String"};
382 return mk_ (span<const Latin1>{buf.begin (), pOut});
385 template <
size_t SIZE, IUNICODECanUnambiguouslyConvertFrom CHAR_T>
388 return FromStringConstant (span<const CHAR_T>{cString, SIZE - 1});
390 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
393 return FromStringConstant (span<const CHAR_T>{str.data (), str.size ()});
395 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
401 if constexpr (same_as<CHAR_T, char8_t>) {
402 if (Character::IsASCII (str)) {
403 return FromStringConstant (Memory::SpanBytesCast<span<const ASCII>> (str));
411 if constexpr (
sizeof (wchar_t) == 2) {
412 return FromStringConstant (Memory::SpanBytesCast<span<const char16_t>> (s));
415 Assert (
sizeof (
wchar_t) == 4);
416 return FromStringConstant (Memory::SpanBytesCast<span<const char32_t>> (s));
419 template <
typename CHAR_T>
421 requires (same_as<remove_cv_t<CHAR_T>,
char8_t> or same_as<remove_cv_t<CHAR_T>,
char>)
423 if (Character::IsASCII (s)) [[likely]] {
424 return mk_ (span<const char>{
reinterpret_cast<const char*
> (s.data ()), s.size ()});
426 else if (UTFConvert::AllFitsInTwoByteEncoding (s)) [[likely]] {
428 return String{UTFConvert::kThe.ConvertSpan (s, span{buf})};
432 return String{UTFConvert::kThe.ConvertSpan (s, span{buf})};
435 template <
typename CHAR_T>
437 requires (same_as<remove_cv_t<CHAR_T>,
char8_t> or same_as<remove_cv_t<CHAR_T>,
char>)
439 return FromUTF8 (span{from.data (), from.length ()});
441 template <
typename CHAR_T>
443 requires (same_as<remove_cv_t<CHAR_T>,
char8_t> or same_as<remove_cv_t<CHAR_T>,
char>)
445 return FromUTF8 (span{from, ::strlen (
reinterpret_cast<const char*
> (from))});
450 return FromSDKString (span{from, CString::Length (from)});
454 if constexpr (same_as<SDKChar, wchar_t>) {
458 return String{SDK2Wide (s)};
463 if constexpr (same_as<SDKString, wstring>) {
467 return FromSDKString (span{from.c_str (), from.length ()});
473 return FromNarrowSDKString (span{from, ::strlen (from)});
481 return FromNarrowSDKString (span{from.c_str (), from.length ()});
483 template <
typename T>
485 requires (is_convertible_v<T, String>)
489 PeekSpanData lhsPSD = GetPeekSpanData<ASCII> ();
491 if (lhsPSD.fInCP == PeekSpanData::StorageCodePointType::eAscii) {
492 if constexpr (derived_from<remove_cvref_t<T>, String>) {
493 PeekSpanData rhsPSD = rhs.template GetPeekSpanData<ASCII> ();
494 if (rhsPSD.fInCP == PeekSpanData::StorageCodePointType::eAscii) {
495 Memory::StackBuffer<ASCII, 512> buf{Memory::eUninitialized, lhsPSD.fAscii.size () + rhsPSD.fAscii.size ()};
496 copy (lhsPSD.fAscii.begin (), lhsPSD.fAscii.end (), buf.data ());
497 copy (rhsPSD.fAscii.begin (), rhsPSD.fAscii.end (), buf.data () + lhsPSD.fAscii.size ());
498 return this->mk_nocheck_ (span<const ASCII>{buf});
504 return Concatenate_ (forward<T> (rhs));
506 inline void String::_AssertRepValidType ()
const
508 EnsureMember (&_SafeReadRepAccessor{
this}._ConstGetRep (), String::_IRep);
510 template <IUNICODECanAlwaysConvertTo CHAR_T>
512 requires (not is_const_v<CHAR_T>)
514 PeekSpanData psd = GetPeekSpanData<CHAR_T> ();
515 if (
auto p = PeekData<CHAR_T> (psd)) {
516 return Memory::CopySpanData (*p, s);
521 case PeekSpanData::StorageCodePointType::eAscii:
522 case PeekSpanData::StorageCodePointType::eSingleByteLatin1:
523 return UTFConvert::kThe.ConvertSpan (psd.fSingleByteLatin1, s);
524 case PeekSpanData::StorageCodePointType::eChar16:
525 return UTFConvert::kThe.ConvertSpan (psd.fChar16, s);
526 case PeekSpanData::StorageCodePointType::eChar32:
527 return UTFConvert::kThe.ConvertSpan (psd.fChar32, s);
530 return span<CHAR_T>{};
536 _SafeReadRepAccessor accessor{
this};
537 return accessor._ConstGetRep ().size ();
539 template <
unsigned_
integral T>
540 inline size_t String::SubString_adjust_ (T fromOrTo, [[maybe_unused]]
size_t myLength)
const
542 Require (fromOrTo <= numeric_limits<size_t>::max ());
543 return static_cast<size_t> (fromOrTo);
545 template <
signed_
integral T>
546 inline size_t String::SubString_adjust_ (T fromOrTo,
size_t myLength)
const
548 if (fromOrTo >= 0) [[likely]] {
549 Require (fromOrTo <= numeric_limits<ptrdiff_t>::max ());
550 return static_cast<size_t> (fromOrTo);
553 Require (fromOrTo >= numeric_limits<ptrdiff_t>::min ());
554 return static_cast<size_t> (myLength +
static_cast<ptrdiff_t
> (fromOrTo));
557 template <
typename SZ>
560 _SafeReadRepAccessor accessor{
this};
561 size_t myLength{accessor._ConstGetRep ().
size ()};
562 size_t f = SubString_adjust_ (from, myLength);
564 Require (f <= myLength);
565 return SubString_ (accessor, f, t);
567 template <
typename SZ1,
typename SZ2>
570 _SafeReadRepAccessor accessor{
this};
571 size_t myLength{accessor._ConstGetRep ().
size ()};
572 size_t f = SubString_adjust_ (from, myLength);
573 size_t t = SubString_adjust_ (to, myLength);
575 Require (t <= myLength);
576 return SubString_ (accessor, f, t);
578 template <
typename SZ>
581 _SafeReadRepAccessor accessor{
this};
582 size_t myLength{accessor._ConstGetRep ().
size ()};
583 size_t f = SubString_adjust_ (from, myLength);
584 f = min (f, myLength);
585 Assert (f <= myLength);
586 size_t useLength{myLength - f};
587 return SubString_ (accessor, f, f + useLength);
589 template <
typename SZ1,
typename SZ2>
592 _SafeReadRepAccessor accessor{
this};
593 size_t myLength{accessor._ConstGetRep ().
size ()};
594 size_t f = SubString_adjust_ (from, myLength);
595 size_t t = SubString_adjust_ (to, myLength);
596 f = min (f, myLength);
597 t = min (t, myLength);
600 Assert (t <= myLength);
601 size_t useLength = (t - f);
602 return SubString_ (accessor, f, f + useLength);
606 return SafeSubString (n);
610 return RemoveAt (charAt, charAt + 1);
614 return RemoveAt (fromTo.first, fromTo.second);
616 inline bool String::empty () const noexcept
618 _SafeReadRepAccessor accessor{
this};
619 return accessor._ConstGetRep ().size () == 0;
623 inline void ExtractMatches_ ([[maybe_unused]]
const wsmatch& base_match, [[maybe_unused]]
size_t currentUnpackIndex)
626 template <Common::IAnyOf<optional<String>*, String*,
nullptr_t> SUBMATCH,
typename... OPTIONAL_STRINGS>
627 void ExtractMatches_ (
const wsmatch& base_match,
size_t currentUnpackIndex, SUBMATCH subMatchI, OPTIONAL_STRINGS&&... remainingSubmatches)
629 if (currentUnpackIndex < base_match.size ()) [[likely]] {
630 if constexpr (not same_as<SUBMATCH, nullptr_t>) {
631 if (subMatchI !=
nullptr) {
632 *subMatchI = base_match[currentUnpackIndex].str ();
635 ExtractMatches_ (base_match, currentUnpackIndex + 1, forward<OPTIONAL_STRINGS> (remainingSubmatches)...);
638 const wregex& RegularExpression_GetCompiled (
const RegularExpression& regExp);
640 template <Common::IAnyOf<optional<String>*, String*,
nullptr_t>... OPTIONAL_STRINGS>
641 bool String::Matches (
const RegularExpression& regEx, OPTIONAL_STRINGS&&... subMatches)
const
643 wstring tmp{As<wstring> ()};
645 if (regex_match (tmp, baseMatch, Private_::RegularExpression_GetCompiled (regEx))) {
646 Private_::ExtractMatches_ (baseMatch, 1, forward<OPTIONAL_STRINGS> (subMatches)...);
652 optional<Common::RepeatedTuple_t<I, String>>
String::Matches (
const RegularExpression& regEx)
const
654 wstring tmp{As<wstring> ()};
656 if (regex_match (tmp, baseMatch, Private_::RegularExpression_GetCompiled (regEx))) {
658 if constexpr (I == 0) {
659 return make_tuple ();
661 else if constexpr (I == 1) {
662 return make_tuple (String{baseMatch[1].str ()});
664 else if constexpr (I == 2) {
665 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()});
667 else if constexpr (I == 3) {
668 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()}, String{baseMatch[3].str ()});
670 else if constexpr (I == 4) {
671 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()}, String{baseMatch[3].str ()},
672 String{baseMatch[4].str ()});
674 else if constexpr (I == 5) {
675 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()}, String{baseMatch[3].str ()},
676 String{baseMatch[4].str ()}, String{baseMatch[5].str ()});
687 return Find (c, 0, co);
689 inline optional<size_t>
String::Find (
const String& subString, CompareOptions co)
const
691 return Find (subString, 0, co);
695 return inherited::Find (that);
699 return static_cast<bool> (Find (c, co));
703 return static_cast<bool> (Find (subString, co));
705 inline bool String::ContainsAny (Iterable<Character> cs, CompareOptions co)
const
707 auto comparer = Character::EqualsComparer{co};
708 auto checkEachCharacter = [&] (Character c) ->
bool {
return cs.Any ([&] (
const Character c2) {
return comparer (c, c2); }); };
709 return Find (checkEachCharacter) !=
nullptr;
711 inline String
String::Replace (pair<size_t, size_t> fromTo,
const String& replacement)
const
713 return Replace (fromTo.first, fromTo.second, replacement);
717 return Col (i).value_or (valueIfMissing);
721 return InsertAt (span<const Character>{&c, 1}, at);
726 return InsertAt (s.
GetData (&ignored1), at);
730 return InsertAt (Memory::ConstSpan (s), at);
732 inline const Character String::GetCharAt (
size_t i)
const noexcept
734 _SafeReadRepAccessor accessor{
this};
736 Require (i < accessor._ConstGetRep ().size ());
737 return accessor._ConstGetRep ().GetAt (i);
742 Require (i < size ());
743 return GetCharAt (i);
747#if qCompiler_vswprintf_on_elispisStr_Buggy
748 static const String kELIPSIS_{
"..."_k};
750 static const String kELIPSIS_{u
"\u2026"sv};
752 return LimitLength (maxLen, keepPref, kELIPSIS_);
754 template <
typename T>
758 if constexpr (same_as<T, u8string>) {
761 else if constexpr (same_as<T, u16string>) {
762 return AsUTF16<T> ();
764 else if constexpr (same_as<T, u32string>) {
765 return AsUTF32<T> ();
767 else if constexpr (same_as<T, wstring>) {
768 if constexpr (
sizeof (wchar_t) == 2) {
769 return AsUTF16<T> ();
772 return AsUTF32<T> ();
775 else if constexpr (same_as<T, String>) {
778 else if constexpr (constructible_from<T, wstring>) {
779 return T{As<wstring> ()};
782 template <
typename T>
784 requires (same_as<T,
string> or same_as<T, u8string>)
786 Memory::StackBuffer<char8_t> maybeIgnoreBuf1;
787 span<const char8_t> thisData = GetData (&maybeIgnoreBuf1);
788 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
790 template <
typename T>
792 requires (same_as<T, u16string> or (sizeof (
wchar_t) == sizeof (
char16_t) and same_as<T, wstring>))
794 Memory::StackBuffer<char16_t> maybeIgnoreBuf1;
795 span<const char16_t> thisData = GetData (&maybeIgnoreBuf1);
796 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
798 template <
typename T>
800 requires (same_as<T, u32string> or (sizeof (
wchar_t) == sizeof (
char32_t) and same_as<T, wstring>))
802 Memory::StackBuffer<char32_t> maybeIgnoreBuf1;
803 span<const char32_t> thisData = GetData (&maybeIgnoreBuf1);
804 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
808#if qTargetPlatformSDKUseswchar_t
810 span<const wchar_t> thisData = GetData (&maybeIgnoreBuf1);
811 return SDKString{thisData.begin (), thisData.end ()};
812#elif qStroika_Foundation_Common_Platform_MacOS
814 span<const char8_t> thisData = GetData (&maybeIgnoreBuf1);
815 return SDKString{thisData.begin (), thisData.end ()};
817 return AsNarrowString (locale{});
822#if qTargetPlatformSDKUseswchar_t
824 span<const wchar_t> thisData = GetData (&maybeIgnoreBuf1);
825 return SDKString{thisData.begin (), thisData.end ()};
826#elif qStroika_Foundation_Common_Platform_MacOS
828 span<const char8_t> thisData = GetData (&maybeIgnoreBuf1);
829 return SDKString{thisData.begin (), thisData.end ()};
831 return AsNarrowString (locale{}, eIgnoreErrors);
840 return SDK2Narrow (AsSDKString (eIgnoreErrors), AllowMissingCharacterErrorsFlag::eIgnoreErrors);
842 template <
typename T>
844 requires requires (T* into) {
845 { into->empty () } -> same_as<bool>;
846 { into->push_back (ASCII{0}) };
850 if (
auto p = AsASCIIQuietly<T> ()) {
854 ThrowInvalidAsciiException_ ();
857 template <
typename T>
859 requires requires (T* into) {
860 { into->empty () } -> same_as<bool>;
861 { into->push_back (ASCII{0}) };
865 Memory::StackBuffer<wchar_t> ignored1;
866 auto thisSpan = GetData (&ignored1);
868 return Character::AsASCIIQuietly<T> (thisSpan, &s) ? s : optional<T>{};
870 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
873 using StorageCodePointType = PeekSpanData::StorageCodePointType;
874 StorageCodePointType preferredSCP{};
875 if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
ASCII>) {
876 preferredSCP = StorageCodePointType::eAscii;
878 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>, Latin1>) {
879 preferredSCP = StorageCodePointType::eSingleByteLatin1;
881 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char8_t>) {
882 preferredSCP = StorageCodePointType::eAscii;
884 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char16_t>) {
885 preferredSCP = StorageCodePointType::eChar16;
887 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char32_t> or same_as<remove_cv_t<CHAR_TYPE>, Character>) {
888 preferredSCP = StorageCodePointType::eChar32;
890 if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
wchar_t>) {
891 if constexpr (
sizeof (wchar_t) == 2) {
892 preferredSCP = StorageCodePointType::eChar16;
894 else if constexpr (
sizeof (wchar_t) == 4) {
895 preferredSCP = StorageCodePointType::eChar32;
898 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>, Character>) {
900 if constexpr (
sizeof (wchar_t) == 2) {
901 preferredSCP = StorageCodePointType::eChar16;
903 else if constexpr (
sizeof (wchar_t) == 4) {
904 preferredSCP = StorageCodePointType::eChar32;
907 return _SafeReadRepAccessor{
this}._ConstGetRep ().PeekData (preferredSCP);
909 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
910 inline optional<span<const CHAR_TYPE>> String::PeekData (
const PeekSpanData& pds)
913 if constexpr (same_as<CHAR_TYPE, ASCII>) {
914 if (pds.fInCP == StorageCodePointType::eAscii) {
918 else if constexpr (same_as<CHAR_TYPE, Latin1>) {
919 if (pds.fInCP == StorageCodePointType::eSingleByteLatin1) {
920 return pds.fSingleByteLatin1;
923 else if constexpr (same_as<CHAR_TYPE, char8_t>) {
924 if (pds.fInCP == StorageCodePointType::eAscii) {
928 else if constexpr (same_as<CHAR_TYPE, char16_t>) {
929 if (pds.fInCP == StorageCodePointType::eChar16) {
933 else if constexpr (same_as<CHAR_TYPE, char32_t>) {
934 if (pds.fInCP == StorageCodePointType::eChar32) {
938 else if constexpr (same_as<CHAR_TYPE, wchar_t>) {
939 if constexpr (
sizeof (wchar_t) == 2) {
940 if (pds.fInCP == StorageCodePointType::eChar16) {
941 return span<const wchar_t>{
reinterpret_cast<const wchar_t*
> (pds.fChar16.data ()), pds.fChar16.size ()};
944 else if constexpr (
sizeof (wchar_t) == 4) {
945 if (pds.fInCP == StorageCodePointType::eChar32) {
946 return span<const wchar_t>{
reinterpret_cast<const wchar_t*
> (pds.fChar32.data ()), pds.fChar32.size ()};
949 return span<const wchar_t>{};
951 else if constexpr (same_as<CHAR_TYPE, Character>) {
952 if (pds.fInCP == StorageCodePointType::eChar32) {
953 return span<const Character>{
reinterpret_cast<const Character*
> (pds.fChar32.data ()), pds.fChar32.size ()};
955 return span<const Character>{};
959 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
960 inline optional<span<const CHAR_TYPE>> String::PeekData ()
const
962 return PeekData<CHAR_TYPE> (GetPeekSpanData<CHAR_TYPE> ());
966 template <IUNICODECanAlwaysConvertTo CHAR_TYPE,
size_t STACK_BUFFER_SZ>
971 if constexpr (same_as<CHAR_TYPE, wchar_t>) {
972 if constexpr (
sizeof (CHAR_TYPE) == 2) {
974 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
976 else if constexpr (
sizeof (wchar_t) == 4) {
978 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
981 else if constexpr (same_as<CHAR_TYPE, Character>) {
983 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
985 if constexpr (same_as<CHAR_TYPE, char8_t>) {
987 case StorageCodePointType::eAscii:
989 return span{
reinterpret_cast<const char8_t*
> (pds.fAscii.data ()), pds.fAscii.size ()};
990 case StorageCodePointType::eSingleByteLatin1: {
992 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
993 return UTFConvert::kThe.ConvertSpan (pds.fSingleByteLatin1, span{*possiblyUsedBuffer});
995 case StorageCodePointType::eChar16: {
996 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar16));
997 return UTFConvert::kThe.ConvertSpan (pds.fChar16, span{*possiblyUsedBuffer});
999 case StorageCodePointType::eChar32: {
1000 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar32));
1001 return UTFConvert::kThe.ConvertSpan (pds.fChar32, span{*possiblyUsedBuffer});
1005 return span<const CHAR_TYPE>{};
1008 else if constexpr (same_as<CHAR_TYPE, char16_t>) {
1009 switch (pds.fInCP) {
1010 case StorageCodePointType::eAscii:
1011 case StorageCodePointType::eSingleByteLatin1: {
1012 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
1013 return UTFConvert::kThe.ConvertSpan (pds.fSingleByteLatin1, span{*possiblyUsedBuffer});
1015 case StorageCodePointType::eChar16:
1017 case StorageCodePointType::eChar32: {
1018 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar32));
1019 return UTFConvert::kThe.ConvertSpan (pds.fChar32, span{*possiblyUsedBuffer});
1023 return span<const CHAR_TYPE>{};
1026 else if constexpr (same_as<CHAR_TYPE, char32_t>) {
1027 switch (pds.fInCP) {
1028 case StorageCodePointType::eAscii:
1029 case StorageCodePointType::eSingleByteLatin1: {
1030 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
1031 return UTFConvert::kThe.ConvertSpan (pds.fSingleByteLatin1, span{*possiblyUsedBuffer});
1033 case StorageCodePointType::eChar16: {
1034 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar16));
1035 return UTFConvert::kThe.ConvertSpan (pds.fChar16, span{*possiblyUsedBuffer});
1037 case StorageCodePointType::eChar32:
1041 return span<const CHAR_TYPE>{};
1045 template <IUNICODECanAlwaysConvertTo CHAR_TYPE,
size_t STACK_BUFFER_SZ>
1046 inline span<const CHAR_TYPE>
String::GetData (Memory::StackBuffer<CHAR_TYPE, STACK_BUFFER_SZ>* possiblyUsedBuffer)
const
1049 return GetData (GetPeekSpanData<CHAR_TYPE> (), possiblyUsedBuffer);
1061 wstring tmp{As<wstring> ()};
1063 copy (tmp.begin (), tmp.end (), possibleBackingStore->begin ());
1064 (*possibleBackingStore)[tmp.length ()] =
'\0';
1065 return make_tuple (possibleBackingStore->begin (), wstring_view{possibleBackingStore->begin (), tmp.length ()});
1069 return Find (c, startAt, eWithCase).value_or (npos);
1073 return Find (s, startAt, eWithCase).value_or (npos);
1077 return RFind (c).value_or (npos);
1081 Require (not empty ());
1082 _SafeReadRepAccessor accessor{
this};
1083 size_t thisLen = accessor._ConstGetRep ().size ();
1084 return accessor._ConstGetRep ().GetAt (thisLen - 1);
1088 Require (not empty ());
1089 _SafeReadRepAccessor accessor{
this};
1090 return accessor._ConstGetRep ().GetAt (0);
1094 _SafeReadRepAccessor accessor{
this};
1095 size_t thisLen = accessor._ConstGetRep ().
size ();
1096 if (from > thisLen) [[unlikely]] {
1097 static auto kException_ = out_of_range{
"string index out of range"};
1102 size_t to = (count == npos) ? thisLen : (from + min (thisLen, count));
1103 return SubString_ (accessor, from, to);
1107 return ThreeWayComparer{}(*
this, rhs);
1109 template <IConvertibleToString T>
1111 requires (not same_as<remove_cvref_t<T>,
String>)
1113 return ThreeWayComparer{}(*
this, forward<T> (rhs));
1119 template <IConvertibleToString T>
1121 requires (not same_as<remove_cvref_t<T>,
String>)
1123 return EqualsComparer{}(*
this, rhs);
1131 inline namespace Literals {
1132 inline String
operator""_k (
const ASCII* s,
size_t len)
1134 return String::FromStringConstant (span<const char>{s, len});
1136 inline String
operator""_k (
const char8_t* s,
size_t len)
1138 return String::FromStringConstant (span<const char8_t>{s, len});
1140 inline String
operator""_k (
const wchar_t* s,
size_t len)
1142 return String::FromStringConstant (span<const wchar_t>{s, len});
1144 inline String
operator""_k (
const char16_t* s,
size_t len)
1146 return String::FromStringConstant (span<const char16_t>{s, len});
1148 inline String
operator""_k (
const char32_t* s,
size_t len)
1150 return String::FromStringConstant (span<const char32_t>{s, len});
1160 : fCompareOptions{co}
1163 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1164 inline bool String::EqualsComparer::Cmp_ (LT&& lhs, RT&& rhs)
const
1167 if constexpr (same_as<remove_cvref_t<LT>,
String> and same_as<remove_cvref_t<RT>,
String>) {
1168 if (
auto lhsAsciiSpan = lhs.template PeekData<ASCII> ()) {
1169 if (
auto rhsAsciiSpan = rhs.template PeekData<ASCII> ()) {
1170 if (fCompareOptions == eWithCase) {
1171 if (lhsAsciiSpan->size () != rhsAsciiSpan->size ()) {
1174 return Memory::CompareBytes (lhsAsciiSpan->data (), rhsAsciiSpan->data (), lhsAsciiSpan->size ()) == 0;
1183 else if constexpr (same_as<remove_cvref_t<LT>,
String> and same_as<remove_cvref_t<RT>, basic_string_view<ASCII>>) {
1184 if (
auto lhsAsciiSpan = lhs.template PeekData<ASCII> ()) {
1185 auto rhsAsciiSpan = span<const ASCII>{rhs};
1187 if (fCompareOptions == eWithCase) {
1188 if (lhsAsciiSpan->size () != rhsAsciiSpan.size ()) {
1191 return Memory::CompareBytes (lhsAsciiSpan->data (), rhsAsciiSpan.data (), lhsAsciiSpan->size ()) == 0;
1198 return Cmp_Generic_ (forward<LT> (lhs), forward<RT> (rhs));
1200 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1201 bool String::EqualsComparer::Cmp_Generic_ (LT&& lhs, RT&& rhs)
const
1206 Memory::StackBuffer<Character, 256> ignore1;
1207 Memory::StackBuffer<Character, 256> ignore2;
1208 return Character::Compare (Private_::AsSpanOfCharacters_ (forward<LT> (lhs), &ignore1),
1209 Private_::AsSpanOfCharacters_ (forward<RT> (rhs), &ignore2), fCompareOptions) == 0;
1211 template <IConvertibleToString LT, IConvertibleToString RT>
1214 if constexpr (
requires { lhs.size (); } and
requires { rhs.size (); }) {
1215 if (lhs.size () != rhs.size ()) {
1219 if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LT> and Private_::ICanBeTreatedAsSpanOfCharacter_<RT>) {
1220 return Cmp_ (forward<LT> (lhs), forward<RT> (rhs));
1224 return operator() (
String{forward<LT> (lhs)},
String{forward<RT> (rhs)});
1233 constexpr String::ThreeWayComparer::ThreeWayComparer (CompareOptions co)
1234 : fCompareOptions{co}
1237 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1238 inline strong_ordering String::ThreeWayComparer::Cmp_ (LT&& lhs, RT&& rhs)
const
1241 if constexpr (same_as<remove_cvref_t<LT>,
String> and same_as<remove_cvref_t<RT>,
String>) {
1242 if (
auto lhsAsciiSpan = lhs.template PeekData<ASCII> ()) {
1243 if (
auto rhsAsciiSpan = rhs.template PeekData<ASCII> ()) {
1248 return Cmp_Generic_ (forward<LT> (lhs), forward<RT> (rhs));
1250 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1251 strong_ordering String::ThreeWayComparer::Cmp_Generic_ (LT&& lhs, RT&& rhs)
const
1256 Memory::StackBuffer<Character, 256> ignore1;
1257 Memory::StackBuffer<Character, 256> ignore2;
1258 return Character::Compare (Private_::AsSpanOfCharacters_ (forward<LT> (lhs), &ignore1),
1259 Private_::AsSpanOfCharacters_ (forward<RT> (rhs), &ignore2), fCompareOptions);
1261 template <IConvertibleToString LT, IConvertibleToString RT>
1262 inline strong_ordering String::ThreeWayComparer::operator() (LT&& lhs, RT&& rhs)
const
1264 if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LT> and Private_::ICanBeTreatedAsSpanOfCharacter_<RT>) {
1265 return Cmp_ (forward<LT> (lhs), forward<RT> (rhs));
1269 return operator() (
String{forward<LT> (lhs)},
String{forward<RT> (rhs)});
1278 constexpr String::LessComparer::LessComparer (CompareOptions co)
1282 template <
typename T1,
typename T2>
1283 inline bool String::LessComparer::operator() (T1 lhs, T2 rhs)
const
1285 return fComparer_ (lhs, rhs) < 0;
1293 template <IConvertibleToString LHS_T, IConvertibleToString RHS_T>
1295 requires (derived_from<remove_cvref_t<LHS_T>,
String> or derived_from<remove_cvref_t<RHS_T>,
String>)
1297 if constexpr (derived_from<remove_cvref_t<LHS_T>,
String>) {
1301 else if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LHS_T> and Private_::ICanBeTreatedAsSpanOfCharacter_<RHS_T>) {
1304 span<const Character> lSpan = Private_::AsSpanOfCharacters_ (forward<LHS_T> (lhs), &ignored1);
1306 span<const Character> rSpan = Private_::AsSpanOfCharacters_ (forward<RHS_T> (rhs), &ignored2);
1309 Memory::CopySpanData (lSpan, bufSpan);
1310 Memory::CopySpanData (rSpan, bufSpan.subspan (lSpan.size ()));
1321#if qStroika_HasComponent_googletest
1322 inline void PrintTo (
const String& s, std::ostream* os)
1333 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1334 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1335 DISABLE_COMPILER_MSC_WARNING_START (4996)
1336 template <typename CHAR_T>
1337 inline
void String::Append (span<const CHAR_T> s)
1338 requires (same_as<CHAR_T, Character> or same_as<CHAR_T,
char32_t>)
1340 if (not s.empty ()) {
1341 Memory::StackBuffer<char32_t> ignored1;
1342 span<const char32_t> thisSpan = this->GetData (&ignored1);
1343 Memory::StackBuffer<char32_t> combinedBuf{Memory::eUninitialized, thisSpan.size () + s.size ()};
1344 Memory::CopySpanData (thisSpan, span{combinedBuf});
1345 char32_t* write2Buf = combinedBuf.data () + thisSpan.size ();
1347 if constexpr (same_as<CHAR_T, Character>) {
1348 *write2Buf = i.template As<char32_t> ();
1355 *
this = mk_ (span{combinedBuf});
1358 inline void String::Append (
const wchar_t* from,
const wchar_t* to)
1360 Require (from <= to);
1362 Memory::StackBuffer<wchar_t> ignored1;
1363 span<const wchar_t> thisSpan = this->GetData (&ignored1);
1364 Memory::StackBuffer<wchar_t> buf{Memory::eUninitialized, thisSpan.size () + (to - from)};
1365 span<wchar_t> bufSpan{buf};
1366 Memory::CopySpanData (thisSpan, bufSpan);
1367 Memory::CopySpanData (span{from, to}, bufSpan.subspan (thisSpan.size ()));
1368 *
this = mk_ (bufSpan);
1371 inline void String::Append (Character c)
1375 inline void String::Append (
const String& s)
1377 Memory::StackBuffer<char32_t> ignored1;
1378 auto rhsSpan = s.GetData (&ignored1);
1381 inline void String::Append (
const wchar_t* s)
1383 Append (s, s + ::wcslen (s));
1385 inline void String::Append (
const Character* from,
const Character* to)
1389 inline String& String::operator+= (Character appendage)
1394 inline String& String::operator+= (
const String& appendage)
1399 inline String& String::operator+= (
const wchar_t* appendageCStr)
1405 inline void String::push_back (
wchar_t c)
1409 inline void String::push_back (Character c)
1414 DISABLE_COMPILER_MSC_WARNING_END (4996)
1415 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1416 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
1418 [[deprecated ("Since Stroika v3.0d1 - just use _k, sv, or nothing")]] inline String operator""_ASCII (const
char* str,
size_t len)
1420 return String{span{str, len}};
1422 class [[deprecated (
"Since Stroika v3.0 - just use String::FromStringConstant")]] String_Constant :
public String {
1424 template <
size_t SIZE>
1425 explicit String_Constant (
const wchar_t (&cString)[SIZE])
1426 : String{String::FromStringConstant (
std::basic_string_view<wchar_t>{cString, SIZE - 1})}
1430 String_Constant (
const wchar_t* start,
const wchar_t* end)
1431 : String{String::FromStringConstant (
std::basic_string_view<wchar_t>{start,
static_cast<size_t> (end - start)})}
1435 String_Constant (
const std::basic_string_view<wchar_t>& str)
1441namespace Stroika::Foundation::Characters::Concrete {
1442 class [[deprecated (
"Since Stroika v3.0 - just use String::FromStringConstant")]] String_ExternalMemoryOwnership_ApplicationLifetime :
public String {
1444 template <
size_t SIZE>
1445 explicit String_ExternalMemoryOwnership_ApplicationLifetime (
const wchar_t (&cString)[SIZE - 1])
1446 : String{String::FromStringConstant (basic_string_view<wchar_t>{cString, SIZE})}
1450 String_ExternalMemoryOwnership_ApplicationLifetime (
const wchar_t* start,
const wchar_t* end)
1451 : String{String::FromStringConstant (basic_string_view<wchar_t>{start,
static_cast<size_t> (end - start)})}
1455 String_ExternalMemoryOwnership_ApplicationLifetime (
const basic_string_view<wchar_t>& str)
1465 String StringCombiner<String>::operator() (
const String& lhs,
const String& rhs,
bool isLast)
const;
1467 template <
typename STRING>
1468 STRING StringCombiner<STRING>::operator() (
const STRING& lhs,
const STRING& rhs,
bool isLast)
const
1471 if (isLast and fSpecialSeparatorForLastPair) [[unlikely]] {
1472 sb = sb + *fSpecialSeparatorForLastPair;
1475 sb = sb + fSeparator;