21#ifndef __has_declspec_attribute
22#define __has_declspec_attribute(x) 0
24const bool isWindowsOs =
32#ifdef SIMSTR_IN_SHARED
33 #if defined(_MSC_VER) || (defined(__clang__) && __has_declspec_attribute(dllexport))
35 #define SIMSTR_API __declspec(dllexport)
37 #define SIMSTR_API __declspec(dllimport)
39 #elif (defined(__GNUC__) || defined(__GNUG__)) && defined(SIMSTR_EXPORT)
40 #define SIMSTR_API __attribute__((visibility("default")))
52#include <unordered_map>
65#pragma warning(disable : 4201)
71struct unicode_traits {};
74struct unicode_traits<u8s> {
89 static SIMSTR_API
size_t upper(
const u8s*& src,
size_t lenStr, u8s*& dest,
size_t lenBuf);
90 static SIMSTR_API
size_t lower(
const u8s*& src,
size_t len, u8s*& dest,
size_t lenBuf);
92 static SIMSTR_API
int compareiu(
const u8s* text1,
size_t len1,
const u8s* text2,
size_t len2);
94 static SIMSTR_API
size_t hashia(
const u8s* src,
size_t l);
95 static SIMSTR_API
size_t hashiu(
const u8s* src,
size_t l);
99struct unicode_traits<u16s> {
100 static SIMSTR_API
void upper(
const u16s* src,
size_t len, u16s* dest);
101 static SIMSTR_API
void lower(
const u16s* src,
size_t len, u16s* dest);
103 static SIMSTR_API
int compareiu(
const u16s* text1,
size_t len1,
const u16s* text2,
size_t len2);
104 static SIMSTR_API
size_t hashia(
const u16s* src,
size_t l);
105 static SIMSTR_API
size_t hashiu(
const u16s* src,
size_t l);
109struct unicode_traits<u32s> {
110 static SIMSTR_API
void upper(
const u32s* src,
size_t len, u32s* dest);
111 static SIMSTR_API
void lower(
const u32s* src,
size_t len, u32s* dest);
113 static SIMSTR_API
int compareiu(
const u32s* text1,
size_t len1,
const u32s* text2,
size_t len2);
114 static SIMSTR_API
size_t hashia(
const u32s* src,
size_t s);
115 static SIMSTR_API
size_t hashiu(
const u32s* src,
size_t s);
119struct unicode_traits<wchar_t> {
120 static void upper(
const wchar_t* src,
size_t len,
wchar_t* dest) {
121 unicode_traits<wchar_type>::upper(to_w(src), len, to_w(dest));
123 static void lower(
const wchar_t* src,
size_t len,
wchar_t* dest) {
124 unicode_traits<wchar_type>::lower(to_w(src), len, to_w(dest));
127 static int compareiu(
const wchar_t* text1,
size_t len1,
const wchar_t* text2,
size_t len2) {
128 return unicode_traits<wchar_type>::compareiu(to_w(text1), len1, to_w(text2), len2);
130 static size_t hashia(
const wchar_t* src,
size_t s) {
131 return unicode_traits<wchar_type>::hashia(to_w(src), s);
133 static size_t hashiu(
const wchar_t* src,
size_t s) {
134 return unicode_traits<wchar_type>::hashiu(to_w(src), s);
139#if defined(_MSC_VER) && _MSC_VER <= 1933
140template<
typename K,
typename... Args>
141using FmtString = std::_Basic_format_string<K, std::type_identity_t<Args>...>;
142#elif __clang_major__ >= 15 || _MSC_VER > 1933 || __GNUC__ >= 13
143template<
typename K,
typename... Args>
144using FmtString = std::basic_format_string<K, std::type_identity_t<Args>...>;
146template<
typename K,
typename... Args>
147using FmtString = std::basic_string_view<K>;
151SIMSTR_API std::optional<double> impl_to_double(
const K* start,
const K* end);
165template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
166class str_algs :
public str_src_algs<K, StrRef, Impl, Mutable> {
167 constexpr const Impl& d()
const noexcept {
168 return *
static_cast<const Impl*
>(
this);
170 constexpr size_t _len()
const noexcept {
173 constexpr const K* _str()
const noexcept {
174 return d().symbols();
176 constexpr bool _is_empty()
const noexcept {
177 return d().is_empty();
182 using str_piece = StrRef;
183 using traits = ch_traits<K>;
184 using uni = unicode_traits<K>;
185 using uns_type = std::make_unsigned_t<K>;
186 using my_type = Impl;
187 using base = str_src_algs<K, StrRef, Impl, Mutable>;
188 str_algs() =
default;
190 int compare_iu(
const K* text,
size_t len)
const noexcept {
192 return _is_empty() ? 0 : 1;
193 return uni::compareiu(_str(), _len(), text, len);
204 return compare_iu(text.symbols(), text.length());
215 return text.length() == _len() && compare_iu(text.symbols(), text.length()) == 0;
226 return compare_iu(text.symbols(), text.length()) < 0;
230 bool starts_with_iu(
const K* prefix,
size_t len)
const noexcept {
231 return _len() >= len && 0 == uni::compareiu(_str(), len, prefix, len);
240 return starts_with_iu(prefix.symbols(), prefix.length());
244 constexpr bool ends_with_iu(
const K* suffix,
size_t len)
const noexcept {
245 size_t myLen = _len();
246 return myLen >= len && 0 == uni::compareiu(_str() + myLen - len, len, suffix, len);
255 return ends_with_iu(suffix.symbols(), suffix.length());
265 template<
typename R = my_type>
267 return R::upperred_from(d());
277 template<
typename R = my_type>
279 return R::lowered_from(d());
287 template<
bool SkipWS = true,
bool AllowPlus = true>
290 const K* ptr = _str();
291 if constexpr (SkipWS) {
292 while (len && uns_type(*ptr) <=
' ') {
297 if constexpr (AllowPlus) {
298 if (len && *ptr == K(
'+')) {
307 if constexpr(
sizeof(K) == 1) {
309 if (std::from_chars(ptr, ptr + len, d).ec == std::errc{}) {
315 if constexpr (
sizeof(K) == 1) {
316 return impl_to_double((
const char*)ptr, (
const char*)ptr + len);
317 }
else if constexpr (
sizeof(K) == 2) {
318 return impl_to_double((
const char16_t*)ptr, (
const char16_t*)ptr + len);
320 return impl_to_double((
const char32_t*)ptr, (
const char32_t*)ptr + len);
331 t = res ? *res : std::nan(
"0");
345 template<ToIntNumber T>
373struct simple_str : str_algs<K, simple_str<K>, simple_str<K>, false> {
375 using my_type = simple_str<K>;
377 const symb_type* str;
380 constexpr simple_str() =
default;
382 constexpr simple_str(
str_src<K> src) : str(src.str), len(src.len){}
388 template<typename T, size_t N = const_lit_for<K, T>::Count>
389 constexpr simple_str(T&& v) noexcept : str((
const K*)v), len(N - 1) {}
394 constexpr simple_str(
const K* p,
size_t l) noexcept : str(p), len(l) {}
400 constexpr simple_str(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : str(s.data()), len(s.length()) {}
405 constexpr simple_str(
const std::basic_string_view<K, std::char_traits<K>>& s) noexcept : str(s.data()), len(s.length()) {}
410 constexpr size_t length() const noexcept {
417 constexpr const symb_type*
symbols() const noexcept {
433 constexpr bool is_same(simple_str<K> other)
const noexcept {
434 return str == other.str && len == other.len;
442 constexpr bool is_part_of(simple_str<K> other)
const noexcept {
443 return str >= other.str && str + len <= other.str + other.len;
484struct simple_str_selector {
485 using type = simple_str<K>;
509struct simple_str_nt : simple_str<K>, null_terminated<K, simple_str_nt<K>> {
511 using my_type = simple_str_nt<K>;
512 using base = simple_str<K>;
514 constexpr static const K empty_string[1] = {0};
516 simple_str_nt() =
default;
533 template<
typename T>
requires is_one_of_type<std::remove_cvref_t<T>,
const K*, K*>::value
536 base::str = base::len ? p : empty_string;
542 template<typename T, size_t N = const_lit_for<K, T>::Count>
551 template<StrType<K> T>
554 base::len = t.length();
561 constexpr simple_str_nt(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : base(s) {}
563 static const my_type empty_str;
573 if (from > base::len) {
576 return {base::str + from, base::len - from};
581inline const simple_str_nt<K> simple_str_nt<K>::empty_str{simple_str_nt<K>::empty_string, 0};
597template<
typename Src,
typename Dest>
598struct utf_convert_selector;
600template<
typename Src>
601struct utf_convert_selector<Src, Src> {
602 static size_t need_len(
const Src* src,
size_t srcLen) {
605 static size_t convert(
const Src* src,
size_t srcLen, Src* dest) {
606 ch_traits<Src>::copy(dest, src, srcLen + 1);
612struct utf_convert_selector<u8s, u16s> {
613 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
614 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u16s* dest);
618struct utf_convert_selector<u8s, u32s> {
619 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
620 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u32s* 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<u32s, u8s> {
637 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
638 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u8s* dest);
642struct utf_convert_selector<u32s, u16s> {
643 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
644 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u16s* dest);
661template<
typename K,
typename Impl>
662class from_utf_convertible {
664 from_utf_convertible() =
default;
665 using my_type = Impl;
673 requires(!std::is_same_v<O, K>)
675 using from_t = to_base_char_t<O>;
676 using to_t = to_base_char_t<K>;
678 using worker = utf_convert_selector<from_t, to_t>;
679 Impl* d =
static_cast<Impl*
>(
this);
680 size_t len = init.
length();
684 size_t need = worker::need_len((
const from_t*)init.
symbols(), len);
685 K*
str = d->init(need);
687 worker::convert((
const from_t*)init.
symbols(), len, (to_t*)
str);
700template<
typename From,
typename To>
requires (!std::is_same_v<From, To>)
702 using symb_type = To;
703 using from_t = to_base_char_t<From>;
704 using to_t = to_base_char_t<To>;
705 using worker = utf_convert_selector<from_t, to_t>;
711 size_t length()
const noexcept {
712 return worker::need_len((
const from_t*)source_.symbols(), source_.length());
714 To* place(To* ptr)
const noexcept {
715 return ptr + worker::convert((
const from_t*)source_.symbols(), source_.length(), (to_t*)ptr);
731template<
typename To,
typename From>
requires (!std::is_same_v<From, To>)
740template<
typename A,
typename K>
742 A::is_str_storable ==
true;
743 std::is_same_v<typename A::symb_type, K>;
750template<
typename A,
typename K>
757template<
typename A,
typename K>
802template<
typename K,
typename Impl,
typename Allocator>
805 using my_type = Impl;
806 using traits = ch_traits<K>;
807 using allocator_t = Allocator;
817 return *
static_cast<Allocator*
>(
this);
819 constexpr const allocator_t&
allocator()
const {
820 return *
static_cast<const Allocator*
>(
this);
823 using uni = unicode_traits<K>;
825 constexpr Impl& d() noexcept {
826 return *
static_cast<Impl*
>(
this);
828 constexpr const Impl& d() const noexcept {
829 return *
static_cast<const Impl*
>(
this);
838 template<
typename... Args>
839 explicit constexpr str_storable(Args&&... args) : Allocator(std::forward<Args>(args)...) {}
849 K* ptr = d().init(other.
length());
864 size_t l = pattern.
length(), allLen = l * repeat;
866 K* ptr = d().init(allLen);
867 for (
size_t i = 0; i < repeat; i++) {
868 traits::copy(ptr, pattern.
symbols(), l);
885 K*
str = d().init(count);
886 traits::assign(
str, count, pad);
903 template<StrExprForType<K> A>
905 size_t len = expr.length();
907 *expr.place((
typename A::symb_type*)d().init(len)) = 0;
925 template<StrType<K> From>
926 void init_replaced(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0) {
927 auto findes = f.find_all(pattern, offset, maxCount);
928 if (!findes.size()) {
929 new (
this) my_type{f};
932 size_t srcLen = f.length();
933 size_t newSize = srcLen +
static_cast<ptrdiff_t
>(repl.len - pattern.len) * findes.size();
936 new (
this) my_type{};
940 K* ptr = d().init(newSize);
943 for (
const auto& s: findes) {
944 size_t copyLen = s - from;
946 traits::copy(ptr, src + from, copyLen);
950 traits::copy(ptr, repl.str, repl.len);
953 from = s + pattern.len;
957 traits::copy(ptr, src + from, srcLen);
963 template<StrType<K> From,
typename Op1,
typename... Args>
964 requires std::is_constructible_v<allocator_t, Args...>
965 static my_type changeCaseAscii(
const From& f,
const Op1& opMakeNeedCase, Args&&... args) {
966 my_type result{std::forward<Args>(args)...};
967 size_t len = f.length();
969 const K* source = f.symbols();
970 K* destination = result.init(len);
971 for (
size_t l = 0; l < len; l++) {
972 destination[l] = opMakeNeedCase(source[l]);
981 template<
typename T,
bool Dummy = true>
983 template<
typename From,
typename Op1,
typename... Args>
984 requires std::is_constructible_v<allocator_t, Args...>
985 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
986 my_type result{std::forward<Args>(args)...};
987 size_t len = f.length();
989 opChangeCase(f.symbols(), len, result.init(len));
997 struct ChangeCase<u8s, Dummy> {
998 template<
typename From,
typename Op1,
typename... Args>
999 requires std::is_constructible_v<allocator_t, Args...>
1000 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
1001 my_type result{std::forward<Args>(args)...};
1003 size_t len = f.length();
1005 const K* ptr = f.symbols();
1006 K* pWrite = result.init(len);
1008 const u8s* source = ptr;
1010 size_t newLen = opChangeCase(source, len, dest, len);
1014 result.set_size(newLen);
1015 }
else if (newLen > len) {
1018 size_t readed =
static_cast<size_t>(source - ptr);
1019 size_t writed =
static_cast<size_t>(dest - pWrite);
1020 pWrite = result.set_size(newLen);
1021 dest = pWrite + writed;
1022 opChangeCase(source, len - readed, dest, newLen - writed);
1032 inline static constexpr bool is_str_storable =
true;
1039 constexpr operator const K*()
const noexcept {
1040 return d().symbols();
1050 constexpr s_str_nt
to_nts(
size_t from = 0)
const {
1051 size_t len = d().
length();
1055 return {d().symbols() + from, len - from};
1063 constexpr operator s_str_nt()
const {
1064 return {d().symbols(), d().length()};
1104 template<
typename T,
typename... Args>
1105 requires std::is_constructible_v<allocator_t, Args...>
1106 static my_type
join(
const T& strings, s_str delimiter,
bool tail =
false,
bool skip_empty =
false, Args&&... args) {
1107 my_type result(std::forward<Args>(args)...);
1108 if (strings.size()) {
1109 if (strings.size() == 1 && (!delimiter.
length() || !tail)) {
1110 result = strings.front();
1112 size_t commonLen = 0;
1113 for (
const auto& t: strings) {
1114 size_t len = t.length();
1115 if (len > 0 || !skip_empty) {
1116 if (commonLen > 0) {
1117 commonLen += delimiter.len;
1122 commonLen += (tail && delimiter.len > 0 && (commonLen > 0 || (!skip_empty && strings.size() > 0))? delimiter.len : 0);
1124 K* ptr = result.init(commonLen);
1126 for (
const auto& t: strings) {
1127 size_t copyLen = t.length();
1128 if (delimiter.len > 0 && write != ptr && (copyLen || !skip_empty)) {
1129 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1130 write += delimiter.len;
1132 ch_traits<K>::copy(write, t.symbols(), copyLen);
1135 if (delimiter.len > 0 && tail && (write != ptr || (!skip_empty && strings.size() > 0))) {
1136 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1137 write += delimiter.len;
1141 result.create_empty();
1155 template<StrType<K> From,
typename... Args>
1156 requires std::is_constructible_v<allocator_t, Args...>
1158 return changeCaseAscii(f, makeAsciiUpper<K>, std::forward<Args>(args)...);
1168 template<StrType<K> From,
typename... Args>
1169 requires std::is_constructible_v<allocator_t, Args...>
1171 return changeCaseAscii(f, makeAsciiLower<K>, std::forward<Args>(args)...);
1185 template<StrType<K> From,
typename... Args>
1186 requires std::is_constructible_v<allocator_t, Args...>
1188 return ChangeCase<K>::changeCase(f, uni::upper, std::forward<Args>(args)...);
1202 template<StrType<K> From,
typename... Args>
1203 requires std::is_constructible_v<allocator_t, Args...>
1205 return ChangeCase<K>::changeCase(f, uni::lower, std::forward<Args>(args)...);
1223 template<StrType<K> From,
typename... Args>
1224 requires std::is_constructible_v<allocator_t, Args...>
1225 static my_type
replaced_from(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args) {
1226 return my_type{f, pattern, repl, offset, maxCount, std::forward<Args>(args)...};
1236 { a.allocate(size) } -> std::same_as<void*>;
1237 { a.deallocate(void_ptr) }
noexcept -> std::same_as<void>;
1240struct printf_selector {
1241 template<
typename K,
typename... T>
requires (is_one_of_std_char_v<K>)
1242 static int snprintf(K* buffer,
size_t count,
const K* format, T&&... args) {
1243 if constexpr (
sizeof(K) == 1) {
1245 return std::snprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), std::forward<T>(args)...);
1249 return _sprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1253 return std::swprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1257 return _swprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1261 template<
typename K>
requires (is_one_of_std_char_v<K>)
1262 static int vsnprintf(K* buffer,
size_t count,
const K* format, va_list args) {
1263 if constexpr (std::is_same_v<K, u8s>) {
1265 return std::vsnprintf(buffer, count, format, args);
1269 return _vsprintf_p(buffer, count, format, args);
1273 return std::vswprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args);
1277 return _vswprintf_p(buffer, count, format, args);
1283inline size_t grow2(
size_t ret,
size_t currentCapacity) {
1284 return ret <= currentCapacity ? ret : ret * 2;
1325template<
typename K,
typename Impl>
1328 using my_type = Impl;
1332 return *
static_cast<Impl*
>(
this);
1334 const Impl& d()
const {
1335 return *
static_cast<const Impl*
>(
this);
1337 size_t _len()
const noexcept {
1338 return d().length();
1340 const K* _str()
const noexcept {
1341 return d().symbols();
1344 using symb_type = K;
1345 using traits = ch_traits<K>;
1346 using uni = unicode_traits<K>;
1347 using uns_type = std::make_unsigned_t<K>;
1349 template<
typename Op>
1350 Impl& make_trim_op(
const Op& op) {
1351 str_piece me = d(), pos = op(me);
1352 if (me.
length() != pos.length()) {
1353 if (me.
symbols() != pos.symbols())
1354 traits::move(
const_cast<K*
>(me.
symbols()), pos.symbols(), pos.length());
1355 d().set_size(pos.length());
1361 Impl& commonChangeCase() {
1362 size_t len = _len();
1364 Op(_str(), len,
str());
1371 template<
typename T,
bool Dummy = true>
1373 static Impl&
upper(Impl& obj) {
1374 return obj.template commonChangeCase<unicode_traits<K>::upper>();
1376 static Impl&
lower(Impl& obj) {
1377 return obj.template commonChangeCase<unicode_traits<K>::lower>();
1382 Impl& utf8CaseChange() {
1385 size_t len = _len();
1387 u8s* writePos =
str();
1388 const u8s *startData = writePos, *readPos = writePos;
1389 size_t newLen = Op(readPos, len, writePos, len);
1393 d().set_size(newLen);
1394 }
else if (newLen > len) {
1397 size_t readed =
static_cast<size_t>(readPos - startData);
1398 size_t writed =
static_cast<size_t>(writePos - startData);
1399 d().set_size(newLen);
1401 readPos = startData + readed;
1402 writePos =
const_cast<u8s*
>(startData) + writed;
1403 Op(readPos, len - readed, writePos, newLen - writed);
1408 template<
bool Dummy>
1409 struct CaseTraits<u8s, Dummy> {
1410 static Impl&
upper(Impl& obj) {
1411 return obj.template utf8CaseChange<unicode_traits<u8s>::upper>();
1413 static Impl&
lower(Impl& obj) {
1414 return obj.template utf8CaseChange<unicode_traits<u8s>::lower>();
1418 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count>
1419 Impl& makeTrim(T&& pattern) {
1420 return make_trim_op(trim_operator<S, K, N - 1, withSpaces>{pattern});
1423 template<TrimS
ides S,
bool withSpaces>
1424 Impl& makeTrim(str_piece pattern) {
1425 return make_trim_op(trim_operator<S, K, 0, withSpaces>{{pattern}});
1444 explicit operator K*()
noexcept {
1454 return make_trim_op(SimpleTrim<TrimSides::TrimAll, K>{});
1463 return make_trim_op(SimpleTrim<TrimSides::TrimLeft, K>{});
1472 return make_trim_op(SimpleTrim<TrimSides::TrimRight, K>{});
1482 template<typename T, size_t N = const_lit_for<K, T>::Count>
1483 requires is_const_pattern<N>
1485 return makeTrim<TrimSides::TrimAll, false>(pattern);
1495 template<typename T, size_t N = const_lit_for<K, T>::Count>
1496 requires is_const_pattern<N>
1498 return makeTrim<TrimSides::TrimLeft, false>(pattern);
1508 template<typename T, size_t N = const_lit_for<K, T>::Count>
1509 requires is_const_pattern<N>
1511 return makeTrim<TrimSides::TrimRight, false>(pattern);
1521 template<typename T, size_t N = const_lit_for<K, T>::Count>
1522 requires is_const_pattern<N>
1524 return makeTrim<TrimSides::TrimAll, true>(pattern);
1534 template<typename T, size_t N = const_lit_for<K, T>::Count>
1535 requires is_const_pattern<N>
1537 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1547 template<typename T, size_t N = const_lit_for<K, T>::Count>
1548 requires is_const_pattern<N>
1550 return makeTrim<TrimSides::TrimRight, true>(pattern);
1561 return pattern.
length() ? makeTrim<TrimSides::TrimAll, false>(pattern) : d();
1572 return pattern.
length() ? makeTrim<TrimSides::TrimLeft, false>(pattern) : d();
1583 return pattern.
length() ? makeTrim<TrimSides::TrimRight, false>(pattern) : d();
1594 return makeTrim<TrimSides::TrimAll, true>(pattern);
1605 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1616 return makeTrim<TrimSides::TrimRight, true>(pattern);
1626 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1628 if (isAsciiLower(s))
1641 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1643 if (isAsciiUpper(s))
1661 return CaseTraits<K>::upper(d());
1676 return CaseTraits<K>::lower(d());
1680 template<
typename T>
1681 Impl& changeImpl(
size_t from,
size_t len, T expr) {
1682 size_t myLen = _len();
1686 if (from + len > myLen) {
1690 size_t otherLen = expr.length();
1691 if (len == otherLen) {
1692 expr.place(buffer + from);
1694 size_t tailLen = myLen - from - len;
1695 if (len > otherLen) {
1696 expr.place(buffer + from);
1697 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1698 d().set_size(myLen - (len - otherLen));
1700 buffer = d().set_size(myLen + otherLen - len);
1701 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1702 expr.place(buffer + from);
1708 template<
typename T>
1709 Impl& appendImpl(T expr) {
1710 if (
size_t len = expr.length(); len) {
1711 size_t size = _len();
1712 expr.place(d().set_size(size + len) + size);
1717 template<
typename T>
1718 Impl& appendFromImpl(
size_t pos, T expr) {
1721 if (
size_t len = expr.length())
1722 expr.place(d().set_size(pos + len) + pos);
1729 inline static constexpr bool is_str_mutable =
true;
1739 return appendImpl<str_piece>(other);
1749 template<StrExprForType<K> A>
1751 return appendImpl<const A&>(expr);
1762 return appendImpl<str_piece>(other);
1772 template<StrExprForType<K> A>
1774 return appendImpl<const A&>(expr);
1791 return appendFromImpl<str_piece>(pos, other);
1807 template<StrExprForType<K> A>
1809 return appendFromImpl<const A&>(pos, expr);
1823 Impl&
change(
size_t from,
size_t len, str_piece other) {
1824 return changeImpl<str_piece>(from, len, other);
1838 template<StrExprForType<K> A>
1839 Impl&
change(
size_t from,
size_t len,
const A& expr) {
1840 return changeImpl<const A&>(from, len, expr);
1853 return changeImpl<str_piece>(to, 0, other);
1865 template<StrExprForType<K> A>
1867 return changeImpl<const A&>(to, 0, expr);
1880 return changeImpl<const empty_expr<K>&>(from, len, {});
1891 return changeImpl<str_piece>(0, 0, other);
1901 template<StrExprForType<K> A>
1903 return changeImpl<const A&>(0, 0, expr);
1919 Impl&
replace(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
1920 offset = d().find(pattern, offset);
1921 if (offset == str::npos) {
1926 size_t replLength = repl.
length(), patternLength = pattern.
length();
1928 if (patternLength == replLength) {
1932 while (maxCount--) {
1933 traits::copy(ptr + offset, repl.
symbols(), replLength);
1934 offset = d().find(pattern, offset + replLength);
1935 if (offset == str::npos)
1938 }
else if (patternLength > replLength) {
1942 traits::copy(ptr + offset, repl.
symbols(), replLength);
1943 size_t posWrite = offset + replLength;
1944 offset += patternLength;
1946 while (--maxCount) {
1947 size_t idx = d().find(pattern, offset);
1948 if (idx == str::npos)
1950 size_t lenOfPiece = idx - offset;
1951 traits::move(ptr + posWrite, ptr + offset, lenOfPiece);
1952 posWrite += lenOfPiece;
1953 traits::copy(ptr + posWrite, repl.
symbols(), replLength);
1954 posWrite += replLength;
1955 offset = idx + patternLength;
1957 size_t tailLen = _len() - offset;
1958 traits::move(ptr + posWrite, ptr + offset, tailLen);
1959 d().set_size(posWrite + tailLen);
1961 struct replace_grow_helper {
1962 replace_grow_helper(my_type& src, str_piece p, str_piece r,
size_t mc,
size_t d)
1963 : source(src), pattern(p), repl(r), maxCount(mc), delta(d) {}
1965 const str_piece pattern;
1966 const str_piece repl;
1970 K* reserve_for_copy{};
1971 size_t end_of_piece{};
1972 size_t total_length{};
1975 size_t found[16] = {offset};
1977 offset += pattern.
length();
1980 for (; idx < std::size(found) && maxCount > 0; idx++, maxCount--) {
1981 found[idx] = source.find(pattern, offset);
1982 if (found[idx] == str::npos) {
1985 offset = found[idx] + pattern.
length();
1988 if (idx == std::size(found) && maxCount > 0 && (offset = source.find(pattern, offset)) != str::npos) {
1993 if (!reserve_for_copy) {
1996 end_of_piece = source.length();
1997 total_length = end_of_piece + all_delta;
1998 reserve_for_copy = source.alloc_for_copy(total_length);
2000 K* dst_start = reserve_for_copy;
2001 const K* src_start = source.symbols();
2003 size_t pos = found[idx] + pattern.
length();
2004 size_t lenOfPiece = end_of_piece - pos;
2005 ch_traits<K>::move(dst_start + pos + all_delta, src_start + pos, lenOfPiece);
2006 ch_traits<K>::copy(dst_start + pos + all_delta - repl.
length(), repl.
symbols(), repl.
length());
2008 end_of_piece = found[idx];
2010 if (!all_delta && reserve_for_copy != src_start) {
2011 ch_traits<K>::copy(dst_start, src_start, found[0]);
2014 } helper(d(), pattern, repl, maxCount, repl.
length() - pattern.
length());
2015 helper.replace(offset);
2016 d().set_from_copy(helper.reserve_for_copy, helper.total_length);
2036 template<StrType<K> From>
2037 Impl&
replace_from(
const From& f, str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
2039 K* dst = d().reserve_no_preserve(f.length());
2042 if (maxCount == 0) {
2045 size_t src_length = f.length(), start = 0;
2046 while (maxCount--) {
2047 offset = f.find(pattern, offset);
2048 if (offset == str::npos) {
2051 size_t piece_len = offset - start;
2053 ch_traits<K>::copy(dst, src + start, piece_len);
2061 offset += pattern.
length();
2064 if (start < src_length) {
2065 ch_traits<K>::copy(dst, src + start, src_length - start);
2067 d().set_size(src_length - delta);
2070 replace(pattern, repl, offset, maxCount);
2098 template<
typename Op>
2099 Impl&
fill(
size_t from,
const Op& fillFunction) {
2100 size_t size = _len();
2103 size_t capacity = d().capacity();
2107 size_t needSize = (size_t)fillFunction(ptr + from, capacity);
2108 if (capacity >= needSize) {
2109 d().set_size(from + needSize);
2112 ptr = from == 0 ? d().reserve_no_preserve(needSize) : d().set_size(from + needSize);
2113 capacity = d().capacity() - from;
2125 template<
typename Op>
2126 requires std::is_invocable_v<Op, K*, size_t>
2128 return fill(0, fillFunction);
2138 template<
typename Op>
2139 requires std::is_invocable_v<Op, K*, size_t>
2141 return fill(_len(), fillFunction);
2151 template<
typename Op>
2152 requires std::is_invocable_v<Op, my_type&>
2171 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2173 size_t size = _len();
2176 size_t capacity = d().capacity();
2187 if constexpr (
sizeof(K) == 1 && !isWindowsOs) {
2188 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2189 if (result > (
int)capacity) {
2190 ptr = from == 0 ? d().reserve_no_preserve(result) : d().set_size(from + result);
2191 result = printf_selector::snprintf(ptr + from, result + 1,
format, std::forward<T>(args)...);
2195 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2202 ptr = from == 0 ? d().reserve_no_preserve(capacity) : d().set_size(from + capacity);
2208 d().set_size(
static_cast<size_t>(traits::length(_str())));
2210 d().set_size(from + result);
2225 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2241 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2252 inline static K pad;
2253 K& operator*()
const {
2256 writer& operator++() {
2257 if (writed < max_write) {
2260 size_t l = ptr - store->begin();
2262 ptr = store->set_size(l + std::min(l / 2,
size_t(8192))) + l;
2270 writer operator++(
int) {
2276 writer(my_type& s, K* p, K* e,
size_t ml) : store(&s), ptr(p), end(e), max_write(ml) {}
2278 writer(
const writer&) =
delete;
2279 writer& operator=(
const writer&)
noexcept =
delete;
2280 writer(writer&&) noexcept = default;
2281 writer& operator=(writer&&) noexcept = default;
2282 using difference_type =
int;
2284 using fmt_type = to_std_char_t<K>;
2299 template<typename... T> requires (is_one_of_std_char_v<K>)
2301 size_t size = _len();
2304 size_t capacity = d().capacity();
2307 auto result = std::format_to(writer{d(), ptr + from, ptr + capacity, size_t(-1)},
2308 std::forward<decltype(format)>(
format), std::forward<T>(args)...);
2309 d().set_size(result.ptr - _str());
2328 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2330 size_t size = _len();
2333 size_t capacity = d().capacity();
2336 if constexpr (std::is_same_v<K, u8s>) {
2337 auto result = std::vformat_to(
2338 writer{d(), ptr + from, ptr + capacity, max_write},
2339 std::basic_string_view<K>{
format.symbols(),
format.length()},
2340 std::make_format_args(args...));
2341 d().set_size(result.ptr - _str());
2343 auto result = std::vformat_to(
2344 writer{d(), to_one_of_std_char(ptr + from), ptr + capacity, max_write},
2345 std::basic_string_view<wchar_t>{to_one_of_std_char(
format.symbols()),
format.length()},
2346 std::make_wformat_args(std::forward<T>(args)...));
2347 d().set_size(result.ptr - _str());
2363 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2364 Impl&
format(
const FmtString<fmt_type, T...>& pattern, T&&... args) {
2365 return format_from(0, pattern, std::forward<T>(args)...);
2379 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2395 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2411 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2429 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2447 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2461 template<
typename Op,
typename... Args>
2462 Impl&
with(
const Op& fillFunction, Args&&... args) {
2463 fillFunction(d(), std::forward<Args>(args)...);
2469struct SharedStringData {
2470 std::atomic_size_t ref_;
2472 SharedStringData() {
2476 return (K*)(
this + 1);
2479 ref_.fetch_add(1, std::memory_order_relaxed);
2481 void decr(Allocatorable
auto& allocator) {
2482 size_t val = ref_.fetch_sub(1, std::memory_order_relaxed);
2484 allocator.deallocate(
this);
2487 static SharedStringData<K>* create(
size_t l, Allocatorable
auto& allocator) {
2488 size_t size =
sizeof(SharedStringData<K>) + (l + 1) *
sizeof(K);
2489 return new (allocator.allocate(size)) SharedStringData();
2491 static SharedStringData<K>* from_str(
const K* p) {
2492 return (SharedStringData<K>*)p - 1;
2494 K* place(K* p,
size_t len) {
2495 ch_traits<K>::copy(p, str(), len);
2502class string_common_allocator {
2504 void* allocate(
size_t bytes) {
2505 return new char[bytes];
2507 void deallocate(
void* address)
noexcept {
2508 delete []
static_cast<char*
>(address);
2512string_common_allocator default_string_allocator_selector(...);
2519using allocator_string =
decltype(default_string_allocator_selector(
int(0)));
2521template<
typename K, Allocatorable Allocator>
2553template<
typename K,
size_t N,
bool forShared = false, Allocatorable Allocator = allocator_
string>
2555 public str_algs<K, simple_str<K>, lstring<K, N, forShared, Allocator>, true>,
2556 public str_mutable<K, lstring<K, N, forShared, Allocator>>,
2557 public str_storable<K, lstring<K, N, forShared, Allocator>, Allocator>,
2558 public null_terminated<K, lstring<K, N, forShared, Allocator>>,
2559 public from_utf_convertible<K, lstring<K, N, forShared, Allocator>> {
2561 using symb_type = K;
2563 using allocator_t = Allocator;
2572 extra = forShared ?
sizeof(SharedStringData<K>) : 0,
2575 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
2576 using base_storable = str_storable<K, my_type, Allocator>;
2577 using base_mutable = str_mutable<K, my_type>;
2578 using base_utf = from_utf_convertible<K, my_type>;
2579 using traits = ch_traits<K>;
2580 using s_str = base_storable::s_str;
2582 friend base_storable;
2583 friend base_mutable;
2585 friend class sstring<K, Allocator>;
2592 K local_[LocalCapacity + 1];
2595 constexpr void create_empty() {
2600 constexpr static size_t calc_capacity(
size_t s) {
2601 const int al =
alignof(std::max_align_t) < 16 ? 16 : alignof(std::max_align_t);
2602 size_t real_need = (s + 1) *
sizeof(K) + extra;
2603 size_t aligned_alloced = (real_need + al - 1) / al * al;
2604 return (aligned_alloced - extra) /
sizeof(K) - 1;
2607 constexpr K* init(
size_t s) {
2608 size_t need_cap = s;
2609 if (need_cap > LocalCapacity) {
2610 need_cap = calc_capacity(s);
2611 data_ = alloc_place(need_cap);
2612 capacity_ = need_cap;
2620 constexpr bool is_alloced() const noexcept {
2621 return data_ != local_;
2624 constexpr void dealloc() {
2626 base_storable::allocator().deallocate(to_real_address(data_));
2631 constexpr static K* to_real_address(
void* ptr) {
2632 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) - extra);
2634 constexpr static K* from_real_address(
void* ptr) {
2635 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) + extra);
2638 constexpr K* alloc_place(
size_t newSize) {
2639 return from_real_address(base_storable::allocator().allocate((newSize + 1) *
sizeof(K) + extra));
2643 constexpr K* alloc_for_copy(
size_t newSize) {
2644 if (capacity() >= newSize) {
2649 return alloc_place(calc_capacity(newSize));
2653 constexpr void set_from_copy(K* ptr,
size_t newSize) {
2659 capacity_ = calc_capacity(newSize);
2672 template<
typename... Args>
2673 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
2674 constexpr lstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
2675 : base_storable(std::forward<Args>(args)...) {
2687 template<
typename... Args>
2688 requires std::is_constructible_v<allocator_t, Args...>
2689 constexpr lstring(s_str other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2702 template<
typename... Args>
2703 requires std::is_constructible_v<allocator_t, Args...>
2704 constexpr lstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2717 template<
typename... Args>
2718 requires std::is_constructible_v<allocator_t, Args...>
2719 constexpr lstring(
size_t count, K pad, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2736 template<
typename... Args>
2737 requires std::is_constructible_v<allocator_t, Args...>
2757 template<StrType<K> From,
typename... Args>
2758 requires std::is_constructible_v<allocator_t, Args...>
2759 constexpr lstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
2760 : base_storable(std::forward<Args>(args)...) {
2768 constexpr ~lstring() {
2780 K* buf = init(other.size_);
2781 const size_t short_str = 16 / sizeof(K);
2782 if (LocalCapacity >= short_str - 1 && other.size_ < short_str) {
2783 struct copy { char buf[16]; };
2784 *reinterpret_cast<copy*>(buf) = *reinterpret_cast<const copy*>(other.symbols());
2786 traits::copy(buf, other.symbols(), other.size_ + 1);
2798 template<
typename... Args>
2799 requires(
sizeof...(Args) > 0 && std::is_convertible_v<allocator_t, Args...>)
2800 constexpr lstring(
const my_type& other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2802 traits::copy(init(other.size_), other.symbols(), other.size_ + 1);
2813 template<typename T, size_t I = const_lit_for<K, T>::Count,
typename... Args>
2814 requires std::is_constructible_v<allocator_t, Args...>
2815 constexpr lstring(T&& value, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2816 if constexpr (I > 1) {
2817 K* ptr = init(I - 1);
2818 traits::copy(ptr, (
const K*)value, I - 1);
2829 constexpr lstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
2831 size_ = other.size_;
2832 if (other.is_alloced()) {
2833 data_ = other.data_;
2834 capacity_ = other.capacity_;
2837 traits::copy(local_, other.local_, size_ + 1);
2839 other.data_ = other.local_;
2841 other.local_[0] = 0;
2852 template<
typename Op,
typename... Args>
2853 requires(std::is_constructible_v<Allocator, Args...> && (std::is_invocable_v<Op, my_type&> || std::is_invocable_v<Op, K*, size_t>))
2854 lstring(
const Op& op, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2858 template<
typename O>
2859 requires(!std::is_same_v<O, K>)
2861 this->init_from_utf_convertible(init);
2864 template<
typename O,
typename I,
bool M>
2865 requires(!std::is_same_v<O, K>)
2866 lstring(
const str_algs<O, simple_str<O>, I, M>& init) {
2867 this->init_from_utf_convertible(init.
to_str());
2886 if (&other !=
this) {
2888 size_ = other.size_;
2903 if (&other !=
this) {
2905 if (other.is_alloced()) {
2906 data_ = other.data_;
2907 capacity_ = other.capacity_;
2909 traits::copy(data_, other.local_, other.size_ + 1);
2912 size_ = other.size_;
2913 other.create_empty();
2918 my_type& assign(
const K* other,
size_t len) {
2920 bool isIntersect = other >= data_ && other + len <= data_ + size_;
2926 if (other > data_) {
2927 traits::move(data_, other, len);
2930 traits::copy(reserve_no_preserve(len), other, len);
2946 return assign(other.str, other.len);
2956 template<typename T, size_t S = const_lit_for<K, T>::Count>
2958 return assign((
const K*)other, S - 1);
2971 size_t newLen = expr.
length();
3017 newSize = calc_capacity(newSize);
3018 K* newData = alloc_place(newSize);
3021 capacity_ = newSize;
3039 newSize = calc_capacity(newSize);
3040 K* newData = alloc_place(newSize);
3041 traits::copy(newData, data_, size_);
3044 capacity_ = newSize;
3062 if (newSize > cap) {
3063 size_t needPlace = newSize;
3064 if (needPlace < (cap + 1) * 2) {
3065 needPlace = (cap + 1) * 2 - 1;
3078 return !is_alloced();
3088 for (
size_t i = 0; i < cap; i++) {
3089 if (data_[i] == 0) {
3104 size_t need_capacity = calc_capacity(size_);
3105 if (is_alloced() && capacity_ > need_capacity) {
3106 K* newData = size_ <=
LocalCapacity ? local_ : alloc_place(need_capacity);
3107 traits::copy(newData, data_, size_ + 1);
3112 capacity_ = need_capacity;
3128template<
size_t N = 15>
3129using lstringa = lstring<u8s, N>;
3130template<
size_t N = 15>
3131using lstringb = lstring<ubs, N>;
3132template<
size_t N = 15>
3133using lstringw = lstring<wchar_t, N>;
3134template<
size_t N = 15>
3135using lstringu = lstring<u16s, N>;
3136template<
size_t N = 15>
3137using lstringuu = lstring<u32s, N>;
3139template<
size_t N = 15>
3140using lstringsa = lstring<u8s, N, true>;
3141template<
size_t N = 15>
3142using lstringsb = lstring<ubs, N, true>;
3143template<
size_t N = 15>
3144using lstringsw = lstring<wchar_t, N, true>;
3145template<
size_t N = 15>
3146using lstringsu = lstring<u16s, N, true>;
3147template<
size_t N = 15>
3148using lstringsuu = lstring<u32s, N, true>;
3151template<typename T, typename K = typename const_lit<T>::symb_type>
3152auto getLiteralType(T&&) {
3156template<
size_t Arch,
size_t L>
3157inline constexpr const size_t _local_count = 0;
3160inline constexpr const size_t _local_count<8, 1> = 23;
3162inline constexpr const size_t _local_count<8, 2> = 15;
3164inline constexpr const size_t _local_count<8, 4> = 7;
3166inline constexpr const size_t _local_count<4, 1> = 15;
3168inline constexpr const size_t _local_count<4, 2> = 11;
3170inline constexpr const size_t _local_count<4, 4> = 5;
3173constexpr const size_t local_count = _local_count<
sizeof(size_t),
sizeof(T)>;
3227template<
typename K, Allocatorable Allocator = allocator_
string>
3228class decl_empty_bases sstring :
3229 public str_algs<K, simple_str<K>, sstring<K, Allocator>, false>,
3230 public str_storable<K, sstring<K, Allocator>, Allocator>,
3231 public null_terminated<K, sstring<K, Allocator>>,
3232 public from_utf_convertible<K, sstring<K, Allocator>> {
3234 using symb_type = K;
3235 using uns_type = std::make_unsigned_t<K>;
3236 using my_type = sstring<K, Allocator>;
3237 using allocator_t = Allocator;
3239 enum { LocalCount = local_count<K> };
3242 using base_algs = str_algs<K, simple_str<K>, my_type,
false>;
3244 using base_utf = from_utf_convertible<K, my_type>;
3245 using traits = ch_traits<K>;
3246 using uni = unicode_traits<K>;
3247 using s_str = base_storable::s_str;
3249 friend base_storable;
3252 enum Types { Local, Constant, Shared };
3265 uns_type localRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
3280 constexpr void create_empty() {
3282 localRemain_ = LocalCount;
3285 constexpr K* init(
size_t s) {
3286 if (s > LocalCount) {
3294 localRemain_ = LocalCount - s;
3299 K* set_size(
size_t newSize) {
3305 if (newSize !=
size) {
3306 if (type_ == Constant) {
3309 if (newSize <= LocalCount) {
3310 if (type_ == Shared) {
3311 SharedStringData<K>* str_buf = SharedStringData<K>::from_str(sstr_);
3312 traits::copy(buf_, sstr_, newSize);
3316 localRemain_ = LocalCount - newSize;
3318 if (type_ == Shared) {
3319 if (newSize >
size || (newSize > 64 && newSize <=
size * 3 / 4)) {
3321 traits::copy(newStr, sstr_, newSize);
3325 }
else if (type_ == Local) {
3328 traits::copy(newStr, buf_,
size);
3337 K*
str = type_ == Local ? buf_ : (K*)sstr_;
3354 template<
typename... Args>
3355 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
3356 sstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
3357 : base_storable(std::forward<Args>(args)...) {
3369 template<
typename... Args>
3370 requires std::is_constructible_v<allocator_t, Args...>
3371 sstring(s_str other, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3384 template<
typename... Args>
3385 requires std::is_constructible_v<allocator_t, Args...>
3386 sstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3399 template<
typename... Args>
3400 requires std::is_constructible_v<allocator_t, Args...>
3401 sstring(
size_t count, K pad, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3418 template<
typename... Args>
3419 requires std::is_constructible_v<allocator_t, Args...>
3439 template<StrType<K> From,
typename... Args>
3440 requires std::is_constructible_v<allocator_t, Args...>
3441 sstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
3442 : base_storable(std::forward<Args>(args)...) {
3449 if (type_ == Shared) {
3459 constexpr sstring(
const my_type& other) noexcept : base_storable(other.allocator()) {
3460 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3461 if (type_ == Shared)
3462 SharedStringData<K>::from_str(sstr_)->incr();
3470 constexpr sstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
3471 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3472 other.create_empty();
3489 if (src.is_alloced()) {
3493 if (
size > LocalCount) {
3500 new (SharedStringData<K>::from_str(
str)) SharedStringData<K>();
3505 localRemain_ = LocalCount -
size;
3506 traits::copy(buf_,
str,
size + 1);
3514 K*
str = init(src.size_);
3532 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename... Args>
3533 requires std::is_constructible_v<allocator_t, Args...>
3534 sstring(T&& s, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3537 cstr_ = (
const K*)s;
3546 template<
typename O>
requires(!std::is_same_v<O, K>)
3548 this->init_from_utf_convertible(init);
3551 template<
typename O,
typename I,
bool M>
requires(!std::is_same_v<O, K>)
3553 this->init_from_utf_convertible(init.
to_str());
3556 constexpr void swap(my_type&& other)
noexcept {
3557 char buf[
sizeof(buf_) +
sizeof(K)];
3558 memcpy(buf, buf_,
sizeof(buf));
3559 memcpy(buf_, other.buf_,
sizeof(buf));
3560 memcpy(other.buf_, buf,
sizeof(buf));
3562 std::swap(base_storable::allocator(), other.allocator());
3573 swap(std::move(other));
3595 template<typename T, size_t N = const_lit_for<K, T>::Count>
3607 template<
size_t N,
bool forShared,
typename A>
3621 return operator=(my_type{std::move(other)});
3643 if (type_ == Shared)
3650 return type_ == Local ? buf_ : cstr_;
3654 return type_ == Local ? LocalCount - localRemain_ : bigLen_;
3676 template<
typename... T>
3677 static my_type
printf(
const K* pattern, T&&... args) {
3690 template<
typename... T>
3691 static my_type
format(
const FmtString<to_std_char_t<K>, T...>& fmtString, T&&... args) {
3704 template<
typename... T>
3710template<
typename K, Allocatorable Allocator>
3711inline const sstring<K> sstring<K, Allocator>::empty_str{};
3715template<
typename K,
size_t N>
3716class decl_empty_bases cestring :
3717 public str_algs<K, simple_str<K>, cestring<K, N>, true>,
3719 public null_terminated<K, lstring<K, N>>
3723 using symb_type = K;
3724 using my_type = cestring<K, N>;
3728 LocalCapacity = N | (
sizeof(
void*) /
sizeof(K) - 1),
3733 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
3734 using base_storable = str_storable<K, my_type, no_alloc>;
3736 using traits = ch_traits<K>;
3737 using s_str = base_storable::s_str;
3739 friend base_storable;
3744 K local_[LocalCapacity + 1]{};
3746 constexpr void create_empty() {
3752 constexpr K* init(
size_t s) {
3754 if (size_ > LocalCapacity) {
3755 throw std::bad_alloc{};
3762 constexpr size_t length() const noexcept {
3766 constexpr const K* symbols() const noexcept {
3767 return is_cstr_ ? cstr_ : local_;
3770 constexpr bool is_empty() const noexcept {
3774 constexpr bool empty() const noexcept {
3778 constexpr size_t capacity() const noexcept {
3779 return LocalCapacity;
3785 constexpr cestring() noexcept = default;
3793 constexpr cestring(s_str other) : base_storable() {
3794 base_storable::init_from_str_other(other);
3804 constexpr cestring(
size_t repeat, s_str pattern) : base_storable() {
3805 base_storable::init_str_repeat(repeat, pattern);
3815 constexpr cestring(
size_t count, K pad) : base_storable() {
3816 base_storable::init_symb_repeat(count, pad);
3830 constexpr cestring(
const StrExprForType<K>
auto& expr) : base_storable() {
3831 base_storable::init_str_expr(expr);
3847 template<StrType<K> From>
3848 constexpr cestring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0)
3850 base_storable::init_replaced(f, pattern, repl, offset, maxCount);
3854 constexpr ~cestring() {}
3864 template<typename T, size_t M = const_lit_for<K, T>::Count>
3865 constexpr cestring(T&& s) : base_storable(), cstr_((const K*)s), size_(M - 1), is_cstr_(true), local_{0} {}
3870 if constexpr (std::is_same_v<K, u8s>)
3872 if constexpr (std::is_same_v<K, ubs>)
3874 if constexpr (std::is_same_v<K, uws>)
3876 if constexpr (std::is_same_v<K, u16s>)
3878 if constexpr (std::is_same_v<K, u32s>)
3882#define uni_string(K, p) select_str<K>(p, u8##p, L##p, u##p, U##p)
3884template<
typename K,
typename H>
3888 char node[
sizeof(sstring<K>)];
3890 const simple_str_nt<K>& to_nt() const noexcept {
3891 return static_cast<const simple_str_nt<K>&
>(str);
3893 const sstring<K>& to_str() const noexcept {
3894 return *
reinterpret_cast<const sstring<K>*
>(node);
3900 static inline constexpr size_t basis =
static_cast<size_t>(14695981039346656037ULL);
3901 static inline constexpr size_t prime =
static_cast<size_t>(1099511628211ULL);
3905struct fnv_const<false> {
3906 static inline constexpr size_t basis =
static_cast<size_t>(2166136261U);
3907 static inline constexpr size_t prime =
static_cast<size_t>(16777619U);
3910using fnv = fnv_const<
sizeof(size_t) == 8>;
3913inline constexpr size_t fnv_hash(
const K* ptr,
size_t l) {
3914 size_t h = fnv::basis;
3915 for (
size_t i = 0; i < l; i++) {
3916 h = (h ^ (std::make_unsigned_t<K>)ptr[i]) * fnv::prime;
3922inline constexpr size_t fnv_hash_ia(
const K* ptr,
size_t l) {
3923 size_t h = fnv::basis;
3924 for (
size_t i = 0; i < l; i++) {
3925 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)ptr[i];
3926 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
3931template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
3932inline constexpr size_t fnv_hash(T&& value) {
3933 size_t h = fnv::basis;
3934 for (
size_t i = 0; i < N - 1; i++) {
3935 h = (h ^ (std::make_unsigned_t<K>)value[i]) * fnv::prime;
3940template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
3941inline constexpr size_t fnv_hash_ia(T&& value) {
3942 size_t h = fnv::basis;
3943 for (
size_t i = 0; i < N - 1; i++) {
3944 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)value[i];
3945 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
3951inline consteval size_t fnv_hash_compile(
const K* ptr,
size_t l) {
3952 return fnv_hash(ptr, l);
3956inline consteval size_t fnv_hash_ia_compile(
const K* ptr,
size_t l) {
3957 return fnv_hash_ia(ptr, l);
3960static_assert(std::is_trivially_copyable_v<StoreType<u8s, int>>,
"Store type must be trivially copyable");
4061template<
typename K,
typename T,
typename H = strhash<K>,
typename E = streql<K>>
4062class hashStrMap :
public std::unordered_map<StoreType<K, H>, T, H, E> {
4064 using InStore = StoreType<K, H>;
4067 using my_type = hashStrMap<K, T, H, E>;
4068 using hash_t = std::unordered_map<InStore, T, H, E>;
4071 hashStrMap() =
default;
4072 hashStrMap(
const my_type& other) : hash_t(other) {
4073 for (
const auto& [k, v] : *
this) {
4074 InStore& stored =
const_cast<InStore&
>(k);
4076 new (stored.node)
sstring<K>(std::move(tmp));
4077 stored.str.str = stored.to_str().symbols();
4081 for (
auto& k: *
this)
4085 hashStrMap(my_type&& o) =
default;
4087 my_type& operator=(
const my_type& other) {
4088 hash_t::operator=(other);
4089 for (
const auto& [k, v] : *
this) {
4090 InStore& stored =
const_cast<InStore&
>(k);
4092 new (stored.node)
sstring<K>(std::move(tmp));
4093 stored.str.str = stored.to_str().symbols();
4097 my_type& operator=(my_type&&) =
default;
4099 hashStrMap(std::initializer_list<std::pair<const InStore, T>>&& init) {
4100 for (
const auto& e: init)
4101 emplace(e.first, e.second);
4104 using init_str = std::initializer_list<std::pair<const sstring<K>, T>>;
4106 hashStrMap(init_str&& init) {
4107 for (
const auto& e: init)
4108 emplace(e.first, e.second);
4113 template<
typename... ValArgs>
4114 auto try_emplace(
const InStore& key, ValArgs&&... args) {
4115 auto it = hash_t::try_emplace(key, std::forward<ValArgs>(args)...);
4117 InStore& stored =
const_cast<InStore&
>(it.first->first);
4119 stored.str.str = stored.to_str().symbols();
4125 return {key, H{}(key)};
4128 template<
typename Key,
typename... ValArgs>
4129 requires(std::is_convertible_v<Key, simple_str<K>>)
4130 auto try_emplace(Key&& key, ValArgs&&... args) {
4131 auto it = hash_t::try_emplace(toStoreType(key), std::forward<ValArgs>(args)...);
4133 InStore& stored =
const_cast<InStore&
>(it.first->first);
4134 new (stored.node)
sstring<K>(std::forward<Key>(key));
4135 stored.str.str = stored.to_str().symbols();
4140 template<
typename... ValArgs>
4141 auto emplace(
const InStore& key, ValArgs&&... args) {
4142 auto it = try_emplace(key, std::forward<ValArgs>(args)...);
4144 it.first->second = T(std::forward<ValArgs>(args)...);
4149 template<
typename Key,
typename... ValArgs>
4150 requires(std::is_convertible_v<Key, simple_str<K>>)
4151 auto emplace(Key&& key, ValArgs&&... args) {
4152 auto it = try_emplace(std::forward<Key>(key), std::forward<ValArgs>(args)...);
4154 it.first->second = T(std::forward<ValArgs>(args)...);
4159 auto& operator[](
const InStore& key) {
4160 return try_emplace(key).first->second;
4163 template<
typename Key>
4164 requires(std::is_convertible_v<Key, simple_str<K>>)
4165 auto&
operator[](Key&& key) {
4166 return try_emplace(std::forward<Key>(key)).first->second;
4169 decltype(
auto) at(
const InStore& key) {
4170 return hash_t::at(key);
4172 decltype(
auto) at(
const InStore& key)
const {
4173 return hash_t::at(key);
4177 return hash_t::at(toStoreType(key));
4180 return hash_t::at(toStoreType(key));
4183 auto find(
const InStore& key)
const {
4184 return hash_t::find(key);
4188 return find(toStoreType(key));
4191 auto find(
const InStore& key) {
4192 return hash_t::find(key);
4196 return find(toStoreType(key));
4199 auto erase(
typename hash_t::const_iterator it) {
4200 if (it != hash_t::end()) {
4203 return hash_t::erase(it);
4206 auto erase(
const InStore& key) {
4207 auto it = hash_t::find(key);
4208 if (it != hash_t::end()) {
4217 return erase(toStoreType(key));
4221 auto it = find(txt);
4222 if (it != hash_t::end()) {
4230 for (
auto& k: *
this)
4234 bool contains(
const InStore& key)
const {
4235 return hash_t::find(key) != this->end();
4239 return find(toStoreType(key)) != this->end();
4245 template<
typename H>
4246 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
4247 return _Left.hash == _Right.hash && _Left.str == _Right.str;
4253 size_t operator()(simple_str<K> _Keyval)
const {
4254 return fnv_hash(_Keyval.symbols(), _Keyval.length());
4256 size_t operator()(
const StoreType<K, strhash<K>>& _Keyval)
const {
4257 return _Keyval.hash;
4263 template<
typename H>
4264 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
4265 return _Left.hash == _Right.hash && _Left.str.equal_ia(_Right.str);
4271 size_t operator()(simple_str<K> _Keyval)
const {
4272 return fnv_hash_ia(_Keyval.symbols(), _Keyval.length());
4274 size_t operator()(
const StoreType<K, strhashia<K>>& _Keyval)
const {
4275 return _Keyval.hash;
4281 template<
typename H>
4282 bool operator()(
const StoreType<K, H>& _Left,
const StoreType<K, H>& _Right)
const {
4283 return _Left.hash == _Right.hash && _Left.str.equal_iu(_Right.str);
4289 size_t operator()(simple_str<K> _Keyval)
const {
4290 return unicode_traits<K>::hashiu(_Keyval.symbols(), _Keyval.length());
4292 size_t operator()(
const StoreType<K, strhashiu<K>>& _Keyval)
const {
4293 return _Keyval.hash;
4313 using chunk_t = std::pair<std::unique_ptr<K[]>,
size_t>;
4314 std::vector<chunk_t> chunks;
4321 using my_type = chunked_string_builder<K>;
4322 using symb_type = K;
4323 chunked_string_builder() =
default;
4324 chunked_string_builder(
size_t a) : align(a){};
4325 chunked_string_builder(
const my_type&) =
delete;
4326 chunked_string_builder(my_type&& other) noexcept
4327 : chunks(std::move(other.chunks)), write(other.write), len(other.len), remain(other.remain), align(other.align) {
4328 other.len = other.remain = 0;
4329 other.write =
nullptr;
4331 my_type& operator=(my_type other)
noexcept {
4332 chunks.swap(other.chunks);
4333 write = other.write;
4335 remain = other.remain;
4336 align = other.align;
4337 other.len = other.remain = 0;
4338 other.write =
nullptr;
4346 if (
data.len <= remain) {
4349 ch_traits<K>::copy(write,
data.str,
data.len);
4351 chunks.back().second +=
data.len;
4358 ch_traits<K>::copy(write,
data.str, remain);
4361 chunks.back().second += remain;
4367 size_t blockSize = (
data.len + align - 1) / align * align;
4368 chunks.emplace_back(std::make_unique<K[]>(blockSize),
data.len);
4369 write = chunks.back().first.get();
4370 ch_traits<K>::copy(write,
data.str,
data.len);
4372 remain = blockSize -
data.len;
4379 size_t l = expr.length();
4382 write = expr.place(write);
4383 chunks.back().second += l;
4386 }
else if (!remain) {
4387 size_t blockSize = (l + align - 1) / align * align;
4388 chunks.emplace_back(std::make_unique<K[]>(blockSize), l);
4389 write = expr.place(chunks.back().first.get());
4391 remain = blockSize - l;
4393 auto store = std::make_unique<K[]>(l);
4394 expr.place(store.get());
4401 template<
typename T>
4403 requires std::is_same_v<T, K>
4405 return operator<<(expr_char<K>(
data));
4413 if (chunks.empty()) {
4416 if (chunks.size() > 1) {
4420 remain += chunks[0].second;
4421 chunks[0].second = 0;
4423 write = chunks[0].first.get();
4426 constexpr K* place(K* p)
const noexcept {
4427 for (
const auto& block: chunks) {
4428 ch_traits<K>::copy(p, block.first.get(), block.second);
4441 template<
typename Op>
4443 for (
const auto& block: chunks)
4444 o(block.first.get(), block.second);
4451 if (chunks.size()) {
4452 const K* ptr = chunks.front().first.get();
4453 for (
const auto& chunk: chunks) {
4454 if (chunk.first.get() != ptr)
4456 ptr += chunk.second;
4468 return chunks.size() ? chunks.front().first.get() : simple_str_nt<K>::empty_str.str;
4485 typename decltype(chunks)::const_iterator it, end;
4486 size_t writedFromCurrentChunk;
4506 while (size && !
is_end()) {
4507 size_t remain = it->second - writedFromCurrentChunk;
4508 size_t write = std::min(size, remain);
4509 ch_traits<K>::copy(buffer, it->first.get() + writedFromCurrentChunk, write);
4515 writedFromCurrentChunk = 0;
4517 writedFromCurrentChunk += write;
4529 return {chunks.begin(), chunks.end(), 0};
4542using stringa = sstring<u8s>;
4543using stringb = sstring<ubs>;
4544using stringw = sstring<wchar_t>;
4545using stringu = sstring<u16s>;
4546using stringuu = sstring<u32s>;
4547static_assert(
sizeof(stringa) == (
sizeof(
void*) == 8 ? 24 : 16),
"Bad size of sstring");
4629inline namespace literals {
4698template<
typename K>
using HashKey = StoreType<K, strhash<K>>;
4699template<
typename K>
using HashKeyIA = StoreType<K, strhashia<K>>;
4700template<
typename K>
using HashKeyIU = StoreType<K, strhashiu<K>>;
4712consteval HashKey<u8s>
operator""_h(
const u8s* ptr,
size_t l) {
4713 return HashKey<u8s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4726consteval HashKeyIA<u8s>
operator""_ia(
const u8s* ptr,
size_t l) {
4727 return HashKeyIA<u8s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4740inline HashKeyIU<u8s>
operator""_iu(
const u8s* ptr,
size_t l) {
4741 return HashKeyIU<u8s>{{ptr, l}, strhashiu<u8s>{}(
simple_str<u8s>{ptr, l})};
4754consteval HashKey<u16s>
operator""_h(
const u16s* ptr,
size_t l) {
4755 return HashKey<u16s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4768consteval HashKeyIA<u16s>
operator""_ia(
const u16s* ptr,
size_t l) {
4769 return HashKeyIA<u16s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4782inline HashKeyIU<u16s>
operator""_iu(
const u16s* ptr,
size_t l) {
4783 return HashKeyIU<u16s>{{ptr, l}, strhashiu<u16s>{}(
simple_str<u16s>{ptr, l})};
4796consteval HashKey<u32s>
operator""_h(
const u32s* ptr,
size_t l) {
4797 return HashKey<u32s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4810consteval HashKeyIA<u32s>
operator""_ia(
const u32s* ptr,
size_t l) {
4811 return HashKeyIA<u32s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4824inline HashKeyIU<u32s>
operator""_iu(
const u32s* ptr,
size_t l) {
4825 return HashKeyIU<u32s>{{ptr, l}, strhashiu<u32s>{}(
simple_str<u32s>{ptr, l})};
4838consteval HashKey<uws>
operator""_h(
const uws* ptr,
size_t l) {
4839 return HashKey<uws>{{ptr, l}, fnv_hash_compile(ptr, l)};
4852consteval HashKeyIA<uws>
operator""_ia(
const uws* ptr,
size_t l) {
4853 return HashKeyIA<uws>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4866inline HashKeyIU<uws>
operator""_iu(
const uws* ptr,
size_t l) {
4867 return HashKeyIU<uws>{{ptr, l}, strhashiu<uws>{}(
simple_str<uws>{ptr, l})};
4882 return stream << std::string_view{text.
symbols(), text.
length()};
4895inline std::wostream&
operator<<(std::wostream& stream, ssw text) {
4896 return stream << std::wstring_view{text.
symbols(), text.
length()};
4910 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
4923inline std::ostream&
operator<<(std::ostream& stream,
const stringa& text) {
4924 return stream << std::string_view{text.
symbols(), text.
length()};
4937inline std::wostream&
operator<<(std::wostream& stream,
const stringw& text) {
4938 return stream << std::wstring_view{text.
symbols(), text.
length()};
4952 return stream << std::wstring_view{from_w(text.symbols()), text.length()};
4965template<
size_t N,
bool S, simstr::Allocatorable A>
4967 return stream << std::string_view{text.
symbols(), text.
length()};
4980template<
size_t N,
bool S, simstr::Allocatorable A>
4982 return stream << std::wstring_view{text.
symbols(), text.
length()};
4995template<
size_t N,
bool S, simstr::Allocatorable A>
4997 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
5007struct std::formatter<
simstr::simple_str<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5009 template<
typename FormatContext>
5011 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5020struct std::formatter<
simstr::simple_str_nt<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5022 template<
typename FormatContext>
5024 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5033struct std::formatter<
simstr::sstring<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5035 template<
typename FormatContext>
5037 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5045template<
typename K,
size_t N,
bool S,
typename A>
5046struct std::formatter<
simstr::lstring<K, N, S, A>, K> : std::formatter<std::basic_string_view<K>, K> {
5048 template<
typename FormatContext>
5050 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5059struct std::formatter<
simstr::simple_str<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5061 template<
typename FormatContext>
5063 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5072struct std::formatter<
simstr::simple_str_nt<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5074 template<
typename FormatContext>
5076 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5085struct std::formatter<
simstr::sstring<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5087 template<
typename FormatContext>
5089 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5097template<
size_t N,
bool S,
typename A>
5098struct std::formatter<
simstr::lstring<char8_t, N, S, A>, char> : std::formatter<std::basic_string_view<char>, char> {
5100 template<
typename FormatContext>
5102 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5111struct std::formatter<
simstr::simple_str<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5113 template<
typename FormatContext>
5115 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5124struct std::formatter<
simstr::simple_str_nt<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5126 template<
typename FormatContext>
5128 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5137struct std::formatter<
simstr::sstring<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5139 template<
typename FormatContext>
5141 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.
symbols(), t.
length()}, fc);
5149template<
size_t N,
bool S,
typename A>
5150struct std::formatter<
simstr::lstring<simstr::wchar_type, N, S, A>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5152 template<
typename FormatContext>
5154 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.
symbols(), t.
length()}, fc);
Класс для последовательного получения подстрок по заданному разделителю.
Определения strexpr.h:3232
my_type & operator<<(simple_str< K > data)
Добавление порции данных.
Определения sstring.h:4343
portion_store get_portion() const
Получить portion_store, через который можно последовательно извлекать данные во внешний буфер.
Определения sstring.h:4528
constexpr size_t length() const noexcept
Длина сохранённого текста.
Определения sstring.h:4408
my_type & operator<<(T data)
Добавление символа.
Определения sstring.h:4402
void reset()
Сбрасывает содержимое, но при этом не удаляет первый буфер, чтобы потом избежать аллокации.
Определения sstring.h:4412
void clear()
Очистить объект, освободив все выделенные буфера.
Определения sstring.h:4474
my_type & operator<<(const StrExprForType< K > auto &expr)
Добавление строкового выражения.
Определения sstring.h:4378
bool is_continuous() const
Проверяет, расположен ли весь текст одним непрерывным куском в памяти.
Определения sstring.h:4450
void out(const Op &o) const
Применяет функтор к каждому сохранённому буферу.
Определения sstring.h:4442
const auto & data() const
Получить внутренние буфера с данными.
Определения sstring.h:4537
const K * begin() const
Получить указатель на начало первого буфера. Имеет смысл применять только если is_continuous true.
Определения sstring.h:4467
Контейнер для более эффективного поиска по строковым ключам.
Определения sstring.h:4062
Класс мутабельной, владеющей строки. Содержит внутренний буфер для строк заданного размера.
Определения sstring.h:2559
constexpr void define_size()
Определить длину строки. Ищет символ 0 в буфере строки до его ёмкости, после чего устаналивает длину ...
Определения sstring.h:3086
constexpr lstring(T &&value, Args &&... args)
Конструктор из строкового литерала.
Определения sstring.h:2815
my_type & operator=(T &&other)
Оператор присваивания строкового литерала.
Определения sstring.h:2957
constexpr void reset()
Делает строку пустой и освобождает внешний буфер, если он был.
Определения sstring.h:3121
@ LocalCapacity
Определения sstring.h:2567
constexpr bool is_local() const noexcept
Узнать, локальный или внешний буфер используется для символов.
Определения sstring.h:3077
my_type & operator=(my_type &&other) noexcept
Оператор присваивания перемещением из строки такого же типа.
Определения sstring.h:2900
constexpr size_t length() const noexcept
Длина строки.
Определения sstring.h:2980
constexpr lstring(s_str other, Args &&... args)
Конструктор из другого строкового объекта.
Определения sstring.h:2689
constexpr lstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Конструктор из строкового источника с заменой.
Определения sstring.h:2759
constexpr lstring(size_t repeat, s_str pattern, Args &&... args)
Конструктор повторения строки.
Определения sstring.h:2704
constexpr lstring(const my_type &other)
Копирование из другой строки такого же типа.
Определения sstring.h:2778
constexpr lstring(const my_type &other, Args &&... args)
Копирование из другой строки такого же типа, но с другим аллокатором.
Определения sstring.h:2800
my_type & operator=(const StrExprForType< K > auto &expr)
Оператор присваивания строкового выражения.
Определения sstring.h:2970
constexpr K * reserve_no_preserve(size_t newSize)
Определения sstring.h:3015
my_type & operator=(const my_type &other)
Оператор присваивания копией из строки такого же типа.
Определения sstring.h:2883
constexpr bool is_empty() const noexcept
Пустая ли строка.
Определения sstring.h:2992
lstring(const Op &op, Args &&... args)
Конструктор заполнения с помощью функтора (см. str_mutable::fill).
Определения sstring.h:2854
constexpr K * set_size(size_t newSize)
Устанавливает размер текущей строки, при необходимости выделяя место.
Определения sstring.h:3060
constexpr lstring(size_t count, K pad, Args &&... args)
Конструктор повторения символа.
Определения sstring.h:2719
constexpr lstring(const StrExprForType< K > auto &expr, Args &&... args)
Конструктор из строкового выражения.
Определения sstring.h:2738
constexpr const K * symbols() const noexcept
Указатель на константные символы.
Определения sstring.h:2984
constexpr void clear()
Делает строку пустой, не меняя буфер строки.
Определения sstring.h:3117
my_type & operator=(simple_str< K > other)
Оператор присваивания из simple_str.
Определения sstring.h:2945
constexpr bool empty() const noexcept
Пустая ли строка, для совместимости с std::string.
Определения sstring.h:2996
constexpr void shrink_to_fit()
Уменьшает размер внешнего буфера до минимально возможного для хранения строки. Если строка уместится ...
Определения sstring.h:3103
constexpr lstring(my_type &&other) noexcept
Конструктор перемещения из строки такого же типа.
Определения sstring.h:2829
constexpr K * reserve(size_t newSize)
Выделить буфер, достаточный для размещения newSize символов плюс завершающий ноль.
Определения sstring.h:3037
constexpr K * str() noexcept
Указатель на буфер строки.
Определения sstring.h:2988
constexpr size_t capacity() const noexcept
Текущая ёмкость буфера строки.
Определения sstring.h:3000
constexpr lstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Создать пустой объект.
Определения sstring.h:2674
Класс иммутабельной владеющей строки.
Определения sstring.h:3232
constexpr my_type & operator=(const lstring< K, N, forShared, A > &other)
Оператор присвоения другой строки типа lstring.
Определения sstring.h:3608
constexpr bool empty() const noexcept
Пустая ли строка, для совместимости с std::string.
Определения sstring.h:3661
constexpr bool is_empty() const noexcept
Пустая ли строка.
Определения sstring.h:3657
sstring(s_str other, Args &&... args)
Конструктор из другого строкового объекта.
Определения sstring.h:3371
sstring(size_t count, K pad, Args &&... args)
Конструктор повторения символа.
Определения sstring.h:3401
constexpr const K * symbols() const noexcept
Указатель на символы строки.
Определения sstring.h:3649
constexpr sstring(const my_type &other) noexcept
Конструктор копирования строки.
Определения sstring.h:3459
static my_type format(const FmtString< to_std_char_t< K >, T... > &fmtString, T &&... args)
Получить строку, отформатированную с помощью std::format.
Определения sstring.h:3691
constexpr my_type & operator=(T &&other)
Оператор присвоения строкового литерала.
Определения sstring.h:3596
sstring(size_t repeat, s_str pattern, Args &&... args)
Конструктор повторения строки.
Определения sstring.h:3386
constexpr my_type & operator=(my_type other) noexcept
Оператор присвоения другой строки того же типа.
Определения sstring.h:3572
static my_type printf(const K *pattern, T &&... args)
Получить строку, отформатированную с помощью std::sprintf.
Определения sstring.h:3677
constexpr sstring(lstring< K, N, true, Allocator > &&src)
Конструктор перемещения из lstring с совместимым с sstring внешним буфером.
Определения sstring.h:3486
constexpr size_t length() const noexcept
Длина строки.
Определения sstring.h:3653
constexpr sstring(my_type &&other) noexcept
Конструктор перемещения.
Определения sstring.h:3470
static my_type vformat(simple_str< K > fmtString, T &&... args)
Получить строку, отформатированную с помощью std::vformat.
Определения sstring.h:3705
sstring(simple_str< O > init)
Инициализация из строкового источника с другим типом символов. Конвертирует через UTF.
Определения sstring.h:3547
constexpr my_type & operator=(simple_str< K > other)
Оператор присвоения другой строки другого типа.
Определения sstring.h:3584
constexpr my_type & make_empty() noexcept
Сделать строку пустой.
Определения sstring.h:3642
constexpr my_type & operator=(const StrExprForType< K > auto &expr)
Оператор присвоения строкового выражения.
Определения sstring.h:3633
sstring(T &&s, Args &&... args)
Инициализация из строкового литерала.
Определения sstring.h:3534
constexpr my_type & operator=(lstring< K, N, true, Allocator > &&other)
Оператор присвоения перемещаемой строки типа lstring с совместимым буфером.
Определения sstring.h:3620
constexpr sstring(const StrExprForType< K > auto &expr, Args &&... args)
Конструктор из строкового выражения.
Определения sstring.h:3420
sstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Конструктор пустой строки.
Определения sstring.h:3356
constexpr ~sstring()
Деструктор строки.
Определения sstring.h:3448
sstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Конструктор из строкового источника с заменой.
Определения sstring.h:3441
Класс с дополнительными константными строковыми алгоритмами.
Определения sstring.h:166
bool starts_with_iu(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки без учёта регистра Unicode символов первой плоскости (<0xFF...
Определения sstring.h:239
int compare_iu(str_piece text) const noexcept
Сравнение строк посимвольно без учёта регистра Unicode символов первой плоскости (<0xFFFF).
Определения sstring.h:203
bool less_iu(str_piece text) const noexcept
Меньше ли строка другой строки посимвольно без учёта регистра Unicode символов первой плоскости (<0xF...
Определения sstring.h:225
constexpr bool ends_with_iu(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой без учёта регистра Unicode символов первой плоскости (<0...
Определения sstring.h:254
R upperred() const
Получить копию строки в верхнем регистре Unicode символов первой плоскости (<0xFFFF).
Определения sstring.h:266
R lowered() const
Получить копию строки в нижнем регистре Unicode символов первой плоскости (<0xFFFF).
Определения sstring.h:278
std::optional< double > to_double() const noexcept
Преобразовать строку в double.
Определения sstring.h:288
constexpr void as_number(T &t) const
Преобразовать строку в целое число.
Определения sstring.h:346
bool equal_iu(str_piece text) const noexcept
Равна ли строка другой строке посимвольно без учёта регистра Unicode символов первой плоскости (<0xFF...
Определения sstring.h:214
void as_number(double &t) const
Преобразовать строку в double.
Определения sstring.h:329
Базовый класс работы с изменяемыми строками
Определения sstring.h:1326
Impl & insert(size_t to, const A &expr)
Вставить строковое выражение в указанную позицию.
Определения sstring.h:1866
Impl & operator<<=(const Op &fillFunction)
Заполняет строку методом fill после конца строки.
Определения sstring.h:2140
Impl & append(const A &expr)
Добавить строковое выражение в конец строки.
Определения sstring.h:1750
Impl & operator<<(const Op &fillFunction)
Вызывает переданный функтор, передав ссылку на себя.
Определения sstring.h:2153
Impl & trim(str_piece pattern)
Удалить символы, входящие в переданную строку, в начале и в конце строки.
Определения sstring.h:1560
Impl & upper_only_ascii()
Преобразовать в верхний регистр ASCII символы.
Определения sstring.h:1624
Impl & lower_only_ascii()
Преобразовать в нижний регистр ASCII символы.
Определения sstring.h:1639
Impl & trim_left()
Удалить пробельные символы в начале строки.
Определения sstring.h:1462
Impl & append_printf(const K *format, T &&... args)
Добавляет отформатированный с помощью sprintf вывод в конец строки.
Определения sstring.h:2242
Impl & trim_right_with_wpaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в конце строки.
Определения sstring.h:1549
Impl & trim_left(str_piece pattern)
Удалить символы, входящие в переданную строку, в начале строки.
Определения sstring.h:1571
Impl & trim_with_spaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в начале и в конце строки.
Определения sstring.h:1523
Impl & prepend(str_piece other)
Добавить другую строку в начало строки.
Определения sstring.h:1890
Impl & append_formatted(const FmtString< fmt_type, T... > &format, T &&... args)
Добавляет отформатированный с помощью std::format вывод в конец строки.
Определения sstring.h:2380
my_type & format(const FmtString< fmt_type, T... > &pattern, T &&... args)
Определения sstring.h:2364
Impl & printf(const K *format, T &&... args)
Форматирует строку помощью sprintf.
Определения sstring.h:2226
Impl & with(const Op &fillFunction, Args &&... args)
Вызов функтора со строкой и переданными аргументами.
Определения sstring.h:2462
Impl & append_vformatted_n(size_t max_write, str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод в конец строки, записывая не более указанног...
Определения sstring.h:2448
Impl & operator<<(const Op &fillFunction)
Заполняет строку методом fill с нулевой позиции.
Определения sstring.h:2127
Impl & vformat(str_piece format, T &&... args)
Форматирует строку с помощью std::vformat.
Определения sstring.h:2396
Impl & change(size_t from, size_t len, const A &expr)
Заменить кусок строки на строковое выражение.
Определения sstring.h:1839
Impl & fill(size_t from, const Op &fillFunction)
Заполнение буфера строки с помощью функтора.
Определения sstring.h:2099
Impl & change(size_t from, size_t len, str_piece other)
Заменить кусок строки на другую строку.
Определения sstring.h:1823
Impl & remove(size_t from, size_t len)
Удалить часть строки.
Определения sstring.h:1879
Impl & trim_left_with_spaces(T &&pattern)
Удалить символы, входящие в строковый литерал, а также пробельные символы, в начале строки.
Определения sstring.h:1536
Impl & trim_left(T &&pattern)
Удалить символы, входящие в строковый литерал, в начале строки.
Определения sstring.h:1497
Impl & trim_right(T &&pattern)
Удалить символы, входящие в строковый литерал, в конце строки.
Определения sstring.h:1510
Impl & trim_right_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в конце строки.
Определения sstring.h:1615
Impl & append_in(size_t pos, str_piece other)
Добавить другую строку, начиная с заданной позиции.
Определения sstring.h:1790
Impl & vformat_from(size_t from, size_t max_write, str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод, начиная с указанной позиции.
Определения sstring.h:2329
Impl & trim_left_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в начале строки.
Определения sstring.h:1604
Impl & insert(size_t to, str_piece other)
Вставить строку в указанную позицию.
Определения sstring.h:1852
Impl & vformat_n(size_t max_write, str_piece format, T &&... args)
Форматирует строку с помощью std::vformat не более указанного размера.
Определения sstring.h:2430
Impl & printf_from(size_t from, const K *format, T &&... args)
Добавляет отформатированный с помощью sprintf вывод, начиная с указанной позиции.
Определения sstring.h:2172
Impl & operator+=(str_piece other)
Добавить другую строку в конец строки.
Определения sstring.h:1761
Impl & trim_right()
Удалить пробельные символы в конце строки.
Определения sstring.h:1471
Impl & append(str_piece other)
Добавить другую строку в конец строки.
Определения sstring.h:1738
Impl & trim_right(str_piece pattern)
Удалить символы, входящие в переданную строку, в конце строки.
Определения sstring.h:1582
Impl & trim_with_spaces(str_piece pattern)
Удалить символы, входящие в переданную строку, а также пробельные символы, в начале и в конце строки.
Определения sstring.h:1593
K * str() noexcept
Получить указатель на буфер строки.
Определения sstring.h:1435
Impl & prepend(const A &expr)
Добавить строковое выражение в начало строки.
Определения sstring.h:1902
Impl & trim()
Удалить пробельные символы в начале и в конце строки.
Определения sstring.h:1453
Impl & lower()
Преобразовать в нижний регистр Unicode символы первой плоскости (<0xFFFF).
Определения sstring.h:1673
Impl & replace(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Заменить вхождения подстроки на другую строку.
Определения sstring.h:1919
Impl & upper()
Преобразовать в верхний регистр Unicode символы первой плоскости (<0xFFFF).
Определения sstring.h:1658
Impl & replace_from(const From &f, str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Скопировать строку-источник, заменив вхождения подстрок на другую строку.
Определения sstring.h:2037
Impl & append_vformatted(str_piece format, T &&... args)
Добавляет отформатированный с помощью std::vformat вывод в конец строки.
Определения sstring.h:2412
Impl & append_in(size_t pos, const A &expr)
Добавить строковое выражение, начиная с заданной позиции.
Определения sstring.h:1808
my_type & format_from(size_t from, const FmtString< fmt_type, T... > &format, T &&... args)
Определения sstring.h:2300
Impl & trim(T &&pattern)
Удалить символы, входящие в строковый литерал, в начале и в конце строки.
Определения sstring.h:1484
Impl & operator+=(const A &expr)
Добавить строковое выражение в конец строки.
Определения sstring.h:1773
constexpr str_piece to_str() const noexcept
Преобразовать себя в "кусок строки", включающий всю строку.
Определения strexpr.h:3420
constexpr size_t size() const
Определения strexpr.h:3361
constexpr void as_number(T &t) const
Преобразовать строку в целое число.
Определения strexpr.h:4217
База для объектов, владеющих строкой.
Определения sstring.h:803
constexpr str_storable(Args &&... args)
Создать пустой объект.
Определения sstring.h:839
void init_replaced(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0)
Инициализация из строкового источника с заменой.
Определения sstring.h:926
static my_type upperred_from(const From &f, Args &&... args)
Создать копию переданной строки в верхнем регистре символов Unicode первой плоскости (<0xFFFF).
Определения sstring.h:1187
constexpr void init_from_str_other(s_str other)
Инициализация из другого строкового объекта.
Определения sstring.h:847
constexpr allocator_t & allocator()
Получить аллокатор.
Определения sstring.h:816
constexpr void init_symb_repeat(size_t count, K pad)
Инициализация повторением символа.
Определения sstring.h:883
constexpr void init_str_expr(const A &expr)
Инициализация из строкового выражения.
Определения sstring.h:904
static my_type upperred_only_ascii_from(const From &f, Args &&... args)
Создать строку, копию переданной в верхнем регистре символов ASCII.
Определения sstring.h:1157
static my_type lowered_from(const From &f, Args &&... args)
Создать копию переданной строки в нижнем регистре символов Unicode первой плоскости (<0xFFFF).
Определения sstring.h:1204
constexpr void init_str_repeat(size_t repeat, s_str pattern)
Инициализация повторением строки.
Определения sstring.h:863
static my_type lowered_only_ascii_from(const From &f, Args &&... args)
Создать копию переданной строки в нижнем регистре символов ASCII.
Определения sstring.h:1170
static my_type join(const T &strings, s_str delimiter, bool tail=false, bool skip_empty=false, Args &&... args)
Конкатенация строк из контейнера в одну строку.
Определения sstring.h:1106
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:1225
constexpr s_str_nt to_nts(size_t from=0) const
Получить simple_str_nt, начиная с заданного символа.
Определения sstring.h:1050
Концепт типа, управляющего памятью
Определения sstring.h:1235
Концепт строкового выражения, совместимого с заданным типом символов.
Определения strexpr.h:525
Концепт типа, который не может модифицировать хранимую строку.
Определения sstring.h:758
Концепт типа, который может модифицировать хранимую строку.
Определения sstring.h:751
Концепт типа, который может сохранить строку.
Определения sstring.h:741
Небольшое пространство для методов работы со стандартными строками.
Определения strexpr.h:1600
Пространство имён для объектов библиотеки
Определения sstring.cpp:12
hashStrMap< u16s, T, strhash< u16s >, streql< u16s > > hashStrMapU
Тип хеш-словаря для char16_t строк, регистрозависимый поиск.
Определения sstring.h:4594
hashStrMap< u8s, T, strhashia< u8s >, streqlia< u8s > > hashStrMapAIA
Тип хеш-словаря для char строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4560
hashStrMap< u32s, T, strhashiu< u32s >, streqliu< u32s > > hashStrMapUUIU
Тип хеш-словаря для char32_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4625
hashStrMap< u32s, T, strhashia< u32s >, streqlia< u32s > > hashStrMapUUIA
Тип хеш-словаря для char32_t строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4619
hashStrMap< wchar_t, T, strhashiu< wchar_t >, streqliu< wchar_t > > hashStrMapWIU
Тип хеш-словаря для wchar_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4587
hashStrMap< wchar_t, T, strhashia< wchar_t >, streqlia< wchar_t > > hashStrMapWIA
Тип хеш-словаря для wchar_t строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4580
expr_utf< From, To > e_utf(simple_str< From > from)
Возвращает строковое выражение, преобразующую строку из одного типа символов в другой тип,...
Определения sstring.h:732
hashStrMap< u8s, T, strhash< u8s >, streql< u8s > > hashStrMapA
Тип хеш-словаря для char строк, регистрозависимый поиск.
Определения sstring.h:4554
hashStrMap< u16s, T, strhashiu< u16s >, streqliu< u16s > > hashStrMapUIU
Тип хеш-словаря для char16_t строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4606
hashStrMap< u16s, T, strhashia< u16s >, streqlia< u16s > > hashStrMapUIA
Тип хеш-словаря для char16_t строк, регистронезависимый поиск для ASCII символов.
Определения sstring.h:4600
hashStrMap< wchar_t, T, strhash< wchar_t >, streql< wchar_t > > hashStrMapW
Тип хеш-словаря для wchar_t строк, регистрозависимый поиск.
Определения sstring.h:4573
hashStrMap< u8s, T, strhashiu< u8s >, streqliu< u8s > > hashStrMapAIU
Тип хеш-словаря для char строк, регистронезависимый поиск для Unicode символов до 0xFFFF.
Определения sstring.h:4566
std::ostream & operator<<(std::ostream &stream, ssa text)
Оператор вывода в поток simple_str.
Определения sstring.h:4881
hashStrMap< u32s, T, strhash< u32s >, streql< u32s > > hashStrMapUU
Тип хеш-словаря для char32_t строк, регистрозависимый поиск.
Определения sstring.h:4613
Объект, позволяющий последовательно копировать содержимое в буфер заданного размера.
Определения sstring.h:4484
bool is_end()
Проверить, что данные ещё не кончились.
Определения sstring.h:4491
size_t store(K *buffer, size_t size)
Сохранить очередную порцию данных в буфер.
Определения sstring.h:4504
Базовый класс для преобразования строковых выражений в стандартные строки
Определения strexpr.h:659
Строковое выражение для конвертации строк в разные виды UTF.
Определения sstring.h:701
Класс, заявляющий, что ссылается на нуль-терминированную строку.
Определения sstring.h:509
constexpr my_type to_nts(size_t from)
Получить нуль-терминированную строку, сдвинув начало на заданное количество символов.
Определения sstring.h:572
constexpr simple_str_nt(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения sstring.h:561
constexpr simple_str_nt(T &&v) noexcept
Конструктор из строкового литерала.
Определения sstring.h:543
constexpr simple_str_nt(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения sstring.h:549
constexpr simple_str_nt(T &&p) noexcept
Явный конструктор из С-строки.
Определения sstring.h:534
Простейший класс иммутабельной не владеющей строки.
Определения sstring.h:373
constexpr simple_str(T &&v) noexcept
Конструктор из строкового литерала.
Определения sstring.h:389
constexpr K operator[](size_t idx) const
Получить символ из указанной позиции. Проверка границ не выполняется.
Определения sstring.h:453
constexpr my_type & remove_suffix(size_t delta)
Укорачивает строку на заданное количество символов.
Определения sstring.h:477
constexpr size_t length() const noexcept
Получить длину строки.
Определения sstring.h:410
constexpr const symb_type * symbols() const noexcept
Получить указатель на константный буфер с символами строки.
Определения sstring.h:417
constexpr my_type & remove_prefix(size_t delta)
Сдвигает начало строки на заданное количество символов.
Определения sstring.h:464
constexpr simple_str(const std::basic_string_view< K, std::char_traits< K > > &s) noexcept
Конструктор из std::basic_string_view.
Определения sstring.h:405
constexpr simple_str(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения sstring.h:394
constexpr simple_str(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения sstring.h:400
constexpr bool is_empty() const noexcept
Проверить, не пуста ли строка.
Определения sstring.h:424
constexpr bool is_same(simple_str< K > other) const noexcept
Проверить, не указывают ли два объекта на одну строку.
Определения sstring.h:433
constexpr bool is_part_of(simple_str< K > other) const noexcept
Проверить, не является ли строка частью другой строки.
Определения sstring.h:442
Простейший класс иммутабельной не владеющей строки.
Определения strexpr.h:4826
constexpr size_t length() const noexcept
Получить длину строки.
Определения strexpr.h:4866
constexpr const symb_type * symbols() const noexcept
Получить указатель на константный буфер с символами строки.
Определения strexpr.h:4873