8#include "Stroika/Foundation/Execution/Throw.h"
9#include "Stroika/Foundation/Memory/Common.h"
13 [[deprecated (
"Since v3.0d1 - use String{s}.AsNarrowSDKString ()")]]
inline std::string WideStringToNarrowSDKString (std::wstring s)
15 return String{s}.AsNarrowSDKString ();
24 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
25 static size_t StrLen_ (
const CHAR_T* s)
27 if constexpr (same_as<CHAR_T, Latin1>) {
28 return StrLen_ (
reinterpret_cast<const char*
> (s));
31 return CString::Length (s);
34 template <IUNICODECanUnambiguouslyConvertFrom SRC_T>
35 inline void CopyAsASCIICharacters_ (span<const SRC_T> src, span<ASCII> trg)
37 Require (trg.size () >= src.size ());
38 ASCII* outI = trg.data ();
39 for (
auto ii = src.begin (); ii != src.end (); ++ii) {
40 if constexpr (same_as<SRC_T, Character>) {
41 *outI++ = ii->GetAsciiCode ();
44 *outI++ =
static_cast<ASCII> (*ii);
48 template <IUNICODECanUnambiguouslyConvertFrom SRC_T>
49 inline void CopyAsLatin1Characters_ (span<const SRC_T> src, span<Latin1> trg)
51 Require (trg.size () >= src.size ());
52 Latin1* outI = trg.data ();
53 for (
auto ii = src.begin (); ii != src.end (); ++ii) {
54 if constexpr (same_as<SRC_T, Character>) {
55 *outI++ = Latin1{
static_cast<unsigned char> (ii->GetCharacterCode ())};
58 *outI++ = Latin1{
static_cast<unsigned char> (*ii)};
62 template <ICanBeTreatedAsSpanOfCharacter_ USTRING,
size_t STACK_BUFFER_SZ>
63 inline span<const Character> AsSpanOfCharacters_ (USTRING&& s, Memory::StackBuffer<Character, STACK_BUFFER_SZ>* mostlyIgnoredBuf)
73 if constexpr (derived_from<remove_cvref_t<USTRING>, String>) {
74 return s.GetData (mostlyIgnoredBuf);
76 else if constexpr (same_as<remove_cvref_t<USTRING>,
const char32_t*> or
77 (
sizeof (
wchar_t) ==
sizeof (Character) and same_as<remove_cvref_t<USTRING>,
const wchar_t*>)) {
78 return span{
reinterpret_cast<const Character*
> (s), CString::Length (s)};
80 else if constexpr (same_as<remove_cvref_t<USTRING>, u32string> or
81 (
sizeof (
wchar_t) ==
sizeof (Character) and same_as<remove_cvref_t<USTRING>, wstring>)) {
82 return span{
reinterpret_cast<const Character*
> (s.c_str ()), s.length ()};
84 else if constexpr (same_as<remove_cvref_t<USTRING>, u32string_view> or
85 (
sizeof (
wchar_t) ==
sizeof (Character) and same_as<remove_cvref_t<USTRING>, wstring_view>)) {
86 return span{
reinterpret_cast<const Character*
> (s.data ()), s.length ()};
88 else if constexpr (same_as<remove_cvref_t<USTRING>,
const char8_t*> or same_as<remove_cvref_t<USTRING>,
const char16_t*> or
89 same_as<remove_cvref_t<USTRING>,
const wchar_t*>) {
90 span spn{s, CString::Length (s)};
91 mostlyIgnoredBuf->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<Character> (spn));
94 else if constexpr (same_as<remove_cvref_t<USTRING>, u8string> or same_as<remove_cvref_t<USTRING>, u16string> or
95 same_as<remove_cvref_t<USTRING>, wstring>) {
96 span spn{s.data (), s.size ()};
97 mostlyIgnoredBuf->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<Character> (spn));
100 else if constexpr (same_as<remove_cvref_t<USTRING>, u8string_view> or same_as<remove_cvref_t<USTRING>, u16string_view> or
101 same_as<remove_cvref_t<USTRING>, wstring_view>) {
102 span spn{s.data (), s.size ()};
103 mostlyIgnoredBuf->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<Character> (spn));
109 mostlyIgnoredBuf->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<Character> (spn));
123 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
124 auto String::mk_ (span<const CHAR_T> s) -> shared_ptr<_IRep>
129 if constexpr (same_as<CHAR_T, ASCII>) {
131 return mk_nocheck_ (s);
133 else if constexpr (same_as<CHAR_T, Latin1>) {
135 return mk_nocheck_ (s);
139 case Character::ASCIIOrLatin1Result::eASCII: {
140 if constexpr (
sizeof (CHAR_T) == 1) {
141 return mk_nocheck_ (span<const ASCII>{
reinterpret_cast<const ASCII*
> (s.data ()), s.size ()});
145 Memory::StackBuffer<
ASCII, Memory::kStackBuffer_SizeIfLargerStackGuardCalled / 4 - 20> buf{Memory::eUninitialized, s.size ()};
146 Private_::CopyAsASCIICharacters_ (s, span{buf});
147 return mk_nocheck_ (span<const ASCII>{buf});
150 case Character::ASCIIOrLatin1Result::eLatin1: {
151 if constexpr (
sizeof (CHAR_T) == 1) {
152 if constexpr (same_as<remove_cv_t<CHAR_T>,
ASCII>) {
155 else if constexpr (same_as<remove_cv_t<CHAR_T>, Latin1>) {
156 return mk_nocheck_ (s);
158 else if constexpr (same_as<remove_cv_t<CHAR_T>,
char8_t>) {
175 Memory::StackBuffer<char16_t, Memory::kStackBuffer_SizeIfLargerStackGuardCalled / 16 - 20> c16buf{Memory::eUninitialized,
178 Memory::StackBuffer<Latin1, Memory::kStackBuffer_SizeIfLargerStackGuardCalled / 16 - 20> buf{Memory::eUninitialized,
180 Private_::CopyAsLatin1Characters_ (s16, span{buf});
181 return mk_nocheck_ (span<const Latin1>{buf});
189 Memory::StackBuffer<Latin1, Memory::kStackBuffer_SizeIfLargerStackGuardCalled / 8 - 20> buf{Memory::eUninitialized, s.size ()};
190 Private_::CopyAsLatin1Characters_ (s, span{buf});
191 return mk_nocheck_ (span<const Latin1>{buf});
197 if constexpr (
sizeof (CHAR_T) == 2) {
199 return mk_nocheck_ (span<const char16_t>{
reinterpret_cast<const char16_t*
> (s.data ()), s.size ()});
203 Memory::StackBuffer<char16_t, Memory::kStackBuffer_SizeIfLargerStackGuardCalled / 16> wideUnicodeBuf{
204 Memory::eUninitialized, UTFConvert::ComputeTargetBufferSize<char16_t> (s)};
205 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (s, span{wideUnicodeBuf})));
209 if constexpr (
sizeof (CHAR_T) == 4) {
211 return mk_nocheck_ (span<const char32_t>{
reinterpret_cast<const char32_t*
> (s.data ()), s.size ()});
215 Memory::StackBuffer<char32_t, Memory::kStackBuffer_SizeIfLargerStackGuardCalled / 32> wideUnicodeBuf{
216 Memory::eUninitialized, UTFConvert::ComputeTargetBufferSize<char32_t> (s)};
217 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (s, span{wideUnicodeBuf})));
220 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
221 auto String::mk_ (span<CHAR_T> s) -> shared_ptr<_IRep>
224 return mk_ (Memory::ConstSpan (s));
226 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
227 auto String::mk_ (Iterable<CHAR_T> it) -> shared_ptr<_IRep>
231 Memory::StackBuffer<char32_t> r;
232 it.Apply ([&r] (CHAR_T c) {
233 if constexpr (same_as<CHAR_T, Character>) {
234 r.push_back (
static_cast<char32_t> (c));
240 return mk_ (span{r.data (), r.size ()});
243 auto String::mk_ (basic_string<char>&& s) -> shared_ptr<_IRep>;
245 auto String::mk_ (basic_string<char16_t>&& s) -> shared_ptr<_IRep>;
247 auto String::mk_ (basic_string<char32_t>&& s) -> shared_ptr<_IRep>;
249 auto String::mk_ (basic_string<wchar_t>&& s) -> shared_ptr<_IRep>;
250 template <IStdBasicStringCompatibleCharacter CHAR_T>
251 inline auto String::mk_ (basic_string<CHAR_T>&& s) -> shared_ptr<_IRep>
254 return mk_ (span{s.begin (), s.size ()});
259 _AssertRepValidType ();
264 _AssertRepValidType ();
267 : inherited{mkEmpty_ ()}
269 _AssertRepValidType ();
271 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
273 : inherited{mk_ (span{cString, CString::Length (cString)})}
276 _AssertRepValidType ();
278 template <Memory::ISpan SPAN_OF_CHAR_T>
280 requires (IUNICODECanUnambiguouslyConvertFrom<typename SPAN_OF_CHAR_T::value_type>)
281 : inherited{mk_ (span<const typename SPAN_OF_CHAR_T::value_type>{s})}
283 _AssertRepValidType ();
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>
297 requires (not Memory::ISpan<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 ()};
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>
390 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
395 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
401 if constexpr (same_as<CHAR_T, char8_t>) {
411 if constexpr (
sizeof (wchar_t) == 2) {
415 Assert (
sizeof (
wchar_t) == 4);
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>)
424 return mk_ (span<const char>{
reinterpret_cast<const char*
> (s.data ()), s.size ()});
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.c_str (), 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))});
454 if constexpr (same_as<SDKChar, wchar_t>) {
463 if constexpr (same_as<SDKString, wstring>) {
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:
524 case PeekSpanData::StorageCodePointType::eChar16:
526 case PeekSpanData::StorageCodePointType::eChar32:
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 RemoveAt (charAt, charAt + 1);
610 return RemoveAt (fromTo.first, fromTo.second);
612 inline bool String::empty () const noexcept
614 _SafeReadRepAccessor accessor{
this};
615 return accessor._ConstGetRep ().
size () == 0;
619 inline void ExtractMatches_ ([[maybe_unused]]
const wsmatch& base_match, [[maybe_unused]]
size_t currentUnpackIndex)
622 template <Common::IAnyOf<optional<String>*, String*,
nullptr_t> SUBMATCH,
typename... OPTIONAL_STRINGS>
623 void ExtractMatches_ (
const wsmatch& base_match,
size_t currentUnpackIndex, SUBMATCH subMatchI, OPTIONAL_STRINGS&&... remainingSubmatches)
625 if (currentUnpackIndex < base_match.size ()) [[likely]] {
626 if constexpr (not same_as<SUBMATCH, nullptr_t>) {
627 if (subMatchI !=
nullptr) {
628 *subMatchI = base_match[currentUnpackIndex].str ();
631 ExtractMatches_ (base_match, currentUnpackIndex + 1, forward<OPTIONAL_STRINGS> (remainingSubmatches)...);
634 const wregex& RegularExpression_GetCompiled (
const RegularExpression& regExp);
636 template <Common::IAnyOf<optional<String>*, String*,
nullptr_t>... OPTIONAL_STRINGS>
637 bool String::Matches (
const RegularExpression& regEx, OPTIONAL_STRINGS&&... subMatches)
const
639 wstring tmp{As<wstring> ()};
641 if (regex_match (tmp, baseMatch, Private_::RegularExpression_GetCompiled (regEx))) {
642 Private_::ExtractMatches_ (baseMatch, 1, forward<OPTIONAL_STRINGS> (subMatches)...);
648 optional<Common::RepeatedTuple_t<I, String>>
String::Matches (
const RegularExpression& regEx)
const
650 wstring tmp{As<wstring> ()};
652 if (regex_match (tmp, baseMatch, Private_::RegularExpression_GetCompiled (regEx))) {
654 if constexpr (I == 0) {
655 return make_tuple ();
657 else if constexpr (I == 1) {
658 return make_tuple (
String{baseMatch[1].str ()});
660 else if constexpr (I == 2) {
661 return make_tuple (
String{baseMatch[1].str ()},
String{baseMatch[2].str ()});
663 else if constexpr (I == 3) {
664 return make_tuple (
String{baseMatch[1].str ()},
String{baseMatch[2].str ()},
String{baseMatch[3].str ()});
666 else if constexpr (I == 4) {
667 return make_tuple (
String{baseMatch[1].str ()},
String{baseMatch[2].str ()},
String{baseMatch[3].str ()},
668 String{baseMatch[4].str ()});
670 else if constexpr (I == 5) {
671 return make_tuple (
String{baseMatch[1].str ()},
String{baseMatch[2].str ()},
String{baseMatch[3].str ()},
672 String{baseMatch[4].str ()},
String{baseMatch[5].str ()});
683 return Find (c, 0, co);
685 inline optional<size_t>
String::Find (
const String& subString, CompareOptions co)
const
687 return Find (subString, 0, co);
691 return inherited::Find (that);
695 return static_cast<bool> (
Find (c, co));
699 return static_cast<bool> (
Find (subString, co));
701 inline bool String::ContainsAny (Iterable<Character> cs, CompareOptions co)
const
703 auto comparer = Character::EqualsComparer{co};
704 auto checkEachCharacter = [&] (Character c) ->
bool {
return cs.Any ([&] (
const Character c2) {
return comparer (c, c2); }); };
705 return Find (checkEachCharacter) !=
nullptr;
707 inline String
String::Replace (pair<size_t, size_t> fromTo,
const String& replacement)
const
709 return Replace (fromTo.first, fromTo.second, replacement);
713 return Col (i).value_or (valueIfMissing);
717 return InsertAt (span<const Character>{&c, 1}, at);
726 return InsertAt (Memory::ConstSpan (s), at);
728 inline const Character String::GetCharAt (
size_t i)
const noexcept
730 _SafeReadRepAccessor accessor{
this};
732 Require (i < accessor._ConstGetRep ().size ());
733 return accessor._ConstGetRep ().GetAt (i);
738 Require (i < size ());
739 return GetCharAt (i);
743#if qCompiler_vswprintf_on_elispisStr_Buggy
744 static const String kELIPSIS_{
"..."_k};
746 static const String kELIPSIS_{u
"\u2026"sv};
750 template <
typename T>
754 if constexpr (same_as<T, u8string>) {
757 else if constexpr (same_as<T, u16string>) {
758 return AsUTF16<T> ();
760 else if constexpr (same_as<T, u32string>) {
761 return AsUTF32<T> ();
763 else if constexpr (same_as<T, wstring>) {
764 if constexpr (
sizeof (wchar_t) == 2) {
765 return AsUTF16<T> ();
768 return AsUTF32<T> ();
771 else if constexpr (same_as<T, String>) {
774 else if constexpr (constructible_from<T, wstring>) {
775 return T{As<wstring> ()};
778 template <
typename T>
780 requires (same_as<T,
string> or same_as<T, u8string>)
782 Memory::StackBuffer<char8_t> maybeIgnoreBuf1;
783 span<const char8_t> thisData =
GetData (&maybeIgnoreBuf1);
784 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
786 template <
typename T>
788 requires (same_as<T, u16string> or (sizeof (
wchar_t) == sizeof (
char16_t) and same_as<T, wstring>))
790 Memory::StackBuffer<char16_t> maybeIgnoreBuf1;
791 span<const char16_t> thisData =
GetData (&maybeIgnoreBuf1);
792 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
794 template <
typename T>
796 requires (same_as<T, u32string> or (sizeof (
wchar_t) == sizeof (
char32_t) and same_as<T, wstring>))
798 Memory::StackBuffer<char32_t> maybeIgnoreBuf1;
799 span<const char32_t> thisData =
GetData (&maybeIgnoreBuf1);
800 return T{
reinterpret_cast<const typename T::value_type*
> (thisData.data ()), thisData.size ()};
804#if qTargetPlatformSDKUseswchar_t
806 span<const wchar_t> thisData =
GetData (&maybeIgnoreBuf1);
807 return SDKString{thisData.begin (), thisData.end ()};
808#elif qStroika_Foundation_Common_Platform_MacOS
810 span<const char8_t> thisData =
GetData (&maybeIgnoreBuf1);
811 return SDKString{thisData.begin (), thisData.end ()};
818#if qTargetPlatformSDKUseswchar_t
820 span<const wchar_t> thisData =
GetData (&maybeIgnoreBuf1);
821 return SDKString{thisData.begin (), thisData.end ()};
822#elif qStroika_Foundation_Common_Platform_MacOS
824 span<const char8_t> thisData =
GetData (&maybeIgnoreBuf1);
825 return SDKString{thisData.begin (), thisData.end ()};
838 template <
typename T>
840 requires requires (T* into) {
841 { into->empty () } -> same_as<bool>;
842 { into->push_back (
ASCII{0}) };
846 if (
auto p = AsASCIIQuietly<T> ()) {
850 ThrowInvalidAsciiException_ ();
853 template <
typename T>
855 requires requires (T* into) {
856 { into->empty () } -> same_as<bool>;
857 { into->push_back (
ASCII{0}) };
861 Memory::StackBuffer<wchar_t> ignored1;
862 auto thisSpan = GetData (&ignored1);
864 return Character::AsASCIIQuietly<T> (thisSpan, &s) ? s : optional<T>{};
866 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
870 StorageCodePointType preferredSCP{};
871 if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
ASCII>) {
872 preferredSCP = StorageCodePointType::eAscii;
874 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>, Latin1>) {
875 preferredSCP = StorageCodePointType::eSingleByteLatin1;
877 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char8_t>) {
878 preferredSCP = StorageCodePointType::eAscii;
880 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char16_t>) {
881 preferredSCP = StorageCodePointType::eChar16;
883 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
char32_t> or same_as<remove_cv_t<CHAR_TYPE>, Character>) {
884 preferredSCP = StorageCodePointType::eChar32;
886 if constexpr (same_as<remove_cv_t<CHAR_TYPE>,
wchar_t>) {
887 if constexpr (
sizeof (wchar_t) == 2) {
888 preferredSCP = StorageCodePointType::eChar16;
890 else if constexpr (
sizeof (wchar_t) == 4) {
891 preferredSCP = StorageCodePointType::eChar32;
894 else if constexpr (same_as<remove_cv_t<CHAR_TYPE>, Character>) {
896 if constexpr (
sizeof (wchar_t) == 2) {
897 preferredSCP = StorageCodePointType::eChar16;
899 else if constexpr (
sizeof (wchar_t) == 4) {
900 preferredSCP = StorageCodePointType::eChar32;
903 return _SafeReadRepAccessor{
this}._ConstGetRep ().PeekData (preferredSCP);
905 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
906 inline optional<span<const CHAR_TYPE>> String::PeekData (
const PeekSpanData& pds)
909 if constexpr (same_as<CHAR_TYPE, ASCII>) {
910 if (pds.fInCP == StorageCodePointType::eAscii) {
914 else if constexpr (same_as<CHAR_TYPE, Latin1>) {
915 if (pds.fInCP == StorageCodePointType::eSingleByteLatin1) {
916 return pds.fSingleByteLatin1;
919 else if constexpr (same_as<CHAR_TYPE, char8_t>) {
920 if (pds.fInCP == StorageCodePointType::eAscii) {
924 else if constexpr (same_as<CHAR_TYPE, char16_t>) {
925 if (pds.fInCP == StorageCodePointType::eChar16) {
929 else if constexpr (same_as<CHAR_TYPE, char32_t>) {
930 if (pds.fInCP == StorageCodePointType::eChar32) {
934 else if constexpr (same_as<CHAR_TYPE, wchar_t>) {
935 if constexpr (
sizeof (wchar_t) == 2) {
936 if (pds.fInCP == StorageCodePointType::eChar16) {
937 return span<const wchar_t>{
reinterpret_cast<const wchar_t*
> (pds.fChar16.data ()), pds.fChar16.size ()};
940 else if constexpr (
sizeof (wchar_t) == 4) {
941 if (pds.fInCP == StorageCodePointType::eChar32) {
942 return span<const wchar_t>{
reinterpret_cast<const wchar_t*
> (pds.fChar32.data ()), pds.fChar32.size ()};
945 return span<const wchar_t>{};
947 else if constexpr (same_as<CHAR_TYPE, Character>) {
948 if (pds.fInCP == StorageCodePointType::eChar32) {
949 return span<const Character>{
reinterpret_cast<const Character*
> (pds.fChar32.data ()), pds.fChar32.size ()};
951 return span<const Character>{};
955 template <IUNICODECanUnambiguouslyConvertFrom CHAR_TYPE>
956 inline optional<span<const CHAR_TYPE>> String::PeekData ()
const
958 return PeekData<CHAR_TYPE> (GetPeekSpanData<CHAR_TYPE> ());
960 template <IUNICODECanAlwaysConvertTo CHAR_TYPE,
size_t STACK_BUFFER_SZ>
965 if constexpr (same_as<CHAR_TYPE, wchar_t>) {
966 if constexpr (
sizeof (CHAR_TYPE) == 2) {
968 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
970 else if constexpr (
sizeof (wchar_t) == 4) {
972 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
975 else if constexpr (same_as<CHAR_TYPE, Character>) {
977 return span<const CHAR_TYPE>{
reinterpret_cast<const CHAR_TYPE*
> (p.data ()), p.size ()};
979 if constexpr (same_as<CHAR_TYPE, char8_t>) {
981 case StorageCodePointType::eAscii:
983 return span{
reinterpret_cast<const char8_t*
> (pds.fAscii.data ()), pds.fAscii.size ()};
984 case StorageCodePointType::eSingleByteLatin1: {
986 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
989 case StorageCodePointType::eChar16: {
990 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar16));
993 case StorageCodePointType::eChar32: {
994 possiblyUsedBuffer->
resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar32));
999 return span<const CHAR_TYPE>{};
1002 else if constexpr (same_as<CHAR_TYPE, char16_t>) {
1003 switch (pds.fInCP) {
1004 case StorageCodePointType::eAscii:
1005 case StorageCodePointType::eSingleByteLatin1: {
1006 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
1009 case StorageCodePointType::eChar16:
1011 case StorageCodePointType::eChar32: {
1012 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar32));
1017 return span<const CHAR_TYPE>{};
1020 else if constexpr (same_as<CHAR_TYPE, char32_t>) {
1021 switch (pds.fInCP) {
1022 case StorageCodePointType::eAscii:
1023 case StorageCodePointType::eSingleByteLatin1: {
1024 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fSingleByteLatin1));
1027 case StorageCodePointType::eChar16: {
1028 possiblyUsedBuffer->resize_uninitialized (UTFConvert::ComputeTargetBufferSize<CHAR_TYPE> (pds.fChar16));
1031 case StorageCodePointType::eChar32:
1035 return span<const CHAR_TYPE>{};
1039 template <IUNICODECanAlwaysConvertTo CHAR_TYPE,
size_t STACK_BUFFER_SZ>
1040 inline span<const CHAR_TYPE>
String::GetData (Memory::StackBuffer<CHAR_TYPE, STACK_BUFFER_SZ>* possiblyUsedBuffer)
const
1043 return GetData (GetPeekSpanData<CHAR_TYPE> (), possiblyUsedBuffer);
1055 wstring tmp{As<wstring> ()};
1057 copy (tmp.begin (), tmp.end (), possibleBackingStore->begin ());
1058 (*possibleBackingStore)[tmp.length ()] =
'\0';
1059 return make_tuple (possibleBackingStore->begin (), wstring_view{possibleBackingStore->begin (), tmp.length ()});
1063 return Find (c, startAt, eWithCase).value_or (
npos);
1067 return Find (s, startAt, eWithCase).value_or (
npos);
1075 Require (not empty ());
1076 _SafeReadRepAccessor accessor{
this};
1077 size_t thisLen = accessor._ConstGetRep ().size ();
1078 return accessor._ConstGetRep ().GetAt (thisLen - 1);
1082 Require (not empty ());
1083 _SafeReadRepAccessor accessor{
this};
1084 return accessor._ConstGetRep ().GetAt (0);
1088 _SafeReadRepAccessor accessor{
this};
1089 size_t thisLen = accessor._ConstGetRep ().
size ();
1090 if (from > thisLen) [[unlikely]] {
1091 static auto kException_ = out_of_range{
"string index out of range"};
1096 size_t to = (count ==
npos) ? thisLen : (from + min (thisLen, count));
1097 return SubString_ (accessor, from, to);
1101 return ThreeWayComparer{}(*
this, rhs);
1103 template <IConvertibleToString T>
1105 requires (not same_as<remove_cvref_t<T>,
String>)
1107 return ThreeWayComparer{}(*
this, forward<T> (rhs));
1113 template <IConvertibleToString T>
1115 requires (not same_as<remove_cvref_t<T>,
String>)
1117 return EqualsComparer{}(*
this, rhs);
1125 inline namespace Literals {
1126 inline String
operator"" _k (
const ASCII* s,
size_t len)
1130 inline String
operator"" _k (
const char8_t* s,
size_t len)
1134 inline String
operator"" _k (
const wchar_t* s,
size_t len)
1138 inline String
operator"" _k (
const char16_t* s,
size_t len)
1142 inline String
operator"" _k (
const char32_t* s,
size_t len)
1154 : fCompareOptions{co}
1157 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1158 inline bool String::EqualsComparer::Cmp_ (LT&& lhs, RT&& rhs)
const
1161 if constexpr (same_as<remove_cvref_t<LT>,
String> and same_as<remove_cvref_t<RT>,
String>) {
1162 if (
auto lhsAsciiSpan = lhs.template PeekData<ASCII> ()) {
1163 if (
auto rhsAsciiSpan = rhs.template PeekData<ASCII> ()) {
1164 if (fCompareOptions == eWithCase) {
1165 if (lhsAsciiSpan->size () != rhsAsciiSpan->size ()) {
1168 return Memory::CompareBytes (lhsAsciiSpan->data (), rhsAsciiSpan->data (), lhsAsciiSpan->size ()) == 0;
1177 else if constexpr (same_as<remove_cvref_t<LT>,
String> and same_as<remove_cvref_t<RT>, basic_string_view<ASCII>>) {
1178 if (
auto lhsAsciiSpan = lhs.template PeekData<ASCII> ()) {
1179 auto rhsAsciiSpan = span<const ASCII>{rhs};
1181 if (fCompareOptions == eWithCase) {
1182 if (lhsAsciiSpan->size () != rhsAsciiSpan.size ()) {
1185 return Memory::CompareBytes (lhsAsciiSpan->data (), rhsAsciiSpan.data (), lhsAsciiSpan->size ()) == 0;
1192 return Cmp_Generic_ (forward<LT> (lhs), forward<RT> (rhs));
1194 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1195 bool String::EqualsComparer::Cmp_Generic_ (LT&& lhs, RT&& rhs)
const
1200 Memory::StackBuffer<Character, 256> ignore1;
1201 Memory::StackBuffer<Character, 256> ignore2;
1202 return Character::Compare (Private_::AsSpanOfCharacters_ (forward<LT> (lhs), &ignore1),
1203 Private_::AsSpanOfCharacters_ (forward<RT> (rhs), &ignore2), fCompareOptions) == 0;
1205 template <IConvertibleToString LT, IConvertibleToString RT>
1208 if constexpr (
requires { lhs.size (); } and
requires { rhs.size (); }) {
1209 if (lhs.size () != rhs.size ()) {
1213 if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LT> and Private_::ICanBeTreatedAsSpanOfCharacter_<RT>) {
1214 return Cmp_ (forward<LT> (lhs), forward<RT> (rhs));
1218 return operator() (
String{forward<LT> (lhs)},
String{forward<RT> (rhs)});
1227 constexpr String::ThreeWayComparer::ThreeWayComparer (CompareOptions co)
1228 : fCompareOptions{co}
1231 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1232 inline strong_ordering String::ThreeWayComparer::Cmp_ (LT&& lhs, RT&& rhs)
const
1235 if constexpr (same_as<remove_cvref_t<LT>,
String> and same_as<remove_cvref_t<RT>,
String>) {
1236 if (
auto lhsAsciiSpan = lhs.template PeekData<ASCII> ()) {
1237 if (
auto rhsAsciiSpan = rhs.template PeekData<ASCII> ()) {
1242 return Cmp_Generic_ (forward<LT> (lhs), forward<RT> (rhs));
1244 template <Private_::ICanBeTreatedAsSpanOfCharacter_ LT, Private_::ICanBeTreatedAsSpanOfCharacter_ RT>
1245 strong_ordering String::ThreeWayComparer::Cmp_Generic_ (LT&& lhs, RT&& rhs)
const
1250 Memory::StackBuffer<Character, 256> ignore1;
1251 Memory::StackBuffer<Character, 256> ignore2;
1252 return Character::Compare (Private_::AsSpanOfCharacters_ (forward<LT> (lhs), &ignore1),
1253 Private_::AsSpanOfCharacters_ (forward<RT> (rhs), &ignore2), fCompareOptions);
1255 template <IConvertibleToString LT, IConvertibleToString RT>
1256 inline strong_ordering String::ThreeWayComparer::operator() (LT&& lhs, RT&& rhs)
const
1258 if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LT> and Private_::ICanBeTreatedAsSpanOfCharacter_<RT>) {
1259 return Cmp_ (forward<LT> (lhs), forward<RT> (rhs));
1263 return operator() (
String{forward<LT> (lhs)},
String{forward<RT> (rhs)});
1272 constexpr String::LessComparer::LessComparer (CompareOptions co)
1276 template <
typename T1,
typename T2>
1277 inline bool String::LessComparer::operator() (T1 lhs, T2 rhs)
const
1279 return fComparer_ (lhs, rhs) < 0;
1287 template <IConvertibleToString LHS_T, IConvertibleToString RHS_T>
1289 requires (derived_from<remove_cvref_t<LHS_T>,
String> or derived_from<remove_cvref_t<RHS_T>,
String>)
1291 if constexpr (derived_from<remove_cvref_t<LHS_T>,
String>) {
1295 else if constexpr (Private_::ICanBeTreatedAsSpanOfCharacter_<LHS_T> and Private_::ICanBeTreatedAsSpanOfCharacter_<RHS_T>) {
1298 span<const Character> lSpan = Private_::AsSpanOfCharacters_ (forward<LHS_T> (lhs), &ignored1);
1300 span<const Character> rSpan = Private_::AsSpanOfCharacters_ (forward<RHS_T> (rhs), &ignored2);
1303 Memory::CopySpanData (lSpan, bufSpan);
1304 Memory::CopySpanData (rSpan, bufSpan.subspan (lSpan.size ()));
1315#if qStroika_HasComponent_googletest
1316 inline void PrintTo (
const String& s, std::ostream* os)
1327 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1328 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1329 DISABLE_COMPILER_MSC_WARNING_START (4996)
1330 template <typename CHAR_T>
1331 inline
void String::Append (span<const CHAR_T> s)
1332 requires (same_as<CHAR_T, Character> or same_as<CHAR_T,
char32_t>)
1334 if (not s.empty ()) {
1335 Memory::StackBuffer<char32_t> ignored1;
1336 span<const char32_t> thisSpan = this->GetData (&ignored1);
1337 Memory::StackBuffer<char32_t> combinedBuf{Memory::eUninitialized, thisSpan.size () + s.size ()};
1338 Memory::CopySpanData (thisSpan, span{combinedBuf});
1339 char32_t* write2Buf = combinedBuf.data () + thisSpan.size ();
1341 if constexpr (same_as<CHAR_T, Character>) {
1342 *write2Buf = i.template As<char32_t> ();
1349 *
this = mk_ (span{combinedBuf});
1352 inline void String::Append (
const wchar_t* from,
const wchar_t* to)
1354 Require (from <= to);
1356 Memory::StackBuffer<wchar_t> ignored1;
1357 span<const wchar_t> thisSpan = this->GetData (&ignored1);
1358 Memory::StackBuffer<wchar_t> buf{Memory::eUninitialized, thisSpan.size () + (to - from)};
1359 span<wchar_t> bufSpan{buf};
1360 Memory::CopySpanData (thisSpan, bufSpan);
1361 Memory::CopySpanData (span{from, to}, bufSpan.subspan (thisSpan.size ()));
1362 *
this = mk_ (bufSpan);
1365 inline void String::Append (Character c)
1369 inline void String::Append (
const String& s)
1371 Memory::StackBuffer<char32_t> ignored1;
1372 auto rhsSpan = s.GetData (&ignored1);
1375 inline void String::Append (
const wchar_t* s)
1377 Append (s, s + ::wcslen (s));
1379 inline void String::Append (
const Character* from,
const Character* to)
1383 inline String& String::operator+= (Character appendage)
1388 inline String& String::operator+= (
const String& appendage)
1393 inline String& String::operator+= (
const wchar_t* appendageCStr)
1399 inline void String::push_back (
wchar_t c)
1403 inline void String::push_back (Character c)
1408 DISABLE_COMPILER_MSC_WARNING_END (4996)
1409 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1410 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
1412 [[deprecated ("Since Stroika v3.0d1 - just use _k, sv, or nothing")]] inline String operator"" _ASCII (const
char* str,
size_t len)
1414 return String{span{str, len}};
1416 class [[deprecated (
"Since Stroika v3.0 - just use String::FromStringConstant")]] String_Constant :
public String {
1418 template <
size_t SIZE>
1419 explicit String_Constant (
const wchar_t (&cString)[SIZE])
1420 : String{String::FromStringConstant (
std::basic_string_view<wchar_t>{cString, SIZE - 1})}
1424 String_Constant (
const wchar_t* start,
const wchar_t* end)
1425 : String{String::FromStringConstant (
std::basic_string_view<wchar_t>{start,
static_cast<size_t> (end - start)})}
1429 String_Constant (
const std::basic_string_view<wchar_t>& str)
1435namespace Stroika::Foundation::Characters::Concrete {
1436 class [[deprecated (
"Since Stroika v3.0 - just use String::FromStringConstant")]] String_ExternalMemoryOwnership_ApplicationLifetime :
public String {
1438 template <
size_t SIZE>
1439 explicit String_ExternalMemoryOwnership_ApplicationLifetime (
const wchar_t (&cString)[SIZE - 1])
1440 : String{String::FromStringConstant (basic_string_view<wchar_t>{cString, SIZE})}
1444 String_ExternalMemoryOwnership_ApplicationLifetime (
const wchar_t* start,
const wchar_t* end)
1445 : String{String::FromStringConstant (basic_string_view<wchar_t>{start,
static_cast<size_t> (end - start)})}
1449 String_ExternalMemoryOwnership_ApplicationLifetime (
const basic_string_view<wchar_t>& str)
1459 String StringCombiner<String>::operator() (
const String& lhs,
const String& rhs,
bool isLast)
const;
1461 template <
typename STRING>
1462 STRING StringCombiner<STRING>::operator() (
const STRING& lhs,
const STRING& rhs,
bool isLast)
const
1465 if (isLast and fSpecialSeparatorForLastPair) [[unlikely]] {
1466 sb = sb + *fSpecialSeparatorForLastPair;
1469 sb = sb + fSeparator;
#define AssertNotImplemented()
#define RequireNotReached()
#define RequireNotNull(p)
#define RequireExpression(c)
#define AssertNotReached()
#define EnsureMember(p, c)
void Append(TARGET_CONTAINER *v)
constexpr bool IsASCII() const noexcept
Return true iff the given character (or all in span) is (are) in the ascii range [0....
static void CheckLatin1(span< const CHAR_T > s)
if not IsLatin1 (arg) throw RuntimeException...
static constexpr void CheckASCII(span< const CHAR_T > s)
if not IsASCII (arg) throw RuntimeException...
static constexpr ASCIIOrLatin1Result IsASCIIOrLatin1(span< const CHAR_T > s) noexcept
static constexpr strong_ordering Compare(span< const CHAR_T, E1 > lhs, span< const CHAR_T, E2 > rhs, CompareOptions co) noexcept
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual bool Contains(Character c, CompareOptions co=eWithCase) const
nonvirtual T AsUTF8() const
nonvirtual size_t length() const noexcept
static String FromNarrowString(const char *from, const locale &l)
nonvirtual bool Matches(const RegularExpression ®Ex) const
static String FromStringConstant(const CHAR_T(&cString)[SIZE])
Take the given argument data (constant span) - which must remain unchanged - constant - for the appli...
nonvirtual String ColValue(size_t i, const String &valueIfMissing={}) const
see Col(i) - but with default value of empty string
nonvirtual bool operator==(const String &rhs) const
static String FromSDKString(const SDKChar *from)
nonvirtual String LimitLength(size_t maxLen, StringShorteningPreference keepPref=StringShorteningPreference::ePreferKeepLeft) const
return the first maxLen (or fewer if string shorter) characters of this string (adding ellipsis if tr...
nonvirtual T AsUTF32() const
nonvirtual string AsNarrowSDKString() const
nonvirtual optional< String > Col(size_t i) const
Useful to replace 'awk print $3' - replace with Col(2) - zero based.
nonvirtual String InsertAt(Character c, size_t at) const
nonvirtual size_t rfind(Character c) const
static String FromNarrowSDKString(const char *from)
nonvirtual string AsNarrowString(const locale &l) const
nonvirtual String Concatenate(T &&rhs) const
appends 'rhs' string to this string (without modifying this string) and returns the combined string
nonvirtual SDKString AsSDKString() const
nonvirtual size_t size() const noexcept
static constexpr size_t npos
nonvirtual String Replace(size_t from, size_t to, const String &replacement) const
nonvirtual String SubString(SZ from) const
nonvirtual strong_ordering operator<=>(const String &rhs) const
nonvirtual Character back() const
nonvirtual T AsASCII() const
nonvirtual span< CHAR_T > CopyTo(span< CHAR_T > s) const
nonvirtual T AsUTF16() const
nonvirtual PeekSpanData GetPeekSpanData() const
return the constant character data inside the string in the form of a case variant union of different...
nonvirtual String SafeSubString(SZ from) const
nonvirtual Character front() const
nonvirtual optional< size_t > RFind(Character c) const noexcept
static span< const CHAR_TYPE > GetData(const PeekSpanData &pds, Memory::StackBuffer< CHAR_TYPE, STACK_BUFFER_SZ > *possiblyUsedBuffer)
return the constant character data inside the string (rep) in the form of a span, possibly quickly an...
nonvirtual String RemoveAt(size_t charAt) const
nonvirtual optional< T > AsASCIIQuietly() const
static String FromLatin1(const CHAR_T *cString)
nonvirtual const Character operator[](size_t i) const noexcept
return (read-only) Character object
static String FromUTF8(span< CHAR_T > from)
nonvirtual optional< size_t > Find(Character c, CompareOptions co=eWithCase) const
nonvirtual String substr(size_t from, size_t count=npos) const
nonvirtual size_t find(Character c, size_t startAt=0) const
static const UTFConvert kThe
Nearly always use this default UTFConvert.
static constexpr bool AllFitsInTwoByteEncoding(span< const CHAR_T > s) noexcept
nonvirtual span< TRG_T > ConvertSpan(span< const SRC_T > source, span< TRG_T > target) const
Convert between UTF-N encoded (including the special case of ASCII, and Latin1) character spans (e....
static constexpr size_t ComputeTargetBufferSize(span< const FROM > src)
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual size_t size() const noexcept
nonvirtual void resize_uninitialized(size_t nElements)
same as resize (), except leaves newly created elements uninitialized (requires is_trivially_copyable...
nonvirtual size_t size() const
Returns the number of items contained.
An Iterator<T> is a copyable object which allows traversing the contents of some container....
returns true iff T == u8string, u16string, u32string, or wstring - which std::string types can be una...
wstring NarrowSDK2Wide(span< const char > s)
wstring SDK2Wide(span< const SDKChar > s)
char ASCII
Stroika's string/character classes treat 'char' as being an ASCII character.
conditional_t< qTargetPlatformSDKUseswchar_t, wchar_t, char > SDKChar
StringShorteningPreference
basic_string< SDKChar > SDKString
String operator+(LHS_T &&lhs, RHS_T &&rhs)
const function< String(String, String, bool)> kDefaultStringCombiner
AllowMissingCharacterErrorsFlag
string SDK2Narrow(span< const SDKChar > s)
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
constexpr EqualsComparer(CompareOptions co=eWithCase)
nonvirtual bool operator()(LT &&lhs, RT &&rhs) const
Summary data for raw contents of rep - each rep will support at least one of these span forms.
StringCombiner is a simple function object used to combine two strings visually - used in Iterable<>:...