14#ifndef __has_declspec_attribute
15#define __has_declspec_attribute(x) 0
19 #if defined(_MSC_VER) || (defined(__clang__) && __has_declspec_attribute(dllexport))
21 #define SIMSTR_API __declspec(dllexport)
23 #define SIMSTR_API __declspec(dllimport)
25 #elif (defined(__GNUC__) || defined(__GNUG__)) && defined(SIMSTR_EXPORT)
26 #define SIMSTR_API __attribute__((visibility("default")))
33const bool isWindowsOs =
40const bool isx64 =
sizeof(
void*) == 8;
43#define _no_unique_address msvc::no_unique_address
45#define _no_unique_address no_unique_address
48#if defined __has_builtin
49# if __has_builtin (__builtin_mul_overflow) && __has_builtin (__builtin_add_overflow)
50# define HAS_BUILTIN_OVERFLOW
61#include <unordered_map>
76#pragma warning(disable : 4201)
82struct unicode_traits {};
85struct unicode_traits<u8s> {
93 static SIMSTR_API
size_t upper(
const u8s*& src,
size_t lenStr, u8s*& dest,
size_t lenBuf);
94 static SIMSTR_API
size_t lower(
const u8s*& src,
size_t len, u8s*& dest,
size_t lenBuf);
96 static SIMSTR_API
int compareiu(
const u8s* text1,
size_t len1,
const u8s* text2,
size_t len2);
98 static SIMSTR_API
size_t hashia(
const u8s* src,
size_t l);
99 static SIMSTR_API
size_t hashiu(
const u8s* src,
size_t l);
103struct unicode_traits<u16s> {
104 static SIMSTR_API
void upper(
const u16s* src,
size_t len, u16s* dest);
105 static SIMSTR_API
void lower(
const u16s* src,
size_t len, u16s* dest);
107 static SIMSTR_API
int compareiu(
const u16s* text1,
size_t len1,
const u16s* text2,
size_t len2);
108 static SIMSTR_API
size_t hashia(
const u16s* src,
size_t l);
109 static SIMSTR_API
size_t hashiu(
const u16s* src,
size_t l);
113struct unicode_traits<u32s> {
114 static SIMSTR_API
void upper(
const u32s* src,
size_t len, u32s* dest);
115 static SIMSTR_API
void lower(
const u32s* src,
size_t len, u32s* dest);
117 static SIMSTR_API
int compareiu(
const u32s* text1,
size_t len1,
const u32s* text2,
size_t len2);
118 static SIMSTR_API
size_t hashia(
const u32s* src,
size_t s);
119 static SIMSTR_API
size_t hashiu(
const u32s* src,
size_t s);
123struct unicode_traits<wchar_t> {
124 static void upper(
const wchar_t* src,
size_t len,
wchar_t* dest) {
125 unicode_traits<wchar_type>::upper(to_w(src), len, to_w(dest));
127 static void lower(
const wchar_t* src,
size_t len,
wchar_t* dest) {
128 unicode_traits<wchar_type>::lower(to_w(src), len, to_w(dest));
131 static int compareiu(
const wchar_t* text1,
size_t len1,
const wchar_t* text2,
size_t len2) {
132 return unicode_traits<wchar_type>::compareiu(to_w(text1), len1, to_w(text2), len2);
134 static size_t hashia(
const wchar_t* src,
size_t s) {
135 return unicode_traits<wchar_type>::hashia(to_w(src), s);
137 static size_t hashiu(
const wchar_t* src,
size_t s) {
138 return unicode_traits<wchar_type>::hashiu(to_w(src), s);
143constexpr const size_t npos =
static_cast<size_t>(-1);
147struct ch_traits : std::char_traits<K>{};
150concept is_const_pattern = N > 1 && N <= 17;
152template<
typename K,
size_t I>
154 constexpr static const size_t value = size_t(K(~0x7F)) << ((I - 1) *
sizeof(K) * 8) | _ascii_mask<K, I - 1>::value;
158struct _ascii_mask<K, 0> {
159 constexpr static const size_t value = 0;
164 using uns = std::make_unsigned_t<K>;
165 constexpr static const size_t WIDTH =
sizeof(size_t) /
sizeof(uns);
166 constexpr static const size_t VALUE = _ascii_mask<uns, WIDTH>::value;
170constexpr inline bool isAsciiUpper(K k) {
171 return k >=
'A' && k <=
'Z';
175constexpr inline bool isAsciiLower(K k) {
176 return k >=
'a' && k <=
'z';
180constexpr inline K makeAsciiLower(K k) {
181 return isAsciiUpper(k) ? k | 0x20 : k;
185constexpr inline K makeAsciiUpper(K k) {
186 return isAsciiLower(k) ? k & ~0x20 : k;
189enum TrimSides { TrimLeft = 1, TrimRight = 2, TrimAll = 3 };
190template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces = false>
193template<
typename K,
size_t N,
size_t L>
197concept FromIntNumber =
198 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;
201concept ToIntNumber = FromIntNumber<T> || is_one_of_type<T, int8_t>::value;
203#if defined(_MSC_VER) && _MSC_VER <= 1933
204template<
typename K,
typename... Args>
205using FmtString = std::_Basic_format_string<K, std::type_identity_t<Args>...>;
206#elif __clang_major__ >= 15 || _MSC_VER > 1933 || __GNUC__ >= 13
207template<
typename K,
typename... Args>
208using FmtString = std::basic_format_string<K, std::type_identity_t<Args>...>;
210template<
typename K,
typename... Args>
211using FmtString = std::basic_string_view<K>;
214template<
typename K,
bool I,
typename T>
217 need_sign(T& t) : sign(t < 0) {
218 if (sign && t != std::numeric_limits<T>::min())
221 void after(K*& ptr) {
227template<
typename K,
typename T>
228struct need_sign<K, false, T> {
243template<
bool CanNegate,
bool CheckOverflow,
typename T>
244struct result_type_selector {
249struct result_type_selector<true, false, T> {
250 using type = std::make_unsigned_t<T>;
253template<
unsigned Base>
254constexpr unsigned digit_width() {
273template<
typename T,
unsigned Base>
274constexpr unsigned max_overflow_digits = (
sizeof(T) * CHAR_BIT) / digit_width<Base>();
278 inline static const uint8_t NUMBERS[] = {
279 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,
280 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,
281 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,
282 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,
283 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,
284 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,
285 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,
286 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,
287 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,
288 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
290 template<
typename K,
unsigned Base>
291 static uint8_t toDigit(K s) {
292 auto us =
static_cast<std::make_unsigned_t<K>
>(s);
293 if constexpr (Base <= 10) {
296 if constexpr (
sizeof(K) == 1) {
299 return us < 256 ? NUMBERS[us] : 255;
304 template<
typename K, ToIntNumber T,
unsigned Base,
bool CheckOverflow>
306 static std::tuple<T, IntConvertResult, size_t> parse(
const K* start,
const K* current,
const K* end,
bool negate) {
307 using u_type = std::make_unsigned_t<T>;
308 #ifndef HAS_BUILTIN_OVERFLOW
309 u_type maxMult = 0, maxAdd = 0;
310 if constexpr (CheckOverflow) {
311 maxMult = std::numeric_limits<u_type>::max() / Base;
312 maxAdd = std::numeric_limits<u_type>::max() % Base;
316 unsigned maxDigits = max_overflow_digits<u_type, Base>;
318 const K* from = current;
320 bool no_need_check_o_f = !CheckOverflow || end - current <= maxDigits;
322 if (no_need_check_o_f) {
324 const unsigned char digit = toDigit<K, Base>(*current);
328 number = number * Base + digit;
329 if (++current == end) {
335 for (;maxDigits; maxDigits--) {
336 const unsigned char digit = toDigit<K, Base>(*current);
340 number = number * Base + digit;
346 const unsigned char digit = toDigit<K, Base>(*current);
350 #ifdef HAS_BUILTIN_OVERFLOW
351 if (__builtin_mul_overflow(number, Base, &number) ||
352 __builtin_add_overflow(number, digit, &number)) {
354 if (number < maxMult || (number == maxMult && number < maxAdd)) {
355 number = number * Base + digit;
359 while(++current < end) {
360 if (toDigit<K, Base>(*current) >= Base) {
366 if (++current == end) {
374 if constexpr (std::is_signed_v<T>) {
375 result = negate ? 0 - number : number;
376 if constexpr (CheckOverflow) {
378 if (number > std::numeric_limits<T>::max() + (negate ? 1 : 0)) {
389 return {result, error, current - start};
394 template<
typename K, ToIntNumber T,
unsigned Base = 0,
bool CheckOverflow = true,
bool SkipWs = true,
bool AllowSign = true>
395 requires(Base == -1 || (Base < 37 && Base != 1))
396 static std::tuple<T, IntConvertResult, size_t> to_integer(
const K* start,
size_t len)
noexcept {
397 const K *ptr = start, *end = ptr + len;
399 if constexpr (SkipWs) {
400 while (ptr < end && std::make_unsigned_t<K>(*ptr) <=
' ')
404 if constexpr (std::is_signed_v<T>) {
405 if constexpr (AllowSign) {
409 }
else if (*ptr ==
'-') {
420 }
else if constexpr (AllowSign) {
428 if constexpr (Base == 0 || Base == -1) {
432 if (*ptr ==
'x' || *ptr ==
'X') {
433 return parse<K, T, 16, CheckOverflow>(start, ++ptr, end, negate);
435 if constexpr (Base == -1) {
436 if (*ptr ==
'b' || *ptr ==
'B') {
437 return parse<K, T, 2, CheckOverflow>(start, ++ptr, end, negate);
439 if (*ptr ==
'o' || *ptr ==
'O') {
440 return parse<K, T, 8, CheckOverflow>(start, ++ptr, end, negate);
443 return parse<K, T, 8, CheckOverflow>(start, --ptr, end, negate);
447 return parse<K, T, 10, CheckOverflow>(start, ptr, end, negate);
449 return parse<K, T, Base, CheckOverflow>(start, ptr, end, negate);
458template<
typename K,
typename Impl,
bool Mutable>
class buffer_pointers;
460template<
typename K,
typename Impl>
461class buffer_pointers<K, Impl, false> {
462 const Impl& d()
const {
return *
static_cast<const Impl*
>(
this); }
468 const K* c_str()
const {
return d().symbols(); }
473 const K* data()
const {
return d().symbols(); }
478 const K* begin()
const {
return d().symbols(); }
483 const K* end()
const {
return d().symbols() + d().length(); }
486template<
typename K,
typename Impl>
487class buffer_pointers<K, Impl, true> :
public buffer_pointers<K, Impl, false> {
488 Impl& d() {
return *
static_cast<Impl*
>(
this); }
489 using base = buffer_pointers<K, Impl, false>;
495 const K* data()
const {
return base::data(); }
500 const K* begin()
const {
return base::begin(); }
505 const K* end()
const {
return base::end(); }
510 K* data() {
return d().str(); }
515 K* begin() {
return d().str(); }
520 K* end() {
return d().str() + d().length(); }
536template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
537class str_algs :
public buffer_pointers<K, Impl, Mutable> {
538 const Impl& d()
const noexcept {
539 return *
static_cast<const Impl*
>(
this);
541 size_t _len()
const noexcept {
544 const K* _str()
const noexcept {
545 return d().symbols();
547 bool _is_empty()
const noexcept {
548 return d().is_empty();
553 using str_piece = StrRef;
554 using traits = ch_traits<K>;
555 using uni = unicode_traits<K>;
556 using uns_type = std::make_unsigned_t<K>;
557 using my_type = Impl;
558 using base = str_algs<K, StrRef, Impl, Mutable>;
560 str_algs() =
default;
569 constexpr K*
place(K* ptr)
const noexcept {
570 size_t myLen = _len();
572 traits::copy(ptr, _str(), myLen);
584 size_t tlen = std::min(_len(), bufSize - 1);
586 traits::copy(buffer, _str(), tlen);
601 constexpr operator str_piece() const noexcept {
602 return str_piece{_str(), _len()};
609 return {_str(), _len()};
615 std::string_view
to_sv() const noexcept {
616 return {_str(), _len()};
623 return {_str(), _len()};
641 constexpr str_piece
operator()(ptrdiff_t from, ptrdiff_t len = 0) const noexcept {
642 size_t myLen = _len(), idxStart = from >= 0 ? from : myLen + from, idxEnd = len > 0 ? idxStart + len : myLen > -len ? myLen + len : 0;
645 if (idxStart > idxEnd)
647 return str_piece{_str() + idxStart, idxEnd - idxStart};
655 constexpr str_piece
mid(
size_t from,
size_t len = -1) const noexcept {
656 size_t myLen = _len(), idxStart = from, idxEnd = from > std::numeric_limits<size_t>::max() - len ? myLen : from + len;
659 if (idxStart > idxEnd)
661 return str_piece{_str() + idxStart, idxEnd - idxStart};
671 constexpr str_piece
from_to(
size_t from,
size_t to)
const noexcept {
672 return str_piece{_str() + from, to - from};
686 K
at(ptrdiff_t idx)
const {
687 return _str()[idx >= 0 ? idx : _len() + idx];
690 constexpr int compare(
const K* text,
size_t len)
const {
691 size_t myLen = _len();
692 int cmp = traits::compare(_str(), text, std::min(myLen, len));
693 return cmp == 0 ? (myLen > len ? 1 : myLen == len ? 0 : -1) : cmp;
708 constexpr int strcmp(
const K* text)
const {
709 size_t myLen = _len(), idx = 0;
710 const K* ptr = _str();
711 for (; idx < myLen; idx++) {
712 uns_type s1 = (uns_type)text[idx];
716 uns_type s2 = (uns_type)ptr[idx];
719 }
else if (s1 > s2) {
723 return text[idx] == 0 ? 0 : -1;
726 constexpr bool equal(
const K* text,
size_t len)
const noexcept {
727 return len == _len() && traits::compare(_str(), text, len) == 0;
734 constexpr bool equal(str_piece other)
const noexcept {
735 return equal(other.symbols(), other.length());
742 constexpr bool operator==(
const base& other)
const noexcept {
743 return equal(other._str(), other._len());
750 return compare(other._str(), other._len()) <=> 0;
756 template<typename T, size_t N = const_lit_for<K, T>::Count>
758 return N - 1 == _len() && traits::compare(_str(), other, N - 1) == 0;
765 template<typename T, size_t N = const_lit_for<K, T>::Count>
767 size_t myLen = _len();
768 int cmp = traits::compare(_str(), other, std::min(myLen, N - 1));
769 int res = cmp == 0 ? (myLen > N - 1 ? 1 : myLen == N - 1 ? 0 : -1) : cmp;
774 int compare_ia(
const K* text,
size_t len)
const noexcept {
776 return _is_empty() ? 0 : 1;
777 size_t myLen = _len(), checkLen = std::min(myLen, len);
778 const uns_type *ptr1 =
reinterpret_cast<const uns_type*
>(_str()), *ptr2 =
reinterpret_cast<const uns_type*
>(text);
780 uns_type s1 = *ptr1++, s2 = *ptr2++;
783 s1 = makeAsciiLower(s1);
784 s2 = makeAsciiLower(s2);
790 return myLen == len ? 0 : myLen > len ? 1 : -1;
798 return compare_ia(text.symbols(), text.length());
807 return text.length() == _len() && compare_ia(text.symbols(), text.length()) == 0;
815 return compare_ia(text.symbols(), text.length()) < 0;
818 int compare_iu(
const K* text,
size_t len)
const noexcept {
820 return _is_empty() ? 0 : 1;
821 return uni::compareiu(_str(), _len(), text, len);
829 return compare_iu(text.symbols(), text.length());
838 return text.length() == _len() && compare_iu(text.symbols(), text.length()) == 0;
846 return compare_iu(text.symbols(), text.length()) < 0;
849 size_t find(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
850 size_t lenText = _len();
852 if (!lenPattern || offset >= lenText || offset + lenPattern > lenText)
855 const K *text = _str(), *last = text + lenText - lenPattern, first = pattern[0];
857 for (
const K* fnd = text + offset;; ++fnd) {
858 fnd = traits::find(fnd, last - fnd, first);
861 if (traits::compare(fnd + 1, pattern, lenPattern) == 0)
862 return static_cast<size_t>(fnd - text);
871 size_t find(str_piece pattern,
size_t offset = 0) const noexcept {
882 template<
typename Exc,
typename ... Args>
requires std::is_constructible_v<Exc, Args...>
883 size_t find_or_throw(str_piece pattern,
size_t offset = 0, Args&& ... args)
const noexcept {
884 if (
auto fnd = find(pattern.symbols(), pattern.length(), offset); fnd != str::npos) {
887 throw Exc(std::forward<Args>(args)...);
895 size_t find_end(str_piece pattern,
size_t offset = 0) const noexcept {
896 size_t fnd = find(pattern.
symbols(), pattern.
length(), offset);
897 return fnd == str::npos ? fnd : fnd + pattern.
length();
905 size_t find_or_all(str_piece pattern,
size_t offset = 0) const noexcept {
906 auto fnd = find(pattern.
symbols(), pattern.
length(), offset);
907 return fnd == str::npos ? _len() : fnd;
916 auto fnd = find(pattern.
symbols(), pattern.
length(), offset);
917 return fnd == str::npos ? _len() : fnd + pattern.
length();
920 size_t find_last(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
922 return find_last(pattern[0], offset);
923 size_t lenText = std::min(_len(), offset);
925 if (!lenPattern || lenPattern > lenText)
929 const K *text = _str() + lenPattern, last = pattern[lenPattern];
930 lenText -= lenPattern;
932 if (text[--lenText] == last) {
933 if (traits::compare(text + lenText - lenPattern, pattern, lenPattern) == 0) {
946 size_t find_last(str_piece pattern,
size_t offset = -1) const noexcept {
947 return find_last(pattern.
symbols(), pattern.
length(), offset);
956 size_t fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
957 return fnd == str::npos ? fnd : fnd + pattern.
length();
966 auto fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
967 return fnd == str::npos ? _len() : fnd;
976 size_t fnd = find_last(pattern.
symbols(), pattern.
length(), offset);
977 return fnd == str::npos ? _len() : fnd + pattern.
length();
985 bool contains(str_piece pattern,
size_t offset = 0) const noexcept {
986 return find(pattern, offset) != str::npos;
994 size_t find(K s,
size_t offset = 0) const noexcept {
997 const K *str = _str(), *fnd = traits::find(str + offset, len - offset, s);
999 return static_cast<size_t>(fnd - str);
1010 size_t len = _len();
1012 const K *str = _str(), *fnd = traits::find(str + offset, len - offset, s);
1014 return static_cast<size_t>(fnd - str);
1019 template<
typename Op>
1020 void for_all_finded(
const Op& op,
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
1023 while (maxCount-- > 0) {
1024 size_t fnd = find(pattern, patternLen, offset);
1025 if (fnd == str::npos)
1028 offset = fnd + patternLen;
1038 template<
typename Op>
1039 void for_all_finded(
const Op& op, str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
1040 for_all_finded(op, pattern.
symbols(), pattern.
length(), offset, maxCount);
1043 std::vector<size_t> find_all(
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
1044 std::vector<size_t> result;
1045 for_all_finded([&](
auto f) { result.push_back(f); }, pattern, patternLen, offset, maxCount);
1055 std::vector<size_t>
find_all(str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
1056 return find_all(pattern.
symbols(), pattern.
length(), offset, maxCount);
1065 size_t len = std::min(_len(), offset);
1066 const K *text = _str();
1068 if (text[--len] == s)
1080 return std::string_view{_str(), _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
1089 const K* text = _str();
1090 size_t fnd = std::string_view{text, _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
1091 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
1100 return std::string_view{_str(), _len()}.find_first_not_of(std::string_view{pattern.str, pattern.len}, offset);
1108 size_t find_last_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
1109 return std::string_view{_str(), _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
1117 std::pair<size_t, size_t>
find_last_of_idx(str_piece pattern,
size_t offset = str::npos)
const noexcept {
1118 const K* text = _str();
1119 size_t fnd = std::string_view{text, _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
1120 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
1129 return std::string_view{_str(), _len()}.find_last_not_of(std::string_view{pattern.str, pattern.len}, offset);
1137 my_type
substr(ptrdiff_t from, ptrdiff_t len = 0)
const {
1138 return my_type{d()(from, len)};
1146 my_type
str_mid(
size_t from,
size_t len = -1)
const {
1147 return my_type{d().mid(from, len)};
1164 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
1166 auto [res, err, _] = int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
1184 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
1185 std::tuple<T, IntConvertResult, size_t>
to_int() const noexcept {
1186 return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
1193 static_assert(
sizeof(K) == 1 ||
sizeof(K) ==
sizeof(wchar_t),
"Only char and wchar available for conversion to double now");
1194 size_t len = _len();
1196 const size_t copyLen = 64;
1198 const K* ptr = _str();
1199 if (ptr[len] != 0) {
1200 while (len && uns_type(*ptr) <=
' ') {
1205 len = std::min(copyLen, len);
1206 traits::copy(buf, ptr, len);
1213 static const _locale_t lc = _wcreate_locale(LC_NUMERIC, L
"C");
1214 if constexpr (
sizeof(K) == 1) {
1215 return _strtod_l(ptr,
nullptr, lc);
1217 if constexpr (
sizeof(K) ==
sizeof(wchar_t)) {
1218 return _wcstod_l((
const wchar_t*)ptr,
nullptr, lc);
1221 if constexpr (
sizeof(K) == 1) {
1222 return std::strtod(ptr,
nullptr);
1223 }
else if constexpr (
sizeof(K) ==
sizeof(wchar_t)) {
1224 return std::wcstod((
const wchar_t*)ptr,
nullptr);
1237 template<ToIntNumber T>
1249 template<
typename T,
typename Op>
1250 T splitf(
const K* delimeter,
size_t lenDelimeter,
const Op& beforeFunc,
size_t offset)
const {
1251 size_t mylen = _len();
1252 std::conditional_t<std::is_same_v<T, void>, char, T> results;
1253 str_piece me{_str(), mylen};
1254 for (
int i = 0;; i++) {
1255 size_t beginOfDelim = find(delimeter, lenDelimeter, offset);
1256 if (beginOfDelim == str::npos) {
1257 str_piece last{me.symbols() + offset, me.length() - offset};
1258 if constexpr (std::is_invocable_v<Op, str_piece&>) {
1261 if constexpr (
requires { results.emplace_back(last); }) {
1262 if (last.is_same(me)) {
1264 results.emplace_back(d());
1266 results.emplace_back(last);
1268 }
else if constexpr (
requires { results.push_back(last); }) {
1269 if (last.is_same(me)) {
1271 results.push_back(d());
1273 results.push_back(last);
1275 }
else if constexpr (
requires {results[i] = last;} &&
requires{std::size(results);}) {
1276 if (i < std::size(results)) {
1277 if (last.is_same(me)) {
1286 str_piece piece{me.symbols() + offset, beginOfDelim - offset};
1287 if constexpr (std::is_invocable_v<Op, str_piece&>) {
1290 if constexpr (
requires { results.emplace_back(piece); }) {
1291 results.emplace_back(piece);
1292 }
else if constexpr (
requires { results.push_back(piece); }) {
1293 results.push_back(piece);
1294 }
else if constexpr (
requires { results[i] = piece; } &&
requires{std::size(results);}) {
1295 if (i < std::size(results)) {
1297 if (i == results.size() - 1) {
1302 offset = beginOfDelim + lenDelimeter;
1304 if constexpr (!std::is_same_v<T, void>) {
1324 template<
typename T,
typename Op>
1325 T
splitf(str_piece delimeter,
const Op& beforeFunc,
size_t offset = 0)
const {
1326 return splitf<T>(delimeter.
symbols(), delimeter.
length(), beforeFunc, offset);
1335 template<
typename T>
1336 T
split(str_piece delimeter,
size_t offset = 0)
const {
1337 return splitf<T>(delimeter.
symbols(), delimeter.
length(), 0, offset);
1348 constexpr bool starts_with(
const K* prefix,
size_t l)
const noexcept {
1349 return _len() >= l && 0 == traits::compare(_str(), prefix, l);
1356 return starts_with(prefix.symbols(), prefix.length());
1359 constexpr bool starts_with_ia(
const K* prefix,
size_t len)
const noexcept {
1360 size_t myLen = _len();
1364 const K* ptr1 = _str();
1366 K s1 = *ptr1++, s2 = *prefix++;
1369 if (makeAsciiLower(s1) != makeAsciiLower(s2))
1379 return starts_with_ia(prefix.symbols(), prefix.length());
1382 bool starts_with_iu(
const K* prefix,
size_t len)
const noexcept {
1383 return _len() >= len && 0 == uni::compareiu(_str(), len, prefix, len);
1390 return starts_with_iu(prefix.symbols(), prefix.length());
1394 constexpr bool prefix_in(
const K* text,
size_t len)
const noexcept {
1395 size_t myLen = _len();
1398 return !myLen || 0 == traits::compare(text, _str(), myLen);
1405 return prefix_in(text.symbols(), text.length());
1408 constexpr bool ends_with(
const K* suffix,
size_t len)
const noexcept {
1409 size_t myLen = _len();
1410 return len <= myLen && traits::compare(_str() + myLen - len, suffix, len) == 0;
1417 return ends_with(suffix.symbols(), suffix.length());
1420 constexpr bool ends_with_ia(
const K* suffix,
size_t len)
const noexcept {
1421 size_t myLen = _len();
1425 const K* ptr1 = _str() + myLen - len;
1427 K s1 = *ptr1++, s2 = *suffix++;
1430 if (makeAsciiLower(s1) != makeAsciiLower(s2))
1440 return ends_with_ia(suffix.symbols(), suffix.length());
1443 constexpr bool ends_with_iu(
const K* suffix,
size_t len)
const noexcept {
1444 size_t myLen = _len();
1445 return myLen >= len && 0 == uni::compareiu(_str() + myLen - len, len, suffix, len);
1452 return ends_with_iu(suffix.symbols(), suffix.length());
1460 const int sl = ascii_mask<K>::WIDTH;
1461 const size_t mask = ascii_mask<K>::VALUE;
1462 size_t len = _len();
1463 const uns_type* ptr =
reinterpret_cast<const uns_type*
>(_str());
1464 if constexpr (sl > 1) {
1465 const size_t roundMask =
sizeof(size_t) - 1;
1466 while (len >= sl && (
reinterpret_cast<size_t>(ptr) & roundMask) != 0) {
1472 if (*
reinterpret_cast<const size_t*
>(ptr) & mask)
1489 template<
typename R = my_type>
1491 return R::uppered_only_ascii_from(d());
1498 template<
typename R = my_type>
1500 return R::lowered_only_ascii_from(d());
1507 template<
typename R = my_type>
1509 return R::uppered_from(d());
1516 template<
typename R = my_type>
1518 return R::lowered_from(d());
1529 template<
typename R = my_type>
1530 R
replaced(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0)
const {
1531 return R::replaced_from(d(), pattern, repl, offset, maxCount);
1540 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename M,
size_t L = const_lit_for<K, M>::Count>
1542 return expr_replaces<K, N - 1, L - 1>{d(), pattern, repl};
1545 template<StrType<K> From>
1546 static my_type make_trim_op(
const From& from,
const auto& opTrim) {
1547 str_piece sfrom = from, newPos = opTrim(sfrom);
1548 return newPos.is_same(sfrom) ? my_type{from} : my_type{newPos};
1550 template<TrimS
ides S, StrType<K> From>
1551 static my_type trim_static(
const From& from) {
1552 return make_trim_op(from, trim_operator<S, K,
static_cast<size_t>(-1),
true>{});
1555 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count, StrType<K> From>
1556 requires is_const_pattern<N>
1557 static my_type trim_static(
const From& from, T&& pattern) {
1558 return make_trim_op(from, trim_operator<S, K, N - 1, withSpaces>{pattern});
1561 template<TrimS
ides S,
bool withSpaces, StrType<K> From>
1562 static my_type trim_static(
const From& from, str_piece pattern) {
1563 return make_trim_op(from, trim_operator<S, K, 0, withSpaces>{{pattern}});
1570 template<
typename R = str_piece>
1572 return R::template trim_static<TrimSides::TrimAll>(d());
1579 template<
typename R = str_piece>
1581 return R::template trim_static<TrimSides::TrimLeft>(d());
1588 template<
typename R = str_piece>
1590 return R::template trim_static<TrimSides::TrimRight>(d());
1598 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1599 requires is_const_pattern<N>
1601 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
1609 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1610 requires is_const_pattern<N>
1612 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
1620 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1621 requires is_const_pattern<N>
1623 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
1635 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1636 requires is_const_pattern<N>
1638 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
1648 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1649 requires is_const_pattern<N>
1651 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
1661 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
1662 requires is_const_pattern<N>
1664 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
1674 template<
typename R = str_piece>
1676 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
1684 template<
typename R = str_piece>
1686 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
1694 template<
typename R = str_piece>
1696 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
1706 template<
typename R = str_piece>
1708 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
1718 template<
typename R = str_piece>
1720 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
1730 template<
typename R = str_piece>
1732 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
1737#define empty_bases __declspec(empty_bases)
1756struct simple_str : str_algs<K, simple_str<K>, simple_str<K>, false> {
1757 using symb_type = K;
1758 using my_type = simple_str<K>;
1760 const symb_type* str;
1763 simple_str() =
default;
1768 template<typename T, size_t N = const_lit_for<K, T>::Count>
1773 constexpr simple_str(
const K* p,
size_t l) noexcept : str(p), len(l) {}
1778 template<
typename S>
1779 requires(std::is_same_v<S, std::string&> || std::is_same_v<S, const std::string&>
1780 || std::is_same_v<S, std::string_view&> || std::is_same_v<S, const std::string_view&>)
1781 constexpr simple_str(S&& s) noexcept : str(s.data()), len(s.length()) {}
1791 constexpr const symb_type*
symbols() const noexcept {
1804 bool is_same(simple_str<K> other)
const noexcept {
1805 return str == other.str && len == other.len;
1812 return str >= other.str && str + len <= other.str + other.len;
1855struct simple_str_nt : simple_str<K> {
1856 using symb_type = K;
1857 using my_type = simple_str_nt<K>;
1858 using base = simple_str<K>;
1861 constexpr static const K empty_string[1] = {0};
1863 simple_str_nt() =
default;
1873 template<
typename T>
requires std::is_same_v<std::remove_const_t<std::remove_pointer_t<std::remove_cvref_t<T>>>, K>
1876 base::str = base::len ? p : empty_string;
1882 template<
typename S>
1883 requires(std::is_same_v<S, std::string&> || std::is_same_v<S, const std::string&>
1884 || std::is_same_v<S, std::string_view&> || std::is_same_v<S, const std::string_view&>)
1887 static const my_type empty_str;
1892 operator const K*()
const noexcept {
1901 if (from > base::len) {
1904 return {base::str + from, base::len - from};
1909inline const simple_str_nt<K> simple_str_nt<K>::empty_str{simple_str_nt<K>::empty_string, 0};
1911using ssa = simple_str<u8s>;
1912using ssw = simple_str<wchar_t>;
1913using ssu = simple_str<u16s>;
1914using ssuu = simple_str<u32s>;
1915using stra = simple_str_nt<u8s>;
1916using strw = simple_str_nt<wchar_t>;
1917using stru = simple_str_nt<u16s>;
1918using struu = simple_str_nt<u32s>;
1935 return text_.length() == str::npos;
1942 if (!text_.length()) {
1947 }
else if (text_.length() == str::npos) {
1948 return {
nullptr, 0};
1950 size_t pos = text_.find(delim_),
next = 0;
1951 if (pos == str::npos) {
1952 pos = text_.length();
1955 next = pos + delim_.length();
1964template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
1969template<
typename K,
bool withSpaces>
1970struct CheckSpaceTrim {
1971 bool is_trim_spaces(K s)
const {
1972 return s ==
' ' || (s >= 9 && s <= 13);
1976struct CheckSpaceTrim<K, false> {
1977 bool is_trim_spaces(K)
const {
1983struct CheckSymbolsTrim {
1984 simple_str<K> symbols;
1985 bool is_trim_symbols(K s)
const {
1986 return symbols.len != 0 && simple_str<K>::traits::find(symbols.str, symbols.len, s) !=
nullptr;
1990template<
typename K,
size_t N>
1991struct CheckConstSymbolsTrim {
1992 const const_lit_to_array<K, N> symbols;
1994 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
1995 constexpr CheckConstSymbolsTrim(T&& s) : symbols(std::forward<T>(s)) {}
1997 bool is_trim_symbols(K s)
const noexcept {
1998 return symbols.contain(s);
2003struct CheckConstSymbolsTrim<K, 0> {
2004 bool is_trim_symbols(K)
const {
2009template<
typename K,
size_t N>
2010struct SymbSelector {
2011 using type = CheckConstSymbolsTrim<K, N>;
2015struct SymbSelector<K, 0> {
2016 using type = CheckSymbolsTrim<K>;
2020struct SymbSelector<K, static_cast<size_t>(-1)> {
2021 using type = CheckConstSymbolsTrim<K, 0>;
2024template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces>
2025struct trim_operator : SymbSelector<K, N>::type, CheckSpaceTrim<K, withSpaces> {
2026 bool isTrim(K s)
const {
2027 return CheckSpaceTrim<K, withSpaces>::is_trim_spaces(s) || SymbSelector<K, N>::type::is_trim_symbols(s);
2029 simple_str<K> operator()(simple_str<K> from)
const {
2030 if constexpr ((S & TrimSides::TrimLeft) != 0) {
2032 if (isTrim(*from.str)) {
2039 if constexpr ((S & TrimSides::TrimRight) != 0) {
2040 const K* back = from.str + from.len - 1;
2042 if (isTrim(*back)) {
2053template<TrimS
ides S,
typename K>
2054using SimpleTrim = trim_operator<S, K, size_t(-1),
true>;
2056using trim_w = SimpleTrim<TrimSides::TrimAll, u16s>;
2057using trim_a = SimpleTrim<TrimSides::TrimAll, u8s>;
2058using triml_w = SimpleTrim<TrimSides::TrimLeft, u16s>;
2059using triml_a = SimpleTrim<TrimSides::TrimLeft, u8s>;
2060using trimr_w = SimpleTrim<TrimSides::TrimRight, u16s>;
2061using trimr_a = SimpleTrim<TrimSides::TrimRight, u8s>;
2063template<TrimSides S = TrimSides::TrimAll, bool withSpaces = false, typename K, typename T, size_t N = const_lit_for<K, T>::Count>
2064 requires is_const_pattern<N>
2065inline auto trimOp(T&& pattern) {
2066 return trim_operator<S, K, N - 1, withSpaces>{pattern};
2069template<TrimS
ides S = TrimS
ides::TrimAll,
bool withSpaces = false,
typename K>
2070inline auto trimOp(simple_str<K> pattern) {
2071 return trim_operator<S, K, 0, withSpaces>{pattern};
2074template<
typename Src,
typename Dest>
2075struct utf_convert_selector;
2078struct utf_convert_selector<u8s, u16s> {
2079 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
2080 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u16s* dest);
2084struct utf_convert_selector<u8s, u32s> {
2085 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
2086 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u32s* dest);
2090struct utf_convert_selector<u8s, wchar_t> {
2091 static size_t need_len(
const u8s* src,
size_t srcLen) {
2092 return utf_convert_selector<u8s, wchar_type>::need_len(src, srcLen);
2094 static size_t convert(
const u8s* src,
size_t srcLen,
wchar_t* dest) {
2095 return utf_convert_selector<u8s, wchar_type>::convert(src, srcLen, to_w(dest));
2100struct utf_convert_selector<u16s, u8s> {
2101 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
2102 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u8s* dest);
2106struct utf_convert_selector<u16s, u32s> {
2107 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
2108 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u32s* dest);
2112struct utf_convert_selector<u16s, u16s> {
2114 static size_t need_len(
const u16s* src,
size_t srcLen) {
2117 static size_t convert(
const u16s* src,
size_t srcLen, u16s* dest) {
2118 ch_traits<u16s>::copy(dest, src, srcLen + 1);
2124struct utf_convert_selector<u32s, u32s> {
2126 static size_t need_len(
const u32s* src,
size_t srcLen) {
2129 static size_t convert(
const u32s* src,
size_t srcLen, u32s* dest) {
2130 ch_traits<u32s>::copy(dest, src, srcLen + 1);
2136struct utf_convert_selector<u16s, wchar_t> {
2137 static size_t need_len(
const u16s* src,
size_t srcLen) {
2138 return utf_convert_selector<u16s, wchar_type>::need_len(src, srcLen);
2140 static size_t convert(
const u16s* src,
size_t srcLen,
wchar_t* dest) {
2141 return utf_convert_selector<u16s, wchar_type>::convert(src, srcLen, to_w(dest));
2146struct utf_convert_selector<u32s, u8s> {
2147 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
2148 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u8s* dest);
2152struct utf_convert_selector<u32s, u16s> {
2153 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
2154 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u16s* dest);
2158struct utf_convert_selector<u32s, wchar_t> {
2159 static size_t need_len(
const u32s* src,
size_t srcLen) {
2160 return utf_convert_selector<u32s, wchar_type>::need_len(src, srcLen);
2162 static size_t convert(
const u32s* src,
size_t srcLen,
wchar_t* dest) {
2163 return utf_convert_selector<u32s, wchar_type>::convert(src, srcLen, to_w(dest));
2168struct utf_convert_selector<wchar_t, u8s> {
2169 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2170 return utf_convert_selector<wchar_type, u8s>::need_len(to_w(src), srcLen);
2172 static size_t convert(
const wchar_t* src,
size_t srcLen, u8s* dest) {
2173 return utf_convert_selector<wchar_type, u8s>::convert(to_w(src), srcLen, dest);
2178struct utf_convert_selector<wchar_t, u16s> {
2179 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2180 return utf_convert_selector<wchar_type, u16s>::need_len(to_w(src), srcLen);
2182 static size_t convert(
const wchar_t* src,
size_t srcLen, u16s* dest) {
2183 return utf_convert_selector<wchar_type, u16s>::convert(to_w(src), srcLen, dest);
2188struct utf_convert_selector<wchar_t, u32s> {
2189 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
2190 return utf_convert_selector<wchar_type, u32s>::need_len(to_w(src), srcLen);
2192 static size_t convert(
const wchar_t* src,
size_t srcLen, u32s* dest) {
2193 return utf_convert_selector<wchar_type, u32s>::convert(to_w(src), srcLen, dest);
2205template<
typename K,
typename Impl>
2206class from_utf_convertable {
2208 from_utf_convertable() =
default;
2209 using my_type = Impl;
2217 template<
typename O>
2218 requires(!std::is_same_v<O, K>)
2220 using worker = utf_convert_selector<O, K>;
2221 Impl* d =
static_cast<Impl*
>(
this);
2222 size_t len = init.
length();
2226 size_t need = worker::need_len(init.
symbols(), len);
2227 K* str = d->init(need);
2229 worker::convert(init.
symbols(), len, str);
2232 template<
typename O,
typename I,
bool M>
2233 requires(!std::is_same_v<O, K>)
2242template<
typename From,
typename To>
requires (!std::is_same_v<From, To>)
2244 using symb_type = To;
2245 using worker = utf_convert_selector<From, To>;
2249 size_t length()
const noexcept {
2250 return worker::need_len(source_.symbols(), source_.length());
2252 To* place(To* ptr)
const noexcept {
2253 return ptr + worker::convert(source_.symbols(), source_.length(), ptr);
2264template<
typename To,
typename From>
requires (!std::is_same_v<From, To>)
2272template<
typename A,
typename K>
2274 A::is_str_storable ==
true;
2275 std::is_same_v<typename A::symb_type, K>;
2281template<
typename A,
typename K>
2287template<
typename A,
typename K>
2313template<
typename K,
typename Impl,
typename Allocator>
2316 using my_type = Impl;
2317 using traits = ch_traits<K>;
2318 using allocator_t = Allocator;
2321 [[_no_unique_address]]
2322 allocator_t allocator_;
2330 const allocator_t& allocator()
const {
2334 using uni = unicode_traits<K>;
2336 Impl& d() noexcept {
2337 return *
static_cast<Impl*
>(
this);
2339 const Impl& d() const noexcept {
2340 return *
static_cast<const Impl*
>(
this);
2342 template<
typename... Args>
2343 requires std::is_constructible_v<allocator_t, Args...>
2344 explicit constexpr str_storable(
size_t size, Args&&... args) : allocator_(std::forward<Args>(args)...) {
2351 template<StrType<K> From,
typename Op1,
typename... Args>
2352 requires std::is_constructible_v<allocator_t, Args...>
2353 static my_type changeCaseAscii(
const From& f,
const Op1& opMakeNeedCase, Args&&... args) {
2354 my_type result{std::forward<Args>(args)...};
2355 size_t len = f.length();
2357 const K* source = f.symbols();
2358 K* destination = result.init(len);
2359 for (
size_t l = 0; l < len; l++) {
2360 destination[l] = opMakeNeedCase(source[l]);
2367 template<
typename T,
bool Dummy = true>
2369 template<
typename From,
typename Op1,
typename... Args>
2370 requires std::is_constructible_v<allocator_t, Args...>
2371 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
2372 my_type result{std::forward<Args>(args)...};
2373 size_t len = f.length();
2375 opChangeCase(f.symbols(), len, result.init(len));
2381 template<
bool Dummy>
2382 struct ChangeCase<u8s, Dummy> {
2383 template<
typename From,
typename Op1,
typename... Args>
2384 requires std::is_constructible_v<allocator_t, Args...>
2385 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
2386 my_type result{std::forward<Args>(args)...};
2388 size_t len = f.length();
2390 const K* ptr = f.symbols();
2391 K* pWrite = result.init(len);
2393 const u8s* source = ptr;
2395 size_t newLen = opChangeCase(source, len, dest, len);
2398 result.set_size(newLen);
2399 }
else if (newLen > len) {
2401 size_t readed =
static_cast<size_t>(source - ptr);
2402 size_t writed =
static_cast<size_t>(dest - pWrite);
2403 pWrite = result.set_size(newLen);
2404 dest = pWrite + writed;
2405 opChangeCase(source, len - readed, dest, newLen - writed);
2414 using s_str = simple_str<K>;
2415 using s_str_nt = simple_str_nt<K>;
2417 inline static constexpr bool is_str_storable =
true;
2423 template<
typename... Args>
2424 requires std::is_constructible_v<allocator_t, Args...>
2425 constexpr str_storable(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
2426 : allocator_(std::forward<Args>(args)...) {
2435 template<
typename... Args>
2436 requires std::is_constructible_v<allocator_t, Args...>
2437 constexpr str_storable(s_str other, Args&&... args) : allocator_(std::forward<Args>(args)...) {
2439 K* ptr = d().init(other.length());
2440 traits::copy(ptr, other.symbols(), other.length());
2441 ptr[other.length()] = 0;
2451 template<
typename... Args>
2452 requires std::is_constructible_v<allocator_t, Args...>
2453 constexpr str_storable(
size_t repeat, s_str pattern, Args&&... args) : allocator_(std::forward<Args>(args)...) {
2454 size_t l = pattern.
length(), allLen = l * repeat;
2456 K* ptr = d().init(allLen);
2457 for (
size_t i = 0; i < repeat; i++) {
2458 traits::copy(ptr, pattern.
symbols(), l);
2471 template<
typename... Args>
2472 requires std::is_constructible_v<allocator_t, Args...>
2473 str_storable(
size_t count, K pad, Args&&... args) : allocator_(std::forward<Args>(args)...) {
2475 K* str = d().init(count);
2476 traits::assign(str, count, pad);
2489 template<
typename... Args>
2490 requires std::is_constructible_v<allocator_t, Args...>
2492 size_t len = expr.length();
2494 *expr.place(d().init(len)) = 0;
2507 template<StrType<K> From,
typename... Args>
2508 requires std::is_constructible_v<allocator_t, Args...>
2509 str_storable(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
2510 : allocator_(std::forward<Args>(args)...) {
2512 auto findes = f.find_all(pattern, offset, maxCount);
2513 if (!findes.size()) {
2514 new (this) my_type{f};
2517 size_t srcLen = f.length();
2518 size_t newSize = srcLen +
static_cast<ptrdiff_t
>(repl.len - pattern.len) * findes.size();
2521 new (
this) my_type{};
2525 K* ptr = d().init(newSize);
2526 const K* src = f.symbols();
2528 for (
const auto& s: findes) {
2529 size_t copyLen = s - from;
2531 traits::copy(ptr, src + from, copyLen);
2535 traits::copy(ptr, repl.str, repl.len);
2538 from = s + pattern.len;
2542 traits::copy(ptr, src + from, srcLen);
2551 operator const K*()
const noexcept {
2552 return d().symbols();
2560 size_t len = d().
length();
2564 return {d().symbols() + from, len - from};
2570 operator s_str_nt()
const {
2571 return {d().symbols(), d().length()};
2593 template<
typename T,
typename... Args>
2594 requires std::is_constructible_v<allocator_t, Args...>
2595 static my_type
join(
const T& strings, s_str delimeter,
bool tail =
false,
bool skip_empty =
false, Args&&... args) {
2596 my_type result(std::forward<Args>(args)...);
2597 if (strings.size()) {
2598 if (strings.size() == 1 && (!delimeter.
length() || !tail)) {
2599 result = strings.front();
2601 size_t commonLen = 0;
2602 for (
const auto& t: strings) {
2603 size_t len = t.length();
2604 if (len > 0 || !skip_empty) {
2605 if (commonLen > 0) {
2606 commonLen += delimeter.len;
2611 commonLen += (tail && delimeter.len > 0 && (commonLen > 0 || (!skip_empty && strings.size() > 0))? delimeter.len : 0);
2613 K* ptr = result.init(commonLen);
2615 for (
const auto& t: strings) {
2616 size_t copyLen = t.length();
2617 if (delimeter.len > 0 && write != ptr && (copyLen || !skip_empty)) {
2618 ch_traits<K>::copy(write, delimeter.str, delimeter.len);
2619 write += delimeter.len;
2621 ch_traits<K>::copy(write, t.symbols(), copyLen);
2624 if (delimeter.len > 0 && tail && (write != ptr || (!skip_empty && strings.size() > 0))) {
2625 ch_traits<K>::copy(write, delimeter.str, delimeter.len);
2626 write += delimeter.len;
2630 result.create_empty();
2641 template<StrType<K> From,
typename... Args>
2642 requires std::is_constructible_v<allocator_t, Args...>
2644 return changeCaseAscii(f, makeAsciiUpper<K>, std::forward<Args>(args)...);
2651 template<StrType<K> From,
typename... Args>
2652 requires std::is_constructible_v<allocator_t, Args...>
2654 return changeCaseAscii(f, makeAsciiLower<K>, std::forward<Args>(args)...);
2663 template<StrType<K> From,
typename... Args>
2664 requires std::is_constructible_v<allocator_t, Args...>
2666 return ChangeCase<K>::changeCase(f, uni::upper, std::forward<Args>(args)...);
2675 template<StrType<K> From,
typename... Args>
2676 requires std::is_constructible_v<allocator_t, Args...>
2678 return ChangeCase<K>::changeCase(f, uni::lower, std::forward<Args>(args)...);
2689 template<StrType<K> From,
typename... Args>
2690 requires std::is_constructible_v<allocator_t, Args...>
2691 static my_type
replaced_from(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args) {
2692 return my_type{f, pattern, repl, offset, maxCount, std::forward<Args>(args)...};
2701 { a.allocate(size) } -> std::same_as<void*>;
2702 { a.deallocate(void_ptr) }
noexcept -> std::same_as<void>;
2705struct printf_selector {
2706 template<
typename K,
typename... T>
requires (is_one_of_std_char_v<K>)
2707 static int snprintf(K* buffer,
size_t count,
const K* format, T&&... args) {
2708 if constexpr (std::is_same_v<K, u8s>) {
2710 return std::snprintf(buffer, count, format, std::forward<T>(args)...);
2713 return _sprintf_p(buffer, count, format, args...);
2717 return std::swprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
2720 return _swprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
2724 template<
typename K>
requires (is_one_of_std_char_v<K>)
2725 static int vsnprintf(K* buffer,
size_t count,
const K* format, va_list args) {
2726 if constexpr (std::is_same_v<K, u8s>) {
2728 return std::vsnprintf(buffer, count, format, args);
2731 return _vsprintf_p(buffer, count, format, args);
2735 return std::vswprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args);
2738 return _vswprintf_p(buffer, count, format, args);
2744inline size_t grow2(
size_t ret,
size_t currentCapacity) {
2745 return ret <= currentCapacity ? ret : ret * 2;
2768template<
typename K,
typename Impl>
2771 using my_type = Impl;
2775 return *
static_cast<Impl*
>(
this);
2777 const Impl& d()
const {
2778 return *
static_cast<const Impl*
>(
this);
2780 size_t _len()
const noexcept {
2781 return d().length();
2783 const K* _str()
const noexcept {
2784 return d().symbols();
2787 using symb_type = K;
2788 using traits = ch_traits<K>;
2789 using uni = unicode_traits<K>;
2790 using uns_type = std::make_unsigned_t<K>;
2792 template<
typename Op>
2793 Impl& make_trim_op(
const Op& op) {
2794 str_piece me =
static_cast<str_piece
>(d()), pos = op(me);
2795 if (me.
length() != pos.length()) {
2796 if (me.
symbols() != pos.symbols())
2797 traits::move(
const_cast<K*
>(me.
symbols()), pos.symbols(), pos.length());
2798 d().set_size(pos.length());
2804 Impl& commonChangeCase() {
2805 size_t len = _len();
2807 Op(_str(), len,
str());
2812 template<
typename T,
bool Dummy = true>
2814 static Impl&
upper(Impl& obj) {
2815 return obj.template commonChangeCase<unicode_traits<K>::upper>();
2817 static Impl&
lower(Impl& obj) {
2818 return obj.template commonChangeCase<unicode_traits<K>::lower>();
2823 Impl& utf8CaseChange() {
2825 size_t len = _len();
2827 u8s* writePos =
str();
2828 const u8s *startData = writePos, *readPos = writePos;
2829 size_t newLen = Op(readPos, len, writePos, len);
2832 d().set_size(newLen);
2833 }
else if (newLen > len) {
2835 size_t readed =
static_cast<size_t>(readPos - startData);
2836 size_t writed =
static_cast<size_t>(writePos - startData);
2837 d().set_size(newLen);
2839 readPos = startData + readed;
2840 writePos =
const_cast<u8s*
>(startData) + writed;
2841 Op(readPos, len - readed, writePos, newLen - writed);
2846 template<
bool Dummy>
2847 struct CaseTraits<u8s, Dummy> {
2848 static Impl&
upper(Impl& obj) {
2849 return obj.template utf8CaseChange<unicode_traits<u8s>::upper>();
2851 static Impl&
lower(Impl& obj) {
2852 return obj.template utf8CaseChange<unicode_traits<u8s>::lower>();
2856 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count>
2857 Impl& makeTrim(T&& pattern) {
2858 return make_trim_op(trim_operator<S, K, N - 1, withSpaces>{pattern});
2861 template<TrimS
ides S,
bool withSpaces>
2862 Impl& makeTrim(str_piece pattern) {
2863 return make_trim_op(trim_operator<S, K, 0, withSpaces>{{pattern}});
2878 explicit operator K*()
noexcept {
2886 return make_trim_op(SimpleTrim<TrimSides::TrimAll, K>{});
2893 return make_trim_op(SimpleTrim<TrimSides::TrimLeft, K>{});
2900 return make_trim_op(SimpleTrim<TrimSides::TrimRight, K>{});
2907 template<typename T, size_t N = const_lit_for<K, T>::Count>
2908 requires is_const_pattern<N>
2910 return makeTrim<TrimSides::TrimAll, false>(pattern);
2917 template<typename T, size_t N = const_lit_for<K, T>::Count>
2918 requires is_const_pattern<N>
2920 return makeTrim<TrimSides::TrimLeft, false>(pattern);
2927 template<typename T, size_t N = const_lit_for<K, T>::Count>
2928 requires is_const_pattern<N>
2930 return makeTrim<TrimSides::TrimRight, false>(pattern);
2937 template<typename T, size_t N = const_lit_for<K, T>::Count>
2938 requires is_const_pattern<N>
2940 return makeTrim<TrimSides::TrimAll, true>(pattern);
2947 template<typename T, size_t N = const_lit_for<K, T>::Count>
2948 requires is_const_pattern<N>
2950 return makeTrim<TrimSides::TrimLeft, true>(pattern);
2957 template<typename T, size_t N = const_lit_for<K, T>::Count>
2958 requires is_const_pattern<N>
2960 return makeTrim<TrimSides::TrimRight, true>(pattern);
2968 return pattern.
length() ? makeTrim<TrimSides::TrimAll, false>(pattern) : d();
2976 return pattern.
length() ? makeTrim<TrimSides::TrimLeft, false>(pattern) : d();
2984 return pattern.
length() ? makeTrim<TrimSides::TrimRight, false>(pattern) : d();
2992 return makeTrim<TrimSides::TrimAll, true>(pattern);
3000 return makeTrim<TrimSides::TrimLeft, true>(pattern);
3008 return makeTrim<TrimSides::TrimRight, true>(pattern);
3016 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
3018 if (isAsciiLower(s))
3029 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
3031 if (isAsciiUpper(s))
3044 return CaseTraits<K>::upper(d());
3054 return CaseTraits<K>::lower(d());
3058 template<
typename T>
3059 Impl& changeImpl(
size_t from,
size_t len, T expr) {
3060 size_t myLen = _len();
3064 if (from + len > myLen) {
3068 size_t otherLen = expr.length();
3069 if (len == otherLen) {
3070 expr.place(buffer + from);
3072 size_t tailLen = myLen - from - len;
3073 if (len > otherLen) {
3074 expr.place(buffer + from);
3075 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
3076 d().set_size(myLen - (len - otherLen));
3078 buffer = d().set_size(myLen + otherLen - len);
3079 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
3080 expr.place(buffer + from);
3086 template<
typename T>
3087 Impl& appendImpl(T expr) {
3088 if (
size_t len = expr.length(); len) {
3089 size_t size = _len();
3090 expr.place(d().set_size(size + len) + size);
3095 template<
typename T>
3096 Impl& appendFromImpl(
size_t pos, T expr) {
3099 if (
size_t len = expr.length())
3100 expr.place(d().set_size(pos + len) + pos);
3107 inline static constexpr bool is_str_mutable =
true;
3114 return appendImpl<str_piece>(other);
3121 template<StrExprForType<K> A>
3123 return appendImpl<const A&>(expr);
3131 return appendImpl<str_piece>(other);
3138 template<StrExprForType<K> A>
3140 return appendImpl<const A&>(expr);
3151 return appendFromImpl<str_piece>(pos, other);
3161 template<StrExprForType<K> A>
3163 return appendFromImpl<const A&>(pos, expr);
3172 Impl&
change(
size_t from,
size_t len, str_piece other) {
3173 return changeImpl<str_piece>(from, len, other);
3182 template<StrExprForType<K> A>
3183 Impl&
change(
size_t from,
size_t len,
const A& expr) {
3184 return changeImpl<const A&>(from, len, expr);
3193 return changeImpl<str_piece>(to, 0, other);
3201 template<StrExprForType<K> A>
3203 return changeImpl<const A&>(to, 0, expr);
3212 return changeImpl<const empty_expr<K>&>(from, len, {});
3220 return changeImpl<str_piece>(0, 0, other);
3227 template<StrExprForType<K> A>
3229 return changeImpl<const A&>(0, 0, expr);
3239 Impl&
replace(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
3240 offset = d().find(pattern, offset);
3241 if (offset == str::npos) {
3246 size_t replLength = repl.
length(), patternLength = pattern.
length();
3248 if (patternLength == replLength) {
3251 for (
size_t i = 0; i < maxCount; i++) {
3252 traits::copy(ptr + offset, repl.
symbols(), replLength);
3253 offset = d().find(pattern, offset + replLength);
3254 if (offset == str::npos)
3257 }
else if (patternLength > replLength) {
3260 traits::copy(ptr + offset, repl.
symbols(), replLength);
3261 size_t posWrite = offset + replLength;
3263 offset += patternLength;
3265 for (
size_t i = 0; i < maxCount; i++) {
3266 size_t idx = d().find(pattern, offset);
3267 if (idx == str::npos)
3269 size_t lenOfPiece = idx - offset;
3270 traits::move(ptr + posWrite, ptr + offset, lenOfPiece);
3271 posWrite += lenOfPiece;
3272 traits::copy(ptr + posWrite, repl.
symbols(), replLength);
3273 posWrite += replLength;
3274 offset = idx + patternLength;
3276 size_t tailLen = _len() - offset;
3277 traits::move(ptr + posWrite, ptr + offset, tailLen);
3278 d().set_size(posWrite + tailLen);
3280 struct replace_grow_helper {
3281 replace_grow_helper(my_type& src, str_piece p, str_piece r,
size_t mc,
size_t d)
3282 : source(src), pattern(p), repl(r), maxCount(mc), delta(d) {}
3284 const str_piece pattern;
3285 const str_piece repl;
3289 K* reserve_for_copy{};
3290 size_t end_of_piece{};
3291 size_t total_length{};
3294 size_t finded[16] = {source.find(pattern, offset)};
3295 if (finded[0] == str::npos) {
3299 offset = finded[0] + pattern.
length();
3302 for (
size_t end = std::min(maxCount, std::size(finded)); idx < end; idx++, maxCount--) {
3303 finded[idx] = source.find(pattern, offset);
3304 if (finded[idx] == str::npos) {
3307 offset = finded[idx] + pattern.
length();
3310 bool needMore = maxCount > 0 && idx == std::size(finded) && offset < source.length() - pattern.
length();
3315 if (!reserve_for_copy) {
3317 end_of_piece = source.length();
3318 total_length = end_of_piece + all_delta;
3319 reserve_for_copy = source.alloc_for_copy(total_length);
3321 K* dst_start = reserve_for_copy;
3322 const K* src_start = source.symbols();
3324 size_t pos = finded[idx] + pattern.
length();
3325 size_t lenOfPiece = end_of_piece - pos;
3326 ch_traits<K>::move(dst_start + pos + all_delta, src_start + pos, lenOfPiece);
3327 ch_traits<K>::copy(dst_start + pos + all_delta - repl.
length(), repl.
symbols(), repl.
length());
3329 end_of_piece = finded[idx];
3331 if (!all_delta && reserve_for_copy != src_start) {
3332 ch_traits<K>::copy(dst_start, src_start, finded[0]);
3335 } helper(d(), pattern, repl, maxCount, repl.
length() - pattern.
length());
3336 helper.replace(offset);
3337 d().set_from_copy(helper.reserve_for_copy, helper.total_length);
3350 template<StrType<K> From>
3351 Impl&
replace_from(
const From& f, str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
3353 K* dst = d().reserve_no_preserve(f.length());
3354 const K* src = f.symbols();
3356 if (maxCount == 0) {
3359 size_t src_length = f.length(), start = 0;
3360 while (maxCount--) {
3361 offset = f.find(pattern, offset);
3362 if (offset == str::npos) {
3365 size_t piece_len = offset - start;
3367 ch_traits<K>::copy(dst, src + start, piece_len);
3375 offset += pattern.
length();
3378 if (start < src_length) {
3379 ch_traits<K>::copy(dst, src + start, src_length - start);
3381 d().set_size(src_length - delta);
3384 replace(pattern, repl, offset, maxCount);
3401 template<
typename Op>
3402 Impl&
fill(
size_t from,
const Op& fillFunction) {
3403 size_t size = _len();
3406 size_t capacity = d().capacity();
3410 size_t needSize = (size_t)fillFunction(ptr + from, capacity);
3411 if (capacity >= needSize) {
3412 d().set_size(from + needSize);
3415 ptr = from == 0 ? d().reserve_no_preserve(needSize) : d().set_size(from + needSize);
3416 capacity = d().capacity() - from;
3425 template<
typename Op>
3426 requires std::is_invocable_v<Op, K*, size_t>
3428 return fill(0, fillFunction);
3435 template<
typename Op>
3436 requires std::is_invocable_v<Op, K*, size_t>
3438 return fill(_len(), fillFunction);
3445 template<
typename Op>
3446 requires std::is_invocable_v<Op, my_type&>
3459 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3461 size_t size = _len();
3464 size_t capacity = d().capacity();
3472 if constexpr (
sizeof(K) == 1 && !isWindowsOs) {
3473 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
3474 if (result > (
int)capacity) {
3475 ptr = from == 0 ? d().reserve_no_preserve(result) : d().set_size(from + result);
3476 result = printf_selector::snprintf(ptr + from, result + 1,
format, std::forward<T>(args)...);
3480 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
3485 ptr = from == 0 ? d().reserve_no_preserve(capacity) : d().set_size(from + capacity);
3491 d().set_size(
static_cast<size_t>(traits::length(_str())));
3493 d().set_size(from + result);
3503 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3514 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3525 inline static K pad;
3526 K& operator*()
const {
3529 writer& operator++() {
3530 if (writed < max_write) {
3533 size_t l = ptr - store->begin();
3535 ptr = store->set_size(l + std::min(l / 2,
size_t(8192))) + l;
3543 writer operator++(
int) {
3549 writer(my_type& s, K* p, K* e,
size_t ml) : store(&s), ptr(p), end(e), max_write(ml) {}
3551 writer(
const writer&) =
delete;
3552 writer& operator=(
const writer&)
noexcept =
delete;
3553 writer(writer&&) noexcept = default;
3554 writer& operator=(writer&&) noexcept = default;
3555 using difference_type =
int;
3565 template<typename... T> requires (is_one_of_std_char_v<K>)
3567 size_t size = _len();
3570 size_t capacity = d().capacity();
3573 auto result = std::format_to(writer{d(), ptr + from, ptr + capacity, size_t(-1)},
3574 std::forward<decltype(format)>(
format), std::forward<T>(args)...);
3575 d().set_size(result.ptr - _str());
3587 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3589 size_t size = _len();
3592 size_t capacity = d().capacity();
3595 if constexpr (std::is_same_v<K, u8s>) {
3596 auto result = std::vformat_to(
3597 writer{d(), ptr + from, ptr + capacity, max_write},
3598 std::basic_string_view<K>{
format.symbols(),
format.length()},
3599 std::make_format_args(args...));
3600 d().set_size(result.ptr - _str());
3602 auto result = std::vformat_to(
3603 writer{d(), to_one_of_std_char(ptr + from), ptr + capacity, max_write},
3604 std::basic_string_view<wchar_t>{to_one_of_std_char(
format.symbols()),
format.length()},
3605 std::make_wformat_args(std::forward<T>(args)...));
3606 d().set_size(result.ptr - _str());
3617 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3618 Impl&
format(
const FmtString<K, T...>& pattern, T&&... args) {
3619 return format_from(0, pattern, std::forward<T>(args)...);
3628 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3639 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3650 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3662 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3674 template<
typename... T>
requires (is_one_of_std_char_v<K>)
3684 template<
typename Op,
typename... Args>
3685 Impl&
with(
const Op& fillFunction, Args&&... args) {
3686 fillFunction(d(), std::forward<Args>(args)...);
3692struct SharedStringData {
3693 std::atomic_size_t ref_;
3695 SharedStringData() {
3699 return (K*)(
this + 1);
3702 ref_.fetch_add(1, std::memory_order_relaxed);
3704 void decr(Allocatorable
auto& allocator) {
3705 size_t val = ref_.fetch_sub(1, std::memory_order_relaxed);
3707 allocator.deallocate(
this);
3710 static SharedStringData<K>* create(
size_t l, Allocatorable
auto& allocator) {
3711 size_t size =
sizeof(SharedStringData<K>) + (l + 1) *
sizeof(K);
3712 return new (allocator.allocate(size)) SharedStringData();
3714 static SharedStringData<K>* from_str(
const K* p) {
3715 return (SharedStringData<K>*)p - 1;
3717 K* place(K* p,
size_t len) {
3718 ch_traits<K>::copy(p, str(), len);
3724class string_common_allocator {
3726 void* allocate(
size_t bytes) {
3727 return new char[bytes];
3729 void deallocate(
void* address)
noexcept {
3730 delete []
static_cast<char*
>(address);
3734string_common_allocator default_string_allocator_selector(...);
3738using allocator_string =
decltype(default_string_allocator_selector(
int(0)));
3740template<
typename K, Allocatorable Allocator>
3760template<
typename K,
size_t N,
bool forShared = false, Allocatorable Allocator = allocator_
string>
3761class empty_bases lstring :
3762 public str_algs<K, simple_str<K>, lstring<K, N, forShared, Allocator>, true>,
3763 public str_mutable<K, lstring<K, N, forShared, Allocator>>,
3764 public str_storable<K, lstring<K, N, forShared, Allocator>, Allocator>,
3765 public from_utf_convertable<K, lstring<K, N, forShared, Allocator>> {
3767 using symb_type = K;
3768 using my_type = lstring<K, N, forShared, Allocator>;
3769 using allocator_t = Allocator;
3777 extra = forShared ?
sizeof(SharedStringData<K>) : 0,
3780 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
3781 using base_storable = str_storable<K, my_type, Allocator>;
3782 using base_mutable = str_mutable<K, my_type>;
3783 using base_utf = from_utf_convertable<K, my_type>;
3784 using traits = ch_traits<K>;
3786 friend base_storable;
3787 friend base_mutable;
3789 friend class sstring<K, Allocator>;
3797 K local_[LocalCapacity + 1];
3800 void create_empty() {
3805 static size_t calc_capacity(
size_t s) {
3806 size_t real_need = (s + 1) *
sizeof(K) + extra;
3807 size_t aligned_alloced = (real_need +
alignof(std::max_align_t) - 1) /
alignof(std::max_align_t) *
alignof(std::max_align_t);
3808 return (aligned_alloced - extra) /
sizeof(K) - 1;
3813 if (size_ > LocalCapacity) {
3814 s = calc_capacity(s);
3815 data_ = alloc_place(s);
3823 bool is_alloced() const noexcept {
3824 return data_ != local_;
3829 base_storable::allocator().deallocate(to_real_address(data_));
3834 static K* to_real_address(
void* ptr) {
3835 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) - extra);
3837 static K* from_real_address(
void* ptr) {
3838 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) + extra);
3841 K* alloc_place(
size_t newSize) {
3842 return from_real_address(base_storable::allocator().allocate((newSize + 1) *
sizeof(K) + extra));
3845 K* alloc_for_copy(
size_t newSize) {
3846 if (capacity() >= newSize) {
3850 return alloc_place(calc_capacity(newSize));
3853 void set_from_copy(K* ptr,
size_t newSize) {
3858 capacity_ = calc_capacity(newSize);
3865 using base_storable::base_storable;
3866 using base_utf::base_utf;
3868 lstring() =
default;
3880 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
3888 template<
typename... Args>
3889 requires(
sizeof...(Args) > 0 && std::is_convertible_v<allocator_t, Args...>)
3890 lstring(
const my_type& other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3892 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
3901 template<typename T, size_t I = const_lit_for<K, T>::Count,
typename... Args>
3902 requires std::is_constructible_v<allocator_t, Args...>
3903 constexpr lstring(T&& value, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3904 if constexpr (I > 1) {
3905 K* ptr = init(I - 1);
3906 traits::copy(ptr, value, I - 1);
3915 lstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
3917 size_ = other.size_;
3918 if (other.is_alloced()) {
3919 data_ = other.data_;
3920 capacity_ = other.capacity_;
3923 traits::copy(local_, other.local_, size_ + 1);
3925 other.data_ = other.local_;
3927 other.local_[0] = 0;
3935 template<
typename Op,
typename... Args>
3936 requires(std::is_constructible_v<Allocator, Args...> && (std::is_invocable_v<Op, my_type&> || std::is_invocable_v<Op, K*, size_t>))
3937 lstring(
const Op& op, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3951 if (&other !=
this) {
3953 size_ = other.size_;
3964 if (&other !=
this) {
3966 if (other.is_alloced()) {
3967 data_ = other.data_;
3968 capacity_ = other.capacity_;
3970 traits::copy(data_, other.local_, other.size_ + 1);
3973 size_ = other.size_;
3974 other.create_empty();
3979 my_type& assign(
const K* other,
size_t len) {
3981 bool isIntersect = other >= data_ && other + len <= data_ + size_;
3985 if (other > data_) {
3986 traits::move(data_, other, len);
3989 traits::copy(reserve_no_preserve(len), other, len);
4002 return assign(other.str, other.len);
4009 template<typename T, size_t S = const_lit_for<K, T>::Count>
4011 return assign(other, S - 1);
4020 size_t newLen = expr.
length();
4061 newSize = calc_capacity(newSize);
4062 K* newData = alloc_place(newSize);
4065 capacity_ = newSize;
4078 newSize = calc_capacity(newSize);
4079 K* newData = alloc_place(newSize);
4080 traits::copy(newData, data_, size_);
4083 capacity_ = newSize;
4096 if (newSize > cap) {
4097 size_t needPlace = newSize;
4098 if (needPlace < (cap + 1) * 2) {
4099 needPlace = (cap + 1) * 2 - 1;
4111 return !is_alloced();
4119 for (
size_t i = 0; i < cap; i++) {
4120 if (data_[i] == 0) {
4133 size_t need_capacity = calc_capacity(size_);
4134 if (is_alloced() && capacity_ > need_capacity) {
4135 K* newData = size_ <=
LocalCapacity ? local_ : alloc_place(need_capacity);
4136 traits::copy(newData, data_, size_ + 1);
4141 capacity_ = need_capacity;
4157template<
size_t N = 15>
4158using lstringa = lstring<u8s, N>;
4159template<
size_t N = 15>
4160using lstringw = lstring<wchar_t, N>;
4161template<
size_t N = 15>
4162using lstringu = lstring<u16s, N>;
4163template<
size_t N = 15>
4164using lstringuu = lstring<u32s, N>;
4166template<
size_t N = 15>
4167using lstringsa = lstring<u8s, N, true>;
4168template<
size_t N = 15>
4169using lstringsw = lstring<wchar_t, N, true>;
4170template<
size_t N = 15>
4171using lstringsu = lstring<u16s, N, true>;
4172template<
size_t N = 15>
4173using lstringsuu = lstring<u32s, N, true>;
4176template<typename T, typename K = typename const_lit<T>::symb_type>
4177auto getLiteralType(T&&) {
4181template<
size_t Arch,
size_t L>
4182inline constexpr const size_t _local_count = 0;
4185inline constexpr const size_t _local_count<8, 1> = 23;
4187inline constexpr const size_t _local_count<8, 2> = 15;
4189inline constexpr const size_t _local_count<8, 4> = 7;
4191inline constexpr const size_t _local_count<4, 1> = 15;
4193inline constexpr const size_t _local_count<4, 2> = 11;
4195inline constexpr const size_t _local_count<4, 4> = 5;
4198constexpr const size_t local_count = _local_count<
sizeof(size_t),
sizeof(T)>;
4227template<
typename K, Allocatorable Allocator = allocator_
string>
4228class empty_bases sstring :
4229 public str_algs<K, simple_str<K>, sstring<K, Allocator>, false>,
4230 public str_storable<K, sstring<K, Allocator>, Allocator>,
4231 public from_utf_convertable<K, sstring<K, Allocator>> {
4233 using symb_type = K;
4234 using uns_type = std::make_unsigned_t<K>;
4235 using my_type = sstring<K, Allocator>;
4236 using allocator_t = Allocator;
4238 enum { LocalCount = local_count<K> };
4241 using base_algs = str_algs<K, simple_str<K>, my_type,
false>;
4242 using base_storable = str_storable<K, my_type, Allocator>;
4243 using base_utf = from_utf_convertable<K, my_type>;
4244 using traits = ch_traits<K>;
4245 using uni = unicode_traits<K>;
4247 friend base_storable;
4250 enum Types { Local, Constant, Shared };
4259 uns_type localRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
4271 void create_empty() {
4273 localRemain_ = LocalCount;
4277 if (s > LocalCount) {
4285 localRemain_ = LocalCount - s;
4290 K* set_size(
size_t newSize) {
4294 if (newSize !=
size) {
4295 if (type_ == Constant) {
4298 if (newSize <= LocalCount) {
4299 if (type_ == Shared) {
4300 SharedStringData<K>* str_buf = SharedStringData<K>::from_str(sstr_);
4301 traits::copy(buf_, sstr_, newSize);
4305 localRemain_ = LocalCount - newSize;
4307 if (type_ == Shared) {
4308 if (newSize >
size || (newSize > 64 && newSize <=
size * 3 / 4)) {
4310 traits::copy(newStr, sstr_, newSize);
4314 }
else if (type_ == Local) {
4317 traits::copy(newStr, buf_,
size);
4326 K* str = type_ == Local ? buf_ : (K*)sstr_;
4332 using base_storable::base_storable;
4333 using base_utf::base_utf;
4335 sstring() =
default;
4341 template<
typename... Args>
4342 requires(
sizeof...(Args) > 0 && std::is_constructible_v<Allocator, Args...>)
4343 sstring(Args&&... args) : Allocator(std::forward<Args>(args)...) {}
4348 if (type_ == Shared) {
4356 sstring(
const my_type& other) noexcept : base_storable(other.allocator()) {
4357 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
4358 if (type_ == Shared)
4359 SharedStringData<K>::from_str(sstr_)->incr();
4365 sstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
4366 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
4367 other.create_empty();
4378 size_t size = src.length();
4380 if (src.is_alloced()) {
4383 if (
size > LocalCount) {
4389 new (SharedStringData<K>::from_str(str)) SharedStringData<K>();
4393 localRemain_ = LocalCount -
size;
4394 traits::copy(buf_, str,
size + 1);
4400 K* str = init(src.size_);
4401 traits::copy(str, src.symbols(),
size + 1);
4414 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename... Args>
4415 requires std::is_constructible_v<allocator_t, Args...>
4416 sstring(T&& s, Args&&... args) : base_storable(std::forward<Args>(args)...) {
4423 void swap(my_type&& other)
noexcept {
4424 char buf[
sizeof(buf_) +
sizeof(K)];
4425 memcpy(buf, buf_,
sizeof(buf));
4426 memcpy(buf_, other.buf_,
sizeof(buf));
4427 memcpy(other.buf_, buf,
sizeof(buf));
4429 std::swap(base_storable::allocator(), other.allocator());
4437 swap(std::move(other));
4453 template<typename T, size_t N = const_lit_for<K, T>::Count>
4462 template<
size_t N,
bool forShared,
typename A>
4473 return operator=(my_type{std::move(other)});
4489 if (type_ == Shared)
4496 return type_ == Local ? buf_ : cstr_;
4500 return type_ == Local ? LocalCount - localRemain_ : bigLen_;
4517 template<
typename... T>
4518 static my_type
printf(
const K* pattern, T&&... args) {
4527 template<
typename... T>
4528 static my_type
format(
const FmtString<K, T...>& fmtString, T&&... args) {
4537 template<
typename... T>
4543template<
typename K, Allocatorable Allocator>
4544inline const sstring<K> sstring<K, Allocator>::empty_str{};
4547struct digits_selector {
4548 using wider_type = uint16_t;
4552struct digits_selector<2> {
4553 using wider_type = uint32_t;
4557struct digits_selector<4> {
4558 using wider_type = uint64_t;
4561template<
typename K,
typename T>
4562constexpr size_t fromInt(K* bufEnd, T val) {
4563 const char* twoDigit =
4564 "0001020304050607080910111213141516171819"
4565 "2021222324252627282930313233343536373839"
4566 "4041424344454647484950515253545556575859"
4567 "6061626364656667686970717273747576777879"
4568 "8081828384858687888990919293949596979899";
4570 need_sign<K, std::is_signed_v<T>, T> sign(val);
4573 if constexpr (std::is_signed_v<T>) {
4576 const char* ptr = twoDigit - (val % 100) * 2;
4577 *--itr =
static_cast<K
>(ptr[1]);
4578 *--itr =
static_cast<K
>(ptr[0]);
4583 while (val >= 100) {
4584 const char* ptr = twoDigit + (val % 100) * 2;
4585 *--itr =
static_cast<K
>(ptr[1]);
4586 *--itr =
static_cast<K
>(ptr[0]);
4590 *--itr =
static_cast<K
>(
'0' + val);
4592 const char* ptr = twoDigit + val * 2;
4593 *--itr =
static_cast<K
>(ptr[1]);
4594 *--itr =
static_cast<K
>(ptr[0]);
4597 return size_t(bufEnd - itr);
4603template<
typename K,
typename T>
4605 using symb_type = K;
4606 using my_type = expr_num<K, T>;
4608 enum { bufSize = 24 };
4610 mutable K buf[bufSize];
4612 expr_num(T t) : value(t) {}
4613 expr_num(expr_num<K, T>&& t) : value(t.value) {}
4615 size_t length() const noexcept {
4616 value = (T)fromInt(buf + bufSize, value);
4617 return (
size_t)value;
4619 K* place(K* ptr)
const noexcept {
4620 ch_traits<K>::copy(ptr, buf + bufSize - (
size_t)value, (
size_t)value);
4621 return ptr + (size_t)value;
4632template<StrExpr A, FromIntNumber T>
4644template<StrExpr A, FromIntNumber T>
4658template<
typename K,
typename T>
4660 return expr_num<K, T>{t};
4664simple_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) {
4665 if constexpr (std::is_same_v<K, u8s>)
4667 if constexpr (std::is_same_v<K, uws>)
4669 if constexpr (std::is_same_v<K, u16s>)
4671 if constexpr (std::is_same_v<K, u32s>)
4675#define uni_string(K, p) select_str<K>(p, L##p, u##p, U##p)
4677template<
typename K>
requires (is_one_of_std_char_v<K>)
4679 using symb_type = K;
4683 expr_real(
double d) : v(d) {}
4684 expr_real(
float d) : v(d) {}
4686 size_t length() const noexcept {
4687 printf_selector::snprintf(buf, 40, uni_string(K,
"%.16g").
str, v);
4688 l = (size_t)ch_traits<K>::length(buf);
4691 K* place(K* ptr)
const noexcept {
4692 ch_traits<K>::copy(ptr, buf, l);
4704template<StrExpr A,
typename R>
4705 requires(is_one_of_std_char_v<typename A::symb_type> && (std::is_same_v<R, double> || std::is_same_v<R, float>))
4706inline constexpr auto operator+(
const A& a, R s) {
4717template<StrExpr A,
typename R>
4718 requires(is_one_of_std_char_v<typename A::symb_type> && (std::is_same_v<R, double> || std::is_same_v<R, float>))
4719inline constexpr auto operator+(R s,
const A& a) {
4730template<
typename K>
requires(is_one_of_std_char_v<K>)
4732 return expr_real<K>{t};
4744template<
typename K,
typename T,
size_t I,
bool tail,
bool skip_empty>
4746 using symb_type = K;
4747 using my_type = expr_join<K, T, I, tail, skip_empty>;
4752 constexpr size_t length() const noexcept {
4754 for (
const auto& t: s) {
4755 size_t len = t.length();
4756 if (len > 0 || !skip_empty) {
4757 if (I > 0 && l > 0) {
4763 return l + (tail && I > 0 && (l > 0 || (!skip_empty && s.size() > 0))? I : 0);
4765 constexpr K* place(K* ptr)
const noexcept {
4770 for (
const auto& t: s) {
4771 size_t copyLen = t.length();
4772 if (I > 0 && write != ptr && (copyLen || !skip_empty)) {
4773 ch_traits<K>::copy(write, delim, I);
4776 ch_traits<K>::copy(write, t.symbols(), copyLen);
4779 if (I > 0 && tail && (write != ptr || (!skip_empty && s.size() > 0))) {
4780 ch_traits<K>::copy(write, delim, I);
4795template<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>
4796inline constexpr auto e_join(
const T& s, L&& d) {
4797 return expr_join<K, T, I - 1, tail, skip_empty>{s, d};
4800template<
typename K,
size_t N,
size_t L>
4801struct expr_replaces {
4802 using symb_type = K;
4803 using my_type = expr_replaces<K, N, L>;
4807 mutable size_t first_, last_;
4809 constexpr expr_replaces(simple_str<K> w,
const K* p,
const K* r) : what(w), pattern(p), repl(r) {}
4811 constexpr size_t length()
const {
4812 size_t l = what.length();
4813 if constexpr (N == L) {
4816 first_ = what.find(pattern, N, 0);
4817 if (first_ != str::npos) {
4821 size_t next = what.find(pattern, N, last_);
4822 if (next == str::npos) {
4830 constexpr K* place(K* ptr)
const noexcept {
4831 if constexpr (N == L) {
4832 const K* from = what.symbols();
4833 for (
size_t start = 0; start < what.length();) {
4834 size_t next = what.find(pattern, N, start);
4835 if (next == str::npos) {
4836 next = what.length();
4838 size_t delta = next - start;
4839 ch_traits<K>::copy(ptr, from + start, delta);
4841 ch_traits<K>::copy(ptr, repl, L);
4847 if (first_ == str::npos) {
4848 return what.place(ptr);
4850 const K* from = what.symbols();
4851 for (
size_t start = 0, offset = first_; ;) {
4852 ch_traits<K>::copy(ptr, from + start, offset - start);
4853 ptr += offset - start;
4854 ch_traits<K>::copy(ptr, repl, L);
4857 if (start >= last_) {
4858 size_t tail = what.length() - last_;
4859 ch_traits<K>::copy(ptr, from + last_, tail);
4863 offset = what.find(pattern, N, start);
4878template<typename K, typename T, size_t N = const_lit_for<K, T>::Count,
typename X,
size_t L = const_lit_for<K, X>::Count>
4881 return expr_replaces<K, N - 1, L - 1>{w, p, r};
4897 using symb_type = K;
4902 mutable size_t first_, last_;
4911 constexpr size_t length()
const {
4912 size_t l = what.
length();
4916 first_ = what.find(pattern);
4917 if (first_ != str::npos) {
4918 last_ = first_ + pattern.
length();
4921 size_t next = what.find(pattern, last_);
4922 if (next == str::npos) {
4925 last_ = next + pattern.
length();
4930 constexpr K* place(K* ptr)
const noexcept {
4932 const K* from = what.
symbols();
4933 for (
size_t start = 0; start < what.
length();) {
4934 size_t next = what.find(pattern, start);
4935 if (next == str::npos) {
4938 size_t delta = next - start;
4939 ch_traits<K>::copy(ptr, from + start, delta);
4943 start = next + pattern.
length();
4947 if (first_ == str::npos) {
4948 return what.
place(ptr);
4950 const K* from = what.
symbols();
4951 for (
size_t start = 0, offset = first_; ;) {
4952 ch_traits<K>::copy(ptr, from + start, offset - start);
4953 ptr += offset - start;
4956 start = offset + pattern.
length();
4957 if (start >= last_) {
4958 size_t tail = what.
length() - last_;
4959 ch_traits<K>::copy(ptr, from + last_, tail);
4963 offset = what.find(pattern, start);
4970template<
bool UseVectorForReplace>
4971struct replace_search_result_store {
4973 std::pair<size_t, size_t> replaces_[16];
4977struct replace_search_result_store<true> : std::vector<std::pair<size_t, size_t>> {};
5000template<
typename K,
bool UseVectorForReplace = false>
5002 using symb_type = K;
5003 inline static const int BIT_SEARCH_TRESHHOLD = 4;
5006 const std::vector<std::pair<K, simple_str<K>>>& replaces_;
5010 mutable replace_search_result_store<UseVectorForReplace> search_results_;
5012 uu8s bit_mask_[
sizeof(K) == 1 ? 32 : 64]{};
5033 : source_(source), replaces_(repl)
5035 size_t pattern_len = replaces_.size();
5036 K* pattern = pattern_.set_size(pattern_len);
5038 for (
size_t idx = 0; idx < replaces_.size(); idx++) {
5039 *pattern++ = replaces_[idx].first;
5042 if (pattern_len >= BIT_SEARCH_TRESHHOLD) {
5043 for (
size_t idx = 0; idx < pattern_len; idx++) {
5044 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
5045 if constexpr (
sizeof(K) == 1) {
5046 bit_mask_[s >> 3] |= (1 << (s & 7));
5048 if (std::make_unsigned_t<K>(pattern_[idx]) > 255) {
5049 bit_mask_[32 + (s >> 3)] |= (1 << (s & 7));
5051 bit_mask_[s >> 3] |= (1 << (s & 7));
5058 size_t length()
const {
5059 size_t l = source_.
length();
5060 auto [fnd, num] = find_first_of(source_.str, source_.len);
5061 if (fnd == str::npos) {
5064 l += replaces_[num].second.len - 1;
5065 if constexpr (UseVectorForReplace) {
5066 search_results_.reserve((l >> 4) + 8);
5067 search_results_.emplace_back(fnd, num);
5068 for (
size_t start = fnd + 1;;) {
5069 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5070 if (fnd == str::npos) {
5073 search_results_.emplace_back(fnd, idx);
5075 l += replaces_[idx].second.len - 1;
5078 const size_t max_store = std::size(search_results_.replaces_);
5079 search_results_.replaces_[0] = {fnd, num};
5080 search_results_.count_++;
5081 for (
size_t start = fnd + 1;;) {
5082 auto [found, idx] = find_first_of(source_.str, source_.len, start);
5083 if (found == str::npos) {
5086 if (search_results_.count_ < max_store) {
5087 search_results_.replaces_[search_results_.count_] = {found, idx};
5089 l += replaces_[idx].second.len - 1;
5090 search_results_.count_++;
5096 K* place(K* ptr)
const noexcept {
5098 const K* text = source_.str;
5099 if constexpr (UseVectorForReplace) {
5100 for (
const auto& [pos, num] : search_results_) {
5101 size_t delta = pos - start;
5102 ch_traits<K>::copy(ptr, text + start, delta);
5104 ptr = replaces_[num].second.place(ptr);
5108 const size_t max_store = std::size(search_results_.replaces_);
5109 size_t founded = search_results_.count_;
5110 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
5111 const auto [pos, num] = search_results_.replaces_[idx];
5112 size_t delta = pos - start;
5113 ch_traits<K>::copy(ptr, text + start, delta);
5115 ptr = replaces_[num].second.place(ptr);
5118 if (founded > max_store) {
5119 founded -= max_store;
5121 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5122 size_t delta = fnd - start;
5123 ch_traits<K>::copy(ptr, text + start, delta);
5125 ptr = replaces_[idx].second.place(ptr);
5130 size_t tail = source_.len - start;
5131 ch_traits<K>::copy(ptr, text + start, tail);
5136 size_t index_of(K s)
const {
5137 return pattern_.find(s);
5140 bool is_in_mask(uu8s s)
const {
5141 return (bit_mask_[s >> 3] & (1 << (s & 7))) != 0;
5143 bool is_in_mask2(uu8s s)
const {
5144 return (bit_mask_[32 + (s >> 3)] & (1 << (s & 7))) != 0;
5147 bool is_in_pattern(K s,
size_t& idx)
const {
5148 if constexpr (
sizeof(K) == 1) {
5149 if (is_in_mask(s)) {
5154 if (std::make_unsigned_t<const K>(s) > 255) {
5155 if (is_in_mask2(s)) {
5156 return (idx = index_of(s)) != -1;
5159 if (is_in_mask(s)) {
5168 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
5169 size_t pl = pattern_.
length();
5170 if (pl >= BIT_SEARCH_TRESHHOLD) {
5172 while (offset < len) {
5173 if (is_in_pattern(text[offset], idx)) {
5174 return {offset, idx};
5179 while (offset < len) {
5180 if (
size_t idx = index_of(text[offset]); idx != -1) {
5181 return {offset, idx};
5191template<
typename K,
size_t N,
bool UseVectorForReplace>
5192struct expr_replace_const_symbols {
5193 using symb_type = K;
5194 inline static const int BIT_SEARCH_TRESHHOLD = 4;
5195 const K pattern_[N];
5196 const simple_str<K> source_;
5197 const simple_str<K> replaces_[N];
5199 mutable replace_search_result_store<UseVectorForReplace> search_results_;
5201 [[_no_unique_address]]
5202 uu8s bit_mask_[N >= BIT_SEARCH_TRESHHOLD ? (
sizeof(K) == 1 ? 32 : 64) : 0]{};
5204 template<
typename ... Repl>
requires (
sizeof...(Repl) == N * 2)
5205 constexpr expr_replace_const_symbols(simple_str<K> source, Repl&& ... repl) : expr_replace_const_symbols(0, source, std::forward<Repl>(repl)...) {}
5207 size_t length()
const {
5208 size_t l = source_.
length();
5209 auto [fnd, num] = find_first_of(source_.str, source_.len);
5210 if (fnd == str::npos) {
5213 l += replaces_[num].len - 1;
5214 if constexpr (UseVectorForReplace) {
5215 search_results_.reserve((l >> 4) + 8);
5216 search_results_.emplace_back(fnd, num);
5217 for (
size_t start = fnd + 1;;) {
5218 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5219 if (fnd == str::npos) {
5222 search_results_.emplace_back(fnd, idx);
5224 l += replaces_[idx].len - 1;
5227 const size_t max_store = std::size(search_results_.replaces_);
5228 search_results_.replaces_[0] = {fnd, num};
5229 search_results_.count_++;
5230 for (
size_t start = fnd + 1;;) {
5231 auto [found, idx] = find_first_of(source_.str, source_.len, start);
5232 if (found == str::npos) {
5235 if (search_results_.count_ < max_store) {
5236 search_results_.replaces_[search_results_.count_] = {found, idx};
5238 l += replaces_[idx].len - 1;
5239 search_results_.count_++;
5245 K* place(K* ptr)
const noexcept {
5247 const K* text = source_.str;
5248 if constexpr (UseVectorForReplace) {
5249 for (
const auto& [pos, num] : search_results_) {
5250 size_t delta = pos - start;
5251 ch_traits<K>::copy(ptr, text + start, delta);
5253 ptr = replaces_[num].place(ptr);
5257 const size_t max_store = std::size(search_results_.replaces_);
5258 size_t founded = search_results_.count_;
5259 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
5260 const auto [pos, num] = search_results_.replaces_[idx];
5261 size_t delta = pos - start;
5262 ch_traits<K>::copy(ptr, text + start, delta);
5264 ptr = replaces_[num].place(ptr);
5267 if (founded > max_store) {
5268 founded -= max_store;
5270 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5271 size_t delta = fnd - start;
5272 ch_traits<K>::copy(ptr, text + start, delta);
5274 ptr = replaces_[idx].place(ptr);
5279 size_t tail = source_.len - start;
5280 ch_traits<K>::copy(ptr, text + start, tail);
5285 template<
typename ... Repl>
5286 constexpr expr_replace_const_symbols(
int, simple_str<K> source, K s, simple_str<K> r, Repl&&... repl) :
5287 expr_replace_const_symbols(0, source, std::forward<Repl>(repl)..., std::make_pair(s, r)){}
5289 template<
typename ... Repl>
requires (
sizeof...(Repl) == N)
5290 constexpr expr_replace_const_symbols(
int, simple_str<K> source, Repl&&... repl) :
5291 source_(source), pattern_ {repl.first...}, replaces_{repl.second...}
5293 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
5294 for (
size_t idx = 0; idx < N; idx++) {
5295 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
5296 if constexpr (
sizeof(K) == 1) {
5297 bit_mask_[s >> 3] |= 1 << (s & 7);
5299 if (std::make_unsigned_t<const K>(pattern_[idx]) > 255) {
5300 bit_mask_[32 + (s >> 3)] |= 1 << (s & 7);
5302 bit_mask_[s >> 3] |= 1 << (s & 7);
5309 template<
size_t Idx>
5310 size_t index_of(K s)
const {
5311 if constexpr (Idx < N) {
5312 return pattern_[Idx] == s ? Idx : index_of<Idx + 1>(s);
5316 bool is_in_mask(uu8s s)
const {
5317 return (bit_mask_[s >> 3] & (1 <<(s & 7))) != 0;
5319 bool is_in_mask2(uu8s s)
const {
5320 return (bit_mask_[32 + (s >> 3)] & (1 <<(s & 7))) != 0;
5323 bool is_in_pattern(K s,
size_t& idx)
const {
5324 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
5325 if constexpr (
sizeof(K) == 1) {
5326 if (is_in_mask(s)) {
5327 idx = index_of<0>(s);
5331 if (std::make_unsigned_t<const K>(s) > 255) {
5332 if (is_in_mask2(s)) {
5333 return (idx = index_of<0>(s)) != -1;
5336 if (is_in_mask(s)) {
5337 idx = index_of<0>(s);
5345 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
5346 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
5348 while (offset < len) {
5349 if (is_in_pattern(text[offset], idx)) {
5350 return {offset, idx};
5355 while (offset < len) {
5356 if (
size_t idx = index_of<0>(text[offset]); idx != -1) {
5357 return {offset, idx};
5391template<
bool UseVector =
false,
typename K,
typename ... Repl>
5392requires (
sizeof...(Repl) % 2 == 0)
5394 return expr_replace_const_symbols<K,
sizeof...(Repl) / 2, UseVector>(src, std::forward<Repl>(other)...);
5401 char node[
sizeof(sstring<K>)];
5403 const simple_str_nt<K>& to_nt() const noexcept {
5404 return static_cast<const simple_str_nt<K>&
>(str);
5406 const sstring<K>& to_str() const noexcept {
5407 return *
reinterpret_cast<const sstring<K>*
>(node);
5411using HashKeyA = StoreType<u8s>;
5412using HashKeyW = StoreType<u16s>;
5413using HashKeyU = StoreType<u32s>;
5417 static inline constexpr size_t basis =
static_cast<size_t>(14695981039346656037ULL);
5418 static inline constexpr size_t prime =
static_cast<size_t>(1099511628211ULL);
5422struct fnv_const<false> {
5423 static inline constexpr size_t basis =
static_cast<size_t>(2166136261U);
5424 static inline constexpr size_t prime =
static_cast<size_t>(16777619U);
5427using fnv = fnv_const<
sizeof(size_t) == 8>;
5430inline constexpr size_t fnv_hash(
const K* ptr,
size_t l) {
5431 size_t h = fnv::basis;
5432 for (
size_t i = 0; i < l; i++) {
5433 h = (h ^ (std::make_unsigned_t<K>)ptr[i]) * fnv::prime;
5439inline constexpr size_t fnv_hash_ia(
const K* ptr,
size_t l) {
5440 size_t h = fnv::basis;
5441 for (
size_t i = 0; i < l; i++) {
5442 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)ptr[i];
5443 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
5448template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
5449inline constexpr size_t fnv_hash(T&& value) {
5450 size_t h = fnv::basis;
5451 for (
size_t i = 0; i < N - 1; i++) {
5452 h = (h ^ (std::make_unsigned_t<K>)value[i]) * fnv::prime;
5457template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
5458inline constexpr size_t fnv_hash_ia(T&& value) {
5459 size_t h = fnv::basis;
5460 for (
size_t i = 0; i < N - 1; i++) {
5461 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)value[i];
5462 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
5468inline consteval size_t fnv_hash_compile(
const K* ptr,
size_t l) {
5469 return fnv_hash(ptr, l);
5473inline consteval size_t fnv_hash_ia_compile(
const K* ptr,
size_t l) {
5474 return fnv_hash_ia(ptr, l);
5477static_assert(std::is_trivially_copyable_v<StoreType<u8s>>,
"Store type must be trivially copyable");
5532template<
typename K,
typename T,
typename H = strhash<K>,
typename E = streql<K>>
5533class hashStrMap :
public std::unordered_map<StoreType<K>, T, H, E> {
5535 using InStore = StoreType<K>;
5538 using my_type = hashStrMap<K, T, H, E>;
5539 using hash_t = std::unordered_map<InStore, T, H, E>;
5542 hashStrMap() =
default;
5543 hashStrMap(
const my_type& other) : hash_t(other) {
5544 for (
const auto& [k, v] : *
this) {
5545 InStore& stored =
const_cast<InStore&
>(k);
5547 new (stored.node)
sstring<K>(std::move(tmp));
5548 stored.str.str = stored.to_str().symbols();
5552 for (
auto& k: *
this)
5556 hashStrMap(my_type&& o) =
default;
5558 my_type& operator=(
const my_type& other) {
5559 hash_t::operator=(other);
5560 for (
const auto& [k, v] : *
this) {
5561 InStore& stored =
const_cast<InStore&
>(k);
5563 new (stored.node)
sstring<K>(std::move(tmp));
5564 stored.str.str = stored.to_str().symbols();
5568 my_type& operator=(my_type&&) =
default;
5570 hashStrMap(std::initializer_list<std::pair<
const StoreType<K>, T>>&& init) {
5571 for (
const auto& e: init)
5572 emplace(e.first, e.second);
5575 using init_str = std::initializer_list<std::pair<const sstring<K>, T>>;
5577 hashStrMap(init_str&& init) {
5578 for (
const auto& e: init)
5579 emplace(e.first, e.second);
5583 template<
typename... ValArgs>
5584 auto try_emplace(
const StoreType<K>& key, ValArgs&&... args) {
5585 auto it = hash_t::try_emplace(key, std::forward<ValArgs>(args)...);
5587 InStore& stored =
const_cast<InStore&
>(it.first->first);
5589 stored.str.str = stored.to_str().symbols();
5595 return {key, H{}(key)};
5598 template<
typename Key,
typename... ValArgs>
5599 requires(std::is_convertible_v<Key, simple_str<K>>)
5600 auto try_emplace(Key&& key, ValArgs&&... args) {
5601 auto it = hash_t::try_emplace(toStoreType(key), std::forward<ValArgs>(args)...);
5603 InStore& stored =
const_cast<InStore&
>(it.first->first);
5604 new (stored.node)
sstring<K>(std::forward<Key>(key));
5605 stored.str.str = stored.to_str().symbols();
5610 template<
typename... ValArgs>
5611 auto emplace(
const StoreType<K>& key, ValArgs&&... args) {
5612 auto it = try_emplace(key, std::forward<ValArgs>(args)...);
5614 it.first->second = T(std::forward<ValArgs>(args)...);
5619 template<
typename Key,
typename... ValArgs>
5620 requires(std::is_convertible_v<Key, simple_str<K>>)
5621 auto emplace(Key&& key, ValArgs&&... args) {
5622 auto it = try_emplace(std::forward<Key>(key), std::forward<ValArgs>(args)...);
5624 it.first->second = T(std::forward<ValArgs>(args)...);
5629 auto& operator[](
const StoreType<K>& key) {
5630 return try_emplace(key).first->second;
5633 template<
typename Key>
5634 requires(std::is_convertible_v<Key, simple_str<K>>)
5635 auto&
operator[](Key&& key) {
5636 return try_emplace(std::forward<Key>(key)).first->second;
5639 auto at(
const StoreType<K>& key) {
5640 return hash_t::at(key);
5642 auto at(
const StoreType<K>& key)
const {
5643 return hash_t::at(key);
5647 return hash_t::at(toStoreType(key));
5650 return hash_t::at(toStoreType(key));
5653 auto find(
const StoreType<K>& key)
const {
5654 return hash_t::find(key);
5658 return find(toStoreType(key));
5661 auto find(
const StoreType<K>& key) {
5662 return hash_t::find(key);
5666 return find(toStoreType(key));
5669 auto erase(
typename hash_t::const_iterator it) {
5670 if (it != hash_t::end()) {
5673 return hash_t::erase(it);
5676 auto erase(
const StoreType<K>& key) {
5677 auto it = hash_t::find(key);
5678 if (it != hash_t::end()) {
5687 return erase(toStoreType(key));
5690 bool lookup(
const K* txt, T& val)
const {
5691 auto it = find(e_s(txt));
5692 if (it != hash_t::end()) {
5700 auto it = find(txt);
5701 if (it != hash_t::end()) {
5709 for (
auto& k: *
this)
5713 bool contains(
const StoreType<K>& key)
const {
5714 return hash_t::find(key) != this->end();
5718 return find(toStoreType(key)) != this->end();
5724 bool operator()(
const StoreType<K>& _Left,
const StoreType<K>& _Right)
const {
5725 return _Left.hash == _Right.hash && _Left.str == _Right.str;
5731 size_t operator()(simple_str<K> _Keyval)
const {
5732 return fnv_hash(_Keyval.symbols(), _Keyval.length());
5734 size_t operator()(
const StoreType<K>& _Keyval)
const {
5735 return _Keyval.hash;
5741 bool operator()(
const StoreType<K>& _Left,
const StoreType<K>& _Right)
const {
5742 return _Left.hash == _Right.hash && _Left.str.equal_ia(_Right.str);
5748 size_t operator()(simple_str<K> _Keyval)
const {
5749 return fnv_hash_ia(_Keyval.symbols(), _Keyval.length());
5751 size_t operator()(
const StoreType<K>& _Keyval)
const {
5752 return _Keyval.hash;
5758 bool operator()(
const StoreType<K>& _Left,
const StoreType<K>& _Right)
const {
5759 return _Left.hash == _Right.hash && _Left.str.equal_iu(_Right.str);
5765 size_t operator()(simple_str<K> _Keyval)
const {
5766 return unicode_traits<K>::hashiu(_Keyval.symbols(), _Keyval.length());
5768 size_t operator()(
const StoreType<K>& _Keyval)
const {
5769 return _Keyval.hash;
5782class chunked_string_builder {
5783 using chunk_t = std::pair<std::unique_ptr<K[]>,
size_t>;
5784 std::vector<chunk_t> chunks;
5791 using my_type = chunked_string_builder<K>;
5792 using symb_type = K;
5793 chunked_string_builder() =
default;
5794 chunked_string_builder(
size_t a) : align(a){};
5795 chunked_string_builder(
const my_type&) =
delete;
5796 chunked_string_builder(my_type&& other) noexcept
5797 : chunks(std::move(other.chunks)), write(other.write), len(other.len), remain(other.remain), align(other.align) {
5798 other.len = other.remain = 0;
5799 other.write =
nullptr;
5801 my_type& operator=(my_type other)
noexcept {
5802 chunks.swap(other.chunks);
5803 write = other.write;
5805 remain = other.remain;
5806 align = other.align;
5807 other.len = other.remain = 0;
5808 other.write =
nullptr;
5816 if (
data.len <= remain) {
5818 ch_traits<K>::copy(write,
data.str,
data.len);
5820 chunks.back().second +=
data.len;
5826 ch_traits<K>::copy(write,
data.str, remain);
5829 chunks.back().second += remain;
5832 size_t blockSize = (
data.len + align - 1) / align * align;
5833 chunks.emplace_back(std::make_unique<K[]>(blockSize),
data.len);
5834 write = chunks.back().first.get();
5835 ch_traits<K>::copy(write,
data.str,
data.len);
5837 remain = blockSize -
data.len;
5844 size_t l = expr.
length();
5847 write = expr.place(write);
5848 chunks.back().second += l;
5851 }
else if (!remain) {
5852 size_t blockSize = (l + align - 1) / align * align;
5853 chunks.emplace_back(std::make_unique<K[]>(blockSize), l);
5854 write = expr.place(chunks.back().first.get());
5856 remain = blockSize - l;
5858 auto store = std::make_unique<K[]>(l);
5859 expr.place(store.get());
5866 template<
typename T>
5868 requires std::is_same_v<T, K>
5870 return operator<<(expr_char<K>(
data));
5878 if (chunks.empty()) {
5881 if (chunks.size() > 1) {
5885 remain += chunks[0].second;
5886 chunks[0].second = 0;
5888 write = chunks[0].first.get();
5891 constexpr K* place(K* p)
const noexcept {
5892 for (
const auto& block: chunks) {
5893 ch_traits<K>::copy(p, block.first.get(), block.second);
5903 template<
typename Op>
5905 for (
const auto& block: chunks)
5906 o(block.first.get(), block.second);
5912 if (chunks.size()) {
5913 const K* ptr = chunks.front().first.get();
5914 for (
const auto& chunk: chunks) {
5915 if (chunk.first.get() != ptr)
5917 ptr += chunk.second;
5927 return chunks.size() ? chunks.front().first.get() : simple_str_nt<K>::empty_str.str;
5943 typename decltype(chunks)::const_iterator it, end;
5944 size_t writedFromCurrentChunk;
5959 while (size && !
is_end()) {
5960 size_t remain = it->second - writedFromCurrentChunk;
5961 size_t write = std::min(size, remain);
5962 ch_traits<K>::copy(buffer, it->first.get() + writedFromCurrentChunk, write);
5968 writedFromCurrentChunk = 0;
5970 writedFromCurrentChunk += write;
5981 return {chunks.begin(), chunks.end(), 0};
5992using stringa = sstring<u8s>;
5993using stringw = sstring<wchar_t>;
5994using stringu = sstring<u16s>;
5995using stringuu = sstring<u32s>;
6065inline namespace literals {
6113consteval StoreType<u8s>
operator""_h(
const u8s* ptr,
size_t l) {
6114 return StoreType<u8s>{{ptr, l}, fnv_hash_compile(ptr, l)};
6123consteval StoreType<u8s>
operator""_ia(
const u8s* ptr,
size_t l) {
6124 return StoreType<u8s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
6133inline StoreType<u8s>
operator""_iu(
const u8s* ptr,
size_t l) {
6134 return StoreType<u8s>{{ptr, l}, strhashiu<u8s>{}(
simple_str<u8s>{ptr, l})};
6143consteval StoreType<u16s>
operator""_h(
const u16s* ptr,
size_t l) {
6144 return StoreType<u16s>{{ptr, l}, fnv_hash_compile(ptr, l)};
6153consteval StoreType<u16s>
operator""_ia(
const u16s* ptr,
size_t l) {
6154 return StoreType<u16s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
6163inline StoreType<u16s>
operator""_iu(
const u16s* ptr,
size_t l) {
6164 return StoreType<u16s>{{ptr, l}, strhashiu<u16s>{}(
simple_str<u16s>{ptr, l})};
6173consteval StoreType<u32s>
operator""_h(
const u32s* ptr,
size_t l) {
6174 return StoreType<u32s>{{ptr, l}, fnv_hash_compile(ptr, l)};
6183consteval StoreType<u32s>
operator""_ia(
const u32s* ptr,
size_t l) {
6184 return StoreType<u32s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
6193inline StoreType<u32s>
operator""_iu(
const u32s* ptr,
size_t l) {
6194 return StoreType<u32s>{{ptr, l}, strhashiu<u32s>{}(
simple_str<u32s>{ptr, l})};
6206 return stream << std::string_view{text.
symbols(), text.
length()};
6215inline std::wostream&
operator<<(std::wostream& stream, ssw text) {
6216 return stream << std::wstring_view{text.
symbols(), text.
length()};
6226 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
6235inline std::ostream&
operator<<(std::ostream& stream,
const stringa& text) {
6236 return stream << std::string_view{text.
symbols(), text.
length()};
6245inline std::wostream&
operator<<(std::wostream& stream,
const stringw& text) {
6246 return stream << std::wstring_view{text.
symbols(), text.
length()};
6256 return stream << std::wstring_view{from_w(text.symbols()), text.length()};
6265template<
size_t N,
bool S, simstr::Allocatorable A>
6267 return stream << std::string_view{text.
symbols(), text.
length()};
6276template<
size_t N,
bool S, simstr::Allocatorable A>
6278 return stream << std::wstring_view{text.
symbols(), text.
length()};
6287template<
size_t N,
bool S, simstr::Allocatorable A>
6289 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
6298struct std::formatter<
simstr::simple_str<K>, K> : std::formatter<std::basic_string_view<K>, K> {
6300 template<
typename FormatContext>
6302 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
6310struct std::formatter<
simstr::simple_str_nt<K>, K> : std::formatter<std::basic_string_view<K>, K> {
6312 template<
typename FormatContext>
6314 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
6322struct std::formatter<
simstr::sstring<K>, K> : std::formatter<std::basic_string_view<K>, K> {
6324 template<
typename FormatContext>
6326 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
6333template<
typename K,
size_t N,
bool S,
typename A>
6334struct std::formatter<
simstr::lstring<K, N, S, A>, K> : std::formatter<std::basic_string_view<K>, K> {
6336 template<
typename FormatContext>
6338 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
Класс для последовательного получения подстрок по заданному разделителю
Определения sstring.h:1925
simple_str< K > next()
Получить следующую подстроку
Определения sstring.h:1941
bool is_done() const
Узнать, не закончились ли подстроки
Определения sstring.h:1934
my_type & operator<<(simple_str< K > data)
Добавление порции данных
Определения sstring.h:5813
portion_store get_portion() const
Получить portion_store, черезк который можно последовательно извлекать данные во внешний буфер
Определения sstring.h:5980
constexpr size_t length() const noexcept
Длина сохранённого текста
Определения sstring.h:5873
my_type & operator<<(T data)
Добавление символа
Определения sstring.h:5867
void reset()
Сбрасывает содержимое, но при этом не удаляет первый буфер, чтобы потом избежать аллокации
Определения sstring.h:5877
void clear()
Очистить объект, освободив все выделенные буфера.
Определения sstring.h:5932
my_type & operator<<(const StrExprForType< K > auto &expr)
Добавление строкового выражения
Определения sstring.h:5843
bool is_continuous() const
Проверяет, расположен ли весь текст одним непрерывным куском в памяти
Определения sstring.h:5911
void out(const Op &o) const
Применяет функтор к каждому сохранённому буферу
Определения sstring.h:5904
const auto & data() const
Получить внутренние буфера с данными
Определения sstring.h:5987
const K * begin() const
Получить указатель на начало первого буфера. Имеет смысл применять только если is_continuous true.
Определения sstring.h:5926
Контейнер для более эффективного поиска по строковым ключам.
Определения sstring.h:5533
Класс мутабельной, владеющей строки. Содержит внутренний буфер для строк заданного размера.
Определения sstring.h:3765
lstring(const my_type &other, Args &&... args)
Копирование из другой строки такого же типа, но с другим аллокатором
Определения sstring.h:3890
lstring(const my_type &other)
Копирование из другой строки такого же типа
Определения sstring.h:3878
constexpr lstring(T &&value, Args &&... args)
Конструктор из строкового литерала
Определения sstring.h:3903
K * reserve_no_preserve(size_t newSize)
Определения sstring.h:4059
my_type & operator=(T &&other)
Оператор присваивания строкового литерала
Определения sstring.h:4010
@ LocalCapacity
Определения sstring.h:3772
my_type & operator=(my_type &&other) noexcept
Оператор присваивания перемещением из строки такого же типа
Определения sstring.h:3962
void clear()
Делает строку пустой, не меняя буфер строки.
Определения sstring.h:4146
bool is_empty() const noexcept
Пустая ли строка
Определения sstring.h:4041
void shrink_to_fit()
Уменьшает размер внешнего буфера до минимально возможного для хранения строки. Если строка уместится ...
Определения sstring.h:4132
size_t length() const noexcept
Длина строки
Определения sstring.h:4029
size_t capacity() const noexcept
Текущая ёмкость буфера строки
Определения sstring.h:4049
K * reserve(size_t newSize)
Выделить буфер, достаточный для размещения newSize символов плюс завершающий ноль.
Определения sstring.h:4076
bool empty() const noexcept
Пустая ли строка, для совместимости с std::string.
Определения sstring.h:4045
my_type & operator=(const StrExprForType< K > auto &expr)
Оператор присаивания строкового выражения
Определения sstring.h:4019
K * str() noexcept
Указатель на буфер строки
Определения sstring.h:4037
my_type & operator=(const my_type &other)
Оператор присваивания копией из строки такого же типа
Определения sstring.h:3949
lstring(const Op &op, Args &&... args)
Конструктор заполнения с помощью функтора (см. str_mutable::fill)
Определения sstring.h:3937
void reset()
Делает строку пустой и освобождает внешний буфер, если он был
Определения sstring.h:4150
const K * symbols() const noexcept
Указатель на константные символы
Определения sstring.h:4033
lstring(my_type &&other) noexcept
Конструктор перемещения из строки такого же типа
Определения sstring.h:3915
K * set_size(size_t newSize)
Устанавливает размер текущей строки, при необходимости выделяя место.
Определения sstring.h:4094
my_type & operator=(simple_str< K > other)
Оператор присваивания из simple_str.
Определения sstring.h:4001
bool is_local() const noexcept
Узнать, локальный или внешний буфер используется для символов
Определения sstring.h:4110
void define_size()
Определить длину строки. Ищет символ 0 в буфере строки до его ёмкости, после чего устаналивает длину ...
Определения sstring.h:4117
Класс иммутабельной владеющей строки
Определения sstring.h:4231
sstring(lstring< K, N, true, Allocator > &&src)
Конструктор перемещения из lstring с совместимым с sstring внешним буфером
Определения sstring.h:4377
my_type & make_empty() noexcept
Сделать строку пустой
Определения sstring.h:4488
sstring(Args &&... args)
Конструктор пустой строки
Определения sstring.h:4343
bool empty() const noexcept
for std::string compatibility
Определения sstring.h:4507
my_type & operator=(my_type other) noexcept
Оператор присвоения другой строки того же типа
Определения sstring.h:4436
my_type & operator=(simple_str< K > other)
Оператор присвоения другой строки другого типа
Определения sstring.h:4445
sstring(const my_type &other) noexcept
Конструктор копирования строки
Определения sstring.h:4356
~sstring()
Деструктор строки
Определения sstring.h:4347
static my_type format(const FmtString< K, T... > &fmtString, T &&... args)
Получить строку, отформатированную с помощью std::format
Определения sstring.h:4528
static my_type printf(const K *pattern, T &&... args)
Получить строку, отформатированную с помощью std::sprintf
Определения sstring.h:4518
my_type & operator=(lstring< K, N, true, Allocator > &&other)
Оператор присвоения перемещаемой строки типа lstring с совместимым буфером
Определения sstring.h:4472
my_type & operator=(const lstring< K, N, forShared, A > &other)
Оператор присвоения другой строки типа lstring.
Определения sstring.h:4463
bool is_empty() const noexcept
Пустая ли строка
Определения sstring.h:4503
my_type & operator=(const StrExprForType< K > auto &expr)
Оператор присвоения строкового выражения
Определения sstring.h:4481
static my_type vformat(simple_str< K > fmtString, T &&... args)
Получить строку, отформатированную с помощью std::vformat
Определения sstring.h:4538
my_type & operator=(T &&other)
Оператор присвоения строкового литерала
Определения sstring.h:4454
const K * symbols() const noexcept
Указатель на символы строки
Определения sstring.h:4495
sstring(T &&s, Args &&... args)
Инициализация из строкового литерала
Определения sstring.h:4416
size_t length() const noexcept
Длина строки
Определения sstring.h:4499
sstring(my_type &&other) noexcept
Конструктор перемещения
Определения sstring.h:4365
Класс с базовыми константными строковыми алгоритмами.
Определения sstring.h:537
bool is_ascii() const noexcept
Содержит ли строка только ASCII символы
Определения sstring.h:1457
T as_int() const noexcept
Преобразовать строку в число заданного типа
Определения sstring.h:1165
constexpr bool starts_with(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки
Определения sstring.h:1355
size_t find_end_of_last(str_piece pattern, size_t offset=-1) const noexcept
Найти конец последнего вхождения подстроки в этой строке.
Определения sstring.h:955
auto operator<=>(T &&other) const noexcept
Оператор сравнения строки и строкового литерала
Определения sstring.h:766
R lowered_only_ascii() const
Получить копию строки в нижнем регистре ASCII символов
Определения sstring.h:1499
R trimmed() const
Получить строку с удалением пробельных символов слева и справа
Определения sstring.h:1571
str_piece to_str() const noexcept
Преобразовать себя в "кусок строки", включающий всю строку
Определения sstring.h:608
size_t find_last(K s, size_t offset=-1) const noexcept
Найти последнее вхождения символа в этой строке
Определения sstring.h:1064
size_t find_or_all(K s, size_t offset=0) const noexcept
Найти символ в этой строке или конец строки.
Определения sstring.h:1009
R trimmed_left(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, слева
Определения sstring.h:1611
size_t find_last_of(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа из заданного набора символов
Определения sstring.h:1108
size_t find(str_piece pattern, size_t offset=0) const noexcept
Найти начало первого вхождения подстроки в этой строке.
Определения sstring.h:871
bool starts_with_iu(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки без учёта регистра Unicode символов первой плоскости (<0xFF...
Определения sstring.h:1389
std::tuple< T, IntConvertResult, size_t > to_int() const noexcept
Преобразовать строку в число заданного типа
Определения sstring.h:1185
R replaced(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0) const
Получить копию строки с заменёнными вхождениями подстрок
Определения sstring.h:1530
int compare_ia(str_piece text) const noexcept
Сравнение строк посимвольно без учёта регистра ASCII символов
Определения sstring.h:797
expr_replaces< K, N - 1, L - 1 > replace_init(T &&pattern, M &&repl) const
Получить строковое выражение, которое выдает строку с заменёнными подстроками, заданными строковыми л...
Определения sstring.h:1541
R uppered() const
Получить копию строки в верхнем регистре Unicode символов первой плоскости (<0xFFFF)
Определения sstring.h:1508
constexpr str_piece mid(size_t from, size_t len=-1) const noexcept
Получить часть строки как "кусок строки".
Определения sstring.h:655
std::pair< size_t, size_t > find_first_of_idx(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа из заданного набора символов
Определения sstring.h:1088
size_t find_end_of_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Найти конец последнего вхождения подстроки в этой строке или конец строки.
Определения sstring.h:975
T splitf(str_piece delimeter, const Op &beforeFunc, size_t offset=0) const
Разделить строку на части по заданному разделителю, с возможным применением функтора к каждой подстро...
Определения sstring.h:1325
void as_number(double &t)
Преобразовать строку в double.
Определения sstring.h:1245
R trimmed_right_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения sstring.h:1731
constexpr bool prefix_in(str_piece text) const noexcept
Является ли эта строка началом другой строки
Определения sstring.h:1404
int compare_iu(str_piece text) const noexcept
Сравнение строк посимвольно без учёта регистра Unicode символов первой плоскости (<0xFFFF)
Определения sstring.h:828
size_t find(K s, size_t offset=0) const noexcept
Найти символ в этой строке.
Определения sstring.h:994
size_t find_last(str_piece pattern, size_t offset=-1) const noexcept
Найти начало последнего вхождения подстроки в этой строке.
Определения sstring.h:946
bool less_iu(str_piece text) const noexcept
Меньше ли строка другой строки посимвольно без учёта регистра Unicode символов первой плоскости (<0xF...
Определения sstring.h:845
std::string_view to_sv() const noexcept
Конвертировать в std::string_view.
Определения sstring.h:615
R trimmed(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, слева и справа
Определения sstring.h:1675
R trimmed_left(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, слева
Определения sstring.h:1685
constexpr bool ends_with_iu(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой без учёта регистра Unicode символов первой плоскости (<0...
Определения sstring.h:1451
double to_double() const noexcept
Преобразовать строку в double.
Определения sstring.h:1192
bool contains(str_piece pattern, size_t offset=0) const noexcept
Содержит ли строка указанную подстроку.
Определения sstring.h:985
R uppered_only_ascii() const
Получить копию строки в верхнем регистре ASCII символов
Определения sstring.h:1490
Splitter< K > splitter(str_piece delimeter) const
Получить объект Splitter по заданному разделителю, который позволяет последовательно получать подстро...
Определения sstring.h:1965
my_type str_mid(size_t from, size_t len=-1) const
Получить часть строки объектом того же типа, к которому применён метод, аналогично mid.
Определения sstring.h:1146
R trimmed_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения sstring.h:1637
std::vector< size_t > find_all(str_piece pattern, size_t offset=0, size_t maxCount=0) const
Найти все вхождения подстроки в этой строке
Определения sstring.h:1055
R trimmed_right() const
Получить строку с удалением пробельных символов справа
Определения sstring.h:1589
R trimmed_right_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения sstring.h:1663
constexpr bool ends_with(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой
Определения sstring.h:1416
R trimmed_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения sstring.h:1707
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len=0) const noexcept
Получить часть строки как "simple_str".
Определения sstring.h:641
bool operator==(T &&other) const noexcept
Оператор сравнения строки и строкового литерала на равенство
Определения sstring.h:757
constexpr auto operator<=>(const base &other) const noexcept
Оператор сравнения строк
Определения sstring.h:749
R lowered() const
Получить копию строки в нижнем регистре Unicode символов первой плоскости (<0xFFFF)
Определения sstring.h:1517
R trimmed_right(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, справа
Определения sstring.h:1622
size_t find_or_all(str_piece pattern, size_t offset=0) const noexcept
Найти начало первого вхождения подстроки в этой строке или конец строки.
Определения sstring.h:905
bool equal_ia(str_piece text) const noexcept
Равна ли строка другой строке посимвольно без учёта регистра ASCII символов
Определения sstring.h:806
constexpr K * place(K *ptr) const noexcept
Копировать строку в указанный буфер.
Определения sstring.h:569
std::pair< size_t, size_t > find_last_of_idx(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа из заданного набора символов
Определения sstring.h:1117
R trimmed_left_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения sstring.h:1719
void copy_to(K *buffer, size_t bufSize)
Копировать строку в указанный буфер.
Определения sstring.h:583
R trimmed_right(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, справа
Определения sstring.h:1695
R trimmed_left() const
Получить строку с удалением пробельных символов слева
Определения sstring.h:1580
size_t find_end_or_all(str_piece pattern, size_t offset=0) const noexcept
Найти конец первого вхождения подстроки в этой строке или конец строки.
Определения sstring.h:915
constexpr int compare(str_piece o) const
Сравнение строк посимвольно
Определения sstring.h:700
K at(ptrdiff_t idx) const
Получить символ на заданной позиции
Определения sstring.h:686
std::string to_string() const noexcept
Конвертировать в std::string.
Определения sstring.h:622
constexpr int strcmp(const K *text) const
Сравнение с C-строкой посимвольно
Определения sstring.h:708
size_t find_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Найти начало последнего вхождения подстроки в этой строке или конец строки.
Определения sstring.h:965
R trimmed_left_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения sstring.h:1650
void as_number(T &t)
Преобразовать строку в целое число
Определения sstring.h:1238
void for_all_finded(const Op &op, str_piece pattern, size_t offset=0, size_t maxCount=0) const
Вызвать функтор для всех найденных вхождений подстроки в этой строке
Определения sstring.h:1039
size_t find_or_throw(str_piece pattern, size_t offset=0, Args &&... args) const noexcept
Найти начало первого вхождения подстроки в этой строке или выкинуть исключение.
Определения sstring.h:883
bool operator!() const noexcept
Проверка на пустоту
Определения sstring.h:677
size_t find_last_not_of(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа не из заданного набора символов
Определения sstring.h:1128
size_t find_first_not_of(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа не из заданного набора символов
Определения sstring.h:1099
bool equal_iu(str_piece text) const noexcept
Равна ли строка другой строке посимвольно без учёта регистра Unicode символов первой плоскости (<0xFF...
Определения sstring.h:837
constexpr bool ends_with_ia(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой без учёта регистра ASCII символов
Определения sstring.h:1439
my_type substr(ptrdiff_t from, ptrdiff_t len=0) const
Получить подстроку. Работает аналогично operator(), только результат выдает того же типа,...
Определения sstring.h:1137
T split(str_piece delimeter, size_t offset=0) const
Разделить строку на подстроки по заданному разделителю
Определения sstring.h:1336
size_t find_end(str_piece pattern, size_t offset=0) const noexcept
Найти конец вхождения подстроки в этой строке.
Определения sstring.h:895
constexpr bool operator==(const base &other) const noexcept
Оператор сравнение строк на равенство
Определения sstring.h:742
size_t size() const
Размер строки в символах.
Определения sstring.h:593
R trimmed(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, слева и справа
Определения sstring.h:1600
constexpr bool equal(str_piece other) const noexcept
Сравнение строк на равенство
Определения sstring.h:734
size_t find_first_of(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа из заданного набора символов
Определения sstring.h:1079
bool less_ia(str_piece text) const noexcept
Меньше ли строка другой строки посимвольно без учёта регистра ASCII символов
Определения sstring.h:814
constexpr str_piece from_to(size_t from, size_t to) const noexcept
Получить подстроку simple_str с позиции от from до позиции to (не включая её)
Определения sstring.h:671
constexpr bool starts_with_ia(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки без учёта регистра ASCII символов
Определения sstring.h:1378
Базовый класс работы с изменяемыми строками
Определения sstring.h:2769
Impl & insert(size_t to, const A &expr)
Вставить строковое выражение в указанную позицию
Определения sstring.h:3202
Impl & operator<<=(const Op &fillFunction)
Заполняет строку методом fill после конца строки
Определения sstring.h:3437
Impl & append(const A &expr)
Добавить строковое выражение в конец строки
Определения sstring.h:3122
Impl & operator<<(const Op &fillFunction)
Вызывает переданный функтор, передав ссылку на себя
Определения sstring.h:3447
Impl & trim(str_piece pattern)
Удалить символы, входящие в переданную строку, в начале и в конце строки.
Определения sstring.h:2967
Impl & upper_only_ascii()
Преобразовать в верхний регистр ASCII символы
Определения sstring.h:3014
Impl & lower_only_ascii()
Преобразовать в нижний регистр ASCII символы
Определения sstring.h:3027
Impl & trim_left()
Удалить пробельные символы в начале строки
Определения sstring.h:2892
Impl & append_printf(const K *format, T &&... args)
Добавляет отформатированный с помощью sprintf вывод в конец строки
Определения sstring.h:3515
Impl & trim_right_with_wpaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в конце строки.
Определения sstring.h:2959
Impl & trim_left(str_piece pattern)
Удалить символы, входящие в переданную строку, в начале строки.
Определения sstring.h:2975
Impl & trim_with_spaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в начале и в конце строки.
Определения sstring.h:2939
Impl & prepend(str_piece other)
Добавить другую строку в начало строки
Определения sstring.h:3219
Impl & printf(const K *format, T &&... args)
Форматирует строку помощью sprintf.
Определения sstring.h:3504
Impl & with(const Op &fillFunction, Args &&... args)
Вызов функтора со строкой и переданными аргументами
Определения sstring.h:3685
Impl & append_vformatted_n(size_t max_write, str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод в конец строки, записывая не более указанног...
Определения sstring.h:3675
Impl & operator<<(const Op &fillFunction)
Заполняет строку методом fill с нулевой позиции
Определения sstring.h:3427
Impl & vformat(str_piece format, T &&... args)
Форматирует строку с помощью std::vformat.
Определения sstring.h:3640
Impl & change(size_t from, size_t len, const A &expr)
Заменить кусок строки на строковое выражение
Определения sstring.h:3183
Impl & fill(size_t from, const Op &fillFunction)
Заполнение буфера строки с помощью функтора
Определения sstring.h:3402
Impl & change(size_t from, size_t len, str_piece other)
Заменить кусок строки на другую строку
Определения sstring.h:3172
Impl & remove(size_t from, size_t len)
Удалить часть строку
Определения sstring.h:3211
Impl & trim_left_with_spaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в начале строки.
Определения sstring.h:2949
Impl & trim_left(T &&pattern)
Удалить символы, входящие в строковый литерал, в начале строки.
Определения sstring.h:2919
Impl & trim_right(T &&pattern)
Удалить символы, входящие в строковый литерал, в конце строки.
Определения sstring.h:2929
Impl & trim_right_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в конце строки.
Определения sstring.h:3007
Impl & append_in(size_t pos, str_piece other)
Добавить другую строку, начиная с заданной позиции
Определения sstring.h:3150
Impl & vformat_from(size_t from, size_t max_write, str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод, начиная с указанной позиции
Определения sstring.h:3588
Impl & trim_left_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в начале строки.
Определения sstring.h:2999
Impl & insert(size_t to, str_piece other)
Вставить строку в указанную позицию
Определения sstring.h:3192
Impl & vformat_n(size_t max_write, str_piece format, T &&... args)
Форматирует строку с помощью std::vformat не более указанного размера
Определения sstring.h:3663
my_type & format(const FmtString< K, T... > &pattern, T &&... args)
Определения sstring.h:3618
Impl & printf_from(size_t from, const K *format, T &&... args)
Добавляет отформатированный с помощью sprintf вывод, начиная с указанной позиции
Определения sstring.h:3460
Impl & operator+=(str_piece other)
Добавить другую строку в конец строки
Определения sstring.h:3130
Impl & trim_right()
Удалить пробельные символы в конце строки
Определения sstring.h:2899
Impl & append(str_piece other)
Добавить другую строку в конец строки
Определения sstring.h:3113
Impl & trim_right(str_piece pattern)
Удалить символы, входящие в переданную строку, в конце строки.
Определения sstring.h:2983
Impl & trim_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в начале и в конце строки.
Определения sstring.h:2991
K * str() noexcept
Получить указатель на буфер строки
Определения sstring.h:2871
my_type & format_from(size_t from, const FmtString< K, T... > &format, T &&... args)
Определения sstring.h:3566
Impl & prepend(const A &expr)
Добавить строковое выражение в начало строки
Определения sstring.h:3228
Impl & trim()
Удалить пробельные символы в начале и в конце строки
Определения sstring.h:2885
Impl & lower()
Преобразовать в нижний регистр Unicode символы первой плоскости (<0xFFFF).
Определения sstring.h:3052
Impl & replace(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Заменить вхождения подстроки на другую строку
Определения sstring.h:3239
Impl & upper()
Преобразовать в верхний регистр Unicode символы первой плоскости (<0xFFFF).
Определения sstring.h:3042
Impl & replace_from(const From &f, str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Скопировать строку-источник, заменив вхождения подстрок на другую строку
Определения sstring.h:3351
Impl & append_vformatted(str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод в конец строки
Определения sstring.h:3651
Impl & append_formatted(const FmtString< K, T... > &format, T &&... args)
Добавляет отформатированный с помощью std::format вывод в конец строки
Определения sstring.h:3629
Impl & append_in(size_t pos, const A &expr)
Добавить строковое выражение, начиная с заданной позиции
Определения sstring.h:3162
Impl & trim(T &&pattern)
Удалить символы, входящие в строковый литерал, в начале и в конце строки.
Определения sstring.h:2909
Impl & operator+=(const A &expr)
Добавить строковое выражение в конец строки
Определения sstring.h:3139
constexpr str_storable(s_str other, Args &&... args)
Конструктор из другого строкового объекта
Определения sstring.h:2437
constexpr str_storable(size_t repeat, s_str pattern, Args &&... args)
Конструктор повторения строки
Определения sstring.h:2453
allocator_t & allocator()
Получить аллокатор
Определения sstring.h:2327
static my_type uppered_from(const From &f, Args &&... args)
Создать копию переданной строки в верхнем регистре символов Unicode первой плоскости (<0xFFFF)
Определения sstring.h:2665
constexpr str_storable(const StrExprForType< K > auto &expr, Args &&... args)
Конструктор из строкового выражения
Определения sstring.h:2491
static my_type lowered_from(const From &f, Args &&... args)
Создать копию переданной строки в нижнем регистре символов Unicode первой плоскости (<0xFFFF)
Определения sstring.h:2677
s_str_nt to_nts(size_t from=0) const
Получить simple_str_nt, начиная с заданного символа
Определения sstring.h:2559
static my_type uppered_only_ascii_from(const From &f, Args &&... args)
Создать строку, копию переданной в верхнем регистре символов ASCII.
Определения sstring.h:2643
constexpr str_storable(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Создать пустой объект
Определения sstring.h:2425
static my_type lowered_only_ascii_from(const From &f, Args &&... args)
Создать копию переданной строки в нижнем регистре символов ASCII.
Определения sstring.h:2653
static my_type join(const T &strings, s_str delimeter, bool tail=false, bool skip_empty=false, Args &&... args)
Конкатенация строк из контейнера в одну строку
Определения sstring.h:2595
static my_type replaced_from(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Создать копию переданной строки с заменой подстрок
Определения sstring.h:2691
str_storable(size_t count, K pad, Args &&... args)
Конструктор повторения символа
Определения sstring.h:2473
str_storable(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Конструктор из строкового источника с заменой
Определения sstring.h:2509
Концепт типа, управляющего памятью
Определения sstring.h:2700
Концепт строкового выражения заданного типа символов
Определения strexpr.h:242
Концепт типа, который не может модифицировать хранимую строку
Определения sstring.h:2288
Концепт типа, который может модифицировать хранимую строку
Определения sstring.h:2282
Концепт типа, который может сохранить строку
Определения sstring.h:2273
constexpr auto e_repl(simple_str< K > w, T &&p, X &&r)
Получить строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки
Определения sstring.h:4880
constexpr auto e_real(double t)
Преобразование double числа в строковое выражение
Определения sstring.h:4731
constexpr auto e_num(T t)
Преобразование целого числа в строковое выражение
Определения sstring.h:4659
constexpr auto operator+(const A &a, T s)
Оператор конкатенации для строкового выражения и целого числа.
Определения sstring.h:4633
auto e_repl_const_symbols(simple_str< K > src, Repl &&... other)
Возвращает строковое выражение, генерирующее строку, в которой заданные символы заменены на заданные ...
Определения sstring.h:5393
constexpr auto e_join(const T &s, L &&d)
Получить строковое выражение, конкатенирующее строки в контейнере в одну строку с заданным разделител...
Определения sstring.h:4796
Пространство имён для объектов библиотеки
Определения sstring.cpp:10
hashStrMap< u16s, T, strhash< u16s >, streql< u16s > > hashStrMapU
Тип хеш-словаря для char16_t строк, регистрозависимый поиск
Определения sstring.h:6035
hashStrMap< u8s, T, strhashia< u8s >, streqlia< u8s > > hashStrMapAIA
Тип хеш-словаря для char строк, регистронезависимый поиск для ASCII символов
Определения sstring.h:6006
IntConvertResult
Перечисление с возможными результатами преобразования строки в целое число
Определения sstring.h:236
@ Overflow
Переполнение, число не помещается в заданный тип
Определения sstring.h:239
@ Success
Успешно
Определения sstring.h:237
@ NotNumber
Вообще не число
Определения sstring.h:240
@ BadSymbolAtTail
Число закончилось не числовым символом
Определения sstring.h:238
hashStrMap< u32s, T, strhashiu< u32s >, streqliu< u32s > > hashStrMapUUIU
Тип хеш-словаря для char32_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:6061
hashStrMap< u32s, T, strhashia< u32s >, streqlia< u32s > > hashStrMapUUIA
Тип хеш-словаря для char32_t строк, регистронезависимый поиск для ASCII символов
Определения sstring.h:6056
hashStrMap< wchar_t, T, strhashiu< wchar_t >, streqliu< wchar_t > > hashStrMapWIU
Тип хеш-словаря для wchar_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:6029
hashStrMap< wchar_t, T, strhashia< wchar_t >, streqlia< wchar_t > > hashStrMapWIA
Тип хеш-словаря для wchar_t строк, регистронезависимый поиск для ASCII символов
Определения sstring.h:6023
hashStrMap< u8s, T, strhash< u8s >, streql< u8s > > hashStrMapA
Тип хеш-словаря для char строк, регистрозависимый поиск
Определения sstring.h:6001
auto e_utf(simple_str< From > from)
Возвращает строковое выражение, преобразующую строку из одного типа символов в другой тип,...
Определения sstring.h:2265
hashStrMap< u16s, T, strhashiu< u16s >, streqliu< u16s > > hashStrMapUIU
Тип хеш-словаря для char16_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:6045
hashStrMap< u16s, T, strhashia< u16s >, streqlia< u16s > > hashStrMapUIA
Тип хеш-словаря для char16_t строк, регистронезависимый поиск для ASCII символов
Определения sstring.h:6040
hashStrMap< wchar_t, T, strhash< wchar_t >, streql< wchar_t > > hashStrMapW
Тип хеш-словаря для wchar_t строк, регистрозависимый поиск
Определения sstring.h:6017
hashStrMap< u8s, T, strhashiu< u8s >, streqliu< u8s > > hashStrMapAIU
Тип хеш-словаря для char строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:6011
hashStrMap< u32s, T, strhash< u32s >, streql< u32s > > hashStrMapUU
Тип хеш-словаря для char32_t строк, регистрозависимый поиск
Определения sstring.h:6051
Объект, позволяющий последовательно копировать содержимое в буфер заданного размера
Определения sstring.h:5942
bool is_end()
Проверить, что данные ещё не кончились
Определения sstring.h:5948
size_t store(K *buffer, size_t size)
Сохранить очередную порцию данных в буфер
Определения sstring.h:5957
constexpr expr_replace_symbols(simple_str< K > source, const std::vector< std::pair< K, simple_str< K > > > &repl)
Конструктор выражения
Определения sstring.h:5032
constexpr expr_replaced(simple_str< K > w, simple_str< K > p, simple_str< K > r)
Конструктор
Определения sstring.h:4909
Строковое выражение для конвертации строк в разные виды UTF.
Определения sstring.h:2243
Класс, заявляющий, что ссылается на нуль-терминированную строку.
Определения sstring.h:1855
constexpr simple_str_nt(S &&s) noexcept
Конструктор, позволяющий инициализировать объектами std::string, и std::string_view при условии,...
Определения sstring.h:1885
my_type to_nts(size_t from)
Получить нуль-терминированную строку, сдвинув начало на заданное количество символов
Определения sstring.h:1900
simple_str_nt(T &&p) noexcept
Явный конструктор из С-строки.
Определения sstring.h:1874
Простейший класс иммутабельной не владеющей строки.
Определения sstring.h:1756
constexpr simple_str(T &&v) noexcept
Конструктор из строкового литерала.
Определения sstring.h:1769
bool is_part_of(simple_str< K > other) const noexcept
Проверить, не является ли строка частью другой строки
Определения sstring.h:1811
my_type & remove_prefix(size_t delta)
Сдвигает начало строки на заданное количество символов
Определения sstring.h:1827
constexpr size_t length() const noexcept
Получить длину строки
Определения sstring.h:1785
constexpr const symb_type * symbols() const noexcept
Получить указатель на константный буфер с символами строки
Определения sstring.h:1791
constexpr simple_str(const K *p, size_t l) noexcept
Конструктор из указателя и длины
Определения sstring.h:1773
constexpr bool is_empty() const noexcept
Проверить, не пуста ли строка
Определения sstring.h:1797
constexpr simple_str(S &&s) noexcept
Конструктор, позволяющий инициализировать объектами std::string, и std::string_view при условии,...
Определения sstring.h:1781
K operator[](size_t idx) const
Получить символ из указанной позиции. Проверка границ не выполняется.
Определения sstring.h:1819
my_type & remove_suffix(size_t delta)
Укорачивает строку на заданное количество символов
Определения sstring.h:1837
bool is_same(simple_str< K > other) const noexcept
Проверить, не указывают ли два объекта на одну строку
Определения sstring.h:1804
Конкатенация ссылки на строковое выражение и значения строкового выражения
Определения strexpr.h:311