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"
37using Memory::MakeSharedPtr;
42static_assert (regular<String>);
44#if qStroika_Foundation_Characters_AsPathAutoMapMSYSAndCygwin
65 struct StringRepHelperAllFitInSize_ :
String {
66 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
67 struct Rep :
public _IRep {
69 using inherited = _IRep;
72 span<const CHAR_T> _fData;
74#if qStroika_Foundation_Debug_AssertionsChecked
76 mutable unsigned int fOutstandingIterators_{};
81 Rep (span<const CHAR_T> s)
82 requires (not same_as<CHAR_T, char8_t>)
85 if constexpr (same_as<CHAR_T, char> or same_as<CHAR_T, char8_t>) {
86 Require (Character::IsASCII (s));
89 if constexpr (same_as<CHAR_T, char16_t>) {
93 Rep& operator= (span<const CHAR_T> s)
95#if qStroika_Foundation_Debug_AssertionsChecked
96 Require (fOutstandingIterators_ == 0);
98 if constexpr (same_as<CHAR_T, char> or same_as<CHAR_T, char8_t>) {
99 Require (Character::IsASCII (s));
101 if constexpr (same_as<CHAR_T, char16_t>) {
110 virtual Character GetAt (
size_t index)
const noexcept override
112 Require (index < _fData.size ());
114 return Character{
static_cast<char32_t> (_fData[index])};
116 virtual PeekSpanData PeekData (optional<PeekSpanData::StorageCodePointType> )
const noexcept override
119 if constexpr (same_as<CHAR_T, ASCII>) {
120 return PeekSpanData{PeekSpanData::StorageCodePointType::eAscii, {.fAscii = _fData}};
122 if constexpr (same_as<CHAR_T, Latin1>) {
123 return PeekSpanData{PeekSpanData::StorageCodePointType::eSingleByteLatin1, {.fSingleByteLatin1 = _fData}};
125 else if constexpr (
sizeof (CHAR_T) == 2) {
127 return PeekSpanData{PeekSpanData::StorageCodePointType::eChar16,
128 {.fChar16 = span<const char16_t>{
reinterpret_cast<const char16_t*
> (_fData.data ()), _fData.size ()}}};
130 else if constexpr (
sizeof (CHAR_T) == 4) {
132 return PeekSpanData{PeekSpanData::StorageCodePointType::eChar32,
133 {.fChar32 = span<const char32_t>{
reinterpret_cast<const char32_t*
> (_fData.data ()), _fData.size ()}}};
140 virtual shared_ptr<Iterable<Character>::_IRep> Clone ()
const override
149 span<const CHAR_T> fData_;
151#if qStroika_Foundation_Debug_AssertionsChecked
152 const Rep* fOwningRep_;
154 MyIterRep_ (span<const CHAR_T> data
162 , fOwningRep_{dbgRep}
165#if qStroika_Foundation_Debug_AssertionsChecked
166 ++fOwningRep_->fOutstandingIterators_;
169#if qStroika_Foundation_Debug_AssertionsChecked
170 virtual ~MyIterRep_ ()
override
172 Require (fOwningRep_->fOutstandingIterators_ > 0);
173 --fOwningRep_->fOutstandingIterators_;
177 virtual unique_ptr<Iterator<Character>::IRep> Clone ()
const override
179 return make_unique<MyIterRep_> (fData_.subspan (fIdx_)
186 virtual void More (optional<Character>* result,
bool advance)
override
189 if (advance) [[likely]] {
190 Require (fIdx_ < fData_.size ());
193 if (fIdx_ < fData_.size ()) [[likely]] {
195 *result =
Character{
static_cast<char32_t> (fData_[fIdx_])};
201 virtual bool Equals (
const IRep* rhs)
const override
205 const MyIterRep_* rrhs = Debug::UncheckedDynamicCast<const MyIterRep_*> (rhs);
206 return fData_.data () == rrhs->fData_.data () and fIdx_ == rrhs->fIdx_;
218 virtual size_t size ()
const override
220 return _fData.size ();
222 virtual bool empty ()
const override
224 return _fData.empty ();
229 return inherited::Find (that, seq);
238 struct DynamicallyAllocatedString : StringRepHelperAllFitInSize_ {
239 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
242 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
245 Rep (span<const CHAR_T> t1)
246 : inherited{mkBuf_ (t1)}
250 Rep (
const Rep&) =
delete;
253 nonvirtual Rep& operator= (
const Rep&) =
delete;
256 virtual ~Rep ()
override
258 delete[] this->_fData.data ();
262 static span<CHAR_T> mkBuf_ (
size_t length)
264 size_t capacity = AdjustCapacity_ (length);
265 Assert (length <= capacity);
266 if constexpr (kAddNullTerminator_) {
267 Assert (length + 1 <= capacity);
269 CHAR_T* newBuf =
new CHAR_T[capacity];
270 return span{newBuf, capacity};
272 static span<CHAR_T> mkBuf_ (span<const CHAR_T> t1)
274 size_t len = t1.size ();
275 span<CHAR_T> buf = mkBuf_ (len);
276 Assert (buf.size () >= len);
277 auto result = Memory::CopyBytes (t1, buf);
278 if constexpr (kAddNullTerminator_) {
279 Assert (len + 1 <= buf.size ());
280 *(buf.data () + len) =
'\0';
287 virtual const wchar_t* c_str_peek () const noexcept
override
290 if constexpr (kAddNullTerminator_) {
291 Assert (*(this->_fData.data () + this->_fData.size ()) ==
'\0');
292 return reinterpret_cast<const wchar_t*
> (this->_fData.data ());
301 static constexpr bool kAddNullTerminator_ =
sizeof (CHAR_T) ==
sizeof (
wchar_t);
304 static size_t AdjustCapacity_ (
size_t initialCapacity)
306 size_t result = initialCapacity;
307 if constexpr (kAddNullTerminator_) {
321 struct FixedCapacityInlineStorageString_ : StringRepHelperAllFitInSize_ {
322 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T,
size_t CAPACITY>
323 struct Rep final :
public StringRepHelperAllFitInSize_::Rep<CHAR_T>,
326 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
329 bool IncludesNullTerminator_ ()
const
331 if constexpr (
sizeof (CHAR_T) ==
sizeof (
wchar_t)) {
332 return this->_fData.size () < CAPACITY;
340 CHAR_T fBuf_[CAPACITY];
343 Rep (span<const CHAR_T> t1)
349 Require (t1.size () <= CAPACITY);
350 inherited::operator= (Memory::CopyBytes (t1, span<CHAR_T>{fBuf_}));
351 if (IncludesNullTerminator_ ()) {
352 Assert (t1.size () + 1 <= CAPACITY);
353 fBuf_[t1.size ()] = CHAR_T{
'\0'};
357 Rep (
const Rep&) =
delete;
360 nonvirtual Rep& operator= (
const Rep&) =
delete;
364 virtual const wchar_t* c_str_peek () const noexcept
override
366 if (IncludesNullTerminator_ ()) {
367 Assert (*(this->_fData.data () + this->_fData.size ()) ==
'\0');
368 return reinterpret_cast<const wchar_t*
> (this->_fData.data ());
380 struct StringConstant_ :
public StringRepHelperAllFitInSize_ {
383 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
384 class DirectIndexRep final :
public StringRepHelperAllFitInSize_::Rep<CHAR_T>,
387 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
390 DirectIndexRep (span<const CHAR_T> s)
397 virtual const wchar_t* c_str_peek () const noexcept
override
407 struct StdStringDelegator_ :
public StringRepHelperAllFitInSize_ {
410 template <IStdBasicStringCompatibleCharacter CHAR_T>
413 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
416 Rep (basic_string<CHAR_T>&& s)
417 : inherited{span<const CHAR_T>{}}
418 , fMovedData_{move (s)}
420 inherited::operator= (span{fMovedData_.data (), fMovedData_.size ()});
425 virtual const wchar_t* c_str_peek () const noexcept
override
427 if constexpr (same_as<CHAR_T, wchar_t>) {
428 return fMovedData_.c_str ();
436 basic_string<CHAR_T> fMovedData_;
443 struct StringWithCStr_ :
public String {
447 shared_ptr<_IRep> fUnderlyingRep_;
452 Rep (
const shared_ptr<_IRep>& underlyingRep)
453 : fUnderlyingRep_{underlyingRep}
457 auto wideSpan = String::GetData<wchar_t> (underlyingRep->PeekData (nullopt), &possibleUsedBuf);
458 fCString_.assign (wideSpan.begin (), wideSpan.end ());
463 virtual shared_ptr<Iterable<Character>::_IRep> Clone ()
const override
465 return fUnderlyingRep_->Clone ();
469 return fUnderlyingRep_->MakeIterator ();
471 virtual size_t size ()
const override
473 return fUnderlyingRep_->size ();
475 virtual bool empty ()
const override
477 return fUnderlyingRep_->empty ();
482 return fUnderlyingRep_->Find (that, seq);
487 virtual Character GetAt (
size_t index)
const noexcept override
489 return fUnderlyingRep_->GetAt (index);
491 virtual PeekSpanData PeekData ([[maybe_unused]] optional<PeekSpanData::StorageCodePointType> preferred)
const noexcept override
493 return fUnderlyingRep_->PeekData (preferred);
495 virtual const wchar_t* c_str_peek () const noexcept
override
497 return fCString_.c_str ();
504 template <
typename FACET>
505 struct deletable_facet_ final : FACET {
506 template <
typename... Args>
507 deletable_facet_ (Args&&... args)
508 : FACET{forward<Args> (args)...}
511 ~deletable_facet_ () =
default;
520const wregex& Characters::Private_::RegularExpression_GetCompiled (
const RegularExpression& regExp)
522 return regExp.GetCompiled ();
530shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<ASCII>& str)
533 return MakeSharedPtr<StringConstant_::DirectIndexRep<ASCII>> (span{str.data (), str.size ()});
536shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char8_t>& str)
539 return MakeSharedPtr<StringConstant_::DirectIndexRep<ASCII>> (Memory::SpanBytesCast<span<const ASCII>> (span{str.data (), str.size ()}));
542 return mk_ (span<const char8_t>{str.data (), str.size ()});
546shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char16_t>& str)
549 return MakeSharedPtr<StringConstant_::DirectIndexRep<char16_t>> (span{str.data (), str.size ()});
552 return mk_ (span<const char16_t>{str.data (), str.size ()});
556shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char32_t>& str)
558 return MakeSharedPtr<StringConstant_::DirectIndexRep<char32_t>> (span{str.data (), str.size ()});
561shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<wchar_t>& str)
563 return MakeSharedPtr<StringConstant_::DirectIndexRep<wchar_t>> (span{str.data (), str.size ()});
569 return String{MakeSharedPtr<StringConstant_::DirectIndexRep<ASCII>> (s)};
575 return String{MakeSharedPtr<StringConstant_::DirectIndexRep<char16_t>> (s)};
584 return String{MakeSharedPtr<StringConstant_::DirectIndexRep<char32_t>> (s)};
593 using Destructible_codecvt_byname = deletable_facet_<codecvt_byname<wchar_t, char, mbstate_t>>;
594 Destructible_codecvt_byname cvt{l.name ()};
599 const char* from_next;
601 codecvt_base::result result =
602 cvt.in (mbstate, s.data (), s.data () + s.size (), from_next, targetBuf.data (), targetBuf.data () + targetBuf.size (), to_next);
603 if (result != codecvt_base::ok) [[unlikely]] {
607 return String{span<const wchar_t>{targetBuf.data (),
static_cast<size_t> (to_next - targetBuf.data ())}};
610shared_ptr<String::_IRep> String::mkEmpty_ ()
612 static constexpr wchar_t kEmptyCStr_[] = L
"";
613 static const shared_ptr<_IRep> s_ = MakeSharedPtr<StringConstant_::DirectIndexRep<wchar_t>> (span{std::begin (kEmptyCStr_), 0});
617template <
typename CHAR_T>
618inline auto String::mk_nocheck_ (span<const CHAR_T> s) -> shared_ptr<_IRep>
619 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>)
622 if constexpr (same_as<CHAR_T, ASCII>) {
625 else if constexpr (same_as<CHAR_T, Latin1>) {
628 else if constexpr (
sizeof (CHAR_T) == 2) {
643 constexpr size_t kBaseOfFixedBufSize_ =
sizeof (StringRepHelperAllFitInSize_::Rep<CHAR_T>);
644 static_assert (kBaseOfFixedBufSize_ < 64);
646 static_assert (kBaseOfFixedBufSize_ == 3 *
sizeof (
void*));
647 if constexpr (
sizeof (
void*) == 4) {
648 static_assert (kBaseOfFixedBufSize_ == 12);
650 else if constexpr (
sizeof (
void*) == 8) {
651 static_assert (kBaseOfFixedBufSize_ == 24);
654 constexpr size_t kOverheadSizeForMakeShared_ =
655 qStroika_Foundation_Common_Platform_Windows ? (
sizeof (
void*) == 4 ? 12 : 16) :
sizeof (
unsigned long) * 2;
656#if qStroika_Foundation_Common_Platform_Windows
657 static_assert (kOverheadSizeForMakeShared_ ==
sizeof (_Ref_count_base));
659 static constexpr size_t kNElts1_ = (64 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
660 static constexpr size_t kNElts2_ = (96 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
661 static constexpr size_t kNElts3_ = (128 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
665 if constexpr (
sizeof (
void*) == 4) {
666 static_assert (kNElts1_ == 40);
667 static_assert (kNElts2_ == 72);
668 static_assert (kNElts3_ == 104);
670 if constexpr (
sizeof (
void*) == 8) {
671 static_assert (kNElts1_ == 24);
672 static_assert (kNElts2_ == 56);
673 static_assert (kNElts3_ == 88);
678 static_assert (kNElts2_ > kNElts1_);
679 static_assert (kNElts3_ > kNElts2_);
681 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts1_>) == 64 - kOverheadSizeForMakeShared_);
682 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts2_>) == 96 - kOverheadSizeForMakeShared_);
683 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts3_>) == 128 - kOverheadSizeForMakeShared_);
685 size_t sz = s.size ();
686 if (sz <= kNElts1_) {
687 return MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts1_>> (s);
689 else if (sz <= kNElts2_) {
690 return MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts2_>> (s);
692 else if (sz <= kNElts3_) {
693 return MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts3_>> (s);
695 return MakeSharedPtr<DynamicallyAllocatedString::Rep<CHAR_T>> (s);
699auto String::mk_ (basic_string<char>&& s) -> shared_ptr<_IRep>
702 return MakeSharedPtr<StdStringDelegator_::Rep<ASCII>> (move (s));
706auto String::mk_ (basic_string<char16_t>&& s) -> shared_ptr<_IRep>
709 return MakeSharedPtr<StdStringDelegator_::Rep<char16_t>> (move (s));
712 Memory::StackBuffer<char32_t> wideUnicodeBuf{Memory::eUninitialized, UTFConvert::ComputeTargetBufferSize<char32_t> (span{s.data (), s.size ()})};
713 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (span{s.data (), s.size ()}, span{wideUnicodeBuf})));
717auto String::mk_ (basic_string<char32_t>&& s) -> shared_ptr<_IRep>
719 return MakeSharedPtr<StdStringDelegator_::Rep<char32_t>> (move (s));
723auto String::mk_ (basic_string<wchar_t>&& s) -> shared_ptr<_IRep>
725 if constexpr (
sizeof (wchar_t) == 2) {
727 return MakeSharedPtr<StdStringDelegator_::Rep<wchar_t>> (move (s));
731 UTFConvert::ComputeTargetBufferSize<char32_t> (span{s.data (), s.size ()})};
732 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (span{s.data (), s.size ()}, span{wideUnicodeBuf})));
735 return MakeSharedPtr<StdStringDelegator_::Rep<wchar_t>> (move (s));
743 span leftSpan =
GetData (&ignoredA);
745 span rightSpan = rhs.
GetData (&ignoredB);
747 copy (leftSpan.begin (), leftSpan.end (), buf.data ());
748 copy (rightSpan.begin (), rightSpan.end (), buf.data () + leftSpan.size ());
749 return mk_ (span{buf});
752void String::SetCharAt (
Character c,
size_t i)
757 Require (i <
size ());
760 Require (i <
size ());
768 Require (at <=
size ());
773 span<const Character> thisStrData =
GetData (&ignored1);
776 sb.Append (thisStrData.subspan (at));
782 Require (from <= to);
783 Require (to <=
size ());
790 _SafeReadRepAccessor accessor{
this};
791 size_t length = accessor._ConstGetRep ().
size ();
799 span<char32_t> bufSpan{buf.data (), buf.size ()};
800 span s1 = d.subspan (0, from);
801 span s2 = d.subspan (to);
802 Memory::CopyBytes (s1, bufSpan);
803 Memory::CopyBytes (s2, bufSpan.subspan (s1.size ()));
804 return String{mk_ (bufSpan)};
811 if (
auto o = tmp.
Find (c, eWithCase)) {
818 if (
auto o = this->
Find (subString, eWithCase)) {
829 while (
auto o = tmp.
Find (c, eWithCase)) {
839 while (
auto o = tmp.
Find (subString, eWithCase)) {
847 PeekSpanData pds = GetPeekSpanData<ASCII> ();
851 span<const char> examineSpan = pds.fAscii.subspan (startAt);
852 if (co == eWithCase) {
853 if (
auto i = std::find (examineSpan.begin (), examineSpan.end (), c.
GetAsciiCode ()); i != examineSpan.end ()) {
854 return i - examineSpan.begin () + startAt;
859 size_t reportIdx = startAt;
860 for (
auto ci : examineSpan) {
861 if (tolower (ci) == lc) {
879 span<const Character> charSpan =
GetData (pds, &maybeIgnoreBuf);
880 Require (startAt <= charSpan.size ());
881 span<const Character> examineSpan = charSpan.subspan (startAt);
883 case eCaseInsensitive: {
885 for (
auto i = examineSpan.begin (); i != examineSpan.end (); ++i) {
886 if (i->ToLowerCase () == lcc) {
887 return startAt + (i - examineSpan.begin ());
892 if (
auto i = std::find (examineSpan.begin (), examineSpan.end (), c); i != examineSpan.end ()) {
893 return startAt + i - examineSpan.begin ();
900optional<size_t>
String::Find (
const String& subString,
size_t startAt, CompareOptions co)
const
903 _SafeReadRepAccessor accessor{
this};
904 Require (startAt <= accessor._ConstGetRep ().size ());
906 size_t subStrLen = subString.
size ();
907 if (subStrLen == 0) {
908 return (accessor._ConstGetRep ().size () == 0) ? optional<size_t>{} : 0;
910 if (accessor._ConstGetRep ().size () < subStrLen) {
914 size_t limit = accessor._ConstGetRep ().size () - subStrLen;
916 case eCaseInsensitive: {
917 for (
size_t i = startAt; i <= limit; ++i) {
918 for (
size_t j = 0; j < subStrLen; ++j) {
919 if (accessor._ConstGetRep ().GetAt (i + j).ToLowerCase () != subString[j].ToLowerCase ()) {
928 for (
size_t i = startAt; i <= limit; ++i) {
929 for (
size_t j = 0; j < subStrLen; ++j) {
930 if (accessor._ConstGetRep ().GetAt (i + j) != subString[j]) {
944 Require (startAt <=
size ());
945 wstring tmp = As<wstring> ();
946 Require (startAt < tmp.size ());
947 tmp = tmp.substr (startAt);
949 regex_search (tmp, res, regEx.GetCompiled ());
950 if (res.size () >= 1) {
951 size_t startOfMatch = startAt + res.position ();
952 return pair<size_t, size_t>{startOfMatch, startOfMatch + res.length ()};
959 vector<size_t> result;
960 for (optional<size_t> i =
Find (string2SearchFor, 0, co); i; i =
Find (string2SearchFor, *i, co)) {
962 *i += string2SearchFor.
length ();
969 vector<pair<size_t, size_t>> result;
971 wstring tmp{As<wstring> ()};
973 regex_search (tmp, res, regEx.GetCompiled ());
974 size_t nMatches = res.size ();
975 result.reserve (nMatches);
976 for (
size_t mi = 0; mi < nMatches; ++mi) {
977 size_t matchLen = res.length (mi);
979 result.push_back (pair<size_t, size_t>{res.position (mi), matchLen});
987 vector<RegularExpressionMatch> result;
988 wstring tmp{As<wstring> ()};
989 for (wsregex_iterator i = wsregex_iterator{tmp.begin (), tmp.end (), regEx.GetCompiled ()}; i != wsregex_iterator (); ++i) {
991 Assert (match.size () != 0);
992 size_t n = match.size ();
994 for (
size_t j = 1; j < n; ++j) {
1004 vector<String> result;
1005 wstring tmp{As<wstring> ()};
1006 for (wsregex_iterator i = wsregex_iterator{tmp.begin (), tmp.end (), regEx.GetCompiled ()}; i != wsregex_iterator (); ++i) {
1015 _SafeReadRepAccessor accessor{
this};
1016 const _IRep& useRep = accessor._ConstGetRep ();
1017 size_t length = useRep.size ();
1018 for (
size_t i = length; i > 0; --i) {
1019 if (useRep.
GetAt (i - 1) == c) {
1032 size_t subStrLen = subString.
size ();
1033 if (subStrLen == 0) {
1034 return ((
size () == 0) ? optional<size_t>{} :
size () - 1);
1037 size_t limit =
size () - subStrLen + 1;
1038 for (
size_t i = limit; i > 0; --i) {
1039 if (
SubString (i - 1, i - 1 + subStrLen) == subString) {
1049 span<const wchar_t> thisSpan =
GetData (&ignored);
1050 Require (from <= to);
1051 Require (to <= this->
size ());
1052 Assert (to < thisSpan.size ());
1055 sb.Append (thisSpan.subspan (to));
1062 _SafeReadRepAccessor accessor{
this};
1063 if (accessor._ConstGetRep ().size () == 0) {
1071 Require (not subString.empty ());
1075#if qStroika_Foundation_Debug_AssertionsChecked
1076 bool referenceResult = ThreeWayComparer{co}(
SubString (0, subString.
size ()), subString) == 0;
1080 span<const Character> subStrData = subString.
GetData (&maybeIgnoreBuf1);
1081 span<const Character> thisData =
GetData (&maybeIgnoreBuf2);
1082 bool result =
Character::Compare (thisData.subspan (0, subStrData.size ()), subStrData, co) == 0;
1083#if qStroika_Foundation_Debug_AssertionsChecked
1084 Ensure (result == referenceResult);
1091 _SafeReadRepAccessor accessor{
this};
1092 const _IRep& useRep = accessor._ConstGetRep ();
1093 size_t thisStrLen = useRep.size ();
1094 if (thisStrLen == 0) {
1102 Require (not subString.empty ());
1103 _SafeReadRepAccessor subStrAccessor{&subString};
1104 _SafeReadRepAccessor accessor{
this};
1105 size_t thisStrLen = accessor._ConstGetRep ().
size ();
1106 size_t subStrLen = subString.
size ();
1107 if (subStrLen > thisStrLen) {
1110#if qStroika_Foundation_Debug_AssertionsChecked
1115 span<const Character> subStrData = subString.
GetData (&maybeIgnoreBuf1);
1116 span<const Character> thisData =
GetData (&maybeIgnoreBuf2);
1117 bool result =
Character::Compare (thisData.subspan (thisStrLen - subStrLen), subStrData, co) == 0;
1118#if qStroika_Foundation_Debug_AssertionsChecked
1119 Ensure (result == referenceResult);
1136 wstring tmp{As<wstring> ()};
1137 return regex_match (tmp.begin (), tmp.end (), regEx.GetCompiled ());
1144 wstring tmp{As<wstring> ()};
1146 if (regex_match (tmp, base_match, regEx.GetCompiled ())) {
1148 for (
size_t i = 1; i < base_match.size (); ++i) {
1149 matches->
Append (base_match[i].str ());
1158 return String{regex_replace (As<wstring> (), regEx.GetCompiled (), with.
As<wstring> ())};
1163 Require (not string2SearchFor.empty ());
1166 optional<size_t> i{0};
1167 while ((i = result.Find (string2SearchFor, *i, co))) {
1178 if (replaceCharP (i)) {
1192 if (charSet.Contains (i)) {
1206 span<const Character> charSpan =
GetData (pds, &maybeIgnoreBuf);
1208 bool everChanged{
false};
1209 for (
auto ci = charSpan.begin (); ci != charSpan.end (); ++ci) {
1214 if (ci + 1 != charSpan.end () and *(ci + 1) ==
'\n') {
1242 bool inToken =
false;
1244 size_t len =
size ();
1245 for (
size_t i = 0; i != len; ++i) {
1247 bool newInToken = not isTokenSeparator (c);
1248 if (inToken != newInToken) {
1273 size_t len = this->
length ();
1274 for (
size_t startAt = 0; startAt < len;) {
1275 if (optional<pair<size_t, size_t>> ofi =
Find (isSeparator, startAt)) {
1276 Assert (ofi->first >= startAt);
1277 Assert (ofi->first <= ofi->second);
1278 if (ofi->first == ofi->second) [[unlikely]] {
1279 static const auto kException_ =
1283 if (ofi->first > startAt) {
1287 Assert (startAt == 0);
1289 startAt = ofi->second;
1290 Assert (startAt <= len);
1304 return Tokenize ([delimiters] (
Character c) ->
bool {
return delimiters.Contains (c); });
1318 if (ii and *ii ==
'\n') {
1321 r += curLineSB.
str ();
1326 r += curLineSB.
str ();
1331 curLineSB.push_back (c);
1336 if (not curLineSB.
empty ()) {
1337 r += curLineSB.
str ();
1346 if (i.Contains (fgrepArg)) {
1356 if (i.Matches (egrepArg)) {
1366 return Col (i, kWS_);
1371 return Tokenize (separator).Nth (i);
1374String String::SubString_ (
const _SafeReadRepAccessor& thisAccessor,
size_t from,
size_t to)
const
1376 constexpr bool kWholeStringOptionization_ =
1378 Require (from <= to);
1379 Require (to <= this->
size ());
1382 if (from == to) [[unlikely]] {
1385 PeekSpanData psd = thisAccessor._ConstGetRep ().PeekData (nullopt);
1386 switch (psd.fInCP) {
1388 if constexpr (kWholeStringOptionization_) {
1389 if (from == 0 and to == psd.fAscii.size ()) [[unlikely]] {
1393 return mk_nocheck_ (psd.fAscii.subspan (from, to - from));
1396 if constexpr (kWholeStringOptionization_) {
1397 if (from == 0 and to == psd.fSingleByteLatin1.size ()) [[unlikely]] {
1401 return mk_ (psd.fSingleByteLatin1.subspan (from, to - from));
1403 case PeekSpanData::eChar16: {
1404 if constexpr (kWholeStringOptionization_) {
1405 if (from == 0 and to == psd.fChar16.size ()) [[unlikely]] {
1409 return mk_ (psd.fChar16.subspan (from, to - from));
1411 case PeekSpanData::eChar32: {
1412 if constexpr (kWholeStringOptionization_) {
1413 if (from == 0 and to == psd.fChar32.size ()) [[unlikely]] {
1417 return mk_ (psd.fChar32.subspan (from, to - from));
1433 return *
this + *
this;
1436 for (
unsigned int i = 0; i < count; ++i) {
1447 auto referenceImpl = [&] () {
1448 _SafeReadRepAccessor accessor{
this};
1449 size_t length = accessor._ConstGetRep ().size ();
1450 for (
size_t i = 0; i <
length; ++i) {
1451 if (not(*shouldBeTrimmed) (accessor._ConstGetRep ().GetAt (i))) {
1462 auto commonAlgorithm = [&]<
typename T> (span<const T> lowLevelCharSpan) ->
String {
1464 for (
size_t i = 0; i <
length; ++i) {
1468 bool thisCharacterTrimmed = [&] () {
1473 return shouldBeTrimmed (c);
1476 if (not thisCharacterTrimmed) {
1478#if qStroika_Foundation_Debug_AssertionsChecked
1479 Assert (*
this == referenceImpl ());
1484#if qStroika_Foundation_Debug_AssertionsChecked
1485 Assert (mk_ (lowLevelCharSpan.subspan (i)) == referenceImpl ());
1487 return mk_ (lowLevelCharSpan.subspan (i));
1493 _SafeReadRepAccessor accessor{
this};
1494 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1495 switch (psd.fInCP) {
1497 return commonAlgorithm (psd.fAscii);
1500 return commonAlgorithm (psd.fSingleByteLatin1);
1502 case PeekSpanData::eChar32: {
1503 return commonAlgorithm (psd.fChar32);
1506 return referenceImpl ();
1512 auto referenceImpl = [&] () {
1513 _SafeReadRepAccessor accessor{
this};
1514 ptrdiff_t
length = accessor._ConstGetRep ().size ();
1515 ptrdiff_t endOfFirstTrim =
length;
1516 for (; endOfFirstTrim != 0; --endOfFirstTrim) {
1517 if ((*shouldBeTrimmed) (accessor._ConstGetRep ().GetAt (endOfFirstTrim - 1))) {
1524 if (endOfFirstTrim == 0) {
1527 else if (endOfFirstTrim ==
length) {
1535 auto commonAlgorithm = [&]<
typename T> (span<const T> lowLevelCharSpan) ->
String {
1537 ptrdiff_t endOfFirstTrim =
length;
1538 for (; endOfFirstTrim != 0; --endOfFirstTrim) {
1540 Character c{lowLevelCharSpan[endOfFirstTrim - 1]};
1542 bool thisCharacterTrimmed = [&] () {
1547 return shouldBeTrimmed (c);
1550 if (thisCharacterTrimmed) {
1557 if (endOfFirstTrim == 0) {
1558#if qStroika_Foundation_Debug_AssertionsChecked
1559 Assert (
String{} == referenceImpl ());
1563 else if (
static_cast<size_t> (endOfFirstTrim) ==
length) {
1564#if qStroika_Foundation_Debug_AssertionsChecked
1565 Assert (*
this == referenceImpl ());
1570#if qStroika_Foundation_Debug_AssertionsChecked
1571 Assert (mk_ (lowLevelCharSpan.subspan (0, endOfFirstTrim)) == referenceImpl ());
1573 return mk_ (lowLevelCharSpan.subspan (0, endOfFirstTrim));
1577 _SafeReadRepAccessor accessor{
this};
1578 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1579 switch (psd.fInCP) {
1581 return commonAlgorithm (psd.fAscii);
1584 return commonAlgorithm (psd.fSingleByteLatin1);
1586 case PeekSpanData::eChar32: {
1587 return commonAlgorithm (psd.fChar32);
1590 return referenceImpl ();
1597 auto referenceImpl = [&] () {
return LTrim (shouldBeTrimmed).
RTrim (shouldBeTrimmed); };
1600 auto useCharTrimmedFunc = [&] (
Character c) {
1605 return shouldBeTrimmed (c);
1609 auto commonAlgorithm = [&]<
typename T> (span<const T> lowLevelCharSpan) ->
String {
1611 size_t firstKeptIdx = 0;
1612 for (; firstKeptIdx <
length; ++firstKeptIdx) {
1614 Character c{lowLevelCharSpan[firstKeptIdx]};
1615 if (not useCharTrimmedFunc (c)) {
1619 ptrdiff_t endOfFirstTrim =
length;
1620 for (;
static_cast<size_t> (endOfFirstTrim) != firstKeptIdx; --endOfFirstTrim) {
1622 Character c{lowLevelCharSpan[endOfFirstTrim - 1]};
1623 if (useCharTrimmedFunc (c)) {
1630 if (firstKeptIdx == 0 and
static_cast<size_t> (endOfFirstTrim) ==
length) {
1631#if qStroika_Foundation_Debug_AssertionsChecked
1632 Assert (*
this == referenceImpl ());
1636 if (firstKeptIdx ==
length) {
1637#if qStroika_Foundation_Debug_AssertionsChecked
1638 Assert (
String{} == referenceImpl ());
1642 Assert (
static_cast<ptrdiff_t
> (firstKeptIdx) < endOfFirstTrim);
1643#if qStroika_Foundation_Debug_AssertionsChecked
1644 Assert (mk_ (lowLevelCharSpan.subspan (firstKeptIdx, endOfFirstTrim - firstKeptIdx)) == referenceImpl ());
1646 return mk_ (lowLevelCharSpan.subspan (firstKeptIdx, endOfFirstTrim - firstKeptIdx));
1649 _SafeReadRepAccessor accessor{
this};
1650 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1651 switch (psd.fInCP) {
1653 return commonAlgorithm (psd.fAscii);
1656 return commonAlgorithm (psd.fSingleByteLatin1);
1658 case PeekSpanData::eChar32: {
1659 return commonAlgorithm (psd.fChar32);
1662 return referenceImpl ();
1673 size_t n = result.
size ();
1674 for (
size_t i = 0; i < n; ++i) {
1676 if (removeCharIf (c)) {
1681 for (; i < n; ++i) {
1683 if (not removeCharIf (c)) {
1696 for (
const String& i : list) {
1697 result << i << separator;
1699 if (result.
empty ()) {
1700 return result.
str ();
1710 bool changed{
false};
1711 _SafeReadRepAccessor accessor{
this};
1712 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1715 for (
auto c : psd.fAscii) {
1718 result.push_back (
static_cast<ASCII> (tolower (c)));
1721 result.push_back (c);
1733 result.push_back (c);
1738 return result.
str ();
1748 bool changed{
false};
1749 _SafeReadRepAccessor accessor{
this};
1750 PeekSpanData psd = accessor._ConstGetRep ().PeekData (nullopt);
1753 for (
auto c : psd.fAscii) {
1756 result.push_back (
static_cast<ASCII> (toupper (c)));
1759 result.push_back (c);
1771 result.push_back (c);
1776 return result.
str ();
1793 if (
length () < maxLen) [[likely]] {
1796 String operateOn = [&] () {
1798 case StringShorteningPreference::ePreferKeepLeft:
1800 case StringShorteningPreference::ePreferKeepRight:
1802 case StringShorteningPreference::ePreferKeepMid:
1809 if (operateOn.
length () <= maxLen) {
1812 size_t useLen = [&] () {
1813 size_t useLen = maxLen;
1814 size_t ellipsisTotalLen = ellipsis.
length ();
1815 if (keepPref == StringShorteningPreference::ePreferKeepMid) {
1816 ellipsisTotalLen *= 2;
1818 if (useLen > ellipsisTotalLen) {
1819 useLen -= ellipsisTotalLen;
1827 case StringShorteningPreference::ePreferKeepLeft:
1828 return operateOn.
substr (0, useLen) + ellipsis;
1829 case StringShorteningPreference::ePreferKeepRight:
1830 return ellipsis + operateOn.
substr (operateOn.
length () - useLen);
1831 case StringShorteningPreference::ePreferKeepMid:
1832 return ellipsis + operateOn.
substr (operateOn.
length () / 2 - useLen / 2, useLen) + ellipsis;
1845 using Destructible_codecvt_byname = deletable_facet_<codecvt_byname<wchar_t, char, mbstate_t>>;
1846 Destructible_codecvt_byname cvt{l.name ()};
1849 span<const wchar_t> thisData =
GetData (&maybeIgnoreBuf1);
1851 mbstate_t mbstate{};
1852 const wchar_t* from_next;
1855 codecvt_base::result result =
1856 cvt.out (mbstate, thisData.data (), thisData.data () + thisData.size (), from_next, into.data (), into.end (), to_next);
1857 if (result != codecvt_base::ok) [[unlikely]] {
1861 return string{into.data (), to_next};
1870 using Destructible_codecvt_byname = deletable_facet_<codecvt_byname<wchar_t, char, mbstate_t>>;
1871 Destructible_codecvt_byname cvt{l.name ()};
1874 span<const wchar_t> thisData =
GetData (&maybeIgnoreBuf1);
1876 mbstate_t mbstate{};
1878 const wchar_t* readFrom = thisData.data ();
1879 char* intoIndex = into.data ();
1881 const wchar_t* from_next{
nullptr};
1882 char* to_next{
nullptr};
1883 codecvt_base::result result = cvt.out (mbstate, readFrom, thisData.data () + thisData.size (), from_next, intoIndex, into.end (), to_next);
1884 if (result != codecvt_base::ok) [[unlikely]] {
1885 if (from_next != thisData.data () + thisData.size ()) {
1886 readFrom = from_next + 1;
1888 intoIndex = to_next + 1;
1892 return string{into.data (), to_next};
1895void String::erase (
size_t from)
1900void String::erase (
size_t from,
size_t count)
1907 size_t max2Erase =
static_cast<size_t> (max (
static_cast<ptrdiff_t
> (0),
static_cast<ptrdiff_t
> (
size ()) -
static_cast<ptrdiff_t
> (from)));
1908 *
this =
RemoveAt (from, from + min (count, max2Erase));
1911const wchar_t* String::c_str () const noexcept
1915 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1916 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1917 return const_cast<String*
> (
this)->c_str ();
1918 DISABLE_COMPILER_MSC_WARNING_END (4996);
1919 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1920 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1922const wchar_t* String::c_str ()
1926 _SafeReadRepAccessor accessor{
this};
1927 const wchar_t* result = accessor._ConstGetRep ().c_str_peek ();
1928 if (result ==
nullptr) {
1929 _fRep = MakeSharedPtr<StringWithCStr_::Rep> (accessor._ConstGetRepSharedPtr ());
1930 result = _SafeReadRepAccessor{
this}._ConstGetRep ().c_str_peek ();
1934 Ensure (result[
size ()] ==
'\0' or (::wcslen (result) >
size () and
sizeof (
wchar_t) == 2));
1938[[noreturn]]
void String::ThrowInvalidAsciiException_ ()
1944#if qStroika_Foundation_Characters_AsPathAutoMapMSYSAndCygwin
1946std::filesystem::path String::As<std::filesystem::path> ()
const
1950 static const String kMSYSDrivePrefix_ =
"/"sv;
1951 static const String kCygrivePrefix_ =
"/cygdrive/"sv;
1952 if (StartsWith (kCygrivePrefix_)) {
1954 if (ss.
length () > 1 and ss[0].IsASCII () and ss[0].IsAlphabetic () and ss[1] ==
'/') {
1955 wstring w = ss.
As<wstring> ();
1956 w.insert (w.begin () + 1,
':');
1957 return filesystem::path{w};
1960 if (StartsWith (kMSYSDrivePrefix_)) {
1962 if (ss.
length () > 1 and ss[0].IsASCII () and ss[0].IsAlphabetic () and ss[1] ==
'/') {
1963 wstring w = ss.
As<wstring> ();
1964 w.insert (w.begin () + 1,
':');
1965 return filesystem::path{w};
1968 return filesystem::path{As<wstring> ()};
1981 if (isLast and fSpecialSeparatorForLastPair) [[unlikely]] {
1982 sb << *fSpecialSeparatorForLastPair;
1996namespace Stroika::Foundation::Traversal {
2001 using namespace Characters;
2002#if qStroika_Foundation_Debug_AssertionsChecked
2008 size_t cnt = this->size ();
2009 this->Apply ([&, idx = 0u] (
const String& i)
mutable {
2014 if (finalSeparator and idx + 1 == cnt) [[unlikely]] {
2015 sb << *finalSeparator;
2024#if qStroika_Foundation_Debug_AssertionsChecked
2025 Ensure (sb == referenceResult);
2039 span<const wchar_t> sData = s.
GetData (&maybeIgnoreBuf1);
2040 out.write (sData.data (), sData.size ());
2053size_t std::hash<String>::operator() (
const String& arg)
const
2055 using namespace Cryptography::Digest;
2056 using DIGESTER = Digester<Algorithm::SuperFastHash>;
2057 static constexpr DIGESTER kDigester_{};
2062 span<const char8_t> s = arg.
GetData (&maybeIgnoreBuf1);
2064 static const size_t kZeroDigest_ = kDigester_ (
nullptr,
nullptr);
2065 return kZeroDigest_;
2068 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