4#include "Stroika/Foundation/StroikaPreComp.h"
15#include "Stroika/Foundation/Characters/SDKString.h"
19#include "Stroika/Foundation/Containers/Set.h"
20#include "Stroika/Foundation/Containers/Support/ReserveTweaks.h"
23#include "Stroika/Foundation/Execution/Exceptions.h"
24#include "Stroika/Foundation/Execution/Throw.h"
25#include "Stroika/Foundation/Math/Common.h"
27#include "Stroika/Foundation/Memory/Common.h"
41static_assert (regular<String>);
43#if qStroika_Foundation_Characters_AsPathAutoMapMSYSAndCygwin
64 struct StringRepHelperAllFitInSize_ :
String {
65 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
66 struct Rep :
public _IRep {
68 using inherited = _IRep;
71 span<const CHAR_T> _fData;
73#if qStroika_Foundation_Debug_AssertionsChecked
75 mutable unsigned int fOutstandingIterators_{};
80 Rep (span<const CHAR_T> s)
81 requires (not same_as<CHAR_T, char8_t>)
84 if constexpr (same_as<CHAR_T, char> or same_as<CHAR_T, char8_t>) {
85 Require (Character::IsASCII (s));
88 if constexpr (same_as<CHAR_T, char16_t>) {
92 Rep& operator= (span<const CHAR_T> s)
94#if qStroika_Foundation_Debug_AssertionsChecked
95 Require (fOutstandingIterators_ == 0);
97 if constexpr (same_as<CHAR_T, char> or same_as<CHAR_T, char8_t>) {
98 Require (Character::IsASCII (s));
100 if constexpr (same_as<CHAR_T, char16_t>) {
109 virtual Character GetAt (
size_t index)
const noexcept override
111 Require (index < _fData.size ());
113 return Character{
static_cast<char32_t> (_fData[index])};
115 virtual PeekSpanData PeekData (optional<PeekSpanData::StorageCodePointType> )
const noexcept override
118 if constexpr (same_as<CHAR_T, ASCII>) {
119 return PeekSpanData{PeekSpanData::StorageCodePointType::eAscii, {.fAscii = _fData}};
121 if constexpr (same_as<CHAR_T, Latin1>) {
122 return PeekSpanData{PeekSpanData::StorageCodePointType::eSingleByteLatin1, {.fSingleByteLatin1 = _fData}};
124 else if constexpr (
sizeof (CHAR_T) == 2) {
126 return PeekSpanData{PeekSpanData::StorageCodePointType::eChar16,
127 {.fChar16 = span<const char16_t>{
reinterpret_cast<const char16_t*
> (_fData.data ()), _fData.size ()}}};
129 else if constexpr (
sizeof (CHAR_T) == 4) {
131 return PeekSpanData{PeekSpanData::StorageCodePointType::eChar32,
132 {.fChar32 = span<const char32_t>{
reinterpret_cast<const char32_t*
> (_fData.data ()), _fData.size ()}}};
139 virtual shared_ptr<Iterable<Character>::_IRep> Clone ()
const override
148 span<const CHAR_T> fData_;
150#if qStroika_Foundation_Debug_AssertionsChecked
151 const Rep* fOwningRep_;
153 MyIterRep_ (span<const CHAR_T> data
161 , fOwningRep_{dbgRep}
164#if qStroika_Foundation_Debug_AssertionsChecked
165 ++fOwningRep_->fOutstandingIterators_;
168#if qStroika_Foundation_Debug_AssertionsChecked
169 virtual ~MyIterRep_ ()
override
171 Require (fOwningRep_->fOutstandingIterators_ > 0);
172 --fOwningRep_->fOutstandingIterators_;
176 virtual unique_ptr<Iterator<Character>::IRep> Clone ()
const override
178 return make_unique<MyIterRep_> (fData_.subspan (fIdx_)
185 virtual void More (optional<Character>* result,
bool advance)
override
188 if (advance) [[likely]] {
189 Require (fIdx_ < fData_.size ());
192 if (fIdx_ < fData_.size ()) [[likely]] {
194 *result =
Character{
static_cast<char32_t> (fData_[fIdx_])};
200 virtual bool Equals (
const IRep* rhs)
const override
204 const MyIterRep_* rrhs = Debug::UncheckedDynamicCast<const MyIterRep_*> (rhs);
205 return fData_.data () == rrhs->fData_.data () and fIdx_ == rrhs->fIdx_;
217 virtual size_t size ()
const override
219 return _fData.size ();
221 virtual bool empty ()
const override
223 return _fData.empty ();
228 return inherited::Find (that, seq);
237 struct DynamicallyAllocatedString : StringRepHelperAllFitInSize_ {
238 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
241 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
244 Rep (span<const CHAR_T> t1)
245 : inherited{mkBuf_ (t1)}
249 Rep (
const Rep&) =
delete;
252 nonvirtual Rep& operator= (
const Rep&) =
delete;
255 virtual ~Rep ()
override
257 delete[] this->_fData.data ();
261 static span<CHAR_T> mkBuf_ (
size_t length)
263 size_t capacity = AdjustCapacity_ (length);
264 Assert (length <= capacity);
265 if constexpr (kAddNullTerminator_) {
266 Assert (length + 1 <= capacity);
268 CHAR_T* newBuf =
new CHAR_T[capacity];
269 return span{newBuf, capacity};
271 static span<CHAR_T> mkBuf_ (span<const CHAR_T> t1)
273 size_t len = t1.size ();
274 span<CHAR_T> buf = mkBuf_ (len);
275 Assert (buf.size () >= len);
276 auto result = Memory::CopyBytes (t1, buf);
277 if constexpr (kAddNullTerminator_) {
278 Assert (len + 1 <= buf.size ());
279 *(buf.data () + len) =
'\0';
286 virtual const wchar_t* c_str_peek () const noexcept
override
289 if constexpr (kAddNullTerminator_) {
290 Assert (*(this->_fData.data () + this->_fData.size ()) ==
'\0');
291 return reinterpret_cast<const wchar_t*
> (this->_fData.data ());
300 static constexpr bool kAddNullTerminator_ =
sizeof (CHAR_T) ==
sizeof (
wchar_t);
303 static size_t AdjustCapacity_ (
size_t initialCapacity)
305 size_t result = initialCapacity;
306 if constexpr (kAddNullTerminator_) {
320 struct FixedCapacityInlineStorageString_ : StringRepHelperAllFitInSize_ {
321 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T,
size_t CAPACITY>
322 struct Rep final :
public StringRepHelperAllFitInSize_::Rep<CHAR_T>,
325 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
328 bool IncludesNullTerminator_ ()
const
330 if constexpr (
sizeof (CHAR_T) ==
sizeof (
wchar_t)) {
331 return this->_fData.size () < CAPACITY;
339 CHAR_T fBuf_[CAPACITY];
342 Rep (span<const CHAR_T> t1)
348 Require (t1.size () <= CAPACITY);
349 inherited::operator= (Memory::CopyBytes (t1, span<CHAR_T>{fBuf_}));
350 if (IncludesNullTerminator_ ()) {
351 Assert (t1.size () + 1 <= CAPACITY);
352 fBuf_[t1.size ()] = CHAR_T{
'\0'};
356 Rep (
const Rep&) =
delete;
359 nonvirtual Rep& operator= (
const Rep&) =
delete;
363 virtual const wchar_t* c_str_peek () const noexcept
override
365 if (IncludesNullTerminator_ ()) {
366 Assert (*(this->_fData.data () + this->_fData.size ()) ==
'\0');
367 return reinterpret_cast<const wchar_t*
> (this->_fData.data ());
379 struct StringConstant_ :
public StringRepHelperAllFitInSize_ {
382 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
383 class DirectIndexRep final :
public StringRepHelperAllFitInSize_::Rep<CHAR_T>,
386 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
389 DirectIndexRep (span<const CHAR_T> s)
396 virtual const wchar_t* c_str_peek () const noexcept
override
406 struct StdStringDelegator_ :
public StringRepHelperAllFitInSize_ {
409 template <IStdBasicStringCompatibleCharacter CHAR_T>
412 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
415 Rep (basic_string<CHAR_T>&& s)
416 : inherited{span<const CHAR_T>{}}
417 , fMovedData_{move (s)}
419 inherited::operator= (span{fMovedData_.data (), fMovedData_.size ()});
424 virtual const wchar_t* c_str_peek () const noexcept
override
426 if constexpr (same_as<CHAR_T, wchar_t>) {
427 return fMovedData_.c_str ();
435 basic_string<CHAR_T> fMovedData_;
442 struct StringWithCStr_ :
public String {
446 shared_ptr<_IRep> fUnderlyingRep_;
451 Rep (
const shared_ptr<_IRep>& underlyingRep)
452 : fUnderlyingRep_{underlyingRep}
456 auto wideSpan = String::GetData<wchar_t> (underlyingRep->PeekData (nullopt), &possibleUsedBuf);
457 fCString_.assign (wideSpan.begin (), wideSpan.end ());
462 virtual shared_ptr<Iterable<Character>::_IRep> Clone ()
const override
464 return fUnderlyingRep_->Clone ();
468 return fUnderlyingRep_->MakeIterator ();
470 virtual size_t size ()
const override
472 return fUnderlyingRep_->size ();
474 virtual bool empty ()
const override
476 return fUnderlyingRep_->empty ();
481 return fUnderlyingRep_->Find (that, seq);
486 virtual Character GetAt (
size_t index)
const noexcept override
488 return fUnderlyingRep_->GetAt (index);
490 virtual PeekSpanData PeekData ([[maybe_unused]] optional<PeekSpanData::StorageCodePointType> preferred)
const noexcept override
492 return fUnderlyingRep_->PeekData (preferred);
494 virtual const wchar_t* c_str_peek () const noexcept
override
496 return fCString_.c_str ();
503 template <
typename FACET>
504 struct deletable_facet_ final : FACET {
505 template <
typename... Args>
506 deletable_facet_ (Args&&... args)
507 : FACET{forward<Args> (args)...}
510 ~deletable_facet_ () =
default;
519const wregex& Characters::Private_::RegularExpression_GetCompiled (
const RegularExpression& regExp)
521 return regExp.GetCompiled ();
529shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<ASCII>& str)
532 return Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<ASCII>> (span{str.data (), str.size ()});
535shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char8_t>& str)
538 return Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<ASCII>> (Memory::SpanBytesCast<span<const ASCII>> (span{str.data (), str.size ()}));
541 return mk_ (span<const char8_t>{str.data (), str.size ()});
545shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char16_t>& str)
548 return Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<char16_t>> (span{str.data (), str.size ()});
551 return mk_ (span<const char16_t>{str.data (), str.size ()});
555shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char32_t>& str)
557 return Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<char32_t>> (span{str.data (), str.size ()});
560shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<wchar_t>& str)
562 return Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<wchar_t>> (span{str.data (), str.size ()});
568 return String{Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<ASCII>> (s)};
574 return String{Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<char16_t>> (s)};
583 return String{Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<char32_t>> (s)};
592 using Destructible_codecvt_byname = deletable_facet_<codecvt_byname<wchar_t, char, mbstate_t>>;
593 Destructible_codecvt_byname cvt{l.name ()};
598 const char* from_next;
600 codecvt_base::result result =
601 cvt.in (mbstate, s.data (), s.data () + s.size (), from_next, targetBuf.data (), targetBuf.data () + targetBuf.size (), to_next);
602 if (result != codecvt_base::ok) [[unlikely]] {
606 return String{span<const wchar_t>{targetBuf.data (),
static_cast<size_t> (to_next - targetBuf.data ())}};
609shared_ptr<String::_IRep> String::mkEmpty_ ()
611 static constexpr wchar_t kEmptyCStr_[] = L
"";
612 static const shared_ptr<_IRep> s_ = Memory::MakeSharedPtr<StringConstant_::DirectIndexRep<wchar_t>> (span{std::begin (kEmptyCStr_), 0});
616template <
typename CHAR_T>
617inline auto String::mk_nocheck_ (span<const CHAR_T> s) -> shared_ptr<_IRep>
618 requires (same_as<CHAR_T, ASCII> or same_as<CHAR_T, Latin1> or same_as<CHAR_T, char16_t> or same_as<CHAR_T, char32_t>)
621 if constexpr (same_as<CHAR_T, ASCII>) {
624 else if constexpr (same_as<CHAR_T, Latin1>) {
627 else if constexpr (
sizeof (CHAR_T) == 2) {
642 constexpr size_t kBaseOfFixedBufSize_ =
sizeof (StringRepHelperAllFitInSize_::Rep<CHAR_T>);
643 static_assert (kBaseOfFixedBufSize_ < 64);
645 static_assert (kBaseOfFixedBufSize_ == 3 *
sizeof (
void*));
646 if constexpr (
sizeof (
void*) == 4) {
647 static_assert (kBaseOfFixedBufSize_ == 12);
649 else if constexpr (
sizeof (
void*) == 8) {
650 static_assert (kBaseOfFixedBufSize_ == 24);
653 constexpr size_t kOverheadSizeForMakeShared_ =
654 qStroika_Foundation_Common_Platform_Windows ? (
sizeof (
void*) == 4 ? 12 : 16) :
sizeof (
unsigned long) * 2;
655#if qStroika_Foundation_Common_Platform_Windows
656 static_assert (kOverheadSizeForMakeShared_ ==
sizeof (_Ref_count_base));
658 static constexpr size_t kNElts1_ = (64 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
659 static constexpr size_t kNElts2_ = (96 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
660 static constexpr size_t kNElts3_ = (128 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
664 if constexpr (
sizeof (
void*) == 4) {
665 static_assert (kNElts1_ == 40);
666 static_assert (kNElts2_ == 72);
667 static_assert (kNElts3_ == 104);
669 if constexpr (
sizeof (
void*) == 8) {
670 static_assert (kNElts1_ == 24);
671 static_assert (kNElts2_ == 56);
672 static_assert (kNElts3_ == 88);
677 static_assert (kNElts2_ > kNElts1_);
678 static_assert (kNElts3_ > kNElts2_);
680 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts1_>) == 64 - kOverheadSizeForMakeShared_);
681 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts2_>) == 96 - kOverheadSizeForMakeShared_);
682 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts3_>) == 128 - kOverheadSizeForMakeShared_);
684 size_t sz = s.size ();
685 if (sz <= kNElts1_) {
686 return Memory::MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts1_>> (s);
688 else if (sz <= kNElts2_) {
689 return Memory::MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts2_>> (s);
691 else if (sz <= kNElts3_) {
692 return Memory::MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts3_>> (s);
694 return Memory::MakeSharedPtr<DynamicallyAllocatedString::Rep<CHAR_T>> (s);
698auto String::mk_ (basic_string<char>&& s) -> shared_ptr<_IRep>
701 return Memory::MakeSharedPtr<StdStringDelegator_::Rep<ASCII>> (move (s));
705auto String::mk_ (basic_string<char16_t>&& s) -> shared_ptr<_IRep>
708 return Memory::MakeSharedPtr<StdStringDelegator_::Rep<char16_t>> (move (s));
711 Memory::StackBuffer<char32_t> wideUnicodeBuf{Memory::eUninitialized, UTFConvert::ComputeTargetBufferSize<char32_t> (span{s.data (), s.size ()})};
712 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (span{s.data (), s.size ()}, span{wideUnicodeBuf})));
716auto String::mk_ (basic_string<char32_t>&& s) -> shared_ptr<_IRep>
718 return Memory::MakeSharedPtr<StdStringDelegator_::Rep<char32_t>> (move (s));
722auto String::mk_ (basic_string<wchar_t>&& s) -> shared_ptr<_IRep>
724 if constexpr (
sizeof (wchar_t) == 2) {
726 return Memory::MakeSharedPtr<StdStringDelegator_::Rep<wchar_t>> (move (s));
730 UTFConvert::ComputeTargetBufferSize<char32_t> (span{s.data (), s.size ()})};
731 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (span{s.data (), s.size ()}, span{wideUnicodeBuf})));
734 return Memory::MakeSharedPtr<StdStringDelegator_::Rep<wchar_t>> (move (s));
742 span leftSpan =
GetData (&ignoredA);
744 span rightSpan = rhs.
GetData (&ignoredB);
746 copy (leftSpan.begin (), leftSpan.end (), buf.data ());
747 copy (rightSpan.begin (), rightSpan.end (), buf.data () + leftSpan.size ());
748 return mk_ (span{buf});
751void String::SetCharAt (
Character c,
size_t i)
756 Require (i <
size ());
759 Require (i <
size ());
767 Require (at <=
size ());
772 span<const Character> thisStrData =
GetData (&ignored1);
775 sb.Append (thisStrData.subspan (at));
781 Require (from <= to);
782 Require (to <=
size ());
789 _SafeReadRepAccessor accessor{
this};
790 size_t length = accessor._ConstGetRep ().
size ();
798 span<char32_t> bufSpan{buf.data (), buf.size ()};
799 span s1 = d.subspan (0, from);
800 span s2 = d.subspan (to);
801 Memory::CopyBytes (s1, bufSpan);
802 Memory::CopyBytes (s2, bufSpan.subspan (s1.size ()));
803 return String{mk_ (bufSpan)};
810 if (
auto o = tmp.
Find (c, eWithCase)) {
817 if (
auto o = this->
Find (subString, eWithCase)) {
828 while (
auto o = tmp.
Find (c, eWithCase)) {
838 while (
auto o = tmp.
Find (subString, eWithCase)) {
846 PeekSpanData pds = GetPeekSpanData<ASCII> ();
850 span<const char> examineSpan = pds.fAscii.subspan (startAt);
851 if (co == eWithCase) {
852 if (
auto i = std::find (examineSpan.begin (), examineSpan.end (), c.
GetAsciiCode ()); i != examineSpan.end ()) {
853 return i - examineSpan.begin () + startAt;
858 size_t reportIdx = startAt;
859 for (
auto ci : examineSpan) {
860 if (tolower (ci) == lc) {
878 span<const Character> charSpan =
GetData (pds, &maybeIgnoreBuf);
879 Require (startAt <= charSpan.size ());
880 span<const Character> examineSpan = charSpan.subspan (startAt);
882 case eCaseInsensitive: {
884 for (
auto i = examineSpan.begin (); i != examineSpan.end (); ++i) {
885 if (i->ToLowerCase () == lcc) {
886 return startAt + (i - examineSpan.begin ());
891 if (
auto i = std::find (examineSpan.begin (), examineSpan.end (), c); i != examineSpan.end ()) {
892 return startAt + i - examineSpan.begin ();
899optional<size_t>
String::Find (
const String& subString,
size_t startAt, CompareOptions co)
const
902 _SafeReadRepAccessor accessor{
this};
903 Require (startAt <= accessor._ConstGetRep ().size ());
905 size_t subStrLen = subString.
size ();
906 if (subStrLen == 0) {
907 return (accessor._ConstGetRep ().size () == 0) ? optional<size_t>{} : 0;
909 if (accessor._ConstGetRep ().size () < subStrLen) {
913 size_t limit = accessor._ConstGetRep ().size () - subStrLen;
915 case eCaseInsensitive: {
916 for (
size_t i = startAt; i <= limit; ++i) {
917 for (
size_t j = 0; j < subStrLen; ++j) {
918 if (accessor._ConstGetRep ().GetAt (i + j).ToLowerCase () != subString[j].ToLowerCase ()) {
927 for (
size_t i = startAt; i <= limit; ++i) {
928 for (
size_t j = 0; j < subStrLen; ++j) {
929 if (accessor._ConstGetRep ().GetAt (i + j) != subString[j]) {
943 Require (startAt <=
size ());
944 wstring tmp = As<wstring> ();
945 Require (startAt < tmp.size ());
946 tmp = tmp.substr (startAt);
948 regex_search (tmp, res, regEx.GetCompiled ());
949 if (res.size () >= 1) {
950 size_t startOfMatch = startAt + res.position ();
951 return pair<size_t, size_t>{startOfMatch, startOfMatch + res.length ()};
958 vector<size_t> result;
959 for (optional<size_t> i =
Find (string2SearchFor, 0, co); i; i =
Find (string2SearchFor, *i, co)) {
961 *i += string2SearchFor.
length ();
968 vector<pair<size_t, size_t>> result;
970 wstring tmp{As<wstring> ()};
972 regex_search (tmp, res, regEx.GetCompiled ());
973 size_t nMatches = res.size ();
974 result.reserve (nMatches);
975 for (
size_t mi = 0; mi < nMatches; ++mi) {
976 size_t matchLen = res.length (mi);
978 result.push_back (pair<size_t, size_t>{res.position (mi), matchLen});
986 vector<RegularExpressionMatch> result;
987 wstring tmp{As<wstring> ()};
988 for (wsregex_iterator i = wsregex_iterator{tmp.begin (), tmp.end (), regEx.GetCompiled ()}; i != wsregex_iterator (); ++i) {
990 Assert (match.size () != 0);
991 size_t n = match.size ();
993 for (
size_t j = 1; j < n; ++j) {
1003 vector<String> result;
1004 wstring tmp{As<wstring> ()};
1005 for (wsregex_iterator i = wsregex_iterator{tmp.begin (), tmp.end (), regEx.GetCompiled ()}; i != wsregex_iterator (); ++i) {
1014 _SafeReadRepAccessor accessor{
this};
1015 const _IRep& useRep = accessor._ConstGetRep ();
1016 size_t length = useRep.size ();
1017 for (
size_t i = length; i > 0; --i) {
1018 if (useRep.
GetAt (i - 1) == c) {
1031 size_t subStrLen = subString.
size ();
1032 if (subStrLen == 0) {
1033 return ((
size () == 0) ? optional<size_t>{} :
size () - 1);
1036 size_t limit =
size () - subStrLen + 1;
1037 for (
size_t i = limit; i > 0; --i) {
1038 if (
SubString (i - 1, i - 1 + subStrLen) == subString) {
1048 span<const wchar_t> thisSpan =
GetData (&ignored);
1049 Require (from <= to);
1050 Require (to <= this->
size ());
1051 Assert (to < thisSpan.size ());
1054 sb.Append (thisSpan.subspan (to));
1061 _SafeReadRepAccessor accessor{
this};
1062 if (accessor._ConstGetRep ().size () == 0) {
1070 Require (not subString.empty ());
1074#if qStroika_Foundation_Debug_AssertionsChecked
1075 bool referenceResult = ThreeWayComparer{co}(
SubString (0, subString.
size ()), subString) == 0;
1079 span<const Character> subStrData = subString.
GetData (&maybeIgnoreBuf1);
1080 span<const Character> thisData =
GetData (&maybeIgnoreBuf2);
1081 bool result =
Character::Compare (thisData.subspan (0, subStrData.size ()), subStrData, co) == 0;
1082#if qStroika_Foundation_Debug_AssertionsChecked
1083 Ensure (result == referenceResult);
1090 _SafeReadRepAccessor accessor{
this};
1091 const _IRep& useRep = accessor._ConstGetRep ();
1092 size_t thisStrLen = useRep.size ();
1093 if (thisStrLen == 0) {
1101 Require (not subString.empty ());
1102 _SafeReadRepAccessor subStrAccessor{&subString};
1103 _SafeReadRepAccessor accessor{
this};
1104 size_t thisStrLen = accessor._ConstGetRep ().
size ();
1105 size_t subStrLen = subString.
size ();
1106 if (subStrLen > thisStrLen) {
1109#if qStroika_Foundation_Debug_AssertionsChecked
1114 span<const Character> subStrData = subString.
GetData (&maybeIgnoreBuf1);
1115 span<const Character> thisData =
GetData (&maybeIgnoreBuf2);
1116 bool result =
Character::Compare (thisData.subspan (thisStrLen - subStrLen), subStrData, co) == 0;
1117#if qStroika_Foundation_Debug_AssertionsChecked
1118 Ensure (result == referenceResult);
1135 wstring tmp{As<wstring> ()};
1136 return regex_match (tmp.begin (), tmp.end (), regEx.GetCompiled ());
1143 wstring tmp{As<wstring> ()};
1145 if (regex_match (tmp, base_match, regEx.GetCompiled ())) {
1147 for (
size_t i = 1; i < base_match.size (); ++i) {
1148 matches->
Append (base_match[i].str ());
1157 return String{regex_replace (As<wstring> (), regEx.GetCompiled (), with.
As<wstring> ())};
1162 Require (not string2SearchFor.empty ());
1165 optional<size_t> i{0};
1166 while ((i = result.Find (string2SearchFor, *i, co))) {
1177 if (replaceCharP (i)) {
1191 if (charSet.Contains (i)) {
1205 span<const Character> charSpan =
GetData (pds, &maybeIgnoreBuf);
1207 bool everChanged{
false};
1208 for (
auto ci = charSpan.begin (); ci != charSpan.end (); ++ci) {
1213 if (ci + 1 != charSpan.end () and *(ci + 1) ==
'\n') {
1241 bool inToken =
false;
1243 size_t len =
size ();
1244 for (
size_t i = 0; i != len; ++i) {
1246 bool newInToken = not isTokenSeparator (c);
1247 if (inToken != newInToken) {
1272 size_t len = this->
length ();
1273 for (
size_t startAt = 0; startAt < len;) {
1274 if (optional<pair<size_t, size_t>> ofi =
Find (isSeparator, startAt)) {
1275 Assert (ofi->first >= startAt);
1276 Assert (ofi->first <= ofi->second);
1277 if (ofi->first == ofi->second) [[unlikely]] {
1278 static const auto kException_ =
1282 if (ofi->first > startAt) {
1286 Assert (startAt == 0);
1288 startAt = ofi->second;
1289 Assert (startAt <= len);
1303 return Tokenize ([delimiters] (
Character c) ->
bool {
return delimiters.Contains (c); });
1317 if (ii and *ii ==
'\n') {
1320 r += curLineSB.
str ();
1325 r += curLineSB.
str ();
1330 curLineSB.push_back (c);
1335 if (not curLineSB.
empty ()) {
1336 r += curLineSB.
str ();
1345 if (i.Contains (fgrepArg)) {
1355 if (i.Matches (egrepArg)) {
1365 return Col (i, kWS_);
1370 return Tokenize (separator).Nth (i);
1373String String::SubString_ (
const _SafeReadRepAccessor& thisAccessor,
size_t from,
size_t to)
const
1375 constexpr bool kWholeStringOptionization_ =
1377 Require (from <= to);
1378 Require (to <= this->
size ());
1381 if (from == to) [[unlikely]] {
1384 PeekSpanData psd = thisAccessor._ConstGetRep ().PeekData (nullopt);
1385 switch (psd.fInCP) {
1387 if constexpr (kWholeStringOptionization_) {
1388 if (from == 0 and to == psd.fAscii.size ()) [[unlikely]] {
1392 return mk_nocheck_ (psd.fAscii.subspan (from, to - from));
1395 if constexpr (kWholeStringOptionization_) {
1396 if (from == 0 and to == psd.fSingleByteLatin1.size ()) [[unlikely]] {
1400 return mk_ (psd.fSingleByteLatin1.subspan (from, to - from));
1402 case PeekSpanData::eChar16: {
1403 if constexpr (kWholeStringOptionization_) {
1404 if (from == 0 and to == psd.fChar16.size ()) [[unlikely]] {
1408 return mk_ (psd.fChar16.subspan (from, to - from));
1410 case PeekSpanData::eChar32: {
1411 if constexpr (kWholeStringOptionization_) {
1412 if (from == 0 and to == psd.fChar32.size ()) [[unlikely]] {
1416 return mk_ (psd.fChar32.subspan (from, to - from));
1432 return *
this + *
this;
1435 for (
unsigned int i = 0; i < count; ++i) {
1446 auto referenceImpl = [&] () {
1447 _SafeReadRepAccessor accessor{
this};
1448 size_t length = accessor._ConstGetRep ().size ();
1449 for (
size_t i = 0; i <
length; ++i) {
1450 if (not(*shouldBeTrimmed) (accessor._ConstGetRep ().GetAt (i))) {
1461 auto commonAlgorithm = [&]<
typename T> (span<const T> lowLevelCharSpan) ->
String {
1463 for (
size_t i = 0; i <
length; ++i) {
1467 bool thisCharacterTrimmed = [&] () {
1472 return shouldBeTrimmed (c);
1475 if (not thisCharacterTrimmed) {
1477#if qStroika_Foundation_Debug_AssertionsChecked
1478 Assert (*
this == referenceImpl ());
1483#if qStroika_Foundation_Debug_AssertionsChecked
1484 Assert (mk_ (lowLevelCharSpan.subspan (i)) == referenceImpl ());
1486 return mk_ (lowLevelCharSpan.subspan (i));
1492 _SafeReadRepAccessor accessor{
this};
1493 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1494 switch (psd.fInCP) {
1496 return commonAlgorithm (psd.fAscii);
1499 return commonAlgorithm (psd.fSingleByteLatin1);
1501 case PeekSpanData::eChar32: {
1502 return commonAlgorithm (psd.fChar32);
1505 return referenceImpl ();
1511 auto referenceImpl = [&] () {
1512 _SafeReadRepAccessor accessor{
this};
1513 ptrdiff_t
length = accessor._ConstGetRep ().size ();
1514 ptrdiff_t endOfFirstTrim =
length;
1515 for (; endOfFirstTrim != 0; --endOfFirstTrim) {
1516 if ((*shouldBeTrimmed) (accessor._ConstGetRep ().GetAt (endOfFirstTrim - 1))) {
1523 if (endOfFirstTrim == 0) {
1526 else if (endOfFirstTrim ==
length) {
1534 auto commonAlgorithm = [&]<
typename T> (span<const T> lowLevelCharSpan) ->
String {
1536 ptrdiff_t endOfFirstTrim =
length;
1537 for (; endOfFirstTrim != 0; --endOfFirstTrim) {
1539 Character c{lowLevelCharSpan[endOfFirstTrim - 1]};
1541 bool thisCharacterTrimmed = [&] () {
1546 return shouldBeTrimmed (c);
1549 if (thisCharacterTrimmed) {
1556 if (endOfFirstTrim == 0) {
1557#if qStroika_Foundation_Debug_AssertionsChecked
1558 Assert (
String{} == referenceImpl ());
1562 else if (
static_cast<size_t> (endOfFirstTrim) ==
length) {
1563#if qStroika_Foundation_Debug_AssertionsChecked
1564 Assert (*
this == referenceImpl ());
1569#if qStroika_Foundation_Debug_AssertionsChecked
1570 Assert (mk_ (lowLevelCharSpan.subspan (0, endOfFirstTrim)) == referenceImpl ());
1572 return mk_ (lowLevelCharSpan.subspan (0, endOfFirstTrim));
1576 _SafeReadRepAccessor accessor{
this};
1577 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1578 switch (psd.fInCP) {
1580 return commonAlgorithm (psd.fAscii);
1583 return commonAlgorithm (psd.fSingleByteLatin1);
1585 case PeekSpanData::eChar32: {
1586 return commonAlgorithm (psd.fChar32);
1589 return referenceImpl ();
1596 auto referenceImpl = [&] () {
return LTrim (shouldBeTrimmed).
RTrim (shouldBeTrimmed); };
1599 auto useCharTrimmedFunc = [&] (
Character c) {
1604 return shouldBeTrimmed (c);
1608 auto commonAlgorithm = [&]<
typename T> (span<const T> lowLevelCharSpan) ->
String {
1610 size_t firstKeptIdx = 0;
1611 for (; firstKeptIdx <
length; ++firstKeptIdx) {
1613 Character c{lowLevelCharSpan[firstKeptIdx]};
1614 if (not useCharTrimmedFunc (c)) {
1618 ptrdiff_t endOfFirstTrim =
length;
1619 for (;
static_cast<size_t> (endOfFirstTrim) != firstKeptIdx; --endOfFirstTrim) {
1621 Character c{lowLevelCharSpan[endOfFirstTrim - 1]};
1622 if (useCharTrimmedFunc (c)) {
1629 if (firstKeptIdx == 0 and
static_cast<size_t> (endOfFirstTrim) ==
length) {
1630#if qStroika_Foundation_Debug_AssertionsChecked
1631 Assert (*
this == referenceImpl ());
1635 if (firstKeptIdx ==
length) {
1636#if qStroika_Foundation_Debug_AssertionsChecked
1637 Assert (
String{} == referenceImpl ());
1641 Assert (
static_cast<ptrdiff_t
> (firstKeptIdx) < endOfFirstTrim);
1642#if qStroika_Foundation_Debug_AssertionsChecked
1643 Assert (mk_ (lowLevelCharSpan.subspan (firstKeptIdx, endOfFirstTrim - firstKeptIdx)) == referenceImpl ());
1645 return mk_ (lowLevelCharSpan.subspan (firstKeptIdx, endOfFirstTrim - firstKeptIdx));
1648 _SafeReadRepAccessor accessor{
this};
1649 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1650 switch (psd.fInCP) {
1652 return commonAlgorithm (psd.fAscii);
1655 return commonAlgorithm (psd.fSingleByteLatin1);
1657 case PeekSpanData::eChar32: {
1658 return commonAlgorithm (psd.fChar32);
1661 return referenceImpl ();
1672 size_t n = result.
size ();
1673 for (
size_t i = 0; i < n; ++i) {
1675 if (removeCharIf (c)) {
1680 for (; i < n; ++i) {
1682 if (not removeCharIf (c)) {
1695 for (
const String& i : list) {
1696 result << i << separator;
1698 if (result.
empty ()) {
1699 return result.
str ();
1709 bool changed{
false};
1710 _SafeReadRepAccessor accessor{
this};
1711 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1714 for (
auto c : psd.fAscii) {
1717 result.push_back (
static_cast<ASCII> (tolower (c)));
1720 result.push_back (c);
1732 result.push_back (c);
1737 return result.
str ();
1747 bool changed{
false};
1748 _SafeReadRepAccessor accessor{
this};
1749 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1752 for (
auto c : psd.fAscii) {
1755 result.push_back (
static_cast<ASCII> (toupper (c)));
1758 result.push_back (c);
1770 result.push_back (c);
1775 return result.
str ();
1792 if (
length () < maxLen) [[likely]] {
1795 String operateOn = [&] () {
1797 case StringShorteningPreference::ePreferKeepLeft:
1799 case StringShorteningPreference::ePreferKeepRight:
1801 case StringShorteningPreference::ePreferKeepMid:
1808 if (operateOn.
length () <= maxLen) {
1811 size_t useLen = [&] () {
1812 size_t useLen = maxLen;
1813 size_t ellipsisTotalLen = ellipsis.
length ();
1814 if (keepPref == StringShorteningPreference::ePreferKeepMid) {
1815 ellipsisTotalLen *= 2;
1817 if (useLen > ellipsisTotalLen) {
1818 useLen -= ellipsisTotalLen;
1826 case StringShorteningPreference::ePreferKeepLeft:
1827 return operateOn.
substr (0, useLen) + ellipsis;
1828 case StringShorteningPreference::ePreferKeepRight:
1829 return ellipsis + operateOn.
substr (operateOn.
length () - useLen);
1830 case StringShorteningPreference::ePreferKeepMid:
1831 return ellipsis + operateOn.
substr (operateOn.
length () / 2 - useLen / 2, useLen) + ellipsis;
1844 using Destructible_codecvt_byname = deletable_facet_<codecvt_byname<wchar_t, char, mbstate_t>>;
1845 Destructible_codecvt_byname cvt{l.name ()};
1848 span<const wchar_t> thisData =
GetData (&maybeIgnoreBuf1);
1850 mbstate_t mbstate{};
1851 const wchar_t* from_next;
1854 codecvt_base::result result =
1855 cvt.out (mbstate, thisData.data (), thisData.data () + thisData.size (), from_next, into.data (), into.end (), to_next);
1856 if (result != codecvt_base::ok) [[unlikely]] {
1860 return string{into.data (), to_next};
1869 using Destructible_codecvt_byname = deletable_facet_<codecvt_byname<wchar_t, char, mbstate_t>>;
1870 Destructible_codecvt_byname cvt{l.name ()};
1873 span<const wchar_t> thisData =
GetData (&maybeIgnoreBuf1);
1875 mbstate_t mbstate{};
1877 const wchar_t* readFrom = thisData.data ();
1878 char* intoIndex = into.data ();
1880 const wchar_t* from_next{
nullptr};
1881 char* to_next{
nullptr};
1882 codecvt_base::result result = cvt.out (mbstate, readFrom, thisData.data () + thisData.size (), from_next, intoIndex, into.end (), to_next);
1883 if (result != codecvt_base::ok) [[unlikely]] {
1884 if (from_next != thisData.data () + thisData.size ()) {
1885 readFrom = from_next + 1;
1887 intoIndex = to_next + 1;
1891 return string{into.data (), to_next};
1894void String::erase (
size_t from)
1899void String::erase (
size_t from,
size_t count)
1906 size_t max2Erase =
static_cast<size_t> (max (
static_cast<ptrdiff_t
> (0),
static_cast<ptrdiff_t
> (
size ()) -
static_cast<ptrdiff_t
> (from)));
1907 *
this =
RemoveAt (from, from + min (count, max2Erase));
1910const wchar_t* String::c_str () const noexcept
1914 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1915 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1916 return const_cast<String*
> (
this)->c_str ();
1917 DISABLE_COMPILER_MSC_WARNING_END (4996);
1918 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1919 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1921const wchar_t* String::c_str ()
1925 _SafeReadRepAccessor accessor{
this};
1926 const wchar_t* result = accessor._ConstGetRep ().c_str_peek ();
1927 if (result ==
nullptr) {
1928 _fRep = Memory::MakeSharedPtr<StringWithCStr_::Rep> (accessor._ConstGetRepSharedPtr ());
1929 result = _SafeReadRepAccessor{
this}._ConstGetRep ().c_str_peek ();
1933 Ensure (result[
size ()] ==
'\0' or (::wcslen (result) >
size () and
sizeof (
wchar_t) == 2));
1937[[noreturn]]
void String::ThrowInvalidAsciiException_ ()
1943#if qStroika_Foundation_Characters_AsPathAutoMapMSYSAndCygwin
1945std::filesystem::path String::As<std::filesystem::path> ()
const
1949 static const String kMSYSDrivePrefix_ =
"/"sv;
1950 static const String kCygrivePrefix_ =
"/cygdrive/"sv;
1951 if (StartsWith (kCygrivePrefix_)) {
1953 if (ss.
length () > 1 and ss[0].IsASCII () and ss[0].IsAlphabetic () and ss[1] ==
'/') {
1954 wstring w = ss.
As<wstring> ();
1955 w.insert (w.begin () + 1,
':');
1956 return filesystem::path{w};
1959 if (StartsWith (kMSYSDrivePrefix_)) {
1961 if (ss.
length () > 1 and ss[0].IsASCII () and ss[0].IsAlphabetic () and ss[1] ==
'/') {
1962 wstring w = ss.
As<wstring> ();
1963 w.insert (w.begin () + 1,
':');
1964 return filesystem::path{w};
1967 return filesystem::path{As<wstring> ()};
1980 if (isLast and fSpecialSeparatorForLastPair) [[unlikely]] {
1981 sb << *fSpecialSeparatorForLastPair;
1995namespace Stroika::Foundation::Traversal {
2000 using namespace Characters;
2001#if qStroika_Foundation_Debug_AssertionsChecked
2007 size_t cnt = this->size ();
2008 this->Apply ([&, idx = 0u] (
const String& i)
mutable {
2013 if (finalSeparator and idx + 1 == cnt) [[unlikely]] {
2014 sb << *finalSeparator;
2023#if qStroika_Foundation_Debug_AssertionsChecked
2024 Ensure (sb == referenceResult);
2038 span<const wchar_t> sData = s.
GetData (&maybeIgnoreBuf1);
2039 out.write (sData.data (), sData.size ());
2052size_t std::hash<String>::operator() (
const String& arg)
const
2054 using namespace Cryptography::Digest;
2055 using DIGESTER = Digester<Algorithm::SuperFastHash>;
2056 static constexpr DIGESTER kDigester_{};
2061 span<const char8_t> s = arg.
GetData (&maybeIgnoreBuf1);
2063 static const size_t kZeroDigest_ = kDigester_ (
nullptr,
nullptr);
2064 return kZeroDigest_;
2067 return kDigester_ (as_bytes (s));
#define RequireMember(p, c)
#define RequireNotReached()
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define RequireNotNull(p)
#define RequireExpression(c)
#define AssertNotReached()
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
bool Equals(const T *lhs, const T *rhs)
strcmp or wsccmp() as appropriate == 0
constexpr bool IsASCII() const noexcept
Return true iff the given character (or all in span) is (are) in the ascii range [0....
static constexpr void CheckASCII(span< const CHAR_T > s)
if not IsASCII (arg) throw RuntimeException...
nonvirtual Character ToLowerCase() const noexcept
nonvirtual ASCII GetAsciiCode() const noexcept
static constexpr strong_ordering Compare(span< const CHAR_T, E1 > lhs, span< const CHAR_T, E2 > rhs, CompareOptions co) noexcept
nonvirtual bool IsLowerCase() const noexcept
constexpr char32_t GetCharacterCode() const noexcept
Return the char32_t UNICODE code-point associated with this character.
nonvirtual Character ToUpperCase() const noexcept
constexpr bool IsWhitespace() const noexcept
nonvirtual bool IsUpperCase() const noexcept
RegularExpression is a compiled regular expression which can be used to match on a String class.
virtual Character GetAt(size_t index) const noexcept=0
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual size_t size() const noexcept
nonvirtual RESULT_T As() const
nonvirtual void Append(span< const CHAR_T > s)
nonvirtual bool empty() const noexcept
nonvirtual String str() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual size_t length() const noexcept
nonvirtual String ToUpperCase() const
static String FromNarrowString(const char *from, const locale &l)
nonvirtual bool Matches(const RegularExpression ®Ex) const
nonvirtual bool IsWhitespace() const
nonvirtual String NormalizeTextToNL() const
static String Join(const Iterable< String > &list, const String &separator=", "sv)
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 NormalizeSpace(Character useSpaceCharacter=' ') const
Replace sequences of whitespace characters (space, tab, newline etc) with a single space (or argument...
nonvirtual Containers::Sequence< pair< size_t, size_t > > FindEach(const RegularExpression ®Ex) const
nonvirtual String Repeat(unsigned int count) const
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 String RemoveAll(Character c) const
nonvirtual Containers::Sequence< RegularExpressionMatch > FindEachMatch(const RegularExpression ®Ex) const
nonvirtual String RemoveFirstIf(Character c) 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 string AsNarrowString(const locale &l) const
nonvirtual size_t size() const noexcept
nonvirtual bool EndsWith(const Character &c, CompareOptions co=eWithCase) const
nonvirtual String ToLowerCase() const
nonvirtual String ReplaceAll(const RegularExpression ®Ex, const String &with) const
nonvirtual String Replace(size_t from, size_t to, const String &replacement) const
nonvirtual String SubString(SZ from) const
nonvirtual String Trim(bool(*shouldBeTrimmed)(Character)=Character::IsWhitespace) const
nonvirtual bool StartsWith(const Character &c, CompareOptions co=eWithCase) const
nonvirtual String StripAll(bool(*removeCharIf)(Character)) const
nonvirtual String AssureEndsWith(const Character &c, CompareOptions co=eWithCase) const
Return *this if it ends with argument character, or append 'c' so that it ends with a 'c'.
nonvirtual Containers::Sequence< String > AsLines() const
break the String into a series of lines;
nonvirtual String LTrim(bool(*shouldBeTrimmed)(Character)=Character::IsWhitespace) const
nonvirtual Containers::Sequence< String > Grep(const String &fgrepArg) const
Breaks this string into Lines, with AsLines (), and applies the argument filter (as if with ....
nonvirtual Containers::Sequence< String > FindEachString(const RegularExpression ®Ex) 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 Containers::Sequence< String > Tokenize() const
nonvirtual String RemoveAt(size_t charAt) const
nonvirtual String RTrim(bool(*shouldBeTrimmed)(Character)=Character::IsWhitespace) const
nonvirtual optional< size_t > Find(Character c, CompareOptions co=eWithCase) const
nonvirtual String substr(size_t from, size_t count=npos) const
static const UTFConvert kThe
Nearly always use this default UTFConvert.
static constexpr bool AllFitsInTwoByteEncoding(span< const CHAR_T > s) noexcept
Sequence_stdvector<T> is an std::vector-based concrete implementation of the Sequence<T> container pa...
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual void push_back(ArgByValueType< value_type > item)
nonvirtual void Append(ArgByValueType< value_type > item)
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual size_t size() const noexcept
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
nonvirtual RESULT_T Join(const CONVERT_TO_RESULT &convertToResult=kDefaultToStringConverter<>, const COMBINER &combiner=Characters::kDefaultStringCombiner) const
ape the JavaScript/python 'join' function - take the parts of 'this' iterable and combine them into a...
_SharedByValueRepType _fRep
nonvirtual size_t size() const
Returns the number of items contained.
nonvirtual Iterator< Character > MakeIterator() const
Create an iterator object which can be used to traverse the 'Iterable'.
An Iterator<T> is a copyable object which allows traversing the contents of some container....
concept - trivial shorthand for variadic same_as A or same_as B, or ...
char ASCII
Stroika's string/character classes treat 'char' as being an ASCII character.
StringShorteningPreference
DISABLE_COMPILER_MSC_WARNING_START(4996)
AllowMissingCharacterErrorsFlag
wostream & operator<<(wostream &out, const String &s)
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
SequencePolicy
equivalent which of 4 types being used std::execution::sequenced_policy, parallel_policy,...
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
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<>:...
Memory::BLOB operator()(const T &t) const