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/Module.h"
25#include "Stroika/Foundation/Execution/Throw.h"
26#include "Stroika/Foundation/Math/Common.h"
28#include "Stroika/Foundation/Memory/Common.h"
38using Memory::MakeSharedPtr;
43static_assert (regular<String>);
45#if qStroika_Foundation_Characters_AsPathAutoMapMSYSAndCygwin
51 template <
typename CHAR_T>
52 inline bool InReadOnlyImage_ (
const basic_string_view<CHAR_T>& s)
54 return Execution::IsAddressReadOnlyAppLifetime (as_bytes (span{s.data (), s.size ()})) ==
true;
75 struct StringRepHelperAllFitInSize_ :
String {
76 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
77 struct Rep :
public _IRep {
79 using inherited = _IRep;
82 span<const CHAR_T> _fData;
84#if qStroika_Foundation_Debug_AssertionsChecked
86 mutable unsigned int fOutstandingIterators_{};
91 Rep (span<const CHAR_T> s)
92 requires (not same_as<CHAR_T, char8_t>)
95 if constexpr (same_as<CHAR_T, char> or same_as<CHAR_T, char8_t>) {
96 Require (Character::IsASCII (s));
99 if constexpr (same_as<CHAR_T, char16_t> or (same_as<CHAR_T, wchar_t> and
sizeof (
wchar_t) == 2)) {
103 Rep& operator= (span<const CHAR_T> s)
105#if qStroika_Foundation_Debug_AssertionsChecked
106 Require (fOutstandingIterators_ == 0);
108 if constexpr (same_as<CHAR_T, char> or same_as<CHAR_T, char8_t>) {
109 Require (Character::IsASCII (s));
111 if constexpr (same_as<CHAR_T, char16_t> or (same_as<CHAR_T, wchar_t> and
sizeof (
wchar_t) == 2)) {
120 virtual Character GetAt (
size_t index)
const noexcept override
122 Require (index < _fData.size ());
124 return Character{
static_cast<char32_t> (_fData[index])};
126 virtual PeekSpanData PeekData (optional<PeekSpanData::StorageCodePointType> )
const noexcept override
129 if constexpr (same_as<CHAR_T, ASCII>) {
130 return PeekSpanData{PeekSpanData::StorageCodePointType::eAscii, {.fAscii = _fData}};
132 if constexpr (same_as<CHAR_T, Latin1>) {
133 return PeekSpanData{PeekSpanData::StorageCodePointType::eSingleByteLatin1, {.fSingleByteLatin1 = _fData}};
135 else if constexpr (
sizeof (CHAR_T) == 2) {
137 return PeekSpanData{PeekSpanData::StorageCodePointType::eChar16,
138 {.fChar16 = span<const char16_t>{
reinterpret_cast<const char16_t*
> (_fData.data ()), _fData.size ()}}};
140 else if constexpr (
sizeof (CHAR_T) == 4) {
142 return PeekSpanData{PeekSpanData::StorageCodePointType::eChar32,
143 {.fChar32 = span<const char32_t>{
reinterpret_cast<const char32_t*
> (_fData.data ()), _fData.size ()}}};
150 virtual shared_ptr<Iterable<Character>::_IRep> Clone ()
const override
159 span<const CHAR_T> fData_;
161#if qStroika_Foundation_Debug_AssertionsChecked
162 const Rep* fOwningRep_;
164 MyIterRep_ (span<const CHAR_T> data
172 , fOwningRep_{dbgRep}
175#if qStroika_Foundation_Debug_AssertionsChecked
176 ++fOwningRep_->fOutstandingIterators_;
179#if qStroika_Foundation_Debug_AssertionsChecked
180 virtual ~MyIterRep_ ()
override
182 Require (fOwningRep_->fOutstandingIterators_ > 0);
183 --fOwningRep_->fOutstandingIterators_;
187 virtual unique_ptr<Iterator<Character>::IRep> Clone ()
const override
189 return make_unique<MyIterRep_> (fData_.subspan (fIdx_)
196 virtual bool AtEnd ()
const override
198 Assert (fIdx_ <= fData_.size ());
199 return fIdx_ == fData_.size ();
201 virtual optional<Character> Current ()
const override
203 if (fIdx_ < fData_.size ()) {
204 return Character{
static_cast<char32_t> (fData_[fIdx_])};
210 virtual optional<Character> More ()
override
212 Require (fIdx_ < fData_.size ());
214 if (fIdx_ < fData_.size ()) [[likely]] {
216 return Character{
static_cast<char32_t> (fData_[fIdx_])};
222 virtual bool Equals (
const IRep* rhs)
const override
226 const MyIterRep_* rrhs = Debug::UncheckedDynamicCast<const MyIterRep_*> (rhs);
227 return fData_.data () == rrhs->fData_.data () and fIdx_ == rrhs->fIdx_;
239 virtual size_t size ()
const override
241 return _fData.size ();
243 virtual bool empty ()
const override
245 return _fData.empty ();
250 return inherited::Find (findFirst, that, seq);
259 struct DynamicallyAllocatedString : StringRepHelperAllFitInSize_ {
260 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
263 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
266 Rep (span<const CHAR_T> t1)
267 : inherited{mkBuf_ (t1)}
271 Rep (
const Rep&) =
delete;
274 nonvirtual Rep& operator= (
const Rep&) =
delete;
277 virtual ~Rep ()
override
279 delete[] this->_fData.data ();
283 static span<CHAR_T> mkBuf_ (
size_t length)
285 size_t capacity = AdjustCapacity_ (length);
286 Assert (length <= capacity);
287 if constexpr (kAddNullTerminator_) {
288 Assert (length + 1 <= capacity);
290 CHAR_T* newBuf =
new CHAR_T[capacity];
291 return span{newBuf, capacity};
293 static span<CHAR_T> mkBuf_ (span<const CHAR_T> t1)
295 size_t len = t1.size ();
296 span<CHAR_T> buf = mkBuf_ (len);
297 Assert (buf.size () >= len);
298 auto result = Memory::CopyBytes (t1, buf);
299 if constexpr (kAddNullTerminator_) {
300 Assert (len + 1 <= buf.size ());
301 *(buf.data () + len) =
'\0';
308 virtual const wchar_t* c_str_peek () const noexcept
override
311 if constexpr (kAddNullTerminator_) {
312 Assert (*(this->_fData.data () + this->_fData.size ()) ==
'\0');
313 return reinterpret_cast<const wchar_t*
> (this->_fData.data ());
322 static constexpr bool kAddNullTerminator_ =
sizeof (CHAR_T) ==
sizeof (
wchar_t);
325 static size_t AdjustCapacity_ (
size_t initialCapacity)
327 size_t result = initialCapacity;
328 if constexpr (kAddNullTerminator_) {
342 struct FixedCapacityInlineStorageString_ : StringRepHelperAllFitInSize_ {
343 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T,
size_t CAPACITY>
344 struct Rep final :
public StringRepHelperAllFitInSize_::Rep<CHAR_T>,
347 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
350 bool IncludesNullTerminator_ ()
const
352 if constexpr (
sizeof (CHAR_T) ==
sizeof (
wchar_t)) {
353 return this->_fData.size () < CAPACITY;
361 CHAR_T fBuf_[CAPACITY];
364 Rep (span<const CHAR_T> t1)
370 Require (t1.size () <= CAPACITY);
371 inherited::operator= (Memory::CopyBytes (t1, span<CHAR_T>{fBuf_}));
372 if (IncludesNullTerminator_ ()) {
373 Assert (t1.size () + 1 <= CAPACITY);
374 fBuf_[t1.size ()] = CHAR_T{
'\0'};
378 Rep (
const Rep&) =
delete;
381 nonvirtual Rep& operator= (
const Rep&) =
delete;
385 virtual const wchar_t* c_str_peek () const noexcept
override
387 if (IncludesNullTerminator_ ()) {
388 Assert (*(this->_fData.data () + this->_fData.size ()) ==
'\0');
389 return reinterpret_cast<const wchar_t*
> (this->_fData.data ());
401 struct StringConstant_ :
public StringRepHelperAllFitInSize_ {
404 template <IUNICODECanUnambiguouslyConvertFrom CHAR_T>
405 class DirectIndexRep final :
public StringRepHelperAllFitInSize_::Rep<CHAR_T>,
408 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
411 DirectIndexRep (span<const CHAR_T> s)
418 virtual const wchar_t* c_str_peek () const noexcept
override
428 struct StdStringDelegator_ :
public StringRepHelperAllFitInSize_ {
431 template <IStdBasicStringCompatibleCharacter CHAR_T>
434 using inherited = StringRepHelperAllFitInSize_::Rep<CHAR_T>;
437 Rep (basic_string<CHAR_T>&& s)
438 : inherited{span<const CHAR_T>{}}
439 , fMovedData_{move (s)}
441 inherited::operator= (span{fMovedData_.data (), fMovedData_.size ()});
446 virtual const wchar_t* c_str_peek () const noexcept
override
448 if constexpr (same_as<CHAR_T, wchar_t>) {
449 return fMovedData_.c_str ();
457 basic_string<CHAR_T> fMovedData_;
464 struct StringWithCStr_ :
public String {
468 shared_ptr<_IRep> fUnderlyingRep_;
473 Rep (
const shared_ptr<_IRep>& underlyingRep)
474 : fUnderlyingRep_{underlyingRep}
478 auto wideSpan = String::GetData<wchar_t> (underlyingRep->PeekData (nullopt), &possibleUsedBuf);
479 fCString_.assign (wideSpan.begin (), wideSpan.end ());
484 virtual shared_ptr<Iterable<Character>::_IRep> Clone ()
const override
486 return fUnderlyingRep_->Clone ();
490 return fUnderlyingRep_->MakeIterator ();
492 virtual size_t size ()
const override
494 return fUnderlyingRep_->size ();
496 virtual bool empty ()
const override
498 return fUnderlyingRep_->empty ();
503 return fUnderlyingRep_->Find (findFirst, that, seq);
508 virtual Character GetAt (
size_t index)
const noexcept override
510 return fUnderlyingRep_->GetAt (index);
512 virtual PeekSpanData PeekData ([[maybe_unused]] optional<PeekSpanData::StorageCodePointType> preferred)
const noexcept override
514 return fUnderlyingRep_->PeekData (preferred);
516 virtual const wchar_t* c_str_peek () const noexcept
override
518 return fCString_.c_str ();
525 template <
typename FACET>
526 struct deletable_facet_ final : FACET {
527 template <
typename... Args>
528 deletable_facet_ (Args&&... args)
529 : FACET{forward<Args> (args)...}
532 ~deletable_facet_ () =
default;
535 using CodeCvtByName_ = deletable_facet_<codecvt_byname<wchar_t, char, mbstate_t>>;
539 thread_local bool tCodeCvtByNameCacheGone_{
false};
545 shared_ptr<const CodeCvtByName_> GetCodeCvtByName_ (
const locale& l)
547 if (tCodeCvtByNameCacheGone_) [[unlikely]] {
548 return MakeSharedPtr<CodeCvtByName_> (l.name ());
552 shared_ptr<const CodeCvtByName_> fCodeCvt;
555 optional<Entry_> fEntry;
558 tCodeCvtByNameCacheGone_ =
true;
561 static thread_local Cache_ tCache_;
562 if (not tCache_.fEntry or tCache_.fEntry->fLocale != l) [[unlikely]] {
563 tCache_.fEntry.emplace (Entry_{l, MakeSharedPtr<CodeCvtByName_> (l.name ())});
565 return tCache_.fEntry->fCodeCvt;
574const wregex& Characters::Private_::RegularExpression_GetCompiled (
const RegularExpression& regExp)
576 return regExp.GetCompiled ();
585shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<ASCII>& str)
591 return mk_ (span{str.data (), str.size ()});
594shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char8_t>& str)
602shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char16_t>& str)
607 return mk_ (span<const char16_t>{str.data (), str.size ()});
610shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<char32_t>& str)
615 return mk_ (span<const char32_t>{str.data (), str.size ()});
618shared_ptr<String::_IRep> String::CTORFromBasicStringView_ (
const basic_string_view<wchar_t>& str)
660 codecvt_base::result result =
662 if (result != codecvt_base::ok) [[
unlikely]] {
669shared_ptr<String::_IRep> String::mkEmpty_ ()
676template <
typename CHAR_T>
677inline auto String::mk_nocheck_ (span<const CHAR_T> s) -> shared_ptr<_IRep>
678 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>)
681 if constexpr (same_as<CHAR_T, ASCII>) {
684 else if constexpr (same_as<CHAR_T, Latin1>) {
687 else if constexpr (
sizeof (CHAR_T) == 2) {
702 constexpr size_t kBaseOfFixedBufSize_ =
sizeof (StringRepHelperAllFitInSize_::Rep<CHAR_T>);
703 static_assert (kBaseOfFixedBufSize_ < 64);
705 static_assert (kBaseOfFixedBufSize_ == 3 *
sizeof (
void*));
706 if constexpr (
sizeof (
void*) == 4) {
707 static_assert (kBaseOfFixedBufSize_ == 12);
709 else if constexpr (
sizeof (
void*) == 8) {
710 static_assert (kBaseOfFixedBufSize_ == 24);
713 constexpr size_t kOverheadSizeForMakeShared_ = qStroika_Platform_Windows ? (
sizeof (
void*) == 4 ? 12 : 16) :
sizeof (
unsigned long) * 2;
714#if qStroika_Platform_Windows
715 static_assert (kOverheadSizeForMakeShared_ ==
sizeof (_Ref_count_base));
717 static constexpr size_t kNElts1_ = (64 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
718 static constexpr size_t kNElts2_ = (96 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
719 static constexpr size_t kNElts3_ = (128 - kBaseOfFixedBufSize_ - kOverheadSizeForMakeShared_) /
sizeof (CHAR_T);
723 if constexpr (
sizeof (
void*) == 4) {
724 static_assert (kNElts1_ == 40);
725 static_assert (kNElts2_ == 72);
726 static_assert (kNElts3_ == 104);
728 if constexpr (
sizeof (
void*) == 8) {
729 static_assert (kNElts1_ == 24);
730 static_assert (kNElts2_ == 56);
731 static_assert (kNElts3_ == 88);
736 static_assert (kNElts2_ > kNElts1_);
737 static_assert (kNElts3_ > kNElts2_);
739 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts1_>) == 64 - kOverheadSizeForMakeShared_);
740 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts2_>) == 96 - kOverheadSizeForMakeShared_);
741 static_assert (
sizeof (FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts3_>) == 128 - kOverheadSizeForMakeShared_);
743 size_t sz = s.size ();
744 if (sz <= kNElts1_) {
745 return MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts1_>> (s);
747 else if (sz <= kNElts2_) {
748 return MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts2_>> (s);
750 else if (sz <= kNElts3_) {
751 return MakeSharedPtr<FixedCapacityInlineStorageString_::Rep<CHAR_T, kNElts3_>> (s);
753 return MakeSharedPtr<DynamicallyAllocatedString::Rep<CHAR_T>> (s);
757auto String::mk_ (basic_string<char>&& s) -> shared_ptr<_IRep>
760 return MakeSharedPtr<StdStringDelegator_::Rep<ASCII>> (move (s));
764auto String::mk_ (basic_string<char16_t>&& s) -> shared_ptr<_IRep>
767 return MakeSharedPtr<StdStringDelegator_::Rep<char16_t>> (move (s));
770 Memory::StackBuffer<char32_t> wideUnicodeBuf{Memory::eUninitialized, UTFConvert::ComputeTargetBufferSize<char32_t> (span{s.data (), s.size ()})};
771 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (span{s.data (), s.size ()}, span{wideUnicodeBuf})));
775auto String::mk_ (basic_string<char32_t>&& s) -> shared_ptr<_IRep>
777 return MakeSharedPtr<StdStringDelegator_::Rep<char32_t>> (move (s));
781auto String::mk_ (basic_string<wchar_t>&& s) -> shared_ptr<_IRep>
783 if constexpr (
sizeof (wchar_t) == 2) {
785 return MakeSharedPtr<StdStringDelegator_::Rep<wchar_t>> (move (s));
789 UTFConvert::ComputeTargetBufferSize<char32_t> (span{s.data (), s.size ()})};
790 return mk_nocheck_ (Memory::ConstSpan (
UTFConvert::kThe.ConvertSpan (span{s.data (), s.size ()}, span{wideUnicodeBuf})));
793 return MakeSharedPtr<StdStringDelegator_::Rep<wchar_t>> (move (s));
807 return mk_ (span{buf});
810void String::SetCharAt (
Character c,
size_t i)
815 Require (i <
size ());
818 Require (i <
size ());
826 Require (at <=
size ());
848 _SafeReadRepAccessor
accessor{
this};
858 span
s1 = d.subspan (0,
from);
859 span
s2 = d.subspan (
to);
861 Memory::CopyBytes (
s2,
bufSpan.subspan (
s1.size ()));
869 if (
auto o =
tmp.Find (c, eWithCase)) {
876 if (
auto o = this->
Find (subString, eWithCase)) {
887 while (
auto o =
tmp.Find (c, eWithCase)) {
910 if (
co == eWithCase) {
941 case eCaseInsensitive: {
944 if (i->ToLowerCase () ==
lcc) {
958optional<size_t>
String::Find (
const String& subString,
size_t startAt, CompareOptions co)
const
961 _SafeReadRepAccessor
accessor{
this};
974 case eCaseInsensitive: {
977 if (
accessor._ConstGetRep ().GetAt (i +
j).ToLowerCase () !=
subString[
j].ToLowerCase ()) {
1008 if (
res.size () >= 1) {
1017 vector<size_t> result;
1049 Assert (
match.size () != 0);
1050 size_t n =
match.size ();
1052 for (
size_t j = 1;
j <
n; ++
j) {
1073 _SafeReadRepAccessor accessor{
this};
1074 const _IRep& useRep = accessor._ConstGetRep ();
1075 size_t length = useRep.size ();
1076 for (
size_t i = length; i > 0; --i) {
1077 if (useRep.
GetAt (i - 1) == c) {
1096 for (
size_t i =
limit; i > 0; --i) {
1120 _SafeReadRepAccessor
accessor{
this};
1121 if (
accessor._ConstGetRep ().size () == 0) {
1133#if qStroika_Foundation_Debug_AssertionsChecked
1141#if qStroika_Foundation_Debug_AssertionsChecked
1149 _SafeReadRepAccessor
accessor{
this};
1162 _SafeReadRepAccessor
accessor{
this};
1168#if qStroika_Foundation_Debug_AssertionsChecked
1176#if qStroika_Foundation_Debug_AssertionsChecked
1206 for (
size_t i = 1; i <
base_match.size (); ++i) {
1303 for (
size_t i = 0; i !=
len; ++i) {
1335 Assert (
ofi->first <=
ofi->second);
1432String String::SubString_ (
const _SafeReadRepAccessor& thisAccessor,
size_t from,
size_t to)
const
1444 switch (
psd.fInCP) {
1459 return mk_ (
psd.fSingleByteLatin1.subspan (
from,
to -
from));
1461 case PeekSpanData::eChar16: {
1469 case PeekSpanData::eChar32: {
1491 return *
this + *
this;
1494 for (
unsigned int i = 0; i < count; ++i) {
1506 _SafeReadRepAccessor
accessor{
this};
1508 for (
size_t i = 0; i <
length; ++i) {
1522 for (
size_t i = 0; i <
length; ++i) {
1536#if qStroika_Foundation_Debug_AssertionsChecked
1542#if qStroika_Foundation_Debug_AssertionsChecked
1551 _SafeReadRepAccessor
accessor{
this};
1553 switch (
psd.fInCP) {
1560 case PeekSpanData::eChar32: {
1571 _SafeReadRepAccessor
accessor{
this};
1616#if qStroika_Foundation_Debug_AssertionsChecked
1622#if qStroika_Foundation_Debug_AssertionsChecked
1628#if qStroika_Foundation_Debug_AssertionsChecked
1635 _SafeReadRepAccessor
accessor{
this};
1637 switch (
psd.fInCP) {
1644 case PeekSpanData::eChar32: {
1689#if qStroika_Foundation_Debug_AssertionsChecked
1695#if qStroika_Foundation_Debug_AssertionsChecked
1701#if qStroika_Foundation_Debug_AssertionsChecked
1707 _SafeReadRepAccessor
accessor{
this};
1709 switch (
psd.fInCP) {
1716 case PeekSpanData::eChar32: {
1731 size_t n = result.
size ();
1732 for (
size_t i = 0; i <
n; ++i) {
1739 for (; i <
n; ++i) {
1754 for (
const String& i : list) {
1757 if (result.
empty ()) {
1758 return result.
str ();
1769 _SafeReadRepAccessor
accessor{
this};
1773 for (
auto c :
psd.fAscii) {
1779 result.push_back (c);
1791 result.push_back (c);
1796 return result.
str ();
1807 _SafeReadRepAccessor
accessor{
this};
1811 for (
auto c :
psd.fAscii) {
1817 result.push_back (c);
1829 result.push_back (c);
1834 return result.
str ();
1856 case StringShorteningPreference::ePreferKeepLeft:
1858 case StringShorteningPreference::ePreferKeepRight:
1860 case StringShorteningPreference::ePreferKeepMid:
1873 if (
keepPref == StringShorteningPreference::ePreferKeepMid) {
1885 case StringShorteningPreference::ePreferKeepLeft:
1887 case StringShorteningPreference::ePreferKeepRight:
1889 case StringShorteningPreference::ePreferKeepMid:
1911 codecvt_base::result result =
1913 if (result != codecvt_base::ok) [[
unlikely]] {
1938 if (result != codecvt_base::ok) [[
unlikely]] {
1949void String::erase (
size_t from)
1954void String::erase (
size_t from,
size_t count)
1965const wchar_t* String::c_str () const noexcept
1969 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1970 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1971 return const_cast<String*
> (
this)->c_str ();
1972 DISABLE_COMPILER_MSC_WARNING_END (4996);
1973 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
1974 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
1976const wchar_t* String::c_str ()
1980 _SafeReadRepAccessor
accessor{
this};
1981 const wchar_t* result =
accessor._ConstGetRep ().c_str_peek ();
1982 if (result ==
nullptr) {
1984 result = _SafeReadRepAccessor{
this}._ConstGetRep ().c_str_peek ();
1992[[noreturn]]
void String::ThrowInvalidAsciiException_ ()
1998#if qStroika_Foundation_Characters_AsPathAutoMapMSYSAndCygwin
2004 static const String kMSYSDrivePrefix_ =
"/"sv;
2005 static const String kCygrivePrefix_ =
"/cygdrive/"sv;
2006 if (StartsWith (kCygrivePrefix_)) {
2008 if (ss.
length () > 1 and ss[0].IsASCII () and ss[0].IsAlphabetic () and ss[1] ==
'/') {
2009 wstring w = ss.
As<wstring> ();
2010 w.insert (w.begin () + 1,
':');
2011 return filesystem::path{w};
2014 if (StartsWith (kMSYSDrivePrefix_)) {
2016 if (ss.
length () > 1 and ss[0].IsASCII () and ss[0].IsAlphabetic () and ss[1] ==
'/') {
2017 wstring w = ss.
As<wstring> ();
2018 w.insert (w.begin () + 1,
':');
2019 return filesystem::path{w};
2022 return filesystem::path{As<wstring> ()};
2035 if (isLast and fSpecialSeparatorForLastPair) [[unlikely]] {
2036 sb << *fSpecialSeparatorForLastPair;
2050namespace Stroika::Foundation::Traversal {
2055 using namespace Characters;
2056#if qStroika_Foundation_Debug_AssertionsChecked
2062 size_t cnt = this->size ();
2063 this->Apply ([&, idx = 0u] (
const String& i)
mutable {
2068 if (finalSeparator and idx + 1 == cnt) [[unlikely]] {
2069 sb << *finalSeparator;
2078#if qStroika_Foundation_Debug_AssertionsChecked
2079 Ensure (sb == referenceResult);
2093 span<const wchar_t> sData = s.
GetData (&maybeIgnoreBuf1);
2094 out.write (sData.data (), sData.size ());
2107size_t std::hash<String>::operator() (
const String& arg)
const
2109 using namespace Cryptography::Digest;
2110 using DIGESTER = Digester<Algorithm::SuperFastHash>;
2111 static constexpr DIGESTER kDigester_{};
2116 span<const char8_t> s = arg.
GetData (&maybeIgnoreBuf1);
2118 static const size_t kZeroDigest_ = kDigester_ (
nullptr,
nullptr);
2119 return kZeroDigest_;
2122 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
Is this blank, and a place text may break (between words, tokens, lines ...)? The C standard white-sp...
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
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.
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
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)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
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