22#ifndef __has_declspec_attribute
23#define __has_declspec_attribute(x) 0
26#ifdef SIMSTR_IN_SHARED
27 #if defined(_MSC_VER) || (defined(__clang__) && __has_declspec_attribute(dllexport))
29 #define SIMSTR_API __declspec(dllexport)
31 #define SIMSTR_API __declspec(dllimport)
33 #elif (defined(__GNUC__) || defined(__GNUG__)) && defined(SIMSTR_EXPORT)
34 #define SIMSTR_API __attribute__((visibility("default")))
41const bool isWindowsOs =
48const bool isx64 =
sizeof(
void*) == 8;
51#define _no_unique_address msvc::no_unique_address
52#define decl_empty_bases __declspec(empty_bases)
54#define _no_unique_address no_unique_address
55#define decl_empty_bases
58#if defined __has_builtin
59# if __has_builtin (__builtin_mul_overflow) && __has_builtin (__builtin_add_overflow)
60# define HAS_BUILTIN_OVERFLOW
71#include <unordered_map>
88#pragma warning(disable : 4201)
94struct unicode_traits {};
97struct unicode_traits<u8s> {
112 static SIMSTR_API
size_t upper(
const u8s*& src,
size_t lenStr, u8s*& dest,
size_t lenBuf);
113 static SIMSTR_API
size_t lower(
const u8s*& src,
size_t len, u8s*& dest,
size_t lenBuf);
115 static SIMSTR_API
int compareiu(
const u8s* text1,
size_t len1,
const u8s* text2,
size_t len2);
117 static SIMSTR_API
size_t hashia(
const u8s* src,
size_t l);
118 static SIMSTR_API
size_t hashiu(
const u8s* src,
size_t l);
122struct unicode_traits<u16s> {
123 static SIMSTR_API
void upper(
const u16s* src,
size_t len, u16s* dest);
124 static SIMSTR_API
void lower(
const u16s* src,
size_t len, u16s* dest);
126 static SIMSTR_API
int compareiu(
const u16s* text1,
size_t len1,
const u16s* text2,
size_t len2);
127 static SIMSTR_API
size_t hashia(
const u16s* src,
size_t l);
128 static SIMSTR_API
size_t hashiu(
const u16s* src,
size_t l);
132struct unicode_traits<u32s> {
133 static SIMSTR_API
void upper(
const u32s* src,
size_t len, u32s* dest);
134 static SIMSTR_API
void lower(
const u32s* src,
size_t len, u32s* dest);
136 static SIMSTR_API
int compareiu(
const u32s* text1,
size_t len1,
const u32s* text2,
size_t len2);
137 static SIMSTR_API
size_t hashia(
const u32s* src,
size_t s);
138 static SIMSTR_API
size_t hashiu(
const u32s* src,
size_t s);
142struct unicode_traits<wchar_t> {
143 static void upper(
const wchar_t* src,
size_t len,
wchar_t* dest) {
144 unicode_traits<wchar_type>::upper(to_w(src), len, to_w(dest));
146 static void lower(
const wchar_t* src,
size_t len,
wchar_t* dest) {
147 unicode_traits<wchar_type>::lower(to_w(src), len, to_w(dest));
150 static int compareiu(
const wchar_t* text1,
size_t len1,
const wchar_t* text2,
size_t len2) {
151 return unicode_traits<wchar_type>::compareiu(to_w(text1), len1, to_w(text2), len2);
153 static size_t hashia(
const wchar_t* src,
size_t s) {
154 return unicode_traits<wchar_type>::hashia(to_w(src), s);
156 static size_t hashiu(
const wchar_t* src,
size_t s) {
157 return unicode_traits<wchar_type>::hashiu(to_w(src), s);
162constexpr const size_t npos =
static_cast<size_t>(-1);
166struct ch_traits : std::char_traits<K>{};
169concept is_const_pattern = N > 1 && N <= 17;
171template<
typename K,
size_t I>
173 constexpr static const size_t value = size_t(K(~0x7F)) << ((I - 1) *
sizeof(K) * 8) | _ascii_mask<K, I - 1>::value;
177struct _ascii_mask<K, 0> {
178 constexpr static const size_t value = 0;
183 using uns = std::make_unsigned_t<K>;
184 constexpr static const size_t WIDTH =
sizeof(size_t) /
sizeof(uns);
185 constexpr static const size_t VALUE = _ascii_mask<uns, WIDTH>::value;
189constexpr inline bool isAsciiUpper(K k) {
190 return k >=
'A' && k <=
'Z';
194constexpr inline bool isAsciiLower(K k) {
195 return k >=
'a' && k <=
'z';
199constexpr inline K makeAsciiLower(K k) {
200 return isAsciiUpper(k) ? k | 0x20 : k;
204constexpr inline K makeAsciiUpper(K k) {
205 return isAsciiLower(k) ? k & ~0x20 : k;
208enum TrimSides { TrimLeft = 1, TrimRight = 2, TrimAll = 3 };
209template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces = false>
212template<
typename K,
size_t N,
size_t L>
216concept FromIntNumber =
217 is_one_of_type<std::remove_cv_t<T>,
unsigned char, int, short, long,
long long, unsigned,
unsigned short,
unsigned long,
unsigned long long>::value;
220concept ToIntNumber = FromIntNumber<T> || is_one_of_type<T, int8_t>::value;
222#if defined(_MSC_VER) && _MSC_VER <= 1933
223template<
typename K,
typename... Args>
224using FmtString = std::_Basic_format_string<K, std::type_identity_t<Args>...>;
225#elif __clang_major__ >= 15 || _MSC_VER > 1933 || __GNUC__ >= 13
226template<
typename K,
typename... Args>
227using FmtString = std::basic_format_string<K, std::type_identity_t<Args>...>;
229template<
typename K,
typename... Args>
230using FmtString = std::basic_string_view<K>;
233template<
typename K,
bool I,
typename T>
236 need_sign(T& t) : sign(t < 0) {
237 if (sign && t != std::numeric_limits<T>::min())
240 void after(K*& ptr) {
246template<
typename K,
typename T>
247struct need_sign<K, false, T> {
263template<
bool CanNegate,
bool CheckOverflow,
typename T>
264struct result_type_selector {
269struct result_type_selector<true, false, T> {
270 using type = std::make_unsigned_t<T>;
273template<
unsigned Base>
274constexpr unsigned digit_width() {
293template<
typename T,
unsigned Base>
294constexpr unsigned max_overflow_digits = (
sizeof(T) * CHAR_BIT) / digit_width<Base>();
297struct convert_result {
304 inline static const uint8_t NUMBERS[] = {
305 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
306 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3,
307 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
308 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16,
309 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, 255, 255,
310 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
311 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
312 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
313 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
314 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
316 template<
typename K,
unsigned Base>
317 static constexpr std::make_unsigned_t<K> toDigit(K s) {
318 auto us =
static_cast<std::make_unsigned_t<K>
>(s);
319 if constexpr (Base <= 10) {
322 if constexpr (
sizeof(K) == 1) {
325 return us < 256 ? NUMBERS[us] : us;
330 template<
typename K, ToIntNumber T,
unsigned Base,
bool CheckOverflow>
332 static constexpr convert_result<T> parse(
const K* start,
const K* current,
const K* end,
bool negate) {
333 using u_type = std::make_unsigned_t<T>;
334 #ifndef HAS_BUILTIN_OVERFLOW
335 u_type maxMult = 0, maxAdd = 0;
336 if constexpr (CheckOverflow) {
337 maxMult = std::numeric_limits<u_type>::max() / Base;
338 maxAdd = std::numeric_limits<u_type>::max() % Base;
342 unsigned maxDigits = max_overflow_digits<u_type, Base>;
344 const K* from = current;
346 bool no_need_check_o_f = !CheckOverflow || end - current <= maxDigits;
348 if (no_need_check_o_f) {
350 const u_type digit = toDigit<K, Base>(*current);
354 number = number * Base + digit;
355 if (++current == end) {
361 for (;maxDigits; maxDigits--) {
362 const u_type digit = toDigit<K, Base>(*current);
366 number = number * Base + digit;
373 const u_type digit = toDigit<K, Base>(*current);
377 #ifdef HAS_BUILTIN_OVERFLOW
378 if (__builtin_mul_overflow(number, Base, &number) ||
379 __builtin_add_overflow(number, digit, &number)) {
381 if (number < maxMult || (number == maxMult && number < maxAdd)) {
382 number = number * Base + digit;
386 while(++current < end) {
387 if (toDigit<K, Base>(*current) >= Base) {
393 if (++current == end) {
401 if constexpr (std::is_signed_v<T>) {
402 result = negate ? 0 - number : number;
403 if constexpr (CheckOverflow) {
405 if (number > std::numeric_limits<T>::max() + (negate ? 1 : 0)) {
416 return {result, error, size_t(current - start)};
423 template<
typename K, ToIntNumber T,
unsigned Base = 0,
bool CheckOverflow = true,
bool SkipWs = true,
bool AllowSign = true>
424 requires(Base == -1 || (Base < 37 && Base != 1))
425 static constexpr convert_result<T> to_integer(
const K* start,
size_t len)
noexcept {
426 const K *ptr = start, *end = ptr + len;
428 if constexpr (SkipWs) {
429 while (ptr < end && std::make_unsigned_t<K>(*ptr) <=
' ')
433 if constexpr (std::is_signed_v<T>) {
434 if constexpr (AllowSign) {
439 }
else if (*ptr ==
'-') {
451 }
else if constexpr (AllowSign) {
460 if constexpr (Base == 0 || Base == -1) {
464 if (*ptr ==
'x' || *ptr ==
'X') {
465 return parse<K, T, 16, CheckOverflow>(start, ++ptr, end, negate);
467 if constexpr (Base == -1) {
468 if (*ptr ==
'b' || *ptr ==
'B') {
469 return parse<K, T, 2, CheckOverflow>(start, ++ptr, end, negate);
471 if (*ptr ==
'o' || *ptr ==
'O') {
472 return parse<K, T, 8, CheckOverflow>(start, ++ptr, end, negate);
475 return parse<K, T, 8, CheckOverflow>(start, --ptr, end, negate);
479 return parse<K, T, 10, CheckOverflow>(start, ptr, end, negate);
481 return parse<K, T, Base, CheckOverflow>(start, ptr, end, negate);
488SIMSTR_API std::optional<double> impl_to_double(
const K* start,
const K* end);
493template<
typename K,
typename Impl>
494class null_terminated {
502 constexpr const K* c_str()
const {
return static_cast<const Impl*
>(
this)->symbols(); }
505template<
typename K,
typename Impl,
bool Mutable>
class buffer_pointers;
515template<
typename K,
typename Impl>
516class buffer_pointers<K, Impl, false> {
517 constexpr const Impl& d()
const {
return *
static_cast<const Impl*
>(
this); }
525 constexpr const K* data()
const {
return d().symbols(); }
532 constexpr const K* begin()
const {
return d().symbols(); }
539 constexpr const K* end()
const {
return d().symbols() + d().length(); }
546 constexpr const K* cbegin()
const {
return d().symbols(); }
553 constexpr const K* cend()
const {
return d().symbols() + d().length(); }
556template<
typename K,
typename Impl>
557class buffer_pointers<K, Impl, true> :
public buffer_pointers<K, Impl, false> {
558 constexpr Impl& d() {
return *
static_cast<Impl*
>(
this); }
559 using base = buffer_pointers<K, Impl, false>;
567 constexpr const K* data()
const {
return base::data(); }
574 constexpr const K* begin()
const {
return base::begin(); }
581 constexpr const K* end()
const {
return base::end(); }
588 constexpr const K* cbegin()
const {
return base::cbegin(); }
595 constexpr const K* cend()
const {
return base::cend(); }
602 constexpr K* data() {
return d().str(); }
609 constexpr K* begin() {
return d().str(); }
616 constexpr K* end() {
return d().str() + d().length(); }
643template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
644class str_algs :
public buffer_pointers<K, Impl, Mutable> {
645 constexpr const Impl& d()
const noexcept {
646 return *
static_cast<const Impl*
>(
this);
648 constexpr size_t _len()
const noexcept {
651 constexpr const K* _str()
const noexcept {
652 return d().symbols();
654 constexpr bool _is_empty()
const noexcept {
655 return d().is_empty();
660 using str_piece = StrRef;
661 using traits = ch_traits<K>;
662 using uni = unicode_traits<K>;
663 using uns_type = std::make_unsigned_t<K>;
664 using my_type = Impl;
665 using base = str_algs<K, StrRef, Impl, Mutable>;
666 str_algs() =
default;
680 constexpr K*
place(K* ptr)
const noexcept {
681 size_t myLen = _len();
683 traits::copy(ptr, _str(), myLen);
699 size_t tlen = std::min(_len(), bufSize - 1);
701 traits::copy(buffer, _str(), tlen);
710 constexpr size_t size()
const {
720 constexpr operator str_piece() const noexcept {
721 return str_piece{_str(), _len()};
729 constexpr str_piece
to_str() const noexcept {
730 return {_str(), _len()};
738 template<
typename=
int>
requires is_one_of_std_char_v<K>
739 constexpr std::basic_string_view<K>
to_sv() const noexcept {
740 return {_str(), _len()};
748 template<
typename=
int>
requires is_one_of_std_char_v<K>
749 constexpr std::basic_string<K>
to_string() const noexcept {
750 return {_str(), _len()};
775 constexpr str_piece
operator()(ptrdiff_t from, ptrdiff_t len = 0) const noexcept {
776 size_t myLen = _len(), idxStart = from >= 0 ? from : myLen > -from ? myLen + from : 0,
777 idxEnd = len > 0 ? idxStart + len : myLen > -len ? myLen + len : 0;
780 if (idxStart > idxEnd)
782 return str_piece{_str() + idxStart, idxEnd - idxStart};
794 constexpr str_piece
mid(
size_t from,
size_t len = -1) const noexcept {
795 size_t myLen = _len(), idxStart = from, idxEnd = from > std::numeric_limits<size_t>::max() - len ? myLen : from + len;
798 if (idxStart > idxEnd)
800 return str_piece{_str() + idxStart, idxEnd - idxStart};
816 constexpr str_piece
from_to(
size_t from,
size_t to)
const noexcept {
817 return str_piece{_str() + from, to - from};
836 constexpr K
at(ptrdiff_t idx)
const {
837 return _str()[idx >= 0 ? idx : _len() + idx];
841 constexpr int compare(
const K* text,
size_t len)
const {
842 size_t myLen = _len();
843 int cmp = traits::compare(_str(), text, std::min(myLen, len));
844 return cmp == 0 ? (myLen > len ? 1 : myLen == len ? 0 : -1) : cmp;
865 constexpr int strcmp(
const K* text)
const {
866 size_t myLen = _len(), idx = 0;
867 const K* ptr = _str();
868 for (; idx < myLen; idx++) {
869 uns_type s1 = (uns_type)text[idx];
873 uns_type s2 = (uns_type)ptr[idx];
876 }
else if (s1 > s2) {
880 return text[idx] == 0 ? 0 : -1;
883 constexpr bool equal(
const K* text,
size_t len)
const noexcept {
884 return len == _len() && traits::compare(_str(), text, len) == 0;
894 constexpr bool equal(str_piece other)
const noexcept {
895 return equal(other.symbols(), other.length());
905 constexpr bool operator==(
const base& other)
const noexcept {
906 return equal(other._str(), other._len());
915 return compare(other._str(), other._len()) <=> 0;
923 template<typename T, size_t N = const_lit_for<K, T>::Count>
925 return N - 1 == _len() && traits::compare(_str(), other, N - 1) == 0;
933 template<typename T, size_t N = const_lit_for<K, T>::Count>
935 size_t myLen = _len();
936 int cmp = traits::compare(_str(), other, std::min(myLen, N - 1));
937 int res = cmp == 0 ? (myLen > N - 1 ? 1 : myLen == N - 1 ? 0 : -1) : cmp;
943 constexpr int compare_ia(
const K* text,
size_t len)
const noexcept {
945 return _is_empty() ? 0 : 1;
946 size_t myLen = _len(), checkLen = std::min(myLen, len);
947 const uns_type *ptr1 =
reinterpret_cast<const uns_type*
>(_str()), *ptr2 =
reinterpret_cast<const uns_type*
>(text);
949 uns_type s1 = *ptr1++, s2 = *ptr2++;
952 s1 = makeAsciiLower(s1);
953 s2 = makeAsciiLower(s2);
959 return myLen == len ? 0 : myLen > len ? 1 : -1;
970 return compare_ia(text.symbols(), text.length());
981 constexpr bool equal_ia(str_piece text)
const noexcept {
982 return text.length() == _len() && compare_ia(text.symbols(), text.length()) == 0;
992 constexpr bool less_ia(str_piece text)
const noexcept {
993 return compare_ia(text.symbols(), text.length()) < 0;
996 int compare_iu(
const K* text,
size_t len)
const noexcept {
998 return _is_empty() ? 0 : 1;
999 return uni::compareiu(_str(), _len(), text, len);
1010 return compare_iu(text.symbols(), text.length());
1022 return text.length() == _len() && compare_iu(text.symbols(), text.length()) == 0;
1033 return compare_iu(text.symbols(), text.length()) < 0;
1036 constexpr size_t find(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
1037 size_t lenText = _len();
1040 if (!lenPattern || offset >= lenText || offset + lenPattern > lenText)
1043 const K *text = _str(), *last = text + lenText - lenPattern, first = pattern[0];
1045 for (
const K* fnd = text + offset;; ++fnd) {
1046 fnd = traits::find(fnd, last - fnd, first);
1049 if (traits::compare(fnd + 1, pattern, lenPattern) == 0)
1050 return static_cast<size_t>(fnd - text);
1063 constexpr size_t find(str_piece pattern,
size_t offset = 0) const noexcept {
1082 template<
typename Exc,
typename ... Args>
requires std::is_constructible_v<Exc, Args...>
1083 constexpr size_t find_or_throw(str_piece pattern,
size_t offset = 0, Args&& ... args)
const noexcept {
1084 if (
auto fnd = find(pattern.symbols(), pattern.length(), offset); fnd != str::npos) {
1087 throw Exc(std::forward<Args>(args)...);
1099 constexpr size_t find_end(str_piece pattern,
size_t offset = 0) const noexcept {
1100 size_t fnd = find(pattern.
symbols(), pattern.
length(), offset);
1101 return fnd == str::npos ? fnd : fnd + pattern.
length();
1113 constexpr size_t find_or_all(str_piece pattern,
size_t offset = 0) const noexcept {
1114 auto fnd = find(pattern.
symbols(), pattern.
length(), offset);
1115 return fnd == str::npos ? _len() : fnd;
1128 auto fnd = find(pattern.
symbols(), pattern.
length(), offset);
1129 return fnd == str::npos ? _len() : fnd + pattern.
length();
1132 constexpr size_t find_last(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
1133 if (lenPattern == 1)
1134 return find_last(pattern[0], offset);
1135 size_t lenText = std::min(_len(), offset);
1138 if (!lenPattern || lenPattern > lenText)
1142 const K *text = _str() + lenPattern, last = pattern[lenPattern];
1143 lenText -= lenPattern;
1145 if (text[--lenText] == last) {
1146 if (traits::compare(text + lenText - lenPattern, pattern, lenPattern) == 0) {
1163 constexpr size_t find_last(str_piece pattern,
size_t offset = -1) const noexcept {
1164 return find_last(pattern.
symbols(), pattern.
length(), offset);
1177 size_t fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
1178 return fnd == str::npos ? fnd : fnd + pattern.
length();
1191 auto fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
1192 return fnd == str::npos ? _len() : fnd;
1205 size_t fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
1206 return fnd == str::npos ? _len() : fnd + pattern.
length();
1218 constexpr bool contains(str_piece pattern,
size_t offset = 0) const noexcept {
1219 return find(pattern, offset) != str::npos;
1231 constexpr size_t find(K s,
size_t offset = 0) const noexcept {
1232 size_t len = _len();
1234 const K *str = _str(), *fnd = traits::find(str + offset, len - offset, s);
1236 return static_cast<size_t>(fnd - str);
1251 size_t len = _len();
1253 const K *str = _str(), *fnd = traits::find(str + offset, len - offset, s);
1255 return static_cast<size_t>(fnd - str);
1260 template<
typename Op>
1261 constexpr void for_all_finded(
const Op& op,
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
1264 while (maxCount-- > 0) {
1265 size_t fnd = find(pattern, patternLen, offset);
1266 if (fnd == str::npos)
1269 offset = fnd + patternLen;
1284 template<
typename Op>
1285 constexpr void for_all_finded(
const Op& op, str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
1286 for_all_finded(op, pattern.
symbols(), pattern.
length(), offset, maxCount);
1289 std::vector<size_t> find_all(
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
1290 std::vector<size_t> result;
1291 for_all_finded([&](
auto f) { result.push_back(f); }, pattern, patternLen, offset, maxCount);
1306 constexpr std::vector<size_t>
find_all(str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
1307 return find_all(pattern.
symbols(), pattern.
length(), offset, maxCount);
1319 constexpr size_t find_last(K s,
size_t offset = -1) const noexcept {
1320 size_t len = std::min(_len(), offset);
1321 const K *text = _str();
1323 if (text[--len] == s)
1338 constexpr size_t find_first_of(str_piece pattern,
size_t offset = 0) const noexcept {
1339 return std::string_view{_str(), _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
1351 constexpr std::pair<size_t, size_t>
find_first_of_idx(str_piece pattern,
size_t offset = 0) const noexcept {
1352 const K* text = _str();
1353 size_t fnd = std::string_view{text, _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
1354 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
1367 return std::string_view{_str(), _len()}.find_first_not_of(std::string_view{pattern.str, pattern.len}, offset);
1379 constexpr size_t find_last_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
1380 return std::string_view{_str(), _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
1392 constexpr std::pair<size_t, size_t>
find_last_of_idx(str_piece pattern,
size_t offset = str::npos)
const noexcept {
1393 const K* text = _str();
1394 size_t fnd = std::string_view{text, _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
1395 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
1407 constexpr size_t find_last_not_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
1408 return std::string_view{_str(), _len()}.find_last_not_of(std::string_view{pattern.str, pattern.len}, offset);
1420 constexpr my_type
substr(ptrdiff_t from, ptrdiff_t len = 0)
const {
1421 return my_type{d()(from, len)};
1433 constexpr my_type
str_mid(
size_t from,
size_t len = -1)
const {
1434 return my_type{d().mid(from, len)};
1464 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
1466 auto [res, err, _] = int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
1497 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
1498 constexpr convert_result<T>
to_int() const noexcept {
1499 return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
1507 template<
bool SkipWS = true,
bool AllowPlus = true>
1509 size_t len = _len();
1510 const K* ptr = _str();
1511 if constexpr (SkipWS) {
1512 while (len && uns_type(*ptr) <=
' ') {
1517 if constexpr (AllowPlus) {
1518 if (len && *ptr == K(
'+')) {
1527 if constexpr(
sizeof(K) == 1) {
1529 if (std::from_chars(ptr, ptr + len, d).ec == std::errc{}) {
1535 return impl_to_double(ptr, ptr + len);
1543 template<
bool SkipWS = true>
requires (
sizeof(K) == 1)
1545 size_t len = _len();
1546 const K* ptr = _str();
1547 if constexpr (SkipWS) {
1548 while (len && uns_type(*ptr) <=
' ') {
1555 if (std::from_chars(ptr, ptr + len, d, std::chars_format::hex).ec == std::errc{}) {
1569 template<ToIntNumber T>
1581 t = res ? *res : std::nan(
"0");
1584 template<
typename T,
typename Op>
1585 constexpr T splitf(
const K* delimeter,
size_t lenDelimeter,
const Op& beforeFunc,
size_t offset)
const {
1586 size_t mylen = _len();
1587 std::conditional_t<std::is_same_v<T, void>, char, T> results;
1588 str_piece me{_str(), mylen};
1589 for (
int i = 0;; i++) {
1590 size_t beginOfDelim = find(delimeter, lenDelimeter, offset);
1591 if (beginOfDelim == str::npos) {
1592 str_piece last{me.symbols() + offset, me.length() - offset};
1593 if constexpr (std::is_invocable_v<Op, str_piece&>) {
1596 if constexpr (
requires { results.emplace_back(last); }) {
1597 if (last.is_same(me)) {
1600 results.emplace_back(d());
1602 results.emplace_back(last);
1604 }
else if constexpr (
requires { results.push_back(last); }) {
1605 if (last.is_same(me)) {
1608 results.push_back(d());
1610 results.push_back(last);
1612 }
else if constexpr (
requires {results[i] = last;} &&
requires{std::size(results);}) {
1613 if (i < std::size(results)) {
1614 if (last.is_same(me)) {
1624 str_piece piece{me.symbols() + offset, beginOfDelim - offset};
1625 if constexpr (std::is_invocable_v<Op, str_piece&>) {
1628 if constexpr (
requires { results.emplace_back(piece); }) {
1629 results.emplace_back(piece);
1630 }
else if constexpr (
requires { results.push_back(piece); }) {
1631 results.push_back(piece);
1632 }
else if constexpr (
requires { results[i] = piece; } &&
requires{std::size(results);}) {
1633 if (i < std::size(results)) {
1635 if (i == results.size() - 1) {
1640 offset = beginOfDelim + lenDelimeter;
1642 if constexpr (!std::is_same_v<T, void>) {
1676 template<
typename T,
typename Op>
1677 constexpr T
splitf(str_piece delimeter,
const Op& beforeFunc,
size_t offset = 0)
const {
1678 return splitf<T>(delimeter.
symbols(), delimeter.
length(), beforeFunc, offset);
1692 template<
typename T>
1693 constexpr T
split(str_piece delimeter,
size_t offset = 0)
const {
1694 return splitf<T>(delimeter.
symbols(), delimeter.
length(), 0, offset);
1710 constexpr bool starts_with(
const K* prefix,
size_t l)
const noexcept {
1711 return _len() >= l && 0 == traits::compare(_str(), prefix, l);
1720 return starts_with(prefix.symbols(), prefix.length());
1723 constexpr bool starts_with_ia(
const K* prefix,
size_t len)
const noexcept {
1724 size_t myLen = _len();
1728 const K* ptr1 = _str();
1730 K s1 = *ptr1++, s2 = *prefix++;
1733 if (makeAsciiLower(s1) != makeAsciiLower(s2))
1745 return starts_with_ia(prefix.symbols(), prefix.length());
1749 bool starts_with_iu(
const K* prefix,
size_t len)
const noexcept {
1750 return _len() >= len && 0 == uni::compareiu(_str(), len, prefix, len);
1759 return starts_with_iu(prefix.symbols(), prefix.length());
1764 constexpr bool prefix_in(
const K* text,
size_t len)
const noexcept {
1765 size_t myLen = _len();
1768 return !myLen || 0 == traits::compare(text, _str(), myLen);
1777 return prefix_in(text.symbols(), text.length());
1781 constexpr bool ends_with(
const K* suffix,
size_t len)
const noexcept {
1782 size_t myLen = _len();
1783 return len <= myLen && traits::compare(_str() + myLen - len, suffix, len) == 0;
1792 return ends_with(suffix.symbols(), suffix.length());
1796 constexpr bool ends_with_ia(
const K* suffix,
size_t len)
const noexcept {
1797 size_t myLen = _len();
1801 const K* ptr1 = _str() + myLen - len;
1803 K s1 = *ptr1++, s2 = *suffix++;
1806 if (makeAsciiLower(s1) != makeAsciiLower(s2))
1818 return ends_with_ia(suffix.symbols(), suffix.length());
1822 constexpr bool ends_with_iu(
const K* suffix,
size_t len)
const noexcept {
1823 size_t myLen = _len();
1824 return myLen >= len && 0 == uni::compareiu(_str() + myLen - len, len, suffix, len);
1833 return ends_with_iu(suffix.symbols(), suffix.length());
1842 const int sl = ascii_mask<K>::WIDTH;
1843 const size_t mask = ascii_mask<K>::VALUE;
1844 size_t len = _len();
1845 const uns_type* ptr =
reinterpret_cast<const uns_type*
>(_str());
1846 if constexpr (sl > 1) {
1847 const size_t roundMask =
sizeof(size_t) - 1;
1848 while (len >= sl && (
reinterpret_cast<size_t>(ptr) & roundMask) != 0) {
1854 if (*
reinterpret_cast<const size_t*
>(ptr) & mask)
1874 template<
typename R = my_type>
1876 return R::upperred_only_ascii_from(d());
1886 template<
typename R = my_type>
1888 return R::lowered_only_ascii_from(d());
1898 template<
typename R = my_type>
1900 return R::upperred_from(d());
1910 template<
typename R = my_type>
1912 return R::lowered_from(d());
1930 template<
typename R = my_type>
1931 R
replaced(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0)
const {
1932 return R::replaced_from(d(), pattern, repl, offset, maxCount);
1945 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename M,
size_t L = const_lit_for<K, M>::Count>
1946 constexpr expr_replaces<K, N - 1, L - 1>
replace_init(T&& pattern, M&& repl)
const {
1947 return expr_replaces<K, N - 1, L - 1>{d(), pattern, repl};
1950 template<StrType<K> From>
1951 constexpr static my_type make_trim_op(
const From& from,
const auto& opTrim) {
1952 str_piece sfrom = from, newPos = opTrim(sfrom);
1953 return newPos.is_same(sfrom) ? my_type{from} : my_type{newPos};
1955 template<TrimS
ides S, StrType<K> From>
1956 constexpr static my_type trim_static(
const From& from) {
1957 return make_trim_op(from, trim_operator<S, K,
static_cast<size_t>(-1),
true>{});
1960 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count, StrType<K> From>
1961 requires is_const_pattern<N>
1962 constexpr static my_type trim_static(
const From& from, T&& pattern) {
1963 return make_trim_op(from, trim_operator<S, K, N - 1, withSpaces>{pattern});
1966 template<TrimS
ides S,
bool withSpaces, StrType<K> From>
1967 constexpr static my_type trim_static(
const From& from, str_piece pattern) {
1968 return make_trim_op(from, trim_operator<S, K, 0, withSpaces>{{pattern}});
1978 template<
typename R = str_piece>
1980 return R::template trim_static<TrimSides::TrimAll>(d());
1990 template<
typename R = str_piece>
1992 return R::template trim_static<TrimSides::TrimLeft>(d());
2002 template<
typename R = str_piece>
2004 return R::template trim_static<TrimSides::TrimRight>(d());
2016 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2017 requires is_const_pattern<N>
2019 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
2031 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2032 requires is_const_pattern<N>
2034 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
2046 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2047 requires is_const_pattern<N>
2049 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
2068 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2069 requires is_const_pattern<N>
2071 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
2087 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2088 requires is_const_pattern<N>
2090 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
2106 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2107 requires is_const_pattern<N>
2109 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
2124 template<
typename R = str_piece>
2126 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
2138 template<
typename R = str_piece>
2140 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
2152 template<
typename R = str_piece>
2154 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
2170 template<
typename R = str_piece>
2172 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
2188 template<
typename R = str_piece>
2190 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
2206 template<
typename R = str_piece>
2208 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
2234struct simple_str : str_algs<K, simple_str<K>, simple_str<K>, false> {
2235 using symb_type = K;
2236 using my_type = simple_str<K>;
2238 const symb_type* str;
2241 simple_str() =
default;
2247 template<typename T, size_t N = const_lit_for<K, T>::Count>
2253 constexpr simple_str(
const K* p,
size_t l) noexcept : str(p), len(l) {}
2260 template<
typename S>
2261 requires(std::is_same_v<S, std::basic_string<K>&> || std::is_same_v<S, const std::basic_string<K>&>
2262 || std::is_same_v<S, std::basic_string_view<K>&> || std::is_same_v<S, const std::basic_string_view<K>&>)
2263 constexpr simple_str(S&& s) noexcept : str(s.data()), len(s.length()) {}
2275 constexpr const symb_type*
symbols() const noexcept {
2291 constexpr bool is_same(simple_str<K> other)
const noexcept {
2292 return str == other.str && len == other.len;
2301 return str >= other.str && str + len <= other.str + other.len;
2362struct simple_str_nt : simple_str<K>, null_terminated<K, simple_str_nt<K>> {
2363 using symb_type = K;
2364 using my_type = simple_str_nt<K>;
2365 using base = simple_str<K>;
2368 constexpr static const K empty_string[1] = {0};
2370 simple_str_nt() =
default;
2387 template<
typename T>
requires std::is_same_v<std::remove_const_t<std::remove_pointer_t<std::remove_cvref_t<T>>>, K>
2390 base::str = base::len ? p : empty_string;
2398 template<
typename S>
2399 requires(std::is_same_v<S, std::string&> || std::is_same_v<S, const std::string&>
2400 || std::is_same_v<S, std::string_view&> || std::is_same_v<S, const std::string_view&>)
2403 static const my_type empty_str;
2410 constexpr operator const K*()
const noexcept {
2422 if (from > base::len) {
2425 return {base::str + from, base::len - from};
2430inline const simple_str_nt<K> simple_str_nt<K>::empty_str{simple_str_nt<K>::empty_string, 0};
2432using ssa = simple_str<u8s>;
2433using ssw = simple_str<wchar_t>;
2434using ssu = simple_str<u16s>;
2435using ssuu = simple_str<u32s>;
2436using stra = simple_str_nt<u8s>;
2437using strw = simple_str_nt<wchar_t>;
2438using stru = simple_str_nt<u16s>;
2439using struu = simple_str_nt<u32s>;
2459 return text_.length() == str::npos;
2468 if (!text_.length()) {
2473 }
else if (text_.length() == str::npos) {
2474 return {
nullptr, 0};
2476 size_t pos = text_.find(delim_),
next = 0;
2477 if (pos == str::npos) {
2478 pos = text_.length();
2481 next = pos + delim_.length();
2490template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
2495template<
typename K,
bool withSpaces>
2496struct CheckSpaceTrim {
2497 constexpr bool is_trim_spaces(K s)
const {
2498 return s ==
' ' || (s >= 9 && s <= 13);
2502struct CheckSpaceTrim<K, false> {
2503 constexpr bool is_trim_spaces(K)
const {
2509struct CheckSymbolsTrim {
2510 simple_str<K> symbols;
2511 constexpr bool is_trim_symbols(K s)
const {
2512 return symbols.len != 0 && simple_str<K>::traits::find(symbols.str, symbols.len, s) !=
nullptr;
2516template<
typename K,
size_t N>
2517struct CheckConstSymbolsTrim {
2518 const const_lit_to_array<K, N> symbols;
2520 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
2521 constexpr CheckConstSymbolsTrim(T&& s) : symbols(std::forward<T>(s)) {}
2523 constexpr bool is_trim_symbols(K s)
const noexcept {
2524 return symbols.contain(s);
2529struct CheckConstSymbolsTrim<K, 0> {
2530 constexpr bool is_trim_symbols(K)
const {
2535template<
typename K,
size_t N>
2536struct SymbSelector {
2537 using type = CheckConstSymbolsTrim<K, N>;
2541struct SymbSelector<K, 0> {
2542 using type = CheckSymbolsTrim<K>;
2546struct SymbSelector<K, static_cast<size_t>(-1)> {
2547 using type = CheckConstSymbolsTrim<K, 0>;
2550template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces>
2551struct trim_operator : SymbSelector<K, N>::type, CheckSpaceTrim<K, withSpaces> {
2552 constexpr bool isTrim(K s)
const {
2553 return CheckSpaceTrim<K, withSpaces>::is_trim_spaces(s) || SymbSelector<K, N>::type::is_trim_symbols(s);
2555 constexpr simple_str<K> operator()(simple_str<K> from)
const {
2556 if constexpr ((S & TrimSides::TrimLeft) != 0) {
2558 if (isTrim(*from.str)) {
2565 if constexpr ((S & TrimSides::TrimRight) != 0) {
2566 const K* back = from.str + from.len - 1;
2568 if (isTrim(*back)) {
2579template<TrimS
ides S,
typename K>
2580using SimpleTrim = trim_operator<S, K, size_t(-1),
true>;
2582using trim_w = SimpleTrim<TrimSides::TrimAll, u16s>;
2583using trim_a = SimpleTrim<TrimSides::TrimAll, u8s>;
2584using triml_w = SimpleTrim<TrimSides::TrimLeft, u16s>;
2585using triml_a = SimpleTrim<TrimSides::TrimLeft, u8s>;
2586using trimr_w = SimpleTrim<TrimSides::TrimRight, u16s>;
2587using trimr_a = SimpleTrim<TrimSides::TrimRight, u8s>;
2589template<TrimSides S = TrimSides::TrimAll, bool withSpaces = false, typename K, typename T, size_t N = const_lit_for<K, T>::Count>
2590 requires is_const_pattern<N>
2591constexpr inline auto trimOp(T&& pattern) {
2592 return trim_operator<S, K, N - 1, withSpaces>{pattern};
2595template<TrimS
ides S = TrimS
ides::TrimAll,
bool withSpaces = false,
typename K>
2596constexpr inline auto trimOp(simple_str<K> pattern) {
2597 return trim_operator<S, K, 0, withSpaces>{pattern};
2600template<
typename Src,
typename Dest>
2601struct utf_convert_selector;
2604struct utf_convert_selector<u8s, u16s> {
2605 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
2606 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u16s* dest);
2610struct utf_convert_selector<u8s, u32s> {
2611 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
2612 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u32s* dest);
2616struct utf_convert_selector<u8s, wchar_t> {
2617 static size_t need_len(
const u8s* src,
size_t srcLen) {
2618 return utf_convert_selector<u8s, wchar_type>::need_len(src, srcLen);
2620 static size_t convert(
const u8s* src,
size_t srcLen,
wchar_t* dest) {
2621 return utf_convert_selector<u8s, wchar_type>::convert(src, srcLen, to_w(dest));
2626struct utf_convert_selector<u16s, u8s> {
2627 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
2628 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u8s* dest);
2632struct utf_convert_selector<u16s, u32s> {
2633 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
2634 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u32s* dest);
2638struct utf_convert_selector<u16s, u16s> {
2641 static size_t need_len(
const u16s* src,
size_t srcLen) {
2644 static size_t convert(
const u16s* src,
size_t srcLen, u16s* dest) {
2645 ch_traits<u16s>::copy(dest, src, srcLen + 1);
2651struct utf_convert_selector<u32s, u32s> {
2654 static size_t need_len(
const u32s* src,
size_t srcLen) {
2657 static size_t convert(
const u32s* src,
size_t srcLen, u32s* dest) {
2658 ch_traits<u32s>::copy(dest, src, srcLen + 1);
2664struct utf_convert_selector<u16s, wchar_t> {
2665 static size_t need_len(
const u16s* src,
size_t srcLen) {
2666 return utf_convert_selector<u16s, wchar_type>::need_len(src, srcLen);
2668 static size_t convert(
const u16s* src,
size_t srcLen,
wchar_t* dest) {
2669 return utf_convert_selector<u16s, wchar_type>::convert(src, srcLen, to_w(dest));
2674struct utf_convert_selector<u32s, u8s> {
2675 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
2676 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u8s* dest);
2680struct utf_convert_selector<u32s, u16s> {
2681 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
2682 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u16s* dest);
2686struct utf_convert_selector<u32s, wchar_t> {
2687 static size_t need_len(
const u32s* src,
size_t srcLen) {
2688 return utf_convert_selector<u32s, wchar_type>::need_len(src, srcLen);
2690 static size_t convert(
const u32s* src,
size_t srcLen,
wchar_t* dest) {
2691 return utf_convert_selector<u32s, wchar_type>::convert(src, srcLen, to_w(dest));
2696struct utf_convert_selector<wchar_t, u8s> {
2697 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2698 return utf_convert_selector<wchar_type, u8s>::need_len(to_w(src), srcLen);
2700 static size_t convert(
const wchar_t* src,
size_t srcLen, u8s* dest) {
2701 return utf_convert_selector<wchar_type, u8s>::convert(to_w(src), srcLen, dest);
2706struct utf_convert_selector<wchar_t, u16s> {
2707 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2708 return utf_convert_selector<wchar_type, u16s>::need_len(to_w(src), srcLen);
2710 static size_t convert(
const wchar_t* src,
size_t srcLen, u16s* dest) {
2711 return utf_convert_selector<wchar_type, u16s>::convert(to_w(src), srcLen, dest);
2716struct utf_convert_selector<wchar_t, u32s> {
2717 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2718 return utf_convert_selector<wchar_type, u32s>::need_len(to_w(src), srcLen);
2720 static size_t convert(
const wchar_t* src,
size_t srcLen, u32s* dest) {
2721 return utf_convert_selector<wchar_type, u32s>::convert(to_w(src), srcLen, dest);
2739template<
typename K,
typename Impl>
2740class from_utf_convertible {
2742 from_utf_convertible() =
default;
2743 using my_type = Impl;
2751 template<
typename O>
2752 requires(!std::is_same_v<O, K>)
2754 using worker = utf_convert_selector<O, K>;
2755 Impl* d =
static_cast<Impl*
>(
this);
2756 size_t len = init.
length();
2760 size_t need = worker::need_len(init.
symbols(), len);
2761 K* str = d->init(need);
2763 worker::convert(init.
symbols(), len, str);
2766 template<
typename O,
typename I,
bool M>
2767 requires(!std::is_same_v<O, K>)
2779template<
typename From,
typename To>
requires (!std::is_same_v<From, To>)
2781 using symb_type = To;
2782 using worker = utf_convert_selector<From, To>;
2786 size_t length()
const noexcept {
2787 return worker::need_len(source_.symbols(), source_.length());
2789 To* place(To* ptr)
const noexcept {
2790 return ptr + worker::convert(source_.symbols(), source_.length(), ptr);
2806template<
typename To,
typename From>
requires (!std::is_same_v<From, To>)
2815template<
typename A,
typename K>
2817 A::is_str_storable ==
true;
2818 std::is_same_v<typename A::symb_type, K>;
2825template<
typename A,
typename K>
2832template<
typename A,
typename K>
2877template<
typename K,
typename Impl,
typename Allocator>
2880 using my_type = Impl;
2881 using traits = ch_traits<K>;
2882 using allocator_t = Allocator;
2892 return *
static_cast<Allocator*
>(
this);
2894 constexpr const allocator_t& allocator()
const {
2895 return *
static_cast<const Allocator*
>(
this);
2898 using uni = unicode_traits<K>;
2900 constexpr Impl& d() noexcept {
2901 return *
static_cast<Impl*
>(
this);
2903 constexpr const Impl& d() const noexcept {
2904 return *
static_cast<const Impl*
>(
this);
2913 template<
typename... Args>
2914 explicit constexpr str_storable(Args&&... args) : Allocator(std::forward<Args>(args)...) {}
2924 K* ptr = d().init(other.
length());
2939 size_t l = pattern.
length(), allLen = l * repeat;
2941 K* ptr = d().init(allLen);
2942 for (
size_t i = 0; i < repeat; i++) {
2943 traits::copy(ptr, pattern.
symbols(), l);
2960 K* str = d().init(count);
2961 traits::assign(str, count, pad);
2979 size_t len = expr.length();
2981 *expr.place(d().init(len)) = 0;
2999 template<StrType<K> From>
3000 void init_replaced(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0) {
3001 auto findes = f.find_all(pattern, offset, maxCount);
3002 if (!findes.size()) {
3003 new (
this) my_type{f};
3006 size_t srcLen = f.length();
3007 size_t newSize = srcLen +
static_cast<ptrdiff_t
>(repl.len - pattern.len) * findes.size();
3010 new (
this) my_type{};
3014 K* ptr = d().init(newSize);
3015 const K* src = f.symbols();
3017 for (
const auto& s: findes) {
3018 size_t copyLen = s - from;
3020 traits::copy(ptr, src + from, copyLen);
3024 traits::copy(ptr, repl.str, repl.len);
3027 from = s + pattern.len;
3031 traits::copy(ptr, src + from, srcLen);
3037 template<StrType<K> From,
typename Op1,
typename... Args>
3038 requires std::is_constructible_v<allocator_t, Args...>
3039 static my_type changeCaseAscii(
const From& f,
const Op1& opMakeNeedCase, Args&&... args) {
3040 my_type result{std::forward<Args>(args)...};
3041 size_t len = f.length();
3043 const K* source = f.symbols();
3044 K* destination = result.init(len);
3045 for (
size_t l = 0; l < len; l++) {
3046 destination[l] = opMakeNeedCase(source[l]);
3055 template<
typename T,
bool Dummy = true>
3057 template<
typename From,
typename Op1,
typename... Args>
3058 requires std::is_constructible_v<allocator_t, Args...>
3059 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
3060 my_type result{std::forward<Args>(args)...};
3061 size_t len = f.length();
3063 opChangeCase(f.symbols(), len, result.init(len));
3070 template<
bool Dummy>
3071 struct ChangeCase<u8s, Dummy> {
3072 template<
typename From,
typename Op1,
typename... Args>
3073 requires std::is_constructible_v<allocator_t, Args...>
3074 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
3075 my_type result{std::forward<Args>(args)...};
3077 size_t len = f.length();
3079 const K* ptr = f.symbols();
3080 K* pWrite = result.init(len);
3082 const u8s* source = ptr;
3084 size_t newLen = opChangeCase(source, len, dest, len);
3088 result.set_size(newLen);
3089 }
else if (newLen > len) {
3092 size_t readed =
static_cast<size_t>(source - ptr);
3093 size_t writed =
static_cast<size_t>(dest - pWrite);
3094 pWrite = result.set_size(newLen);
3095 dest = pWrite + writed;
3096 opChangeCase(source, len - readed, dest, newLen - writed);
3106 inline static constexpr bool is_str_storable =
true;
3113 constexpr operator const K*()
const noexcept {
3114 return d().symbols();
3124 constexpr s_str_nt
to_nts(
size_t from = 0)
const {
3125 size_t len = d().
length();
3129 return {d().symbols() + from, len - from};
3137 constexpr operator s_str_nt()
const {
3138 return {d().symbols(), d().length()};
3178 template<
typename T,
typename... Args>
3179 requires std::is_constructible_v<allocator_t, Args...>
3180 static my_type
join(
const T& strings, s_str delimeter,
bool tail =
false,
bool skip_empty =
false, Args&&... args) {
3181 my_type result(std::forward<Args>(args)...);
3182 if (strings.size()) {
3183 if (strings.size() == 1 && (!delimeter.
length() || !tail)) {
3184 result = strings.front();
3186 size_t commonLen = 0;
3187 for (
const auto& t: strings) {
3188 size_t len = t.length();
3189 if (len > 0 || !skip_empty) {
3190 if (commonLen > 0) {
3191 commonLen += delimeter.len;
3196 commonLen += (tail && delimeter.len > 0 && (commonLen > 0 || (!skip_empty && strings.size() > 0))? delimeter.len : 0);
3198 K* ptr = result.init(commonLen);
3200 for (
const auto& t: strings) {
3201 size_t copyLen = t.length();
3202 if (delimeter.len > 0 && write != ptr && (copyLen || !skip_empty)) {
3203 ch_traits<K>::copy(write, delimeter.str, delimeter.len);
3204 write += delimeter.len;
3206 ch_traits<K>::copy(write, t.symbols(), copyLen);
3209 if (delimeter.len > 0 && tail && (write != ptr || (!skip_empty && strings.size() > 0))) {
3210 ch_traits<K>::copy(write, delimeter.str, delimeter.len);
3211 write += delimeter.len;
3215 result.create_empty();
3229 template<StrType<K> From,
typename... Args>
3230 requires std::is_constructible_v<allocator_t, Args...>
3232 return changeCaseAscii(f, makeAsciiUpper<K>, std::forward<Args>(args)...);
3242 template<StrType<K> From,
typename... Args>
3243 requires std::is_constructible_v<allocator_t, Args...>
3245 return changeCaseAscii(f, makeAsciiLower<K>, std::forward<Args>(args)...);
3259 template<StrType<K> From,
typename... Args>
3260 requires std::is_constructible_v<allocator_t, Args...>
3262 return ChangeCase<K>::changeCase(f, uni::upper, std::forward<Args>(args)...);
3276 template<StrType<K> From,
typename... Args>
3277 requires std::is_constructible_v<allocator_t, Args...>
3279 return ChangeCase<K>::changeCase(f, uni::lower, std::forward<Args>(args)...);
3297 template<StrType<K> From,
typename... Args>
3298 requires std::is_constructible_v<allocator_t, Args...>
3299 static my_type
replaced_from(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args) {
3300 return my_type{f, pattern, repl, offset, maxCount, std::forward<Args>(args)...};
3310 { a.allocate(size) } -> std::same_as<void*>;
3311 { a.deallocate(void_ptr) }
noexcept -> std::same_as<void>;
3314struct printf_selector {
3315 template<
typename K,
typename... T>
requires (is_one_of_std_char_v<K>)
3316 static int snprintf(K* buffer,
size_t count,
const K* format, T&&... args) {
3317 if constexpr (std::is_same_v<K, u8s>) {
3319 return std::snprintf(buffer, count, format, std::forward<T>(args)...);
3323 return _sprintf_p(buffer, count, format, args...);
3327 return std::swprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
3331 return _swprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
3335 template<
typename K>
requires (is_one_of_std_char_v<K>)
3336 static int vsnprintf(K* buffer,
size_t count,
const K* format, va_list args) {
3337 if constexpr (std::is_same_v<K, u8s>) {
3339 return std::vsnprintf(buffer, count, format, args);
3343 return _vsprintf_p(buffer, count, format, args);
3347 return std::vswprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args);
3351 return _vswprintf_p(buffer, count, format, args);
3357inline size_t grow2(
size_t ret,
size_t currentCapacity) {
3358 return ret <= currentCapacity ? ret : ret * 2;
3399template<
typename K,
typename Impl>
3402 using my_type = Impl;
3406 return *
static_cast<Impl*
>(
this);
3408 const Impl& d()
const {
3409 return *
static_cast<const Impl*
>(
this);
3411 size_t _len()
const noexcept {
3412 return d().length();
3414 const K* _str()
const noexcept {
3415 return d().symbols();
3418 using symb_type = K;
3419 using traits = ch_traits<K>;
3420 using uni = unicode_traits<K>;
3421 using uns_type = std::make_unsigned_t<K>;
3423 template<
typename Op>
3424 Impl& make_trim_op(
const Op& op) {
3425 str_piece me =
static_cast<str_piece
>(d()), pos = op(me);
3426 if (me.
length() != pos.length()) {
3427 if (me.
symbols() != pos.symbols())
3428 traits::move(
const_cast<K*
>(me.
symbols()), pos.symbols(), pos.length());
3429 d().set_size(pos.length());
3435 Impl& commonChangeCase() {
3436 size_t len = _len();
3438 Op(_str(), len,
str());
3445 template<
typename T,
bool Dummy = true>
3447 static Impl&
upper(Impl& obj) {
3448 return obj.template commonChangeCase<unicode_traits<K>::upper>();
3450 static Impl&
lower(Impl& obj) {
3451 return obj.template commonChangeCase<unicode_traits<K>::lower>();
3456 Impl& utf8CaseChange() {
3459 size_t len = _len();
3461 u8s* writePos =
str();
3462 const u8s *startData = writePos, *readPos = writePos;
3463 size_t newLen = Op(readPos, len, writePos, len);
3467 d().set_size(newLen);
3468 }
else if (newLen > len) {
3471 size_t readed =
static_cast<size_t>(readPos - startData);
3472 size_t writed =
static_cast<size_t>(writePos - startData);
3473 d().set_size(newLen);
3475 readPos = startData + readed;
3476 writePos =
const_cast<u8s*
>(startData) + writed;
3477 Op(readPos, len - readed, writePos, newLen - writed);
3482 template<
bool Dummy>
3483 struct CaseTraits<u8s, Dummy> {
3484 static Impl&
upper(Impl& obj) {
3485 return obj.template utf8CaseChange<unicode_traits<u8s>::upper>();
3487 static Impl&
lower(Impl& obj) {
3488 return obj.template utf8CaseChange<unicode_traits<u8s>::lower>();
3492 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count>
3493 Impl& makeTrim(T&& pattern) {
3494 return make_trim_op(trim_operator<S, K, N - 1, withSpaces>{pattern});
3497 template<TrimS
ides S,
bool withSpaces>
3498 Impl& makeTrim(str_piece pattern) {
3499 return make_trim_op(trim_operator<S, K, 0, withSpaces>{{pattern}});
3518 explicit operator K*()
noexcept {
3528 return make_trim_op(SimpleTrim<TrimSides::TrimAll, K>{});
3537 return make_trim_op(SimpleTrim<TrimSides::TrimLeft, K>{});
3546 return make_trim_op(SimpleTrim<TrimSides::TrimRight, K>{});
3556 template<typename T, size_t N = const_lit_for<K, T>::Count>
3557 requires is_const_pattern<N>
3559 return makeTrim<TrimSides::TrimAll, false>(pattern);
3569 template<typename T, size_t N = const_lit_for<K, T>::Count>
3570 requires is_const_pattern<N>
3572 return makeTrim<TrimSides::TrimLeft, false>(pattern);
3582 template<typename T, size_t N = const_lit_for<K, T>::Count>
3583 requires is_const_pattern<N>
3585 return makeTrim<TrimSides::TrimRight, false>(pattern);
3595 template<typename T, size_t N = const_lit_for<K, T>::Count>
3596 requires is_const_pattern<N>
3598 return makeTrim<TrimSides::TrimAll, true>(pattern);
3608 template<typename T, size_t N = const_lit_for<K, T>::Count>
3609 requires is_const_pattern<N>
3611 return makeTrim<TrimSides::TrimLeft, true>(pattern);
3621 template<typename T, size_t N = const_lit_for<K, T>::Count>
3622 requires is_const_pattern<N>
3624 return makeTrim<TrimSides::TrimRight, true>(pattern);
3635 return pattern.
length() ? makeTrim<TrimSides::TrimAll, false>(pattern) : d();
3646 return pattern.
length() ? makeTrim<TrimSides::TrimLeft, false>(pattern) : d();
3657 return pattern.
length() ? makeTrim<TrimSides::TrimRight, false>(pattern) : d();
3668 return makeTrim<TrimSides::TrimAll, true>(pattern);
3679 return makeTrim<TrimSides::TrimLeft, true>(pattern);
3690 return makeTrim<TrimSides::TrimRight, true>(pattern);
3700 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
3702 if (isAsciiLower(s))
3715 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
3717 if (isAsciiUpper(s))
3735 return CaseTraits<K>::upper(d());
3750 return CaseTraits<K>::lower(d());
3754 template<
typename T>
3755 Impl& changeImpl(
size_t from,
size_t len, T expr) {
3756 size_t myLen = _len();
3760 if (from + len > myLen) {
3764 size_t otherLen = expr.length();
3765 if (len == otherLen) {
3766 expr.place(buffer + from);
3768 size_t tailLen = myLen - from - len;
3769 if (len > otherLen) {
3770 expr.place(buffer + from);
3771 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
3772 d().set_size(myLen - (len - otherLen));
3774 buffer = d().set_size(myLen + otherLen - len);
3775 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
3776 expr.place(buffer + from);
3782 template<
typename T>
3783 Impl& appendImpl(T expr) {
3784 if (
size_t len = expr.length(); len) {
3785 size_t size = _len();
3786 expr.place(d().set_size(size + len) + size);
3791 template<
typename T>
3792 Impl& appendFromImpl(
size_t pos, T expr) {
3795 if (
size_t len = expr.length())
3796 expr.place(d().set_size(pos + len) + pos);
3803 inline static constexpr bool is_str_mutable =
true;
3813 return appendImpl<str_piece>(other);
3823 template<StrExprForType<K> A>
3825 return appendImpl<const A&>(expr);
3836 return appendImpl<str_piece>(other);
3846 template<StrExprForType<K> A>
3848 return appendImpl<const A&>(expr);
3865 return appendFromImpl<str_piece>(pos, other);
3881 template<StrExprForType<K> A>
3883 return appendFromImpl<const A&>(pos, expr);
3897 Impl&
change(
size_t from,
size_t len, str_piece other) {
3898 return changeImpl<str_piece>(from, len, other);
3912 template<StrExprForType<K> A>
3913 Impl&
change(
size_t from,
size_t len,
const A& expr) {
3914 return changeImpl<const A&>(from, len, expr);
3927 return changeImpl<str_piece>(to, 0, other);
3939 template<StrExprForType<K> A>
3941 return changeImpl<const A&>(to, 0, expr);
3954 return changeImpl<const empty_expr<K>&>(from, len, {});
3965 return changeImpl<str_piece>(0, 0, other);
3975 template<StrExprForType<K> A>
3977 return changeImpl<const A&>(0, 0, expr);
3993 Impl&
replace(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
3994 offset = d().find(pattern, offset);
3995 if (offset == str::npos) {
4000 size_t replLength = repl.
length(), patternLength = pattern.
length();
4002 if (patternLength == replLength) {
4006 for (
size_t i = 0; i < maxCount; i++) {
4007 traits::copy(ptr + offset, repl.
symbols(), replLength);
4008 offset = d().find(pattern, offset + replLength);
4009 if (offset == str::npos)
4012 }
else if (patternLength > replLength) {
4016 traits::copy(ptr + offset, repl.
symbols(), replLength);
4017 size_t posWrite = offset + replLength;
4019 offset += patternLength;
4021 for (
size_t i = 0; i < maxCount; i++) {
4022 size_t idx = d().find(pattern, offset);
4023 if (idx == str::npos)
4025 size_t lenOfPiece = idx - offset;
4026 traits::move(ptr + posWrite, ptr + offset, lenOfPiece);
4027 posWrite += lenOfPiece;
4028 traits::copy(ptr + posWrite, repl.
symbols(), replLength);
4029 posWrite += replLength;
4030 offset = idx + patternLength;
4032 size_t tailLen = _len() - offset;
4033 traits::move(ptr + posWrite, ptr + offset, tailLen);
4034 d().set_size(posWrite + tailLen);
4036 struct replace_grow_helper {
4037 replace_grow_helper(my_type& src, str_piece p, str_piece r,
size_t mc,
size_t d)
4038 : source(src), pattern(p), repl(r), maxCount(mc), delta(d) {}
4040 const str_piece pattern;
4041 const str_piece repl;
4045 K* reserve_for_copy{};
4046 size_t end_of_piece{};
4047 size_t total_length{};
4050 size_t finded[16] = {source.find(pattern, offset)};
4051 if (finded[0] == str::npos) {
4055 offset = finded[0] + pattern.
length();
4058 for (
size_t end = std::min(maxCount, std::size(finded)); idx < end; idx++, maxCount--) {
4059 finded[idx] = source.find(pattern, offset);
4060 if (finded[idx] == str::npos) {
4063 offset = finded[idx] + pattern.
length();
4066 bool needMore = maxCount > 0 && idx == std::size(finded) && offset < source.length() - pattern.
length();
4072 if (!reserve_for_copy) {
4075 end_of_piece = source.length();
4076 total_length = end_of_piece + all_delta;
4077 reserve_for_copy = source.alloc_for_copy(total_length);
4079 K* dst_start = reserve_for_copy;
4080 const K* src_start = source.symbols();
4082 size_t pos = finded[idx] + pattern.
length();
4083 size_t lenOfPiece = end_of_piece - pos;
4084 ch_traits<K>::move(dst_start + pos + all_delta, src_start + pos, lenOfPiece);
4085 ch_traits<K>::copy(dst_start + pos + all_delta - repl.
length(), repl.
symbols(), repl.
length());
4087 end_of_piece = finded[idx];
4089 if (!all_delta && reserve_for_copy != src_start) {
4090 ch_traits<K>::copy(dst_start, src_start, finded[0]);
4093 } helper(d(), pattern, repl, maxCount, repl.
length() - pattern.
length());
4094 helper.replace(offset);
4095 d().set_from_copy(helper.reserve_for_copy, helper.total_length);
4115 template<StrType<K> From>
4116 Impl&
replace_from(
const From& f, str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
4118 K* dst = d().reserve_no_preserve(f.length());
4119 const K* src = f.symbols();
4121 if (maxCount == 0) {
4124 size_t src_length = f.length(), start = 0;
4125 while (maxCount--) {
4126 offset = f.find(pattern, offset);
4127 if (offset == str::npos) {
4130 size_t piece_len = offset - start;
4132 ch_traits<K>::copy(dst, src + start, piece_len);
4140 offset += pattern.
length();
4143 if (start < src_length) {
4144 ch_traits<K>::copy(dst, src + start, src_length - start);
4146 d().set_size(src_length - delta);
4149 replace(pattern, repl, offset, maxCount);
4177 template<
typename Op>
4178 Impl&
fill(
size_t from,
const Op& fillFunction) {
4179 size_t size = _len();
4182 size_t capacity = d().capacity();
4186 size_t needSize = (size_t)fillFunction(ptr + from, capacity);
4187 if (capacity >= needSize) {
4188 d().set_size(from + needSize);
4191 ptr = from == 0 ? d().reserve_no_preserve(needSize) : d().set_size(from + needSize);
4192 capacity = d().capacity() - from;
4204 template<
typename Op>
4205 requires std::is_invocable_v<Op, K*, size_t>
4207 return fill(0, fillFunction);
4217 template<
typename Op>
4218 requires std::is_invocable_v<Op, K*, size_t>
4220 return fill(_len(), fillFunction);
4230 template<
typename Op>
4231 requires std::is_invocable_v<Op, my_type&>
4250 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4252 size_t size = _len();
4255 size_t capacity = d().capacity();
4266 if constexpr (
sizeof(K) == 1 && !isWindowsOs) {
4267 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
4268 if (result > (
int)capacity) {
4269 ptr = from == 0 ? d().reserve_no_preserve(result) : d().set_size(from + result);
4270 result = printf_selector::snprintf(ptr + from, result + 1,
format, std::forward<T>(args)...);
4274 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
4281 ptr = from == 0 ? d().reserve_no_preserve(capacity) : d().set_size(from + capacity);
4287 d().set_size(
static_cast<size_t>(traits::length(_str())));
4289 d().set_size(from + result);
4304 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4320 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4331 inline static K pad;
4332 K& operator*()
const {
4335 writer& operator++() {
4336 if (writed < max_write) {
4339 size_t l = ptr - store->begin();
4341 ptr = store->set_size(l + std::min(l / 2,
size_t(8192))) + l;
4349 writer operator++(
int) {
4355 writer(my_type& s, K* p, K* e,
size_t ml) : store(&s), ptr(p), end(e), max_write(ml) {}
4357 writer(
const writer&) =
delete;
4358 writer& operator=(
const writer&)
noexcept =
delete;
4359 writer(writer&&) noexcept = default;
4360 writer& operator=(writer&&) noexcept = default;
4361 using difference_type =
int;
4377 template<typename... T> requires (is_one_of_std_char_v<K>)
4379 size_t size = _len();
4382 size_t capacity = d().capacity();
4385 auto result = std::format_to(writer{d(), ptr + from, ptr + capacity, size_t(-1)},
4386 std::forward<decltype(format)>(
format), std::forward<T>(args)...);
4387 d().set_size(result.ptr - _str());
4406 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4408 size_t size = _len();
4411 size_t capacity = d().capacity();
4414 if constexpr (std::is_same_v<K, u8s>) {
4415 auto result = std::vformat_to(
4416 writer{d(), ptr + from, ptr + capacity, max_write},
4417 std::basic_string_view<K>{
format.symbols(),
format.length()},
4418 std::make_format_args(args...));
4419 d().set_size(result.ptr - _str());
4421 auto result = std::vformat_to(
4422 writer{d(), to_one_of_std_char(ptr + from), ptr + capacity, max_write},
4423 std::basic_string_view<wchar_t>{to_one_of_std_char(
format.symbols()),
format.length()},
4424 std::make_wformat_args(std::forward<T>(args)...));
4425 d().set_size(result.ptr - _str());
4441 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4442 Impl&
format(
const FmtString<K, T...>& pattern, T&&... args) {
4443 return format_from(0, pattern, std::forward<T>(args)...);
4457 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4473 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4489 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4507 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4525 template<
typename... T>
requires (is_one_of_std_char_v<K>)
4539 template<
typename Op,
typename... Args>
4540 Impl&
with(
const Op& fillFunction, Args&&... args) {
4541 fillFunction(d(), std::forward<Args>(args)...);
4547struct SharedStringData {
4548 std::atomic_size_t ref_;
4550 SharedStringData() {
4554 return (K*)(
this + 1);
4557 ref_.fetch_add(1, std::memory_order_relaxed);
4559 void decr(Allocatorable
auto& allocator) {
4560 size_t val = ref_.fetch_sub(1, std::memory_order_relaxed);
4562 allocator.deallocate(
this);
4565 static SharedStringData<K>* create(
size_t l, Allocatorable
auto& allocator) {
4566 size_t size =
sizeof(SharedStringData<K>) + (l + 1) *
sizeof(K);
4567 return new (allocator.allocate(size)) SharedStringData();
4569 static SharedStringData<K>* from_str(
const K* p) {
4570 return (SharedStringData<K>*)p - 1;
4572 K* place(K* p,
size_t len) {
4573 ch_traits<K>::copy(p, str(), len);
4580class string_common_allocator {
4582 void* allocate(
size_t bytes) {
4583 return new char[bytes];
4585 void deallocate(
void* address)
noexcept {
4586 delete []
static_cast<char*
>(address);
4590string_common_allocator default_string_allocator_selector(...);
4597using allocator_string =
decltype(default_string_allocator_selector(
int(0)));
4599template<
typename K, Allocatorable Allocator>
4631template<
typename K,
size_t N,
bool forShared = false, Allocatorable Allocator = allocator_
string>
4633 public str_algs<K, simple_str<K>, lstring<K, N, forShared, Allocator>, true>,
4634 public str_mutable<K, lstring<K, N, forShared, Allocator>>,
4635 public str_storable<K, lstring<K, N, forShared, Allocator>, Allocator>,
4636 public null_terminated<K, lstring<K, N, forShared, Allocator>>,
4637 public from_utf_convertible<K, lstring<K, N, forShared, Allocator>> {
4639 using symb_type = K;
4641 using allocator_t = Allocator;
4650 extra = forShared ?
sizeof(SharedStringData<K>) : 0,
4653 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
4654 using base_storable = str_storable<K, my_type, Allocator>;
4655 using base_mutable = str_mutable<K, my_type>;
4656 using base_utf = from_utf_convertible<K, my_type>;
4657 using traits = ch_traits<K>;
4658 using s_str = base_storable::s_str;
4660 friend base_storable;
4661 friend base_mutable;
4663 friend class sstring<K, Allocator>;
4672 K local_[LocalCapacity + 1];
4675 constexpr void create_empty() {
4680 constexpr static size_t calc_capacity(
size_t s) {
4681 size_t real_need = (s + 1) *
sizeof(K) + extra;
4682 size_t aligned_alloced = (real_need +
alignof(std::max_align_t) - 1) /
alignof(std::max_align_t) *
alignof(std::max_align_t);
4683 return (aligned_alloced - extra) /
sizeof(K) - 1;
4686 constexpr K* init(
size_t s) {
4688 if (size_ > LocalCapacity) {
4689 s = calc_capacity(s);
4690 data_ = alloc_place(s);
4698 constexpr bool is_alloced() const noexcept {
4699 return data_ != local_;
4702 constexpr void dealloc() {
4704 base_storable::allocator().deallocate(to_real_address(data_));
4709 constexpr static K* to_real_address(
void* ptr) {
4710 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) - extra);
4712 constexpr static K* from_real_address(
void* ptr) {
4713 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) + extra);
4716 constexpr K* alloc_place(
size_t newSize) {
4717 return from_real_address(base_storable::allocator().allocate((newSize + 1) *
sizeof(K) + extra));
4721 constexpr K* alloc_for_copy(
size_t newSize) {
4722 if (capacity() >= newSize) {
4727 return alloc_place(calc_capacity(newSize));
4731 constexpr void set_from_copy(K* ptr,
size_t newSize) {
4737 capacity_ = calc_capacity(newSize);
4744 using base_utf::base_utf;
4752 template<
typename... Args>
4753 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
4754 constexpr lstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
4755 : base_storable(std::forward<Args>(args)...) {
4767 template<
typename... Args>
4768 requires std::is_constructible_v<allocator_t, Args...>
4769 constexpr lstring(s_str other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4782 template<
typename... Args>
4783 requires std::is_constructible_v<allocator_t, Args...>
4784 constexpr lstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4797 template<
typename... Args>
4798 requires std::is_constructible_v<allocator_t, Args...>
4799 constexpr lstring(
size_t count, K pad, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4816 template<
typename... Args>
4817 requires std::is_constructible_v<allocator_t, Args...>
4837 template<StrType<K> From,
typename... Args>
4838 requires std::is_constructible_v<allocator_t, Args...>
4839 constexpr lstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
4840 : base_storable(std::forward<Args>(args)...) {
4848 constexpr ~lstring() {
4860 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
4871 template<
typename... Args>
4872 requires(
sizeof...(Args) > 0 && std::is_convertible_v<allocator_t, Args...>)
4873 constexpr lstring(
const my_type& other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4875 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
4886 template<typename T, size_t I = const_lit_for<K, T>::Count,
typename... Args>
4887 requires std::is_constructible_v<allocator_t, Args...>
4888 constexpr lstring(T&& value, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4889 if constexpr (I > 1) {
4890 K* ptr = init(I - 1);
4891 traits::copy(ptr, value, I - 1);
4902 constexpr lstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
4904 size_ = other.size_;
4905 if (other.is_alloced()) {
4906 data_ = other.data_;
4907 capacity_ = other.capacity_;
4910 traits::copy(local_, other.local_, size_ + 1);
4912 other.data_ = other.local_;
4914 other.local_[0] = 0;
4925 template<
typename Op,
typename... Args>
4926 requires(std::is_constructible_v<Allocator, Args...> && (std::is_invocable_v<Op, my_type&> || std::is_invocable_v<Op, K*, size_t>))
4927 lstring(
const Op& op, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4948 if (&other !=
this) {
4950 size_ = other.size_;
4965 if (&other !=
this) {
4967 if (other.is_alloced()) {
4968 data_ = other.data_;
4969 capacity_ = other.capacity_;
4971 traits::copy(data_, other.local_, other.size_ + 1);
4974 size_ = other.size_;
4975 other.create_empty();
4980 my_type& assign(
const K* other,
size_t len) {
4982 bool isIntersect = other >= data_ && other + len <= data_ + size_;
4988 if (other > data_) {
4989 traits::move(data_, other, len);
4992 traits::copy(reserve_no_preserve(len), other, len);
5008 return assign(other.str, other.len);
5018 template<typename T, size_t S = const_lit_for<K, T>::Count>
5020 return assign(other, S - 1);
5033 size_t newLen = expr.
length();
5079 newSize = calc_capacity(newSize);
5080 K* newData = alloc_place(newSize);
5083 capacity_ = newSize;
5101 newSize = calc_capacity(newSize);
5102 K* newData = alloc_place(newSize);
5103 traits::copy(newData, data_, size_);
5106 capacity_ = newSize;
5124 if (newSize > cap) {
5125 size_t needPlace = newSize;
5126 if (needPlace < (cap + 1) * 2) {
5127 needPlace = (cap + 1) * 2 - 1;
5140 return !is_alloced();
5150 for (
size_t i = 0; i < cap; i++) {
5151 if (data_[i] == 0) {
5166 size_t need_capacity = calc_capacity(size_);
5167 if (is_alloced() && capacity_ > need_capacity) {
5168 K* newData = size_ <=
LocalCapacity ? local_ : alloc_place(need_capacity);
5169 traits::copy(newData, data_, size_ + 1);
5174 capacity_ = need_capacity;
5190template<
size_t N = 15>
5191using lstringa = lstring<u8s, N>;
5192template<
size_t N = 15>
5193using lstringw = lstring<wchar_t, N>;
5194template<
size_t N = 15>
5195using lstringu = lstring<u16s, N>;
5196template<
size_t N = 15>
5197using lstringuu = lstring<u32s, N>;
5199template<
size_t N = 15>
5200using lstringsa = lstring<u8s, N, true>;
5201template<
size_t N = 15>
5202using lstringsw = lstring<wchar_t, N, true>;
5203template<
size_t N = 15>
5204using lstringsu = lstring<u16s, N, true>;
5205template<
size_t N = 15>
5206using lstringsuu = lstring<u32s, N, true>;
5209template<typename T, typename K = typename const_lit<T>::symb_type>
5210auto getLiteralType(T&&) {
5214template<
size_t Arch,
size_t L>
5215inline constexpr const size_t _local_count = 0;
5218inline constexpr const size_t _local_count<8, 1> = 23;
5220inline constexpr const size_t _local_count<8, 2> = 15;
5222inline constexpr const size_t _local_count<8, 4> = 7;
5224inline constexpr const size_t _local_count<4, 1> = 15;
5226inline constexpr const size_t _local_count<4, 2> = 11;
5228inline constexpr const size_t _local_count<4, 4> = 5;
5231constexpr const size_t local_count = _local_count<
sizeof(size_t),
sizeof(T)>;
5285template<
typename K, Allocatorable Allocator = allocator_
string>
5286class decl_empty_bases sstring :
5287 public str_algs<K, simple_str<K>, sstring<K, Allocator>, false>,
5288 public str_storable<K, sstring<K, Allocator>, Allocator>,
5289 public null_terminated<K, sstring<K, Allocator>>,
5290 public from_utf_convertible<K, sstring<K, Allocator>> {
5292 using symb_type = K;
5293 using uns_type = std::make_unsigned_t<K>;
5294 using my_type = sstring<K, Allocator>;
5295 using allocator_t = Allocator;
5297 enum { LocalCount = local_count<K> };
5300 using base_algs = str_algs<K, simple_str<K>, my_type,
false>;
5302 using base_utf = from_utf_convertible<K, my_type>;
5303 using traits = ch_traits<K>;
5304 using uni = unicode_traits<K>;
5305 using s_str = base_storable::s_str;
5307 friend base_storable;
5310 enum Types { Local, Constant, Shared };
5323 uns_type localRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
5335 uns_type pad_[LocalCount - (
sizeof(
const K*) +
sizeof(
size_t)) /
sizeof(K)];
5336 uns_type blocalRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
5337 uns_type btype_ : 2;
5341 constexpr void create_empty() {
5343 localRemain_ = LocalCount;
5347 if (s > LocalCount) {
5355 localRemain_ = LocalCount - s;
5360 K* set_size(
size_t newSize) {
5366 if (newSize !=
size) {
5367 if (type_ == Constant) {
5370 if (newSize <= LocalCount) {
5371 if (type_ == Shared) {
5372 SharedStringData<K>* str_buf = SharedStringData<K>::from_str(sstr_);
5373 traits::copy(buf_, sstr_, newSize);
5377 localRemain_ = LocalCount - newSize;
5379 if (type_ == Shared) {
5380 if (newSize >
size || (newSize > 64 && newSize <=
size * 3 / 4)) {
5382 traits::copy(newStr, sstr_, newSize);
5386 }
else if (type_ == Local) {
5389 traits::copy(newStr, buf_,
size);
5398 K* str = type_ == Local ? buf_ : (K*)sstr_;
5404 using base_utf::base_utf;
5416 template<
typename... Args>
5417 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
5418 sstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
5419 : base_storable(std::forward<Args>(args)...) {
5431 template<
typename... Args>
5432 requires std::is_constructible_v<allocator_t, Args...>
5433 sstring(s_str other, Args&&... args) : base_storable(std::forward<Args>(args)...), buf_{0} {
5446 template<
typename... Args>
5447 requires std::is_constructible_v<allocator_t, Args...>
5448 sstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(std::forward<Args>(args)...) {
5461 template<
typename... Args>
5462 requires std::is_constructible_v<allocator_t, Args...>
5463 sstring(
size_t count, K pad, Args&&... args) : base_storable(std::forward<Args>(args)...) {
5480 template<
typename... Args>
5481 requires std::is_constructible_v<allocator_t, Args...>
5501 template<StrType<K> From,
typename... Args>
5502 requires std::is_constructible_v<allocator_t, Args...>
5503 sstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
5504 : base_storable(std::forward<Args>(args)...) {
5511 if (btype_ == Shared) {
5521 constexpr sstring(
const my_type& other) noexcept : base_storable(other.allocator()) {
5522 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
5523 if (type_ == Shared)
5524 SharedStringData<K>::from_str(sstr_)->incr();
5532 constexpr sstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
5533 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
5534 other.create_empty();
5549 size_t size = src.length();
5551 if (src.is_alloced()) {
5555 if (
size > LocalCount) {
5562 new (SharedStringData<K>::from_str(str)) SharedStringData<K>();
5567 localRemain_ = LocalCount -
size;
5568 traits::copy(buf_, str,
size + 1);
5576 K* str = init(src.size_);
5577 traits::copy(str, src.symbols(),
size + 1);
5594 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename... Args>
5595 requires std::is_constructible_v<allocator_t, Args...>
5596 constexpr sstring(T&& s, Args&&... args) : base_storable(std::forward<Args>(args)...)
5605 constexpr void swap(my_type&& other)
noexcept {
5606 char buf[
sizeof(buf_) +
sizeof(K)];
5607 memcpy(buf, buf_,
sizeof(buf));
5608 memcpy(buf_, other.buf_,
sizeof(buf));
5609 memcpy(other.buf_, buf,
sizeof(buf));
5611 std::swap(base_storable::allocator(), other.allocator());
5622 swap(std::move(other));
5644 template<typename T, size_t N = const_lit_for<K, T>::Count>
5656 template<
size_t N,
bool forShared,
typename A>
5670 return operator=(my_type{std::move(other)});
5692 if (type_ == Shared)
5699 return btype_ == Local ? buf_ : cstr_;
5703 return btype_ == Local ? LocalCount - blocalRemain_ : bigLen_;
5725 template<
typename... T>
5726 static my_type
printf(
const K* pattern, T&&... args) {
5739 template<
typename... T>
5740 static my_type
format(
const FmtString<K, T...>& fmtString, T&&... args) {
5753 template<
typename... T>
5759template<
typename K, Allocatorable Allocator>
5760inline const sstring<K> sstring<K, Allocator>::empty_str{};
5763struct digits_selector {
5764 using wider_type = uint16_t;
5768struct digits_selector<2> {
5769 using wider_type = uint32_t;
5773struct digits_selector<4> {
5774 using wider_type = uint64_t;
5777template<
typename K,
typename T>
5778constexpr size_t fromInt(K* bufEnd, T val) {
5779 const char* twoDigit =
5780 "0001020304050607080910111213141516171819"
5781 "2021222324252627282930313233343536373839"
5782 "4041424344454647484950515253545556575859"
5783 "6061626364656667686970717273747576777879"
5784 "8081828384858687888990919293949596979899";
5786 need_sign<K, std::is_signed_v<T>, T> sign(val);
5790 if constexpr (std::is_signed_v<T>) {
5794 const char* ptr = twoDigit - (val % 100) * 2;
5795 *--itr =
static_cast<K
>(ptr[1]);
5796 *--itr =
static_cast<K
>(ptr[0]);
5801 while (val >= 100) {
5802 const char* ptr = twoDigit + (val % 100) * 2;
5803 *--itr =
static_cast<K
>(ptr[1]);
5804 *--itr =
static_cast<K
>(ptr[0]);
5808 *--itr =
static_cast<K
>(
'0' + val);
5810 const char* ptr = twoDigit + val * 2;
5811 *--itr =
static_cast<K
>(ptr[1]);
5812 *--itr =
static_cast<K
>(ptr[0]);
5815 return size_t(bufEnd - itr);
5821template<
typename K,
typename T>
5823 using symb_type = K;
5824 using my_type = expr_num<K, T>;
5826 enum { bufSize = 24 };
5828 mutable K buf[bufSize];
5830 expr_num(T t) : value(t) {}
5831 expr_num(expr_num<K, T>&& t) : value(t.value) {}
5833 size_t length() const noexcept {
5834 value = (T)fromInt(buf + bufSize, value);
5835 return (
size_t)value;
5837 K* place(K* ptr)
const noexcept {
5838 ch_traits<K>::copy(ptr, buf + bufSize - (
size_t)value, (
size_t)value);
5839 return ptr + (size_t)value;
5854template<StrExpr A, FromIntNumber T>
5870template<StrExpr A, FromIntNumber T>
5890template<
typename K,
typename T>
5896consteval simple_str_nt<K> select_str(simple_str_nt<u8s> s8, simple_str_nt<uws> sw, simple_str_nt<u16s> s16, simple_str_nt<u32s> s32) {
5897 if constexpr (std::is_same_v<K, u8s>)
5899 if constexpr (std::is_same_v<K, uws>)
5901 if constexpr (std::is_same_v<K, u16s>)
5903 if constexpr (std::is_same_v<K, u32s>)
5907#define uni_string(K, p) select_str<K>(p, L##p, u##p, U##p)
5911 using symb_type = K;
5912 mutable std::conditional_t<is_one_of_std_char_v<K>, K, u8s> buf[40];
5915 expr_real(
double d) : v(d) {}
5916 expr_real(
float d) : v(d) {}
5918 size_t length() const noexcept {
5919 if constexpr (is_one_of_std_char_v<K>) {
5920 printf_selector::snprintf(buf, 40, uni_string(K,
"%.16g").str, v);
5921 l = (size_t)ch_traits<K>::length(buf);
5923 l = std::snprintf(buf,
sizeof(buf),
"%.16g", v);
5927 K* place(K* ptr)
const noexcept {
5928 if constexpr (is_one_of_std_char_v<K>) {
5929 ch_traits<K>::copy(ptr, buf, l);
5931 for (
size_t i = 0; i < l; i++) {
5950template<StrExpr A,
typename R>
5951 requires(std::is_same_v<R, double> || std::is_same_v<R, float>)
5952inline constexpr auto operator+(
const A& a, R s) {
5967template<StrExpr A,
typename R>
5968 requires(is_one_of_std_char_v<typename A::symb_type> && (std::is_same_v<R, double> || std::is_same_v<R, float>))
5969inline constexpr auto operator+(R s,
const A& a) {
5984template<
typename K>
requires(is_one_of_std_char_v<K>)
5986 return expr_real<K>{t};
6005template<
typename K,
typename T,
size_t I,
bool tail,
bool skip_empty>
6007 using symb_type = K;
6008 using my_type = expr_join<K, T, I, tail, skip_empty>;
6013 constexpr size_t length() const noexcept {
6015 for (
const auto& t: s) {
6016 size_t len = t.length();
6017 if (len > 0 || !skip_empty) {
6018 if (I > 0 && l > 0) {
6024 return l + (tail && I > 0 && (l > 0 || (!skip_empty && s.size() > 0))? I : 0);
6026 constexpr K* place(K* ptr)
const noexcept {
6031 for (
const auto& t: s) {
6032 size_t copyLen = t.length();
6033 if (I > 0 && write != ptr && (copyLen || !skip_empty)) {
6034 ch_traits<K>::copy(write, delim, I);
6037 ch_traits<K>::copy(write, t.symbols(), copyLen);
6040 if (I > 0 && tail && (write != ptr || (!skip_empty && s.size() > 0))) {
6041 ch_traits<K>::copy(write, delim, I);
6061template<bool tail = false, bool skip_empty = false, typename L, typename K = typename const_lit<L>::symb_type,
size_t I = const_lit<L>::Count,
typename T>
6062inline constexpr auto e_join(
const T& s, L&& d) {
6063 return expr_join<K, T, I - 1, tail, skip_empty>{s, d};
6066template<
typename K,
size_t N,
size_t L>
6067struct expr_replaces {
6068 using symb_type = K;
6069 using my_type = expr_replaces<K, N, L>;
6073 mutable size_t first_, last_;
6075 constexpr expr_replaces(simple_str<K> w,
const K* p,
const K* r) : what(w), pattern(p), repl(r) {}
6077 constexpr size_t length()
const {
6078 size_t l = what.length();
6079 if constexpr (N == L) {
6082 first_ = what.find(pattern, N, 0);
6083 if (first_ != str::npos) {
6087 size_t next = what.find(pattern, N, last_);
6088 if (next == str::npos) {
6096 constexpr K* place(K* ptr)
const noexcept {
6097 if constexpr (N == L) {
6098 const K* from = what.symbols();
6099 for (
size_t start = 0; start < what.length();) {
6100 size_t next = what.find(pattern, N, start);
6101 if (next == str::npos) {
6102 next = what.length();
6104 size_t delta = next - start;
6105 ch_traits<K>::copy(ptr, from + start, delta);
6107 ch_traits<K>::copy(ptr, repl, L);
6113 if (first_ == str::npos) {
6114 return what.place(ptr);
6116 const K* from = what.symbols();
6117 for (
size_t start = 0, offset = first_; ;) {
6118 ch_traits<K>::copy(ptr, from + start, offset - start);
6119 ptr += offset - start;
6120 ch_traits<K>::copy(ptr, repl, L);
6123 if (start >= last_) {
6124 size_t tail = what.length() - last_;
6125 ch_traits<K>::copy(ptr, from + last_, tail);
6129 offset = what.find(pattern, N, start);
6149template<typename K, typename T, size_t N = const_lit_for<K, T>::Count,
typename X,
size_t L = const_lit_for<K, X>::Count>
6152 return expr_replaces<K, N - 1, L - 1>{w, p, r};
6174 using symb_type = K;
6179 mutable size_t first_, last_;
6192 constexpr size_t length()
const {
6193 size_t l = what.
length();
6197 first_ = what.find(pattern);
6198 if (first_ != str::npos) {
6199 last_ = first_ + pattern.
length();
6202 size_t next = what.find(pattern, last_);
6203 if (next == str::npos) {
6206 last_ = next + pattern.
length();
6211 constexpr K* place(K* ptr)
const noexcept {
6213 const K* from = what.
symbols();
6214 for (
size_t start = 0; start < what.
length();) {
6215 size_t next = what.find(pattern, start);
6216 if (next == str::npos) {
6219 size_t delta = next - start;
6220 ch_traits<K>::copy(ptr, from + start, delta);
6224 start = next + pattern.
length();
6228 if (first_ == str::npos) {
6229 return what.
place(ptr);
6231 const K* from = what.
symbols();
6232 for (
size_t start = 0, offset = first_; ;) {
6233 ch_traits<K>::copy(ptr, from + start, offset - start);
6234 ptr += offset - start;
6237 start = offset + pattern.
length();
6238 if (start >= last_) {
6239 size_t tail = what.
length() - last_;
6240 ch_traits<K>::copy(ptr, from + last_, tail);
6244 offset = what.find(pattern, start);
6251template<
bool UseVectorForReplace>
6252struct replace_search_result_store {
6254 std::pair<size_t, size_t> replaces_[16];
6258struct replace_search_result_store<true> : std::vector<std::pair<size_t, size_t>> {};
6299template<
typename K,
bool UseVectorForReplace = false>
6301 using symb_type = K;
6302 inline static const int BIT_SEARCH_TRESHHOLD = 4;
6305 const std::vector<std::pair<K, simple_str<K>>>& replaces_;
6309 mutable replace_search_result_store<UseVectorForReplace> search_results_;
6311 uu8s bit_mask_[
sizeof(K) == 1 ? 32 : 64]{};
6340 : source_(source), replaces_(repl)
6342 size_t pattern_len = replaces_.size();
6343 K* pattern = pattern_.set_size(pattern_len);
6345 for (
size_t idx = 0; idx < replaces_.size(); idx++) {
6346 *pattern++ = replaces_[idx].first;
6349 if (pattern_len >= BIT_SEARCH_TRESHHOLD) {
6350 for (
size_t idx = 0; idx < pattern_len; idx++) {
6351 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
6352 if constexpr (
sizeof(K) == 1) {
6353 bit_mask_[s >> 3] |= (1 << (s & 7));
6355 if (std::make_unsigned_t<K>(pattern_[idx]) > 255) {
6356 bit_mask_[32 + (s >> 3)] |= (1 << (s & 7));
6358 bit_mask_[s >> 3] |= (1 << (s & 7));
6365 size_t length()
const {
6366 size_t l = source_.
length();
6367 auto [fnd, num] = find_first_of(source_.str, source_.len);
6368 if (fnd == str::npos) {
6371 l += replaces_[num].second.len - 1;
6372 if constexpr (UseVectorForReplace) {
6373 search_results_.reserve((l >> 4) + 8);
6374 search_results_.emplace_back(fnd, num);
6375 for (
size_t start = fnd + 1;;) {
6376 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6377 if (fnd == str::npos) {
6380 search_results_.emplace_back(fnd, idx);
6382 l += replaces_[idx].second.len - 1;
6385 const size_t max_store = std::size(search_results_.replaces_);
6386 search_results_.replaces_[0] = {fnd, num};
6387 search_results_.count_++;
6388 for (
size_t start = fnd + 1;;) {
6389 auto [found, idx] = find_first_of(source_.str, source_.len, start);
6390 if (found == str::npos) {
6393 if (search_results_.count_ < max_store) {
6394 search_results_.replaces_[search_results_.count_] = {found, idx};
6396 l += replaces_[idx].second.len - 1;
6397 search_results_.count_++;
6403 K* place(K* ptr)
const noexcept {
6405 const K* text = source_.str;
6406 if constexpr (UseVectorForReplace) {
6407 for (
const auto& [pos, num] : search_results_) {
6408 size_t delta = pos - start;
6409 ch_traits<K>::copy(ptr, text + start, delta);
6411 ptr = replaces_[num].second.place(ptr);
6415 const size_t max_store = std::size(search_results_.replaces_);
6416 size_t founded = search_results_.count_;
6417 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
6418 const auto [pos, num] = search_results_.replaces_[idx];
6419 size_t delta = pos - start;
6420 ch_traits<K>::copy(ptr, text + start, delta);
6422 ptr = replaces_[num].second.place(ptr);
6425 if (founded > max_store) {
6426 founded -= max_store;
6428 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6429 size_t delta = fnd - start;
6430 ch_traits<K>::copy(ptr, text + start, delta);
6432 ptr = replaces_[idx].second.place(ptr);
6437 size_t tail = source_.len - start;
6438 ch_traits<K>::copy(ptr, text + start, tail);
6443 size_t index_of(K s)
const {
6444 return pattern_.find(s);
6447 bool is_in_mask(uu8s s)
const {
6448 return (bit_mask_[s >> 3] & (1 << (s & 7))) != 0;
6450 bool is_in_mask2(uu8s s)
const {
6451 return (bit_mask_[32 + (s >> 3)] & (1 << (s & 7))) != 0;
6454 bool is_in_pattern(K s,
size_t& idx)
const {
6455 if constexpr (
sizeof(K) == 1) {
6456 if (is_in_mask(s)) {
6461 if (std::make_unsigned_t<const K>(s) > 255) {
6462 if (is_in_mask2(s)) {
6463 return (idx = index_of(s)) != -1;
6466 if (is_in_mask(s)) {
6475 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
6476 size_t pl = pattern_.
length();
6477 if (pl >= BIT_SEARCH_TRESHHOLD) {
6479 while (offset < len) {
6480 if (is_in_pattern(text[offset], idx)) {
6481 return {offset, idx};
6486 while (offset < len) {
6487 if (
size_t idx = index_of(text[offset]); idx != -1) {
6488 return {offset, idx};
6499template<
typename K,
size_t N,
bool UseVectorForReplace>
6500struct expr_replace_const_symbols {
6501 using symb_type = K;
6502 inline static const int BIT_SEARCH_TRESHHOLD = 4;
6503 const K pattern_[N];
6504 const simple_str<K> source_;
6505 const simple_str<K> replaces_[N];
6507 mutable replace_search_result_store<UseVectorForReplace> search_results_;
6509 [[_no_unique_address]]
6510 uu8s bit_mask_[N >= BIT_SEARCH_TRESHHOLD ? (
sizeof(K) == 1 ? 32 : 64) : 0]{};
6512 template<
typename ... Repl>
requires (
sizeof...(Repl) == N * 2)
6513 constexpr expr_replace_const_symbols(simple_str<K> source, Repl&& ... repl) : expr_replace_const_symbols(0, source, std::forward<Repl>(repl)...) {}
6515 size_t length()
const {
6516 size_t l = source_.
length();
6517 auto [fnd, num] = find_first_of(source_.str, source_.len);
6518 if (fnd == str::npos) {
6521 l += replaces_[num].len - 1;
6522 if constexpr (UseVectorForReplace) {
6523 search_results_.reserve((l >> 4) + 8);
6524 search_results_.emplace_back(fnd, num);
6525 for (
size_t start = fnd + 1;;) {
6526 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6527 if (fnd == str::npos) {
6530 search_results_.emplace_back(fnd, idx);
6532 l += replaces_[idx].len - 1;
6535 const size_t max_store = std::size(search_results_.replaces_);
6536 search_results_.replaces_[0] = {fnd, num};
6537 search_results_.count_++;
6538 for (
size_t start = fnd + 1;;) {
6539 auto [found, idx] = find_first_of(source_.str, source_.len, start);
6540 if (found == str::npos) {
6543 if (search_results_.count_ < max_store) {
6544 search_results_.replaces_[search_results_.count_] = {found, idx};
6546 l += replaces_[idx].len - 1;
6547 search_results_.count_++;
6553 K* place(K* ptr)
const noexcept {
6555 const K* text = source_.str;
6556 if constexpr (UseVectorForReplace) {
6557 for (
const auto& [pos, num] : search_results_) {
6558 size_t delta = pos - start;
6559 ch_traits<K>::copy(ptr, text + start, delta);
6561 ptr = replaces_[num].place(ptr);
6565 const size_t max_store = std::size(search_results_.replaces_);
6566 size_t founded = search_results_.count_;
6567 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
6568 const auto [pos, num] = search_results_.replaces_[idx];
6569 size_t delta = pos - start;
6570 ch_traits<K>::copy(ptr, text + start, delta);
6572 ptr = replaces_[num].place(ptr);
6575 if (founded > max_store) {
6576 founded -= max_store;
6578 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6579 size_t delta = fnd - start;
6580 ch_traits<K>::copy(ptr, text + start, delta);
6582 ptr = replaces_[idx].place(ptr);
6587 size_t tail = source_.len - start;
6588 ch_traits<K>::copy(ptr, text + start, tail);
6593 template<
typename ... Repl>
6594 constexpr expr_replace_const_symbols(
int, simple_str<K> source, K s, simple_str<K> r, Repl&&... repl) :
6595 expr_replace_const_symbols(0, source, std::forward<Repl>(repl)..., std::make_pair(s, r)){}
6597 template<
typename ... Repl>
requires (
sizeof...(Repl) == N)
6598 constexpr expr_replace_const_symbols(
int, simple_str<K> source, Repl&&... repl) :
6599 source_(source), pattern_ {repl.first...}, replaces_{repl.second...}
6601 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6602 for (
size_t idx = 0; idx < N; idx++) {
6603 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
6604 if constexpr (
sizeof(K) == 1) {
6605 bit_mask_[s >> 3] |= 1 << (s & 7);
6607 if (std::make_unsigned_t<const K>(pattern_[idx]) > 255) {
6608 bit_mask_[32 + (s >> 3)] |= 1 << (s & 7);
6610 bit_mask_[s >> 3] |= 1 << (s & 7);
6617 template<
size_t Idx>
6618 size_t index_of(K s)
const {
6619 if constexpr (Idx < N) {
6620 return pattern_[Idx] == s ? Idx : index_of<Idx + 1>(s);
6624 bool is_in_mask(uu8s s)
const {
6625 return (bit_mask_[s >> 3] & (1 <<(s & 7))) != 0;
6627 bool is_in_mask2(uu8s s)
const {
6628 return (bit_mask_[32 + (s >> 3)] & (1 <<(s & 7))) != 0;
6631 bool is_in_pattern(K s,
size_t& idx)
const {
6632 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6633 if constexpr (
sizeof(K) == 1) {
6634 if (is_in_mask(s)) {
6635 idx = index_of<0>(s);
6639 if (std::make_unsigned_t<const K>(s) > 255) {
6640 if (is_in_mask2(s)) {
6641 return (idx = index_of<0>(s)) != -1;
6644 if (is_in_mask(s)) {
6645 idx = index_of<0>(s);
6653 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
6654 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6656 while (offset < len) {
6657 if (is_in_pattern(text[offset], idx)) {
6658 return {offset, idx};
6663 while (offset < len) {
6664 if (
size_t idx = index_of<0>(text[offset]); idx != -1) {
6665 return {offset, idx};
6713template<
bool UseVector =
false,
typename K,
typename ... Repl>
6714requires (
sizeof...(Repl) % 2 == 0)
6716 return expr_replace_const_symbols<K,
sizeof...(Repl) / 2, UseVector>(src, std::forward<Repl>(other)...);
6719template<
typename K,
typename H>
6723 char node[
sizeof(sstring<K>)];
6725 const simple_str_nt<K>& to_nt() const noexcept {
6726 return static_cast<const simple_str_nt<K>&
>(str);
6728 const sstring<K>& to_str() const noexcept {
6729 return *
reinterpret_cast<const sstring<K>*
>(node);
6735 static inline constexpr size_t basis =
static_cast<size_t>(14695981039346656037ULL);
6736 static inline constexpr size_t prime =
static_cast<size_t>(1099511628211ULL);
6740struct fnv_const<false> {
6741 static inline constexpr size_t basis =
static_cast<size_t>(2166136261U);
6742 static inline constexpr size_t prime =
static_cast<size_t>(16777619U);
6745using fnv = fnv_const<
sizeof(size_t) == 8>;
6748inline constexpr size_t fnv_hash(
const K* ptr,
size_t l) {
6749 size_t h = fnv::basis;
6750 for (
size_t i = 0; i < l; i++) {
6751 h = (h ^ (std::make_unsigned_t<K>)ptr[i]) * fnv::prime;
6757inline constexpr size_t fnv_hash_ia(
const K* ptr,
size_t l) {
6758 size_t h = fnv::basis;
6759 for (
size_t i = 0; i < l; i++) {
6760 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)ptr[i];
6761 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
6766template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
6767inline constexpr size_t fnv_hash(T&& value) {
6768 size_t h = fnv::basis;
6769 for (
size_t i = 0; i < N - 1; i++) {
6770 h = (h ^ (std::make_unsigned_t<K>)value[i]) * fnv::prime;
6775template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
6776inline constexpr size_t fnv_hash_ia(T&& value) {
6777 size_t h = fnv::basis;
6778 for (
size_t i = 0; i < N - 1; i++) {
6779 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)value[i];
6780 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
6786inline consteval size_t fnv_hash_compile(
const K* ptr,
size_t l) {
6787 return fnv_hash(ptr, l);
6791inline consteval size_t fnv_hash_ia_compile(
const K* ptr,
size_t l) {
6792 return fnv_hash_ia(ptr, l);
6795static_assert(std::is_trivially_copyable_v<StoreType<u8s, int>>,
"Store type must be trivially copyable");
6896template<
typename K,
typename T,
typename H = strhash<K>,
typename E = streql<K>>
6897class hashStrMap :
public std::unordered_map<StoreType<K, H>, T, H, E> {
6899 using InStore = StoreType<K, H>;
6902 using my_type = hashStrMap<K, T, H, E>;
6903 using hash_t = std::unordered_map<InStore, T, H, E>;
6906 hashStrMap() =
default;
6907 hashStrMap(
const my_type& other) : hash_t(other) {
6908 for (
const auto& [k, v] : *
this) {
6909 InStore& stored =
const_cast<InStore&
>(k);
6911 new (stored.node)
sstring<K>(std::move(tmp));
6912 stored.str.str = stored.to_str().symbols();
6916 for (
auto& k: *
this)
6920 hashStrMap(my_type&& o) =
default;
6922 my_type& operator=(
const my_type& other) {
6923 hash_t::operator=(other);
6924 for (
const auto& [k, v] : *
this) {
6925 InStore& stored =
const_cast<InStore&
>(k);
6927 new (stored.node)
sstring<K>(std::move(tmp));
6928 stored.str.str = stored.to_str().symbols();
6932 my_type& operator=(my_type&&) =
default;
6934 hashStrMap(std::initializer_list<std::pair<const InStore, T>>&& init) {
6935 for (
const auto& e: init)
6936 emplace(e.first, e.second);
6939 using init_str = std::initializer_list<std::pair<const sstring<K>, T>>;
6941 hashStrMap(init_str&& init) {
6942 for (
const auto& e: init)
6943 emplace(e.first, e.second);
6948 template<
typename... ValArgs>
6949 auto try_emplace(
const InStore& key, ValArgs&&... args) {
6950 auto it = hash_t::try_emplace(key, std::forward<ValArgs>(args)...);
6952 InStore& stored =
const_cast<InStore&
>(it.first->first);
6954 stored.str.str = stored.to_str().symbols();
6960 return {key, H{}(key)};
6963 template<
typename Key,
typename... ValArgs>
6964 requires(std::is_convertible_v<Key, simple_str<K>>)
6965 auto try_emplace(Key&& key, ValArgs&&... args) {
6966 auto it = hash_t::try_emplace(toStoreType(key), std::forward<ValArgs>(args)...);
6968 InStore& stored =
const_cast<InStore&
>(it.first->first);
6969 new (stored.node)
sstring<K>(std::forward<Key>(key));
6970 stored.str.str = stored.to_str().symbols();
6975 template<
typename... ValArgs>
6976 auto emplace(
const InStore& key, ValArgs&&... args) {
6977 auto it = try_emplace(key, std::forward<ValArgs>(args)...);
6979 it.first->second = T(std::forward<ValArgs>(args)...);
6984 template<
typename Key,
typename... ValArgs>
6985 requires(std::is_convertible_v<Key, simple_str<K>>)
6986 auto emplace(Key&& key, ValArgs&&... args) {
6987 auto it = try_emplace(std::forward<Key>(key), std::forward<ValArgs>(args)...);
6989 it.first->second = T(std::forward<ValArgs>(args)...);
6994 auto& operator[](
const InStore& key) {
6995 return try_emplace(key).first->second;
6998 template<
typename Key>
6999 requires(std::is_convertible_v<Key, simple_str<K>>)
7000 auto&
operator[](Key&& key) {
7001 return try_emplace(std::forward<Key>(key)).first->second;
7004 decltype(
auto) at(
const InStore& key) {
7005 return hash_t::at(key);
7007 decltype(
auto) at(
const InStore& key)
const {
7008 return hash_t::at(key);
7012 return hash_t::at(toStoreType(key));
7015 return hash_t::at(toStoreType(key));
7018 auto find(
const InStore& key)
const {
7019 return hash_t::find(key);
7023 return find(toStoreType(key));
7026 auto find(
const InStore& key) {
7027 return hash_t::find(key);
7031 return find(toStoreType(key));
7034 auto erase(
typename hash_t::const_iterator it) {
7035 if (it != hash_t::end()) {
7038 return hash_t::erase(it);
7041 auto erase(
const InStore& key) {
7042 auto it = hash_t::find(key);
7043 if (it != hash_t::end()) {
7052 return erase(toStoreType(key));
7056 auto it = find(txt);
7057 if (it != hash_t::end()) {
7065 for (
auto& k: *
this)
7069 bool contains(
const InStore& key)
const {
7070 return hash_t::find(key) != this->end();
7074 return find(toStoreType(key)) != this->end();
7080 template<
typename H>
7081 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
7082 return _Left.hash == _Right.hash && _Left.str == _Right.str;
7088 size_t operator()(simple_str<K> _Keyval)
const {
7089 return fnv_hash(_Keyval.symbols(), _Keyval.length());
7091 size_t operator()(
const StoreType<K, strhash<K>>& _Keyval)
const {
7092 return _Keyval.hash;
7098 template<
typename H>
7099 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
7100 return _Left.hash == _Right.hash && _Left.str.equal_ia(_Right.str);
7106 size_t operator()(simple_str<K> _Keyval)
const {
7107 return fnv_hash_ia(_Keyval.symbols(), _Keyval.length());
7109 size_t operator()(
const StoreType<K, strhashia<K>>& _Keyval)
const {
7110 return _Keyval.hash;
7116 template<
typename H>
7117 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
7118 return _Left.hash == _Right.hash && _Left.str.equal_iu(_Right.str);
7124 size_t operator()(simple_str<K> _Keyval)
const {
7125 return unicode_traits<K>::hashiu(_Keyval.symbols(), _Keyval.length());
7127 size_t operator()(
const StoreType<K, strhashiu<K>>& _Keyval)
const {
7128 return _Keyval.hash;
7147class chunked_string_builder {
7148 using chunk_t = std::pair<std::unique_ptr<K[]>,
size_t>;
7149 std::vector<chunk_t> chunks;
7156 using my_type = chunked_string_builder<K>;
7157 using symb_type = K;
7158 chunked_string_builder() =
default;
7159 chunked_string_builder(
size_t a) : align(a){};
7160 chunked_string_builder(
const my_type&) =
delete;
7161 chunked_string_builder(my_type&& other) noexcept
7162 : chunks(std::move(other.chunks)), write(other.write), len(other.len), remain(other.remain), align(other.align) {
7163 other.len = other.remain = 0;
7164 other.write =
nullptr;
7166 my_type& operator=(my_type other)
noexcept {
7167 chunks.swap(other.chunks);
7168 write = other.write;
7170 remain = other.remain;
7171 align = other.align;
7172 other.len = other.remain = 0;
7173 other.write =
nullptr;
7181 if (
data.len <= remain) {
7184 ch_traits<K>::copy(write,
data.str,
data.len);
7186 chunks.back().second +=
data.len;
7193 ch_traits<K>::copy(write,
data.str, remain);
7196 chunks.back().second += remain;
7202 size_t blockSize = (
data.len + align - 1) / align * align;
7203 chunks.emplace_back(std::make_unique<K[]>(blockSize),
data.len);
7204 write = chunks.back().first.get();
7205 ch_traits<K>::copy(write,
data.str,
data.len);
7207 remain = blockSize -
data.len;
7214 size_t l = expr.
length();
7217 write = expr.place(write);
7218 chunks.back().second += l;
7221 }
else if (!remain) {
7222 size_t blockSize = (l + align - 1) / align * align;
7223 chunks.emplace_back(std::make_unique<K[]>(blockSize), l);
7224 write = expr.place(chunks.back().first.get());
7226 remain = blockSize - l;
7228 auto store = std::make_unique<K[]>(l);
7229 expr.place(store.get());
7236 template<
typename T>
7238 requires std::is_same_v<T, K>
7240 return operator<<(expr_char<K>(
data));
7248 if (chunks.empty()) {
7251 if (chunks.size() > 1) {
7255 remain += chunks[0].second;
7256 chunks[0].second = 0;
7258 write = chunks[0].first.get();
7261 constexpr K* place(K* p)
const noexcept {
7262 for (
const auto& block: chunks) {
7263 ch_traits<K>::copy(p, block.first.get(), block.second);
7276 template<
typename Op>
7278 for (
const auto& block: chunks)
7279 o(block.first.get(), block.second);
7286 if (chunks.size()) {
7287 const K* ptr = chunks.front().first.get();
7288 for (
const auto& chunk: chunks) {
7289 if (chunk.first.get() != ptr)
7291 ptr += chunk.second;
7303 return chunks.size() ? chunks.front().first.get() : simple_str_nt<K>::empty_str.str;
7320 typename decltype(chunks)::const_iterator it, end;
7321 size_t writedFromCurrentChunk;
7341 while (size && !
is_end()) {
7342 size_t remain = it->second - writedFromCurrentChunk;
7343 size_t write = std::min(size, remain);
7344 ch_traits<K>::copy(buffer, it->first.get() + writedFromCurrentChunk, write);
7350 writedFromCurrentChunk = 0;
7352 writedFromCurrentChunk += write;
7364 return {chunks.begin(), chunks.end(), 0};
7377using stringa = sstring<u8s>;
7378using stringw = sstring<wchar_t>;
7379using stringu = sstring<u16s>;
7380using stringuu = sstring<u32s>;
7381static_assert(
sizeof(stringa) == (
sizeof(
void*) == 8 ? 24 : 16),
"Bad size of sstring");
7463inline namespace literals {
7474#define SS_CONSTEVAL constexpr
7476#define SS_CONSTEVAL consteval
7533template<
typename K>
using HashKey = StoreType<K, strhash<K>>;
7534template<
typename K>
using HashKeyIA = StoreType<K, strhashia<K>>;
7535template<
typename K>
using HashKeyIU = StoreType<K, strhashiu<K>>;
7547consteval HashKey<u8s>
operator""_h(
const u8s* ptr,
size_t l) {
7548 return HashKey<u8s>{{ptr, l}, fnv_hash_compile(ptr, l)};
7561consteval HashKeyIA<u8s>
operator""_ia(
const u8s* ptr,
size_t l) {
7562 return HashKeyIA<u8s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7575inline HashKeyIU<u8s>
operator""_iu(
const u8s* ptr,
size_t l) {
7576 return HashKeyIU<u8s>{{ptr, l}, strhashiu<u8s>{}(
simple_str<u8s>{ptr, l})};
7589consteval HashKey<u16s>
operator""_h(
const u16s* ptr,
size_t l) {
7590 return HashKey<u16s>{{ptr, l}, fnv_hash_compile(ptr, l)};
7603consteval HashKeyIA<u16s>
operator""_ia(
const u16s* ptr,
size_t l) {
7604 return HashKeyIA<u16s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7617inline HashKeyIU<u16s>
operator""_iu(
const u16s* ptr,
size_t l) {
7618 return HashKeyIU<u16s>{{ptr, l}, strhashiu<u16s>{}(
simple_str<u16s>{ptr, l})};
7631consteval HashKey<u32s>
operator""_h(
const u32s* ptr,
size_t l) {
7632 return HashKey<u32s>{{ptr, l}, fnv_hash_compile(ptr, l)};
7645consteval HashKeyIA<u32s>
operator""_ia(
const u32s* ptr,
size_t l) {
7646 return HashKeyIA<u32s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7659inline HashKeyIU<u32s>
operator""_iu(
const u32s* ptr,
size_t l) {
7660 return HashKeyIU<u32s>{{ptr, l}, strhashiu<u32s>{}(
simple_str<u32s>{ptr, l})};
7673consteval HashKey<uws>
operator""_h(
const uws* ptr,
size_t l) {
7674 return HashKey<uws>{{ptr, l}, fnv_hash_compile(ptr, l)};
7687consteval HashKeyIA<uws>
operator""_ia(
const uws* ptr,
size_t l) {
7688 return HashKeyIA<uws>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7701inline HashKeyIU<uws>
operator""_iu(
const uws* ptr,
size_t l) {
7702 return HashKeyIU<uws>{{ptr, l}, strhashiu<uws>{}(
simple_str<uws>{ptr, l})};
7717 return stream << std::string_view{text.
symbols(), text.
length()};
7730inline std::wostream&
operator<<(std::wostream& stream, ssw text) {
7731 return stream << std::wstring_view{text.
symbols(), text.
length()};
7745 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
7758inline std::ostream&
operator<<(std::ostream& stream,
const stringa& text) {
7759 return stream << std::string_view{text.
symbols(), text.
length()};
7772inline std::wostream&
operator<<(std::wostream& stream,
const stringw& text) {
7773 return stream << std::wstring_view{text.
symbols(), text.
length()};
7787 return stream << std::wstring_view{from_w(text.symbols()), text.length()};
7800template<
size_t N,
bool S, simstr::Allocatorable A>
7802 return stream << std::string_view{text.
symbols(), text.
length()};
7815template<
size_t N,
bool S, simstr::Allocatorable A>
7817 return stream << std::wstring_view{text.
symbols(), text.
length()};
7830template<
size_t N,
bool S, simstr::Allocatorable A>
7832 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
7842struct std::formatter<
simstr::simple_str<K>, K> : std::formatter<std::basic_string_view<K>, K> {
7844 template<
typename FormatContext>
7846 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
7855struct std::formatter<
simstr::simple_str_nt<K>, K> : std::formatter<std::basic_string_view<K>, K> {
7857 template<
typename FormatContext>
7859 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
7868struct std::formatter<
simstr::sstring<K>, K> : std::formatter<std::basic_string_view<K>, K> {
7870 template<
typename FormatContext>
7872 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
7880template<
typename K,
size_t N,
bool S,
typename A>
7881struct std::formatter<
simstr::lstring<K, N, S, A>, K> : std::formatter<std::basic_string_view<K>, K> {
7883 template<
typename FormatContext>
7885 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
Class for sequentially obtaining substrings by a given delimiter.
Definition sstring.h:2448
constexpr bool is_done() const
Find out if substrings are running out.
Definition sstring.h:2458
constexpr simple_str< K > next()
Get the next substring.
Definition sstring.h:2467
my_type & operator<<(simple_str< K > data)
Adding a piece of data.
Definition sstring.h:7178
portion_store get_portion() const
Get a portion_store through which data can be sequentially retrieved into an external buffer.
Definition sstring.h:7363
constexpr size_t length() const noexcept
Length of the saved text.
Definition sstring.h:7243
my_type & operator<<(T data)
Adding a symbol.
Definition sstring.h:7237
void reset()
Resets the contents, but does not delete the first buffer in order to avoid allocation later.
Definition sstring.h:7247
void clear()
Clear the object, freeing all allocated buffers.
Definition sstring.h:7309
my_type & operator<<(const StrExprForType< K > auto &expr)
Adding a string expression.
Definition sstring.h:7213
bool is_continuous() const
Checks whether all text is located in one contiguous chunk in memory.
Definition sstring.h:7285
void out(const Op &o) const
Applies a functor to each stored buffer.
Definition sstring.h:7277
const auto & data() const
Get internal data buffers.
Definition sstring.h:7372
const K * begin() const
Get a pointer to the beginning of the first buffer. It makes sense to apply only if is_continuous tru...
Definition sstring.h:7302
Container for more efficient searching by string keys.
Definition sstring.h:6897
The mutable, owning string class. Contains an internal buffer for text of a given size.
Definition sstring.h:4637
constexpr void define_size()
Determine the length of the string. Searches for the character 0 in the string buffer to its capacity...
Definition sstring.h:5148
constexpr lstring(T &&value, Args &&... args)
String literal constructor.
Definition sstring.h:4888
my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:5019
constexpr void reset()
Makes the string empty and frees the external buffer, if there was one.
Definition sstring.h:5183
@ LocalCapacity
Definition sstring.h:4645
constexpr bool is_local() const noexcept
Find out whether a local or external buffer is used for characters.
Definition sstring.h:5139
my_type & operator=(my_type &&other) noexcept
Assignment operator by moving from a string of the same type.
Definition sstring.h:4962
constexpr size_t length() const noexcept
String length.
Definition sstring.h:5042
constexpr lstring(s_str other, Args &&... args)
A constructor from another string object.
Definition sstring.h:4769
constexpr lstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Constructor from string source with replacement.
Definition sstring.h:4839
constexpr lstring(size_t repeat, s_str pattern, Args &&... args)
String repetition constructor.
Definition sstring.h:4784
constexpr lstring(const my_type &other)
Copy from another string of the same type.
Definition sstring.h:4858
constexpr lstring(const my_type &other, Args &&... args)
Copy from another string of the same type, but with a different allocator.
Definition sstring.h:4873
my_type & operator=(const StrExprForType< K > auto &expr)
String expression appending operator.
Definition sstring.h:5032
constexpr K * reserve_no_preserve(size_t newSize)
Definition sstring.h:5077
my_type & operator=(const my_type &other)
Copy assignment operator from a string of the same type.
Definition sstring.h:4945
constexpr bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:5054
lstring(const Op &op, Args &&... args)
A fill constructor using a functor (see str_mutable::fill).
Definition sstring.h:4927
constexpr K * set_size(size_t newSize)
Sets the size of the current string, allocating space if necessary.
Definition sstring.h:5122
constexpr lstring(size_t count, K pad, Args &&... args)
Character repetition constructor.
Definition sstring.h:4799
constexpr lstring(const StrExprForType< K > auto &expr, Args &&... args)
Constructor from a string expression.
Definition sstring.h:4818
constexpr const K * symbols() const noexcept
Pointer to constant characters.
Definition sstring.h:5046
constexpr void clear()
Makes a string empty without changing the string buffer.
Definition sstring.h:5179
my_type & operator=(simple_str< K > other)
Assignment operator from simple_str.
Definition sstring.h:5007
constexpr bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:5058
constexpr void shrink_to_fit()
Reduces the size of the external buffer to the smallest possible size to hold the string....
Definition sstring.h:5165
constexpr lstring(my_type &&other) noexcept
Constructor for moving from a string of the same type.
Definition sstring.h:4902
constexpr K * reserve(size_t newSize)
Allocate a buffer large enough to hold newSize characters plus a terminating null.
Definition sstring.h:5099
constexpr K * str() noexcept
Pointer to a string buffer.
Definition sstring.h:5050
constexpr size_t capacity() const noexcept
Current row buffer capacity.
Definition sstring.h:5062
constexpr lstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Create an empty object.
Definition sstring.h:4754
Immutable owning string class.
Definition sstring.h:5290
constexpr my_type & operator=(const lstring< K, N, forShared, A > &other)
Assignment operator to another string of type lstring.
Definition sstring.h:5657
constexpr bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:5710
constexpr bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:5706
sstring(s_str other, Args &&... args)
A constructor from another string object.
Definition sstring.h:5433
sstring(size_t count, K pad, Args &&... args)
Character repetition constructor.
Definition sstring.h:5463
constexpr const K * symbols() const noexcept
Pointer to characters in the string.
Definition sstring.h:5698
constexpr sstring(const my_type &other) noexcept
String copy constructor.
Definition sstring.h:5521
constexpr my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:5645
sstring(size_t repeat, s_str pattern, Args &&... args)
String repetition constructor.
Definition sstring.h:5448
static my_type format(const FmtString< K, T... > &fmtString, T &&... args)
Get a string formatted with std::format.
Definition sstring.h:5740
constexpr my_type & operator=(my_type other) noexcept
Assignment operator to another string of the same type.
Definition sstring.h:5621
static my_type printf(const K *pattern, T &&... args)
Get a string formatted with std::sprintf.
Definition sstring.h:5726
constexpr sstring(T &&s, Args &&... args)
Initialize from a string literal.
Definition sstring.h:5596
constexpr sstring(lstring< K, N, true, Allocator > &&src)
A move constructor from lstring with an sstring-compatible external buffer.
Definition sstring.h:5548
constexpr size_t length() const noexcept
Line length.
Definition sstring.h:5702
constexpr sstring(my_type &&other) noexcept
Move constructor.
Definition sstring.h:5532
static my_type vformat(simple_str< K > fmtString, T &&... args)
Get a string formatted with std::vformat.
Definition sstring.h:5754
constexpr my_type & operator=(simple_str< K > other)
Assignment operator to another string of a different type.
Definition sstring.h:5633
constexpr my_type & make_empty() noexcept
Make the string empty.
Definition sstring.h:5691
constexpr my_type & operator=(const StrExprForType< K > auto &expr)
String expression assignment operator.
Definition sstring.h:5682
constexpr my_type & operator=(lstring< K, N, true, Allocator > &&other)
Assignment operator to a movable string of type lstring with a compatible buffer.
Definition sstring.h:5669
constexpr sstring(const StrExprForType< K > auto &expr, Args &&... args)
Constructor from a string expression.
Definition sstring.h:5482
sstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Constructor for the empty string.
Definition sstring.h:5418
constexpr ~sstring()
String destructor.
Definition sstring.h:5510
sstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Constructor from string source with replacement.
Definition sstring.h:5503
A class with basic constant string algorithms.
Definition sstring.h:644
constexpr size_t size() const
The size of the string in characters.
Definition sstring.h:710
constexpr bool operator!() const noexcept
Check for emptiness.
Definition sstring.h:823
constexpr bool starts_with(str_piece prefix) const noexcept
Whether the string begins with the given substring.
Definition sstring.h:1719
R lowered_only_ascii() const
Get a copy of the string in lowercase ASCII characters.
Definition sstring.h:1887
constexpr str_piece to_str() const noexcept
Convert itself to a "string chunk" that includes the entire string.
Definition sstring.h:729
R trimmed_left(T &&pattern) const
Get a string with the characters specified by the string literal removed from the left.
Definition sstring.h:2033
constexpr std::basic_string_view< K > to_sv() const noexcept
Convert to std::string_view.
Definition sstring.h:739
bool starts_with_iu(str_piece prefix) const noexcept
Whether the string starts with the given substring, case-insensitive Unicode characters of the first ...
Definition sstring.h:1758
R replaced(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0) const
Get a copy of the string with occurrences of substrings replaced.
Definition sstring.h:1931
constexpr bool equal_ia(str_piece text) const noexcept
Whether a string is equal to another string, character-by-character-insensitive, of ASCII characters.
Definition sstring.h:981
constexpr str_piece mid(size_t from, size_t len=-1) const noexcept
Get part of a string as "string chunk".
Definition sstring.h:794
R upperred_only_ascii() const
Get a copy of the string in uppercase ASCII characters.
Definition sstring.h:1875
constexpr size_t find_or_throw(str_piece pattern, size_t offset=0, Args &&... args) const noexcept
Find the beginning of the first occurrence of a substring in this string or throw an exception.
Definition sstring.h:1083
constexpr T split(str_piece delimeter, size_t offset=0) const
Split a string into substrings using a given delimiter.
Definition sstring.h:1693
constexpr convert_result< T > to_int() const noexcept
Convert a string to a number of the given type.
Definition sstring.h:1498
constexpr size_t find_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Find the beginning of the last occurrence of a substring in this string or the end of the string.
Definition sstring.h:1190
R trimmed_right_with_spaces(str_piece pattern) const
Get a string, removing characters specified by another string, as well as whitespace characters,...
Definition sstring.h:2207
constexpr T as_int() const noexcept
Convert a string to a number of the given type.
Definition sstring.h:1465
constexpr size_t find_end_of_last(str_piece pattern, size_t offset=-1) const noexcept
Find the end of the last occurrence of a substring in this string.
Definition sstring.h:1176
constexpr bool operator==(T &&other) const noexcept
Operator for comparing a string and a string literal for equality.
Definition sstring.h:924
constexpr bool prefix_in(str_piece text) const noexcept
Whether this string is the beginning of another string.
Definition sstring.h:1776
constexpr size_t find(K s, size_t offset=0) const noexcept
Find a character in this string.
Definition sstring.h:1231
int compare_iu(str_piece text) const noexcept
Compare strings character by character without taking into account the case of Unicode characters of ...
Definition sstring.h:1009
constexpr bool is_ascii() const noexcept
Whether the string contains only ASCII characters.
Definition sstring.h:1839
bool less_iu(str_piece text) const noexcept
Whether a string is smaller than another string, character-by-character-insensitive,...
Definition sstring.h:1032
R trimmed(str_piece pattern) const
Get a string with characters specified by another string removed, left and right.
Definition sstring.h:2125
R trimmed_left(str_piece pattern) const
Get a string with characters specified by another string removed from the left.
Definition sstring.h:2139
constexpr bool ends_with_iu(str_piece suffix) const noexcept
Whether the string ends with the specified substring, case-insensitive Unicode characters of the firs...
Definition sstring.h:1832
constexpr size_t find_or_all(str_piece pattern, size_t offset=0) const noexcept
Find the beginning of the first occurrence of a substring in this string or the end of the string.
Definition sstring.h:1113
constexpr size_t find_end_of_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Find the end of the last occurrence of a substring in this string, or the end of a string.
Definition sstring.h:1204
constexpr my_type str_mid(size_t from, size_t len=-1) const
Get part of a string with an object of the same type to which the method is applied,...
Definition sstring.h:1433
R trimmed_with_spaces(T &&pattern) const
Get a string with the characters specified by the string literal removed, as well as whitespace chara...
Definition sstring.h:2070
std::optional< double > to_double_hex() const noexcept
Convert string in hex form to double.
Definition sstring.h:1544
R upperred() const
Get a copy of the string in upper case Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:1899
R trimmed_right() const
Get a string with whitespace removed on the right.
Definition sstring.h:2003
constexpr bool contains(str_piece pattern, size_t offset=0) const noexcept
Whether the string contains the specified substring.
Definition sstring.h:1218
constexpr std::vector< size_t > find_all(str_piece pattern, size_t offset=0, size_t maxCount=0) const
Find all occurrences of a substring in this string.
Definition sstring.h:1306
R trimmed_right_with_spaces(T &&pattern) const
Get a string with the characters specified by the string literal removed, as well as whitespace chara...
Definition sstring.h:2108
constexpr bool ends_with(str_piece suffix) const noexcept
Whether the string ends with the specified substring.
Definition sstring.h:1791
R trimmed_with_spaces(str_piece pattern) const
Get a string, removing characters specified by another string, as well as whitespace characters,...
Definition sstring.h:2171
constexpr size_t find_or_all(K s, size_t offset=0) const noexcept
Find a character in this string or the end of a string.
Definition sstring.h:1250
constexpr R trimmed() const
Get a string with whitespace removed on the left and right.
Definition sstring.h:1979
constexpr size_t find(str_piece pattern, size_t offset=0) const noexcept
Find the beginning of the first occurrence of a substring in this string.
Definition sstring.h:1063
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len=0) const noexcept
Get part of a string as "simple_str".
Definition sstring.h:775
constexpr auto operator<=>(const base &other) const noexcept
String comparison operator.
Definition sstring.h:914
R lowered() const
Get a copy of the string in lowercase Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:1911
R trimmed_right(T &&pattern) const
Get a string with the characters specified by the string literal removed from the right.
Definition sstring.h:2048
constexpr size_t find_last(str_piece pattern, size_t offset=-1) const noexcept
Find the beginning of the last occurrence of a substring in this string.
Definition sstring.h:1163
constexpr std::pair< size_t, size_t > find_first_of_idx(str_piece pattern, size_t offset=0) const noexcept
Find the first occurrence of a character from a given character set.
Definition sstring.h:1351
constexpr K * place(K *ptr) const noexcept
Copy the string to the specified buffer.
Definition sstring.h:680
std::optional< double > to_double() const noexcept
Convert string to double.
Definition sstring.h:1508
R trimmed_left_with_spaces(str_piece pattern) const
Get a string, removing characters specified by another string, as well as whitespace characters,...
Definition sstring.h:2189
void copy_to(K *buffer, size_t bufSize)
Copy the string to the specified buffer.
Definition sstring.h:698
R trimmed_right(str_piece pattern) const
Get a string with characters specified by another string removed to the right.
Definition sstring.h:2153
R trimmed_left() const
Get a string with whitespace removed on the left.
Definition sstring.h:1991
constexpr int compare(str_piece o) const
Compare strings character by character.
Definition sstring.h:854
constexpr void for_all_finded(const Op &op, str_piece pattern, size_t offset=0, size_t maxCount=0) const
Call a functor on all found occurrences of a substring in this string.
Definition sstring.h:1285
constexpr int strcmp(const K *text) const
Compare with C-string character by character.
Definition sstring.h:865
R trimmed_left_with_spaces(T &&pattern) const
Get a string with the characters specified by the string literal removed, as well as whitespace chara...
Definition sstring.h:2089
constexpr my_type substr(ptrdiff_t from, ptrdiff_t len=0) const
Get a substring. Works similarly to operator(), only the result is the same type as the method applie...
Definition sstring.h:1420
constexpr size_t find_first_of(str_piece pattern, size_t offset=0) const noexcept
Find the first occurrence of a character from a given character set.
Definition sstring.h:1338
constexpr void as_number(T &t) const
Convert a string to an integer.
Definition sstring.h:1570
constexpr Splitter< K > splitter(str_piece delimeter) const
Retrieve a Splitter object by the given splitter, which allows sequential get substrings using the ne...
Definition sstring.h:2491
constexpr auto operator<=>(T &&other) const noexcept
Comparison operator between a string and a string literal.
Definition sstring.h:934
constexpr size_t find_end(str_piece pattern, size_t offset=0) const noexcept
Find the end of the occurrence of a substring in this string.
Definition sstring.h:1099
constexpr size_t find_last_of(str_piece pattern, size_t offset=str::npos) const noexcept
Find the last occurrence of a character from a given character set.
Definition sstring.h:1379
bool equal_iu(str_piece text) const noexcept
Whether a string is equal to another string, character-by-character-insensitive, of the Unicode chara...
Definition sstring.h:1021
constexpr size_t find_last_not_of(str_piece pattern, size_t offset=str::npos) const noexcept
Find the last occurrence of a character not from the given character set.
Definition sstring.h:1407
constexpr bool ends_with_ia(str_piece suffix) const noexcept
Whether the string ends with the specified substring in a case-insensitive ASCII character.
Definition sstring.h:1817
constexpr K at(ptrdiff_t idx) const
Get the character at the given position.
Definition sstring.h:836
constexpr size_t find_last(K s, size_t offset=-1) const noexcept
Find the last occurrence of a character in this string.
Definition sstring.h:1319
constexpr bool operator==(const base &other) const noexcept
Operator comparing strings for equality.
Definition sstring.h:905
constexpr int compare_ia(str_piece text) const noexcept
Compare strings character by character and not case sensitive ASCII characters.
Definition sstring.h:969
constexpr size_t find_end_or_all(str_piece pattern, size_t offset=0) const noexcept
Find the end of the first occurrence of a substring in this string, or the end of a string.
Definition sstring.h:1127
constexpr T splitf(str_piece delimeter, const Op &beforeFunc, size_t offset=0) const
Split a string into parts at a given delimiter, possibly applying a functor to each substring.
Definition sstring.h:1677
R trimmed(T &&pattern) const
Get a string with the characters specified by the string literal removed from the left and right.
Definition sstring.h:2018
constexpr bool equal(str_piece other) const noexcept
String comparison for equality.
Definition sstring.h:894
constexpr std::pair< size_t, size_t > find_last_of_idx(str_piece pattern, size_t offset=str::npos) const noexcept
Find the last occurrence of a character from a given character set.
Definition sstring.h:1392
constexpr expr_replaces< K, N - 1, L - 1 > replace_init(T &&pattern, M &&repl) const
Get a string expression that produces a string with replaced substrings given by string literals.
Definition sstring.h:1946
constexpr std::basic_string< K > to_string() const noexcept
Convert to std::string.
Definition sstring.h:749
constexpr bool less_ia(str_piece text) const noexcept
Whether a string is smaller than another string, character-by-character-insensitive,...
Definition sstring.h:992
constexpr str_piece from_to(size_t from, size_t to) const noexcept
Get the substring simple_str from position from to position to (not including it).
Definition sstring.h:816
void as_number(double &t) const
Convert string to double.
Definition sstring.h:1579
constexpr size_t find_first_not_of(str_piece pattern, size_t offset=0) const noexcept
Find the first occurrence of a character not from the given character set.
Definition sstring.h:1366
constexpr bool starts_with_ia(str_piece prefix) const noexcept
Whether the string begins with the given substring in a case-insensitive ASCII character.
Definition sstring.h:1744
Base class for working with mutable strings.
Definition sstring.h:3400
Impl & insert(size_t to, const A &expr)
Insert a string expression at the specified position.
Definition sstring.h:3940
Impl & operator<<=(const Op &fillFunction)
Fills a string with the fill method after the end of the string.
Definition sstring.h:4219
Impl & append(const A &expr)
Add a string expression to the end of the line.
Definition sstring.h:3824
Impl & operator<<(const Op &fillFunction)
Calls the passed functor, passing a reference to itself.
Definition sstring.h:4232
Impl & trim(str_piece pattern)
Remove characters included in the passed string at the beginning and end of the line.
Definition sstring.h:3634
Impl & upper_only_ascii()
Convert ASCII characters to uppercase.
Definition sstring.h:3698
Impl & lower_only_ascii()
Convert ASCII characters to lowercase.
Definition sstring.h:3713
Impl & trim_left()
Remove whitespace at the beginning of a line.
Definition sstring.h:3536
Impl & append_printf(const K *format, T &&... args)
Appends sprintf formatted output to the end of the line.
Definition sstring.h:4321
Impl & trim_right_with_wpaces(T &&pattern)
Remove characters included in a string literal, as well as whitespace, at the end of a string.
Definition sstring.h:3623
Impl & trim_left(str_piece pattern)
Remove characters included in the passed string at the beginning of the line.
Definition sstring.h:3645
Impl & trim_with_spaces(T &&pattern)
Remove characters included in a string literal, as well as whitespace, at the beginning and end of th...
Definition sstring.h:3597
Impl & prepend(str_piece other)
Add another line to the beginning of the line.
Definition sstring.h:3964
Impl & printf(const K *format, T &&... args)
Formats a string using sprintf.
Definition sstring.h:4305
Impl & with(const Op &fillFunction, Args &&... args)
Call a functor with a string and passed arguments.
Definition sstring.h:4540
Impl & append_vformatted_n(size_t max_write, str_piece format, T &&... args)
Appends std::vformat-formatted output to the end of the line, writing no more than the specified numb...
Definition sstring.h:4526
Impl & operator<<(const Op &fillFunction)
Fills a string with the fill method from position zero.
Definition sstring.h:4206
Impl & vformat(str_piece format, T &&... args)
Formats a string using std::vformat.
Definition sstring.h:4474
Impl & change(size_t from, size_t len, const A &expr)
Replace a piece of string with a string expression.
Definition sstring.h:3913
Impl & fill(size_t from, const Op &fillFunction)
Fill a string buffer using a functor.
Definition sstring.h:4178
Impl & change(size_t from, size_t len, str_piece other)
Replace a piece of string with another string.
Definition sstring.h:3897
Impl & remove(size_t from, size_t len)
Remove part of a line.
Definition sstring.h:3953
Impl & trim_left_with_spaces(T &&pattern)
Remove characters included in a string literal, as well as whitespace, at the beginning of a line.
Definition sstring.h:3610
Impl & trim_left(T &&pattern)
Remove characters included in a string literal at the beginning of the line.
Definition sstring.h:3571
Impl & trim_right(T &&pattern)
Remove characters included in a string literal at the end of the line.
Definition sstring.h:3584
Impl & trim_right_with_spaces(str_piece pattern)
Remove characters included in the passed string, as well as whitespace at the end of the string.
Definition sstring.h:3689
Impl & append_in(size_t pos, str_piece other)
Add another line starting at the given position.
Definition sstring.h:3864
Impl & vformat_from(size_t from, size_t max_write, str_piece format, T &&... args)
Appends std::vformat formatted output starting at the specified position.
Definition sstring.h:4407
Impl & trim_left_with_spaces(str_piece pattern)
Remove characters included in the passed string, as well as whitespace, at the beginning of the strin...
Definition sstring.h:3678
Impl & insert(size_t to, str_piece other)
Insert a line at the specified position.
Definition sstring.h:3926
Impl & vformat_n(size_t max_write, str_piece format, T &&... args)
Formats a string using std::vformat up to the specified size.
Definition sstring.h:4508
my_type & format(const FmtString< K, T... > &pattern, T &&... args)
Definition sstring.h:4442
Impl & printf_from(size_t from, const K *format, T &&... args)
Appends sprintf formatted output starting at the specified position.
Definition sstring.h:4251
Impl & operator+=(str_piece other)
Add another line to the end of the line.
Definition sstring.h:3835
Impl & trim_right()
Remove whitespace from the end of a line.
Definition sstring.h:3545
Impl & append(str_piece other)
Add another line to the end of the line.
Definition sstring.h:3812
Impl & trim_right(str_piece pattern)
Remove characters included in the passed string from the end of the string.
Definition sstring.h:3656
Impl & trim_with_spaces(str_piece pattern)
Remove characters included in the passed string, as well as whitespace characters,...
Definition sstring.h:3667
K * str() noexcept
Get a pointer to the string buffer.
Definition sstring.h:3509
my_type & format_from(size_t from, const FmtString< K, T... > &format, T &&... args)
Definition sstring.h:4378
Impl & prepend(const A &expr)
Add a string expression to the beginning of a line.
Definition sstring.h:3976
Impl & trim()
Remove whitespace from the beginning and end of a line.
Definition sstring.h:3527
Impl & lower()
Convert first plane characters (<0xFFFF) to lowercase Unicode.
Definition sstring.h:3747
Impl & replace(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Replace occurrences of a substring with another string.
Definition sstring.h:3993
Impl & upper()
Convert first plane characters (<0xFFFF) to uppercase Unicode.
Definition sstring.h:3732
Impl & replace_from(const From &f, str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Copy the source string, replacing occurrences of substrings with another string.
Definition sstring.h:4116
Impl & append_vformatted(str_piece format, T &&... args)
Appends std::vformat-formatted output to the end of the line.
Definition sstring.h:4490
Impl & append_formatted(const FmtString< K, T... > &format, T &&... args)
Appends std::format-formatted output to the end of the line.
Definition sstring.h:4458
Impl & append_in(size_t pos, const A &expr)
Add a string expression starting at the given position.
Definition sstring.h:3882
Impl & trim(T &&pattern)
Remove characters included in a string literal at the beginning and end of the line.
Definition sstring.h:3558
Impl & operator+=(const A &expr)
Add a string expression to the end of the line.
Definition sstring.h:3847
constexpr str_storable(Args &&... args)
Create an empty object.
Definition sstring.h:2914
void init_replaced(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0)
Initialization from string source with replacement.
Definition sstring.h:3000
constexpr void init_str_expr(const StrExprForType< K > auto &expr)
Initialization from a string expression.
Definition sstring.h:2978
static my_type upperred_from(const From &f, Args &&... args)
Create a copy of the passed string in uppercase Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:3261
constexpr void init_from_str_other(s_str other)
Initialization from another string object.
Definition sstring.h:2922
constexpr allocator_t & allocator()
Get the allocator.
Definition sstring.h:2891
constexpr void init_symb_repeat(size_t count, K pad)
Character repetition initialization.
Definition sstring.h:2958
static my_type upperred_only_ascii_from(const From &f, Args &&... args)
Create a string copy of the passed in uppercase ASCII characters.
Definition sstring.h:3231
static my_type lowered_from(const From &f, Args &&... args)
Create a copy of the passed string in lowercase Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:3278
constexpr void init_str_repeat(size_t repeat, s_str pattern)
String repetition initialization.
Definition sstring.h:2938
static my_type lowered_only_ascii_from(const From &f, Args &&... args)
Create a copy of the passed string in lowercase ASCII characters.
Definition sstring.h:3244
static my_type join(const T &strings, s_str delimeter, bool tail=false, bool skip_empty=false, Args &&... args)
Concatenate strings from the container into one string.
Definition sstring.h:3180
static my_type replaced_from(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Create a copy of the passed string with substrings replaced.
Definition sstring.h:3299
constexpr s_str_nt to_nts(size_t from=0) const
Get simple_str_nt starting at the given character.
Definition sstring.h:3124
Concept of a memory management type.
Definition sstring.h:3309
The concept of a string expression of a given character type.
Definition strexpr.h:339
A type concept that cannot modify a stored string.
Definition sstring.h:2833
A type concept that can modify a stored string.
Definition sstring.h:2826
A type concept that can store a string.
Definition sstring.h:2816
constexpr auto e_repl(simple_str< K > w, T &&p, X &&r)
Get a string expression that generates a string with all occurrences of a given substring replaced.
Definition sstring.h:6151
constexpr expr_num< K, T > e_num(T t)
Convert an integer to a string expression.
Definition sstring.h:5891
constexpr auto e_real(double t)
Convert a double number to a string expression.
Definition sstring.h:5985
auto e_repl_const_symbols(simple_str< K > src, Repl &&... other)
Returns a string expression that generates a string containing the given characters replaced with giv...
Definition sstring.h:6715
constexpr auto e_join(const T &s, L &&d)
Get a string expression concatenating the strings in the container into a single string with the give...
Definition sstring.h:6062
Library namespace.
Definition sstring.cpp:10
hashStrMap< u16s, T, strhash< u16s >, streql< u16s > > hashStrMapU
Hash dictionary type for char16_t strings, case sensitive search.
Definition sstring.h:7428
hashStrMap< u8s, T, strhashia< u8s >, streqlia< u8s > > hashStrMapAIA
Type of hash dictionary for char strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:7394
IntConvertResult
Enumeration with possible results of converting a string to an integer.
Definition sstring.h:256
@ Overflow
Переполнение, число не помещается в заданный тип
Definition sstring.h:259
@ Success
Успешно
Definition sstring.h:257
@ NotNumber
Вообще не число
Definition sstring.h:260
@ BadSymbolAtTail
Число закончилось не числовым символом
Definition sstring.h:258
hashStrMap< u32s, T, strhashiu< u32s >, streqliu< u32s > > hashStrMapUUIU
Hash dictionary type for char32_t strings, case insensitive search for Unicode characters up to 0xFFF...
Definition sstring.h:7459
hashStrMap< u32s, T, strhashia< u32s >, streqlia< u32s > > hashStrMapUUIA
Hash dictionary type for char32_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:7453
hashStrMap< wchar_t, T, strhashiu< wchar_t >, streqliu< wchar_t > > hashStrMapWIU
Hash dictionary type for wchar_t strings, case insensitive search for Unicode characters up to 0xFFFF...
Definition sstring.h:7421
hashStrMap< wchar_t, T, strhashia< wchar_t >, streqlia< wchar_t > > hashStrMapWIA
Hash dictionary type for wchar_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:7414
hashStrMap< u8s, T, strhash< u8s >, streql< u8s > > hashStrMapA
Type of hash dictionary for char strings, case sensitive search.
Definition sstring.h:7388
auto e_utf(simple_str< From > from)
Returns a string expression that converts a string of one character type to another type,...
Definition sstring.h:2807
hashStrMap< u16s, T, strhashiu< u16s >, streqliu< u16s > > hashStrMapUIU
Hash dictionary type for char16_t strings, case insensitive search for Unicode characters up to 0xFFF...
Definition sstring.h:7440
hashStrMap< u16s, T, strhashia< u16s >, streqlia< u16s > > hashStrMapUIA
Hash dictionary type for char16_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:7434
hashStrMap< wchar_t, T, strhash< wchar_t >, streql< wchar_t > > hashStrMapW
Hash dictionary type for wchar_t strings, case sensitive search.
Definition sstring.h:7407
hashStrMap< u8s, T, strhashiu< u8s >, streqliu< u8s > > hashStrMapAIU
Hash dictionary type for char strings, case-insensitive search for Unicode characters up to 0xFFFF.
Definition sstring.h:7400
std::ostream & operator<<(std::ostream &stream, ssa text)
Stream output operator simple_str.
Definition sstring.h:7716
hashStrMap< u32s, T, strhash< u32s >, streql< u32s > > hashStrMapUU
Hash dictionary type for char32_t strings, case sensitive search.
Definition sstring.h:7447
An object that allows you to sequentially copy content into a buffer of a given size.
Definition sstring.h:7319
bool is_end()
Check that the data has not yet run out.
Definition sstring.h:7326
size_t store(K *buffer, size_t size)
Save the next portion of data to the buffer.
Definition sstring.h:7339
constexpr expr_replace_symbols(simple_str< K > source, const std::vector< std::pair< K, simple_str< K > > > &repl)
Expression constructor.
Definition sstring.h:6339
constexpr expr_replaced(simple_str< K > w, simple_str< K > p, simple_str< K > r)
Constructor.
Definition sstring.h:6190
String expression to convert strings to different UTF types.
Definition sstring.h:2780
A class that claims to refer to a null-terminated string.
Definition sstring.h:2362
constexpr my_type to_nts(size_t from)
Get a null-terminated string by shifting the start by the specified number of characters.
Definition sstring.h:2421
constexpr simple_str_nt(T &&p) noexcept
Explicit constructor from C-string.
Definition sstring.h:2388
constexpr simple_str_nt(S &&s) noexcept
Constructor that allows you to initialize std::string and std::string_view objects provided that they...
Definition sstring.h:2401
The simplest immutable non-owning string class.
Definition sstring.h:2234
constexpr simple_str(T &&v) noexcept
Constructor from a string literal.
Definition sstring.h:2248
constexpr K operator[](size_t idx) const
Get the character from the specified position. Bounds checking is not performed.
Definition sstring.h:2311
constexpr my_type & remove_suffix(size_t delta)
Shortens the string by the specified number of characters.
Definition sstring.h:2335
constexpr simple_str(S &&s) noexcept
Constructor that allows you to initialize std::string and std::string_view objects provided that they...
Definition sstring.h:2263
constexpr size_t length() const noexcept
Get the length of the string.
Definition sstring.h:2268
constexpr const symb_type * symbols() const noexcept
Get a pointer to a constant buffer containing string characters.
Definition sstring.h:2275
constexpr my_type & remove_prefix(size_t delta)
Shifts the start of a line by the specified number of characters.
Definition sstring.h:2322
constexpr simple_str(const K *p, size_t l) noexcept
Constructor from pointer and length.
Definition sstring.h:2253
constexpr bool is_empty() const noexcept
Check if a string is empty.
Definition sstring.h:2282
constexpr bool is_same(simple_str< K > other) const noexcept
Check if two objects point to the same string.
Definition sstring.h:2291
constexpr bool is_part_of(simple_str< K > other) const noexcept
Check if a string is part of another string.
Definition sstring.h:2300
Concatenation of a reference to a string expression and the value of the string expression.
Definition strexpr.h:440