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 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] : 255;
330 template<
typename K, ToIntNumber T,
unsigned Base,
bool CheckOverflow>
332 static 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 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,
bool Mutable>
class buffer_pointers;
503template<
typename K,
typename Impl>
504class buffer_pointers<K, Impl, false> {
505 const Impl& d()
const {
return *
static_cast<const Impl*
>(
this); }
513 const K* c_str()
const {
return d().symbols(); }
520 const K* data()
const {
return d().symbols(); }
527 const K* begin()
const {
return d().symbols(); }
534 const K* end()
const {
return d().symbols() + d().length(); }
537template<
typename K,
typename Impl>
538class buffer_pointers<K, Impl, true> :
public buffer_pointers<K, Impl, false> {
539 Impl& d() {
return *
static_cast<Impl*
>(
this); }
540 using base = buffer_pointers<K, Impl, false>;
548 const K* data()
const {
return base::data(); }
555 const K* begin()
const {
return base::begin(); }
562 const K* end()
const {
return base::end(); }
569 K* data() {
return d().str(); }
576 K* begin() {
return d().str(); }
583 K* end() {
return d().str() + d().length(); }
610template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
611class str_algs :
public buffer_pointers<K, Impl, Mutable> {
612 const Impl& d()
const noexcept {
613 return *
static_cast<const Impl*
>(
this);
615 size_t _len()
const noexcept {
618 const K* _str()
const noexcept {
619 return d().symbols();
621 bool _is_empty()
const noexcept {
622 return d().is_empty();
627 using str_piece = StrRef;
628 using traits = ch_traits<K>;
629 using uni = unicode_traits<K>;
630 using uns_type = std::make_unsigned_t<K>;
631 using my_type = Impl;
632 using base = str_algs<K, StrRef, Impl, Mutable>;
633 str_algs() =
default;
647 constexpr K*
place(K* ptr)
const noexcept {
648 size_t myLen = _len();
650 traits::copy(ptr, _str(), myLen);
666 size_t tlen = std::min(_len(), bufSize - 1);
668 traits::copy(buffer, _str(), tlen);
687 constexpr operator str_piece() const noexcept {
688 return str_piece{_str(), _len()};
697 return {_str(), _len()};
705 template<
typename=
int>
requires is_one_of_std_char_v<K>
706 std::basic_string_view<K>
to_sv() const noexcept {
707 return {_str(), _len()};
715 template<
typename=
int>
requires is_one_of_std_char_v<K>
717 return {_str(), _len()};
742 constexpr str_piece
operator()(ptrdiff_t from, ptrdiff_t len = 0) const noexcept {
743 size_t myLen = _len(), idxStart = from >= 0 ? from : myLen > -from ? myLen + from : 0,
744 idxEnd = len > 0 ? idxStart + len : myLen > -len ? myLen + len : 0;
747 if (idxStart > idxEnd)
749 return str_piece{_str() + idxStart, idxEnd - idxStart};
761 constexpr str_piece
mid(
size_t from,
size_t len = -1) const noexcept {
762 size_t myLen = _len(), idxStart = from, idxEnd = from > std::numeric_limits<size_t>::max() - len ? myLen : from + len;
765 if (idxStart > idxEnd)
767 return str_piece{_str() + idxStart, idxEnd - idxStart};
783 constexpr str_piece
from_to(
size_t from,
size_t to)
const noexcept {
784 return str_piece{_str() + from, to - from};
803 K
at(ptrdiff_t idx)
const {
804 return _str()[idx >= 0 ? idx : _len() + idx];
808 constexpr int compare(
const K* text,
size_t len)
const {
809 size_t myLen = _len();
810 int cmp = traits::compare(_str(), text, std::min(myLen, len));
811 return cmp == 0 ? (myLen > len ? 1 : myLen == len ? 0 : -1) : cmp;
832 constexpr int strcmp(
const K* text)
const {
833 size_t myLen = _len(), idx = 0;
834 const K* ptr = _str();
835 for (; idx < myLen; idx++) {
836 uns_type s1 = (uns_type)text[idx];
840 uns_type s2 = (uns_type)ptr[idx];
843 }
else if (s1 > s2) {
847 return text[idx] == 0 ? 0 : -1;
850 constexpr bool equal(
const K* text,
size_t len)
const noexcept {
851 return len == _len() && traits::compare(_str(), text, len) == 0;
861 constexpr bool equal(str_piece other)
const noexcept {
862 return equal(other.symbols(), other.length());
872 constexpr bool operator==(
const base& other)
const noexcept {
873 return equal(other._str(), other._len());
882 return compare(other._str(), other._len()) <=> 0;
890 template<typename T, size_t N = const_lit_for<K, T>::Count>
892 return N - 1 == _len() && traits::compare(_str(), other, N - 1) == 0;
900 template<typename T, size_t N = const_lit_for<K, T>::Count>
902 size_t myLen = _len();
903 int cmp = traits::compare(_str(), other, std::min(myLen, N - 1));
904 int res = cmp == 0 ? (myLen > N - 1 ? 1 : myLen == N - 1 ? 0 : -1) : cmp;
910 int compare_ia(
const K* text,
size_t len)
const noexcept {
912 return _is_empty() ? 0 : 1;
913 size_t myLen = _len(), checkLen = std::min(myLen, len);
914 const uns_type *ptr1 =
reinterpret_cast<const uns_type*
>(_str()), *ptr2 =
reinterpret_cast<const uns_type*
>(text);
916 uns_type s1 = *ptr1++, s2 = *ptr2++;
919 s1 = makeAsciiLower(s1);
920 s2 = makeAsciiLower(s2);
926 return myLen == len ? 0 : myLen > len ? 1 : -1;
937 return compare_ia(text.symbols(), text.length());
949 return text.length() == _len() && compare_ia(text.symbols(), text.length()) == 0;
960 return compare_ia(text.symbols(), text.length()) < 0;
963 int compare_iu(
const K* text,
size_t len)
const noexcept {
965 return _is_empty() ? 0 : 1;
966 return uni::compareiu(_str(), _len(), text, len);
977 return compare_iu(text.symbols(), text.length());
989 return text.length() == _len() && compare_iu(text.symbols(), text.length()) == 0;
1000 return compare_iu(text.symbols(), text.length()) < 0;
1003 size_t find(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
1004 size_t lenText = _len();
1007 if (!lenPattern || offset >= lenText || offset + lenPattern > lenText)
1010 const K *text = _str(), *last = text + lenText - lenPattern, first = pattern[0];
1012 for (
const K* fnd = text + offset;; ++fnd) {
1013 fnd = traits::find(fnd, last - fnd, first);
1016 if (traits::compare(fnd + 1, pattern, lenPattern) == 0)
1017 return static_cast<size_t>(fnd - text);
1030 size_t find(str_piece pattern,
size_t offset = 0) const noexcept {
1049 template<
typename Exc,
typename ... Args>
requires std::is_constructible_v<Exc, Args...>
1050 size_t find_or_throw(str_piece pattern,
size_t offset = 0, Args&& ... args)
const noexcept {
1051 if (
auto fnd = find(pattern.symbols(), pattern.length(), offset); fnd != str::npos) {
1054 throw Exc(std::forward<Args>(args)...);
1066 size_t find_end(str_piece pattern,
size_t offset = 0) const noexcept {
1067 size_t fnd = find(pattern.
symbols(), pattern.
length(), offset);
1068 return fnd == str::npos ? fnd : fnd + pattern.
length();
1080 size_t find_or_all(str_piece pattern,
size_t offset = 0) const noexcept {
1081 auto fnd = find(pattern.
symbols(), pattern.
length(), offset);
1082 return fnd == str::npos ? _len() : fnd;
1095 auto fnd = find(pattern.
symbols(), pattern.
length(), offset);
1096 return fnd == str::npos ? _len() : fnd + pattern.
length();
1099 size_t find_last(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
1100 if (lenPattern == 1)
1101 return find_last(pattern[0], offset);
1102 size_t lenText = std::min(_len(), offset);
1105 if (!lenPattern || lenPattern > lenText)
1109 const K *text = _str() + lenPattern, last = pattern[lenPattern];
1110 lenText -= lenPattern;
1112 if (text[--lenText] == last) {
1113 if (traits::compare(text + lenText - lenPattern, pattern, lenPattern) == 0) {
1130 size_t find_last(str_piece pattern,
size_t offset = -1) const noexcept {
1131 return find_last(pattern.
symbols(), pattern.
length(), offset);
1144 size_t fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
1145 return fnd == str::npos ? fnd : fnd + pattern.
length();
1158 auto fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
1159 return fnd == str::npos ? _len() : fnd;
1172 size_t fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
1173 return fnd == str::npos ? _len() : fnd + pattern.
length();
1185 bool contains(str_piece pattern,
size_t offset = 0) const noexcept {
1186 return find(pattern, offset) != str::npos;
1198 size_t find(K s,
size_t offset = 0) const noexcept {
1199 size_t len = _len();
1201 const K *str = _str(), *fnd = traits::find(str + offset, len - offset, s);
1203 return static_cast<size_t>(fnd - str);
1218 size_t len = _len();
1220 const K *str = _str(), *fnd = traits::find(str + offset, len - offset, s);
1222 return static_cast<size_t>(fnd - str);
1227 template<
typename Op>
1228 void for_all_finded(
const Op& op,
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
1231 while (maxCount-- > 0) {
1232 size_t fnd = find(pattern, patternLen, offset);
1233 if (fnd == str::npos)
1236 offset = fnd + patternLen;
1251 template<
typename Op>
1252 void for_all_finded(
const Op& op, str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
1253 for_all_finded(op, pattern.
symbols(), pattern.
length(), offset, maxCount);
1256 std::vector<size_t> find_all(
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
1257 std::vector<size_t> result;
1258 for_all_finded([&](
auto f) { result.push_back(f); }, pattern, patternLen, offset, maxCount);
1273 std::vector<size_t>
find_all(str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
1274 return find_all(pattern.
symbols(), pattern.
length(), offset, maxCount);
1287 size_t len = std::min(_len(), offset);
1288 const K *text = _str();
1290 if (text[--len] == s)
1306 return std::string_view{_str(), _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
1319 const K* text = _str();
1320 size_t fnd = std::string_view{text, _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
1321 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
1334 return std::string_view{_str(), _len()}.find_first_not_of(std::string_view{pattern.str, pattern.len}, offset);
1346 size_t find_last_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
1347 return std::string_view{_str(), _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
1359 std::pair<size_t, size_t>
find_last_of_idx(str_piece pattern,
size_t offset = str::npos)
const noexcept {
1360 const K* text = _str();
1361 size_t fnd = std::string_view{text, _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
1362 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
1375 return std::string_view{_str(), _len()}.find_last_not_of(std::string_view{pattern.str, pattern.len}, offset);
1387 my_type
substr(ptrdiff_t from, ptrdiff_t len = 0)
const {
1388 return my_type{d()(from, len)};
1400 my_type
str_mid(
size_t from,
size_t len = -1)
const {
1401 return my_type{d().mid(from, len)};
1431 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
1433 auto [res, err, _] = int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
1464 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
1466 return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
1474 template<
bool SkipWS = true,
bool AllowPlus = true>
1476 size_t len = _len();
1477 const K* ptr = _str();
1478 if constexpr (SkipWS) {
1479 while (len && uns_type(*ptr) <=
' ') {
1484 if constexpr (AllowPlus) {
1485 if (len && *ptr == K(
'+')) {
1494 if constexpr(
sizeof(K) == 1) {
1496 if (std::from_chars(ptr, ptr + len, d).ec == std::errc{}) {
1502 return impl_to_double(ptr, ptr + len);
1510 template<
bool SkipWS = true>
requires (
sizeof(K) == 1)
1512 size_t len = _len();
1513 const K* ptr = _str();
1514 if constexpr (SkipWS) {
1515 while (len && uns_type(*ptr) <=
' ') {
1522 if (std::from_chars(ptr, ptr + len, d, std::chars_format::hex).ec == std::errc{}) {
1536 template<ToIntNumber T>
1548 t = res ? *res : std::nan(
"0");
1551 template<
typename T,
typename Op>
1552 T splitf(
const K* delimeter,
size_t lenDelimeter,
const Op& beforeFunc,
size_t offset)
const {
1553 size_t mylen = _len();
1554 std::conditional_t<std::is_same_v<T, void>, char, T> results;
1555 str_piece me{_str(), mylen};
1556 for (
int i = 0;; i++) {
1557 size_t beginOfDelim = find(delimeter, lenDelimeter, offset);
1558 if (beginOfDelim == str::npos) {
1559 str_piece last{me.symbols() + offset, me.length() - offset};
1560 if constexpr (std::is_invocable_v<Op, str_piece&>) {
1563 if constexpr (
requires { results.emplace_back(last); }) {
1564 if (last.is_same(me)) {
1567 results.emplace_back(d());
1569 results.emplace_back(last);
1571 }
else if constexpr (
requires { results.push_back(last); }) {
1572 if (last.is_same(me)) {
1575 results.push_back(d());
1577 results.push_back(last);
1579 }
else if constexpr (
requires {results[i] = last;} &&
requires{std::size(results);}) {
1580 if (i < std::size(results)) {
1581 if (last.is_same(me)) {
1591 str_piece piece{me.symbols() + offset, beginOfDelim - offset};
1592 if constexpr (std::is_invocable_v<Op, str_piece&>) {
1595 if constexpr (
requires { results.emplace_back(piece); }) {
1596 results.emplace_back(piece);
1597 }
else if constexpr (
requires { results.push_back(piece); }) {
1598 results.push_back(piece);
1599 }
else if constexpr (
requires { results[i] = piece; } &&
requires{std::size(results);}) {
1600 if (i < std::size(results)) {
1602 if (i == results.size() - 1) {
1607 offset = beginOfDelim + lenDelimeter;
1609 if constexpr (!std::is_same_v<T, void>) {
1643 template<
typename T,
typename Op>
1644 T
splitf(str_piece delimeter,
const Op& beforeFunc,
size_t offset = 0)
const {
1645 return splitf<T>(delimeter.
symbols(), delimeter.
length(), beforeFunc, offset);
1659 template<
typename T>
1660 T
split(str_piece delimeter,
size_t offset = 0)
const {
1661 return splitf<T>(delimeter.
symbols(), delimeter.
length(), 0, offset);
1677 constexpr bool starts_with(
const K* prefix,
size_t l)
const noexcept {
1678 return _len() >= l && 0 == traits::compare(_str(), prefix, l);
1687 return starts_with(prefix.symbols(), prefix.length());
1690 constexpr bool starts_with_ia(
const K* prefix,
size_t len)
const noexcept {
1691 size_t myLen = _len();
1695 const K* ptr1 = _str();
1697 K s1 = *ptr1++, s2 = *prefix++;
1700 if (makeAsciiLower(s1) != makeAsciiLower(s2))
1712 return starts_with_ia(prefix.symbols(), prefix.length());
1716 bool starts_with_iu(
const K* prefix,
size_t len)
const noexcept {
1717 return _len() >= len && 0 == uni::compareiu(_str(), len, prefix, len);
1726 return starts_with_iu(prefix.symbols(), prefix.length());
1731 constexpr bool prefix_in(
const K* text,
size_t len)
const noexcept {
1732 size_t myLen = _len();
1735 return !myLen || 0 == traits::compare(text, _str(), myLen);
1744 return prefix_in(text.symbols(), text.length());
1748 constexpr bool ends_with(
const K* suffix,
size_t len)
const noexcept {
1749 size_t myLen = _len();
1750 return len <= myLen && traits::compare(_str() + myLen - len, suffix, len) == 0;
1759 return ends_with(suffix.symbols(), suffix.length());
1763 constexpr bool ends_with_ia(
const K* suffix,
size_t len)
const noexcept {
1764 size_t myLen = _len();
1768 const K* ptr1 = _str() + myLen - len;
1770 K s1 = *ptr1++, s2 = *suffix++;
1773 if (makeAsciiLower(s1) != makeAsciiLower(s2))
1785 return ends_with_ia(suffix.symbols(), suffix.length());
1789 constexpr bool ends_with_iu(
const K* suffix,
size_t len)
const noexcept {
1790 size_t myLen = _len();
1791 return myLen >= len && 0 == uni::compareiu(_str() + myLen - len, len, suffix, len);
1800 return ends_with_iu(suffix.symbols(), suffix.length());
1809 const int sl = ascii_mask<K>::WIDTH;
1810 const size_t mask = ascii_mask<K>::VALUE;
1811 size_t len = _len();
1812 const uns_type* ptr =
reinterpret_cast<const uns_type*
>(_str());
1813 if constexpr (sl > 1) {
1814 const size_t roundMask =
sizeof(size_t) - 1;
1815 while (len >= sl && (
reinterpret_cast<size_t>(ptr) & roundMask) != 0) {
1821 if (*
reinterpret_cast<const size_t*
>(ptr) & mask)
1841 template<
typename R = my_type>
1843 return R::uppered_only_ascii_from(d());
1853 template<
typename R = my_type>
1855 return R::lowered_only_ascii_from(d());
1865 template<
typename R = my_type>
1867 return R::uppered_from(d());
1877 template<
typename R = my_type>
1879 return R::lowered_from(d());
1897 template<
typename R = my_type>
1898 R
replaced(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0)
const {
1899 return R::replaced_from(d(), pattern, repl, offset, maxCount);
1912 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename M,
size_t L = const_lit_for<K, M>::Count>
1914 return expr_replaces<K, N - 1, L - 1>{d(), pattern, repl};
1917 template<StrType<K> From>
1918 static my_type make_trim_op(
const From& from,
const auto& opTrim) {
1919 str_piece sfrom = from, newPos = opTrim(sfrom);
1920 return newPos.is_same(sfrom) ? my_type{from} : my_type{newPos};
1922 template<TrimS
ides S, StrType<K> From>
1923 static my_type trim_static(
const From& from) {
1924 return make_trim_op(from, trim_operator<S, K,
static_cast<size_t>(-1),
true>{});
1927 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count, StrType<K> From>
1928 requires is_const_pattern<N>
1929 static my_type trim_static(
const From& from, T&& pattern) {
1930 return make_trim_op(from, trim_operator<S, K, N - 1, withSpaces>{pattern});
1933 template<TrimS
ides S,
bool withSpaces, StrType<K> From>
1934 static my_type trim_static(
const From& from, str_piece pattern) {
1935 return make_trim_op(from, trim_operator<S, K, 0, withSpaces>{{pattern}});
1945 template<
typename R = str_piece>
1947 return R::template trim_static<TrimSides::TrimAll>(d());
1957 template<
typename R = str_piece>
1959 return R::template trim_static<TrimSides::TrimLeft>(d());
1969 template<
typename R = str_piece>
1971 return R::template trim_static<TrimSides::TrimRight>(d());
1983 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1984 requires is_const_pattern<N>
1986 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
1998 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1999 requires is_const_pattern<N>
2001 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
2013 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2014 requires is_const_pattern<N>
2016 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
2035 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2036 requires is_const_pattern<N>
2038 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
2054 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2055 requires is_const_pattern<N>
2057 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
2073 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
2074 requires is_const_pattern<N>
2076 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
2091 template<
typename R = str_piece>
2093 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
2105 template<
typename R = str_piece>
2107 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
2119 template<
typename R = str_piece>
2121 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
2137 template<
typename R = str_piece>
2139 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
2155 template<
typename R = str_piece>
2157 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
2173 template<
typename R = str_piece>
2175 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
2201struct simple_str : str_algs<K, simple_str<K>, simple_str<K>, false> {
2202 using symb_type = K;
2203 using my_type = simple_str<K>;
2205 const symb_type* str;
2208 simple_str() =
default;
2214 template<typename T, size_t N = const_lit_for<K, T>::Count>
2220 constexpr simple_str(
const K* p,
size_t l) noexcept : str(p), len(l) {}
2227 template<
typename S>
2228 requires(std::is_same_v<S, std::string&> || std::is_same_v<S, const std::string&>
2229 || std::is_same_v<S, std::string_view&> || std::is_same_v<S, const std::string_view&>)
2230 constexpr simple_str(S&& s) noexcept : str(s.data()), len(s.length()) {}
2242 constexpr const symb_type*
symbols() const noexcept {
2258 bool is_same(simple_str<K> other)
const noexcept {
2259 return str == other.str && len == other.len;
2268 return str >= other.str && str + len <= other.str + other.len;
2329struct simple_str_nt : simple_str<K> {
2330 using symb_type = K;
2331 using my_type = simple_str_nt<K>;
2332 using base = simple_str<K>;
2335 constexpr static const K empty_string[1] = {0};
2337 simple_str_nt() =
default;
2354 template<
typename T>
requires std::is_same_v<std::remove_const_t<std::remove_pointer_t<std::remove_cvref_t<T>>>, K>
2357 base::str = base::len ? p : empty_string;
2365 template<
typename S>
2366 requires(std::is_same_v<S, std::string&> || std::is_same_v<S, const std::string&>
2367 || std::is_same_v<S, std::string_view&> || std::is_same_v<S, const std::string_view&>)
2370 static const my_type empty_str;
2377 operator const K*()
const noexcept {
2389 if (from > base::len) {
2392 return {base::str + from, base::len - from};
2397inline const simple_str_nt<K> simple_str_nt<K>::empty_str{simple_str_nt<K>::empty_string, 0};
2399using ssa = simple_str<u8s>;
2400using ssw = simple_str<wchar_t>;
2401using ssu = simple_str<u16s>;
2402using ssuu = simple_str<u32s>;
2403using stra = simple_str_nt<u8s>;
2404using strw = simple_str_nt<wchar_t>;
2405using stru = simple_str_nt<u16s>;
2406using struu = simple_str_nt<u32s>;
2426 return text_.length() == str::npos;
2435 if (!text_.length()) {
2440 }
else if (text_.length() == str::npos) {
2441 return {
nullptr, 0};
2443 size_t pos = text_.find(delim_),
next = 0;
2444 if (pos == str::npos) {
2445 pos = text_.length();
2448 next = pos + delim_.length();
2457template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
2462template<
typename K,
bool withSpaces>
2463struct CheckSpaceTrim {
2464 bool is_trim_spaces(K s)
const {
2465 return s ==
' ' || (s >= 9 && s <= 13);
2469struct CheckSpaceTrim<K, false> {
2470 bool is_trim_spaces(K)
const {
2476struct CheckSymbolsTrim {
2477 simple_str<K> symbols;
2478 bool is_trim_symbols(K s)
const {
2479 return symbols.len != 0 && simple_str<K>::traits::find(symbols.str, symbols.len, s) !=
nullptr;
2483template<
typename K,
size_t N>
2484struct CheckConstSymbolsTrim {
2485 const const_lit_to_array<K, N> symbols;
2487 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
2488 constexpr CheckConstSymbolsTrim(T&& s) : symbols(std::forward<T>(s)) {}
2490 bool is_trim_symbols(K s)
const noexcept {
2491 return symbols.contain(s);
2496struct CheckConstSymbolsTrim<K, 0> {
2497 bool is_trim_symbols(K)
const {
2502template<
typename K,
size_t N>
2503struct SymbSelector {
2504 using type = CheckConstSymbolsTrim<K, N>;
2508struct SymbSelector<K, 0> {
2509 using type = CheckSymbolsTrim<K>;
2513struct SymbSelector<K, static_cast<size_t>(-1)> {
2514 using type = CheckConstSymbolsTrim<K, 0>;
2517template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces>
2518struct trim_operator : SymbSelector<K, N>::type, CheckSpaceTrim<K, withSpaces> {
2519 bool isTrim(K s)
const {
2520 return CheckSpaceTrim<K, withSpaces>::is_trim_spaces(s) || SymbSelector<K, N>::type::is_trim_symbols(s);
2522 simple_str<K> operator()(simple_str<K> from)
const {
2523 if constexpr ((S & TrimSides::TrimLeft) != 0) {
2525 if (isTrim(*from.str)) {
2532 if constexpr ((S & TrimSides::TrimRight) != 0) {
2533 const K* back = from.str + from.len - 1;
2535 if (isTrim(*back)) {
2546template<TrimS
ides S,
typename K>
2547using SimpleTrim = trim_operator<S, K, size_t(-1),
true>;
2549using trim_w = SimpleTrim<TrimSides::TrimAll, u16s>;
2550using trim_a = SimpleTrim<TrimSides::TrimAll, u8s>;
2551using triml_w = SimpleTrim<TrimSides::TrimLeft, u16s>;
2552using triml_a = SimpleTrim<TrimSides::TrimLeft, u8s>;
2553using trimr_w = SimpleTrim<TrimSides::TrimRight, u16s>;
2554using trimr_a = SimpleTrim<TrimSides::TrimRight, u8s>;
2556template<TrimSides S = TrimSides::TrimAll, bool withSpaces = false, typename K, typename T, size_t N = const_lit_for<K, T>::Count>
2557 requires is_const_pattern<N>
2558inline auto trimOp(T&& pattern) {
2559 return trim_operator<S, K, N - 1, withSpaces>{pattern};
2562template<TrimS
ides S = TrimS
ides::TrimAll,
bool withSpaces = false,
typename K>
2563inline auto trimOp(simple_str<K> pattern) {
2564 return trim_operator<S, K, 0, withSpaces>{pattern};
2567template<
typename Src,
typename Dest>
2568struct utf_convert_selector;
2571struct utf_convert_selector<u8s, u16s> {
2572 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
2573 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u16s* dest);
2577struct utf_convert_selector<u8s, u32s> {
2578 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
2579 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u32s* dest);
2583struct utf_convert_selector<u8s, wchar_t> {
2584 static size_t need_len(
const u8s* src,
size_t srcLen) {
2585 return utf_convert_selector<u8s, wchar_type>::need_len(src, srcLen);
2587 static size_t convert(
const u8s* src,
size_t srcLen,
wchar_t* dest) {
2588 return utf_convert_selector<u8s, wchar_type>::convert(src, srcLen, to_w(dest));
2593struct utf_convert_selector<u16s, u8s> {
2594 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
2595 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u8s* dest);
2599struct utf_convert_selector<u16s, u32s> {
2600 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
2601 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u32s* dest);
2605struct utf_convert_selector<u16s, u16s> {
2608 static size_t need_len(
const u16s* src,
size_t srcLen) {
2611 static size_t convert(
const u16s* src,
size_t srcLen, u16s* dest) {
2612 ch_traits<u16s>::copy(dest, src, srcLen + 1);
2618struct utf_convert_selector<u32s, u32s> {
2621 static size_t need_len(
const u32s* src,
size_t srcLen) {
2624 static size_t convert(
const u32s* src,
size_t srcLen, u32s* dest) {
2625 ch_traits<u32s>::copy(dest, src, srcLen + 1);
2631struct utf_convert_selector<u16s, wchar_t> {
2632 static size_t need_len(
const u16s* src,
size_t srcLen) {
2633 return utf_convert_selector<u16s, wchar_type>::need_len(src, srcLen);
2635 static size_t convert(
const u16s* src,
size_t srcLen,
wchar_t* dest) {
2636 return utf_convert_selector<u16s, wchar_type>::convert(src, srcLen, to_w(dest));
2641struct utf_convert_selector<u32s, u8s> {
2642 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
2643 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u8s* dest);
2647struct utf_convert_selector<u32s, u16s> {
2648 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
2649 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u16s* dest);
2653struct utf_convert_selector<u32s, wchar_t> {
2654 static size_t need_len(
const u32s* src,
size_t srcLen) {
2655 return utf_convert_selector<u32s, wchar_type>::need_len(src, srcLen);
2657 static size_t convert(
const u32s* src,
size_t srcLen,
wchar_t* dest) {
2658 return utf_convert_selector<u32s, wchar_type>::convert(src, srcLen, to_w(dest));
2663struct utf_convert_selector<wchar_t, u8s> {
2664 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2665 return utf_convert_selector<wchar_type, u8s>::need_len(to_w(src), srcLen);
2667 static size_t convert(
const wchar_t* src,
size_t srcLen, u8s* dest) {
2668 return utf_convert_selector<wchar_type, u8s>::convert(to_w(src), srcLen, dest);
2673struct utf_convert_selector<wchar_t, u16s> {
2674 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2675 return utf_convert_selector<wchar_type, u16s>::need_len(to_w(src), srcLen);
2677 static size_t convert(
const wchar_t* src,
size_t srcLen, u16s* dest) {
2678 return utf_convert_selector<wchar_type, u16s>::convert(to_w(src), srcLen, dest);
2683struct utf_convert_selector<wchar_t, u32s> {
2684 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2685 return utf_convert_selector<wchar_type, u32s>::need_len(to_w(src), srcLen);
2687 static size_t convert(
const wchar_t* src,
size_t srcLen, u32s* dest) {
2688 return utf_convert_selector<wchar_type, u32s>::convert(to_w(src), srcLen, dest);
2706template<
typename K,
typename Impl>
2707class from_utf_convertable {
2709 from_utf_convertable() =
default;
2710 using my_type = Impl;
2718 template<
typename O>
2719 requires(!std::is_same_v<O, K>)
2721 using worker = utf_convert_selector<O, K>;
2722 Impl* d =
static_cast<Impl*
>(
this);
2723 size_t len = init.
length();
2727 size_t need = worker::need_len(init.
symbols(), len);
2728 K* str = d->init(need);
2730 worker::convert(init.
symbols(), len, str);
2733 template<
typename O,
typename I,
bool M>
2734 requires(!std::is_same_v<O, K>)
2746template<
typename From,
typename To>
requires (!std::is_same_v<From, To>)
2748 using symb_type = To;
2749 using worker = utf_convert_selector<From, To>;
2753 size_t length()
const noexcept {
2754 return worker::need_len(source_.symbols(), source_.length());
2756 To* place(To* ptr)
const noexcept {
2757 return ptr + worker::convert(source_.symbols(), source_.length(), ptr);
2773template<
typename To,
typename From>
requires (!std::is_same_v<From, To>)
2782template<
typename A,
typename K>
2784 A::is_str_storable ==
true;
2785 std::is_same_v<typename A::symb_type, K>;
2792template<
typename A,
typename K>
2799template<
typename A,
typename K>
2844template<
typename K,
typename Impl,
typename Allocator>
2845class str_storable :
protected Allocator {
2847 using my_type = Impl;
2848 using traits = ch_traits<K>;
2849 using allocator_t = Allocator;
2857 return *
static_cast<Allocator*
>(
this);
2859 const allocator_t& allocator()
const {
2860 return *
static_cast<const Allocator*
>(
this);
2863 using uni = unicode_traits<K>;
2865 Impl& d() noexcept {
2866 return *
static_cast<Impl*
>(
this);
2868 const Impl& d() const noexcept {
2869 return *
static_cast<const Impl*
>(
this);
2871 template<
typename... Args>
2872 requires std::is_constructible_v<allocator_t, Args...>
2873 explicit constexpr str_storable(
size_t size, Args&&... args) : Allocator(std::forward<Args>(args)...) {
2880 template<StrType<K> From,
typename Op1,
typename... Args>
2881 requires std::is_constructible_v<allocator_t, Args...>
2882 static my_type changeCaseAscii(
const From& f,
const Op1& opMakeNeedCase, Args&&... args) {
2883 my_type result{std::forward<Args>(args)...};
2884 size_t len = f.length();
2886 const K* source = f.symbols();
2887 K* destination = result.init(len);
2888 for (
size_t l = 0; l < len; l++) {
2889 destination[l] = opMakeNeedCase(source[l]);
2898 template<
typename T,
bool Dummy = true>
2900 template<
typename From,
typename Op1,
typename... Args>
2901 requires std::is_constructible_v<allocator_t, Args...>
2902 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
2903 my_type result{std::forward<Args>(args)...};
2904 size_t len = f.length();
2906 opChangeCase(f.symbols(), len, result.init(len));
2913 template<
bool Dummy>
2914 struct ChangeCase<u8s, Dummy> {
2915 template<
typename From,
typename Op1,
typename... Args>
2916 requires std::is_constructible_v<allocator_t, Args...>
2917 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
2918 my_type result{std::forward<Args>(args)...};
2920 size_t len = f.length();
2922 const K* ptr = f.symbols();
2923 K* pWrite = result.init(len);
2925 const u8s* source = ptr;
2927 size_t newLen = opChangeCase(source, len, dest, len);
2931 result.set_size(newLen);
2932 }
else if (newLen > len) {
2935 size_t readed =
static_cast<size_t>(source - ptr);
2936 size_t writed =
static_cast<size_t>(dest - pWrite);
2937 pWrite = result.set_size(newLen);
2938 dest = pWrite + writed;
2939 opChangeCase(source, len - readed, dest, newLen - writed);
2948 using s_str = simple_str<K>;
2949 using s_str_nt = simple_str_nt<K>;
2951 inline static constexpr bool is_str_storable =
true;
2959 template<
typename... Args>
2960 requires std::is_constructible_v<allocator_t, Args...>
2961 constexpr str_storable(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
2962 : Allocator(std::forward<Args>(args)...) {
2974 template<
typename... Args>
2975 requires std::is_constructible_v<allocator_t, Args...>
2976 constexpr str_storable(s_str other, Args&&... args) : Allocator(std::forward<Args>(args)...) {
2978 K* ptr = d().init(other.length());
2979 traits::copy(ptr, other.symbols(), other.length());
2980 ptr[other.length()] = 0;
2994 template<
typename... Args>
2995 requires std::is_constructible_v<allocator_t, Args...>
2996 constexpr str_storable(
size_t repeat, s_str pattern, Args&&... args) : Allocator(std::forward<Args>(args)...) {
2997 size_t l = pattern.
length(), allLen = l * repeat;
2999 K* ptr = d().init(allLen);
3000 for (
size_t i = 0; i < repeat; i++) {
3001 traits::copy(ptr, pattern.
symbols(), l);
3018 template<
typename... Args>
3019 requires std::is_constructible_v<allocator_t, Args...>
3020 str_storable(
size_t count, K pad, Args&&... args) : Allocator(std::forward<Args>(args)...) {
3022 K* str = d().init(count);
3023 traits::assign(str, count, pad);
3042 template<
typename... Args>
3043 requires std::is_constructible_v<allocator_t, Args...>
3045 size_t len = expr.length();
3047 *expr.place(d().init(len)) = 0;
3067 template<StrType<K> From,
typename... Args>
3068 requires std::is_constructible_v<allocator_t, Args...>
3069 str_storable(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
3070 : Allocator(std::forward<Args>(args)...) {
3072 auto findes = f.find_all(pattern, offset, maxCount);
3073 if (!findes.size()) {
3074 new (this) my_type{f};
3077 size_t srcLen = f.length();
3078 size_t newSize = srcLen +
static_cast<ptrdiff_t
>(repl.len - pattern.len) * findes.size();
3081 new (
this) my_type{};
3085 K* ptr = d().init(newSize);
3086 const K* src = f.symbols();
3088 for (
const auto& s: findes) {
3089 size_t copyLen = s - from;
3091 traits::copy(ptr, src + from, copyLen);
3095 traits::copy(ptr, repl.str, repl.len);
3098 from = s + pattern.len;
3102 traits::copy(ptr, src + from, srcLen);
3113 operator const K*()
const noexcept {
3114 return d().symbols();
3125 size_t len = d().
length();
3129 return {d().symbols() + from, len - from};
3137 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>
4632class decl_empty_bases lstring :
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 from_utf_convertable<K, lstring<K, N, forShared, Allocator>> {
4638 using symb_type = K;
4639 using my_type = lstring<K, N, forShared, Allocator>;
4640 using allocator_t = Allocator;
4649 extra = forShared ?
sizeof(SharedStringData<K>) : 0,
4652 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
4653 using base_storable = str_storable<K, my_type, Allocator>;
4654 using base_mutable = str_mutable<K, my_type>;
4655 using base_utf = from_utf_convertable<K, my_type>;
4656 using traits = ch_traits<K>;
4658 friend base_storable;
4659 friend base_mutable;
4661 friend class sstring<K, Allocator>;
4672 K local_[LocalCapacity + 1];
4675 void create_empty() {
4680 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;
4688 if (size_ > LocalCapacity) {
4689 s = calc_capacity(s);
4690 data_ = alloc_place(s);
4698 bool is_alloced() const noexcept {
4699 return data_ != local_;
4704 base_storable::allocator().deallocate(to_real_address(data_));
4709 static K* to_real_address(
void* ptr) {
4710 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) - extra);
4712 static K* from_real_address(
void* ptr) {
4713 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) + extra);
4716 K* alloc_place(
size_t newSize) {
4717 return from_real_address(base_storable::allocator().allocate((newSize + 1) *
sizeof(K) + extra));
4721 K* alloc_for_copy(
size_t newSize) {
4722 if (capacity() >= newSize) {
4727 return alloc_place(calc_capacity(newSize));
4731 void set_from_copy(K* ptr,
size_t newSize) {
4737 capacity_ = calc_capacity(newSize);
4744 using base_storable::base_storable;
4745 using base_utf::base_utf;
4747 lstring() =
default;
4761 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
4772 template<
typename... Args>
4773 requires(
sizeof...(Args) > 0 && std::is_convertible_v<allocator_t, Args...>)
4774 lstring(
const my_type& other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4776 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
4788 template<typename T, size_t I = const_lit_for<K, T>::Count,
typename... Args>
4789 requires std::is_constructible_v<allocator_t, Args...>
4790 constexpr lstring(T&& value, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4791 if constexpr (I > 1) {
4792 K* ptr = init(I - 1);
4793 traits::copy(ptr, value, I - 1);
4804 lstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
4806 size_ = other.size_;
4807 if (other.is_alloced()) {
4808 data_ = other.data_;
4809 capacity_ = other.capacity_;
4812 traits::copy(local_, other.local_, size_ + 1);
4814 other.data_ = other.local_;
4816 other.local_[0] = 0;
4827 template<
typename Op,
typename... Args>
4828 requires(std::is_constructible_v<Allocator, Args...> && (std::is_invocable_v<Op, my_type&> || std::is_invocable_v<Op, K*, size_t>))
4829 lstring(
const Op& op, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4849 if (&other !=
this) {
4851 size_ = other.size_;
4866 if (&other !=
this) {
4868 if (other.is_alloced()) {
4869 data_ = other.data_;
4870 capacity_ = other.capacity_;
4872 traits::copy(data_, other.local_, other.size_ + 1);
4875 size_ = other.size_;
4876 other.create_empty();
4881 my_type& assign(
const K* other,
size_t len) {
4883 bool isIntersect = other >= data_ && other + len <= data_ + size_;
4889 if (other > data_) {
4890 traits::move(data_, other, len);
4893 traits::copy(reserve_no_preserve(len), other, len);
4909 return assign(other.str, other.len);
4919 template<typename T, size_t S = const_lit_for<K, T>::Count>
4921 return assign(other, S - 1);
4934 size_t newLen = expr.
length();
4980 newSize = calc_capacity(newSize);
4981 K* newData = alloc_place(newSize);
4984 capacity_ = newSize;
5002 newSize = calc_capacity(newSize);
5003 K* newData = alloc_place(newSize);
5004 traits::copy(newData, data_, size_);
5007 capacity_ = newSize;
5025 if (newSize > cap) {
5026 size_t needPlace = newSize;
5027 if (needPlace < (cap + 1) * 2) {
5028 needPlace = (cap + 1) * 2 - 1;
5041 return !is_alloced();
5051 for (
size_t i = 0; i < cap; i++) {
5052 if (data_[i] == 0) {
5067 size_t need_capacity = calc_capacity(size_);
5068 if (is_alloced() && capacity_ > need_capacity) {
5069 K* newData = size_ <=
LocalCapacity ? local_ : alloc_place(need_capacity);
5070 traits::copy(newData, data_, size_ + 1);
5075 capacity_ = need_capacity;
5091template<
size_t N = 15>
5092using lstringa = lstring<u8s, N>;
5093template<
size_t N = 15>
5094using lstringw = lstring<wchar_t, N>;
5095template<
size_t N = 15>
5096using lstringu = lstring<u16s, N>;
5097template<
size_t N = 15>
5098using lstringuu = lstring<u32s, N>;
5100template<
size_t N = 15>
5101using lstringsa = lstring<u8s, N, true>;
5102template<
size_t N = 15>
5103using lstringsw = lstring<wchar_t, N, true>;
5104template<
size_t N = 15>
5105using lstringsu = lstring<u16s, N, true>;
5106template<
size_t N = 15>
5107using lstringsuu = lstring<u32s, N, true>;
5110template<typename T, typename K = typename const_lit<T>::symb_type>
5111auto getLiteralType(T&&) {
5115template<
size_t Arch,
size_t L>
5116inline constexpr const size_t _local_count = 0;
5119inline constexpr const size_t _local_count<8, 1> = 23;
5121inline constexpr const size_t _local_count<8, 2> = 15;
5123inline constexpr const size_t _local_count<8, 4> = 7;
5125inline constexpr const size_t _local_count<4, 1> = 15;
5127inline constexpr const size_t _local_count<4, 2> = 11;
5129inline constexpr const size_t _local_count<4, 4> = 5;
5132constexpr const size_t local_count = _local_count<
sizeof(size_t),
sizeof(T)>;
5186template<
typename K, Allocatorable Allocator = allocator_
string>
5187class decl_empty_bases sstring :
5188 public str_algs<K, simple_str<K>, sstring<K, Allocator>, false>,
5189 public str_storable<K, sstring<K, Allocator>, Allocator>,
5190 public from_utf_convertable<K, sstring<K, Allocator>> {
5192 using symb_type = K;
5193 using uns_type = std::make_unsigned_t<K>;
5194 using my_type = sstring<K, Allocator>;
5195 using allocator_t = Allocator;
5197 enum { LocalCount = local_count<K> };
5200 using base_algs = str_algs<K, simple_str<K>, my_type,
false>;
5201 using base_storable = str_storable<K, my_type, Allocator>;
5202 using base_utf = from_utf_convertable<K, my_type>;
5203 using traits = ch_traits<K>;
5204 using uni = unicode_traits<K>;
5206 friend base_storable;
5209 enum Types { Local, Constant, Shared };
5222 uns_type localRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
5237 void create_empty() {
5239 localRemain_ = LocalCount;
5243 if (s > LocalCount) {
5251 localRemain_ = LocalCount - s;
5256 K* set_size(
size_t newSize) {
5262 if (newSize !=
size) {
5263 if (type_ == Constant) {
5266 if (newSize <= LocalCount) {
5267 if (type_ == Shared) {
5268 SharedStringData<K>* str_buf = SharedStringData<K>::from_str(sstr_);
5269 traits::copy(buf_, sstr_, newSize);
5273 localRemain_ = LocalCount - newSize;
5275 if (type_ == Shared) {
5276 if (newSize >
size || (newSize > 64 && newSize <=
size * 3 / 4)) {
5278 traits::copy(newStr, sstr_, newSize);
5282 }
else if (type_ == Local) {
5285 traits::copy(newStr, buf_,
size);
5294 K* str = type_ == Local ? buf_ : (K*)sstr_;
5300 using base_storable::base_storable;
5301 using base_utf::base_utf;
5303 sstring() =
default;
5311 template<
typename... Args>
5312 requires(
sizeof...(Args) > 0 && std::is_constructible_v<Allocator, Args...>)
5313 sstring(Args&&... args) : Allocator(std::forward<Args>(args)...) {}
5318 if (type_ == Shared) {
5328 sstring(
const my_type& other) noexcept : base_storable(other.allocator()) {
5329 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
5330 if (type_ == Shared)
5331 SharedStringData<K>::from_str(sstr_)->incr();
5339 sstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
5340 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
5341 other.create_empty();
5356 size_t size = src.length();
5358 if (src.is_alloced()) {
5362 if (
size > LocalCount) {
5369 new (SharedStringData<K>::from_str(str)) SharedStringData<K>();
5374 localRemain_ = LocalCount -
size;
5375 traits::copy(buf_, str,
size + 1);
5383 K* str = init(src.size_);
5384 traits::copy(str, src.symbols(),
size + 1);
5401 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename... Args>
5402 requires std::is_constructible_v<allocator_t, Args...>
5403 sstring(T&& s, Args&&... args) : base_storable(std::forward<Args>(args)...) {
5410 void swap(my_type&& other)
noexcept {
5411 char buf[
sizeof(buf_) +
sizeof(K)];
5412 memcpy(buf, buf_,
sizeof(buf));
5413 memcpy(buf_, other.buf_,
sizeof(buf));
5414 memcpy(other.buf_, buf,
sizeof(buf));
5416 std::swap(base_storable::allocator(), other.allocator());
5427 swap(std::move(other));
5449 template<typename T, size_t N = const_lit_for<K, T>::Count>
5461 template<
size_t N,
bool forShared,
typename A>
5475 return operator=(my_type{std::move(other)});
5497 if (type_ == Shared)
5504 return type_ == Local ? buf_ : cstr_;
5508 return type_ == Local ? LocalCount - localRemain_ : bigLen_;
5530 template<
typename... T>
5531 static my_type
printf(
const K* pattern, T&&... args) {
5544 template<
typename... T>
5545 static my_type
format(
const FmtString<K, T...>& fmtString, T&&... args) {
5558 template<
typename... T>
5564template<
typename K, Allocatorable Allocator>
5565inline const sstring<K> sstring<K, Allocator>::empty_str{};
5568struct digits_selector {
5569 using wider_type = uint16_t;
5573struct digits_selector<2> {
5574 using wider_type = uint32_t;
5578struct digits_selector<4> {
5579 using wider_type = uint64_t;
5582template<
typename K,
typename T>
5583constexpr size_t fromInt(K* bufEnd, T val) {
5584 const char* twoDigit =
5585 "0001020304050607080910111213141516171819"
5586 "2021222324252627282930313233343536373839"
5587 "4041424344454647484950515253545556575859"
5588 "6061626364656667686970717273747576777879"
5589 "8081828384858687888990919293949596979899";
5591 need_sign<K, std::is_signed_v<T>, T> sign(val);
5595 if constexpr (std::is_signed_v<T>) {
5599 const char* ptr = twoDigit - (val % 100) * 2;
5600 *--itr =
static_cast<K
>(ptr[1]);
5601 *--itr =
static_cast<K
>(ptr[0]);
5606 while (val >= 100) {
5607 const char* ptr = twoDigit + (val % 100) * 2;
5608 *--itr =
static_cast<K
>(ptr[1]);
5609 *--itr =
static_cast<K
>(ptr[0]);
5613 *--itr =
static_cast<K
>(
'0' + val);
5615 const char* ptr = twoDigit + val * 2;
5616 *--itr =
static_cast<K
>(ptr[1]);
5617 *--itr =
static_cast<K
>(ptr[0]);
5620 return size_t(bufEnd - itr);
5626template<
typename K,
typename T>
5628 using symb_type = K;
5629 using my_type = expr_num<K, T>;
5631 enum { bufSize = 24 };
5633 mutable K buf[bufSize];
5635 expr_num(T t) : value(t) {}
5636 expr_num(expr_num<K, T>&& t) : value(t.value) {}
5638 size_t length() const noexcept {
5639 value = (T)fromInt(buf + bufSize, value);
5640 return (
size_t)value;
5642 K* place(K* ptr)
const noexcept {
5643 ch_traits<K>::copy(ptr, buf + bufSize - (
size_t)value, (
size_t)value);
5644 return ptr + (size_t)value;
5659template<StrExpr A, FromIntNumber T>
5675template<StrExpr A, FromIntNumber T>
5695template<
typename K,
typename T>
5697 return expr_num<K, T>{t};
5701consteval 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) {
5702 if constexpr (std::is_same_v<K, u8s>)
5704 if constexpr (std::is_same_v<K, uws>)
5706 if constexpr (std::is_same_v<K, u16s>)
5708 if constexpr (std::is_same_v<K, u32s>)
5712#define uni_string(K, p) select_str<K>(p, L##p, u##p, U##p)
5716 using symb_type = K;
5717 mutable std::conditional_t<is_one_of_std_char_v<K>, K, u8s> buf[40];
5720 expr_real(
double d) : v(d) {}
5721 expr_real(
float d) : v(d) {}
5723 size_t length() const noexcept {
5724 if constexpr (is_one_of_std_char_v<K>) {
5725 printf_selector::snprintf(buf, 40, uni_string(K,
"%.16g").str, v);
5726 l = (size_t)ch_traits<K>::length(buf);
5728 l = std::snprintf(buf,
sizeof(buf),
"%.16g", v);
5732 K* place(K* ptr)
const noexcept {
5733 if constexpr (is_one_of_std_char_v<K>) {
5734 ch_traits<K>::copy(ptr, buf, l);
5736 for (
size_t i = 0; i < l; i++) {
5755template<StrExpr A,
typename R>
5756 requires(std::is_same_v<R, double> || std::is_same_v<R, float>)
5757inline constexpr auto operator+(
const A& a, R s) {
5772template<StrExpr A,
typename R>
5773 requires(is_one_of_std_char_v<typename A::symb_type> && (std::is_same_v<R, double> || std::is_same_v<R, float>))
5774inline constexpr auto operator+(R s,
const A& a) {
5789template<
typename K>
requires(is_one_of_std_char_v<K>)
5791 return expr_real<K>{t};
5810template<
typename K,
typename T,
size_t I,
bool tail,
bool skip_empty>
5812 using symb_type = K;
5813 using my_type = expr_join<K, T, I, tail, skip_empty>;
5818 constexpr size_t length() const noexcept {
5820 for (
const auto& t: s) {
5821 size_t len = t.length();
5822 if (len > 0 || !skip_empty) {
5823 if (I > 0 && l > 0) {
5829 return l + (tail && I > 0 && (l > 0 || (!skip_empty && s.size() > 0))? I : 0);
5831 constexpr K* place(K* ptr)
const noexcept {
5836 for (
const auto& t: s) {
5837 size_t copyLen = t.length();
5838 if (I > 0 && write != ptr && (copyLen || !skip_empty)) {
5839 ch_traits<K>::copy(write, delim, I);
5842 ch_traits<K>::copy(write, t.symbols(), copyLen);
5845 if (I > 0 && tail && (write != ptr || (!skip_empty && s.size() > 0))) {
5846 ch_traits<K>::copy(write, delim, I);
5866template<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>
5867inline constexpr auto e_join(
const T& s, L&& d) {
5868 return expr_join<K, T, I - 1, tail, skip_empty>{s, d};
5871template<
typename K,
size_t N,
size_t L>
5872struct expr_replaces {
5873 using symb_type = K;
5874 using my_type = expr_replaces<K, N, L>;
5878 mutable size_t first_, last_;
5880 constexpr expr_replaces(simple_str<K> w,
const K* p,
const K* r) : what(w), pattern(p), repl(r) {}
5882 constexpr size_t length()
const {
5883 size_t l = what.length();
5884 if constexpr (N == L) {
5887 first_ = what.find(pattern, N, 0);
5888 if (first_ != str::npos) {
5892 size_t next = what.find(pattern, N, last_);
5893 if (next == str::npos) {
5901 constexpr K* place(K* ptr)
const noexcept {
5902 if constexpr (N == L) {
5903 const K* from = what.symbols();
5904 for (
size_t start = 0; start < what.length();) {
5905 size_t next = what.find(pattern, N, start);
5906 if (next == str::npos) {
5907 next = what.length();
5909 size_t delta = next - start;
5910 ch_traits<K>::copy(ptr, from + start, delta);
5912 ch_traits<K>::copy(ptr, repl, L);
5918 if (first_ == str::npos) {
5919 return what.place(ptr);
5921 const K* from = what.symbols();
5922 for (
size_t start = 0, offset = first_; ;) {
5923 ch_traits<K>::copy(ptr, from + start, offset - start);
5924 ptr += offset - start;
5925 ch_traits<K>::copy(ptr, repl, L);
5928 if (start >= last_) {
5929 size_t tail = what.length() - last_;
5930 ch_traits<K>::copy(ptr, from + last_, tail);
5934 offset = what.find(pattern, N, start);
5954template<typename K, typename T, size_t N = const_lit_for<K, T>::Count,
typename X,
size_t L = const_lit_for<K, X>::Count>
5957 return expr_replaces<K, N - 1, L - 1>{w, p, r};
5979 using symb_type = K;
5984 mutable size_t first_, last_;
5997 constexpr size_t length()
const {
5998 size_t l = what.
length();
6002 first_ = what.find(pattern);
6003 if (first_ != str::npos) {
6004 last_ = first_ + pattern.
length();
6007 size_t next = what.find(pattern, last_);
6008 if (next == str::npos) {
6011 last_ = next + pattern.
length();
6016 constexpr K* place(K* ptr)
const noexcept {
6018 const K* from = what.
symbols();
6019 for (
size_t start = 0; start < what.
length();) {
6020 size_t next = what.find(pattern, start);
6021 if (next == str::npos) {
6024 size_t delta = next - start;
6025 ch_traits<K>::copy(ptr, from + start, delta);
6029 start = next + pattern.
length();
6033 if (first_ == str::npos) {
6034 return what.
place(ptr);
6036 const K* from = what.
symbols();
6037 for (
size_t start = 0, offset = first_; ;) {
6038 ch_traits<K>::copy(ptr, from + start, offset - start);
6039 ptr += offset - start;
6042 start = offset + pattern.
length();
6043 if (start >= last_) {
6044 size_t tail = what.
length() - last_;
6045 ch_traits<K>::copy(ptr, from + last_, tail);
6049 offset = what.find(pattern, start);
6056template<
bool UseVectorForReplace>
6057struct replace_search_result_store {
6059 std::pair<size_t, size_t> replaces_[16];
6063struct replace_search_result_store<true> : std::vector<std::pair<size_t, size_t>> {};
6104template<
typename K,
bool UseVectorForReplace = false>
6106 using symb_type = K;
6107 inline static const int BIT_SEARCH_TRESHHOLD = 4;
6110 const std::vector<std::pair<K, simple_str<K>>>& replaces_;
6114 mutable replace_search_result_store<UseVectorForReplace> search_results_;
6116 uu8s bit_mask_[
sizeof(K) == 1 ? 32 : 64]{};
6145 : source_(source), replaces_(repl)
6147 size_t pattern_len = replaces_.size();
6148 K* pattern = pattern_.set_size(pattern_len);
6150 for (
size_t idx = 0; idx < replaces_.size(); idx++) {
6151 *pattern++ = replaces_[idx].first;
6154 if (pattern_len >= BIT_SEARCH_TRESHHOLD) {
6155 for (
size_t idx = 0; idx < pattern_len; idx++) {
6156 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
6157 if constexpr (
sizeof(K) == 1) {
6158 bit_mask_[s >> 3] |= (1 << (s & 7));
6160 if (std::make_unsigned_t<K>(pattern_[idx]) > 255) {
6161 bit_mask_[32 + (s >> 3)] |= (1 << (s & 7));
6163 bit_mask_[s >> 3] |= (1 << (s & 7));
6170 size_t length()
const {
6171 size_t l = source_.
length();
6172 auto [fnd, num] = find_first_of(source_.str, source_.len);
6173 if (fnd == str::npos) {
6176 l += replaces_[num].second.len - 1;
6177 if constexpr (UseVectorForReplace) {
6178 search_results_.reserve((l >> 4) + 8);
6179 search_results_.emplace_back(fnd, num);
6180 for (
size_t start = fnd + 1;;) {
6181 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6182 if (fnd == str::npos) {
6185 search_results_.emplace_back(fnd, idx);
6187 l += replaces_[idx].second.len - 1;
6190 const size_t max_store = std::size(search_results_.replaces_);
6191 search_results_.replaces_[0] = {fnd, num};
6192 search_results_.count_++;
6193 for (
size_t start = fnd + 1;;) {
6194 auto [found, idx] = find_first_of(source_.str, source_.len, start);
6195 if (found == str::npos) {
6198 if (search_results_.count_ < max_store) {
6199 search_results_.replaces_[search_results_.count_] = {found, idx};
6201 l += replaces_[idx].second.len - 1;
6202 search_results_.count_++;
6208 K* place(K* ptr)
const noexcept {
6210 const K* text = source_.str;
6211 if constexpr (UseVectorForReplace) {
6212 for (
const auto& [pos, num] : search_results_) {
6213 size_t delta = pos - start;
6214 ch_traits<K>::copy(ptr, text + start, delta);
6216 ptr = replaces_[num].second.place(ptr);
6220 const size_t max_store = std::size(search_results_.replaces_);
6221 size_t founded = search_results_.count_;
6222 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
6223 const auto [pos, num] = search_results_.replaces_[idx];
6224 size_t delta = pos - start;
6225 ch_traits<K>::copy(ptr, text + start, delta);
6227 ptr = replaces_[num].second.place(ptr);
6230 if (founded > max_store) {
6231 founded -= max_store;
6233 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6234 size_t delta = fnd - start;
6235 ch_traits<K>::copy(ptr, text + start, delta);
6237 ptr = replaces_[idx].second.place(ptr);
6242 size_t tail = source_.len - start;
6243 ch_traits<K>::copy(ptr, text + start, tail);
6248 size_t index_of(K s)
const {
6249 return pattern_.find(s);
6252 bool is_in_mask(uu8s s)
const {
6253 return (bit_mask_[s >> 3] & (1 << (s & 7))) != 0;
6255 bool is_in_mask2(uu8s s)
const {
6256 return (bit_mask_[32 + (s >> 3)] & (1 << (s & 7))) != 0;
6259 bool is_in_pattern(K s,
size_t& idx)
const {
6260 if constexpr (
sizeof(K) == 1) {
6261 if (is_in_mask(s)) {
6266 if (std::make_unsigned_t<const K>(s) > 255) {
6267 if (is_in_mask2(s)) {
6268 return (idx = index_of(s)) != -1;
6271 if (is_in_mask(s)) {
6280 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
6281 size_t pl = pattern_.
length();
6282 if (pl >= BIT_SEARCH_TRESHHOLD) {
6284 while (offset < len) {
6285 if (is_in_pattern(text[offset], idx)) {
6286 return {offset, idx};
6291 while (offset < len) {
6292 if (
size_t idx = index_of(text[offset]); idx != -1) {
6293 return {offset, idx};
6304template<
typename K,
size_t N,
bool UseVectorForReplace>
6305struct expr_replace_const_symbols {
6306 using symb_type = K;
6307 inline static const int BIT_SEARCH_TRESHHOLD = 4;
6308 const K pattern_[N];
6309 const simple_str<K> source_;
6310 const simple_str<K> replaces_[N];
6312 mutable replace_search_result_store<UseVectorForReplace> search_results_;
6314 [[_no_unique_address]]
6315 uu8s bit_mask_[N >= BIT_SEARCH_TRESHHOLD ? (
sizeof(K) == 1 ? 32 : 64) : 0]{};
6317 template<
typename ... Repl>
requires (
sizeof...(Repl) == N * 2)
6318 constexpr expr_replace_const_symbols(simple_str<K> source, Repl&& ... repl) : expr_replace_const_symbols(0, source, std::forward<Repl>(repl)...) {}
6320 size_t length()
const {
6321 size_t l = source_.
length();
6322 auto [fnd, num] = find_first_of(source_.str, source_.len);
6323 if (fnd == str::npos) {
6326 l += replaces_[num].len - 1;
6327 if constexpr (UseVectorForReplace) {
6328 search_results_.reserve((l >> 4) + 8);
6329 search_results_.emplace_back(fnd, num);
6330 for (
size_t start = fnd + 1;;) {
6331 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6332 if (fnd == str::npos) {
6335 search_results_.emplace_back(fnd, idx);
6337 l += replaces_[idx].len - 1;
6340 const size_t max_store = std::size(search_results_.replaces_);
6341 search_results_.replaces_[0] = {fnd, num};
6342 search_results_.count_++;
6343 for (
size_t start = fnd + 1;;) {
6344 auto [found, idx] = find_first_of(source_.str, source_.len, start);
6345 if (found == str::npos) {
6348 if (search_results_.count_ < max_store) {
6349 search_results_.replaces_[search_results_.count_] = {found, idx};
6351 l += replaces_[idx].len - 1;
6352 search_results_.count_++;
6358 K* place(K* ptr)
const noexcept {
6360 const K* text = source_.str;
6361 if constexpr (UseVectorForReplace) {
6362 for (
const auto& [pos, num] : search_results_) {
6363 size_t delta = pos - start;
6364 ch_traits<K>::copy(ptr, text + start, delta);
6366 ptr = replaces_[num].place(ptr);
6370 const size_t max_store = std::size(search_results_.replaces_);
6371 size_t founded = search_results_.count_;
6372 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
6373 const auto [pos, num] = search_results_.replaces_[idx];
6374 size_t delta = pos - start;
6375 ch_traits<K>::copy(ptr, text + start, delta);
6377 ptr = replaces_[num].place(ptr);
6380 if (founded > max_store) {
6381 founded -= max_store;
6383 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6384 size_t delta = fnd - start;
6385 ch_traits<K>::copy(ptr, text + start, delta);
6387 ptr = replaces_[idx].place(ptr);
6392 size_t tail = source_.len - start;
6393 ch_traits<K>::copy(ptr, text + start, tail);
6398 template<
typename ... Repl>
6399 constexpr expr_replace_const_symbols(
int, simple_str<K> source, K s, simple_str<K> r, Repl&&... repl) :
6400 expr_replace_const_symbols(0, source, std::forward<Repl>(repl)..., std::make_pair(s, r)){}
6402 template<
typename ... Repl>
requires (
sizeof...(Repl) == N)
6403 constexpr expr_replace_const_symbols(
int, simple_str<K> source, Repl&&... repl) :
6404 source_(source), pattern_ {repl.first...}, replaces_{repl.second...}
6406 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6407 for (
size_t idx = 0; idx < N; idx++) {
6408 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
6409 if constexpr (
sizeof(K) == 1) {
6410 bit_mask_[s >> 3] |= 1 << (s & 7);
6412 if (std::make_unsigned_t<const K>(pattern_[idx]) > 255) {
6413 bit_mask_[32 + (s >> 3)] |= 1 << (s & 7);
6415 bit_mask_[s >> 3] |= 1 << (s & 7);
6422 template<
size_t Idx>
6423 size_t index_of(K s)
const {
6424 if constexpr (Idx < N) {
6425 return pattern_[Idx] == s ? Idx : index_of<Idx + 1>(s);
6429 bool is_in_mask(uu8s s)
const {
6430 return (bit_mask_[s >> 3] & (1 <<(s & 7))) != 0;
6432 bool is_in_mask2(uu8s s)
const {
6433 return (bit_mask_[32 + (s >> 3)] & (1 <<(s & 7))) != 0;
6436 bool is_in_pattern(K s,
size_t& idx)
const {
6437 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6438 if constexpr (
sizeof(K) == 1) {
6439 if (is_in_mask(s)) {
6440 idx = index_of<0>(s);
6444 if (std::make_unsigned_t<const K>(s) > 255) {
6445 if (is_in_mask2(s)) {
6446 return (idx = index_of<0>(s)) != -1;
6449 if (is_in_mask(s)) {
6450 idx = index_of<0>(s);
6458 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
6459 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6461 while (offset < len) {
6462 if (is_in_pattern(text[offset], idx)) {
6463 return {offset, idx};
6468 while (offset < len) {
6469 if (
size_t idx = index_of<0>(text[offset]); idx != -1) {
6470 return {offset, idx};
6518template<
bool UseVector =
false,
typename K,
typename ... Repl>
6519requires (
sizeof...(Repl) % 2 == 0)
6521 return expr_replace_const_symbols<K,
sizeof...(Repl) / 2, UseVector>(src, std::forward<Repl>(other)...);
6524template<
typename K,
typename H>
6528 char node[
sizeof(sstring<K>)];
6530 const simple_str_nt<K>& to_nt() const noexcept {
6531 return static_cast<const simple_str_nt<K>&
>(str);
6533 const sstring<K>& to_str() const noexcept {
6534 return *
reinterpret_cast<const sstring<K>*
>(node);
6540 static inline constexpr size_t basis =
static_cast<size_t>(14695981039346656037ULL);
6541 static inline constexpr size_t prime =
static_cast<size_t>(1099511628211ULL);
6545struct fnv_const<false> {
6546 static inline constexpr size_t basis =
static_cast<size_t>(2166136261U);
6547 static inline constexpr size_t prime =
static_cast<size_t>(16777619U);
6550using fnv = fnv_const<
sizeof(size_t) == 8>;
6553inline constexpr size_t fnv_hash(
const K* ptr,
size_t l) {
6554 size_t h = fnv::basis;
6555 for (
size_t i = 0; i < l; i++) {
6556 h = (h ^ (std::make_unsigned_t<K>)ptr[i]) * fnv::prime;
6562inline constexpr size_t fnv_hash_ia(
const K* ptr,
size_t l) {
6563 size_t h = fnv::basis;
6564 for (
size_t i = 0; i < l; i++) {
6565 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)ptr[i];
6566 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
6571template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
6572inline constexpr size_t fnv_hash(T&& value) {
6573 size_t h = fnv::basis;
6574 for (
size_t i = 0; i < N - 1; i++) {
6575 h = (h ^ (std::make_unsigned_t<K>)value[i]) * fnv::prime;
6580template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
6581inline constexpr size_t fnv_hash_ia(T&& value) {
6582 size_t h = fnv::basis;
6583 for (
size_t i = 0; i < N - 1; i++) {
6584 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)value[i];
6585 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
6591inline consteval size_t fnv_hash_compile(
const K* ptr,
size_t l) {
6592 return fnv_hash(ptr, l);
6596inline consteval size_t fnv_hash_ia_compile(
const K* ptr,
size_t l) {
6597 return fnv_hash_ia(ptr, l);
6600static_assert(std::is_trivially_copyable_v<StoreType<u8s, int>>,
"Store type must be trivially copyable");
6701template<
typename K,
typename T,
typename H = strhash<K>,
typename E = streql<K>>
6702class hashStrMap :
public std::unordered_map<StoreType<K, H>, T, H, E> {
6704 using InStore = StoreType<K, H>;
6707 using my_type = hashStrMap<K, T, H, E>;
6708 using hash_t = std::unordered_map<InStore, T, H, E>;
6711 hashStrMap() =
default;
6712 hashStrMap(
const my_type& other) : hash_t(other) {
6713 for (
const auto& [k, v] : *
this) {
6714 InStore& stored =
const_cast<InStore&
>(k);
6716 new (stored.node)
sstring<K>(std::move(tmp));
6717 stored.str.str = stored.to_str().symbols();
6721 for (
auto& k: *
this)
6725 hashStrMap(my_type&& o) =
default;
6727 my_type& operator=(
const my_type& other) {
6728 hash_t::operator=(other);
6729 for (
const auto& [k, v] : *
this) {
6730 InStore& stored =
const_cast<InStore&
>(k);
6732 new (stored.node)
sstring<K>(std::move(tmp));
6733 stored.str.str = stored.to_str().symbols();
6737 my_type& operator=(my_type&&) =
default;
6739 hashStrMap(std::initializer_list<std::pair<const InStore, T>>&& init) {
6740 for (
const auto& e: init)
6741 emplace(e.first, e.second);
6744 using init_str = std::initializer_list<std::pair<const sstring<K>, T>>;
6746 hashStrMap(init_str&& init) {
6747 for (
const auto& e: init)
6748 emplace(e.first, e.second);
6753 template<
typename... ValArgs>
6754 auto try_emplace(
const InStore& key, ValArgs&&... args) {
6755 auto it = hash_t::try_emplace(key, std::forward<ValArgs>(args)...);
6757 InStore& stored =
const_cast<InStore&
>(it.first->first);
6759 stored.str.str = stored.to_str().symbols();
6765 return {key, H{}(key)};
6768 template<
typename Key,
typename... ValArgs>
6769 requires(std::is_convertible_v<Key, simple_str<K>>)
6770 auto try_emplace(Key&& key, ValArgs&&... args) {
6771 auto it = hash_t::try_emplace(toStoreType(key), std::forward<ValArgs>(args)...);
6773 InStore& stored =
const_cast<InStore&
>(it.first->first);
6774 new (stored.node)
sstring<K>(std::forward<Key>(key));
6775 stored.str.str = stored.to_str().symbols();
6780 template<
typename... ValArgs>
6781 auto emplace(
const InStore& key, ValArgs&&... args) {
6782 auto it = try_emplace(key, std::forward<ValArgs>(args)...);
6784 it.first->second = T(std::forward<ValArgs>(args)...);
6789 template<
typename Key,
typename... ValArgs>
6790 requires(std::is_convertible_v<Key, simple_str<K>>)
6791 auto emplace(Key&& key, ValArgs&&... args) {
6792 auto it = try_emplace(std::forward<Key>(key), std::forward<ValArgs>(args)...);
6794 it.first->second = T(std::forward<ValArgs>(args)...);
6799 auto& operator[](
const InStore& key) {
6800 return try_emplace(key).first->second;
6803 template<
typename Key>
6804 requires(std::is_convertible_v<Key, simple_str<K>>)
6805 auto&
operator[](Key&& key) {
6806 return try_emplace(std::forward<Key>(key)).first->second;
6809 decltype(
auto) at(
const InStore& key) {
6810 return hash_t::at(key);
6812 decltype(
auto) at(
const InStore& key)
const {
6813 return hash_t::at(key);
6817 return hash_t::at(toStoreType(key));
6820 return hash_t::at(toStoreType(key));
6823 auto find(
const InStore& key)
const {
6824 return hash_t::find(key);
6828 return find(toStoreType(key));
6831 auto find(
const InStore& key) {
6832 return hash_t::find(key);
6836 return find(toStoreType(key));
6839 auto erase(
typename hash_t::const_iterator it) {
6840 if (it != hash_t::end()) {
6843 return hash_t::erase(it);
6846 auto erase(
const InStore& key) {
6847 auto it = hash_t::find(key);
6848 if (it != hash_t::end()) {
6857 return erase(toStoreType(key));
6861 auto it = find(txt);
6862 if (it != hash_t::end()) {
6870 for (
auto& k: *
this)
6874 bool contains(
const InStore& key)
const {
6875 return hash_t::find(key) != this->end();
6879 return find(toStoreType(key)) != this->end();
6885 template<
typename H>
6886 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
6887 return _Left.hash == _Right.hash && _Left.str == _Right.str;
6893 size_t operator()(simple_str<K> _Keyval)
const {
6894 return fnv_hash(_Keyval.symbols(), _Keyval.length());
6896 size_t operator()(
const StoreType<K, strhash<K>>& _Keyval)
const {
6897 return _Keyval.hash;
6903 template<
typename H>
6904 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
6905 return _Left.hash == _Right.hash && _Left.str.equal_ia(_Right.str);
6911 size_t operator()(simple_str<K> _Keyval)
const {
6912 return fnv_hash_ia(_Keyval.symbols(), _Keyval.length());
6914 size_t operator()(
const StoreType<K, strhashia<K>>& _Keyval)
const {
6915 return _Keyval.hash;
6921 template<
typename H>
6922 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
6923 return _Left.hash == _Right.hash && _Left.str.equal_iu(_Right.str);
6929 size_t operator()(simple_str<K> _Keyval)
const {
6930 return unicode_traits<K>::hashiu(_Keyval.symbols(), _Keyval.length());
6932 size_t operator()(
const StoreType<K, strhashiu<K>>& _Keyval)
const {
6933 return _Keyval.hash;
6952class chunked_string_builder {
6953 using chunk_t = std::pair<std::unique_ptr<K[]>,
size_t>;
6954 std::vector<chunk_t> chunks;
6961 using my_type = chunked_string_builder<K>;
6962 using symb_type = K;
6963 chunked_string_builder() =
default;
6964 chunked_string_builder(
size_t a) : align(a){};
6965 chunked_string_builder(
const my_type&) =
delete;
6966 chunked_string_builder(my_type&& other) noexcept
6967 : chunks(std::move(other.chunks)), write(other.write), len(other.len), remain(other.remain), align(other.align) {
6968 other.len = other.remain = 0;
6969 other.write =
nullptr;
6971 my_type& operator=(my_type other)
noexcept {
6972 chunks.swap(other.chunks);
6973 write = other.write;
6975 remain = other.remain;
6976 align = other.align;
6977 other.len = other.remain = 0;
6978 other.write =
nullptr;
6986 if (
data.len <= remain) {
6989 ch_traits<K>::copy(write,
data.str,
data.len);
6991 chunks.back().second +=
data.len;
6998 ch_traits<K>::copy(write,
data.str, remain);
7001 chunks.back().second += remain;
7007 size_t blockSize = (
data.len + align - 1) / align * align;
7008 chunks.emplace_back(std::make_unique<K[]>(blockSize),
data.len);
7009 write = chunks.back().first.get();
7010 ch_traits<K>::copy(write,
data.str,
data.len);
7012 remain = blockSize -
data.len;
7019 size_t l = expr.
length();
7022 write = expr.place(write);
7023 chunks.back().second += l;
7026 }
else if (!remain) {
7027 size_t blockSize = (l + align - 1) / align * align;
7028 chunks.emplace_back(std::make_unique<K[]>(blockSize), l);
7029 write = expr.place(chunks.back().first.get());
7031 remain = blockSize - l;
7033 auto store = std::make_unique<K[]>(l);
7034 expr.place(store.get());
7041 template<
typename T>
7043 requires std::is_same_v<T, K>
7045 return operator<<(expr_char<K>(
data));
7053 if (chunks.empty()) {
7056 if (chunks.size() > 1) {
7060 remain += chunks[0].second;
7061 chunks[0].second = 0;
7063 write = chunks[0].first.get();
7066 constexpr K* place(K* p)
const noexcept {
7067 for (
const auto& block: chunks) {
7068 ch_traits<K>::copy(p, block.first.get(), block.second);
7081 template<
typename Op>
7083 for (
const auto& block: chunks)
7084 o(block.first.get(), block.second);
7091 if (chunks.size()) {
7092 const K* ptr = chunks.front().first.get();
7093 for (
const auto& chunk: chunks) {
7094 if (chunk.first.get() != ptr)
7096 ptr += chunk.second;
7108 return chunks.size() ? chunks.front().first.get() : simple_str_nt<K>::empty_str.str;
7125 typename decltype(chunks)::const_iterator it, end;
7126 size_t writedFromCurrentChunk;
7146 while (size && !
is_end()) {
7147 size_t remain = it->second - writedFromCurrentChunk;
7148 size_t write = std::min(size, remain);
7149 ch_traits<K>::copy(buffer, it->first.get() + writedFromCurrentChunk, write);
7155 writedFromCurrentChunk = 0;
7157 writedFromCurrentChunk += write;
7169 return {chunks.begin(), chunks.end(), 0};
7182using stringa = sstring<u8s>;
7183using stringw = sstring<wchar_t>;
7184using stringu = sstring<u16s>;
7185using stringuu = sstring<u32s>;
7186static_assert(
sizeof(stringa) == (
sizeof(
void*) == 8 ? 24 : 16),
"Bad size of sstring");
7268inline namespace literals {
7279#define SS_CONSTEVAL constexpr
7281#define SS_CONSTEVAL consteval
7338template<
typename K>
using HashKey = StoreType<K, strhash<K>>;
7339template<
typename K>
using HashKeyIA = StoreType<K, strhashia<K>>;
7340template<
typename K>
using HashKeyIU = StoreType<K, strhashiu<K>>;
7352consteval HashKey<u8s>
operator""_h(
const u8s* ptr,
size_t l) {
7353 return HashKey<u8s>{{ptr, l}, fnv_hash_compile(ptr, l)};
7366consteval HashKeyIA<u8s>
operator""_ia(
const u8s* ptr,
size_t l) {
7367 return HashKeyIA<u8s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7380inline HashKeyIU<u8s>
operator""_iu(
const u8s* ptr,
size_t l) {
7381 return HashKeyIU<u8s>{{ptr, l}, strhashiu<u8s>{}(
simple_str<u8s>{ptr, l})};
7394consteval HashKey<u16s>
operator""_h(
const u16s* ptr,
size_t l) {
7395 return HashKey<u16s>{{ptr, l}, fnv_hash_compile(ptr, l)};
7408consteval HashKeyIA<u16s>
operator""_ia(
const u16s* ptr,
size_t l) {
7409 return HashKeyIA<u16s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7422inline HashKeyIU<u16s>
operator""_iu(
const u16s* ptr,
size_t l) {
7423 return HashKeyIU<u16s>{{ptr, l}, strhashiu<u16s>{}(
simple_str<u16s>{ptr, l})};
7436consteval HashKey<u32s>
operator""_h(
const u32s* ptr,
size_t l) {
7437 return HashKey<u32s>{{ptr, l}, fnv_hash_compile(ptr, l)};
7450consteval HashKeyIA<u32s>
operator""_ia(
const u32s* ptr,
size_t l) {
7451 return HashKeyIA<u32s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7464inline HashKeyIU<u32s>
operator""_iu(
const u32s* ptr,
size_t l) {
7465 return HashKeyIU<u32s>{{ptr, l}, strhashiu<u32s>{}(
simple_str<u32s>{ptr, l})};
7478consteval HashKey<uws>
operator""_h(
const uws* ptr,
size_t l) {
7479 return HashKey<uws>{{ptr, l}, fnv_hash_compile(ptr, l)};
7492consteval HashKeyIA<uws>
operator""_ia(
const uws* ptr,
size_t l) {
7493 return HashKeyIA<uws>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
7506inline HashKeyIU<uws>
operator""_iu(
const uws* ptr,
size_t l) {
7507 return HashKeyIU<uws>{{ptr, l}, strhashiu<uws>{}(
simple_str<uws>{ptr, l})};
7522 return stream << std::string_view{text.
symbols(), text.
length()};
7535inline std::wostream&
operator<<(std::wostream& stream, ssw text) {
7536 return stream << std::wstring_view{text.
symbols(), text.
length()};
7550 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
7563inline std::ostream&
operator<<(std::ostream& stream,
const stringa& text) {
7564 return stream << std::string_view{text.
symbols(), text.
length()};
7577inline std::wostream&
operator<<(std::wostream& stream,
const stringw& text) {
7578 return stream << std::wstring_view{text.
symbols(), text.
length()};
7592 return stream << std::wstring_view{from_w(text.symbols()), text.length()};
7605template<
size_t N,
bool S, simstr::Allocatorable A>
7607 return stream << std::string_view{text.
symbols(), text.
length()};
7620template<
size_t N,
bool S, simstr::Allocatorable A>
7622 return stream << std::wstring_view{text.
symbols(), text.
length()};
7635template<
size_t N,
bool S, simstr::Allocatorable A>
7637 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
7647struct std::formatter<
simstr::simple_str<K>, K> : std::formatter<std::basic_string_view<K>, K> {
7649 template<
typename FormatContext>
7651 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
7660struct std::formatter<
simstr::simple_str_nt<K>, K> : std::formatter<std::basic_string_view<K>, K> {
7662 template<
typename FormatContext>
7664 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
7673struct std::formatter<
simstr::sstring<K>, K> : std::formatter<std::basic_string_view<K>, K> {
7675 template<
typename FormatContext>
7677 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
7685template<
typename K,
size_t N,
bool S,
typename A>
7686struct std::formatter<
simstr::lstring<K, N, S, A>, K> : std::formatter<std::basic_string_view<K>, K> {
7688 template<
typename FormatContext>
7690 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:2415
simple_str< K > next()
Get the next substring.
Definition sstring.h:2434
bool is_done() const
Find out if substrings are running out.
Definition sstring.h:2425
my_type & operator<<(simple_str< K > data)
Adding a piece of data.
Definition sstring.h:6983
portion_store get_portion() const
Get a portion_store through which data can be sequentially retrieved into an external buffer.
Definition sstring.h:7168
constexpr size_t length() const noexcept
Length of the saved text.
Definition sstring.h:7048
my_type & operator<<(T data)
Adding a symbol.
Definition sstring.h:7042
void reset()
Resets the contents, but does not delete the first buffer in order to avoid allocation later.
Definition sstring.h:7052
void clear()
Clear the object, freeing all allocated buffers.
Definition sstring.h:7114
my_type & operator<<(const StrExprForType< K > auto &expr)
Adding a string expression.
Definition sstring.h:7018
bool is_continuous() const
Checks whether all text is located in one contiguous chunk in memory.
Definition sstring.h:7090
void out(const Op &o) const
Applies a functor to each stored buffer.
Definition sstring.h:7082
const auto & data() const
Get internal data buffers.
Definition sstring.h:7177
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:7107
Container for more efficient searching by string keys.
Definition sstring.h:6702
The mutable, owning string class. Contains an internal buffer for text of a given size.
Definition sstring.h:4636
lstring(const my_type &other, Args &&... args)
Copy from another string of the same type, but with a different allocator.
Definition sstring.h:4774
lstring(const my_type &other)
Copy from another string of the same type.
Definition sstring.h:4759
constexpr lstring(T &&value, Args &&... args)
String literal constructor.
Definition sstring.h:4790
K * reserve_no_preserve(size_t newSize)
Definition sstring.h:4978
my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:4920
@ LocalCapacity
Definition sstring.h:4644
my_type & operator=(my_type &&other) noexcept
Assignment operator by moving from a string of the same type.
Definition sstring.h:4863
void clear()
Makes a string empty without changing the string buffer.
Definition sstring.h:5080
bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:4955
void shrink_to_fit()
Reduces the size of the external buffer to the smallest possible size to hold the string....
Definition sstring.h:5066
size_t length() const noexcept
String length.
Definition sstring.h:4943
size_t capacity() const noexcept
Current row buffer capacity.
Definition sstring.h:4963
K * reserve(size_t newSize)
Allocate a buffer large enough to hold newSize characters plus a terminating null.
Definition sstring.h:5000
bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:4959
my_type & operator=(const StrExprForType< K > auto &expr)
String expression appending operator.
Definition sstring.h:4933
K * str() noexcept
Pointer to a string buffer.
Definition sstring.h:4951
my_type & operator=(const my_type &other)
Copy assignment operator from a string of the same type.
Definition sstring.h:4846
lstring(const Op &op, Args &&... args)
A fill constructor using a functor (see str_mutable::fill).
Definition sstring.h:4829
void reset()
Makes the string empty and frees the external buffer, if there was one.
Definition sstring.h:5084
const K * symbols() const noexcept
Pointer to constant characters.
Definition sstring.h:4947
lstring(my_type &&other) noexcept
Constructor for moving from a string of the same type.
Definition sstring.h:4804
K * set_size(size_t newSize)
Sets the size of the current string, allocating space if necessary.
Definition sstring.h:5023
my_type & operator=(simple_str< K > other)
Assignment operator from simple_str.
Definition sstring.h:4908
bool is_local() const noexcept
Find out whether a local or external buffer is used for characters.
Definition sstring.h:5040
void define_size()
Determine the length of the string. Searches for the character 0 in the string buffer to its capacity...
Definition sstring.h:5049
Immutable owning string class.
Definition sstring.h:5190
sstring(lstring< K, N, true, Allocator > &&src)
A move constructor from lstring with an sstring-compatible external buffer.
Definition sstring.h:5355
my_type & make_empty() noexcept
Make the string empty.
Definition sstring.h:5496
sstring(Args &&... args)
Constructor for the empty string.
Definition sstring.h:5313
bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:5515
my_type & operator=(my_type other) noexcept
Assignment operator to another string of the same type.
Definition sstring.h:5426
my_type & operator=(simple_str< K > other)
Assignment operator to another string of a different type.
Definition sstring.h:5438
sstring(const my_type &other) noexcept
String copy constructor.
Definition sstring.h:5328
~sstring()
String destructor.
Definition sstring.h:5317
static my_type format(const FmtString< K, T... > &fmtString, T &&... args)
Get a string formatted with std::format.
Definition sstring.h:5545
static my_type printf(const K *pattern, T &&... args)
Get a string formatted with std::sprintf.
Definition sstring.h:5531
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:5474
my_type & operator=(const lstring< K, N, forShared, A > &other)
Assignment operator to another string of type lstring.
Definition sstring.h:5462
bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:5511
my_type & operator=(const StrExprForType< K > auto &expr)
String expression assignment operator.
Definition sstring.h:5487
static my_type vformat(simple_str< K > fmtString, T &&... args)
Get a string formatted with std::vformat.
Definition sstring.h:5559
my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:5450
const K * symbols() const noexcept
Pointer to characters in the string.
Definition sstring.h:5503
sstring(T &&s, Args &&... args)
Initialize from a string literal.
Definition sstring.h:5403
size_t length() const noexcept
Line length.
Definition sstring.h:5507
sstring(my_type &&other) noexcept
Move constructor.
Definition sstring.h:5339
A class with basic constant string algorithms.
Definition sstring.h:611
bool is_ascii() const noexcept
Whether the string contains only ASCII characters.
Definition sstring.h:1806
T as_int() const noexcept
Convert a string to a number of the given type.
Definition sstring.h:1432
constexpr bool starts_with(str_piece prefix) const noexcept
Whether the string begins with the given substring.
Definition sstring.h:1686
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:1143
auto operator<=>(T &&other) const noexcept
Comparison operator between a string and a string literal.
Definition sstring.h:901
R lowered_only_ascii() const
Get a copy of the string in lowercase ASCII characters.
Definition sstring.h:1854
R trimmed() const
Get a string with whitespace removed on the left and right.
Definition sstring.h:1946
str_piece to_str() const noexcept
Convert itself to a "string chunk" that includes the entire string.
Definition sstring.h:696
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:1286
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:1217
R trimmed_left(T &&pattern) const
Get a string with the characters specified by the string literal removed from the left.
Definition sstring.h:2000
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:1346
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:1030
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:1725
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:1898
int compare_ia(str_piece text) const noexcept
Compare strings character by character and not case sensitive ASCII characters.
Definition sstring.h:936
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:1913
R uppered() const
Get a copy of the string in upper case Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:1866
constexpr str_piece mid(size_t from, size_t len=-1) const noexcept
Get part of a string as "string chunk".
Definition sstring.h:761
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:1318
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:1171
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:1644
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:2174
constexpr bool prefix_in(str_piece text) const noexcept
Whether this string is the beginning of another string.
Definition sstring.h:1743
void as_number(T &t) const
Convert a string to an integer.
Definition sstring.h:1537
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:976
size_t find(K s, size_t offset=0) const noexcept
Find a character in this string.
Definition sstring.h:1198
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:1130
bool less_iu(str_piece text) const noexcept
Whether a string is smaller than another string, character-by-character-insensitive,...
Definition sstring.h:999
R trimmed(str_piece pattern) const
Get a string with characters specified by another string removed, left and right.
Definition sstring.h:2092
R trimmed_left(str_piece pattern) const
Get a string with characters specified by another string removed from the left.
Definition sstring.h:2106
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:1799
std::basic_string< K > to_string() const noexcept
Convert to std::string.
Definition sstring.h:716
bool contains(str_piece pattern, size_t offset=0) const noexcept
Whether the string contains the specified substring.
Definition sstring.h:1185
R uppered_only_ascii() const
Get a copy of the string in uppercase ASCII characters.
Definition sstring.h:1842
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:2458
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:1400
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:2037
std::optional< double > to_double_hex() const noexcept
Convert string in hex form to double.
Definition sstring.h:1511
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:1273
R trimmed_right() const
Get a string with whitespace removed on the right.
Definition sstring.h:1970
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:2075
constexpr bool ends_with(str_piece suffix) const noexcept
Whether the string ends with the specified substring.
Definition sstring.h:1758
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:2138
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len=0) const noexcept
Get part of a string as "simple_str".
Definition sstring.h:742
bool operator==(T &&other) const noexcept
Operator for comparing a string and a string literal for equality.
Definition sstring.h:891
constexpr auto operator<=>(const base &other) const noexcept
String comparison operator.
Definition sstring.h:881
R lowered() const
Get a copy of the string in lowercase Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:1878
R trimmed_right(T &&pattern) const
Get a string with the characters specified by the string literal removed from the right.
Definition sstring.h:2015
convert_result< T > to_int() const noexcept
Convert a string to a number of the given type.
Definition sstring.h:1465
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:1080
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:948
constexpr K * place(K *ptr) const noexcept
Copy the string to the specified buffer.
Definition sstring.h:647
std::optional< double > to_double() const noexcept
Convert string to double.
Definition sstring.h:1475
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:1359
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:2156
void copy_to(K *buffer, size_t bufSize)
Copy the string to the specified buffer.
Definition sstring.h:665
R trimmed_right(str_piece pattern) const
Get a string with characters specified by another string removed to the right.
Definition sstring.h:2120
R trimmed_left() const
Get a string with whitespace removed on the left.
Definition sstring.h:1958
std::basic_string_view< K > to_sv() const noexcept
Convert to std::string_view.
Definition sstring.h:706
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:1094
constexpr int compare(str_piece o) const
Compare strings character by character.
Definition sstring.h:821
K at(ptrdiff_t idx) const
Get the character at the given position.
Definition sstring.h:803
constexpr int strcmp(const K *text) const
Compare with C-string character by character.
Definition sstring.h:832
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:1157
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:2056
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:1252
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:1050
bool operator!() const noexcept
Check for emptiness.
Definition sstring.h:790
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:1374
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:1333
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:988
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:1784
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:1387
T split(str_piece delimeter, size_t offset=0) const
Split a string into substrings using a given delimiter.
Definition sstring.h:1660
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:1066
constexpr bool operator==(const base &other) const noexcept
Operator comparing strings for equality.
Definition sstring.h:872
size_t size() const
The size of the string in characters.
Definition sstring.h:677
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:1985
constexpr bool equal(str_piece other) const noexcept
String comparison for equality.
Definition sstring.h:861
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:1305
bool less_ia(str_piece text) const noexcept
Whether a string is smaller than another string, character-by-character-insensitive,...
Definition sstring.h:959
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:783
void as_number(double &t) const
Convert string to double.
Definition sstring.h:1546
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:1711
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(s_str other, Args &&... args)
A constructor from another string object.
Definition sstring.h:2976
constexpr str_storable(size_t repeat, s_str pattern, Args &&... args)
String repetition constructor.
Definition sstring.h:2996
allocator_t & allocator()
Get the allocator.
Definition sstring.h:2856
static my_type uppered_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 str_storable(const StrExprForType< K > auto &expr, Args &&... args)
Constructor from a string expression.
Definition sstring.h:3044
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
s_str_nt to_nts(size_t from=0) const
Get simple_str_nt starting at the given character.
Definition sstring.h:3124
static my_type uppered_only_ascii_from(const From &f, Args &&... args)
Create a string copy of the passed in uppercase ASCII characters.
Definition sstring.h:3231
constexpr str_storable(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Create an empty object.
Definition sstring.h:2961
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
str_storable(size_t count, K pad, Args &&... args)
Character repetition constructor.
Definition sstring.h:3020
str_storable(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:3069
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:2800
A type concept that can modify a stored string.
Definition sstring.h:2793
A type concept that can store a string.
Definition sstring.h:2783
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:5956
constexpr auto e_real(double t)
Convert a double number to a string expression.
Definition sstring.h:5790
constexpr auto e_num(T t)
Convert an integer to a string expression.
Definition sstring.h:5696
constexpr auto operator+(const A &a, T s)
Concatenation operator for string expression and integer.
Definition sstring.h:5660
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:6520
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:5867
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:7233
hashStrMap< u8s, T, strhashia< u8s >, streqlia< u8s > > hashStrMapAIA
Type of hash dictionary for char strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:7199
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:7264
hashStrMap< u32s, T, strhashia< u32s >, streqlia< u32s > > hashStrMapUUIA
Hash dictionary type for char32_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:7258
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:7226
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:7219
hashStrMap< u8s, T, strhash< u8s >, streql< u8s > > hashStrMapA
Type of hash dictionary for char strings, case sensitive search.
Definition sstring.h:7193
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:2774
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:7245
hashStrMap< u16s, T, strhashia< u16s >, streqlia< u16s > > hashStrMapUIA
Hash dictionary type for char16_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:7239
hashStrMap< wchar_t, T, strhash< wchar_t >, streql< wchar_t > > hashStrMapW
Hash dictionary type for wchar_t strings, case sensitive search.
Definition sstring.h:7212
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:7205
hashStrMap< u32s, T, strhash< u32s >, streql< u32s > > hashStrMapUU
Hash dictionary type for char32_t strings, case sensitive search.
Definition sstring.h:7252
An object that allows you to sequentially copy content into a buffer of a given size.
Definition sstring.h:7124
bool is_end()
Check that the data has not yet run out.
Definition sstring.h:7131
size_t store(K *buffer, size_t size)
Save the next portion of data to the buffer.
Definition sstring.h:7144
constexpr expr_replace_symbols(simple_str< K > source, const std::vector< std::pair< K, simple_str< K > > > &repl)
Expression constructor.
Definition sstring.h:6144
constexpr expr_replaced(simple_str< K > w, simple_str< K > p, simple_str< K > r)
Constructor.
Definition sstring.h:5995
String expression to convert strings to different UTF types.
Definition sstring.h:2747
A class that claims to refer to a null-terminated string.
Definition sstring.h:2329
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:2368
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:2388
simple_str_nt(T &&p) noexcept
Explicit constructor from C-string.
Definition sstring.h:2355
The simplest immutable non-owning string class.
Definition sstring.h:2201
constexpr simple_str(T &&v) noexcept
Constructor from a string literal.
Definition sstring.h:2215
bool is_part_of(simple_str< K > other) const noexcept
Check if a string is part of another string.
Definition sstring.h:2267
my_type & remove_prefix(size_t delta)
Shifts the start of a line by the specified number of characters.
Definition sstring.h:2289
constexpr size_t length() const noexcept
Get the length of the string.
Definition sstring.h:2235
constexpr const symb_type * symbols() const noexcept
Get a pointer to a constant buffer containing string characters.
Definition sstring.h:2242
constexpr simple_str(const K *p, size_t l) noexcept
Constructor from pointer and length.
Definition sstring.h:2220
constexpr bool is_empty() const noexcept
Check if a string is empty.
Definition sstring.h:2249
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:2230
K operator[](size_t idx) const
Get the character from the specified position. Bounds checking is not performed.
Definition sstring.h:2278
my_type & remove_suffix(size_t delta)
Shortens the string by the specified number of characters.
Definition sstring.h:2302
bool is_same(simple_str< K > other) const noexcept
Check if two objects point to the same string.
Definition sstring.h:2258
Concatenation of a reference to a string expression and the value of the string expression.
Definition strexpr.h:440