287 template <IStdBasicStringCompatibleCharacter CHAR_T>
288 inline String::String (
const basic_string<CHAR_T>& s)
289 : inherited{mk_ (span<const CHAR_T>{
s.data (),
s.size ()})}
292 template <IStdBasicStringCompatibleCharacter CHAR_T>
294 : inherited{CTORFromBasicStringView_ (s)}
297 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
299 requires (not Memory::ISpan<CHAR_T>)
300 : inherited{mk_ (src)}
304 : String{span{&c, 1}}
307 template <IStdBasicStringCompatibleCharacter CHAR_T>
309 : inherited{mk_ (forward<basic_string<CHAR_T>> (s))}
312 template <IStdPathLike2UNICODEString PATHLIKE_TOSTRINGABLE>
315 : String{mkSTR_ (forward<PATHLIKE_TOSTRINGABLE> (s))}
318 template <IStdPathLike2UNICODEString PATHLIKE_TOSTRINGABLE>
319 String String::mkSTR_ (PATHLIKE_TOSTRINGABLE&& s)
321 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
322 { t.wstring () } -> same_as<wstring>;
324 return String{forward<PATHLIKE_TOSTRINGABLE> (s).wstring ()};
326 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
327 { t.u8string () } -> same_as<u8string>;
329 return String{forward<PATHLIKE_TOSTRINGABLE> (s).u8string ()};
331 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
332 { t.u16string () } -> same_as<u16string>;
334 return String{forward<PATHLIKE_TOSTRINGABLE> (s).u16string ()};
336 if constexpr (
requires (PATHLIKE_TOSTRINGABLE t) {
337 { t.u32string () } -> same_as<u32string>;
339 return String{forward<PATHLIKE_TOSTRINGABLE> (s).u32string ()};
345 return FromNarrowString (span{from, ::strlen (from)}, l);
349 return FromNarrowString (span{from.c_str (), from.length ()}, l);
351 template <IStdBasicStringCompatibleCharacter CHAR_T>
354 return FromLatin1 (span{s.data (), s.size ()});
356 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
360 return FromLatin1 (span{cString, Private_::StrLen_ (cString)});
362 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
369 if constexpr (
sizeof (CHAR_T) == 1) {
370 return mk_ (span<const Latin1>{
reinterpret_cast<const Latin1*
> (s.data ()), s.size ()});
373 const CHAR_T* b =
reinterpret_cast<const CHAR_T*
> (s.data ());
374 const CHAR_T* e = b + s.
size ();
376 Latin1* pOut = buf.begin ();
377 for (
const CHAR_T* i = b; i != e; ++i, ++pOut) {
379 static const auto kException_ = out_of_range{
"Error converting non-iso-latin-1 text to String"};
384 return mk_ (span<const Latin1>{buf.begin (), pOut});
387 template <
size_t SIZE, IUNICODECanUnambiguouslyConvertFrom CHAR_T>
390 return FromStringConstant (span<const CHAR_T>{cString, SIZE - 1});
392 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
395 return FromStringConstant (span<const CHAR_T>{str.data (), str.size ()});
397 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
403 if constexpr (same_as<CHAR_T, char8_t>) {
404 if (Character::IsASCII (str)) {
405 return FromStringConstant (Memory::SpanBytesCast<span<const ASCII>> (str));
413 if constexpr (
sizeof (wchar_t) == 2) {
414 return FromStringConstant (Memory::SpanBytesCast<span<const char16_t>> (s));
417 Assert (
sizeof (
wchar_t) == 4);
418 return FromStringConstant (Memory::SpanBytesCast<span<const char32_t>> (s));
421 template <
typename CHAR_T>
423 requires (same_as<remove_cv_t<CHAR_T>,
char8_t> or same_as<remove_cv_t<CHAR_T>,
char>)
425 if (Character::IsASCII (s)) [[likely]] {
426 return mk_ (span<const char>{
reinterpret_cast<const char*
> (s.data ()), s.size ()});
428 else if (UTFConvert::AllFitsInTwoByteEncoding (s)) [[likely]] {
430 return String{UTFConvert::kThe.ConvertSpan (s, span{buf})};
434 return String{UTFConvert::kThe.ConvertSpan (s, span{buf})};
437 template <
typename CHAR_T>
439 requires (same_as<remove_cv_t<CHAR_T>,
char8_t> or same_as<remove_cv_t<CHAR_T>,
char>)
441 return FromUTF8 (span{from.data (), from.length ()});
443 template <
typename CHAR_T>
445 requires (same_as<remove_cv_t<CHAR_T>,
char8_t> or same_as<remove_cv_t<CHAR_T>,
char>)
447 return FromUTF8 (span{from, ::strlen (
reinterpret_cast<const char*
> (from))});
452 return FromSDKString (span{from, CString::Length (from)});
456 if constexpr (same_as<SDKChar, wchar_t>) {
460 return String{SDK2Wide (s)};
465 if constexpr (same_as<SDKString, wstring>) {
469 return FromSDKString (span{from.c_str (), from.length ()});
475 return FromNarrowSDKString (span{from, ::strlen (from)});
483 return FromNarrowSDKString (span{from.c_str (), from.length ()});
485 template <
typename T>
487 requires (is_convertible_v<T, String>)
491 PeekSpanData lhsPSD = GetPeekSpanData<ASCII> ();
493 if (lhsPSD.fInCP == PeekSpanData::StorageCodePointType::eAscii) {
494 if constexpr (derived_from<remove_cvref_t<T>, String>) {
495 PeekSpanData rhsPSD = rhs.template GetPeekSpanData<ASCII> ();
496 if (rhsPSD.fInCP == PeekSpanData::StorageCodePointType::eAscii) {
497 Memory::StackBuffer<ASCII, 512> buf{Memory::eUninitialized, lhsPSD.fAscii.size () + rhsPSD.fAscii.size ()};
498 copy (lhsPSD.fAscii.begin (), lhsPSD.fAscii.end (), buf.data ());
499 copy (rhsPSD.fAscii.begin (), rhsPSD.fAscii.end (), buf.data () + lhsPSD.fAscii.size ());
500 return this->mk_nocheck_ (span<const ASCII>{buf});
506 return Concatenate_ (forward<T> (rhs));
508 inline void String::_AssertRepValidType ()
const
510 EnsureMember (&_SafeReadRepAccessor{
this}._ConstGetRep (), String::_IRep);
512 template <IUNICODECanAlwaysConvertTo CHAR_T>
514 requires (not is_const_v<CHAR_T>)
516 PeekSpanData psd = GetPeekSpanData<CHAR_T> ();
517 if (
auto p = PeekData<CHAR_T> (psd)) {
518 return Memory::CopySpanData (*p, s);
523 case PeekSpanData::StorageCodePointType::eAscii:
524 case PeekSpanData::StorageCodePointType::eSingleByteLatin1:
525 return UTFConvert::kThe.ConvertSpan (psd.fSingleByteLatin1, s);
526 case PeekSpanData::StorageCodePointType::eChar16:
527 return UTFConvert::kThe.ConvertSpan (psd.fChar16, s);
528 case PeekSpanData::StorageCodePointType::eChar32:
529 return UTFConvert::kThe.ConvertSpan (psd.fChar32, s);
532 return span<CHAR_T>{};
538 _SafeReadRepAccessor accessor{
this};
539 return accessor._ConstGetRep ().size ();
541 template <
unsigned_
integral T>
542 inline size_t String::SubString_adjust_ (T fromOrTo, [[maybe_unused]]
size_t myLength)
const
544 Require (fromOrTo <= numeric_limits<size_t>::max ());
545 return static_cast<size_t> (fromOrTo);
547 template <
signed_
integral T>
548 inline size_t String::SubString_adjust_ (T fromOrTo,
size_t myLength)
const
550 if (fromOrTo >= 0) [[likely]] {
551 Require (fromOrTo <= numeric_limits<ptrdiff_t>::max ());
552 return static_cast<size_t> (fromOrTo);
555 Require (fromOrTo >= numeric_limits<ptrdiff_t>::min ());
556 return static_cast<size_t> (myLength +
static_cast<ptrdiff_t
> (fromOrTo));
559 template <
typename SZ>
562 _SafeReadRepAccessor accessor{
this};
563 size_t myLength{accessor._ConstGetRep ().
size ()};
564 size_t f = SubString_adjust_ (from, myLength);
566 Require (f <= myLength);
567 return SubString_ (accessor, f, t);
569 template <
typename SZ1,
typename SZ2>
572 _SafeReadRepAccessor accessor{
this};
573 size_t myLength{accessor._ConstGetRep ().
size ()};
574 size_t f = SubString_adjust_ (from, myLength);
575 size_t t = SubString_adjust_ (to, myLength);
577 Require (t <= myLength);
578 return SubString_ (accessor, f, t);
580 template <
typename SZ>
583 _SafeReadRepAccessor accessor{
this};
584 size_t myLength{accessor._ConstGetRep ().
size ()};
585 size_t f = SubString_adjust_ (from, myLength);
586 f = min (f, myLength);
587 Assert (f <= myLength);
588 size_t useLength{myLength - f};
589 return SubString_ (accessor, f, f + useLength);
591 template <
typename SZ1,
typename SZ2>
594 _SafeReadRepAccessor accessor{
this};
595 size_t myLength{accessor._ConstGetRep ().
size ()};
596 size_t f = SubString_adjust_ (from, myLength);
597 size_t t = SubString_adjust_ (to, myLength);
598 f = min (f, myLength);
599 t = min (t, myLength);
602 Assert (t <= myLength);
603 size_t useLength = (t - f);
604 return SubString_ (accessor, f, f + useLength);
608 return SafeSubString (n);
612 return RemoveAt (charAt, charAt + 1);
616 return RemoveAt (fromTo.first, fromTo.second);
618 inline bool String::empty () const noexcept
620 _SafeReadRepAccessor accessor{
this};
621 return accessor._ConstGetRep ().size () == 0;
625 inline void ExtractMatches_ ([[maybe_unused]]
const wsmatch& base_match, [[maybe_unused]]
size_t currentUnpackIndex)
628 template <Common::IAnyOf<optional<String>*, String*,
nullptr_t> SUBMATCH,
typename... OPTIONAL_STRINGS>
629 void ExtractMatches_ (
const wsmatch& base_match,
size_t currentUnpackIndex, SUBMATCH subMatchI, OPTIONAL_STRINGS&&... remainingSubmatches)
631 if (currentUnpackIndex < base_match.size ()) [[likely]] {
632 if constexpr (not same_as<SUBMATCH, nullptr_t>) {
633 if (subMatchI !=
nullptr) {
634 *subMatchI = base_match[currentUnpackIndex].str ();
637 ExtractMatches_ (base_match, currentUnpackIndex + 1, forward<OPTIONAL_STRINGS> (remainingSubmatches)...);
640 const wregex& RegularExpression_GetCompiled (
const RegularExpression& regExp);
642 template <Common::IAnyOf<optional<String>*, String*,
nullptr_t>... OPTIONAL_STRINGS>
643 bool String::Matches (
const RegularExpression& regEx, OPTIONAL_STRINGS&&... subMatches)
const
645 wstring tmp{As<wstring> ()};
647 if (regex_match (tmp, baseMatch, Private_::RegularExpression_GetCompiled (regEx))) {
648 Private_::ExtractMatches_ (baseMatch, 1, forward<OPTIONAL_STRINGS> (subMatches)...);
654 optional<Common::RepeatedTuple_t<I, String>>
String::Matches (
const RegularExpression& regEx)
const
656 wstring tmp{As<wstring> ()};
658 if (regex_match (tmp, baseMatch, Private_::RegularExpression_GetCompiled (regEx))) {
660 if constexpr (I == 0) {
661 return make_tuple ();
663 else if constexpr (I == 1) {
664 return make_tuple (String{baseMatch[1].str ()});
666 else if constexpr (I == 2) {
667 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()});
669 else if constexpr (I == 3) {
670 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()}, String{baseMatch[3].str ()});
672 else if constexpr (I == 4) {
673 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()}, String{baseMatch[3].str ()},
674 String{baseMatch[4].str ()});
676 else if constexpr (I == 5) {
677 return make_tuple (String{baseMatch[1].str ()}, String{baseMatch[2].str ()}, String{baseMatch[3].str ()},
678 String{baseMatch[4].str ()}, String{baseMatch[5].str ()});
689 return Find (c, 0, co);
691 inline optional<size_t>
String::Find (
const String& subString, CompareOptions co)
const
693 return Find (subString, 0, co);
697 return inherited::Find (that);
701 return static_cast<bool> (Find (c, co));
705 return static_cast<bool> (Find (subString, co));
707 inline bool String::ContainsAny (Iterable<Character> cs, CompareOptions co)
const
709 auto comparer = Character::EqualsComparer{co};
710 auto checkEachCharacter = [&] (Character c) ->
bool {
return cs.Any ([&] (
const Character c2) {
return comparer (c, c2); }); };
711 return Find (checkEachCharacter) !=
nullptr;
713 inline String
String::Replace (pair<size_t, size_t> fromTo,
const String& replacement)
const
715 return Replace (fromTo.first, fromTo.second, replacement);
719 return Col (i).value_or (valueIfMissing);
723 return InsertAt (span<const Character>{&c, 1}, at);
728 return InsertAt (s.
GetData (&ignored1), at);
732 return InsertAt (Memory::ConstSpan (s), at);
734 inline const Character String::GetCharAt (
size_t i)
const noexcept
736 _SafeReadRepAccessor accessor{
this};
738 Require (i < accessor._ConstGetRep ().size ());
739 return accessor._ConstGetRep ().GetAt (i);
744 Require (i < size ());
745 return GetCharAt (i);
749 static const String kELIPSIS_{u
"\u2026"sv};
750 return LimitLength (maxLen, keepPref, kELIPSIS_);
752 template <
typename T>
756 if constexpr (same_as<T, u8string>) {
759 else if constexpr (same_as<T, u16string>) {
760 return AsUTF16<T> ();
762 else if constexpr (same_as<T, u32string>) {
763 return AsUTF32<T> ();
765 else if constexpr (same_as<T, wstring>) {
766 if constexpr (
sizeof (wchar_t) == 2) {
767 return AsUTF16<T> ();
770 return AsUTF32<T> ();
773 else if constexpr (same_as<T, String>) {
776 else if constexpr (constructible_from<T, wstring>) {
777 return T{As<wstring> ()};
780 template <
typename T>
782 requires (same_as<T,
string> or same_as<T, u8string>)
784 Memory::StackBuffer<char8_t> maybeIgnoreBuf1;
785 span<const char8_t> thisData = GetData (&maybeIgnoreBuf1);
786 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
788 template <
typename T>
790 requires (same_as<T, u16string> or (sizeof (
wchar_t) == sizeof (
char16_t) and same_as<T, wstring>))
792 Memory::StackBuffer<char16_t> maybeIgnoreBuf1;
793 span<const char16_t> thisData = GetData (&maybeIgnoreBuf1);
794 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
796 template <
typename T>
798 requires (same_as<T, u32string> or (sizeof (
wchar_t) == sizeof (
char32_t) and same_as<T, wstring>))
800 Memory::StackBuffer<char32_t> maybeIgnoreBuf1;
801 span<const char32_t> thisData = GetData (&maybeIgnoreBuf1);
802 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
806#if qStroika_Foundation_Characters_SDKUseswchar_t
808 span<const wchar_t> thisData = GetData (&maybeIgnoreBuf1);
809 return SDKString{thisData.begin (), thisData.end ()};
810#elif qStroika_Platform_MacOS
812 span<const char8_t> thisData = GetData (&maybeIgnoreBuf1);
813 return SDKString{thisData.begin (), thisData.end ()};
815 return AsNarrowString (locale{});
820#if qStroika_Foundation_Characters_SDKUseswchar_t
822 span<const wchar_t> thisData = GetData (&maybeIgnoreBuf1);
823 return SDKString{thisData.begin (), thisData.end ()};
824#elif qStroika_Platform_MacOS
826 span<const char8_t> thisData = GetData (&maybeIgnoreBuf1);
827 return SDKString{thisData.begin (), thisData.end ()};
829 return AsNarrowString (locale{}, eIgnoreErrors);
838 return SDK2Narrow (AsSDKString (eIgnoreErrors), AllowMissingCharacterErrorsFlag::eIgnoreErrors);
840 template <
typename T>
842 requires requires (T* into) {
843 { into->empty () } -> same_as<bool>;
844 { into->push_back (ASCII{0}) };
848 if (
auto p = AsASCIIQuietly<T> ()) {
852 ThrowInvalidAsciiException_ ();
855 template <
typename T>
857 requires requires (T* into) {
858 { into->empty () } -> same_as<bool>;
859 { into->push_back (ASCII{0}) };
863 Memory::StackBuffer<wchar_t> ignored1;
864 auto thisSpan = GetData (&ignored1);
866 return Character::AsASCIIQuietly<T> (thisSpan, &s) ? s : optional<T>{};
868 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
871 using StorageCodePointType = PeekSpanData::StorageCodePointType;
872 StorageCodePointType preferredSCP{};
873 if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
ASCII>) {
874 preferredSCP = StorageCodePointType::eAscii;
876 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>, Latin1>) {
877 preferredSCP = StorageCodePointType::eSingleByteLatin1;
879 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char8_t>) {
880 preferredSCP = StorageCodePointType::eAscii;
882 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char16_t>) {
883 preferredSCP = StorageCodePointType::eChar16;
885 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char32_t> or same_as<remove_cv_t<CHAR_TYPE>, Character>) {
886 preferredSCP = StorageCodePointType::eChar32;
888 if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
wchar_t>) {
889 if constexpr (
sizeof (wchar_t) == 2) {
890 preferredSCP = StorageCodePointType::eChar16;
892 else if constexpr (
sizeof (wchar_t) == 4) {
893 preferredSCP = StorageCodePointType::eChar32;
896 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>, Character>) {
898 if constexpr (
sizeof (wchar_t) == 2) {
899 preferredSCP = StorageCodePointType::eChar16;
901 else if constexpr (
sizeof (wchar_t) == 4) {
902 preferredSCP = StorageCodePointType::eChar32;
905 return _SafeReadRepAccessor{
this}._ConstGetRep ().PeekData (preferredSCP);
907 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
908 inline optional<span<const CHAR_TYPE>> String::PeekData (
const PeekSpanData& pds)
911 if constexpr (same_as<CHAR_TYPE, ASCII>) {
912 if (pds.fInCP == StorageCodePointType::eAscii) {
916 else if constexpr (same_as<CHAR_TYPE, Latin1>) {
917 if (pds.fInCP == StorageCodePointType::eSingleByteLatin1) {
918 return pds.fSingleByteLatin1;
921 else if constexpr (same_as<CHAR_TYPE, char8_t>) {
922 if (pds.fInCP == StorageCodePointType::eAscii) {
926 else if constexpr (same_as<CHAR_TYPE, char16_t>) {
927 if (pds.fInCP == StorageCodePointType::eChar16) {
931 else if constexpr (same_as<CHAR_TYPE, char32_t>) {
932 if (pds.fInCP == StorageCodePointType::eChar32) {
936 else if constexpr (same_as<CHAR_TYPE, wchar_t>) {
937 if constexpr (
sizeof (wchar_t) == 2) {
938 if (pds.fInCP == StorageCodePointType::eChar16) {
939 return span<const wchar_t>{
reinterpret_cast<const wchar_t*
> (pds.fChar16.data ()), pds.fChar16.size ()};
942 else if constexpr (
sizeof (wchar_t) == 4) {
943 if (pds.fInCP == StorageCodePointType::eChar32) {
944 return span<const wchar_t>{
reinterpret_cast<const wchar_t*
> (pds.fChar32.data ()), pds.fChar32.size ()};
947 return span<const wchar_t>{};
949 else if constexpr (same_as<CHAR_TYPE, Character>) {
950 if (pds.fInCP == StorageCodePointType::eChar32) {
951 return span<const Character>{
reinterpret_cast<const Character*
> (pds.fChar32.data ()), pds.fChar32.size ()};
953 return span<const Character>{};
957 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
958 inline optional<span<const CHAR_TYPE>> String::PeekData ()
const
960 return PeekData<CHAR_TYPE> (GetPeekSpanData<CHAR_TYPE> ());
964 template <IUNICODECanAlwaysConvertTo CHAR_TYPE,
size_t STACK_BUFFER_SZ>
969 if constexpr (same_as<CHAR_TYPE, wchar_t>) {
970 if constexpr (
sizeof (CHAR_TYPE) == 2) {
972 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
974 else if constexpr (
sizeof (wchar_t) == 4) {
976 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
979 else if constexpr (same_as<CHAR_TYPE, Character>) {
981 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
983 if constexpr (same_as<CHAR_TYPE, char8_t>) {
985 case StorageCodePointType::eAscii:
987 return span{
reinterpret_cast<const char8_t*
> (pds.fAscii.data ()), pds.fAscii.size ()};
988 case StorageCodePointType::eSingleByteLatin1: {
990 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
991 return UTFConvert::kThe.ConvertSpan (pds.fSingleByteLatin1, span{*possiblyUsedBuffer});
993 case StorageCodePointType::eChar16: {
994 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar16));
995 return UTFConvert::kThe.ConvertSpan (pds.fChar16, span{*possiblyUsedBuffer});
997 case StorageCodePointType::eChar32: {
998 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar32));
999 return UTFConvert::kThe.ConvertSpan (pds.fChar32, span{*possiblyUsedBuffer});
1003 return span<const CHAR_TYPE>{};
1006 else if constexpr (same_as<CHAR_TYPE, char16_t>) {
1007 switch (pds.fInCP) {
1008 case StorageCodePointType::eAscii:
1009 case StorageCodePointType::eSingleByteLatin1: {
1010 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
1011 return UTFConvert::kThe.ConvertSpan (pds.fSingleByteLatin1, span{*possiblyUsedBuffer});
1013 case StorageCodePointType::eChar16:
1015 case StorageCodePointType::eChar32: {
1016 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar32));
1017 return UTFConvert::kThe.ConvertSpan (pds.fChar32, span{*possiblyUsedBuffer});
1021 return span<const CHAR_TYPE>{};
1024 else if constexpr (same_as<CHAR_TYPE, char32_t>) {
1025 switch (pds.fInCP) {
1026 case StorageCodePointType::eAscii:
1027 case StorageCodePointType::eSingleByteLatin1: {
1028 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
1029 return UTFConvert::kThe.ConvertSpan (pds.fSingleByteLatin1, span{*possiblyUsedBuffer});
1031 case StorageCodePointType::eChar16: {
1032 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar16));
1033 return UTFConvert::kThe.ConvertSpan (pds.fChar16, span{*possiblyUsedBuffer});
1035 case StorageCodePointType::eChar32:
1039 return span<const CHAR_TYPE>{};
1043 template <IUNICODECanAlwaysConvertTo CHAR_TYPE,
size_t STACK_BUFFER_SZ>
1044 inline span<const CHAR_TYPE>
String::GetData (Memory::StackBuffer<CHAR_TYPE, STACK_BUFFER_SZ>* possiblyUsedBuffer)
const
1047 return GetData (GetPeekSpanData<CHAR_TYPE> (), possiblyUsedBuffer);
1059 wstring tmp{As<wstring> ()};
1061 copy (tmp.begin (), tmp.end (), possibleBackingStore->begin ());
1062 (*possibleBackingStore)[tmp.length ()] =
'\0';
1063 return make_tuple (possibleBackingStore->begin (), wstring_view{possibleBackingStore->begin (), tmp.length ()});
1067 return Find (c, startAt, eWithCase).value_or (npos);
1071 return Find (s, startAt, eWithCase).value_or (npos);
1075 return RFind (c).value_or (npos);
1079 Require (not empty ());
1080 _SafeReadRepAccessor accessor{
this};
1081 size_t thisLen = accessor._ConstGetRep ().size ();
1082 return accessor._ConstGetRep ().GetAt (thisLen - 1);
1086 Require (not empty ());
1087 _SafeReadRepAccessor accessor{
this};
1088 return accessor._ConstGetRep ().GetAt (0);
1092 _SafeReadRepAccessor accessor{
this};
1093 size_t thisLen = accessor._ConstGetRep ().
size ();
1094 if (from > thisLen) [[unlikely]] {
1095 static auto kException_ = out_of_range{
"string index out of range"};
1100 size_t to = (count == npos) ? thisLen : (from + min (thisLen, count));
1101 return SubString_ (accessor, from, to);
1105 return ThreeWayComparer{}(*
this, rhs);
1107 template <IConvertibleToString T>
1109 requires (not same_as<remove_cvref_t<T>,
String>)
1111 return ThreeWayComparer{}(*
this, forward<T> (rhs));
1117 template <IConvertibleToString T>
1119 requires (not same_as<remove_cvref_t<T>,
String>)
1121 return EqualsComparer{}(*
this, rhs);
1129 inline namespace Literals {
1130 inline String
operator""_k (
const ASCII* s,
size_t len)
1132 return String::FromStringConstant (span<const char>{s, len});
1134 inline String
operator""_k (
const char8_t* s,
size_t len)
1136 return String::FromStringConstant (span<const char8_t>{s, len});
1138 inline String
operator""_k (
const wchar_t* s,
size_t len)
1140 return String::FromStringConstant (span<const wchar_t>{s, len});
1142 inline String
operator""_k (
const char16_t* s,
size_t len)
1144 return String::FromStringConstant (span<const char16_t>{s, len});
1146 inline String
operator""_k (
const char32_t* s,
size_t len)
1148 return String::FromStringConstant (span<const char32_t>{s, len});
1158 : fCompareOptions{co}
1161 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1162 inline bool String::EqualsComparer::Cmp_ (
LT&&
lhs,
RT&&
rhs)
const
1168 if (fCompareOptions == eWithCase) {
1185 if (fCompareOptions == eWithCase) {
1198 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1199 bool String::EqualsComparer::Cmp_Generic_ (
LT&&
lhs,
RT&&
rhs)
const
1204 Memory::StackBuffer<Character, 256>
ignore1;
1205 Memory::StackBuffer<Character, 256>
ignore2;
1209 template <IConvertibleToString LT, IConvertibleToString RT>
1212 if constexpr (
requires {
lhs.size (); }
and requires {
rhs.size (); }) {
1213 if (
lhs.size () !=
rhs.size ()) {
1217 if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LT>
and Private_::ICanBeTreatedAsSpanOfCharacter_<RT>) {
1231 constexpr String::ThreeWayComparer::ThreeWayComparer (CompareOptions
co)
1232 : fCompareOptions{
co}
1235 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1248 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1254 Memory::StackBuffer<Character, 256>
ignore1;
1255 Memory::StackBuffer<Character, 256>
ignore2;
1259 template <IConvertibleToString LT, IConvertibleToString RT>
1262 if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LT>
and Private_::ICanBeTreatedAsSpanOfCharacter_<RT>) {
1276 constexpr String::LessComparer::LessComparer (CompareOptions
co)
1280 template <
typename T1,
typename T2>
1281 inline bool String::LessComparer::operator() (
T1 lhs,
T2 rhs)
const
1283 return fComparer_ (
lhs,
rhs) < 0;
1291 template <IConvertibleToString LHS_T, IConvertibleToString RHS_T>
1299 else if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LHS_T>
and Private_::ICanBeTreatedAsSpanOfCharacter_<RHS_T>) {
1319#if qStroika_HasComponent_googletest
1331 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1332 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1333 DISABLE_COMPILER_MSC_WARNING_START (4996)
1334 template <typename CHAR_T>
1335 inline
void String::Append (span<const CHAR_T> s)
1336 requires (same_as<CHAR_T, Character> or same_as<CHAR_T,
char32_t>)
1338 if (not s.empty ()) {
1339 Memory::StackBuffer<char32_t> ignored1;
1340 span<const char32_t> thisSpan = this->GetData (&ignored1);
1341 Memory::StackBuffer<char32_t> combinedBuf{Memory::eUninitialized, thisSpan.size () + s.size ()};
1342 Memory::CopySpanData (thisSpan, span{combinedBuf});
1343 char32_t* write2Buf = combinedBuf.data () + thisSpan.size ();
1345 if constexpr (same_as<CHAR_T, Character>) {
1346 *write2Buf = i.template As<char32_t> ();
1353 *
this = mk_ (span{combinedBuf});
1356 inline void String::Append (
const wchar_t* from,
const wchar_t* to)
1358 Require (from <= to);
1360 Memory::StackBuffer<wchar_t> ignored1;
1361 span<const wchar_t> thisSpan = this->GetData (&ignored1);
1362 Memory::StackBuffer<wchar_t> buf{Memory::eUninitialized, thisSpan.size () + (to - from)};
1363 span<wchar_t> bufSpan{buf};
1364 Memory::CopySpanData (thisSpan, bufSpan);
1365 Memory::CopySpanData (span{from, to}, bufSpan.subspan (thisSpan.size ()));
1366 *
this = mk_ (bufSpan);
1369 inline void String::Append (Character c)
1373 inline void String::Append (
const String& s)
1375 Memory::StackBuffer<char32_t> ignored1;
1376 auto rhsSpan = s.GetData (&ignored1);
1379 inline void String::Append (
const wchar_t* s)
1381 Append (s, s + ::wcslen (s));
1383 inline void String::Append (
const Character* from,
const Character* to)
1387 inline String& String::operator+= (Character appendage)
1392 inline String& String::operator+= (
const String& appendage)
1397 inline String& String::operator+= (
const wchar_t* appendageCStr)
1403 inline void String::push_back (
wchar_t c)
1407 inline void String::push_back (Character c)
1412 DISABLE_COMPILER_MSC_WARNING_END (4996)
1413 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1414 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
1416 [[deprecated ("Since Stroika v3.0d1 - just use _k, sv, or nothing")]] inline String operator""_ASCII (const
char* str,
size_t len)
1418 return String{span{str, len}};
1420 class [[deprecated (
"Since Stroika v3.0 - just use String::FromStringConstant")]] String_Constant :
public String {
1422 template <
size_t SIZE>
1423 explicit String_Constant (
const wchar_t (&cString)[SIZE])
1424 : String{String::FromStringConstant (
std::basic_string_view<wchar_t>{cString, SIZE - 1})}
1428 String_Constant (
const wchar_t* start,
const wchar_t* end)
1429 : String{String::FromStringConstant (
std::basic_string_view<wchar_t>{start,
static_cast<size_t> (end - start)})}
1433 String_Constant (
const std::basic_string_view<wchar_t>& str)
1439namespace Stroika::Foundation::Characters::Concrete {
1440 class [[deprecated (
"Since Stroika v3.0 - just use String::FromStringConstant")]] String_ExternalMemoryOwnership_ApplicationLifetime :
public String {
1442 template <
size_t SIZE>
1443 explicit String_ExternalMemoryOwnership_ApplicationLifetime (
const wchar_t (&cString)[SIZE - 1])
1444 : String{String::FromStringConstant (basic_string_view<wchar_t>{cString, SIZE})}
1448 String_ExternalMemoryOwnership_ApplicationLifetime (
const wchar_t* start,
const wchar_t* end)
1449 : String{String::FromStringConstant (basic_string_view<wchar_t>{start,
static_cast<size_t> (end - start)})}
1453 String_ExternalMemoryOwnership_ApplicationLifetime (
const basic_string_view<wchar_t>& str)
1463 String StringCombiner<String>::operator() (
const String& lhs,
const String& rhs,
bool isLast)
const;
1465 template <
typename STRING>
1466 STRING StringCombiner<STRING>::operator() (
const STRING& lhs,
const STRING& rhs,
bool isLast)
const
1469 if (isLast and fSpecialSeparatorForLastPair) [[unlikely]] {
1470 sb = sb + *fSpecialSeparatorForLastPair;
1473 sb = sb + fSeparator;