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 len, u8s*& dest,
size_t lenBuf);
90 static SIMSTR_API
size_t lower(
const u8s*& src,
size_t len, u8s*& dest,
size_t lenBuf);
91 static SIMSTR_API
size_t upper_len(
const u8s* src,
size_t len);
92 static SIMSTR_API
size_t lower_len(
const u8s* src,
size_t len);
94 static SIMSTR_API
int compareiu(
const u8s* text1,
size_t len1,
const u8s* text2,
size_t len2);
96 static SIMSTR_API
size_t hashia(
const u8s* src,
size_t l);
97 static SIMSTR_API
size_t hashiu(
const u8s* src,
size_t l);
101struct unicode_traits<u16s> {
102 static SIMSTR_API
void upper(
const u16s* src,
size_t len, u16s* dest);
103 static SIMSTR_API
void lower(
const u16s* src,
size_t len, u16s* dest);
105 static SIMSTR_API
int compareiu(
const u16s* text1,
size_t len1,
const u16s* text2,
size_t len2);
106 static SIMSTR_API
size_t hashia(
const u16s* src,
size_t l);
107 static SIMSTR_API
size_t hashiu(
const u16s* src,
size_t l);
111struct unicode_traits<u32s> {
112 static SIMSTR_API
void upper(
const u32s* src,
size_t len, u32s* dest);
113 static SIMSTR_API
void lower(
const u32s* src,
size_t len, u32s* dest);
115 static SIMSTR_API
int compareiu(
const u32s* text1,
size_t len1,
const u32s* text2,
size_t len2);
116 static SIMSTR_API
size_t hashia(
const u32s* src,
size_t s);
117 static SIMSTR_API
size_t hashiu(
const u32s* src,
size_t s);
121struct unicode_traits<wchar_t> {
122 static void upper(
const wchar_t* src,
size_t len,
wchar_t* dest) {
123 unicode_traits<wchar_type>::upper(to_w(src), len, to_w(dest));
125 static void lower(
const wchar_t* src,
size_t len,
wchar_t* dest) {
126 unicode_traits<wchar_type>::lower(to_w(src), len, to_w(dest));
129 static int compareiu(
const wchar_t* text1,
size_t len1,
const wchar_t* text2,
size_t len2) {
130 return unicode_traits<wchar_type>::compareiu(to_w(text1), len1, to_w(text2), len2);
132 static size_t hashia(
const wchar_t* src,
size_t s) {
133 return unicode_traits<wchar_type>::hashia(to_w(src), s);
135 static size_t hashiu(
const wchar_t* src,
size_t s) {
136 return unicode_traits<wchar_type>::hashiu(to_w(src), s);
141struct unicode_traits<char8_t> {
142 static size_t upper(
const ubs*& src,
size_t lenStr, ubs*& dest,
size_t lenBuf) {
143 return unicode_traits<char>::upper((
const u8s*&)src, lenStr, (u8s*&)dest, lenBuf);
145 static size_t lower(
const ubs*& src,
size_t len, ubs*& dest,
size_t lenBuf) {
146 return unicode_traits<char>::lower((
const u8s*&)src, len, (u8s*&)dest, lenBuf);
148 static size_t upper_len(
const ubs* src,
size_t len) {
149 return unicode_traits<char>::upper_len((
const u8s*)src, len);
151 static size_t lower_len(
const ubs* src,
size_t len) {
152 return unicode_traits<char>::lower_len((
const u8s*)src, len);
155 static int compareiu(
const char8_t* text1,
size_t len1,
const char8_t* text2,
size_t len2) {
156 return unicode_traits<char>::compareiu((
const char*)text1, len1, (
const char*)text2, len2);
158 static size_t hashia(
const char8_t* src,
size_t s) {
159 return unicode_traits<char>::hashia((
const char*)src, s);
161 static size_t hashiu(
const char8_t* src,
size_t s) {
162 return unicode_traits<char>::hashiu((
const char*)src, s);
166#if defined(_MSC_VER) && _MSC_VER <= 1933
167template<
typename K,
typename... Args>
168using FmtString = std::_Basic_format_string<K, std::type_identity_t<Args>...>;
169#elif __clang_major__ >= 15 || _MSC_VER > 1933 || __GNUC__ >= 13
170template<
typename K,
typename... Args>
171using FmtString = std::basic_format_string<K, std::type_identity_t<Args>...>;
173template<
typename K,
typename... Args>
174using FmtString = std::basic_string_view<K>;
178SIMSTR_API std::optional<double> impl_to_double(
const K* start,
const K* end);
192template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
193class str_algs :
public str_src_algs<K, StrRef, Impl, Mutable> {
194 constexpr const Impl& d()
const noexcept {
195 return *
static_cast<const Impl*
>(
this);
197 constexpr size_t _len()
const noexcept {
200 constexpr const K* _str()
const noexcept {
201 return d().symbols();
203 constexpr bool _is_empty()
const noexcept {
204 return d().is_empty();
209 using str_piece = StrRef;
210 using traits = ch_traits<K>;
211 using uni = unicode_traits<K>;
212 using uns_type = std::make_unsigned_t<K>;
213 using my_type = Impl;
214 using base = str_src_algs<K, StrRef, Impl, Mutable>;
215 str_algs() =
default;
217 int compare_iu(
const K* text,
size_t len)
const noexcept {
219 return _is_empty() ? 0 : 1;
220 return uni::compareiu(_str(), _len(), text, len);
231 return compare_iu(text.symbols(), text.length());
242 return text.length() == _len() && compare_iu(text.symbols(), text.length()) == 0;
253 return compare_iu(text.symbols(), text.length()) < 0;
257 bool starts_with_iu(
const K* prefix,
size_t len)
const noexcept {
258 return _len() >= len && 0 == uni::compareiu(_str(), len, prefix, len);
267 return starts_with_iu(prefix.symbols(), prefix.length());
271 constexpr bool ends_with_iu(
const K* suffix,
size_t len)
const noexcept {
272 size_t myLen = _len();
273 return myLen >= len && 0 == uni::compareiu(_str() + myLen - len, len, suffix, len);
282 return ends_with_iu(suffix.symbols(), suffix.length());
292 template<
typename R = my_type>
294 return R::upperred_from(d());
304 template<
typename R = my_type>
306 return R::lowered_from(d());
314 template<
bool SkipWS = true,
bool AllowPlus = true>
317 const K* ptr = _str();
318 if constexpr (SkipWS) {
319 while (len && uns_type(*ptr) <=
' ') {
324 if constexpr (AllowPlus) {
325 if (len && *ptr == K(
'+')) {
334 if constexpr(
sizeof(K) == 1 &&
requires {std::from_chars(std::declval<const K*>(), std::declval<const K*>(), std::declval<double&>()); }) {
336 if (std::from_chars((
const K*)ptr, (
const K*)ptr + len, d).ec == std::errc{}) {
342 if constexpr (
sizeof(K) == 1) {
343 return impl_to_double((
const char*)ptr, (
const char*)ptr + len);
344 }
else if constexpr (
sizeof(K) == 2) {
345 return impl_to_double((
const char16_t*)ptr, (
const char16_t*)ptr + len);
347 return impl_to_double((
const char32_t*)ptr, (
const char32_t*)ptr + len);
358 t = res ? *res : std::nan(
"0");
372 template<ToIntNumber T>
388 template<
typename R = str_piece>
390 if (starts_with_iu(prefix)) {
407 template<
typename R = str_piece>
409 if (ends_with_iu(suffix)) {
426 template<
typename R = str_piece>
428 str_piece res = *
this;
429 while(res.starts_with_iu(prefix)) {
430 res = res(prefix.
length());
431 if (--max_count == 0) {
449 template<
typename R = str_piece>
451 str_piece res = *
this;
452 while(res.ends_with_iu(suffix)) {
453 res = res(0, -suffix.
length());
481struct simple_str : str_algs<K, simple_str<K>, simple_str<K>, false> {
483 using my_type = simple_str<K>;
485 const symb_type* str;
488 constexpr simple_str() =
default;
490 constexpr simple_str(
str_src<K> src) : str(src.str), len(src.len){}
496 template<typename T, size_t N = const_lit_for<K, T>::Count>
497 constexpr simple_str(T&& v) noexcept : str((
const K*)v), len(N - 1) {}
502 constexpr simple_str(
const K* p,
size_t l) noexcept : str(p), len(l) {}
508 constexpr simple_str(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : str(s.data()), len(s.length()) {}
513 constexpr simple_str(
const std::basic_string_view<K, std::char_traits<K>>& s) noexcept : str(s.data()), len(s.length()) {}
518 constexpr size_t length() const noexcept {
525 constexpr const symb_type*
symbols() const noexcept {
541 constexpr bool is_same(simple_str<K> other)
const noexcept {
542 return str == other.str && len == other.len;
550 constexpr bool is_part_of(simple_str<K> other)
const noexcept {
551 return str >= other.str && str + len <= other.str + other.len;
592struct simple_str_selector {
593 using type = simple_str<K>;
617struct simple_str_nt : simple_str<K>, null_terminated<K, simple_str_nt<K>> {
619 using my_type = simple_str_nt<K>;
620 using base = simple_str<K>;
622 constexpr static const K empty_string[1] = {0};
624 simple_str_nt() =
default;
641 template<
typename T>
requires is_one_of_type<std::remove_cvref_t<T>,
const K*, K*>::value
644 base::str = base::len ? p : empty_string;
650 template<typename T, size_t N = const_lit_for<K, T>::Count>
659 template<StrType<K> T>
662 base::len = t.length();
669 constexpr simple_str_nt(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : base(s) {}
671 static const my_type empty_str;
681 if (from > base::len) {
684 return {base::str + from, base::len - from};
689inline const simple_str_nt<K> simple_str_nt<K>::empty_str{simple_str_nt<K>::empty_string, 0};
705template<
typename Src,
typename Dest>
706struct utf_convert_selector;
708template<
typename Src>
709struct utf_convert_selector<Src, Src> {
710 static size_t need_len(
const Src* src,
size_t srcLen) {
713 static size_t convert(
const Src* src,
size_t srcLen, Src* dest) {
714 ch_traits<Src>::copy(dest, src, srcLen + 1);
720struct utf_convert_selector<u8s, u16s> {
721 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
722 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u16s* dest);
726struct utf_convert_selector<u8s, u32s> {
727 static SIMSTR_API
size_t need_len(
const u8s* src,
size_t srcLen);
728 static SIMSTR_API
size_t convert(
const u8s* src,
size_t srcLen, u32s* dest);
732struct utf_convert_selector<u16s, u8s> {
733 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
734 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u8s* dest);
738struct utf_convert_selector<u16s, u32s> {
739 static SIMSTR_API
size_t need_len(
const u16s* src,
size_t srcLen);
740 static SIMSTR_API
size_t convert(
const u16s* src,
size_t srcLen, u32s* dest);
744struct utf_convert_selector<u32s, u8s> {
745 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
746 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u8s* dest);
750struct utf_convert_selector<u32s, u16s> {
751 static SIMSTR_API
size_t need_len(
const u32s* src,
size_t srcLen);
752 static SIMSTR_API
size_t convert(
const u32s* src,
size_t srcLen, u16s* dest);
769template<
typename K,
typename Impl>
770class from_utf_convertible {
772 from_utf_convertible() =
default;
773 using my_type = Impl;
781 requires(!std::is_same_v<O, K>)
783 using from_t = to_base_char_t<O>;
784 using to_t = to_base_char_t<K>;
786 using worker = utf_convert_selector<from_t, to_t>;
787 Impl* d =
static_cast<Impl*
>(
this);
788 size_t len = init.
length();
792 size_t need = worker::need_len((
const from_t*)init.
symbols(), len);
793 K*
str = d->init(need);
795 worker::convert((
const from_t*)init.
symbols(), len, (to_t*)
str);
808template<
typename From,
typename To>
requires (!std::is_same_v<From, To>)
810 using symb_type = To;
811 using from_t = to_base_char_t<From>;
812 using to_t = to_base_char_t<To>;
813 using worker = utf_convert_selector<from_t, to_t>;
819 size_t length()
const noexcept {
820 return worker::need_len((
const from_t*)source_.symbols(), source_.length());
822 To* place(To* ptr)
const noexcept {
823 return ptr + worker::convert((
const from_t*)source_.symbols(), source_.length(), (to_t*)ptr);
839template<
typename To,
typename From>
requires (!std::is_same_v<From, To>)
848template<
typename A,
typename K>
850 A::is_str_storable ==
true;
851 std::is_same_v<typename A::symb_type, K>;
858template<
typename A,
typename K>
865template<
typename A,
typename K>
910template<
typename K,
typename Impl,
typename Allocator>
913 using my_type = Impl;
914 using traits = ch_traits<K>;
915 using allocator_t = Allocator;
925 return *
static_cast<Allocator*
>(
this);
927 constexpr const allocator_t&
allocator()
const {
928 return *
static_cast<const Allocator*
>(
this);
931 using uni = unicode_traits<K>;
933 constexpr Impl& d() noexcept {
934 return *
static_cast<Impl*
>(
this);
936 constexpr const Impl& d() const noexcept {
937 return *
static_cast<const Impl*
>(
this);
946 template<
typename... Args>
947 explicit constexpr str_storable(Args&&... args) : Allocator(
std::forward<Args>(args)...) {}
957 K* ptr = d().init(other.
length());
972 size_t l = pattern.
length(), allLen = l * repeat;
974 K* ptr = d().init(allLen);
975 for (
size_t i = 0; i < repeat; i++) {
976 traits::copy(ptr, pattern.
symbols(), l);
993 K*
str = d().init(count);
994 traits::assign(
str, count, pad);
1011 template<StrExprForType<K> A>
1013 size_t len = expr.length();
1015 *expr.place((
typename A::symb_type*)d().init(len)) = 0;
1033 template<StrType<K> From>
1034 void init_replaced(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0) {
1035 auto findes = f.find_all(pattern, offset, maxCount);
1036 if (!findes.size()) {
1037 new (
this) my_type{f};
1040 size_t srcLen = f.length();
1041 size_t newSize = srcLen +
static_cast<ptrdiff_t
>(repl.len - pattern.len) * findes.size();
1044 new (
this) my_type{};
1048 K* ptr = d().init(newSize);
1051 for (
const auto& s: findes) {
1052 size_t copyLen = s - from;
1054 traits::copy(ptr, src + from, copyLen);
1058 traits::copy(ptr, repl.str, repl.len);
1061 from = s + pattern.len;
1065 traits::copy(ptr, src + from, srcLen);
1071 template<StrType<K> From,
typename Op1,
typename... Args>
1072 requires std::is_constructible_v<allocator_t, Args...>
1073 static my_type changeCaseAscii(
const From& f,
const Op1& opMakeNeedCase, Args&&... args) {
1074 my_type result{std::forward<Args>(args)...};
1075 size_t len = f.length();
1077 const K* source = f.symbols();
1078 K* destination = result.init(len);
1080 *destination++ = opMakeNeedCase(*source++);
1090 template<
typename T,
bool Dummy = true>
1092 template<
typename From,
typename Op1,
typename... Args>
1093 requires std::is_constructible_v<allocator_t, Args...>
1094 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
1095 my_type result{std::forward<Args>(args)...};
1096 size_t len = f.length();
1098 opChangeCase(f.symbols(), len, result.init(len));
1105 template<
bool Dummy>
1106 struct ChangeCase<u8s, Dummy> {
1107 template<
typename From,
typename Op1,
typename... Args>
1108 requires std::is_constructible_v<allocator_t, Args...>
1109 static my_type changeCase(
const From& f,
const Op1& opChangeCase, Args&&... args) {
1110 my_type result{std::forward<Args>(args)...};
1112 size_t len = f.length();
1114 const K* ptr = f.symbols();
1115 K* pWrite = result.init(len);
1117 const u8s* source = ptr;
1119 size_t newLen = opChangeCase(source, len, dest, len);
1123 result.set_size(newLen);
1124 }
else if (newLen > len) {
1127 size_t readed =
static_cast<size_t>(source - ptr);
1128 size_t writed =
static_cast<size_t>(dest - pWrite);
1129 pWrite = result.set_size(newLen);
1130 dest = pWrite + writed;
1131 opChangeCase(source, len - readed, dest, newLen - writed);
1141 inline static constexpr bool is_str_storable =
true;
1148 constexpr operator const K*()
const noexcept {
1149 return d().symbols();
1159 constexpr s_str_nt
to_nts(
size_t from = 0)
const {
1160 size_t len = d().
length();
1164 return {d().symbols() + from, len - from};
1172 constexpr operator s_str_nt()
const {
1173 return {d().symbols(), d().length()};
1213 template<
typename T,
typename... Args>
1214 requires std::is_constructible_v<allocator_t, Args...>
1215 static my_type
join(
const T& strings, s_str delimiter,
bool tail =
false,
bool skip_empty =
false, Args&&... args) {
1216 my_type result(std::forward<Args>(args)...);
1217 if (strings.size()) {
1218 if (strings.size() == 1 && (!delimiter.
length() || !tail)) {
1219 result = strings.front();
1221 size_t commonLen = 0;
1222 for (
const auto& t: strings) {
1223 size_t len = t.length();
1224 if (len > 0 || !skip_empty) {
1225 if (commonLen > 0) {
1226 commonLen += delimiter.len;
1231 commonLen += (tail && delimiter.len > 0 && (commonLen > 0 || (!skip_empty && strings.size() > 0))? delimiter.len : 0);
1233 K* ptr = result.init(commonLen);
1235 for (
const auto& t: strings) {
1236 size_t copyLen = t.length();
1237 if (delimiter.len > 0 && write != ptr && (copyLen || !skip_empty)) {
1238 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1239 write += delimiter.len;
1241 ch_traits<K>::copy(write, t.symbols(), copyLen);
1244 if (delimiter.len > 0 && tail && (write != ptr || (!skip_empty && strings.size() > 0))) {
1245 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1246 write += delimiter.len;
1250 result.create_empty();
1264 template<StrType<K> From,
typename... Args>
1265 requires std::is_constructible_v<allocator_t, Args...>
1267 return changeCaseAscii(f, makeAsciiUpper<K>, std::forward<Args>(args)...);
1277 template<StrType<K> From,
typename... Args>
1278 requires std::is_constructible_v<allocator_t, Args...>
1280 return changeCaseAscii(f, makeAsciiLower<K>, std::forward<Args>(args)...);
1294 template<StrType<K> From,
typename... Args>
1295 requires std::is_constructible_v<allocator_t, Args...>
1297 return ChangeCase<K>::changeCase(f, uni::upper, std::forward<Args>(args)...);
1311 template<StrType<K> From,
typename... Args>
1312 requires std::is_constructible_v<allocator_t, Args...>
1314 return ChangeCase<K>::changeCase(f, uni::lower, std::forward<Args>(args)...);
1332 template<StrType<K> From,
typename... Args>
1333 requires std::is_constructible_v<allocator_t, Args...>
1334 static my_type
replaced_from(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args) {
1335 return my_type{f, pattern, repl, offset, maxCount, std::forward<Args>(args)...};
1345 { a.allocate(size) } -> std::same_as<void*>;
1346 { a.deallocate(void_ptr) }
noexcept -> std::same_as<void>;
1349struct printf_selector {
1350 template<
typename K,
typename... T>
requires (is_one_of_std_char_v<K>)
1351 static int snprintf(K* buffer,
size_t count,
const K* format, T&&... args) {
1352 if constexpr (
sizeof(K) == 1) {
1354 return std::snprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), std::forward<T>(args)...);
1358 return _sprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1362 return std::swprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1366 return _swprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1370 template<
typename K>
requires (is_one_of_std_char_v<K>)
1371 static int vsnprintf(K* buffer,
size_t count,
const K* format, va_list args) {
1372 if constexpr (std::is_same_v<K, u8s>) {
1374 return std::vsnprintf(buffer, count, format, args);
1378 return _vsprintf_p(buffer, count, format, args);
1382 return std::vswprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args);
1386 return _vswprintf_p(buffer, count, format, args);
1392inline size_t grow2(
size_t ret,
size_t currentCapacity) {
1393 return ret <= currentCapacity ? ret : ret * 2;
1434template<
typename K,
typename Impl>
1437 using my_type = Impl;
1441 return *
static_cast<Impl*
>(
this);
1443 const Impl& d()
const {
1444 return *
static_cast<const Impl*
>(
this);
1446 size_t _len()
const noexcept {
1447 return d().length();
1449 const K* _str()
const noexcept {
1450 return d().symbols();
1453 using symb_type = K;
1454 using traits = ch_traits<K>;
1455 using uni = unicode_traits<K>;
1456 using uns_type = std::make_unsigned_t<K>;
1458 template<
typename Op>
1459 Impl& make_trim_op(
const Op& op) {
1460 str_piece me = d(), pos = op(me);
1461 if (me.
length() != pos.length()) {
1462 if (me.
symbols() != pos.symbols())
1463 traits::move(
const_cast<K*
>(me.
symbols()), pos.symbols(), pos.length());
1464 d().set_size(pos.length());
1470 Impl& commonChangeCase() {
1471 size_t len = _len();
1473 Op(_str(), len,
str());
1480 template<
typename T,
bool Dummy = true>
1482 static Impl&
upper(Impl& obj) {
1483 return obj.template commonChangeCase<unicode_traits<K>::upper>();
1485 static Impl&
lower(Impl& obj) {
1486 return obj.template commonChangeCase<unicode_traits<K>::lower>();
1491 Impl& utf8CaseChange() {
1494 size_t len = _len();
1496 u8s* writePos =
str();
1497 const u8s *startData = writePos, *readPos = writePos;
1498 size_t newLen = Op(readPos, len, writePos, len);
1502 d().set_size(newLen);
1503 }
else if (newLen > len) {
1506 size_t readed =
static_cast<size_t>(readPos - startData);
1507 size_t writed =
static_cast<size_t>(writePos - startData);
1508 d().set_size(newLen);
1510 readPos = startData + readed;
1511 writePos =
const_cast<u8s*
>(startData) + writed;
1512 Op(readPos, len - readed, writePos, newLen - writed);
1517 template<
bool Dummy>
1518 struct CaseTraits<u8s, Dummy> {
1519 static Impl&
upper(Impl& obj) {
1520 return obj.template utf8CaseChange<unicode_traits<u8s>::upper>();
1522 static Impl&
lower(Impl& obj) {
1523 return obj.template utf8CaseChange<unicode_traits<u8s>::lower>();
1527 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count>
1528 Impl& makeTrim(T&& pattern) {
1529 return make_trim_op(trim_operator<S, K, N - 1, withSpaces>{pattern});
1532 template<TrimS
ides S,
bool withSpaces>
1533 Impl& makeTrim(str_piece pattern) {
1534 return make_trim_op(trim_operator<S, K, 0, withSpaces>{{pattern}});
1553 explicit operator K*()
noexcept {
1563 return make_trim_op(SimpleTrim<TrimSides::TrimAll, K>{});
1572 return make_trim_op(SimpleTrim<TrimSides::TrimLeft, K>{});
1581 return make_trim_op(SimpleTrim<TrimSides::TrimRight, K>{});
1591 template<typename T, size_t N = const_lit_for<K, T>::Count>
1592 requires is_const_pattern<N>
1594 return makeTrim<TrimSides::TrimAll, false>(pattern);
1604 template<typename T, size_t N = const_lit_for<K, T>::Count>
1605 requires is_const_pattern<N>
1607 return makeTrim<TrimSides::TrimLeft, false>(pattern);
1617 template<typename T, size_t N = const_lit_for<K, T>::Count>
1618 requires is_const_pattern<N>
1620 return makeTrim<TrimSides::TrimRight, false>(pattern);
1630 template<typename T, size_t N = const_lit_for<K, T>::Count>
1631 requires is_const_pattern<N>
1633 return makeTrim<TrimSides::TrimAll, true>(pattern);
1643 template<typename T, size_t N = const_lit_for<K, T>::Count>
1644 requires is_const_pattern<N>
1646 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1656 template<typename T, size_t N = const_lit_for<K, T>::Count>
1657 requires is_const_pattern<N>
1659 return makeTrim<TrimSides::TrimRight, true>(pattern);
1670 return pattern.
length() ? makeTrim<TrimSides::TrimAll, false>(pattern) : d();
1681 return pattern.
length() ? makeTrim<TrimSides::TrimLeft, false>(pattern) : d();
1692 return pattern.
length() ? makeTrim<TrimSides::TrimRight, false>(pattern) : d();
1703 return makeTrim<TrimSides::TrimAll, true>(pattern);
1714 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1725 return makeTrim<TrimSides::TrimRight, true>(pattern);
1735 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1737 if (isAsciiLower(s))
1750 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1752 if (isAsciiUpper(s))
1770 return CaseTraits<K>::upper(d());
1785 return CaseTraits<K>::lower(d());
1789 template<
typename T>
1790 Impl& changeImpl(
size_t from,
size_t len, T expr) {
1791 size_t myLen = _len();
1795 if (from + len > myLen) {
1799 size_t otherLen = expr.length();
1800 if (len == otherLen) {
1801 expr.place(buffer + from);
1803 size_t tailLen = myLen - from - len;
1804 if (len > otherLen) {
1805 expr.place(buffer + from);
1806 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1807 d().set_size(myLen - (len - otherLen));
1809 buffer = d().set_size(myLen + otherLen - len);
1810 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1811 expr.place(buffer + from);
1817 template<
typename T>
1818 Impl& appendImpl(T expr) {
1819 if (
size_t len = expr.length(); len) {
1820 size_t size = _len();
1821 expr.place(d().set_size(size + len) + size);
1826 template<
typename T>
1827 Impl& appendFromImpl(
size_t pos, T expr) {
1830 if (
size_t len = expr.length())
1831 expr.place(d().set_size(pos + len) + pos);
1838 inline static constexpr bool is_str_mutable =
true;
1848 return appendImpl<str_piece>(other);
1858 template<StrExprForType<K> A>
1860 return appendImpl<const A&>(expr);
1871 return appendImpl<str_piece>(other);
1881 template<StrExprForType<K> A>
1883 return appendImpl<const A&>(expr);
1900 return appendFromImpl<str_piece>(pos, other);
1916 template<StrExprForType<K> A>
1918 return appendFromImpl<const A&>(pos, expr);
1932 Impl&
change(
size_t from,
size_t len, str_piece other) {
1933 return changeImpl<str_piece>(from, len, other);
1947 template<StrExprForType<K> A>
1948 Impl&
change(
size_t from,
size_t len,
const A& expr) {
1949 return changeImpl<const A&>(from, len, expr);
1962 return changeImpl<str_piece>(to, 0, other);
1974 template<StrExprForType<K> A>
1976 return changeImpl<const A&>(to, 0, expr);
1989 return changeImpl<const empty_expr<K>&>(from, len, {});
2000 return changeImpl<str_piece>(0, 0, other);
2010 template<StrExprForType<K> A>
2012 return changeImpl<const A&>(0, 0, expr);
2028 Impl&
replace(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
2029 offset = d().find(pattern, offset);
2030 if (offset == str::npos) {
2035 size_t replLength = repl.
length(), patternLength = pattern.
length();
2037 if (patternLength == replLength) {
2041 while (maxCount--) {
2042 traits::copy(ptr + offset, repl.
symbols(), replLength);
2043 offset = d().find(pattern, offset + replLength);
2044 if (offset == str::npos)
2047 }
else if (patternLength > replLength) {
2051 traits::copy(ptr + offset, repl.
symbols(), replLength);
2052 size_t posWrite = offset + replLength;
2053 offset += patternLength;
2055 while (--maxCount) {
2056 size_t idx = d().find(pattern, offset);
2057 if (idx == str::npos)
2059 size_t lenOfPiece = idx - offset;
2060 traits::move(ptr + posWrite, ptr + offset, lenOfPiece);
2061 posWrite += lenOfPiece;
2062 traits::copy(ptr + posWrite, repl.
symbols(), replLength);
2063 posWrite += replLength;
2064 offset = idx + patternLength;
2066 size_t tailLen = _len() - offset;
2067 traits::move(ptr + posWrite, ptr + offset, tailLen);
2068 d().set_size(posWrite + tailLen);
2070 struct replace_grow_helper {
2071 replace_grow_helper(my_type& src, str_piece p, str_piece r,
size_t mc,
size_t d)
2072 : source(src), pattern(p), repl(r), maxCount(mc), delta(d) {}
2074 const str_piece pattern;
2075 const str_piece repl;
2079 K* reserve_for_copy{};
2080 size_t end_of_piece{};
2081 size_t total_length{};
2084 size_t found[16] = {offset};
2086 offset += pattern.
length();
2089 for (; idx < std::size(found) && maxCount > 0; idx++, maxCount--) {
2090 found[idx] = source.find(pattern, offset);
2091 if (found[idx] == str::npos) {
2094 offset = found[idx] + pattern.
length();
2097 if (idx == std::size(found) && maxCount > 0 && (offset = source.find(pattern, offset)) != str::npos) {
2102 if (!reserve_for_copy) {
2105 end_of_piece = source.length();
2106 total_length = end_of_piece + all_delta;
2107 reserve_for_copy = source.alloc_for_copy(total_length);
2109 K* dst_start = reserve_for_copy;
2110 const K* src_start = source.symbols();
2112 size_t pos = found[idx] + pattern.
length();
2113 size_t lenOfPiece = end_of_piece - pos;
2114 ch_traits<K>::move(dst_start + pos + all_delta, src_start + pos, lenOfPiece);
2115 ch_traits<K>::copy(dst_start + pos + all_delta - repl.
length(), repl.
symbols(), repl.
length());
2117 end_of_piece = found[idx];
2119 if (!all_delta && reserve_for_copy != src_start) {
2120 ch_traits<K>::copy(dst_start, src_start, found[0]);
2123 } helper(d(), pattern, repl, maxCount, repl.
length() - pattern.
length());
2124 helper.replace(offset);
2125 d().set_from_copy(helper.reserve_for_copy, helper.total_length);
2145 template<StrType<K> From>
2146 Impl&
replace_from(
const From& f, str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
2148 K* dst = d().reserve_no_preserve(f.length());
2151 if (maxCount == 0) {
2154 size_t src_length = f.length(), start = 0;
2155 while (maxCount--) {
2156 offset = f.find(pattern, offset);
2157 if (offset == str::npos) {
2160 size_t piece_len = offset - start;
2162 ch_traits<K>::copy(dst, src + start, piece_len);
2170 offset += pattern.
length();
2173 if (start < src_length) {
2174 ch_traits<K>::copy(dst, src + start, src_length - start);
2176 d().set_size(src_length - delta);
2179 replace(pattern, repl, offset, maxCount);
2207 template<
typename Op>
2208 Impl&
fill(
size_t from,
const Op& fillFunction) {
2209 size_t size = _len();
2212 size_t capacity = d().capacity();
2216 size_t needSize =
static_cast<size_t>(fillFunction(ptr + from, capacity));
2217 if (capacity >= needSize) {
2218 d().set_size(from + needSize);
2221 ptr = from == 0 ? d().reserve_no_preserve(needSize) : d().set_size(from + needSize);
2222 capacity = d().capacity() - from;
2234 template<
typename Op>
2235 requires std::is_invocable_v<Op, K*, size_t>
2237 return fill(0, fillFunction);
2247 template<
typename Op>
2248 requires std::is_invocable_v<Op, K*, size_t>
2250 return fill(_len(), fillFunction);
2260 template<
typename Op>
2261 requires std::is_invocable_v<Op, my_type&>
2280 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2282 size_t size = _len();
2285 size_t capacity = d().capacity();
2296 if constexpr (
sizeof(K) == 1 && !isWindowsOs) {
2297 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2298 if (result > (
int)capacity) {
2299 ptr = from == 0 ? d().reserve_no_preserve(result) : d().set_size(from + result);
2300 result = printf_selector::snprintf(ptr + from, result + 1,
format, std::forward<T>(args)...);
2304 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2311 ptr = from == 0 ? d().reserve_no_preserve(capacity) : d().set_size(from + capacity);
2317 d().set_size(
static_cast<size_t>(traits::length(_str())));
2319 d().set_size(from + result);
2334 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2350 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2361 inline static K pad;
2362 K& operator*()
const {
2365 writer& operator++() {
2366 if (writed < max_write) {
2369 size_t l = ptr - store->begin();
2371 ptr = store->set_size(l + std::min(l / 2,
size_t(8192))) + l;
2379 writer operator++(
int) {
2385 writer(my_type& s, K* p, K* e,
size_t ml) : store(&s), ptr(p), end(e), max_write(ml) {}
2387 writer(
const writer&) =
delete;
2388 writer& operator=(
const writer&)
noexcept =
delete;
2389 writer(writer&&) noexcept = default;
2390 writer& operator=(writer&&) noexcept = default;
2391 using difference_type =
int;
2393 using fmt_type = to_std_char_t<K>;
2408 template<typename... T> requires (is_one_of_std_char_v<K>)
2410 size_t size = _len();
2413 size_t capacity = d().capacity();
2416 auto result = std::format_to(writer{d(), ptr + from, ptr + capacity, size_t(-1)},
2417 std::forward<decltype(format)>(
format), std::forward<T>(args)...);
2418 d().set_size(result.ptr - _str());
2437 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2439 size_t size = _len();
2442 size_t capacity = d().capacity();
2445 if constexpr (std::is_same_v<K, u8s>) {
2446 auto result = std::vformat_to(
2447 writer{d(), ptr + from, ptr + capacity, max_write},
2448 std::basic_string_view<K>{
format.symbols(),
format.length()},
2449 std::make_format_args(args...));
2450 d().set_size(result.ptr - _str());
2452 auto result = std::vformat_to(
2453 writer{d(), to_one_of_std_char(ptr + from), ptr + capacity, max_write},
2454 std::basic_string_view<wchar_t>{to_one_of_std_char(
format.symbols()),
format.length()},
2455 std::make_wformat_args(std::forward<T>(args)...));
2456 d().set_size(result.ptr - _str());
2472 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2473 Impl&
format(
const FmtString<fmt_type, T...>& pattern, T&&... args) {
2474 return format_from(0, pattern, std::forward<T>(args)...);
2488 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2504 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2520 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2538 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2556 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2570 template<
typename Op,
typename... Args>
2571 Impl&
with(
const Op& fillFunction, Args&&... args) {
2572 fillFunction(d(), std::forward<Args>(args)...);
2578struct SharedStringData {
2579 std::atomic_size_t ref_;
2581 SharedStringData() {
2585 return (K*)(
this + 1);
2588 ref_.fetch_add(1, std::memory_order_relaxed);
2590 void decr(Allocatorable
auto& allocator) {
2591 size_t val = ref_.fetch_sub(1, std::memory_order_relaxed);
2593 allocator.deallocate(
this);
2596 static SharedStringData<K>* create(
size_t l, Allocatorable
auto& allocator) {
2597 size_t size =
sizeof(SharedStringData<K>) + (l + 1) *
sizeof(K);
2598 return new (allocator.allocate(size)) SharedStringData();
2600 static SharedStringData<K>* from_str(
const K* p) {
2601 return (SharedStringData<K>*)p - 1;
2603 K* place(K* p,
size_t len) {
2604 ch_traits<K>::copy(p, str(), len);
2611class string_common_allocator {
2613 void* allocate(
size_t bytes) {
2614 return new char[bytes];
2616 void deallocate(
void* address)
noexcept {
2617 delete []
static_cast<char*
>(address);
2621string_common_allocator default_string_allocator_selector(...);
2628using allocator_string =
decltype(default_string_allocator_selector(
int(0)));
2630template<
typename K, Allocatorable Allocator>
2662template<
typename K,
size_t N,
bool forShared = false, Allocatorable Allocator = allocator_
string>
2664 public str_algs<K, simple_str<K>, lstring<K, N, forShared, Allocator>, true>,
2665 public str_mutable<K, lstring<K, N, forShared, Allocator>>,
2666 public str_storable<K, lstring<K, N, forShared, Allocator>, Allocator>,
2667 public null_terminated<K, lstring<K, N, forShared, Allocator>>,
2668 public from_utf_convertible<K, lstring<K, N, forShared, Allocator>> {
2670 using symb_type = K;
2672 using allocator_t = Allocator;
2681 extra = forShared ?
sizeof(SharedStringData<K>) : 0,
2684 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
2685 using base_storable = str_storable<K, my_type, Allocator>;
2686 using base_mutable = str_mutable<K, my_type>;
2687 using base_utf = from_utf_convertible<K, my_type>;
2688 using traits = ch_traits<K>;
2689 using s_str = base_storable::s_str;
2691 friend base_storable;
2692 friend base_mutable;
2694 friend class sstring<K, Allocator>;
2701 K local_[LocalCapacity + 1];
2704 constexpr void create_empty() {
2709 constexpr static size_t calc_capacity(
size_t s) {
2710 const int al =
alignof(std::max_align_t) < 16 ? 16 : alignof(std::max_align_t);
2711 size_t real_need = (s + 1) *
sizeof(K) + extra;
2712 size_t aligned_alloced = (real_need + al - 1) / al * al;
2713 return (aligned_alloced - extra) /
sizeof(K) - 1;
2716 constexpr K* init(
size_t s) {
2717 size_t need_cap = s;
2718 if (need_cap > LocalCapacity) {
2719 need_cap = calc_capacity(s);
2720 data_ = alloc_place(need_cap);
2721 capacity_ = need_cap;
2729 constexpr bool is_alloced() const noexcept {
2730 return data_ != local_;
2733 constexpr void dealloc() {
2735 base_storable::allocator().deallocate(to_real_address(data_));
2740 constexpr static K* to_real_address(
void* ptr) {
2741 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) - extra);
2743 constexpr static K* from_real_address(
void* ptr) {
2744 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) + extra);
2747 constexpr K* alloc_place(
size_t newSize) {
2748 return from_real_address(base_storable::allocator().allocate((newSize + 1) *
sizeof(K) + extra));
2752 constexpr K* alloc_for_copy(
size_t newSize) {
2753 if (capacity() >= newSize) {
2758 return alloc_place(calc_capacity(newSize));
2762 constexpr void set_from_copy(K* ptr,
size_t newSize) {
2768 capacity_ = calc_capacity(newSize);
2773 constexpr void copy_from_another(K* buf,
const K* src,
size_t size) {
2776 size_t need_copy_bytes = (size + 1) *
sizeof(K);
2777 size_t cnt = (need_copy_bytes +
sizeof(
void*) - 1) /
sizeof(
void*) *
sizeof(
void*);
2778 traits::copy(buf, src, cnt /
sizeof(K));
2787 template<
typename... Args>
2788 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
2789 constexpr lstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
2790 : base_storable(
std::forward<Args>(args)...) {
2802 template<
typename... Args>
2803 requires std::is_constructible_v<allocator_t, Args...>
2804 constexpr lstring(s_str other, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2817 template<
typename... Args>
2818 requires std::is_constructible_v<allocator_t, Args...>
2819 constexpr lstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2832 template<
typename... Args>
2833 requires std::is_constructible_v<allocator_t, Args...>
2834 constexpr lstring(
size_t count, K pad, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2851 template<
typename... Args>
2852 requires std::is_constructible_v<allocator_t, Args...>
2872 template<StrType<K> From,
typename... Args>
2873 requires std::is_constructible_v<allocator_t, Args...>
2874 constexpr lstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
2875 : base_storable(
std::forward<Args>(args)...) {
2883 constexpr ~lstring() {
2894 struct copy{uint64_t p[2];};
2895 constexpr size_t short_str =
sizeof(copy) /
sizeof(K);
2897 if (other.size_ < short_str) {
2899 size_ = other.size_;
2900 *(copy*)local_ = *(
const copy*)other.local_;
2904 if (
size_t size = other.size_) {
2905 copy_from_another(init(size), other.symbols(), size);
2918 template<
typename... Args>
2919 requires(
sizeof...(Args) > 0 && std::is_convertible_v<allocator_t, Args...>)
2920 constexpr lstring(
const my_type& other, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2922 copy_from_another(init(other.size_), other.symbols(), other.size_);
2935 template<typename T, size_t I = const_lit_for<K, T>::Count,
typename... Args>
2936 requires std::is_constructible_v<allocator_t, Args...>
2937 constexpr lstring(T&& value, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2938 if constexpr (I > 1) {
2939 K* ptr = init(I - 1);
2940 traits::copy(ptr, (
const K*)value, I - 1);
2952 constexpr lstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
2954 size_ = other.size_;
2955 if (other.is_alloced()) {
2956 data_ = other.data_;
2957 other.data_ = other.local_;
2958 capacity_ = other.capacity_;
2961 copy_from_another(data_, other.local_, size_);
2964 other.local_[0] = 0;
2977 template<
typename Op,
typename... Args>
2978 requires(std::is_constructible_v<Allocator, Args...> && (std::is_invocable_v<Op, my_type&> || std::is_invocable_v<Op, K*, size_t>))
2979 lstring(
const Op& op, Args&&... args) : base_storable(std::forward<Args>(args)...) {
2983 template<
typename O>
2984 requires(!std::is_same_v<O, K>)
2986 this->init_from_utf_convertible(init);
2989 template<
typename O,
typename I,
bool M>
2990 requires(!std::is_same_v<O, K>)
2991 lstring(
const str_algs<O, simple_str<O>, I, M>& init) {
2992 this->init_from_utf_convertible(init.
to_str());
3011 if (&other !=
this) {
3013 size_ = other.size_;
3028 if (&other !=
this) {
3030 if (other.is_alloced()) {
3031 data_ = other.data_;
3032 capacity_ = other.capacity_;
3034 traits::copy(data_, other.local_, other.size_ + 1);
3037 size_ = other.size_;
3038 other.create_empty();
3043 my_type& assign(
const K* other,
size_t len) {
3045 bool isIntersect = other >= data_ && other + len <= data_ + size_;
3051 if (other > data_) {
3052 traits::move(data_, other, len);
3055 traits::copy(reserve_no_preserve(len), other, len);
3071 return assign(other.str, other.len);
3081 template<typename T, size_t S = const_lit_for<K, T>::Count>
3083 return assign((
const K*)other, S - 1);
3096 size_t newLen = expr.
length();
3142 newSize = calc_capacity(newSize);
3143 K* newData = alloc_place(newSize);
3146 capacity_ = newSize;
3164 newSize = calc_capacity(newSize);
3165 K* newData = alloc_place(newSize);
3166 traits::copy(newData, data_, size_);
3169 capacity_ = newSize;
3187 if (newSize > cap) {
3188 size_t needPlace = newSize;
3189 if (needPlace < (cap + 1) * 2) {
3190 needPlace = (cap + 1) * 2 - 1;
3203 return !is_alloced();
3213 for (
size_t i = 0; i < cap; i++) {
3214 if (data_[i] == 0) {
3229 size_t need_capacity = calc_capacity(size_);
3230 if (is_alloced() && capacity_ > need_capacity) {
3231 K* newData = size_ <=
LocalCapacity ? local_ : alloc_place(need_capacity);
3232 traits::copy(newData, data_, size_ + 1);
3237 capacity_ = need_capacity;
3253template<
size_t N = 15>
3254using lstringa = lstring<u8s, N>;
3255template<
size_t N = 15>
3256using lstringb = lstring<ubs, N>;
3257template<
size_t N = 15>
3258using lstringw = lstring<wchar_t, N>;
3259template<
size_t N = 15>
3260using lstringu = lstring<u16s, N>;
3261template<
size_t N = 15>
3262using lstringuu = lstring<u32s, N>;
3264template<
size_t N = 15>
3265using lstringsa = lstring<u8s, N, true>;
3266template<
size_t N = 15>
3267using lstringsb = lstring<ubs, N, true>;
3268template<
size_t N = 15>
3269using lstringsw = lstring<wchar_t, N, true>;
3270template<
size_t N = 15>
3271using lstringsu = lstring<u16s, N, true>;
3272template<
size_t N = 15>
3273using lstringsuu = lstring<u32s, N, true>;
3276template<typename T, typename K = typename const_lit<T>::symb_type>
3277auto getLiteralType(T&&) {
3281template<
size_t Arch,
size_t L>
3282inline constexpr const size_t _local_count = 0;
3285inline constexpr const size_t _local_count<8, 1> = 23;
3287inline constexpr const size_t _local_count<8, 2> = 15;
3289inline constexpr const size_t _local_count<8, 4> = 7;
3291inline constexpr const size_t _local_count<4, 1> = 15;
3293inline constexpr const size_t _local_count<4, 2> = 11;
3295inline constexpr const size_t _local_count<4, 4> = 5;
3298constexpr const size_t local_count = _local_count<
sizeof(size_t),
sizeof(T)>;
3352template<
typename K, Allocatorable Allocator = allocator_
string>
3353class decl_empty_bases sstring :
3354 public str_algs<K, simple_str<K>, sstring<K, Allocator>, false>,
3355 public str_storable<K, sstring<K, Allocator>, Allocator>,
3356 public null_terminated<K, sstring<K, Allocator>>,
3357 public from_utf_convertible<K, sstring<K, Allocator>> {
3359 using symb_type = K;
3360 using uns_type = std::make_unsigned_t<K>;
3361 using my_type = sstring<K, Allocator>;
3362 using allocator_t = Allocator;
3364 enum { LocalCount = local_count<K> };
3367 using base_algs = str_algs<K, simple_str<K>, my_type,
false>;
3369 using base_utf = from_utf_convertible<K, my_type>;
3370 using traits = ch_traits<K>;
3371 using uni = unicode_traits<K>;
3372 using s_str = base_storable::s_str;
3374 friend base_storable;
3377 enum Types { Local, Constant, Shared };
3390 uns_type localRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
3405 constexpr void create_empty() {
3407 localRemain_ = LocalCount;
3410 constexpr K* init(
size_t s) {
3411 if (s > LocalCount) {
3419 localRemain_ = LocalCount - s;
3424 K* set_size(
size_t newSize) {
3430 if (newSize !=
size) {
3431 if (type_ == Constant) {
3434 if (newSize <= LocalCount) {
3435 if (type_ == Shared) {
3436 SharedStringData<K>* str_buf = SharedStringData<K>::from_str(sstr_);
3437 traits::copy(buf_, sstr_, newSize);
3441 localRemain_ = LocalCount - newSize;
3443 if (type_ == Shared) {
3444 if (newSize >
size || (newSize > 64 && newSize <=
size * 3 / 4)) {
3446 traits::copy(newStr, sstr_, newSize);
3450 }
else if (type_ == Local) {
3453 traits::copy(newStr, buf_,
size);
3462 K*
str = type_ == Local ? buf_ : (K*)sstr_;
3479 template<
typename... Args>
3480 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
3481 sstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
3482 : base_storable(
std::forward<Args>(args)...) {
3494 template<
typename... Args>
3495 requires std::is_constructible_v<allocator_t, Args...>
3496 sstring(s_str other, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3509 template<
typename... Args>
3510 requires std::is_constructible_v<allocator_t, Args...>
3511 sstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3524 template<
typename... Args>
3525 requires std::is_constructible_v<allocator_t, Args...>
3526 sstring(
size_t count, K pad, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3543 template<
typename... Args>
3544 requires std::is_constructible_v<allocator_t, Args...>
3564 template<StrType<K> From,
typename... Args>
3565 requires std::is_constructible_v<allocator_t, Args...>
3566 sstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
3567 : base_storable(
std::forward<Args>(args)...) {
3574 if (type_ == Shared) {
3584 constexpr sstring(
const my_type& other) noexcept : base_storable(other.allocator()) {
3585 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3586 if (type_ == Shared)
3587 SharedStringData<K>::from_str(sstr_)->incr();
3595 constexpr sstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
3596 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3597 other.create_empty();
3612 size_t size = src.length();
3614 if (src.is_alloced()) {
3618 if (
size > LocalCount) {
3625 new (SharedStringData<K>::from_str(
str)) SharedStringData<K>();
3630 localRemain_ = LocalCount -
size;
3631 traits::copy(buf_,
str,
size + 1);
3639 K*
str = init(src.size_);
3640 traits::copy(
str, src.symbols(),
size + 1);
3657 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename... Args>
3658 requires std::is_constructible_v<allocator_t, Args...>
3659 sstring(T&& s, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3662 cstr_ = (
const K*)s;
3671 template<
typename O>
requires(!std::is_same_v<O, K>)
3673 this->init_from_utf_convertible(init);
3676 template<
typename O,
typename I,
bool M>
requires(!std::is_same_v<O, K>)
3678 this->init_from_utf_convertible(init.
to_str());
3681 constexpr void swap(my_type&& other)
noexcept {
3682 char buf[
sizeof(buf_) +
sizeof(K)];
3683 memcpy(buf, buf_,
sizeof(buf));
3684 memcpy(buf_, other.buf_,
sizeof(buf));
3685 memcpy(other.buf_, buf,
sizeof(buf));
3687 std::swap(base_storable::allocator(), other.allocator());
3698 swap(std::move(other));
3720 template<typename T, size_t N = const_lit_for<K, T>::Count>
3732 template<
size_t N,
bool forShared,
typename A>
3746 return operator=(my_type{std::move(other)});
3768 if (type_ == Shared)
3775 return type_ == Local ? buf_ : cstr_;
3779 return type_ == Local ? LocalCount - localRemain_ : bigLen_;
3801 template<
typename... T>
3802 static my_type
printf(
const K* pattern, T&&... args) {
3815 template<
typename... T>
3816 static my_type
format(
const FmtString<to_std_char_t<K>, T...>& fmtString, T&&... args) {
3829 template<
typename... T>
3835template<
typename K, Allocatorable Allocator>
3836inline const sstring<K> sstring<K, Allocator>::empty_str{};
3840template<
typename K,
size_t N>
3841class decl_empty_bases cestring :
3842 public str_algs<K, simple_str<K>, cestring<K, N>, true>,
3843 public str_storable<K, cestring<K, N>, no_alloc>,
3844 public null_terminated<K, lstring<K, N>>
3848 using symb_type = K;
3849 using my_type = cestring<K, N>;
3853 LocalCapacity = N | (
sizeof(
void*) /
sizeof(K) - 1),
3858 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
3859 using base_storable = str_storable<K, my_type, no_alloc>;
3861 using traits = ch_traits<K>;
3862 using s_str = base_storable::s_str;
3864 friend base_storable;
3869 K local_[LocalCapacity + 1]{};
3871 constexpr void create_empty() {
3877 constexpr K* init(
size_t s) {
3879 if (size_ > LocalCapacity) {
3880 throw std::bad_alloc{};
3887 constexpr size_t length() const noexcept {
3891 constexpr const K* symbols() const noexcept {
3892 return is_cstr_ ? cstr_ : local_;
3895 constexpr bool is_empty() const noexcept {
3899 constexpr bool empty() const noexcept {
3903 constexpr size_t capacity() const noexcept {
3904 return LocalCapacity;
3910 constexpr cestring() noexcept = default;
3918 constexpr cestring(s_str other) : base_storable() {
3919 base_storable::init_from_str_other(other);
3929 constexpr cestring(
size_t repeat, s_str pattern) : base_storable() {
3930 base_storable::init_str_repeat(repeat, pattern);
3940 constexpr cestring(
size_t count, K pad) : base_storable() {
3941 base_storable::init_symb_repeat(count, pad);
3955 constexpr cestring(
const StrExprForType<K>
auto& expr) : base_storable() {
3956 base_storable::init_str_expr(expr);
3972 template<StrType<K> From>
3973 constexpr cestring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0)
3975 base_storable::init_replaced(f, pattern, repl, offset, maxCount);
3979 constexpr ~cestring() {}
3989 template<typename T, size_t M = const_lit_for<K, T>::Count>
3990 constexpr cestring(T&& s) : base_storable(), cstr_((const K*)s), size_(M - 1), is_cstr_(true), local_{0} {}
3994consteval 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) {
3995 if constexpr (std::is_same_v<K, u8s>)
3997 if constexpr (std::is_same_v<K, ubs>)
3999 if constexpr (std::is_same_v<K, uws>)
4001 if constexpr (std::is_same_v<K, u16s>)
4003 if constexpr (std::is_same_v<K, u32s>)
4007#define uni_string(K, p) select_str<K>(p, u8##p, L##p, u##p, U##p)
4009template<
typename K,
template<
typename C>
typename H>
4013 char node[
sizeof(sstring<K>)];
4015 const simple_str_nt<K>& to_nt() const noexcept {
4016 return static_cast<const simple_str_nt<K>&
>(str);
4018 const sstring<K>& to_str() const noexcept {
4019 return *
reinterpret_cast<const sstring<K>*
>(node);
4021 bool operator==(
const StoreType& other)
const {
4022 return hash == other.hash &&
typename H<K>::eql{}(*
this, other);
4028 static inline constexpr size_t basis =
static_cast<size_t>(14695981039346656037ULL);
4029 static inline constexpr size_t prime =
static_cast<size_t>(1099511628211ULL);
4033struct fnv_const<false> {
4034 static inline constexpr size_t basis =
static_cast<size_t>(2166136261U);
4035 static inline constexpr size_t prime =
static_cast<size_t>(16777619U);
4038using fnv = fnv_const<
sizeof(size_t) == 8>;
4041inline constexpr size_t fnv_hash(
const K* ptr,
size_t l) {
4042 size_t h = fnv::basis;
4043 for (
size_t i = 0; i < l; i++) {
4044 h = (h ^ (std::make_unsigned_t<K>)ptr[i]) * fnv::prime;
4050inline constexpr size_t fnv_hash_ia(
const K* ptr,
size_t l) {
4051 size_t h = fnv::basis;
4052 for (
size_t i = 0; i < l; i++) {
4053 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)ptr[i];
4054 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
4059template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
4060inline constexpr size_t fnv_hash(T&& value) {
4061 size_t h = fnv::basis;
4062 for (
size_t i = 0; i < N - 1; i++) {
4063 h = (h ^ (std::make_unsigned_t<K>)value[i]) * fnv::prime;
4068template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
4069inline constexpr size_t fnv_hash_ia(T&& value) {
4070 size_t h = fnv::basis;
4071 for (
size_t i = 0; i < N - 1; i++) {
4072 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)value[i];
4073 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
4079inline consteval size_t fnv_hash_compile(
const K* ptr,
size_t l) {
4080 return fnv_hash(ptr, l);
4084inline consteval size_t fnv_hash_ia_compile(
const K* ptr,
size_t l) {
4085 return fnv_hash_ia(ptr, l);
4091static_assert(std::is_trivially_copyable_v<StoreType<u8s, str_exact>>,
"Store type must be trivially copyable");
4094template<
typename K,
typename V>
4095std::allocator<std::pair<K, V>> default_hashstrmap_allocator_selector(...);
4104template<
typename K,
template<
typename C>
typename H,
typename V>
4105using allocator_hashstrmap =
decltype(default_hashstrmap_allocator_selector<const StoreType<K, H>, V>(int(0)));
4201template<
typename K,
typename T,
template<
typename C>
typename HE = str_exact,
typename A = allocator_hashstrmap<K, HE, T>>
4202class hashStrMap :
public std::unordered_map<StoreType<K, HE>, T, typename HE<K>::hash, typename HE<K>::eql, A> {
4204 using InStore = StoreType<K, HE>;
4207 using hasher =
typename HE<K>::hash;
4208 using comparator =
typename HE<K>::eql;
4209 using my_type = hashStrMap<K, T, HE, A>;
4210 using hash_t = std::unordered_map<StoreType<K, HE>, T, hasher, comparator, A>;
4212 hashStrMap() =
default;
4213 hashStrMap(
const my_type& other) : hash_t(other) {
4214 for (
const auto& [k, v] : *
this) {
4215 InStore& stored =
const_cast<InStore&
>(k);
4217 new (stored.node)
sstring<K>(std::move(tmp));
4218 stored.str.str = stored.to_str().symbols();
4222 for (
auto& k: *
this)
4226 hashStrMap(my_type&& o) =
default;
4228 my_type& operator=(
const my_type& other) {
4229 hash_t::operator=(other);
4230 for (
const auto& [k, v] : *
this) {
4231 InStore& stored =
const_cast<InStore&
>(k);
4233 new (stored.node)
sstring<K>(std::move(tmp));
4234 stored.str.str = stored.to_str().symbols();
4238 my_type& operator=(my_type&&) =
default;
4240 hashStrMap(std::initializer_list<std::pair<const InStore, T>>&& init) {
4241 for (
const auto& e: init)
4242 emplace(e.first, e.second);
4245 using init_str = std::initializer_list<std::pair<const sstring<K>, T>>;
4247 hashStrMap(init_str&& init) {
4248 for (
const auto& e: init)
4249 emplace(e.first, e.second);
4254 template<
typename... ValArgs>
4255 auto try_emplace(
const InStore& key, ValArgs&&... args) {
4256 auto it = hash_t::try_emplace(key, std::forward<ValArgs>(args)...);
4258 InStore& stored =
const_cast<InStore&
>(it.first->first);
4260 stored.str.str = stored.to_str().symbols();
4266 return {key, hasher{}(key)};
4269 template<
typename Key,
typename... ValArgs>
4270 requires(std::is_convertible_v<Key, simple_str<K>>)
4271 auto try_emplace(Key&& key, ValArgs&&... args) {
4272 auto it = hash_t::try_emplace(toStoreType(key), std::forward<ValArgs>(args)...);
4274 InStore& stored =
const_cast<InStore&
>(it.first->first);
4275 new (stored.node)
sstring<K>(std::forward<Key>(key));
4276 stored.str.str = stored.to_str().symbols();
4281 template<
typename... ValArgs>
4282 auto emplace(
const InStore& key, ValArgs&&... args) {
4283 auto it = try_emplace(key, std::forward<ValArgs>(args)...);
4285 it.first->second = T(std::forward<ValArgs>(args)...);
4290 template<
typename Key,
typename... ValArgs>
4291 requires(std::is_convertible_v<Key, simple_str<K>>)
4292 auto emplace(Key&& key, ValArgs&&... args) {
4293 auto it = try_emplace(std::forward<Key>(key), std::forward<ValArgs>(args)...);
4295 it.first->second = T(std::forward<ValArgs>(args)...);
4300 auto& operator[](
const InStore& key) {
4301 return try_emplace(key).first->second;
4304 template<
typename Key>
4305 requires(std::is_convertible_v<Key, simple_str<K>>)
4306 auto&
operator[](Key&& key) {
4307 return try_emplace(std::forward<Key>(key)).first->second;
4310 decltype(
auto) at(
const InStore& key) {
4311 return hash_t::at(key);
4313 decltype(
auto) at(
const InStore& key)
const {
4314 return hash_t::at(key);
4318 return hash_t::at(toStoreType(key));
4321 return hash_t::at(toStoreType(key));
4324 auto find(
const InStore& key)
const {
4325 return hash_t::find(key);
4329 return find(toStoreType(key));
4332 auto find(
const InStore& key) {
4333 return hash_t::find(key);
4337 return find(toStoreType(key));
4340 auto erase(
typename hash_t::const_iterator it) {
4341 if (it != hash_t::end()) {
4344 return hash_t::erase(it);
4347 auto erase(
const InStore& key) {
4348 auto it = hash_t::find(key);
4349 if (it != hash_t::end()) {
4358 return erase(toStoreType(key));
4362 auto it = find(txt);
4363 if (it != hash_t::end()) {
4371 for (
auto& k: *
this)
4375 bool contains(
const InStore& key)
const {
4376 return hash_t::find(key) != this->end();
4380 return find(toStoreType(key)) != this->end();
4387 bool operator()(
const StoreType<K, str_exact>& _Left,
const StoreType<K, str_exact>& _Right)
const {
4388 return _Left.hash == _Right.hash && _Left.str == _Right.str;
4392 size_t operator()(simple_str<K> _Keyval)
const {
4393 return fnv_hash(_Keyval.symbols(), _Keyval.length());
4395 size_t operator()(
const StoreType<K, str_exact>& _Keyval)
const {
4396 return _Keyval.hash;
4404 bool operator()(
const StoreType<K, str_eqlia>& _Left,
const StoreType<K, str_eqlia>& _Right)
const {
4405 return _Left.hash == _Right.hash && _Left.str.equal_ia(_Right.str);
4409 size_t operator()(simple_str<K> _Keyval)
const {
4410 return fnv_hash_ia(_Keyval.symbols(), _Keyval.length());
4412 size_t operator()(
const StoreType<K, str_eqlia>& _Keyval)
const {
4413 return _Keyval.hash;
4421 bool operator()(
const StoreType<K, str_eqliu>& _Left,
const StoreType<K, str_eqliu>& _Right)
const {
4422 return _Left.hash == _Right.hash && _Left.str.equal_iu(_Right.str);
4426 size_t operator()(simple_str<K> _Keyval)
const {
4427 using bc = to_base_char_t<K>;
4428 return unicode_traits<bc>::hashiu((
const bc*)_Keyval.symbols(), _Keyval.length());
4430 size_t operator()(
const StoreType<K, str_eqliu>& _Keyval)
const {
4431 return _Keyval.hash;
4452 using chunk_t = std::pair<std::unique_ptr<K[]>,
size_t>;
4453 std::vector<chunk_t> chunks;
4460 using my_type = chunked_string_builder<K>;
4461 using symb_type = K;
4462 chunked_string_builder() =
default;
4463 chunked_string_builder(
size_t a) : align(a){};
4464 chunked_string_builder(
const my_type&) =
delete;
4465 chunked_string_builder(my_type&& other) noexcept
4466 : chunks(std::move(other.chunks)), write(other.write), len(other.len), remain(other.remain), align(other.align) {
4467 other.len = other.remain = 0;
4468 other.write =
nullptr;
4470 my_type& operator=(my_type other)
noexcept {
4471 chunks.swap(other.chunks);
4472 write = other.write;
4474 remain = other.remain;
4475 align = other.align;
4476 other.len = other.remain = 0;
4477 other.write =
nullptr;
4485 if (
data.len <= remain) {
4488 ch_traits<K>::copy(write,
data.str,
data.len);
4490 chunks.back().second +=
data.len;
4497 ch_traits<K>::copy(write,
data.str, remain);
4500 chunks.back().second += remain;
4506 size_t blockSize = (
data.len + align - 1) / align * align;
4507 chunks.emplace_back(std::make_unique<K[]>(blockSize),
data.len);
4508 write = chunks.back().first.get();
4509 ch_traits<K>::copy(write,
data.str,
data.len);
4511 remain = blockSize -
data.len;
4518 size_t l = expr.length();
4521 write = expr.place(write);
4522 chunks.back().second += l;
4525 }
else if (!remain) {
4526 size_t blockSize = (l + align - 1) / align * align;
4527 chunks.emplace_back(std::make_unique<K[]>(blockSize), l);
4528 write = expr.place(chunks.back().first.get());
4530 remain = blockSize - l;
4532 auto store = std::make_unique<K[]>(l);
4533 expr.place(store.get());
4540 template<
typename T>
4542 requires std::is_same_v<T, K>
4544 return operator<<(expr_char<K>(
data));
4552 if (chunks.empty()) {
4555 if (chunks.size() > 1) {
4559 remain += chunks[0].second;
4560 chunks[0].second = 0;
4562 write = chunks[0].first.get();
4565 constexpr K* place(K* p)
const noexcept {
4566 for (
const auto& block: chunks) {
4567 ch_traits<K>::copy(p, block.first.get(), block.second);
4580 template<
typename Op>
4582 for (
const auto& block: chunks)
4583 o(block.first.get(), block.second);
4590 if (chunks.size()) {
4591 const K* ptr = chunks.front().first.get();
4592 for (
const auto& chunk: chunks) {
4593 if (chunk.first.get() != ptr)
4595 ptr += chunk.second;
4607 return chunks.size() ? chunks.front().first.get() : simple_str_nt<K>::empty_str.str;
4624 typename decltype(chunks)::const_iterator it, end;
4625 size_t writedFromCurrentChunk;
4645 while (size && !
is_end()) {
4646 size_t remain = it->second - writedFromCurrentChunk;
4647 size_t write = std::min(size, remain);
4648 ch_traits<K>::copy(buffer, it->first.get() + writedFromCurrentChunk, write);
4654 writedFromCurrentChunk = 0;
4656 writedFromCurrentChunk += write;
4668 return {chunks.begin(), chunks.end(), 0};
4681using stringa = sstring<u8s>;
4682using stringb = sstring<ubs>;
4683using stringw = sstring<wchar_t>;
4684using stringu = sstring<u16s>;
4685using stringuu = sstring<u32s>;
4686static_assert(
sizeof(stringa) == (
sizeof(
void*) == 8 ? 24 : 16),
"Bad size of sstring");
4692template<
typename T,
typename A = allocator_hashstrmap<u8s, str_exact, T>>
4698template<
typename T,
typename A = allocator_hashstrmap<u8s, str_eqlia, T>>
4704template<
typename T,
typename A = allocator_hashstrmap<u8s, str_eqliu, T>>
4711template<
typename T,
typename A = allocator_hashstrmap<ubs, str_exact, T>>
4717template<
typename T,
typename A = allocator_hashstrmap<ubs, str_eqlia, T>>
4723template<
typename T,
typename A = allocator_hashstrmap<ubs, str_eqliu, T>>
4730template<
typename T,
typename A = allocator_hashstrmap<
wchar_t, str_exact, T>>
4737template<
typename T,
typename A = allocator_hashstrmap<
wchar_t, str_eqlia, T>>
4744template<
typename T,
typename A = allocator_hashstrmap<
wchar_t, str_eqliu, T>>
4751template<
typename T,
typename A = allocator_hashstrmap<u16s, str_exact, T>>
4757template<
typename T,
typename A = allocator_hashstrmap<u16s, str_eqlia, T>>
4763template<
typename T,
typename A = allocator_hashstrmap<u16s, str_eqliu, T>>
4770template<
typename T,
typename A = allocator_hashstrmap<u32s, str_exact, T>>
4776template<
typename T,
typename A = allocator_hashstrmap<u32s, str_eqlia, T>>
4782template<
typename T,
typename A = allocator_hashstrmap<u32s, str_eqliu, T>>
4787inline namespace literals {
4856template<
typename K>
using HashKey = StoreType<K, str_exact>;
4857template<
typename K>
using HashKeyIA = StoreType<K, str_eqlia>;
4858template<
typename K>
using HashKeyIU = StoreType<K, str_eqliu>;
4870consteval HashKey<u8s>
operator""_h(
const u8s* ptr,
size_t l) {
4871 return HashKey<u8s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4884consteval HashKeyIA<u8s>
operator""_ia(
const u8s* ptr,
size_t l) {
4885 return HashKeyIA<u8s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4898inline HashKeyIU<u8s>
operator""_iu(
const u8s* ptr,
size_t l) {
4899 return HashKeyIU<u8s>{{ptr, l}, str_eqliu<u8s>::hash{}(
simple_str<u8s>{ptr, l})};
4912consteval HashKey<ubs>
operator""_h(
const ubs* ptr,
size_t l) {
4913 return HashKey<ubs>{{ptr, l}, fnv_hash_compile(ptr, l)};
4926consteval HashKeyIA<ubs>
operator""_ia(
const ubs* ptr,
size_t l) {
4927 return HashKeyIA<ubs>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4940inline HashKeyIU<ubs>
operator""_iu(
const ubs* ptr,
size_t l) {
4941 return HashKeyIU<ubs>{{ptr, l}, str_eqliu<u8s>::hash{}(
simple_str<u8s>{(
const u8s*)ptr, l})};
4954consteval HashKey<u16s>
operator""_h(
const u16s* ptr,
size_t l) {
4955 return HashKey<u16s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4968consteval HashKeyIA<u16s>
operator""_ia(
const u16s* ptr,
size_t l) {
4969 return HashKeyIA<u16s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4982inline HashKeyIU<u16s>
operator""_iu(
const u16s* ptr,
size_t l) {
4983 return HashKeyIU<u16s>{{ptr, l}, str_eqliu<u16s>::hash{}(
simple_str<u16s>{ptr, l})};
4996consteval HashKey<u32s>
operator""_h(
const u32s* ptr,
size_t l) {
4997 return HashKey<u32s>{{ptr, l}, fnv_hash_compile(ptr, l)};
5010consteval HashKeyIA<u32s>
operator""_ia(
const u32s* ptr,
size_t l) {
5011 return HashKeyIA<u32s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
5024inline HashKeyIU<u32s>
operator""_iu(
const u32s* ptr,
size_t l) {
5025 return HashKeyIU<u32s>{{ptr, l}, str_eqliu<u32s>::hash{}(
simple_str<u32s>{ptr, l})};
5038consteval HashKey<uws>
operator""_h(
const uws* ptr,
size_t l) {
5039 return HashKey<uws>{{ptr, l}, fnv_hash_compile(ptr, l)};
5052consteval HashKeyIA<uws>
operator""_ia(
const uws* ptr,
size_t l) {
5053 return HashKeyIA<uws>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
5066inline HashKeyIU<uws>
operator""_iu(
const uws* ptr,
size_t l) {
5067 return HashKeyIU<uws>{{ptr, l}, str_eqliu<uws>::hash{}(
simple_str<uws>{ptr, l})};
5071template<is_one_of_
char_v K,
bool upper>
5072struct expr_change_case : expr_to_std_string<expr_change_case<K, upper>>{
5073 using symb_type = K;
5076 mutable size_t len_{};
5078 template<StrSource S>
5079 expr_change_case(S&& s) : src_(std::forward<S>(s)){}
5081 constexpr size_t length() const noexcept {
5082 if constexpr (
sizeof(K) > 1) {
5083 return src_.length();
5085 if constexpr (upper) {
5086 len_ = unicode_traits<K>::upper_len(src_.str, src_.len);
5088 len_ = unicode_traits<K>::lower_len(src_.str, src_.len);
5093 constexpr K* place(K* ptr)
const noexcept {
5094 if constexpr (
sizeof(K) > 1) {
5095 if constexpr (upper) {
5096 unicode_traits<K>::upper(src_.str, src_.len, ptr);
5098 unicode_traits<K>::lower(src_.str, src_.len, ptr);
5100 return ptr + src_.len;
5102 const K* src = src_.str;
5103 if constexpr (upper) {
5104 unicode_traits<K>::upper(src, src_.len, ptr, len_);
5106 unicode_traits<K>::lower(src, src_.len, ptr, len_);
5127template<is_one_of_
char_v K>
5129 using base = expr_change_case<K, true>;
5133template<StrSource S>
5150template<is_one_of_
char_v K>
5152 using base = expr_change_case<K, false>;
5156template<StrSource S>
5170 return stream << std::string_view{text.
symbols(), text.
length()};
5183inline std::wostream&
operator<<(std::wostream& stream, ssw text) {
5184 return stream << std::wstring_view{text.
symbols(), text.
length()};
5198 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
5211inline std::ostream&
operator<<(std::ostream& stream,
const stringa& text) {
5212 return stream << std::string_view{text.
symbols(), text.
length()};
5225inline std::wostream&
operator<<(std::wostream& stream,
const stringw& text) {
5226 return stream << std::wstring_view{text.
symbols(), text.
length()};
5240 return stream << std::wstring_view{from_w(text.symbols()), text.length()};
5253template<
size_t N,
bool S, simstr::Allocatorable A>
5255 return stream << std::string_view{text.
symbols(), text.
length()};
5268template<
size_t N,
bool S, simstr::Allocatorable A>
5270 return stream << std::wstring_view{text.
symbols(), text.
length()};
5283template<
size_t N,
bool S, simstr::Allocatorable A>
5285 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
5295struct std::formatter<
simstr::simple_str<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5297 template<
typename FormatContext>
5299 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5308struct std::formatter<
simstr::simple_str_nt<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5310 template<
typename FormatContext>
5312 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5321struct std::formatter<
simstr::sstring<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5323 template<
typename FormatContext>
5325 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5333template<
typename K,
size_t N,
bool S,
typename A>
5334struct std::formatter<
simstr::lstring<K, N, S, A>, K> : std::formatter<std::basic_string_view<K>, K> {
5336 template<
typename FormatContext>
5338 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5347struct std::formatter<
simstr::simple_str<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5349 template<
typename FormatContext>
5351 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5360struct std::formatter<
simstr::simple_str_nt<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5362 template<
typename FormatContext>
5364 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5373struct std::formatter<
simstr::sstring<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5375 template<
typename FormatContext>
5377 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5385template<
size_t N,
bool S,
typename A>
5386struct std::formatter<
simstr::lstring<char8_t, N, S, A>, char> : std::formatter<std::basic_string_view<char>, char> {
5388 template<
typename FormatContext>
5390 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5399struct std::formatter<
simstr::simple_str<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5401 template<
typename FormatContext>
5403 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5412struct std::formatter<
simstr::simple_str_nt<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5414 template<
typename FormatContext>
5416 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5425struct std::formatter<
simstr::sstring<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5427 template<
typename FormatContext>
5429 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.
symbols(), t.
length()}, fc);
5437template<
size_t N,
bool S,
typename A>
5438struct std::formatter<
simstr::lstring<simstr::wchar_type, N, S, A>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5440 template<
typename FormatContext>
5442 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.
symbols(), t.
length()}, fc);
Class for sequentially obtaining substrings by a given delimiter.
Definition strexpr.h:3234
my_type & operator<<(simple_str< K > data)
Adding a piece of data.
Definition sstring.h:4482
portion_store get_portion() const
Get a portion_store through which data can be sequentially retrieved into an external buffer.
Definition sstring.h:4667
constexpr size_t length() const noexcept
Length of the saved text.
Definition sstring.h:4547
my_type & operator<<(T data)
Adding a symbol.
Definition sstring.h:4541
void reset()
Resets the contents, but does not delete the first buffer in order to avoid allocation later.
Definition sstring.h:4551
void clear()
Clear the object, freeing all allocated buffers.
Definition sstring.h:4613
my_type & operator<<(const StrExprForType< K > auto &expr)
Adding a string expression.
Definition sstring.h:4517
bool is_continuous() const
Checks whether all text is located in one contiguous chunk in memory.
Definition sstring.h:4589
void out(const Op &o) const
Applies a functor to each stored buffer.
Definition sstring.h:4581
const auto & data() const
Get internal data buffers.
Definition sstring.h:4676
const K * begin() const
Get a pointer to the beginning of the first buffer. It makes sense to apply only if is_continuous tru...
Definition sstring.h:4606
Container for more efficient searching by string keys.
Definition sstring.h:4202
The mutable, owning string class. Contains an internal buffer for text of a given size.
Definition sstring.h:2668
constexpr void define_size()
Determine the length of the string. Searches for the character 0 in the string buffer to its capacity...
Definition sstring.h:3211
constexpr lstring(T &&value, Args &&... args)
String literal constructor.
Definition sstring.h:2937
my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:3082
constexpr void reset()
Makes the string empty and frees the external buffer, if there was one.
Definition sstring.h:3246
@ LocalCapacity
Definition sstring.h:2676
constexpr bool is_local() const noexcept
Find out whether a local or external buffer is used for characters.
Definition sstring.h:3202
my_type & operator=(my_type &&other) noexcept
Assignment operator by moving from a string of the same type.
Definition sstring.h:3025
constexpr size_t length() const noexcept
String length.
Definition sstring.h:3105
constexpr lstring(s_str other, Args &&... args)
A constructor from another string object.
Definition sstring.h:2804
constexpr lstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Constructor from string source with replacement.
Definition sstring.h:2874
constexpr lstring(size_t repeat, s_str pattern, Args &&... args)
String repetition constructor.
Definition sstring.h:2819
constexpr lstring(const my_type &other)
Copy from another string of the same type.
Definition sstring.h:2893
constexpr lstring(const my_type &other, Args &&... args)
Copy from another string of the same type, but with a different allocator.
Definition sstring.h:2920
my_type & operator=(const StrExprForType< K > auto &expr)
String expression appending operator.
Definition sstring.h:3095
constexpr K * reserve_no_preserve(size_t newSize)
Definition sstring.h:3140
my_type & operator=(const my_type &other)
Copy assignment operator from a string of the same type.
Definition sstring.h:3008
constexpr bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:3117
lstring(const Op &op, Args &&... args)
A fill constructor using a functor (see str_mutable::fill).
Definition sstring.h:2979
constexpr K * set_size(size_t newSize)
Sets the size of the current string, allocating space if necessary.
Definition sstring.h:3185
constexpr lstring(size_t count, K pad, Args &&... args)
Character repetition constructor.
Definition sstring.h:2834
constexpr lstring(const StrExprForType< K > auto &expr, Args &&... args)
Constructor from a string expression.
Definition sstring.h:2853
constexpr const K * symbols() const noexcept
Pointer to constant characters.
Definition sstring.h:3109
constexpr void clear()
Makes a string empty without changing the string buffer.
Definition sstring.h:3242
my_type & operator=(simple_str< K > other)
Assignment operator from simple_str.
Definition sstring.h:3070
constexpr bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:3121
constexpr void shrink_to_fit()
Reduces the size of the external buffer to the smallest possible size to hold the string....
Definition sstring.h:3228
constexpr lstring(my_type &&other) noexcept
Constructor for moving from a string of the same type.
Definition sstring.h:2952
constexpr K * reserve(size_t newSize)
Allocate a buffer large enough to hold newSize characters plus a terminating null.
Definition sstring.h:3162
constexpr K * str() noexcept
Pointer to a string buffer.
Definition sstring.h:3113
constexpr size_t capacity() const noexcept
Current row buffer capacity.
Definition sstring.h:3125
constexpr lstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Create an empty object.
Definition sstring.h:2789
Immutable owning string class.
Definition sstring.h:3357
constexpr my_type & operator=(const lstring< K, N, forShared, A > &other)
Assignment operator to another string of type lstring.
Definition sstring.h:3733
constexpr bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:3786
constexpr bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:3782
sstring(s_str other, Args &&... args)
A constructor from another string object.
Definition sstring.h:3496
sstring(size_t count, K pad, Args &&... args)
Character repetition constructor.
Definition sstring.h:3526
constexpr const K * symbols() const noexcept
Pointer to characters in the string.
Definition sstring.h:3774
constexpr sstring(const my_type &other) noexcept
String copy constructor.
Definition sstring.h:3584
static my_type format(const FmtString< to_std_char_t< K >, T... > &fmtString, T &&... args)
Get a string formatted with std::format.
Definition sstring.h:3816
constexpr my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:3721
sstring(size_t repeat, s_str pattern, Args &&... args)
String repetition constructor.
Definition sstring.h:3511
constexpr my_type & operator=(my_type other) noexcept
Assignment operator to another string of the same type.
Definition sstring.h:3697
static my_type printf(const K *pattern, T &&... args)
Get a string formatted with std::sprintf.
Definition sstring.h:3802
constexpr sstring(lstring< K, N, true, Allocator > &&src)
A move constructor from lstring with an sstring-compatible external buffer.
Definition sstring.h:3611
constexpr size_t length() const noexcept
string length.
Definition sstring.h:3778
constexpr sstring(my_type &&other) noexcept
Move constructor.
Definition sstring.h:3595
static my_type vformat(simple_str< K > fmtString, T &&... args)
Get a string formatted with std::vformat.
Definition sstring.h:3830
sstring(simple_str< O > init)
Initialization from a string source with a different character type. Converts via UTF.
Definition sstring.h:3672
constexpr my_type & operator=(simple_str< K > other)
Assignment operator to another string of a different type.
Definition sstring.h:3709
constexpr my_type & make_empty() noexcept
Make the string empty.
Definition sstring.h:3767
constexpr my_type & operator=(const StrExprForType< K > auto &expr)
String expression assignment operator.
Definition sstring.h:3758
sstring(T &&s, Args &&... args)
Initialize from a string literal.
Definition sstring.h:3659
constexpr my_type & operator=(lstring< K, N, true, Allocator > &&other)
Assignment operator to a movable string of type lstring with a compatible buffer.
Definition sstring.h:3745
constexpr sstring(const StrExprForType< K > auto &expr, Args &&... args)
Constructor from a string expression.
Definition sstring.h:3545
sstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Constructor for the empty string.
Definition sstring.h:3481
constexpr ~sstring()
String destructor.
Definition sstring.h:3573
sstring(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Constructor from string source with replacement.
Definition sstring.h:3566
A class with additional constant string algorithms.
Definition sstring.h:193
bool starts_with_iu(str_piece prefix) const noexcept
Whether the string starts with the given substring, case-insensitive Unicode characters of the first ...
Definition sstring.h:266
int compare_iu(str_piece text) const noexcept
Compare strings character by character without taking into account the case of Unicode characters of ...
Definition sstring.h:230
bool less_iu(str_piece text) const noexcept
Whether a string is smaller than another string, character-by-character-insensitive,...
Definition sstring.h:252
constexpr bool ends_with_iu(str_piece suffix) const noexcept
Whether the string ends with the specified substring, case-insensitive Unicode characters of the firs...
Definition sstring.h:281
R upperred() const
Get a copy of the string in upper case Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:293
constexpr std::optional< R > strip_prefix_iu(str_piece prefix) const
Get a string without a prefix if it starts with it, insensitive to Unicode characters up to 0xFFFF.
Definition sstring.h:389
constexpr R trimmed_prefix_iu(str_piece prefix, size_t max_count=0) const
Returns a string with the beginning of the string removed if it begins with the specified prefix,...
Definition sstring.h:427
R lowered() const
Get a copy of the string in lowercase Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:305
std::optional< double > to_double() const noexcept
Convert string to double.
Definition sstring.h:315
constexpr std::optional< R > strip_suffix_iu(str_piece suffix) const
Get a string without a suffix if it ends with one in case-insensitive Unicode characters up to 0xFFFF...
Definition sstring.h:408
constexpr void as_number(T &t) const
Convert a string to an integer.
Definition sstring.h:373
bool equal_iu(str_piece text) const noexcept
Whether a string is equal to another string, character-by-character-insensitive, of the Unicode chara...
Definition sstring.h:241
constexpr R trimmed_suffix_iu(str_piece suffix) const
Returns a string with the end of the string removed if it ends with the specified suffix of case-inse...
Definition sstring.h:450
void as_number(double &t) const
Convert string to double.
Definition sstring.h:356
Base class for working with mutable strings.
Definition sstring.h:1435
Impl & insert(size_t to, const A &expr)
Insert a string expression at the specified position.
Definition sstring.h:1975
Impl & operator<<=(const Op &fillFunction)
Fills a string with the fill method after the end of the string.
Definition sstring.h:2249
Impl & append(const A &expr)
Add a string expression to the end of the string.
Definition sstring.h:1859
Impl & operator<<(const Op &fillFunction)
Calls the passed functor, passing a reference to itself.
Definition sstring.h:2262
Impl & trim(str_piece pattern)
Remove characters included in the passed string at the beginning and end of the string.
Definition sstring.h:1669
Impl & upper_only_ascii()
Convert ASCII characters to uppercase.
Definition sstring.h:1733
Impl & lower_only_ascii()
Convert ASCII characters to lowercase.
Definition sstring.h:1748
Impl & trim_left()
Remove whitespace at the beginning of a string.
Definition sstring.h:1571
Impl & append_printf(const K *format, T &&... args)
Appends sprintf formatted output to the end of the string.
Definition sstring.h:2351
Impl & trim_right_with_wpaces(T &&pattern)
Remove characters included in a string literal, as well as whitespace, at the end of a string.
Definition sstring.h:1658
Impl & trim_left(str_piece pattern)
Remove characters included in the passed string at the beginning of the string.
Definition sstring.h:1680
Impl & trim_with_spaces(T &&pattern)
Remove characters included in a string literal, as well as whitespace, at the beginning and end of th...
Definition sstring.h:1632
Impl & prepend(str_piece other)
Add another string to the beginning of the string.
Definition sstring.h:1999
Impl & append_formatted(const FmtString< fmt_type, T... > &format, T &&... args)
Appends std::format-formatted output to the end of the string.
Definition sstring.h:2489
my_type & format(const FmtString< fmt_type, T... > &pattern, T &&... args)
Definition sstring.h:2473
Impl & printf(const K *format, T &&... args)
Formats a string using sprintf.
Definition sstring.h:2335
Impl & with(const Op &fillFunction, Args &&... args)
Call a functor with a string and passed arguments.
Definition sstring.h:2571
Impl & append_vformatted_n(size_t max_write, str_piece format, T &&... args)
Appends std::vformat-formatted output to the end of the line, writing no more than the specified numb...
Definition sstring.h:2557
Impl & operator<<(const Op &fillFunction)
Fills a string with the fill method from position zero.
Definition sstring.h:2236
Impl & vformat(str_piece format, T &&... args)
Formats a string using std::vformat.
Definition sstring.h:2505
Impl & change(size_t from, size_t len, const A &expr)
Replace a piece of string with a string expression.
Definition sstring.h:1948
Impl & fill(size_t from, const Op &fillFunction)
Fill a string buffer using a functor.
Definition sstring.h:2208
Impl & change(size_t from, size_t len, str_piece other)
Replace a piece of string with another string.
Definition sstring.h:1932
Impl & remove(size_t from, size_t len)
Remove part of a string.
Definition sstring.h:1988
Impl & trim_left_with_spaces(T &&pattern)
Remove characters included in a string literal, as well as whitespace, at the beginning of a string.
Definition sstring.h:1645
Impl & trim_left(T &&pattern)
Remove characters included in a string literal at the beginning of the string.
Definition sstring.h:1606
Impl & trim_right(T &&pattern)
Remove characters included in a string literal at the end of the string.
Definition sstring.h:1619
Impl & trim_right_with_spaces(str_piece pattern)
Remove characters included in the passed string, as well as whitespace at the end of the string.
Definition sstring.h:1724
Impl & append_in(size_t pos, str_piece other)
Add another string starting at the given position.
Definition sstring.h:1899
Impl & vformat_from(size_t from, size_t max_write, str_piece format, T &&... args)
Appends std::vformat formatted output starting at the specified position.
Definition sstring.h:2438
Impl & trim_left_with_spaces(str_piece pattern)
Remove characters included in the passed string, as well as whitespace, at the beginning of the strin...
Definition sstring.h:1713
Impl & insert(size_t to, str_piece other)
Insert a string at the specified position.
Definition sstring.h:1961
Impl & vformat_n(size_t max_write, str_piece format, T &&... args)
Formats a string using std::vformat up to the specified size.
Definition sstring.h:2539
Impl & printf_from(size_t from, const K *format, T &&... args)
Appends sprintf formatted output starting at the specified position.
Definition sstring.h:2281
Impl & operator+=(str_piece other)
Add another string to the end of the string.
Definition sstring.h:1870
Impl & trim_right()
Remove whitespace from the end of a string.
Definition sstring.h:1580
Impl & append(str_piece other)
Add another string to the end of the string.
Definition sstring.h:1847
Impl & trim_right(str_piece pattern)
Remove characters included in the passed string from the end of the string.
Definition sstring.h:1691
Impl & trim_with_spaces(str_piece pattern)
Remove characters included in the passed string, as well as whitespace characters,...
Definition sstring.h:1702
K * str() noexcept
Get a pointer to the string buffer.
Definition sstring.h:1544
Impl & prepend(const A &expr)
Add a string expression to the beginning of a string.
Definition sstring.h:2011
Impl & trim()
Remove whitespace from the beginning and end of a string.
Definition sstring.h:1562
Impl & lower()
Convert first plane characters (<0xFFFF) to lowercase Unicode.
Definition sstring.h:1782
Impl & replace(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Replace occurrences of a substring with another string.
Definition sstring.h:2028
Impl & upper()
Convert first plane characters (<0xFFFF) to uppercase Unicode.
Definition sstring.h:1767
Impl & replace_from(const From &f, str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0)
Copy the source string, replacing occurrences of substrings with another string.
Definition sstring.h:2146
Impl & append_vformatted(str_piece format, T &&... args)
Appends std::vformat-formatted output to the end of the string.
Definition sstring.h:2521
Impl & append_in(size_t pos, const A &expr)
Add a string expression starting at the given position.
Definition sstring.h:1917
my_type & format_from(size_t from, const FmtString< fmt_type, T... > &format, T &&... args)
Definition sstring.h:2409
Impl & trim(T &&pattern)
Remove characters included in a string literal at the beginning and end of the string.
Definition sstring.h:1593
Impl & operator+=(const A &expr)
Add a string expression to the end of the string.
Definition sstring.h:1882
constexpr str_piece to_str() const noexcept
Convert itself to a "string chunk" that includes the entire string.
Definition strexpr.h:3422
constexpr size_t size() const
Definition strexpr.h:3363
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len=0) const noexcept
Get part of a string as "str_src".
Definition strexpr.h:3448
constexpr void as_number(T &t) const
Convert a string to an integer.
Definition strexpr.h:4227
constexpr str_storable(Args &&... args)
Create an empty object.
Definition sstring.h:947
void init_replaced(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0)
Initialization from string source with replacement.
Definition sstring.h:1034
static my_type upperred_from(const From &f, Args &&... args)
Create a copy of the passed string in uppercase Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:1296
constexpr void init_from_str_other(s_str other)
Initialization from another string object.
Definition sstring.h:955
constexpr allocator_t & allocator()
Get the allocator.
Definition sstring.h:924
constexpr void init_symb_repeat(size_t count, K pad)
Character repetition initialization.
Definition sstring.h:991
constexpr void init_str_expr(const A &expr)
Initialization from a string expression.
Definition sstring.h:1012
static my_type upperred_only_ascii_from(const From &f, Args &&... args)
Create a string copy of the passed in uppercase ASCII characters.
Definition sstring.h:1266
static my_type lowered_from(const From &f, Args &&... args)
Create a copy of the passed string in lowercase Unicode characters of the first plane (<0xFFFF).
Definition sstring.h:1313
constexpr void init_str_repeat(size_t repeat, s_str pattern)
String repetition initialization.
Definition sstring.h:971
static my_type lowered_only_ascii_from(const From &f, Args &&... args)
Create a copy of the passed string in lowercase ASCII characters.
Definition sstring.h:1279
static my_type join(const T &strings, s_str delimiter, bool tail=false, bool skip_empty=false, Args &&... args)
Concatenate strings from the container into one string.
Definition sstring.h:1215
static my_type replaced_from(const From &f, s_str pattern, s_str repl, size_t offset=0, size_t maxCount=0, Args &&... args)
Create a copy of the passed string with substrings replaced.
Definition sstring.h:1334
constexpr s_str_nt to_nts(size_t from=0) const
Get simple_str_nt starting at the given character.
Definition sstring.h:1159
Concept of a memory management type.
Definition sstring.h:1344
The concept of a string expression compatible with a given character type.
Definition strexpr.h:525
A type concept that cannot modify a stored string.
Definition sstring.h:866
A type concept that can modify a stored string.
Definition sstring.h:859
A type concept that can store a string.
Definition sstring.h:849
Small namespace for standard string methods.
Definition strexpr.h:1600
Library namespace.
Definition sstring.cpp:12
hashStrMap< u16s, T, str_eqlia, A > hashStrMapUIA
Hash dictionary type for char16_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4758
hashStrMap< ubs, T, str_exact, A > hashStrMapB
Type of hash dictionary for char8_t strings, case sensitive search.
Definition sstring.h:4712
hashStrMap< wchar_t, T, str_eqliu, A > hashStrMapWIU
Hash dictionary type for wchar_t strings, case insensitive search for Unicode characters up to 0xFFFF...
Definition sstring.h:4745
hashStrMap< u16s, T, str_exact, A > hashStrMapU
Hash dictionary type for char16_t strings, case sensitive search.
Definition sstring.h:4752
hashStrMap< u8s, T, str_exact, A > hashStrMapA
Type of hash dictionary for char strings, case sensitive search.
Definition sstring.h:4693
hashStrMap< u32s, T, str_exact, A > hashStrMapUU
Hash dictionary type for char32_t strings, case sensitive search.
Definition sstring.h:4771
hashStrMap< ubs, T, str_eqliu, A > hashStrMapBIU
Hash dictionary type for char8_t strings, case-insensitive search for Unicode characters up to 0xFFFF...
Definition sstring.h:4724
hashStrMap< wchar_t, T, str_eqlia, A > hashStrMapWIA
Hash dictionary type for wchar_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4738
hashStrMap< u32s, T, str_eqliu, A > hashStrMapUUIU
Hash dictionary type for char32_t strings, case insensitive search for Unicode characters up to 0xFFF...
Definition sstring.h:4783
expr_utf< From, To > e_utf(simple_str< From > from)
Returns a string expression that converts a string of one character type to another type,...
Definition sstring.h:840
hashStrMap< ubs, T, str_eqlia, A > hashStrMapBIA
Type of hash dictionary for char8_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4718
hashStrMap< u8s, T, str_eqliu, A > hashStrMapAIU
Hash dictionary type for char strings, case-insensitive search for Unicode characters up to 0xFFFF.
Definition sstring.h:4705
hashStrMap< wchar_t, T, str_exact, A > hashStrMapW
Hash dictionary type for wchar_t strings, case sensitive search.
Definition sstring.h:4731
hashStrMap< u32s, T, str_eqlia, A > hashStrMapUUIA
Hash dictionary type for char32_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4777
hashStrMap< u8s, T, str_eqlia, A > hashStrMapAIA
Type of hash dictionary for char strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4699
hashStrMap< u16s, T, str_eqliu, A > hashStrMapUIU
Hash dictionary type for char16_t strings, case insensitive search for Unicode characters up to 0xFFF...
Definition sstring.h:4764
Some methods for working with standard strings.
Definition strexpr.h:7505
An object that allows you to sequentially copy content into a buffer of a given size.
Definition sstring.h:4623
bool is_end()
Check that the data has not yet run out.
Definition sstring.h:4630
size_t store(K *buffer, size_t size)
Save the next portion of data to the buffer.
Definition sstring.h:4643
Definition sstring.h:5151
Generates a string based on the original one, replacing all lowercase letters of the first Unicode pl...
Definition sstring.h:5128
Base class for converting string expressions to standard strings.
Definition strexpr.h:659
String expression to convert strings to different UTF types.
Definition sstring.h:809
A class that claims to refer to a null-terminated string.
Definition sstring.h:617
constexpr my_type to_nts(size_t from)
Get a null-terminated string by shifting the start by the specified number of characters.
Definition sstring.h:680
constexpr simple_str_nt(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Constructor from std::basic_string.
Definition sstring.h:669
constexpr simple_str_nt(T &&v) noexcept
Constructor from a string literal.
Definition sstring.h:651
constexpr simple_str_nt(const K *p, size_t l) noexcept
Constructor from pointer and length.
Definition sstring.h:657
constexpr simple_str_nt(T &&p) noexcept
Explicit constructor from C-string.
Definition sstring.h:642
The simplest immutable non-owning string class.
Definition sstring.h:481
constexpr simple_str(T &&v) noexcept
Constructor from a string literal.
Definition sstring.h:497
constexpr K operator[](size_t idx) const
Get the character from the specified position. Bounds checking is not performed.
Definition sstring.h:561
constexpr my_type & remove_suffix(size_t delta)
Shortens the string by the specified number of characters.
Definition sstring.h:585
constexpr size_t length() const noexcept
Get the length of the string.
Definition sstring.h:518
constexpr const symb_type * symbols() const noexcept
Get a pointer to a constant buffer containing string characters.
Definition sstring.h:525
constexpr my_type & remove_prefix(size_t delta)
Shifts the start of a string by the specified number of characters.
Definition sstring.h:572
constexpr simple_str(const std::basic_string_view< K, std::char_traits< K > > &s) noexcept
Constructor from std::basic_string_view.
Definition sstring.h:513
constexpr simple_str(const K *p, size_t l) noexcept
Constructor from pointer and length.
Definition sstring.h:502
constexpr simple_str(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Constructor from std::basic_string.
Definition sstring.h:508
constexpr bool is_empty() const noexcept
Check if a string is empty.
Definition sstring.h:532
constexpr bool is_same(simple_str< K > other) const noexcept
Check if two objects point to the same string.
Definition sstring.h:541
constexpr bool is_part_of(simple_str< K > other) const noexcept
Check if a string is part of another string.
Definition sstring.h:550
The simplest class of an immutable non-owning string.
Definition strexpr.h:5057
constexpr const symb_type * symbols() const noexcept
Get a pointer to a constant buffer containing string characters.
Definition strexpr.h:5104