22#ifndef __has_declspec_attribute
23#define __has_declspec_attribute(x) 0
25const bool isWindowsOs =
33#ifdef SIMSTR_IN_SHARED
34 #if defined(_MSC_VER) || (defined(__clang__) && __has_declspec_attribute(dllexport))
36 #define SIMSTR_API __declspec(dllexport)
38 #define SIMSTR_API __declspec(dllimport)
40 #elif (defined(__GNUC__) || defined(__GNUG__)) && defined(SIMSTR_EXPORT)
41 #define SIMSTR_API __attribute__((visibility("default")))
53#include <unordered_map>
66#pragma warning(disable : 4201)
72struct unicode_traits {};
75struct unicode_traits<u8s> {
90 static SIMSTR_API
size_t upper(
const u8s*& src,
size_t lenStr, u8s*& dest,
size_t lenBuf);
91 static SIMSTR_API
size_t lower(
const u8s*& src,
size_t len, u8s*& dest,
size_t lenBuf);
93 static SIMSTR_API
int compareiu(
const u8s* text1,
size_t len1,
const u8s* text2,
size_t len2);
95 static SIMSTR_API
size_t hashia(
const u8s* src,
size_t l);
96 static SIMSTR_API
size_t hashiu(
const u8s* src,
size_t l);
100struct unicode_traits<u16s> {
101 static SIMSTR_API
void upper(
const u16s* src,
size_t len, u16s* dest);
102 static SIMSTR_API
void lower(
const u16s* src,
size_t len, u16s* dest);
104 static SIMSTR_API
int compareiu(
const u16s* text1,
size_t len1,
const u16s* text2,
size_t len2);
105 static SIMSTR_API
size_t hashia(
const u16s* src,
size_t l);
106 static SIMSTR_API
size_t hashiu(
const u16s* src,
size_t l);
110struct unicode_traits<u32s> {
111 static SIMSTR_API
void upper(
const u32s* src,
size_t len, u32s* dest);
112 static SIMSTR_API
void lower(
const u32s* src,
size_t len, u32s* dest);
114 static SIMSTR_API
int compareiu(
const u32s* text1,
size_t len1,
const u32s* text2,
size_t len2);
115 static SIMSTR_API
size_t hashia(
const u32s* src,
size_t s);
116 static SIMSTR_API
size_t hashiu(
const u32s* src,
size_t s);
120struct unicode_traits<wchar_t> {
121 static void upper(
const wchar_t* src,
size_t len,
wchar_t* dest) {
122 unicode_traits<wchar_type>::upper(to_w(src), len, to_w(dest));
124 static void lower(
const wchar_t* src,
size_t len,
wchar_t* dest) {
125 unicode_traits<wchar_type>::lower(to_w(src), len, to_w(dest));
128 static int compareiu(
const wchar_t* text1,
size_t len1,
const wchar_t* text2,
size_t len2) {
129 return unicode_traits<wchar_type>::compareiu(to_w(text1), len1, to_w(text2), len2);
131 static size_t hashia(
const wchar_t* src,
size_t s) {
132 return unicode_traits<wchar_type>::hashia(to_w(src), s);
134 static size_t hashiu(
const wchar_t* src,
size_t s) {
135 return unicode_traits<wchar_type>::hashiu(to_w(src), s);
140#if defined(_MSC_VER) && _MSC_VER <= 1933
141template<
typename K,
typename... Args>
142using FmtString = std::_Basic_format_string<K, std::type_identity_t<Args>...>;
143#elif __clang_major__ >= 15 || _MSC_VER > 1933 || __GNUC__ >= 13
144template<
typename K,
typename... Args>
145using FmtString = std::basic_format_string<K, std::type_identity_t<Args>...>;
147template<
typename K,
typename... Args>
148using FmtString = std::basic_string_view<K>;
152SIMSTR_API std::optional<double> impl_to_double(
const K* start,
const K* end);
166template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
167class str_algs :
public str_src_algs<K, StrRef, Impl, Mutable> {
168 constexpr const Impl& d()
const noexcept {
169 return *
static_cast<const Impl*
>(
this);
171 constexpr size_t _len()
const noexcept {
174 constexpr const K* _str()
const noexcept {
175 return d().symbols();
177 constexpr bool _is_empty()
const noexcept {
178 return d().is_empty();
183 using str_piece = StrRef;
184 using traits = ch_traits<K>;
185 using uni = unicode_traits<K>;
186 using uns_type = std::make_unsigned_t<K>;
187 using my_type = Impl;
188 using base = str_src_algs<K, StrRef, Impl, Mutable>;
189 str_algs() =
default;
191 int compare_iu(
const K* text,
size_t len)
const noexcept {
193 return _is_empty() ? 0 : 1;
194 return uni::compareiu(_str(), _len(), text, len);
205 return compare_iu(text.symbols(), text.length());
216 return text.length() == _len() && compare_iu(text.symbols(), text.length()) == 0;
227 return compare_iu(text.symbols(), text.length()) < 0;
231 bool starts_with_iu(
const K* prefix,
size_t len)
const noexcept {
232 return _len() >= len && 0 == uni::compareiu(_str(), len, prefix, len);
241 return starts_with_iu(prefix.symbols(), prefix.length());
245 constexpr bool ends_with_iu(
const K* suffix,
size_t len)
const noexcept {
246 size_t myLen = _len();
247 return myLen >= len && 0 == uni::compareiu(_str() + myLen - len, len, suffix, len);
256 return ends_with_iu(suffix.symbols(), suffix.length());
266 template<
typename R = my_type>
268 return R::upperred_from(d());
278 template<
typename R = my_type>
280 return R::lowered_from(d());
288 template<
bool SkipWS = true,
bool AllowPlus = true>
291 const K* ptr = _str();
292 if constexpr (SkipWS) {
293 while (len && uns_type(*ptr) <=
' ') {
298 if constexpr (AllowPlus) {
299 if (len && *ptr == K(
'+')) {
308 if constexpr(
sizeof(K) == 1) {
310 if (std::from_chars(ptr, ptr + len, d).ec == std::errc{}) {
316 if constexpr (
sizeof(K) == 1) {
317 return impl_to_double((
const char*)ptr, (
const char*)ptr + len);
318 }
else if constexpr (
sizeof(K) == 2) {
319 return impl_to_double((
const char16_t*)ptr, (
const char16_t*)ptr + len);
321 return impl_to_double((
const char32_t*)ptr, (
const char32_t*)ptr + len);
332 t = res ? *res : std::nan(
"0");
346 template<ToIntNumber T>
374struct simple_str : str_algs<K, simple_str<K>, simple_str<K>, false> {
376 using my_type = simple_str<K>;
378 const symb_type* str;
381 constexpr simple_str() =
default;
383 constexpr simple_str(
str_src<K> src) : str(src.str), len(src.len){}
389 template<typename T, size_t N = const_lit_for<K, T>::Count>
395 constexpr simple_str(
const K* p,
size_t l) noexcept : str(p), len(l) {}
401 constexpr simple_str(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : str(s.data()), len(s.length()) {}
406 constexpr simple_str(
const std::basic_string_view<K, std::char_traits<K>>& s) noexcept : str(s.data()), len(s.length()) {}
411 constexpr size_t length() const noexcept {
418 constexpr const symb_type*
symbols() const noexcept {
434 constexpr bool is_same(simple_str<K> other)
const noexcept {
435 return str == other.str && len == other.len;
443 constexpr bool is_part_of(simple_str<K> other)
const noexcept {
444 return str >= other.str && str + len <= other.str + other.len;
485struct simple_str_selector {
486 using type = simple_str<K>;
510struct simple_str_nt : simple_str<K>, null_terminated<K, simple_str_nt<K>> {
512 using my_type = simple_str_nt<K>;
513 using base = simple_str<K>;
515 constexpr static const K empty_string[1] = {0};
517 simple_str_nt() =
default;
534 template<
typename T>
requires is_one_of_type<std::remove_cvref_t<T>,
const K*, K*>::value
537 base::str = base::len ? p : empty_string;
543 template<typename T, size_t N = const_lit_for<K, T>::Count>
552 template<StrType<K> T>
555 base::len = t.length();
562 constexpr simple_str_nt(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : base(s) {}
564 static const my_type empty_str;
574 if (from > base::len) {
577 return {base::str + from, base::len - from};
582inline const simple_str_nt<K> simple_str_nt<K>::empty_str{simple_str_nt<K>::empty_string, 0};
598template<
typename Src,
typename Dest>
599struct utf_convert_selector;
602struct utf_convert_selector<u8s, u16s> {
603 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
604 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u16s* dest);
608struct utf_convert_selector<u8s, u32s> {
609 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
610 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u32s* dest);
614struct utf_convert_selector<u8s, wchar_t> {
615 static size_t need_len(
const u8s* src,
size_t srcLen) {
616 return utf_convert_selector<u8s, wchar_type>::need_len(src, srcLen);
618 static size_t convert(
const u8s* src,
size_t srcLen,
wchar_t* dest) {
619 return utf_convert_selector<u8s, wchar_type>::convert(src, srcLen, to_w(dest));
624struct utf_convert_selector<u16s, u8s> {
625 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
626 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u8s* dest);
630struct utf_convert_selector<u16s, u32s> {
631 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
632 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u32s* dest);
636struct utf_convert_selector<u16s, u16s> {
639 static size_t need_len(
const u16s* src,
size_t srcLen) {
642 static size_t convert(
const u16s* src,
size_t srcLen, u16s* dest) {
643 ch_traits<u16s>::copy(dest, src, srcLen + 1);
649struct utf_convert_selector<u32s, u32s> {
652 static size_t need_len(
const u32s* src,
size_t srcLen) {
655 static size_t convert(
const u32s* src,
size_t srcLen, u32s* dest) {
656 ch_traits<u32s>::copy(dest, src, srcLen + 1);
662struct utf_convert_selector<u16s, wchar_t> {
663 static size_t need_len(
const u16s* src,
size_t srcLen) {
664 return utf_convert_selector<u16s, wchar_type>::need_len(src, srcLen);
666 static size_t convert(
const u16s* src,
size_t srcLen,
wchar_t* dest) {
667 return utf_convert_selector<u16s, wchar_type>::convert(src, srcLen, to_w(dest));
672struct utf_convert_selector<u32s, u8s> {
673 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
674 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u8s* dest);
678struct utf_convert_selector<u32s, u16s> {
679 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
680 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u16s* dest);
684struct utf_convert_selector<u32s, wchar_t> {
685 static size_t need_len(
const u32s* src,
size_t srcLen) {
686 return utf_convert_selector<u32s, wchar_type>::need_len(src, srcLen);
688 static size_t convert(
const u32s* src,
size_t srcLen,
wchar_t* dest) {
689 return utf_convert_selector<u32s, wchar_type>::convert(src, srcLen, to_w(dest));
694struct utf_convert_selector<wchar_t, u8s> {
695 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
696 return utf_convert_selector<wchar_type, u8s>::need_len(to_w(src), srcLen);
698 static size_t convert(
const wchar_t* src,
size_t srcLen, u8s* dest) {
699 return utf_convert_selector<wchar_type, u8s>::convert(to_w(src), srcLen, dest);
704struct utf_convert_selector<wchar_t, u16s> {
705 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
706 return utf_convert_selector<wchar_type, u16s>::need_len(to_w(src), srcLen);
708 static size_t convert(
const wchar_t* src,
size_t srcLen, u16s* dest) {
709 return utf_convert_selector<wchar_type, u16s>::convert(to_w(src), srcLen, dest);
714struct utf_convert_selector<wchar_t, u32s> {
715 static size_t need_len(
const wchar_t* src,
size_t srcLen) {
716 return utf_convert_selector<wchar_type, u32s>::need_len(to_w(src), srcLen);
718 static size_t convert(
const wchar_t* src,
size_t srcLen, u32s* dest) {
719 return utf_convert_selector<wchar_type, u32s>::convert(to_w(src), srcLen, dest);
724struct utf_convert_selector<u8s, ubs> {
725 static size_t need_len(
const u8s* src,
size_t srcLen) {
728 static size_t convert(
const u8s* src,
size_t srcLen, ubs* dest) {
729 ch_traits<u8s>::copy((u8s*)dest, src, srcLen);
735struct utf_convert_selector<ubs, u8s> {
736 static size_t need_len(
const ubs* src,
size_t srcLen) {
739 static size_t convert(
const ubs* src,
size_t srcLen, u8s* dest) {
740 ch_traits<u8s>::copy(dest, (
const u8s*)src, srcLen);
759template<
typename K,
typename Impl>
760class from_utf_convertible {
762 from_utf_convertible() =
default;
763 using my_type = Impl;
771 requires(!std::is_same_v<O, K>)
773 using worker = utf_convert_selector<O, K>;
774 Impl* d =
static_cast<Impl*
>(
this);
775 size_t len = init.
length();
779 size_t need = worker::need_len(init.
symbols(), len);
780 K*
str = d->init(need);
795template<
typename From,
typename To>
requires (!std::is_same_v<From, To>)
797 using symb_type = To;
798 using worker = utf_convert_selector<From, To>;
804 size_t length()
const noexcept {
805 return worker::need_len(source_.symbols(), source_.length());
807 To* place(To* ptr)
const noexcept {
808 return ptr + worker::convert(source_.symbols(), source_.length(), ptr);
824template<
typename To,
typename From>
requires (!std::is_same_v<From, To>)
833template<
typename A,
typename K>
835 A::is_str_storable ==
true;
836 std::is_same_v<typename A::symb_type, K>;
843template<
typename A,
typename K>
850template<
typename A,
typename K>
895template<
typename K,
typename Impl,
typename Allocator>
898 using my_type = Impl;
899 using traits = ch_traits<K>;
900 using allocator_t = Allocator;
910 return *
static_cast<Allocator*
>(
this);
912 constexpr const allocator_t&
allocator()
const {
913 return *
static_cast<const Allocator*
>(
this);
916 using uni = unicode_traits<K>;
918 constexpr Impl& d() noexcept {
919 return *
static_cast<Impl*
>(
this);
921 constexpr const Impl& d() const noexcept {
922 return *
static_cast<const Impl*
>(
this);
931 template<
typename... Args>
932 explicit constexpr str_storable(Args&&... args) : Allocator(std::forward<Args>(args)...) {}
942 K* ptr = d().init(other.
length());
957 size_t l = pattern.
length(), allLen = l * repeat;
959 K* ptr = d().init(allLen);
960 for (
size_t i = 0; i < repeat; i++) {
961 traits::copy(ptr, pattern.
symbols(), l);
978 K*
str = d().init(count);
979 traits::assign(
str, count, pad);
996 template<StrExprForType<K> A>
998 size_t len = expr.length();
1000 *expr.place((
typename A::symb_type*)d().init(len)) = 0;
1018 template<StrType<K> From>
1019 void init_replaced(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0) {
1020 auto findes = f.find_all(pattern, offset, maxCount);
1021 if (!findes.size()) {
1022 new (
this) my_type{f};
1025 size_t srcLen = f.length();
1026 size_t newSize = srcLen +
static_cast<ptrdiff_t
>(repl.len - pattern.len) * findes.size();
1029 new (
this) my_type{};
1033 K* ptr = d().init(newSize);
1034 const K* src = f.symbols();
1036 for (
const auto& s: findes) {
1037 size_t copyLen = s - from;
1039 traits::copy(ptr, src + from, copyLen);
1043 traits::copy(ptr, repl.str, repl.len);
1046 from = s + pattern.len;
1050 traits::copy(ptr, src + from, srcLen);
1056 template<StrType<K> From,
typename Op1,
typename... Args>
1057 requires std::is_constructible_v<allocator_t, Args...>
1058 static my_type changeCaseAscii(
const From& f,
const Op1& opMakeNeedCase, Args&&... args) {
1059 my_type result{std::forward<Args>(args)...};
1060 size_t len = f.length();
1062 const K* source = f.symbols();
1063 K* destination = result.init(len);
1064 for (
size_t l = 0; l < len; l++) {
1065 destination[l] = opMakeNeedCase(source[l]);
1074 template<
typename T,
bool Dummy = true>
1076 template<
typename From,
typename Op1,
typename... Args>
1077 requires std::is_constructible_v<allocator_t, Args...>
1078 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
1079 my_type result{std::forward<Args>(args)...};
1080 size_t len = f.length();
1082 opChangeCase(f.symbols(), len, result.init(len));
1089 template<
bool Dummy>
1090 struct ChangeCase<u8s, Dummy> {
1091 template<
typename From,
typename Op1,
typename... Args>
1092 requires std::is_constructible_v<allocator_t, Args...>
1093 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
1094 my_type result{std::forward<Args>(args)...};
1096 size_t len = f.length();
1098 const K* ptr = f.symbols();
1099 K* pWrite = result.init(len);
1101 const u8s* source = ptr;
1103 size_t newLen = opChangeCase(source, len, dest, len);
1107 result.set_size(newLen);
1108 }
else if (newLen > len) {
1111 size_t readed =
static_cast<size_t>(source - ptr);
1112 size_t writed =
static_cast<size_t>(dest - pWrite);
1113 pWrite = result.set_size(newLen);
1114 dest = pWrite + writed;
1115 opChangeCase(source, len - readed, dest, newLen - writed);
1125 inline static constexpr bool is_str_storable =
true;
1132 constexpr operator const K*()
const noexcept {
1133 return d().symbols();
1143 constexpr s_str_nt
to_nts(
size_t from = 0)
const {
1144 size_t len = d().
length();
1148 return {d().symbols() + from, len - from};
1156 constexpr operator s_str_nt()
const {
1157 return {d().symbols(), d().length()};
1197 template<
typename T,
typename... Args>
1198 requires std::is_constructible_v<allocator_t, Args...>
1199 static my_type
join(
const T& strings, s_str delimiter,
bool tail =
false,
bool skip_empty =
false, Args&&... args) {
1200 my_type result(std::forward<Args>(args)...);
1201 if (strings.size()) {
1202 if (strings.size() == 1 && (!delimiter.
length() || !tail)) {
1203 result = strings.front();
1205 size_t commonLen = 0;
1206 for (
const auto& t: strings) {
1207 size_t len = t.length();
1208 if (len > 0 || !skip_empty) {
1209 if (commonLen > 0) {
1210 commonLen += delimiter.len;
1215 commonLen += (tail && delimiter.len > 0 && (commonLen > 0 || (!skip_empty && strings.size() > 0))? delimiter.len : 0);
1217 K* ptr = result.init(commonLen);
1219 for (
const auto& t: strings) {
1220 size_t copyLen = t.length();
1221 if (delimiter.len > 0 && write != ptr && (copyLen || !skip_empty)) {
1222 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1223 write += delimiter.len;
1225 ch_traits<K>::copy(write, t.symbols(), copyLen);
1228 if (delimiter.len > 0 && tail && (write != ptr || (!skip_empty && strings.size() > 0))) {
1229 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1230 write += delimiter.len;
1234 result.create_empty();
1248 template<StrType<K> From,
typename... Args>
1249 requires std::is_constructible_v<allocator_t, Args...>
1251 return changeCaseAscii(f, makeAsciiUpper<K>, std::forward<Args>(args)...);
1261 template<StrType<K> From,
typename... Args>
1262 requires std::is_constructible_v<allocator_t, Args...>
1264 return changeCaseAscii(f, makeAsciiLower<K>, std::forward<Args>(args)...);
1278 template<StrType<K> From,
typename... Args>
1279 requires std::is_constructible_v<allocator_t, Args...>
1281 return ChangeCase<K>::changeCase(f, uni::upper, std::forward<Args>(args)...);
1295 template<StrType<K> From,
typename... Args>
1296 requires std::is_constructible_v<allocator_t, Args...>
1298 return ChangeCase<K>::changeCase(f, uni::lower, std::forward<Args>(args)...);
1316 template<StrType<K> From,
typename... Args>
1317 requires std::is_constructible_v<allocator_t, Args...>
1318 static my_type
replaced_from(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args) {
1319 return my_type{f, pattern, repl, offset, maxCount, std::forward<Args>(args)...};
1329 { a.allocate(size) } -> std::same_as<void*>;
1330 { a.deallocate(void_ptr) }
noexcept -> std::same_as<void>;
1333struct printf_selector {
1334 template<
typename K,
typename... T>
requires (is_one_of_std_char_v<K>)
1335 static int snprintf(K* buffer,
size_t count,
const K* format, T&&... args) {
1336 if constexpr (
sizeof(K) == 1) {
1338 return std::snprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), std::forward<T>(args)...);
1342 return _sprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1346 return std::swprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1350 return _swprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1354 template<
typename K>
requires (is_one_of_std_char_v<K>)
1355 static int vsnprintf(K* buffer,
size_t count,
const K* format, va_list args) {
1356 if constexpr (std::is_same_v<K, u8s>) {
1358 return std::vsnprintf(buffer, count, format, args);
1362 return _vsprintf_p(buffer, count, format, args);
1366 return std::vswprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args);
1370 return _vswprintf_p(buffer, count, format, args);
1376inline size_t grow2(
size_t ret,
size_t currentCapacity) {
1377 return ret <= currentCapacity ? ret : ret * 2;
1381struct to_std_char_type : std::type_identity<K>{};
1384struct to_std_char_type<char8_t>{
1389struct to_std_char_type<char16_t>{
1390 using type = std::conditional_t<
sizeof(char16_t) ==
sizeof(
wchar_t), wchar_t,
void>;
1394struct to_std_char_type<char32_t>{
1395 using type = std::conditional_t<
sizeof(char32_t) ==
sizeof(
wchar_t), wchar_t,
void>;
1436template<
typename K,
typename Impl>
1439 using my_type = Impl;
1443 return *
static_cast<Impl*
>(
this);
1445 const Impl& d()
const {
1446 return *
static_cast<const Impl*
>(
this);
1448 size_t _len()
const noexcept {
1449 return d().length();
1451 const K* _str()
const noexcept {
1452 return d().symbols();
1455 using symb_type = K;
1456 using traits = ch_traits<K>;
1457 using uni = unicode_traits<K>;
1458 using uns_type = std::make_unsigned_t<K>;
1460 template<
typename Op>
1461 Impl& make_trim_op(
const Op& op) {
1462 str_piece me = d(), pos = op(me);
1463 if (me.
length() != pos.length()) {
1464 if (me.
symbols() != pos.symbols())
1465 traits::move(
const_cast<K*
>(me.
symbols()), pos.symbols(), pos.length());
1466 d().set_size(pos.length());
1472 Impl& commonChangeCase() {
1473 size_t len = _len();
1475 Op(_str(), len,
str());
1482 template<
typename T,
bool Dummy = true>
1484 static Impl&
upper(Impl& obj) {
1485 return obj.template commonChangeCase<unicode_traits<K>::upper>();
1487 static Impl&
lower(Impl& obj) {
1488 return obj.template commonChangeCase<unicode_traits<K>::lower>();
1493 Impl& utf8CaseChange() {
1496 size_t len = _len();
1498 u8s* writePos =
str();
1499 const u8s *startData = writePos, *readPos = writePos;
1500 size_t newLen = Op(readPos, len, writePos, len);
1504 d().set_size(newLen);
1505 }
else if (newLen > len) {
1508 size_t readed =
static_cast<size_t>(readPos - startData);
1509 size_t writed =
static_cast<size_t>(writePos - startData);
1510 d().set_size(newLen);
1512 readPos = startData + readed;
1513 writePos =
const_cast<u8s*
>(startData) + writed;
1514 Op(readPos, len - readed, writePos, newLen - writed);
1519 template<
bool Dummy>
1520 struct CaseTraits<u8s, Dummy> {
1521 static Impl&
upper(Impl& obj) {
1522 return obj.template utf8CaseChange<unicode_traits<u8s>::upper>();
1524 static Impl&
lower(Impl& obj) {
1525 return obj.template utf8CaseChange<unicode_traits<u8s>::lower>();
1529 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count>
1530 Impl& makeTrim(T&& pattern) {
1531 return make_trim_op(trim_operator<S, K, N - 1, withSpaces>{pattern});
1534 template<TrimS
ides S,
bool withSpaces>
1535 Impl& makeTrim(str_piece pattern) {
1536 return make_trim_op(trim_operator<S, K, 0, withSpaces>{{pattern}});
1555 explicit operator K*()
noexcept {
1565 return make_trim_op(SimpleTrim<TrimSides::TrimAll, K>{});
1574 return make_trim_op(SimpleTrim<TrimSides::TrimLeft, K>{});
1583 return make_trim_op(SimpleTrim<TrimSides::TrimRight, K>{});
1593 template<typename T, size_t N = const_lit_for<K, T>::Count>
1594 requires is_const_pattern<N>
1596 return makeTrim<TrimSides::TrimAll, false>(pattern);
1606 template<typename T, size_t N = const_lit_for<K, T>::Count>
1607 requires is_const_pattern<N>
1609 return makeTrim<TrimSides::TrimLeft, false>(pattern);
1619 template<typename T, size_t N = const_lit_for<K, T>::Count>
1620 requires is_const_pattern<N>
1622 return makeTrim<TrimSides::TrimRight, false>(pattern);
1632 template<typename T, size_t N = const_lit_for<K, T>::Count>
1633 requires is_const_pattern<N>
1635 return makeTrim<TrimSides::TrimAll, true>(pattern);
1645 template<typename T, size_t N = const_lit_for<K, T>::Count>
1646 requires is_const_pattern<N>
1648 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1658 template<typename T, size_t N = const_lit_for<K, T>::Count>
1659 requires is_const_pattern<N>
1661 return makeTrim<TrimSides::TrimRight, true>(pattern);
1672 return pattern.
length() ? makeTrim<TrimSides::TrimAll, false>(pattern) : d();
1683 return pattern.
length() ? makeTrim<TrimSides::TrimLeft, false>(pattern) : d();
1694 return pattern.
length() ? makeTrim<TrimSides::TrimRight, false>(pattern) : d();
1705 return makeTrim<TrimSides::TrimAll, true>(pattern);
1716 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1727 return makeTrim<TrimSides::TrimRight, true>(pattern);
1737 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1739 if (isAsciiLower(s))
1752 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1754 if (isAsciiUpper(s))
1772 return CaseTraits<K>::upper(d());
1787 return CaseTraits<K>::lower(d());
1791 template<
typename T>
1792 Impl& changeImpl(
size_t from,
size_t len, T expr) {
1793 size_t myLen = _len();
1797 if (from + len > myLen) {
1801 size_t otherLen = expr.length();
1802 if (len == otherLen) {
1803 expr.place(buffer + from);
1805 size_t tailLen = myLen - from - len;
1806 if (len > otherLen) {
1807 expr.place(buffer + from);
1808 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1809 d().set_size(myLen - (len - otherLen));
1811 buffer = d().set_size(myLen + otherLen - len);
1812 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1813 expr.place(buffer + from);
1819 template<
typename T>
1820 Impl& appendImpl(T expr) {
1821 if (
size_t len = expr.length(); len) {
1822 size_t size = _len();
1823 expr.place(d().set_size(size + len) + size);
1828 template<
typename T>
1829 Impl& appendFromImpl(
size_t pos, T expr) {
1832 if (
size_t len = expr.length())
1833 expr.place(d().set_size(pos + len) + pos);
1840 inline static constexpr bool is_str_mutable =
true;
1850 return appendImpl<str_piece>(other);
1860 template<StrExprForType<K> A>
1862 return appendImpl<const A&>(expr);
1873 return appendImpl<str_piece>(other);
1883 template<StrExprForType<K> A>
1885 return appendImpl<const A&>(expr);
1902 return appendFromImpl<str_piece>(pos, other);
1918 template<StrExprForType<K> A>
1920 return appendFromImpl<const A&>(pos, expr);
1934 Impl&
change(
size_t from,
size_t len, str_piece other) {
1935 return changeImpl<str_piece>(from, len, other);
1949 template<StrExprForType<K> A>
1950 Impl&
change(
size_t from,
size_t len,
const A& expr) {
1951 return changeImpl<const A&>(from, len, expr);
1964 return changeImpl<str_piece>(to, 0, other);
1976 template<StrExprForType<K> A>
1978 return changeImpl<const A&>(to, 0, expr);
1991 return changeImpl<const empty_expr<K>&>(from, len, {});
2002 return changeImpl<str_piece>(0, 0, other);
2012 template<StrExprForType<K> A>
2014 return changeImpl<const A&>(0, 0, expr);
2030 Impl&
replace(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
2031 offset = d().find(pattern, offset);
2032 if (offset == str::npos) {
2037 size_t replLength = repl.
length(), patternLength = pattern.
length();
2039 if (patternLength == replLength) {
2043 while (maxCount--) {
2044 traits::copy(ptr + offset, repl.
symbols(), replLength);
2045 offset = d().find(pattern, offset + replLength);
2046 if (offset == str::npos)
2049 }
else if (patternLength > replLength) {
2053 traits::copy(ptr + offset, repl.
symbols(), replLength);
2054 size_t posWrite = offset + replLength;
2055 offset += patternLength;
2057 while (--maxCount) {
2058 size_t idx = d().find(pattern, offset);
2059 if (idx == str::npos)
2061 size_t lenOfPiece = idx - offset;
2062 traits::move(ptr + posWrite, ptr + offset, lenOfPiece);
2063 posWrite += lenOfPiece;
2064 traits::copy(ptr + posWrite, repl.
symbols(), replLength);
2065 posWrite += replLength;
2066 offset = idx + patternLength;
2068 size_t tailLen = _len() - offset;
2069 traits::move(ptr + posWrite, ptr + offset, tailLen);
2070 d().set_size(posWrite + tailLen);
2072 struct replace_grow_helper {
2073 replace_grow_helper(my_type& src, str_piece p, str_piece r,
size_t mc,
size_t d)
2074 : source(src), pattern(p), repl(r), maxCount(mc), delta(d) {}
2076 const str_piece pattern;
2077 const str_piece repl;
2081 K* reserve_for_copy{};
2082 size_t end_of_piece{};
2083 size_t total_length{};
2086 size_t found[16] = {offset};
2088 offset += pattern.
length();
2091 for (; idx < std::size(found) && maxCount > 0; idx++, maxCount--) {
2092 found[idx] = source.find(pattern, offset);
2093 if (found[idx] == str::npos) {
2096 offset = found[idx] + pattern.
length();
2099 if (idx == std::size(found) && maxCount > 0 && (offset = source.find(pattern, offset)) != str::npos) {
2104 if (!reserve_for_copy) {
2107 end_of_piece = source.length();
2108 total_length = end_of_piece + all_delta;
2109 reserve_for_copy = source.alloc_for_copy(total_length);
2111 K* dst_start = reserve_for_copy;
2112 const K* src_start = source.symbols();
2114 size_t pos = found[idx] + pattern.
length();
2115 size_t lenOfPiece = end_of_piece - pos;
2116 ch_traits<K>::move(dst_start + pos + all_delta, src_start + pos, lenOfPiece);
2117 ch_traits<K>::copy(dst_start + pos + all_delta - repl.
length(), repl.
symbols(), repl.
length());
2119 end_of_piece = found[idx];
2121 if (!all_delta && reserve_for_copy != src_start) {
2122 ch_traits<K>::copy(dst_start, src_start, found[0]);
2125 } helper(d(), pattern, repl, maxCount, repl.
length() - pattern.
length());
2126 helper.replace(offset);
2127 d().set_from_copy(helper.reserve_for_copy, helper.total_length);
2147 template<StrType<K> From>
2148 Impl&
replace_from(
const From& f, str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
2150 K* dst = d().reserve_no_preserve(f.length());
2151 const K* src = f.symbols();
2153 if (maxCount == 0) {
2156 size_t src_length = f.length(), start = 0;
2157 while (maxCount--) {
2158 offset = f.find(pattern, offset);
2159 if (offset == str::npos) {
2162 size_t piece_len = offset - start;
2164 ch_traits<K>::copy(dst, src + start, piece_len);
2172 offset += pattern.
length();
2175 if (start < src_length) {
2176 ch_traits<K>::copy(dst, src + start, src_length - start);
2178 d().set_size(src_length - delta);
2181 replace(pattern, repl, offset, maxCount);
2209 template<
typename Op>
2210 Impl&
fill(
size_t from,
const Op& fillFunction) {
2211 size_t size = _len();
2214 size_t capacity = d().capacity();
2218 size_t needSize = (size_t)fillFunction(ptr + from, capacity);
2219 if (capacity >= needSize) {
2220 d().set_size(from + needSize);
2223 ptr = from == 0 ? d().reserve_no_preserve(needSize) : d().set_size(from + needSize);
2224 capacity = d().capacity() - from;
2236 template<
typename Op>
2237 requires std::is_invocable_v<Op, K*, size_t>
2239 return fill(0, fillFunction);
2249 template<
typename Op>
2250 requires std::is_invocable_v<Op, K*, size_t>
2252 return fill(_len(), fillFunction);
2262 template<
typename Op>
2263 requires std::is_invocable_v<Op, my_type&>
2282 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2284 size_t size = _len();
2287 size_t capacity = d().capacity();
2298 if constexpr (
sizeof(K) == 1 && !isWindowsOs) {
2299 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2300 if (result > (
int)capacity) {
2301 ptr = from == 0 ? d().reserve_no_preserve(result) : d().set_size(from + result);
2302 result = printf_selector::snprintf(ptr + from, result + 1,
format, std::forward<T>(args)...);
2306 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2313 ptr = from == 0 ? d().reserve_no_preserve(capacity) : d().set_size(from + capacity);
2319 d().set_size(
static_cast<size_t>(traits::length(_str())));
2321 d().set_size(from + result);
2336 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2352 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2363 inline static K pad;
2364 K& operator*()
const {
2367 writer& operator++() {
2368 if (writed < max_write) {
2371 size_t l = ptr - store->begin();
2373 ptr = store->set_size(l + std::min(l / 2,
size_t(8192))) + l;
2381 writer operator++(
int) {
2387 writer(my_type& s, K* p, K* e,
size_t ml) : store(&s), ptr(p), end(e), max_write(ml) {}
2389 writer(
const writer&) =
delete;
2390 writer& operator=(
const writer&)
noexcept =
delete;
2391 writer(writer&&) noexcept = default;
2392 writer& operator=(writer&&) noexcept = default;
2393 using difference_type =
int;
2395 using fmt_type = typename to_std_char_type<K>::type;
2410 template<typename... T> requires (is_one_of_std_char_v<K>)
2412 size_t size = _len();
2415 size_t capacity = d().capacity();
2418 auto result = std::format_to(writer{d(), ptr + from, ptr + capacity, size_t(-1)},
2419 std::forward<decltype(format)>(
format), std::forward<T>(args)...);
2420 d().set_size(result.ptr - _str());
2439 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2441 size_t size = _len();
2444 size_t capacity = d().capacity();
2447 if constexpr (std::is_same_v<K, u8s>) {
2448 auto result = std::vformat_to(
2449 writer{d(), ptr + from, ptr + capacity, max_write},
2450 std::basic_string_view<K>{
format.symbols(),
format.length()},
2451 std::make_format_args(args...));
2452 d().set_size(result.ptr - _str());
2454 auto result = std::vformat_to(
2455 writer{d(), to_one_of_std_char(ptr + from), ptr + capacity, max_write},
2456 std::basic_string_view<wchar_t>{to_one_of_std_char(
format.symbols()),
format.length()},
2457 std::make_wformat_args(std::forward<T>(args)...));
2458 d().set_size(result.ptr - _str());
2474 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2475 Impl&
format(
const FmtString<fmt_type, T...>& pattern, T&&... args) {
2476 return format_from(0, pattern, std::forward<T>(args)...);
2490 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2506 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2522 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2540 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2558 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2572 template<
typename Op,
typename... Args>
2573 Impl&
with(
const Op& fillFunction, Args&&... args) {
2574 fillFunction(d(), std::forward<Args>(args)...);
2580struct SharedStringData {
2581 std::atomic_size_t ref_;
2583 SharedStringData() {
2587 return (K*)(
this + 1);
2590 ref_.fetch_add(1, std::memory_order_relaxed);
2592 void decr(Allocatorable
auto& allocator) {
2593 size_t val = ref_.fetch_sub(1, std::memory_order_relaxed);
2595 allocator.deallocate(
this);
2598 static SharedStringData<K>* create(
size_t l, Allocatorable
auto& allocator) {
2599 size_t size =
sizeof(SharedStringData<K>) + (l + 1) *
sizeof(K);
2600 return new (allocator.allocate(size)) SharedStringData();
2602 static SharedStringData<K>* from_str(
const K* p) {
2603 return (SharedStringData<K>*)p - 1;
2605 K* place(K* p,
size_t len) {
2606 ch_traits<K>::copy(p, str(), len);
2613class string_common_allocator {
2615 void* allocate(
size_t bytes) {
2616 return new char[bytes];
2618 void deallocate(
void* address)
noexcept {
2619 delete []
static_cast<char*
>(address);
2623string_common_allocator default_string_allocator_selector(...);
2630using allocator_string =
decltype(default_string_allocator_selector(
int(0)));
2632template<
typename K, Allocatorable Allocator>
2664template<
typename K,
size_t N,
bool forShared = false, Allocatorable Allocator = allocator_
string>
2666 public str_algs<K, simple_str<K>, lstring<K, N, forShared, Allocator>, true>,
2667 public str_mutable<K, lstring<K, N, forShared, Allocator>>,
2668 public str_storable<K, lstring<K, N, forShared, Allocator>, Allocator>,
2669 public null_terminated<K, lstring<K, N, forShared, Allocator>>,
2670 public from_utf_convertible<K, lstring<K, N, forShared, Allocator>> {
2672 using symb_type = K;
2674 using allocator_t = Allocator;
2683 extra = forShared ?
sizeof(SharedStringData<K>) : 0,
2686 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
2687 using base_storable = str_storable<K, my_type, Allocator>;
2688 using base_mutable = str_mutable<K, my_type>;
2689 using base_utf = from_utf_convertible<K, my_type>;
2690 using traits = ch_traits<K>;
2691 using s_str = base_storable::s_str;
2693 friend base_storable;
2694 friend base_mutable;
2696 friend class sstring<K, Allocator>;
2703 K local_[LocalCapacity + 1];
2706 constexpr void create_empty() {
2711 constexpr static size_t calc_capacity(
size_t s) {
2712 const int al =
alignof(std::max_align_t) < 16 ? 16 : alignof(std::max_align_t);
2713 size_t real_need = (s + 1) *
sizeof(K) + extra;
2714 size_t aligned_alloced = (real_need + al - 1) / al * al;
2715 return (aligned_alloced - extra) /
sizeof(K) - 1;
2718 constexpr K* init(
size_t s) {
2720 if (size_ > LocalCapacity) {
2721 s = calc_capacity(s);
2722 data_ = alloc_place(s);
2730 constexpr bool is_alloced() const noexcept {
2731 return data_ != local_;
2734 constexpr void dealloc() {
2736 base_storable::allocator().deallocate(to_real_address(data_));
2741 constexpr static K* to_real_address(
void* ptr) {
2742 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) - extra);
2744 constexpr static K* from_real_address(
void* ptr) {
2745 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) + extra);
2748 constexpr K* alloc_place(
size_t newSize) {
2749 return from_real_address(base_storable::allocator().allocate((newSize + 1) *
sizeof(K) + extra));
2753 constexpr K* alloc_for_copy(
size_t newSize) {
2754 if (capacity() >= newSize) {
2759 return alloc_place(calc_capacity(newSize));
2763 constexpr void set_from_copy(K* ptr,
size_t newSize) {
2769 capacity_ = calc_capacity(newSize);
2782 template<
typename... Args>
2783 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
2784 constexpr lstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
2785 : base_storable(std::forward<Args>(args)...) {
2797 template<
typename... Args>
2798 requires std::is_constructible_v<allocator_t, Args...>
2799 constexpr lstring(s_str other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2812 template<
typename... Args>
2813 requires std::is_constructible_v<allocator_t, Args...>
2814 constexpr lstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2827 template<
typename... Args>
2828 requires std::is_constructible_v<allocator_t, Args...>
2829 constexpr lstring(
size_t count, K pad, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2846 template<
typename... Args>
2847 requires std::is_constructible_v<allocator_t, Args...>
2867 template<StrType<K> From,
typename... Args>
2868 requires std::is_constructible_v<allocator_t, Args...>
2869 constexpr lstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
2870 : base_storable(std::forward<Args>(args)...) {
2878 constexpr ~lstring() {
2890 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
2901 template<
typename... Args>
2902 requires(
sizeof...(Args) > 0 && std::is_convertible_v<allocator_t, Args...>)
2903 constexpr lstring(
const my_type& other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2905 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
2916 template<typename T, size_t I = const_lit_for<K, T>::Count,
typename... Args>
2917 requires std::is_constructible_v<allocator_t, Args...>
2918 constexpr lstring(T&& value, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2919 if constexpr (I > 1) {
2920 K* ptr = init(I - 1);
2921 traits::copy(ptr, value, I - 1);
2932 constexpr lstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
2934 size_ = other.size_;
2935 if (other.is_alloced()) {
2936 data_ = other.data_;
2937 capacity_ = other.capacity_;
2940 traits::copy(local_, other.local_, size_ + 1);
2942 other.data_ = other.local_;
2944 other.local_[0] = 0;
2955 template<
typename Op,
typename... Args>
2956 requires(std::is_constructible_v<Allocator, Args...> && (std::is_invocable_v<Op, my_type&> || std::is_invocable_v<Op, K*, size_t>))
2957 lstring(
const Op& op, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2961 template<
typename O>
2962 requires(!std::is_same_v<O, K>)
2964 this->init_from_utf_convertible(init);
2967 template<
typename O,
typename I,
bool M>
2968 requires(!std::is_same_v<O, K>)
2969 lstring(
const str_algs<O, simple_str<O>, I, M>& init) {
2970 this->init_from_utf_convertible(init.
to_str());
2989 if (&other !=
this) {
2991 size_ = other.size_;
3006 if (&other !=
this) {
3008 if (other.is_alloced()) {
3009 data_ = other.data_;
3010 capacity_ = other.capacity_;
3012 traits::copy(data_, other.local_, other.size_ + 1);
3015 size_ = other.size_;
3016 other.create_empty();
3021 my_type& assign(
const K* other,
size_t len) {
3023 bool isIntersect = other >= data_ && other + len <= data_ + size_;
3029 if (other > data_) {
3030 traits::move(data_, other, len);
3033 traits::copy(reserve_no_preserve(len), other, len);
3049 return assign(other.str, other.len);
3059 template<typename T, size_t S = const_lit_for<K, T>::Count>
3061 return assign(other, S - 1);
3074 size_t newLen = expr.
length();
3120 newSize = calc_capacity(newSize);
3121 K* newData = alloc_place(newSize);
3124 capacity_ = newSize;
3142 newSize = calc_capacity(newSize);
3143 K* newData = alloc_place(newSize);
3144 traits::copy(newData, data_, size_);
3147 capacity_ = newSize;
3165 if (newSize > cap) {
3166 size_t needPlace = newSize;
3167 if (needPlace < (cap + 1) * 2) {
3168 needPlace = (cap + 1) * 2 - 1;
3181 return !is_alloced();
3191 for (
size_t i = 0; i < cap; i++) {
3192 if (data_[i] == 0) {
3207 size_t need_capacity = calc_capacity(size_);
3208 if (is_alloced() && capacity_ > need_capacity) {
3209 K* newData = size_ <=
LocalCapacity ? local_ : alloc_place(need_capacity);
3210 traits::copy(newData, data_, size_ + 1);
3215 capacity_ = need_capacity;
3231template<
size_t N = 15>
3232using lstringa = lstring<u8s, N>;
3233template<
size_t N = 15>
3234using lstringb = lstring<ubs, N>;
3235template<
size_t N = 15>
3236using lstringw = lstring<wchar_t, N>;
3237template<
size_t N = 15>
3238using lstringu = lstring<u16s, N>;
3239template<
size_t N = 15>
3240using lstringuu = lstring<u32s, N>;
3242template<
size_t N = 15>
3243using lstringsa = lstring<u8s, N, true>;
3244template<
size_t N = 15>
3245using lstringsb = lstring<ubs, N, true>;
3246template<
size_t N = 15>
3247using lstringsw = lstring<wchar_t, N, true>;
3248template<
size_t N = 15>
3249using lstringsu = lstring<u16s, N, true>;
3250template<
size_t N = 15>
3251using lstringsuu = lstring<u32s, N, true>;
3254template<typename T, typename K = typename const_lit<T>::symb_type>
3255auto getLiteralType(T&&) {
3259template<
size_t Arch,
size_t L>
3260inline constexpr const size_t _local_count = 0;
3263inline constexpr const size_t _local_count<8, 1> = 23;
3265inline constexpr const size_t _local_count<8, 2> = 15;
3267inline constexpr const size_t _local_count<8, 4> = 7;
3269inline constexpr const size_t _local_count<4, 1> = 15;
3271inline constexpr const size_t _local_count<4, 2> = 11;
3273inline constexpr const size_t _local_count<4, 4> = 5;
3276constexpr const size_t local_count = _local_count<
sizeof(size_t),
sizeof(T)>;
3330template<
typename K, Allocatorable Allocator = allocator_
string>
3331class decl_empty_bases sstring :
3332 public str_algs<K, simple_str<K>, sstring<K, Allocator>, false>,
3333 public str_storable<K, sstring<K, Allocator>, Allocator>,
3334 public null_terminated<K, sstring<K, Allocator>>,
3335 public from_utf_convertible<K, sstring<K, Allocator>> {
3337 using symb_type = K;
3338 using uns_type = std::make_unsigned_t<K>;
3339 using my_type = sstring<K, Allocator>;
3340 using allocator_t = Allocator;
3342 enum { LocalCount = local_count<K> };
3345 using base_algs = str_algs<K, simple_str<K>, my_type,
false>;
3347 using base_utf = from_utf_convertible<K, my_type>;
3348 using traits = ch_traits<K>;
3349 using uni = unicode_traits<K>;
3350 using s_str = base_storable::s_str;
3352 friend base_storable;
3355 enum Types { Local, Constant, Shared };
3368 uns_type localRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
3383 constexpr void create_empty() {
3385 localRemain_ = LocalCount;
3388 constexpr K* init(
size_t s) {
3389 if (s > LocalCount) {
3397 localRemain_ = LocalCount - s;
3402 K* set_size(
size_t newSize) {
3408 if (newSize !=
size) {
3409 if (type_ == Constant) {
3412 if (newSize <= LocalCount) {
3413 if (type_ == Shared) {
3414 SharedStringData<K>* str_buf = SharedStringData<K>::from_str(sstr_);
3415 traits::copy(buf_, sstr_, newSize);
3419 localRemain_ = LocalCount - newSize;
3421 if (type_ == Shared) {
3422 if (newSize >
size || (newSize > 64 && newSize <=
size * 3 / 4)) {
3424 traits::copy(newStr, sstr_, newSize);
3428 }
else if (type_ == Local) {
3431 traits::copy(newStr, buf_,
size);
3440 K*
str = type_ == Local ? buf_ : (K*)sstr_;
3457 template<
typename... Args>
3458 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
3459 sstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
3460 : base_storable(std::forward<Args>(args)...) {
3472 template<
typename... Args>
3473 requires std::is_constructible_v<allocator_t, Args...>
3474 sstring(s_str other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3487 template<
typename... Args>
3488 requires std::is_constructible_v<allocator_t, Args...>
3489 sstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3502 template<
typename... Args>
3503 requires std::is_constructible_v<allocator_t, Args...>
3504 sstring(
size_t count, K pad, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3521 template<
typename... Args>
3522 requires std::is_constructible_v<allocator_t, Args...>
3542 template<StrType<K> From,
typename... Args>
3543 requires std::is_constructible_v<allocator_t, Args...>
3544 sstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
3545 : base_storable(std::forward<Args>(args)...) {
3552 if (type_ == Shared) {
3562 constexpr sstring(
const my_type& other) noexcept : base_storable(other.allocator()) {
3563 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3564 if (type_ == Shared)
3565 SharedStringData<K>::from_str(sstr_)->incr();
3573 constexpr sstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
3574 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3575 other.create_empty();
3590 size_t size = src.length();
3592 if (src.is_alloced()) {
3596 if (
size > LocalCount) {
3603 new (SharedStringData<K>::from_str(
str)) SharedStringData<K>();
3608 localRemain_ = LocalCount -
size;
3609 traits::copy(buf_,
str,
size + 1);
3617 K*
str = init(src.size_);
3618 traits::copy(
str, src.symbols(),
size + 1);
3635 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename... Args>
3636 requires std::is_constructible_v<allocator_t, Args...>
3637 sstring(T&& s, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3649 template<
typename O>
requires(!std::is_same_v<O, K>)
3651 this->init_from_utf_convertible(init);
3654 template<
typename O,
typename I,
bool M>
requires(!std::is_same_v<O, K>)
3656 this->init_from_utf_convertible(init.
to_str());
3659 constexpr void swap(my_type&& other)
noexcept {
3660 char buf[
sizeof(buf_) +
sizeof(K)];
3661 memcpy(buf, buf_,
sizeof(buf));
3662 memcpy(buf_, other.buf_,
sizeof(buf));
3663 memcpy(other.buf_, buf,
sizeof(buf));
3665 std::swap(base_storable::allocator(), other.allocator());
3676 swap(std::move(other));
3698 template<typename T, size_t N = const_lit_for<K, T>::Count>
3710 template<
size_t N,
bool forShared,
typename A>
3724 return operator=(my_type{std::move(other)});
3746 if (type_ == Shared)
3753 return type_ == Local ? buf_ : cstr_;
3757 return type_ == Local ? LocalCount - localRemain_ : bigLen_;
3779 template<
typename... T>
3780 static my_type
printf(
const K* pattern, T&&... args) {
3793 template<
typename... T>
3794 static my_type
format(
const FmtString<
typename to_std_char_type<K>::type, T...>& fmtString, T&&... args) {
3807 template<
typename... T>
3813template<
typename K, Allocatorable Allocator>
3814inline const sstring<K> sstring<K, Allocator>::empty_str{};
3818template<
typename K,
size_t N>
3819class decl_empty_bases cestring :
3820 public str_algs<K, simple_str<K>, cestring<K, N>, true>,
3821 public str_storable<K, cestring<K, N>, no_alloc>,
3822 public null_terminated<K, lstring<K, N>>
3825 using symb_type = K;
3826 using my_type = cestring<K, N>;
3830 LocalCapacity = N | (
sizeof(
void*) /
sizeof(K) - 1),
3835 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
3836 using base_storable = str_storable<K, my_type, no_alloc>;
3838 using traits = ch_traits<K>;
3839 using s_str = base_storable::s_str;
3841 friend base_storable;
3846 K local_[LocalCapacity + 1]{};
3848 constexpr void create_empty() {
3854 constexpr K* init(
size_t s) {
3856 if (size_ > LocalCapacity) {
3857 throw std::bad_alloc{};
3864 constexpr size_t length() const noexcept {
3868 constexpr const K* symbols() const noexcept {
3869 return is_cstr_ ? cstr_ : local_;
3872 constexpr bool is_empty() const noexcept {
3876 constexpr bool empty() const noexcept {
3880 constexpr size_t capacity() const noexcept {
3881 return LocalCapacity;
3887 constexpr cestring() noexcept = default;
3895 constexpr cestring(s_str other) : base_storable() {
3896 base_storable::init_from_str_other(other);
3906 constexpr cestring(
size_t repeat, s_str pattern) : base_storable() {
3907 base_storable::init_str_repeat(repeat, pattern);
3917 constexpr cestring(
size_t count, K pad) : base_storable() {
3918 base_storable::init_symb_repeat(count, pad);
3932 constexpr cestring(
const StrExprForType<K>
auto& expr) : base_storable() {
3933 base_storable::init_str_expr(expr);
3949 template<StrType<K> From>
3950 constexpr cestring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0)
3952 base_storable::init_replaced(f, pattern, repl, offset, maxCount);
3956 constexpr ~cestring() {}
3966 template<typename T, size_t M = const_lit_for<K, T>::Count>
3967 constexpr cestring(T&& s) : base_storable(), cstr_(s), size_(M - 1), is_cstr_(true), local_{0} {}
3971consteval simple_str_nt<K> select_str(simple_str_nt<u8s> s8, simple_str_nt<ubs> sb, simple_str_nt<uws> sw, simple_str_nt<u16s> s16, simple_str_nt<u32s> s32) {
3972 if constexpr (std::is_same_v<K, u8s>)
3974 if constexpr (std::is_same_v<K, ubs>)
3976 if constexpr (std::is_same_v<K, uws>)
3978 if constexpr (std::is_same_v<K, u16s>)
3980 if constexpr (std::is_same_v<K, u32s>)
3984#define uni_string(K, p) select_str<K>(p, u8##p, L##p, u##p, U##p)
3986template<
typename K,
typename H>
3990 char node[
sizeof(sstring<K>)];
3992 const simple_str_nt<K>& to_nt() const noexcept {
3993 return static_cast<const simple_str_nt<K>&
>(str);
3995 const sstring<K>& to_str() const noexcept {
3996 return *
reinterpret_cast<const sstring<K>*
>(node);
4002 static inline constexpr size_t basis =
static_cast<size_t>(14695981039346656037ULL);
4003 static inline constexpr size_t prime =
static_cast<size_t>(1099511628211ULL);
4007struct fnv_const<false> {
4008 static inline constexpr size_t basis =
static_cast<size_t>(2166136261U);
4009 static inline constexpr size_t prime =
static_cast<size_t>(16777619U);
4012using fnv = fnv_const<
sizeof(size_t) == 8>;
4015inline constexpr size_t fnv_hash(
const K* ptr,
size_t l) {
4016 size_t h = fnv::basis;
4017 for (
size_t i = 0; i < l; i++) {
4018 h = (h ^ (std::make_unsigned_t<K>)ptr[i]) * fnv::prime;
4024inline constexpr size_t fnv_hash_ia(
const K* ptr,
size_t l) {
4025 size_t h = fnv::basis;
4026 for (
size_t i = 0; i < l; i++) {
4027 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)ptr[i];
4028 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
4033template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
4034inline constexpr size_t fnv_hash(T&& value) {
4035 size_t h = fnv::basis;
4036 for (
size_t i = 0; i < N - 1; i++) {
4037 h = (h ^ (std::make_unsigned_t<K>)value[i]) * fnv::prime;
4042template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
4043inline constexpr size_t fnv_hash_ia(T&& value) {
4044 size_t h = fnv::basis;
4045 for (
size_t i = 0; i < N - 1; i++) {
4046 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)value[i];
4047 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
4053inline consteval size_t fnv_hash_compile(
const K* ptr,
size_t l) {
4054 return fnv_hash(ptr, l);
4058inline consteval size_t fnv_hash_ia_compile(
const K* ptr,
size_t l) {
4059 return fnv_hash_ia(ptr, l);
4062static_assert(std::is_trivially_copyable_v<StoreType<u8s, int>>,
"Store type must be trivially copyable");
4163template<
typename K,
typename T,
typename H = strhash<K>,
typename E = streql<K>>
4164class hashStrMap :
public std::unordered_map<StoreType<K, H>, T, H, E> {
4166 using InStore = StoreType<K, H>;
4169 using my_type = hashStrMap<K, T, H, E>;
4170 using hash_t = std::unordered_map<InStore, T, H, E>;
4173 hashStrMap() =
default;
4174 hashStrMap(
const my_type& other) : hash_t(other) {
4175 for (
const auto& [k, v] : *
this) {
4176 InStore& stored =
const_cast<InStore&
>(k);
4178 new (stored.node)
sstring<K>(std::move(tmp));
4179 stored.str.str = stored.to_str().symbols();
4183 for (
auto& k: *
this)
4187 hashStrMap(my_type&& o) =
default;
4189 my_type& operator=(
const my_type& other) {
4190 hash_t::operator=(other);
4191 for (
const auto& [k, v] : *
this) {
4192 InStore& stored =
const_cast<InStore&
>(k);
4194 new (stored.node)
sstring<K>(std::move(tmp));
4195 stored.str.str = stored.to_str().symbols();
4199 my_type& operator=(my_type&&) =
default;
4201 hashStrMap(std::initializer_list<std::pair<const InStore, T>>&& init) {
4202 for (
const auto& e: init)
4203 emplace(e.first, e.second);
4206 using init_str = std::initializer_list<std::pair<const sstring<K>, T>>;
4208 hashStrMap(init_str&& init) {
4209 for (
const auto& e: init)
4210 emplace(e.first, e.second);
4215 template<
typename... ValArgs>
4216 auto try_emplace(
const InStore& key, ValArgs&&... args) {
4217 auto it = hash_t::try_emplace(key, std::forward<ValArgs>(args)...);
4219 InStore& stored =
const_cast<InStore&
>(it.first->first);
4221 stored.str.str = stored.to_str().symbols();
4227 return {key, H{}(key)};
4230 template<
typename Key,
typename... ValArgs>
4231 requires(std::is_convertible_v<Key, simple_str<K>>)
4232 auto try_emplace(Key&& key, ValArgs&&... args) {
4233 auto it = hash_t::try_emplace(toStoreType(key), std::forward<ValArgs>(args)...);
4235 InStore& stored =
const_cast<InStore&
>(it.first->first);
4236 new (stored.node)
sstring<K>(std::forward<Key>(key));
4237 stored.str.str = stored.to_str().symbols();
4242 template<
typename... ValArgs>
4243 auto emplace(
const InStore& key, ValArgs&&... args) {
4244 auto it = try_emplace(key, std::forward<ValArgs>(args)...);
4246 it.first->second = T(std::forward<ValArgs>(args)...);
4251 template<
typename Key,
typename... ValArgs>
4252 requires(std::is_convertible_v<Key, simple_str<K>>)
4253 auto emplace(Key&& key, ValArgs&&... args) {
4254 auto it = try_emplace(std::forward<Key>(key), std::forward<ValArgs>(args)...);
4256 it.first->second = T(std::forward<ValArgs>(args)...);
4261 auto& operator[](
const InStore& key) {
4262 return try_emplace(key).first->second;
4265 template<
typename Key>
4266 requires(std::is_convertible_v<Key, simple_str<K>>)
4267 auto&
operator[](Key&& key) {
4268 return try_emplace(std::forward<Key>(key)).first->second;
4271 decltype(
auto) at(
const InStore& key) {
4272 return hash_t::at(key);
4274 decltype(
auto) at(
const InStore& key)
const {
4275 return hash_t::at(key);
4279 return hash_t::at(toStoreType(key));
4282 return hash_t::at(toStoreType(key));
4285 auto find(
const InStore& key)
const {
4286 return hash_t::find(key);
4290 return find(toStoreType(key));
4293 auto find(
const InStore& key) {
4294 return hash_t::find(key);
4298 return find(toStoreType(key));
4301 auto erase(
typename hash_t::const_iterator it) {
4302 if (it != hash_t::end()) {
4305 return hash_t::erase(it);
4308 auto erase(
const InStore& key) {
4309 auto it = hash_t::find(key);
4310 if (it != hash_t::end()) {
4319 return erase(toStoreType(key));
4323 auto it = find(txt);
4324 if (it != hash_t::end()) {
4332 for (
auto& k: *
this)
4336 bool contains(
const InStore& key)
const {
4337 return hash_t::find(key) != this->end();
4341 return find(toStoreType(key)) != this->end();
4347 template<
typename H>
4348 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
4349 return _Left.hash == _Right.hash && _Left.str == _Right.str;
4355 size_t operator()(simple_str<K> _Keyval)
const {
4356 return fnv_hash(_Keyval.symbols(), _Keyval.length());
4358 size_t operator()(
const StoreType<K, strhash<K>>& _Keyval)
const {
4359 return _Keyval.hash;
4365 template<
typename H>
4366 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
4367 return _Left.hash == _Right.hash && _Left.str.equal_ia(_Right.str);
4373 size_t operator()(simple_str<K> _Keyval)
const {
4374 return fnv_hash_ia(_Keyval.symbols(), _Keyval.length());
4376 size_t operator()(
const StoreType<K, strhashia<K>>& _Keyval)
const {
4377 return _Keyval.hash;
4383 template<
typename H>
4384 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
4385 return _Left.hash == _Right.hash && _Left.str.equal_iu(_Right.str);
4391 size_t operator()(simple_str<K> _Keyval)
const {
4392 return unicode_traits<K>::hashiu(_Keyval.symbols(), _Keyval.length());
4394 size_t operator()(
const StoreType<K, strhashiu<K>>& _Keyval)
const {
4395 return _Keyval.hash;
4415 using chunk_t = std::pair<std::unique_ptr<K[]>,
size_t>;
4416 std::vector<chunk_t> chunks;
4423 using my_type = chunked_string_builder<K>;
4424 using symb_type = K;
4425 chunked_string_builder() =
default;
4426 chunked_string_builder(
size_t a) : align(a){};
4427 chunked_string_builder(
const my_type&) =
delete;
4428 chunked_string_builder(my_type&& other) noexcept
4429 : chunks(std::move(other.chunks)), write(other.write), len(other.len), remain(other.remain), align(other.align) {
4430 other.len = other.remain = 0;
4431 other.write =
nullptr;
4433 my_type& operator=(my_type other)
noexcept {
4434 chunks.swap(other.chunks);
4435 write = other.write;
4437 remain = other.remain;
4438 align = other.align;
4439 other.len = other.remain = 0;
4440 other.write =
nullptr;
4448 if (
data.len <= remain) {
4451 ch_traits<K>::copy(write,
data.str,
data.len);
4453 chunks.back().second +=
data.len;
4460 ch_traits<K>::copy(write,
data.str, remain);
4463 chunks.back().second += remain;
4469 size_t blockSize = (
data.len + align - 1) / align * align;
4470 chunks.emplace_back(std::make_unique<K[]>(blockSize),
data.len);
4471 write = chunks.back().first.get();
4472 ch_traits<K>::copy(write,
data.str,
data.len);
4474 remain = blockSize -
data.len;
4481 size_t l = expr.
length();
4484 write = expr.place(write);
4485 chunks.back().second += l;
4488 }
else if (!remain) {
4489 size_t blockSize = (l + align - 1) / align * align;
4490 chunks.emplace_back(std::make_unique<K[]>(blockSize), l);
4491 write = expr.place(chunks.back().first.get());
4493 remain = blockSize - l;
4495 auto store = std::make_unique<K[]>(l);
4496 expr.place(store.get());
4503 template<
typename T>
4505 requires std::is_same_v<T, K>
4507 return operator<<(expr_char<K>(
data));
4515 if (chunks.empty()) {
4518 if (chunks.size() > 1) {
4522 remain += chunks[0].second;
4523 chunks[0].second = 0;
4525 write = chunks[0].first.get();
4528 constexpr K* place(K* p)
const noexcept {
4529 for (
const auto& block: chunks) {
4530 ch_traits<K>::copy(p, block.first.get(), block.second);
4543 template<
typename Op>
4545 for (
const auto& block: chunks)
4546 o(block.first.get(), block.second);
4553 if (chunks.size()) {
4554 const K* ptr = chunks.front().first.get();
4555 for (
const auto& chunk: chunks) {
4556 if (chunk.first.get() != ptr)
4558 ptr += chunk.second;
4570 return chunks.size() ? chunks.front().first.get() : simple_str_nt<K>::empty_str.str;
4587 typename decltype(chunks)::const_iterator it, end;
4588 size_t writedFromCurrentChunk;
4608 while (size && !
is_end()) {
4609 size_t remain = it->second - writedFromCurrentChunk;
4610 size_t write = std::min(size, remain);
4611 ch_traits<K>::copy(buffer, it->first.get() + writedFromCurrentChunk, write);
4617 writedFromCurrentChunk = 0;
4619 writedFromCurrentChunk += write;
4631 return {chunks.begin(), chunks.end(), 0};
4644using stringa = sstring<u8s>;
4645using stringb = sstring<ubs>;
4646using stringw = sstring<wchar_t>;
4647using stringu = sstring<u16s>;
4648using stringuu = sstring<u32s>;
4649static_assert(
sizeof(stringa) == (
sizeof(
void*) == 8 ? 24 : 16),
"Bad size of sstring");
4731inline namespace literals {
4800template<
typename K>
using HashKey = StoreType<K, strhash<K>>;
4801template<
typename K>
using HashKeyIA = StoreType<K, strhashia<K>>;
4802template<
typename K>
using HashKeyIU = StoreType<K, strhashiu<K>>;
4814consteval HashKey<u8s>
operator""_h(
const u8s* ptr,
size_t l) {
4815 return HashKey<u8s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4828consteval HashKeyIA<u8s>
operator""_ia(
const u8s* ptr,
size_t l) {
4829 return HashKeyIA<u8s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4842inline HashKeyIU<u8s>
operator""_iu(
const u8s* ptr,
size_t l) {
4843 return HashKeyIU<u8s>{{ptr, l}, strhashiu<u8s>{}(
simple_str<u8s>{ptr, l})};
4856consteval HashKey<u16s>
operator""_h(
const u16s* ptr,
size_t l) {
4857 return HashKey<u16s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4870consteval HashKeyIA<u16s>
operator""_ia(
const u16s* ptr,
size_t l) {
4871 return HashKeyIA<u16s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4884inline HashKeyIU<u16s>
operator""_iu(
const u16s* ptr,
size_t l) {
4885 return HashKeyIU<u16s>{{ptr, l}, strhashiu<u16s>{}(
simple_str<u16s>{ptr, l})};
4898consteval HashKey<u32s>
operator""_h(
const u32s* ptr,
size_t l) {
4899 return HashKey<u32s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4912consteval HashKeyIA<u32s>
operator""_ia(
const u32s* ptr,
size_t l) {
4913 return HashKeyIA<u32s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4926inline HashKeyIU<u32s>
operator""_iu(
const u32s* ptr,
size_t l) {
4927 return HashKeyIU<u32s>{{ptr, l}, strhashiu<u32s>{}(
simple_str<u32s>{ptr, l})};
4940consteval HashKey<uws>
operator""_h(
const uws* ptr,
size_t l) {
4941 return HashKey<uws>{{ptr, l}, fnv_hash_compile(ptr, l)};
4954consteval HashKeyIA<uws>
operator""_ia(
const uws* ptr,
size_t l) {
4955 return HashKeyIA<uws>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4968inline HashKeyIU<uws>
operator""_iu(
const uws* ptr,
size_t l) {
4969 return HashKeyIU<uws>{{ptr, l}, strhashiu<uws>{}(
simple_str<uws>{ptr, l})};
4984 return stream << std::string_view{text.
symbols(), text.
length()};
4997inline std::wostream&
operator<<(std::wostream& stream, ssw text) {
4998 return stream << std::wstring_view{text.
symbols(), text.
length()};
5012 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
5025inline std::ostream&
operator<<(std::ostream& stream,
const stringa& text) {
5026 return stream << std::string_view{text.
symbols(), text.
length()};
5039inline std::wostream&
operator<<(std::wostream& stream,
const stringw& text) {
5040 return stream << std::wstring_view{text.
symbols(), text.
length()};
5054 return stream << std::wstring_view{from_w(text.symbols()), text.length()};
5067template<
size_t N,
bool S, simstr::Allocatorable A>
5069 return stream << std::string_view{text.
symbols(), text.
length()};
5082template<
size_t N,
bool S, simstr::Allocatorable A>
5084 return stream << std::wstring_view{text.
symbols(), text.
length()};
5097template<
size_t N,
bool S, simstr::Allocatorable A>
5099 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
5109struct std::formatter<
simstr::simple_str<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5111 template<
typename FormatContext>
5113 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5122struct std::formatter<
simstr::simple_str_nt<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5124 template<
typename FormatContext>
5126 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5135struct std::formatter<
simstr::sstring<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5137 template<
typename FormatContext>
5139 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5147template<
typename K,
size_t N,
bool S,
typename A>
5148struct std::formatter<
simstr::lstring<K, N, S, A>, K> : std::formatter<std::basic_string_view<K>, K> {
5150 template<
typename FormatContext>
5152 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5161struct std::formatter<
simstr::simple_str<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5163 template<
typename FormatContext>
5165 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5174struct std::formatter<
simstr::simple_str_nt<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5176 template<
typename FormatContext>
5178 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5187struct std::formatter<
simstr::sstring<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5189 template<
typename FormatContext>
5191 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5199template<
size_t N,
bool S,
typename A>
5200struct std::formatter<
simstr::lstring<char8_t, N, S, A>, char> : std::formatter<std::basic_string_view<char>, char> {
5202 template<
typename FormatContext>
5204 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5213struct std::formatter<
simstr::simple_str<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5215 template<
typename FormatContext>
5217 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5226struct std::formatter<
simstr::simple_str_nt<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5228 template<
typename FormatContext>
5230 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5239struct std::formatter<
simstr::sstring<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5241 template<
typename FormatContext>
5243 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.
symbols(), t.
length()}, fc);
5251template<
size_t N,
bool S,
typename A>
5252struct std::formatter<
simstr::lstring<simstr::wchar_type, N, S, A>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5254 template<
typename FormatContext>
5256 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.
symbols(), t.
length()}, fc);
Класс для последовательного получения подстрок по заданному разделителю.
Определения strexpr.h:2466
my_type & operator<<(simple_str< K > data)
Добавление порции данных.
Определения sstring.h:4445
portion_store get_portion() const
Получить portion_store, через который можно последовательно извлекать данные во внешний буфер.
Определения sstring.h:4630
constexpr size_t length() const noexcept
Длина сохранённого текста.
Определения sstring.h:4510
my_type & operator<<(T data)
Добавление символа.
Определения sstring.h:4504
void reset()
Сбрасывает содержимое, но при этом не удаляет первый буфер, чтобы потом избежать аллокации.
Определения sstring.h:4514
void clear()
Очистить объект, освободив все выделенные буфера.
Определения sstring.h:4576
my_type & operator<<(const StrExprForType< K > auto &expr)
Добавление строкового выражения.
Определения sstring.h:4480
bool is_continuous() const
Проверяет, расположен ли весь текст одним непрерывным куском в памяти.
Определения sstring.h:4552
void out(const Op &o) const
Применяет функтор к каждому сохранённому буферу.
Определения sstring.h:4544
const auto & data() const
Получить внутренние буфера с данными.
Определения sstring.h:4639
const K * begin() const
Получить указатель на начало первого буфера. Имеет смысл применять только если is_continuous true.
Определения sstring.h:4569
Контейнер для более эффективного поиска по строковым ключам.
Определения sstring.h:4164
Класс мутабельной, владеющей строки. Содержит внутренний буфер для строк заданного размера.
Определения sstring.h:2670
constexpr void define_size()
Определить длину строки. Ищет символ 0 в буфере строки до его ёмкости, после чего устаналивает длину ...
Определения sstring.h:3189
constexpr lstring(T &&value, Args &&... args)
Конструктор из строкового литерала.
Определения sstring.h:2918
my_type & operator=(T &&other)
Оператор присваивания строкового литерала.
Определения sstring.h:3060
constexpr void reset()
Делает строку пустой и освобождает внешний буфер, если он был.
Определения sstring.h:3224
@ LocalCapacity
Определения sstring.h:2678
constexpr bool is_local() const noexcept
Узнать, локальный или внешний буфер используется для символов.
Определения sstring.h:3180
my_type & operator=(my_type &&other) noexcept
Оператор присваивания перемещением из строки такого же типа.
Определения sstring.h:3003
constexpr size_t length() const noexcept
Длина строки.
Определения sstring.h:3083
constexpr lstring(s_str other, Args &&... args)
Конструктор из другого строкового объекта.
Определения sstring.h:2799
constexpr lstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Конструктор из строкового источника с заменой.
Определения sstring.h:2869
constexpr lstring(size_t repeat, s_str pattern, Args &&... args)
Конструктор повторения строки.
Определения sstring.h:2814
constexpr lstring(const my_type &other)
Копирование из другой строки такого же типа.
Определения sstring.h:2888
constexpr lstring(const my_type &other, Args &&... args)
Копирование из другой строки такого же типа, но с другим аллокатором.
Определения sstring.h:2903
my_type & operator=(const StrExprForType< K > auto &expr)
Оператор присваивания строкового выражения.
Определения sstring.h:3073
constexpr K * reserve_no_preserve(size_t newSize)
Определения sstring.h:3118
my_type & operator=(const my_type &other)
Оператор присваивания копией из строки такого же типа.
Определения sstring.h:2986
constexpr bool is_empty() const noexcept
Пустая ли строка.
Определения sstring.h:3095
lstring(const Op &op, Args &&... args)
Конструктор заполнения с помощью функтора (см. str_mutable::fill).
Определения sstring.h:2957
constexpr K * set_size(size_t newSize)
Устанавливает размер текущей строки, при необходимости выделяя место.
Определения sstring.h:3163
constexpr lstring(size_t count, K pad, Args &&... args)
Конструктор повторения символа.
Определения sstring.h:2829
constexpr lstring(const StrExprForType< K > auto &expr, Args &&... args)
Конструктор из строкового выражения.
Определения sstring.h:2848
constexpr const K * symbols() const noexcept
Указатель на константные символы.
Определения sstring.h:3087
constexpr void clear()
Делает строку пустой, не меняя буфер строки.
Определения sstring.h:3220
my_type & operator=(simple_str< K > other)
Оператор присваивания из simple_str.
Определения sstring.h:3048
constexpr bool empty() const noexcept
Пустая ли строка, для совместимости с std::string.
Определения sstring.h:3099
constexpr void shrink_to_fit()
Уменьшает размер внешнего буфера до минимально возможного для хранения строки. Если строка уместится ...
Определения sstring.h:3206
constexpr lstring(my_type &&other) noexcept
Конструктор перемещения из строки такого же типа.
Определения sstring.h:2932
constexpr K * reserve(size_t newSize)
Выделить буфер, достаточный для размещения newSize символов плюс завершающий ноль.
Определения sstring.h:3140
constexpr K * str() noexcept
Указатель на буфер строки.
Определения sstring.h:3091
constexpr size_t capacity() const noexcept
Текущая ёмкость буфера строки.
Определения sstring.h:3103
constexpr lstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Создать пустой объект.
Определения sstring.h:2784
Класс иммутабельной владеющей строки.
Определения sstring.h:3335
constexpr my_type & operator=(const lstring< K, N, forShared, A > &other)
Оператор присвоения другой строки типа lstring.
Определения sstring.h:3711
constexpr bool empty() const noexcept
Пустая ли строка, для совместимости с std::string.
Определения sstring.h:3764
constexpr bool is_empty() const noexcept
Пустая ли строка.
Определения sstring.h:3760
sstring(s_str other, Args &&... args)
Конструктор из другого строкового объекта.
Определения sstring.h:3474
sstring(size_t count, K pad, Args &&... args)
Конструктор повторения символа.
Определения sstring.h:3504
constexpr const K * symbols() const noexcept
Указатель на символы строки.
Определения sstring.h:3752
constexpr sstring(const my_type &other) noexcept
Конструктор копирования строки.
Определения sstring.h:3562
constexpr my_type & operator=(T &&other)
Оператор присвоения строкового литерала.
Определения sstring.h:3699
sstring(size_t repeat, s_str pattern, Args &&... args)
Конструктор повторения строки.
Определения sstring.h:3489
constexpr my_type & operator=(my_type other) noexcept
Оператор присвоения другой строки того же типа.
Определения sstring.h:3675
static my_type printf(const K *pattern, T &&... args)
Получить строку, отформатированную с помощью std::sprintf.
Определения sstring.h:3780
constexpr sstring(lstring< K, N, true, Allocator > &&src)
Конструктор перемещения из lstring с совместимым с sstring внешним буфером.
Определения sstring.h:3589
constexpr size_t length() const noexcept
Длина строки.
Определения sstring.h:3756
constexpr sstring(my_type &&other) noexcept
Конструктор перемещения.
Определения sstring.h:3573
static my_type format(const FmtString< typename to_std_char_type< K >::type, T... > &fmtString, T &&... args)
Получить строку, отформатированную с помощью std::format.
Определения sstring.h:3794
static my_type vformat(simple_str< K > fmtString, T &&... args)
Получить строку, отформатированную с помощью std::vformat.
Определения sstring.h:3808
sstring(simple_str< O > init)
Инициализация из строкового источника с другим типом символов. Конвертирует через UTF.
Определения sstring.h:3650
constexpr my_type & operator=(simple_str< K > other)
Оператор присвоения другой строки другого типа.
Определения sstring.h:3687
constexpr my_type & make_empty() noexcept
Сделать строку пустой.
Определения sstring.h:3745
constexpr my_type & operator=(const StrExprForType< K > auto &expr)
Оператор присвоения строкового выражения.
Определения sstring.h:3736
sstring(T &&s, Args &&... args)
Инициализация из строкового литерала.
Определения sstring.h:3637
constexpr my_type & operator=(lstring< K, N, true, Allocator > &&other)
Оператор присвоения перемещаемой строки типа lstring с совместимым буфером.
Определения sstring.h:3723
constexpr sstring(const StrExprForType< K > auto &expr, Args &&... args)
Конструктор из строкового выражения.
Определения sstring.h:3523
sstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Конструктор пустой строки.
Определения sstring.h:3459
constexpr ~sstring()
Деструктор строки.
Определения sstring.h:3551
sstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Конструктор из строкового источника с заменой.
Определения sstring.h:3544
Класс с дополнительными константными строковыми алгоритмами.
Определения sstring.h:167
bool starts_with_iu(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки без учёта регистра Unicode символов первой плоскости (<0xFF...
Определения sstring.h:240
int compare_iu(str_piece text) const noexcept
Сравнение строк посимвольно без учёта регистра Unicode символов первой плоскости (<0xFFFF).
Определения sstring.h:204
bool less_iu(str_piece text) const noexcept
Меньше ли строка другой строки посимвольно без учёта регистра Unicode символов первой плоскости (<0xF...
Определения sstring.h:226
constexpr bool ends_with_iu(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой без учёта регистра Unicode символов первой плоскости (<0...
Определения sstring.h:255
R upperred() const
Получить копию строки в верхнем регистре Unicode символов первой плоскости (<0xFFFF).
Определения sstring.h:267
R lowered() const
Получить копию строки в нижнем регистре Unicode символов первой плоскости (<0xFFFF).
Определения sstring.h:279
std::optional< double > to_double() const noexcept
Преобразовать строку в double.
Определения sstring.h:289
constexpr void as_number(T &t) const
Преобразовать строку в целое число.
Определения sstring.h:347
bool equal_iu(str_piece text) const noexcept
Равна ли строка другой строке посимвольно без учёта регистра Unicode символов первой плоскости (<0xFF...
Определения sstring.h:215
void as_number(double &t) const
Преобразовать строку в double.
Определения sstring.h:330
Базовый класс работы с изменяемыми строками
Определения sstring.h:1437
Impl & insert(size_t to, const A &expr)
Вставить строковое выражение в указанную позицию.
Определения sstring.h:1977
Impl & operator<<=(const Op &fillFunction)
Заполняет строку методом fill после конца строки.
Определения sstring.h:2251
Impl & append(const A &expr)
Добавить строковое выражение в конец строки.
Определения sstring.h:1861
Impl & operator<<(const Op &fillFunction)
Вызывает переданный функтор, передав ссылку на себя.
Определения sstring.h:2264
Impl & trim(str_piece pattern)
Удалить символы, входящие в переданную строку, в начале и в конце строки.
Определения sstring.h:1671
Impl & upper_only_ascii()
Преобразовать в верхний регистр ASCII символы.
Определения sstring.h:1735
Impl & lower_only_ascii()
Преобразовать в нижний регистр ASCII символы.
Определения sstring.h:1750
Impl & trim_left()
Удалить пробельные символы в начале строки.
Определения sstring.h:1573
Impl & append_printf(const K *format, T &&... args)
Добавляет отформатированный с помощью sprintf вывод в конец строки.
Определения sstring.h:2353
Impl & trim_right_with_wpaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в конце строки.
Определения sstring.h:1660
Impl & trim_left(str_piece pattern)
Удалить символы, входящие в переданную строку, в начале строки.
Определения sstring.h:1682
Impl & trim_with_spaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в начале и в конце строки.
Определения sstring.h:1634
Impl & prepend(str_piece other)
Добавить другую строку в начало строки.
Определения sstring.h:2001
Impl & append_formatted(const FmtString< fmt_type, T... > &format, T &&... args)
Добавляет отформатированный с помощью std::format вывод в конец строки.
Определения sstring.h:2491
my_type & format(const FmtString< fmt_type, T... > &pattern, T &&... args)
Определения sstring.h:2475
Impl & printf(const K *format, T &&... args)
Форматирует строку помощью sprintf.
Определения sstring.h:2337
Impl & with(const Op &fillFunction, Args &&... args)
Вызов функтора со строкой и переданными аргументами.
Определения sstring.h:2573
Impl & append_vformatted_n(size_t max_write, str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод в конец строки, записывая не более указанног...
Определения sstring.h:2559
Impl & operator<<(const Op &fillFunction)
Заполняет строку методом fill с нулевой позиции.
Определения sstring.h:2238
Impl & vformat(str_piece format, T &&... args)
Форматирует строку с помощью std::vformat.
Определения sstring.h:2507
Impl & change(size_t from, size_t len, const A &expr)
Заменить кусок строки на строковое выражение.
Определения sstring.h:1950
Impl & fill(size_t from, const Op &fillFunction)
Заполнение буфера строки с помощью функтора.
Определения sstring.h:2210
Impl & change(size_t from, size_t len, str_piece other)
Заменить кусок строки на другую строку.
Определения sstring.h:1934
Impl & remove(size_t from, size_t len)
Удалить часть строки.
Определения sstring.h:1990
Impl & trim_left_with_spaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в начале строки.
Определения sstring.h:1647
Impl & trim_left(T &&pattern)
Удалить символы, входящие в строковый литерал, в начале строки.
Определения sstring.h:1608
Impl & trim_right(T &&pattern)
Удалить символы, входящие в строковый литерал, в конце строки.
Определения sstring.h:1621
Impl & trim_right_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в конце строки.
Определения sstring.h:1726
Impl & append_in(size_t pos, str_piece other)
Добавить другую строку, начиная с заданной позиции.
Определения sstring.h:1901
Impl & vformat_from(size_t from, size_t max_write, str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод, начиная с указанной позиции.
Определения sstring.h:2440
Impl & trim_left_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в начале строки.
Определения sstring.h:1715
Impl & insert(size_t to, str_piece other)
Вставить строку в указанную позицию.
Определения sstring.h:1963
Impl & vformat_n(size_t max_write, str_piece format, T &&... args)
Форматирует строку с помощью std::vformat не более указанного размера.
Определения sstring.h:2541
Impl & printf_from(size_t from, const K *format, T &&... args)
Добавляет отформатированный с помощью sprintf вывод, начиная с указанной позиции.
Определения sstring.h:2283
Impl & operator+=(str_piece other)
Добавить другую строку в конец строки.
Определения sstring.h:1872
Impl & trim_right()
Удалить пробельные символы в конце строки.
Определения sstring.h:1582
Impl & append(str_piece other)
Добавить другую строку в конец строки.
Определения sstring.h:1849
Impl & trim_right(str_piece pattern)
Удалить символы, входящие в переданную строку, в конце строки.
Определения sstring.h:1693
Impl & trim_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в начале и в конце строки.
Определения sstring.h:1704
K * str() noexcept
Получить указатель на буфер строки.
Определения sstring.h:1546
Impl & prepend(const A &expr)
Добавить строковое выражение в начало строки.
Определения sstring.h:2013
Impl & trim()
Удалить пробельные символы в начале и в конце строки.
Определения sstring.h:1564
Impl & lower()
Преобразовать в нижний регистр Unicode символы первой плоскости (<0xFFFF).
Определения sstring.h:1784
Impl & replace(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Заменить вхождения подстроки на другую строку.
Определения sstring.h:2030
Impl & upper()
Преобразовать в верхний регистр Unicode символы первой плоскости (<0xFFFF).
Определения sstring.h:1769
Impl & replace_from(const From &f, str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Скопировать строку-источник, заменив вхождения подстрок на другую строку.
Определения sstring.h:2148
Impl & append_vformatted(str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод в конец строки.
Определения sstring.h:2523
Impl & append_in(size_t pos, const A &expr)
Добавить строковое выражение, начиная с заданной позиции.
Определения sstring.h:1919
my_type & format_from(size_t from, const FmtString< fmt_type, T... > &format, T &&... args)
Определения sstring.h:2411
Impl & trim(T &&pattern)
Удалить символы, входящие в строковый литерал, в начале и в конце строки.
Определения sstring.h:1595
Impl & operator+=(const A &expr)
Добавить строковое выражение в конец строки.
Определения sstring.h:1884
constexpr str_piece to_str() const noexcept
Преобразовать себя в "кусок строки", включающий всю строку.
Определения strexpr.h:2654
constexpr size_t size() const
Определения strexpr.h:2595
constexpr void as_number(T &t) const
Преобразовать строку в целое число.
Определения strexpr.h:3438
constexpr str_storable(Args &&... args)
Создать пустой объект.
Определения sstring.h:932
void init_replaced(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0)
Инициализация из строкового источника с заменой.
Определения sstring.h:1019
static my_type upperred_from(const From &f, Args &&... args)
Создать копию переданной строки в верхнем регистре символов Unicode первой плоскости (<0xFFFF).
Определения sstring.h:1280
constexpr void init_from_str_other(s_str other)
Инициализация из другого строкового объекта.
Определения sstring.h:940
constexpr allocator_t & allocator()
Получить аллокатор.
Определения sstring.h:909
constexpr void init_symb_repeat(size_t count, K pad)
Инициализация повторением символа.
Определения sstring.h:976
constexpr void init_str_expr(const A &expr)
Инициализация из строкового выражения.
Определения sstring.h:997
static my_type upperred_only_ascii_from(const From &f, Args &&... args)
Создать строку, копию переданной в верхнем регистре символов ASCII.
Определения sstring.h:1250
static my_type lowered_from(const From &f, Args &&... args)
Создать копию переданной строки в нижнем регистре символов Unicode первой плоскости (<0xFFFF).
Определения sstring.h:1297
constexpr void init_str_repeat(size_t repeat, s_str pattern)
Инициализация повторением строки.
Определения sstring.h:956
static my_type lowered_only_ascii_from(const From &f, Args &&... args)
Создать копию переданной строки в нижнем регистре символов ASCII.
Определения sstring.h:1263
static my_type join(const T &strings, s_str delimiter, bool tail=false, bool skip_empty=false, Args &&... args)
Конкатенация строк из контейнера в одну строку.
Определения sstring.h:1199
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:1318
constexpr s_str_nt to_nts(size_t from=0) const
Получить simple_str_nt, начиная с заданного символа.
Определения sstring.h:1143
Концепт типа, управляющего памятью
Определения sstring.h:1328
Концепт строкового выражения, совместимого с заданным типом символов.
Определения strexpr.h:488
Концепт типа, который не может модифицировать хранимую строку.
Определения sstring.h:851
Концепт типа, который может модифицировать хранимую строку.
Определения sstring.h:844
Концепт типа, который может сохранить строку.
Определения sstring.h:834
Небольшое пространство для методов работы со стандартными строками.
Определения strexpr.h:1569
Пространство имён для объектов библиотеки
Определения sstring.cpp:12
hashStrMap< u16s, T, strhash< u16s >, streql< u16s > > hashStrMapU
Тип хеш-словаря для char16_t строк, регистрозависимый поиск.
Определения sstring.h:4696
hashStrMap< u8s, T, strhashia< u8s >, streqlia< u8s > > hashStrMapAIA
Тип хеш-словаря для char строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4662
hashStrMap< u32s, T, strhashiu< u32s >, streqliu< u32s > > hashStrMapUUIU
Тип хеш-словаря для char32_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4727
hashStrMap< u32s, T, strhashia< u32s >, streqlia< u32s > > hashStrMapUUIA
Тип хеш-словаря для char32_t строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4721
hashStrMap< wchar_t, T, strhashiu< wchar_t >, streqliu< wchar_t > > hashStrMapWIU
Тип хеш-словаря для wchar_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4689
hashStrMap< wchar_t, T, strhashia< wchar_t >, streqlia< wchar_t > > hashStrMapWIA
Тип хеш-словаря для wchar_t строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4682
expr_utf< From, To > e_utf(simple_str< From > from)
Возвращает строковое выражение, преобразующую строку из одного типа символов в другой тип,...
Определения sstring.h:825
hashStrMap< u8s, T, strhash< u8s >, streql< u8s > > hashStrMapA
Тип хеш-словаря для char строк, регистрозависимый поиск.
Определения sstring.h:4656
hashStrMap< u16s, T, strhashiu< u16s >, streqliu< u16s > > hashStrMapUIU
Тип хеш-словаря для char16_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4708
hashStrMap< u16s, T, strhashia< u16s >, streqlia< u16s > > hashStrMapUIA
Тип хеш-словаря для char16_t строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4702
hashStrMap< wchar_t, T, strhash< wchar_t >, streql< wchar_t > > hashStrMapW
Тип хеш-словаря для wchar_t строк, регистрозависимый поиск.
Определения sstring.h:4675
hashStrMap< u8s, T, strhashiu< u8s >, streqliu< u8s > > hashStrMapAIU
Тип хеш-словаря для char строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4668
hashStrMap< u32s, T, strhash< u32s >, streql< u32s > > hashStrMapUU
Тип хеш-словаря для char32_t строк, регистрозависимый поиск.
Определения sstring.h:4715
Объект, позволяющий последовательно копировать содержимое в буфер заданного размера.
Определения sstring.h:4586
bool is_end()
Проверить, что данные ещё не кончились.
Определения sstring.h:4593
size_t store(K *buffer, size_t size)
Сохранить очередную порцию данных в буфер.
Определения sstring.h:4606
Базовый класс для преобразования строковых выражений в стандартные строки
Определения strexpr.h:625
Строковое выражение для конвертации строк в разные виды UTF.
Определения sstring.h:796
Класс, заявляющий, что ссылается на нуль-терминированную строку.
Определения sstring.h:510
constexpr my_type to_nts(size_t from)
Получить нуль-терминированную строку, сдвинув начало на заданное количество символов.
Определения sstring.h:573
constexpr simple_str_nt(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения sstring.h:562
constexpr simple_str_nt(T &&v) noexcept
Конструктор из строкового литерала.
Определения sstring.h:544
constexpr simple_str_nt(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения sstring.h:550
constexpr simple_str_nt(T &&p) noexcept
Явный конструктор из С-строки.
Определения sstring.h:535
Простейший класс иммутабельной не владеющей строки.
Определения sstring.h:374
constexpr simple_str(T &&v) noexcept
Конструктор из строкового литерала.
Определения sstring.h:390
constexpr K operator[](size_t idx) const
Получить символ из указанной позиции. Проверка границ не выполняется.
Определения sstring.h:454
constexpr my_type & remove_suffix(size_t delta)
Укорачивает строку на заданное количество символов.
Определения sstring.h:478
constexpr size_t length() const noexcept
Получить длину строки.
Определения sstring.h:411
constexpr const symb_type * symbols() const noexcept
Получить указатель на константный буфер с символами строки.
Определения sstring.h:418
constexpr my_type & remove_prefix(size_t delta)
Сдвигает начало строки на заданное количество символов.
Определения sstring.h:465
constexpr simple_str(const std::basic_string_view< K, std::char_traits< K > > &s) noexcept
Конструктор из std::basic_string_view.
Определения sstring.h:406
constexpr simple_str(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения sstring.h:395
constexpr simple_str(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения sstring.h:401
constexpr bool is_empty() const noexcept
Проверить, не пуста ли строка.
Определения sstring.h:425
constexpr bool is_same(simple_str< K > other) const noexcept
Проверить, не указывают ли два объекта на одну строку.
Определения sstring.h:434
constexpr bool is_part_of(simple_str< K > other) const noexcept
Проверить, не является ли строка частью другой строки.
Определения sstring.h:443
Простейший класс иммутабельной не владеющей строки.
Определения strexpr.h:4047