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;
780 requires(!std::is_same_v<O, K>)
782 using from_t = to_base_char_t<O>;
783 using to_t = to_base_char_t<K>;
785 using worker = utf_convert_selector<from_t, to_t>;
786 Impl* d =
static_cast<Impl*
>(
this);
787 size_t len = init.
length();
791 size_t need = worker::need_len((
const from_t*)init.
symbols(), len);
792 K*
str = d->init(need);
794 worker::convert((
const from_t*)init.
symbols(), len, (to_t*)
str);
807template<
typename From,
typename To>
requires (!std::is_same_v<From, To>)
809 using symb_type = To;
810 using from_t = to_base_char_t<From>;
811 using to_t = to_base_char_t<To>;
812 using worker = utf_convert_selector<from_t, to_t>;
818 size_t length()
const noexcept {
819 return worker::need_len((
const from_t*)source_.symbols(), source_.length());
821 To* place(To* ptr)
const noexcept {
822 return ptr + worker::convert((
const from_t*)source_.symbols(), source_.length(), (to_t*)ptr);
838template<
typename To,
typename From>
requires (!std::is_same_v<From, To>)
843template<is_one_of_
char_v K,
bool upper>
844struct expr_change_case : expr_to_std_string<expr_change_case<K, upper>>{
848 mutable size_t len_{};
850 template<StrSource S>
851 expr_change_case(S&& s) : src_(std::forward<S>(s)){}
853 constexpr size_t length() const noexcept {
854 if constexpr (
sizeof(K) > 1) {
855 return src_.length();
857 if constexpr (upper) {
858 len_ = unicode_traits<K>::upper_len(src_.str, src_.len);
860 len_ = unicode_traits<K>::lower_len(src_.str, src_.len);
865 constexpr K* place(K* ptr)
const noexcept {
866 if constexpr (
sizeof(K) > 1) {
867 if constexpr (upper) {
868 unicode_traits<K>::upper(src_.str, src_.len, ptr);
870 unicode_traits<K>::lower(src_.str, src_.len, ptr);
872 return ptr + src_.len;
874 const K* src = src_.str;
875 if constexpr (upper) {
876 unicode_traits<K>::upper(src, src_.len, ptr, len_);
878 unicode_traits<K>::lower(src, src_.len, ptr, len_);
899template<is_one_of_
char_v K>
901 using base = expr_change_case<K, true>;
922template<is_one_of_
char_v K>
924 using base = expr_change_case<K, false>;
935template<
typename A,
typename K>
937 A::is_str_storable ==
true;
938 std::is_same_v<typename A::symb_type, K>;
945template<
typename A,
typename K>
952template<
typename A,
typename K>
991template<
typename K,
typename Impl,
typename Allocator>
994 using my_type = Impl;
995 using traits = ch_traits<K>;
996 using allocator_t = Allocator;
1006 return *
static_cast<Allocator*
>(
this);
1008 constexpr const allocator_t&
allocator()
const {
1009 return *
static_cast<const Allocator*
>(
this);
1012 using uni = unicode_traits<K>;
1014 constexpr Impl& d() noexcept {
1015 return *
static_cast<Impl*
>(
this);
1017 constexpr const Impl& d() const noexcept {
1018 return *
static_cast<const Impl*
>(
this);
1027 template<
typename... Args>
1028 explicit constexpr str_storable(Args&&... args) : Allocator(
std::forward<Args>(args)...) {}
1038 K* ptr = d().init(other.
length());
1053 size_t l = pattern.
length(), allLen = l * repeat;
1055 K* ptr = d().init(allLen);
1056 for (
size_t i = 0; i < repeat; i++) {
1057 traits::copy(ptr, pattern.
symbols(), l);
1074 K*
str = d().init(count);
1075 traits::assign(
str, count, pad);
1092 template<StrExprForType<K> A>
1094 size_t len = expr.length();
1096 *expr.place((
typename A::symb_type*)d().init(len)) = 0;
1114 template<StrType<K> From>
1115 void init_replaced(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0) {
1116 auto findes = f.find_all(pattern, offset, maxCount);
1117 if (!findes.size()) {
1118 new (
this) my_type{f};
1121 size_t srcLen = f.length();
1122 size_t newSize = srcLen +
static_cast<ptrdiff_t
>(repl.len - pattern.len) * findes.size();
1125 new (
this) my_type{};
1129 K* ptr = d().init(newSize);
1132 for (
const auto& s: findes) {
1133 size_t copyLen = s - from;
1135 traits::copy(ptr, src + from, copyLen);
1139 traits::copy(ptr, repl.str, repl.len);
1142 from = s + pattern.len;
1146 traits::copy(ptr, src + from, srcLen);
1154 inline static constexpr bool is_str_storable =
true;
1161 constexpr operator const K*()
const noexcept {
1162 return d().symbols();
1172 constexpr s_str_nt
to_nts(
size_t from = 0)
const {
1173 size_t len = d().
length();
1177 return {d().symbols() + from, len - from};
1185 constexpr operator s_str_nt()
const {
1186 return {d().symbols(), d().length()};
1226 template<
typename T,
typename... Args>
1227 requires std::is_constructible_v<allocator_t, Args...>
1228 static my_type
join(
const T& strings, s_str delimiter,
bool tail =
false,
bool skip_empty =
false, Args&&... args) {
1229 my_type result(std::forward<Args>(args)...);
1230 if (strings.size()) {
1231 if (strings.size() == 1 && (!delimiter.
length() || !tail)) {
1232 result = strings.front();
1234 size_t commonLen = 0;
1235 for (
const auto& t: strings) {
1236 size_t len = t.length();
1237 if (len > 0 || !skip_empty) {
1238 if (commonLen > 0) {
1239 commonLen += delimiter.len;
1244 commonLen += (tail && delimiter.len > 0 && (commonLen > 0 || (!skip_empty && strings.size() > 0))? delimiter.len : 0);
1246 K* ptr = result.init(commonLen);
1248 for (
const auto& t: strings) {
1249 size_t copyLen = t.length();
1250 if (delimiter.len > 0 && write != ptr && (copyLen || !skip_empty)) {
1251 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1252 write += delimiter.len;
1254 ch_traits<K>::copy(write, t.symbols(), copyLen);
1257 if (delimiter.len > 0 && tail && (write != ptr || (!skip_empty && strings.size() > 0))) {
1258 ch_traits<K>::copy(write, delimiter.str, delimiter.len);
1259 write += delimiter.len;
1263 result.create_empty();
1277 template<StrType<K> From,
typename... Args>
1278 requires std::is_constructible_v<allocator_t, Args...>
1290 template<StrType<K> From,
typename... Args>
1291 requires std::is_constructible_v<allocator_t, Args...>
1307 template<StrType<K> From,
typename... Args>
1308 requires std::is_constructible_v<allocator_t, Args...>
1310 return my_type{
e_upper<K>{f}, std::forward<Args>(args)...};
1324 template<StrType<K> From,
typename... Args>
1325 requires std::is_constructible_v<allocator_t, Args...>
1327 return my_type{
e_lower<K>{f}, std::forward<Args>(args)...};
1345 template<StrType<K> From,
typename... Args>
1346 requires std::is_constructible_v<allocator_t, Args...>
1347 static my_type
replaced_from(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args) {
1348 return my_type{f, pattern, repl, offset, maxCount, std::forward<Args>(args)...};
1358 { a.allocate(size) } -> std::same_as<void*>;
1359 { a.deallocate(void_ptr) }
noexcept -> std::same_as<void>;
1368 { a.allocate(size) } -> std::same_as<void*>;
1369 { a.deallocate(void_ptr, size) }
noexcept -> std::same_as<void>;
1379struct printf_selector {
1380 template<
typename K,
typename... T>
requires (is_one_of_std_char_v<K>)
1381 static int snprintf(K* buffer,
size_t count,
const K* format, T&&... args) {
1382 if constexpr (
sizeof(K) == 1) {
1384 return std::snprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), std::forward<T>(args)...);
1388 return _sprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1392 return std::swprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1396 return _swprintf_p(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args...);
1400 template<
typename K>
requires (is_one_of_std_char_v<K>)
1401 static int vsnprintf(K* buffer,
size_t count,
const K* format, va_list args) {
1402 if constexpr (std::is_same_v<K, u8s>) {
1404 return std::vsnprintf(buffer, count, format, args);
1408 return _vsprintf_p(buffer, count, format, args);
1412 return std::vswprintf(to_one_of_std_char(buffer), count, to_one_of_std_char(format), args);
1416 return _vswprintf_p(buffer, count, format, args);
1422inline size_t grow2(
size_t ret,
size_t currentCapacity) {
1423 return ret <= currentCapacity ? ret : ret * 2;
1464template<
typename K,
typename Impl>
1467 using my_type = Impl;
1471 return *
static_cast<Impl*
>(
this);
1473 const Impl& d()
const {
1474 return *
static_cast<const Impl*
>(
this);
1476 size_t _len()
const noexcept {
1477 return d().length();
1479 const K* _str()
const noexcept {
1480 return d().symbols();
1483 using symb_type = K;
1484 using traits = ch_traits<K>;
1485 using uni = unicode_traits<K>;
1486 using uns_type = std::make_unsigned_t<K>;
1488 template<
typename Op>
1489 Impl& make_trim_op(
const Op& op) {
1490 str_piece me = d(), pos = op(me);
1491 if (me.
length() != pos.length()) {
1492 if (me.
symbols() != pos.symbols())
1493 traits::move(
const_cast<K*
>(me.
symbols()), pos.symbols(), pos.length());
1494 d().set_size(pos.length());
1500 Impl& commonChangeCase() {
1501 size_t len = _len();
1503 Op(_str(), len,
str());
1510 template<
typename T,
bool Dummy = true>
1512 static Impl&
upper(Impl& obj) {
1513 return obj.template commonChangeCase<unicode_traits<K>::upper>();
1515 static Impl&
lower(Impl& obj) {
1516 return obj.template commonChangeCase<unicode_traits<K>::lower>();
1521 Impl& utf8CaseChange() {
1524 size_t len = _len();
1526 u8s* writePos =
str();
1527 const u8s *startData = writePos, *readPos = writePos;
1528 size_t newLen = Op(readPos, len, writePos, len);
1532 d().set_size(newLen);
1533 }
else if (newLen > len) {
1536 size_t readed =
static_cast<size_t>(readPos - startData);
1537 size_t writed =
static_cast<size_t>(writePos - startData);
1538 d().set_size(newLen);
1540 readPos = startData + readed;
1541 writePos =
const_cast<u8s*
>(startData) + writed;
1542 Op(readPos, len - readed, writePos, newLen - writed);
1547 template<
bool Dummy>
1548 struct CaseTraits<u8s, Dummy> {
1549 static Impl&
upper(Impl& obj) {
1550 return obj.template utf8CaseChange<unicode_traits<u8s>::upper>();
1552 static Impl&
lower(Impl& obj) {
1553 return obj.template utf8CaseChange<unicode_traits<u8s>::lower>();
1557 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count>
1558 Impl& makeTrim(T&& pattern) {
1559 return make_trim_op(trim_operator<S, K, N - 1, withSpaces>{pattern});
1562 template<TrimS
ides S,
bool withSpaces>
1563 Impl& makeTrim(str_piece pattern) {
1564 return make_trim_op(trim_operator<S, K, 0, withSpaces>{{pattern}});
1583 explicit operator K*()
noexcept {
1593 return make_trim_op(SimpleTrim<TrimSides::TrimAll, K>{});
1602 return make_trim_op(SimpleTrim<TrimSides::TrimLeft, K>{});
1611 return make_trim_op(SimpleTrim<TrimSides::TrimRight, K>{});
1621 template<typename T, size_t N = const_lit_for<K, T>::Count>
1622 requires is_const_pattern<N>
1624 return makeTrim<TrimSides::TrimAll, false>(pattern);
1634 template<typename T, size_t N = const_lit_for<K, T>::Count>
1635 requires is_const_pattern<N>
1637 return makeTrim<TrimSides::TrimLeft, false>(pattern);
1647 template<typename T, size_t N = const_lit_for<K, T>::Count>
1648 requires is_const_pattern<N>
1650 return makeTrim<TrimSides::TrimRight, false>(pattern);
1660 template<typename T, size_t N = const_lit_for<K, T>::Count>
1661 requires is_const_pattern<N>
1663 return makeTrim<TrimSides::TrimAll, true>(pattern);
1673 template<typename T, size_t N = const_lit_for<K, T>::Count>
1674 requires is_const_pattern<N>
1676 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1686 template<typename T, size_t N = const_lit_for<K, T>::Count>
1687 requires is_const_pattern<N>
1689 return makeTrim<TrimSides::TrimRight, true>(pattern);
1700 return pattern.
length() ? makeTrim<TrimSides::TrimAll, false>(pattern) : d();
1711 return pattern.
length() ? makeTrim<TrimSides::TrimLeft, false>(pattern) : d();
1722 return pattern.
length() ? makeTrim<TrimSides::TrimRight, false>(pattern) : d();
1733 return makeTrim<TrimSides::TrimAll, true>(pattern);
1744 return makeTrim<TrimSides::TrimLeft, true>(pattern);
1755 return makeTrim<TrimSides::TrimRight, true>(pattern);
1765 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1767 if (isAsciiLower(s))
1780 for (
size_t i = 0, l = _len(); i < l; i++, ptr++) {
1782 if (isAsciiUpper(s))
1800 return CaseTraits<K>::upper(d());
1815 return CaseTraits<K>::lower(d());
1819 template<
typename T>
1820 Impl& changeImpl(
size_t from,
size_t len, T expr) {
1821 size_t myLen = _len();
1825 if (from + len > myLen) {
1829 size_t otherLen = expr.length();
1830 if (len == otherLen) {
1831 expr.place(buffer + from);
1833 size_t tailLen = myLen - from - len;
1834 if (len > otherLen) {
1835 expr.place(buffer + from);
1836 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1837 d().set_size(myLen - (len - otherLen));
1839 buffer = d().set_size(myLen + otherLen - len);
1840 traits::move(buffer + from + otherLen, buffer + from + len, tailLen);
1841 expr.place(buffer + from);
1847 template<
typename T>
1848 Impl& appendImpl(T expr) {
1849 if (
size_t len = expr.length(); len) {
1850 size_t size = _len();
1851 expr.place(d().set_size(size + len) + size);
1856 template<
typename T>
1857 Impl& appendFromImpl(
size_t pos, T expr) {
1860 if (
size_t len = expr.length())
1861 expr.place(d().set_size(pos + len) + pos);
1868 inline static constexpr bool is_str_mutable =
true;
1878 return appendImpl<str_piece>(other);
1888 template<StrExprForType<K> A>
1890 return appendImpl<const A&>(expr);
1901 return appendImpl<str_piece>(other);
1911 template<StrExprForType<K> A>
1913 return appendImpl<const A&>(expr);
1930 return appendFromImpl<str_piece>(pos, other);
1946 template<StrExprForType<K> A>
1948 return appendFromImpl<const A&>(pos, expr);
1962 Impl&
change(
size_t from,
size_t len, str_piece other) {
1963 return changeImpl<str_piece>(from, len, other);
1977 template<StrExprForType<K> A>
1978 Impl&
change(
size_t from,
size_t len,
const A& expr) {
1979 return changeImpl<const A&>(from, len, expr);
1992 return changeImpl<str_piece>(to, 0, other);
2004 template<StrExprForType<K> A>
2006 return changeImpl<const A&>(to, 0, expr);
2019 return changeImpl<const empty_expr<K>&>(from, len, {});
2030 return changeImpl<str_piece>(0, 0, other);
2040 template<StrExprForType<K> A>
2042 return changeImpl<const A&>(0, 0, expr);
2058 Impl&
replace(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
2059 offset = d().find(pattern, offset);
2060 if (offset == str::npos) {
2065 size_t replLength = repl.
length(), patternLength = pattern.
length();
2067 if (patternLength == replLength) {
2071 while (maxCount--) {
2072 traits::copy(ptr + offset, repl.
symbols(), replLength);
2073 offset = d().find(pattern, offset + replLength);
2074 if (offset == str::npos)
2077 }
else if (patternLength > replLength) {
2081 traits::copy(ptr + offset, repl.
symbols(), replLength);
2082 size_t posWrite = offset + replLength;
2083 offset += patternLength;
2085 while (--maxCount) {
2086 size_t idx = d().find(pattern, offset);
2087 if (idx == str::npos)
2089 size_t lenOfPiece = idx - offset;
2090 traits::move(ptr + posWrite, ptr + offset, lenOfPiece);
2091 posWrite += lenOfPiece;
2092 traits::copy(ptr + posWrite, repl.
symbols(), replLength);
2093 posWrite += replLength;
2094 offset = idx + patternLength;
2096 size_t tailLen = _len() - offset;
2097 traits::move(ptr + posWrite, ptr + offset, tailLen);
2098 d().set_size(posWrite + tailLen);
2100 struct replace_grow_helper {
2101 replace_grow_helper(my_type& src, str_piece p, str_piece r,
size_t mc,
size_t d)
2102 : source(src), pattern(p), repl(r), maxCount(mc), delta(d) {}
2104 const str_piece pattern;
2105 const str_piece repl;
2109 K* reserve_for_copy{};
2110 size_t end_of_piece{};
2111 size_t total_length{};
2114 size_t found[16] = {offset};
2116 offset += pattern.
length();
2119 for (; idx < std::size(found) && maxCount > 0; idx++, maxCount--) {
2120 found[idx] = source.find(pattern, offset);
2121 if (found[idx] == str::npos) {
2124 offset = found[idx] + pattern.
length();
2127 if (idx == std::size(found) && maxCount > 0 && (offset = source.find(pattern, offset)) != str::npos) {
2132 if (!reserve_for_copy) {
2135 end_of_piece = source.length();
2136 total_length = end_of_piece + all_delta;
2137 reserve_for_copy = source.alloc_for_copy(total_length);
2139 K* dst_start = reserve_for_copy;
2140 const K* src_start = source.symbols();
2142 size_t pos = found[idx] + pattern.
length();
2143 size_t lenOfPiece = end_of_piece - pos;
2144 ch_traits<K>::move(dst_start + pos + all_delta, src_start + pos, lenOfPiece);
2145 ch_traits<K>::copy(dst_start + pos + all_delta - repl.
length(), repl.
symbols(), repl.
length());
2147 end_of_piece = found[idx];
2149 if (!all_delta && reserve_for_copy != src_start) {
2150 ch_traits<K>::copy(dst_start, src_start, found[0]);
2153 } helper(d(), pattern, repl, maxCount, repl.
length() - pattern.
length());
2154 helper.replace(offset);
2155 d().set_from_copy(helper.reserve_for_copy, helper.total_length);
2175 template<StrType<K> From>
2176 Impl&
replace_from(
const From& f, str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0) {
2178 K* dst = d().reserve_no_preserve(f.length());
2181 if (maxCount == 0) {
2184 size_t src_length = f.length(), start = 0;
2185 while (maxCount--) {
2186 offset = f.find(pattern, offset);
2187 if (offset == str::npos) {
2190 size_t piece_len = offset - start;
2192 ch_traits<K>::copy(dst, src + start, piece_len);
2200 offset += pattern.
length();
2203 if (start < src_length) {
2204 ch_traits<K>::copy(dst, src + start, src_length - start);
2206 d().set_size(src_length - delta);
2209 replace(pattern, repl, offset, maxCount);
2237 template<
typename Op>
2238 Impl&
fill(
size_t from,
const Op& fillFunction) {
2239 size_t size = _len();
2242 size_t capacity = d().capacity();
2246 size_t needSize =
static_cast<size_t>(fillFunction(ptr + from, capacity));
2247 if (capacity >= needSize) {
2248 d().set_size(from + needSize);
2251 ptr = from == 0 ? d().reserve_no_preserve(needSize) : d().set_size(from + needSize);
2252 capacity = d().capacity() - from;
2264 template<
typename Op>
2265 requires std::is_invocable_v<Op, K*, size_t>
2267 return fill(0, fillFunction);
2277 template<
typename Op>
2278 requires std::is_invocable_v<Op, K*, size_t>
2280 return fill(_len(), fillFunction);
2290 template<
typename Op>
2291 requires std::is_invocable_v<Op, my_type&>
2310 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2312 size_t size = _len();
2315 size_t capacity = d().capacity();
2326 if constexpr (
sizeof(K) == 1 && !isWindowsOs) {
2327 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2328 if (result > (
int)capacity) {
2329 ptr = from == 0 ? d().reserve_no_preserve(result) : d().set_size(from + result);
2330 result = printf_selector::snprintf(ptr + from, result + 1,
format, std::forward<T>(args)...);
2334 result = printf_selector::snprintf(ptr + from, capacity + 1,
format, std::forward<T>(args)...);
2341 ptr = from == 0 ? d().reserve_no_preserve(capacity) : d().set_size(from + capacity);
2347 d().set_size(
static_cast<size_t>(traits::length(_str())));
2349 d().set_size(from + result);
2364 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2380 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2391 inline static K pad;
2392 K& operator*()
const {
2395 writer& operator++() {
2396 if (writed < max_write) {
2399 size_t l = ptr - store->begin();
2401 ptr = store->set_size(l + std::min(l / 2,
size_t(8192))) + l;
2409 writer operator++(
int) {
2415 writer(my_type& s, K* p, K* e,
size_t ml) : store(&s), ptr(p), end(e), max_write(ml) {}
2417 writer(
const writer&) =
delete;
2418 writer& operator=(
const writer&)
noexcept =
delete;
2419 writer(writer&&) noexcept = default;
2420 writer& operator=(writer&&) noexcept = default;
2421 using difference_type =
int;
2423 using fmt_type = to_std_char_t<K>;
2438 template<typename... T> requires (is_one_of_std_char_v<K>)
2440 size_t size = _len();
2443 size_t capacity = d().capacity();
2446 auto result = std::format_to(writer{d(), ptr + from, ptr + capacity, size_t(-1)},
2447 std::forward<decltype(format)>(
format), std::forward<T>(args)...);
2448 d().set_size(result.ptr - _str());
2467 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2469 size_t size = _len();
2472 size_t capacity = d().capacity();
2475 if constexpr (std::is_same_v<K, u8s>) {
2476 auto result = std::vformat_to(
2477 writer{d(), ptr + from, ptr + capacity, max_write},
2478 std::basic_string_view<K>{
format.symbols(),
format.length()},
2479 std::make_format_args(args...));
2480 d().set_size(result.ptr - _str());
2482 auto result = std::vformat_to(
2483 writer{d(), to_one_of_std_char(ptr + from), ptr + capacity, max_write},
2484 std::basic_string_view<wchar_t>{to_one_of_std_char(
format.symbols()),
format.length()},
2485 std::make_wformat_args(std::forward<T>(args)...));
2486 d().set_size(result.ptr - _str());
2502 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2503 Impl&
format(
const FmtString<fmt_type, T...>& pattern, T&&... args) {
2504 return format_from(0, pattern, std::forward<T>(args)...);
2518 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2534 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2550 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2568 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2586 template<
typename... T>
requires (is_one_of_std_char_v<K>)
2600 template<
typename Op,
typename... Args>
2601 Impl&
with(
const Op& fillFunction, Args&&... args) {
2602 fillFunction(d(), std::forward<Args>(args)...);
2608struct SharedStringData {
2609 std::atomic_size_t ref_;
2610 inline static constexpr size_t mask = (size_t(-1)) >> 1, check = ~mask;
2612 SharedStringData() {
2615 SharedStringData(
size_t capacity) {
2617 reinterpret_cast<size_t*
>(
this)[-1] = (capacity + 1) *
sizeof(K) +
sizeof(*
this) +
sizeof(size_t);
2620 return (K*)(
this + 1);
2623 ref_.fetch_add(1, std::memory_order_relaxed);
2625 void decr(AllocatableNoSized
auto& allocator) {
2626 size_t val = ref_.fetch_sub(1, std::memory_order_relaxed);
2628 allocator.deallocate(
this);
2631 void decr(AllocatableSized
auto& allocator,
size_t len) {
2632 size_t val = ref_.fetch_sub(1, std::memory_order_relaxed);
2633 if ((val & mask) == 1) {
2637 size_t* ptr =
reinterpret_cast<size_t*
>(
this);
2639 allocator.deallocate(ptr, *ptr);
2641 allocator.deallocate(
this, (len + 1) *
sizeof(K) +
sizeof(*
this));
2645 static SharedStringData* create(
size_t l, Allocatable
auto& allocator) {
2646 size_t size =
sizeof(SharedStringData) + (l + 1) *
sizeof(K);
2647 return new (allocator.allocate(size)) SharedStringData();
2649 static SharedStringData* from_str(
const K* p) {
2650 return (SharedStringData*)p - 1;
2652 K* place(K* p,
size_t len) {
2653 ch_traits<K>::copy(p, str(), len);
2660class string_common_allocator {
2662 void* allocate(
size_t bytes) {
2663 return ::operator
new(bytes);
2665 void deallocate(
void* address)
noexcept {
2666 ::operator
delete(address);
2670string_common_allocator default_string_allocator_selector(...);
2677using allocator_string =
decltype(default_string_allocator_selector(
int(0)));
2679template<
typename K, Allocatable Allocator>
2711template<
typename K,
size_t N,
bool forShared = false, Allocatable Allocator = allocator_
string>
2713 public str_algs<K, simple_str<K>, lstring<K, N, forShared, Allocator>, true>,
2714 public str_mutable<K, lstring<K, N, forShared, Allocator>>,
2715 public str_storable<K, lstring<K, N, forShared, Allocator>, Allocator>,
2716 public null_terminated<K, lstring<K, N, forShared, Allocator>>,
2717 public from_utf_convertible<K, lstring<K, N, forShared, Allocator>> {
2719 using symb_type = K;
2721 using allocator_t = Allocator;
2733 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
2734 using base_storable = str_storable<K, my_type, Allocator>;
2735 using base_mutable = str_mutable<K, my_type>;
2736 using base_utf = from_utf_convertible<K, my_type>;
2737 using traits = ch_traits<K>;
2738 using s_str = base_storable::s_str;
2740 friend base_storable;
2741 friend base_mutable;
2743 friend class sstring<K, Allocator>;
2750 K local_[LocalCapacity + 1];
2753 constexpr void create_empty() {
2758 constexpr static size_t calc_capacity(
size_t s) {
2759 const int al =
alignof(std::max_align_t) < 16 ? 16 : alignof(std::max_align_t);
2760 size_t real_need = (s + 1) *
sizeof(K) + extra;
2761 size_t aligned_alloced = (real_need + al - 1) / al * al;
2762 return (aligned_alloced - extra) /
sizeof(K) - 1;
2765 constexpr K* init(
size_t s) {
2766 size_t need_cap = s;
2767 if (need_cap > LocalCapacity) {
2768 need_cap = calc_capacity(s);
2769 data_ = alloc_place(need_cap);
2770 capacity_ = need_cap;
2778 constexpr bool is_alloced() const noexcept {
2779 return data_ != local_;
2782 constexpr void dealloc() {
2784 if constexpr (AllocatableNoSized<Allocator>) {
2785 base_storable::allocator().deallocate(to_real_address(data_));
2787 base_storable::allocator().deallocate(to_real_address(data_), (capacity_ + 1) *
sizeof(K) + extra);
2793 constexpr static K* to_real_address(
void* ptr) {
2794 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) - extra);
2796 constexpr static K* from_real_address(
void* ptr) {
2797 return reinterpret_cast<K*
>(
reinterpret_cast<u8s*
>(ptr) + extra);
2800 constexpr K* alloc_place(
size_t newSize) {
2801 return from_real_address(base_storable::allocator().allocate((newSize + 1) *
sizeof(K) + extra));
2805 constexpr K* alloc_for_copy(
size_t newSize) {
2806 if (capacity() >= newSize) {
2811 return alloc_place(calc_capacity(newSize));
2815 constexpr void set_from_copy(K* ptr,
size_t newSize) {
2821 capacity_ = calc_capacity(newSize);
2826 constexpr void copy_from_another(K* buf,
const K* src,
size_t size) {
2829 size_t need_copy_bytes = (size + 1) *
sizeof(K);
2830 size_t cnt = (need_copy_bytes +
sizeof(
void*) - 1) /
sizeof(
void*) *
sizeof(
void*);
2831 traits::copy(buf, src, cnt /
sizeof(K));
2840 template<
typename... Args>
2841 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
2842 constexpr lstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
2843 : base_storable(
std::forward<Args>(args)...) {
2855 template<
typename... Args>
2856 requires std::is_constructible_v<allocator_t, Args...>
2857 constexpr lstring(s_str other, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2870 template<
typename... Args>
2871 requires std::is_constructible_v<allocator_t, Args...>
2872 constexpr lstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2885 template<
typename... Args>
2886 requires std::is_constructible_v<allocator_t, Args...>
2887 constexpr lstring(
size_t count, K pad, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2904 template<
typename... Args>
2905 requires std::is_constructible_v<allocator_t, Args...>
2925 template<StrType<K> From,
typename... Args>
2926 requires std::is_constructible_v<allocator_t, Args...>
2927 constexpr lstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
2928 : base_storable(
std::forward<Args>(args)...) {
2936 constexpr ~lstring() {
2947 struct copy{uint64_t p[2];};
2948 constexpr size_t short_str =
sizeof(copy) /
sizeof(K);
2950 if (other.size_ < short_str) {
2952 size_ = other.size_;
2953 *(copy*)local_ = *(
const copy*)other.local_;
2957 if (
size_t size = other.size_) {
2958 copy_from_another(init(size), other.symbols(), size);
2971 template<
typename... Args>
2972 requires(
sizeof...(Args) > 0 && std::is_convertible_v<allocator_t, Args...>)
2973 constexpr lstring(
const my_type& other, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2975 copy_from_another(init(other.size_), other.symbols(), other.size_);
2988 template<typename T, size_t I = const_lit_for<K, T>::Count,
typename... Args>
2989 requires std::is_constructible_v<allocator_t, Args...>
2990 constexpr lstring(T&& value, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
2991 if constexpr (I > 1) {
2992 K* ptr = init(I - 1);
2993 traits::copy(ptr, (
const K*)value, I - 1);
3005 constexpr lstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
3007 size_ = other.size_;
3008 if (other.is_alloced()) {
3009 data_ = other.data_;
3010 other.data_ = other.local_;
3011 capacity_ = other.capacity_;
3014 copy_from_another(data_, other.local_, size_);
3017 other.local_[0] = 0;
3030 template<
typename Op,
typename... Args>
3031 requires(std::is_constructible_v<Allocator, Args...> && (std::is_invocable_v<Op, my_type&> || std::is_invocable_v<Op, K*, size_t>))
3032 lstring(
const Op& op, Args&&... args) : base_storable(std::forward<Args>(args)...) {
3036 template<
typename O>
3037 requires(!std::is_same_v<O, K>)
3039 this->init_from_utf_convertible(init);
3042 template<
typename O,
typename I,
bool M>
3043 requires(!std::is_same_v<O, K>)
3044 lstring(
const str_algs<O, simple_str<O>, I, M>& init) {
3045 this->init_from_utf_convertible(init.
to_str());
3064 if (&other !=
this) {
3066 size_ = other.size_;
3081 if (&other !=
this) {
3083 if (other.is_alloced()) {
3084 data_ = other.data_;
3085 capacity_ = other.capacity_;
3087 traits::copy(data_, other.local_, other.size_ + 1);
3090 size_ = other.size_;
3091 other.create_empty();
3096 my_type& assign(
const K* other,
size_t len) {
3098 bool isIntersect = other >= data_ && other + len <= data_ + size_;
3104 if (other > data_) {
3105 traits::move(data_, other, len);
3108 traits::copy(reserve_no_preserve(len), other, len);
3124 return assign(other.str, other.len);
3134 template<typename T, size_t S = const_lit_for<K, T>::Count>
3136 return assign((
const K*)other, S - 1);
3149 size_t newLen = expr.
length();
3195 newSize = calc_capacity(newSize);
3196 K* newData = alloc_place(newSize);
3199 capacity_ = newSize;
3217 newSize = calc_capacity(newSize);
3218 K* newData = alloc_place(newSize);
3219 traits::copy(newData, data_, size_);
3222 capacity_ = newSize;
3240 if (newSize > cap) {
3241 size_t needPlace = newSize;
3242 if (needPlace < (cap + 1) * 2) {
3243 needPlace = (cap + 1) * 2 - 1;
3256 return !is_alloced();
3266 for (
size_t i = 0; i < cap; i++) {
3267 if (data_[i] == 0) {
3282 size_t need_capacity = calc_capacity(size_);
3283 if (is_alloced() && capacity_ > need_capacity) {
3284 K* newData = size_ <=
LocalCapacity ? local_ : alloc_place(need_capacity);
3285 traits::copy(newData, data_, size_ + 1);
3290 capacity_ = need_capacity;
3306template<
size_t N = 15>
3307using lstringa = lstring<u8s, N>;
3308template<
size_t N = 15>
3309using lstringb = lstring<ubs, N>;
3310template<
size_t N = 15>
3311using lstringw = lstring<wchar_t, N>;
3312template<
size_t N = 15>
3313using lstringu = lstring<u16s, N>;
3314template<
size_t N = 15>
3315using lstringuu = lstring<u32s, N>;
3317template<
size_t N = 15>
3318using lstringsa = lstring<u8s, N, true>;
3319template<
size_t N = 15>
3320using lstringsb = lstring<ubs, N, true>;
3321template<
size_t N = 15>
3322using lstringsw = lstring<wchar_t, N, true>;
3323template<
size_t N = 15>
3324using lstringsu = lstring<u16s, N, true>;
3325template<
size_t N = 15>
3326using lstringsuu = lstring<u32s, N, true>;
3329template<typename T, typename K = typename const_lit<T>::symb_type>
3330auto getLiteralType(T&&) {
3334template<
size_t Arch,
size_t L>
3335inline constexpr const size_t _local_count = 0;
3338inline constexpr const size_t _local_count<8, 1> = 23;
3340inline constexpr const size_t _local_count<8, 2> = 15;
3342inline constexpr const size_t _local_count<8, 4> = 7;
3344inline constexpr const size_t _local_count<4, 1> = 15;
3346inline constexpr const size_t _local_count<4, 2> = 11;
3348inline constexpr const size_t _local_count<4, 4> = 5;
3351constexpr const size_t local_count = _local_count<
sizeof(size_t),
sizeof(T)>;
3405template<
typename K, Allocatable Allocator = allocator_
string>
3406class decl_empty_bases sstring :
3407 public str_algs<K, simple_str<K>, sstring<K, Allocator>, false>,
3408 public str_storable<K, sstring<K, Allocator>, Allocator>,
3409 public null_terminated<K, sstring<K, Allocator>>,
3410 public from_utf_convertible<K, sstring<K, Allocator>> {
3412 using symb_type = K;
3413 using uns_type = std::make_unsigned_t<K>;
3414 using my_type = sstring<K, Allocator>;
3415 using allocator_t = Allocator;
3417 enum { LocalCount = local_count<K> };
3420 using base_algs = str_algs<K, simple_str<K>, my_type,
false>;
3422 using base_utf = from_utf_convertible<K, my_type>;
3423 using traits = ch_traits<K>;
3424 using uni = unicode_traits<K>;
3425 using s_str = base_storable::s_str;
3427 friend base_storable;
3430 enum Types { Local, Constant, Shared };
3443 uns_type localRemain_ :
sizeof(uns_type) * CHAR_BIT - 2;
3458 constexpr void create_empty() {
3460 localRemain_ = LocalCount;
3463 constexpr K* init(
size_t s) {
3464 if (s > LocalCount) {
3472 localRemain_ = LocalCount - s;
3478 if (type_ == Shared) {
3498 template<
typename... Args>
3499 requires (std::is_constructible_v<allocator_t, Args...> &&
sizeof...(Args) > 0)
3500 sstring(Args&&... args)
noexcept(std::is_nothrow_constructible_v<allocator_t, Args...>)
3501 : base_storable(
std::forward<Args>(args)...) {
3513 template<
typename... Args>
3514 requires std::is_constructible_v<allocator_t, Args...>
3515 sstring(s_str other, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3528 template<
typename... Args>
3529 requires std::is_constructible_v<allocator_t, Args...>
3530 sstring(
size_t repeat, s_str pattern, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3543 template<
typename... Args>
3544 requires std::is_constructible_v<allocator_t, Args...>
3545 sstring(
size_t count, K pad, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3562 template<
typename... Args>
3563 requires std::is_constructible_v<allocator_t, Args...>
3583 template<StrType<K> From,
typename... Args>
3584 requires std::is_constructible_v<allocator_t, Args...>
3585 sstring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0, Args&&... args)
3586 : base_storable(
std::forward<Args>(args)...) {
3601 constexpr sstring(
const my_type& other) noexcept : base_storable(other.allocator()) {
3602 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3603 if (type_ == Shared)
3604 SharedStringData<K>::from_str(sstr_)->incr();
3612 constexpr sstring(my_type&& other) noexcept : base_storable(std::move(other.allocator())) {
3613 memcpy(buf_, other.buf_,
sizeof(buf_) +
sizeof(K));
3614 other.create_empty();
3629 size_t size = src.length();
3631 if (src.is_alloced()) {
3635 if (
size > LocalCount) {
3643 new (SharedStringData<K>::from_str(
str)) SharedStringData<K>;
3645 new (SharedStringData<K>::from_str(
str)) SharedStringData<K>(src.capacity_);
3651 localRemain_ = LocalCount -
size;
3652 traits::copy(buf_,
str,
size + 1);
3660 K*
str = init(src.size_);
3661 traits::copy(
str, src.symbols(),
size + 1);
3678 template<typename T, size_t N = const_lit_for<K, T>::Count,
typename... Args>
3679 requires std::is_constructible_v<allocator_t, Args...>
3680 sstring(T&& s, Args&&... args) : base_storable(
std::forward<Args>(args)...) {
3683 cstr_ = (
const K*)s;
3692 template<
typename O>
requires(!std::is_same_v<O, K>)
3694 this->init_from_utf_convertible(init);
3697 template<
typename O,
typename I,
bool M>
requires(!std::is_same_v<O, K>)
3699 this->init_from_utf_convertible(init.
to_str());
3702 constexpr void swap(my_type&& other)
noexcept {
3703 char buf[
sizeof(buf_) +
sizeof(K)];
3704 memcpy(buf, buf_,
sizeof(buf));
3705 memcpy(buf_, other.buf_,
sizeof(buf));
3706 memcpy(other.buf_, buf,
sizeof(buf));
3708 std::swap(base_storable::allocator(), other.allocator());
3719 swap(std::move(other));
3741 template<typename T, size_t N = const_lit_for<K, T>::Count>
3753 template<
size_t N,
bool forShared,
typename A>
3767 return operator=(my_type{std::move(other)});
3795 return type_ == Local ? buf_ : cstr_;
3799 return type_ == Local ? LocalCount - localRemain_ : bigLen_;
3821 template<
typename... T>
3822 static my_type
printf(
const K* pattern, T&&... args) {
3835 template<
typename... T>
3836 static my_type
format(
const FmtString<to_std_char_t<K>, T...>& fmtString, T&&... args) {
3849 template<
typename... T>
3855template<
typename K, Allocatable Allocator>
3856inline const sstring<K> sstring<K, Allocator>::empty_str{};
3860template<
typename K,
size_t N>
3861class decl_empty_bases cestring :
3862 public str_algs<K, simple_str<K>, cestring<K, N>, true>,
3863 public str_storable<K, cestring<K, N>, no_alloc>,
3864 public null_terminated<K, lstring<K, N>>
3868 using symb_type = K;
3869 using my_type = cestring<K, N>;
3873 LocalCapacity = N | (
sizeof(
void*) /
sizeof(K) - 1),
3878 using base_algs = str_algs<K, simple_str<K>, my_type,
true>;
3879 using base_storable = str_storable<K, my_type, no_alloc>;
3881 using traits = ch_traits<K>;
3882 using s_str = base_storable::s_str;
3884 friend base_storable;
3889 K local_[LocalCapacity + 1]{};
3891 constexpr void create_empty() {
3897 constexpr K* init(
size_t s) {
3899 if (size_ > LocalCapacity) {
3900 throw std::bad_alloc{};
3907 constexpr size_t length() const noexcept {
3911 constexpr const K* symbols() const noexcept {
3912 return is_cstr_ ? cstr_ : local_;
3915 constexpr bool is_empty() const noexcept {
3919 constexpr bool empty() const noexcept {
3923 constexpr size_t capacity() const noexcept {
3924 return LocalCapacity;
3930 constexpr cestring() noexcept = default;
3938 constexpr cestring(s_str other) : base_storable() {
3939 base_storable::init_from_str_other(other);
3949 constexpr cestring(
size_t repeat, s_str pattern) : base_storable() {
3950 base_storable::init_str_repeat(repeat, pattern);
3960 constexpr cestring(
size_t count, K pad) : base_storable() {
3961 base_storable::init_symb_repeat(count, pad);
3975 constexpr cestring(
const StrExprForType<K>
auto& expr) : base_storable() {
3976 base_storable::init_str_expr(expr);
3992 template<StrType<K> From>
3993 constexpr cestring(
const From& f, s_str pattern, s_str repl,
size_t offset = 0,
size_t maxCount = 0)
3995 base_storable::init_replaced(f, pattern, repl, offset, maxCount);
3999 constexpr ~cestring() {}
4009 template<typename T, size_t M = const_lit_for<K, T>::Count>
4010 constexpr cestring(T&& s) : base_storable(), cstr_((const K*)s), size_(M - 1), is_cstr_(true), local_{0} {}
4014consteval 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) {
4015 if constexpr (std::is_same_v<K, u8s>)
4017 if constexpr (std::is_same_v<K, ubs>)
4019 if constexpr (std::is_same_v<K, uws>)
4021 if constexpr (std::is_same_v<K, u16s>)
4023 if constexpr (std::is_same_v<K, u32s>)
4027#define uni_string(K, p) select_str<K>(p, u8##p, L##p, u##p, U##p)
4029template<
typename K,
template<
typename C>
typename H>
4033 char node[
sizeof(sstring<K>)];
4035 const simple_str_nt<K>& to_nt() const noexcept {
4036 return static_cast<const simple_str_nt<K>&
>(str);
4038 const sstring<K>& to_str() const noexcept {
4039 return *
reinterpret_cast<const sstring<K>*
>(node);
4041 bool operator==(
const StoreType& other)
const {
4042 return hash == other.hash &&
typename H<K>::eql{}(*
this, other);
4048 static inline constexpr size_t basis =
static_cast<size_t>(14695981039346656037ULL);
4049 static inline constexpr size_t prime =
static_cast<size_t>(1099511628211ULL);
4053struct fnv_const<false> {
4054 static inline constexpr size_t basis =
static_cast<size_t>(2166136261U);
4055 static inline constexpr size_t prime =
static_cast<size_t>(16777619U);
4058using fnv = fnv_const<
sizeof(size_t) == 8>;
4061inline constexpr size_t fnv_hash(
const K* ptr,
size_t l) {
4062 size_t h = fnv::basis;
4063 for (
size_t i = 0; i < l; i++) {
4064 h = (h ^ (std::make_unsigned_t<K>)ptr[i]) * fnv::prime;
4070inline constexpr size_t fnv_hash_ia(
const K* ptr,
size_t l) {
4071 size_t h = fnv::basis;
4072 for (
size_t i = 0; i < l; i++) {
4073 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)ptr[i];
4074 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
4079template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
4080inline constexpr size_t fnv_hash(T&& value) {
4081 size_t h = fnv::basis;
4082 for (
size_t i = 0; i < N - 1; i++) {
4083 h = (h ^ (std::make_unsigned_t<K>)value[i]) * fnv::prime;
4088template<typename T, typename K = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
4089inline constexpr size_t fnv_hash_ia(T&& value) {
4090 size_t h = fnv::basis;
4091 for (
size_t i = 0; i < N - 1; i++) {
4092 std::make_unsigned_t<K> s = (std::make_unsigned_t<K>)value[i];
4093 h = (h ^ (s >=
'A' && s <=
'Z' ? s | 0x20 : s)) * fnv::prime;
4099inline consteval size_t fnv_hash_compile(
const K* ptr,
size_t l) {
4100 return fnv_hash(ptr, l);
4104inline consteval size_t fnv_hash_ia_compile(
const K* ptr,
size_t l) {
4105 return fnv_hash_ia(ptr, l);
4111static_assert(std::is_trivially_copyable_v<StoreType<u8s, str_exact>>,
"Store type must be trivially copyable");
4114template<
typename K,
typename V>
4115std::allocator<std::pair<K, V>> default_hashstrmap_allocator_selector(...);
4124template<
typename K,
template<
typename C>
typename H,
typename V>
4125using allocator_hashstrmap =
decltype(default_hashstrmap_allocator_selector<const StoreType<K, H>, V>(int(0)));
4221template<
typename K,
typename T,
template<
typename C>
typename HE = str_exact,
typename A = allocator_hashstrmap<K, HE, T>>
4222class hashStrMap :
public std::unordered_map<StoreType<K, HE>, T, typename HE<K>::hash, typename HE<K>::eql, A> {
4224 using InStore = StoreType<K, HE>;
4227 using hasher =
typename HE<K>::hash;
4228 using comparator =
typename HE<K>::eql;
4229 using my_type = hashStrMap<K, T, HE, A>;
4230 using hash_t = std::unordered_map<StoreType<K, HE>, T, hasher, comparator, A>;
4232 hashStrMap() =
default;
4233 hashStrMap(
const my_type& other) : hash_t(other) {
4234 for (
const auto& [k, v] : *
this) {
4235 InStore& stored =
const_cast<InStore&
>(k);
4237 new (stored.node)
sstring<K>(std::move(tmp));
4238 stored.str.str = stored.to_str().symbols();
4242 for (
auto& k: *
this)
4246 hashStrMap(my_type&& o) =
default;
4248 my_type& operator=(
const my_type& other) {
4249 hash_t::operator=(other);
4250 for (
const auto& [k, v] : *
this) {
4251 InStore& stored =
const_cast<InStore&
>(k);
4253 new (stored.node)
sstring<K>(std::move(tmp));
4254 stored.str.str = stored.to_str().symbols();
4258 my_type& operator=(my_type&&) =
default;
4260 hashStrMap(std::initializer_list<std::pair<const InStore, T>>&& init) {
4261 for (
const auto& e: init)
4262 emplace(e.first, e.second);
4265 using init_str = std::initializer_list<std::pair<const sstring<K>, T>>;
4267 hashStrMap(init_str&& init) {
4268 for (
const auto& e: init)
4269 emplace(e.first, e.second);
4274 template<
typename... ValArgs>
4275 auto try_emplace(
const InStore& key, ValArgs&&... args) {
4276 auto it = hash_t::try_emplace(key, std::forward<ValArgs>(args)...);
4278 InStore& stored =
const_cast<InStore&
>(it.first->first);
4280 stored.str.str = stored.to_str().symbols();
4286 return {key, hasher{}(key)};
4289 template<
typename Key,
typename... ValArgs>
4290 requires(std::is_convertible_v<Key, simple_str<K>>)
4291 auto try_emplace(Key&& key, ValArgs&&... args) {
4292 auto it = hash_t::try_emplace(toStoreType(key), std::forward<ValArgs>(args)...);
4294 InStore& stored =
const_cast<InStore&
>(it.first->first);
4295 new (stored.node)
sstring<K>(std::forward<Key>(key));
4296 stored.str.str = stored.to_str().symbols();
4301 template<
typename... ValArgs>
4302 auto emplace(
const InStore& key, ValArgs&&... args) {
4303 auto it = try_emplace(key, std::forward<ValArgs>(args)...);
4305 it.first->second = T(std::forward<ValArgs>(args)...);
4310 template<
typename Key,
typename... ValArgs>
4311 requires(std::is_convertible_v<Key, simple_str<K>>)
4312 auto emplace(Key&& key, ValArgs&&... args) {
4313 auto it = try_emplace(std::forward<Key>(key), std::forward<ValArgs>(args)...);
4315 it.first->second = T(std::forward<ValArgs>(args)...);
4320 auto& operator[](
const InStore& key) {
4321 return try_emplace(key).first->second;
4324 template<
typename Key>
4325 requires(std::is_convertible_v<Key, simple_str<K>>)
4326 auto&
operator[](Key&& key) {
4327 return try_emplace(std::forward<Key>(key)).first->second;
4330 decltype(
auto) at(
const InStore& key) {
4331 return hash_t::at(key);
4333 decltype(
auto) at(
const InStore& key)
const {
4334 return hash_t::at(key);
4338 return hash_t::at(toStoreType(key));
4341 return hash_t::at(toStoreType(key));
4344 auto find(
const InStore& key)
const {
4345 return hash_t::find(key);
4349 return find(toStoreType(key));
4352 auto find(
const InStore& key) {
4353 return hash_t::find(key);
4357 return find(toStoreType(key));
4360 auto erase(
typename hash_t::const_iterator it) {
4361 if (it != hash_t::end()) {
4364 return hash_t::erase(it);
4367 auto erase(
const InStore& key) {
4368 auto it = hash_t::find(key);
4369 if (it != hash_t::end()) {
4378 return erase(toStoreType(key));
4382 auto it = find(txt);
4383 if (it != hash_t::end()) {
4391 for (
auto& k: *
this)
4395 bool contains(
const InStore& key)
const {
4396 return hash_t::find(key) != this->end();
4400 return find(toStoreType(key)) != this->end();
4407 bool operator()(
const StoreType<K, str_exact>& _Left,
const StoreType<K, str_exact>& _Right)
const {
4408 return _Left.hash == _Right.hash && _Left.str == _Right.str;
4412 size_t operator()(simple_str<K> _Keyval)
const {
4413 return fnv_hash(_Keyval.symbols(), _Keyval.length());
4415 size_t operator()(
const StoreType<K, str_exact>& _Keyval)
const {
4416 return _Keyval.hash;
4424 bool operator()(
const StoreType<K, str_eqlia>& _Left,
const StoreType<K, str_eqlia>& _Right)
const {
4425 return _Left.hash == _Right.hash && _Left.str.equal_ia(_Right.str);
4429 size_t operator()(simple_str<K> _Keyval)
const {
4430 return fnv_hash_ia(_Keyval.symbols(), _Keyval.length());
4432 size_t operator()(
const StoreType<K, str_eqlia>& _Keyval)
const {
4433 return _Keyval.hash;
4441 bool operator()(
const StoreType<K, str_eqliu>& _Left,
const StoreType<K, str_eqliu>& _Right)
const {
4442 return _Left.hash == _Right.hash && _Left.str.equal_iu(_Right.str);
4446 size_t operator()(simple_str<K> _Keyval)
const {
4447 using bc = to_base_char_t<K>;
4448 return unicode_traits<bc>::hashiu((
const bc*)_Keyval.symbols(), _Keyval.length());
4450 size_t operator()(
const StoreType<K, str_eqliu>& _Keyval)
const {
4451 return _Keyval.hash;
4472 using chunk_t = std::pair<std::unique_ptr<K[]>,
size_t>;
4473 std::vector<chunk_t> chunks;
4480 using my_type = chunked_string_builder<K>;
4481 using symb_type = K;
4482 chunked_string_builder() =
default;
4483 chunked_string_builder(
size_t a) : align(a){};
4484 chunked_string_builder(
const my_type&) =
delete;
4485 chunked_string_builder(my_type&& other) noexcept
4486 : chunks(std::move(other.chunks)), write(other.write), len(other.len), remain(other.remain), align(other.align) {
4487 other.len = other.remain = 0;
4488 other.write =
nullptr;
4490 my_type& operator=(my_type other)
noexcept {
4491 chunks.swap(other.chunks);
4492 write = other.write;
4494 remain = other.remain;
4495 align = other.align;
4496 other.len = other.remain = 0;
4497 other.write =
nullptr;
4505 if (
data.len <= remain) {
4508 ch_traits<K>::copy(write,
data.str,
data.len);
4510 chunks.back().second +=
data.len;
4517 ch_traits<K>::copy(write,
data.str, remain);
4520 chunks.back().second += remain;
4526 size_t blockSize = (
data.len + align - 1) / align * align;
4527 chunks.emplace_back(std::make_unique<K[]>(blockSize),
data.len);
4528 write = chunks.back().first.get();
4529 ch_traits<K>::copy(write,
data.str,
data.len);
4531 remain = blockSize -
data.len;
4538 size_t l = expr.length();
4541 write = expr.place(write);
4542 chunks.back().second += l;
4545 }
else if (!remain) {
4546 size_t blockSize = (l + align - 1) / align * align;
4547 chunks.emplace_back(std::make_unique<K[]>(blockSize), l);
4548 write = expr.place(chunks.back().first.get());
4550 remain = blockSize - l;
4552 auto store = std::make_unique<K[]>(l);
4553 expr.place(store.get());
4560 template<
typename T>
4562 requires std::is_same_v<T, K>
4564 return operator<<(expr_char<K>(
data));
4572 if (chunks.empty()) {
4575 if (chunks.size() > 1) {
4579 remain += chunks[0].second;
4580 chunks[0].second = 0;
4582 write = chunks[0].first.get();
4585 constexpr K* place(K* p)
const noexcept {
4586 for (
const auto& block: chunks) {
4587 ch_traits<K>::copy(p, block.first.get(), block.second);
4600 template<
typename Op>
4602 for (
const auto& block: chunks)
4603 o(block.first.get(), block.second);
4610 if (chunks.size()) {
4611 const K* ptr = chunks.front().first.get();
4612 for (
const auto& chunk: chunks) {
4613 if (chunk.first.get() != ptr)
4615 ptr += chunk.second;
4627 return chunks.size() ? chunks.front().first.get() : simple_str_nt<K>::empty_str.str;
4644 typename decltype(chunks)::const_iterator it, end;
4645 size_t writedFromCurrentChunk;
4665 while (size && !
is_end()) {
4666 size_t remain = it->second - writedFromCurrentChunk;
4667 size_t write = std::min(size, remain);
4668 ch_traits<K>::copy(buffer, it->first.get() + writedFromCurrentChunk, write);
4674 writedFromCurrentChunk = 0;
4676 writedFromCurrentChunk += write;
4688 return {chunks.begin(), chunks.end(), 0};
4701using stringa = sstring<u8s>;
4702using stringb = sstring<ubs>;
4703using stringw = sstring<wchar_t>;
4704using stringu = sstring<u16s>;
4705using stringuu = sstring<u32s>;
4706static_assert(
sizeof(stringa) == (
sizeof(
void*) == 8 ? 24 : 16),
"Bad size of sstring");
4712template<
typename T,
typename A = allocator_hashstrmap<u8s, str_exact, T>>
4718template<
typename T,
typename A = allocator_hashstrmap<u8s, str_eqlia, T>>
4724template<
typename T,
typename A = allocator_hashstrmap<u8s, str_eqliu, T>>
4731template<
typename T,
typename A = allocator_hashstrmap<ubs, str_exact, T>>
4737template<
typename T,
typename A = allocator_hashstrmap<ubs, str_eqlia, T>>
4743template<
typename T,
typename A = allocator_hashstrmap<ubs, str_eqliu, T>>
4750template<
typename T,
typename A = allocator_hashstrmap<
wchar_t, str_exact, T>>
4757template<
typename T,
typename A = allocator_hashstrmap<
wchar_t, str_eqlia, T>>
4764template<
typename T,
typename A = allocator_hashstrmap<
wchar_t, str_eqliu, T>>
4771template<
typename T,
typename A = allocator_hashstrmap<u16s, str_exact, T>>
4777template<
typename T,
typename A = allocator_hashstrmap<u16s, str_eqlia, T>>
4783template<
typename T,
typename A = allocator_hashstrmap<u16s, str_eqliu, T>>
4790template<
typename T,
typename A = allocator_hashstrmap<u32s, str_exact, T>>
4796template<
typename T,
typename A = allocator_hashstrmap<u32s, str_eqlia, T>>
4802template<
typename T,
typename A = allocator_hashstrmap<u32s, str_eqliu, T>>
4807inline namespace literals {
4876template<
typename K>
using HashKey = StoreType<K, str_exact>;
4877template<
typename K>
using HashKeyIA = StoreType<K, str_eqlia>;
4878template<
typename K>
using HashKeyIU = StoreType<K, str_eqliu>;
4890consteval HashKey<u8s>
operator""_h(
const u8s* ptr,
size_t l) {
4891 return HashKey<u8s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4904consteval HashKeyIA<u8s>
operator""_ia(
const u8s* ptr,
size_t l) {
4905 return HashKeyIA<u8s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4918inline HashKeyIU<u8s>
operator""_iu(
const u8s* ptr,
size_t l) {
4919 return HashKeyIU<u8s>{{ptr, l}, str_eqliu<u8s>::hash{}(
simple_str<u8s>{ptr, l})};
4932consteval HashKey<ubs>
operator""_h(
const ubs* ptr,
size_t l) {
4933 return HashKey<ubs>{{ptr, l}, fnv_hash_compile(ptr, l)};
4946consteval HashKeyIA<ubs>
operator""_ia(
const ubs* ptr,
size_t l) {
4947 return HashKeyIA<ubs>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
4960inline HashKeyIU<ubs>
operator""_iu(
const ubs* ptr,
size_t l) {
4961 return HashKeyIU<ubs>{{ptr, l}, str_eqliu<u8s>::hash{}(
simple_str<u8s>{(
const u8s*)ptr, l})};
4974consteval HashKey<u16s>
operator""_h(
const u16s* ptr,
size_t l) {
4975 return HashKey<u16s>{{ptr, l}, fnv_hash_compile(ptr, l)};
4988consteval HashKeyIA<u16s>
operator""_ia(
const u16s* ptr,
size_t l) {
4989 return HashKeyIA<u16s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
5002inline HashKeyIU<u16s>
operator""_iu(
const u16s* ptr,
size_t l) {
5003 return HashKeyIU<u16s>{{ptr, l}, str_eqliu<u16s>::hash{}(
simple_str<u16s>{ptr, l})};
5016consteval HashKey<u32s>
operator""_h(
const u32s* ptr,
size_t l) {
5017 return HashKey<u32s>{{ptr, l}, fnv_hash_compile(ptr, l)};
5030consteval HashKeyIA<u32s>
operator""_ia(
const u32s* ptr,
size_t l) {
5031 return HashKeyIA<u32s>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
5044inline HashKeyIU<u32s>
operator""_iu(
const u32s* ptr,
size_t l) {
5045 return HashKeyIU<u32s>{{ptr, l}, str_eqliu<u32s>::hash{}(
simple_str<u32s>{ptr, l})};
5058consteval HashKey<uws>
operator""_h(
const uws* ptr,
size_t l) {
5059 return HashKey<uws>{{ptr, l}, fnv_hash_compile(ptr, l)};
5072consteval HashKeyIA<uws>
operator""_ia(
const uws* ptr,
size_t l) {
5073 return HashKeyIA<uws>{{ptr, l}, fnv_hash_ia_compile(ptr, l)};
5086inline HashKeyIU<uws>
operator""_iu(
const uws* ptr,
size_t l) {
5087 return HashKeyIU<uws>{{ptr, l}, str_eqliu<uws>::hash{}(
simple_str<uws>{ptr, l})};
5102 return stream << std::string_view{text.
symbols(), text.
length()};
5115inline std::wostream&
operator<<(std::wostream& stream, ssw text) {
5116 return stream << std::wstring_view{text.
symbols(), text.
length()};
5130 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
5143inline std::ostream&
operator<<(std::ostream& stream,
const stringa& text) {
5144 return stream << std::string_view{text.
symbols(), text.
length()};
5157inline std::wostream&
operator<<(std::wostream& stream,
const stringw& text) {
5158 return stream << std::wstring_view{text.
symbols(), text.
length()};
5172 return stream << std::wstring_view{from_w(text.symbols()), text.length()};
5185template<
size_t N,
bool S, simstr::Allocatable A>
5187 return stream << std::string_view{text.
symbols(), text.
length()};
5200template<
size_t N,
bool S, simstr::Allocatable A>
5202 return stream << std::wstring_view{text.
symbols(), text.
length()};
5215template<
size_t N,
bool S, simstr::Allocatable A>
5217 return stream << std::wstring_view{from_w(text.
symbols()), text.
length()};
5227struct std::formatter<
simstr::simple_str<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5229 template<
typename FormatContext>
5231 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5240struct std::formatter<
simstr::simple_str_nt<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5242 template<
typename FormatContext>
5244 return std::formatter<std::basic_string_view<K>, K>::format({t.str, t.len}, fc);
5253struct std::formatter<
simstr::sstring<K>, K> : std::formatter<std::basic_string_view<K>, K> {
5255 template<
typename FormatContext>
5257 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5265template<
typename K,
size_t N,
bool S,
typename A>
5266struct std::formatter<
simstr::lstring<K, N, S, A>, K> : std::formatter<std::basic_string_view<K>, K> {
5268 template<
typename FormatContext>
5270 return std::formatter<std::basic_string_view<K>, K>::format({t.
symbols(), t.
length()}, fc);
5279struct std::formatter<
simstr::simple_str<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5281 template<
typename FormatContext>
5283 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5292struct std::formatter<
simstr::simple_str_nt<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5294 template<
typename FormatContext>
5296 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.str, t.len}, fc);
5305struct std::formatter<
simstr::sstring<char8_t>, char> : std::formatter<std::basic_string_view<char>, char> {
5307 template<
typename FormatContext>
5309 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5317template<
size_t N,
bool S,
typename A>
5318struct std::formatter<
simstr::lstring<char8_t, N, S, A>, char> : std::formatter<std::basic_string_view<char>, char> {
5320 template<
typename FormatContext>
5322 return std::formatter<std::basic_string_view<char>,
char>::format({(
const char*)t.
symbols(), t.
length()}, fc);
5331struct std::formatter<
simstr::simple_str<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5333 template<
typename FormatContext>
5335 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5344struct std::formatter<
simstr::simple_str_nt<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5346 template<
typename FormatContext>
5348 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.str, t.len}, fc);
5357struct std::formatter<
simstr::sstring<simstr::wchar_type>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5359 template<
typename FormatContext>
5361 return std::formatter<std::basic_string_view<wchar_t>,
wchar_t>::format({(
const wchar_t*)t.
symbols(), t.
length()}, fc);
5369template<
size_t N,
bool S,
typename A>
5370struct std::formatter<
simstr::lstring<simstr::wchar_type, N, S, A>, wchar_t> : std::formatter<std::basic_string_view<wchar_t>, wchar_t> {
5372 template<
typename FormatContext>
5374 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:4502
portion_store get_portion() const
Get a portion_store through which data can be sequentially retrieved into an external buffer.
Definition sstring.h:4687
constexpr size_t length() const noexcept
Length of the saved text.
Definition sstring.h:4567
my_type & operator<<(T data)
Adding a symbol.
Definition sstring.h:4561
void reset()
Resets the contents, but does not delete the first buffer in order to avoid allocation later.
Definition sstring.h:4571
void clear()
Clear the object, freeing all allocated buffers.
Definition sstring.h:4633
my_type & operator<<(const StrExprForType< K > auto &expr)
Adding a string expression.
Definition sstring.h:4537
bool is_continuous() const
Checks whether all text is located in one contiguous chunk in memory.
Definition sstring.h:4609
void out(const Op &o) const
Applies a functor to each stored buffer.
Definition sstring.h:4601
const auto & data() const
Get internal data buffers.
Definition sstring.h:4696
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:4626
Container for more efficient searching by string keys.
Definition sstring.h:4222
The mutable, owning string class. Contains an internal buffer for text of a given size.
Definition sstring.h:2717
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:3264
constexpr lstring(T &&value, Args &&... args)
String literal constructor.
Definition sstring.h:2990
my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:3135
constexpr void reset()
Makes the string empty and frees the external buffer, if there was one.
Definition sstring.h:3299
@ LocalCapacity
Definition sstring.h:2725
constexpr bool is_local() const noexcept
Find out whether a local or external buffer is used for characters.
Definition sstring.h:3255
my_type & operator=(my_type &&other) noexcept
Assignment operator by moving from a string of the same type.
Definition sstring.h:3078
constexpr size_t length() const noexcept
String length.
Definition sstring.h:3158
constexpr lstring(s_str other, Args &&... args)
A constructor from another string object.
Definition sstring.h:2857
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:2927
constexpr lstring(size_t repeat, s_str pattern, Args &&... args)
String repetition constructor.
Definition sstring.h:2872
constexpr lstring(const my_type &other)
Copy from another string of the same type.
Definition sstring.h:2946
constexpr lstring(const my_type &other, Args &&... args)
Copy from another string of the same type, but with a different allocator.
Definition sstring.h:2973
my_type & operator=(const StrExprForType< K > auto &expr)
String expression appending operator.
Definition sstring.h:3148
constexpr K * reserve_no_preserve(size_t newSize)
Definition sstring.h:3193
my_type & operator=(const my_type &other)
Copy assignment operator from a string of the same type.
Definition sstring.h:3061
constexpr bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:3170
lstring(const Op &op, Args &&... args)
A fill constructor using a functor (see str_mutable::fill).
Definition sstring.h:3032
constexpr K * set_size(size_t newSize)
Sets the size of the current string, allocating space if necessary.
Definition sstring.h:3238
constexpr lstring(size_t count, K pad, Args &&... args)
Character repetition constructor.
Definition sstring.h:2887
constexpr lstring(const StrExprForType< K > auto &expr, Args &&... args)
Constructor from a string expression.
Definition sstring.h:2906
constexpr const K * symbols() const noexcept
Pointer to constant characters.
Definition sstring.h:3162
constexpr void clear()
Makes a string empty without changing the string buffer.
Definition sstring.h:3295
my_type & operator=(simple_str< K > other)
Assignment operator from simple_str.
Definition sstring.h:3123
constexpr bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:3174
constexpr void shrink_to_fit()
Reduces the size of the external buffer to the smallest possible size to hold the string....
Definition sstring.h:3281
constexpr lstring(my_type &&other) noexcept
Constructor for moving from a string of the same type.
Definition sstring.h:3005
constexpr K * reserve(size_t newSize)
Allocate a buffer large enough to hold newSize characters plus a terminating null.
Definition sstring.h:3215
constexpr K * str() noexcept
Pointer to a string buffer.
Definition sstring.h:3166
constexpr size_t capacity() const noexcept
Current row buffer capacity.
Definition sstring.h:3178
constexpr lstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Create an empty object.
Definition sstring.h:2842
Immutable owning string class.
Definition sstring.h:3410
constexpr my_type & operator=(const lstring< K, N, forShared, A > &other)
Assignment operator to another string of type lstring.
Definition sstring.h:3754
constexpr bool empty() const noexcept
Whether the string is empty, for compatibility with std::string.
Definition sstring.h:3806
constexpr bool is_empty() const noexcept
Is the string empty?
Definition sstring.h:3802
sstring(s_str other, Args &&... args)
A constructor from another string object.
Definition sstring.h:3515
sstring(size_t count, K pad, Args &&... args)
Character repetition constructor.
Definition sstring.h:3545
constexpr const K * symbols() const noexcept
Pointer to characters in the string.
Definition sstring.h:3794
constexpr sstring(const my_type &other) noexcept
String copy constructor.
Definition sstring.h:3601
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:3836
constexpr my_type & operator=(T &&other)
String literal assignment operator.
Definition sstring.h:3742
sstring(size_t repeat, s_str pattern, Args &&... args)
String repetition constructor.
Definition sstring.h:3530
constexpr my_type & operator=(my_type other) noexcept
Assignment operator to another string of the same type.
Definition sstring.h:3718
static my_type printf(const K *pattern, T &&... args)
Get a string formatted with std::sprintf.
Definition sstring.h:3822
constexpr sstring(lstring< K, N, true, Allocator > &&src)
A move constructor from lstring with an sstring-compatible external buffer.
Definition sstring.h:3628
constexpr size_t length() const noexcept
string length.
Definition sstring.h:3798
constexpr sstring(my_type &&other) noexcept
Move constructor.
Definition sstring.h:3612
static my_type vformat(simple_str< K > fmtString, T &&... args)
Get a string formatted with std::vformat.
Definition sstring.h:3850
sstring(simple_str< O > init)
Initialization from a string source with a different character type. Converts via UTF.
Definition sstring.h:3693
constexpr my_type & operator=(simple_str< K > other)
Assignment operator to another string of a different type.
Definition sstring.h:3730
constexpr my_type & make_empty() noexcept
Make the string empty.
Definition sstring.h:3788
constexpr my_type & operator=(const StrExprForType< K > auto &expr)
String expression assignment operator.
Definition sstring.h:3779
sstring(T &&s, Args &&... args)
Initialize from a string literal.
Definition sstring.h:3680
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:3766
constexpr sstring(const StrExprForType< K > auto &expr, Args &&... args)
Constructor from a string expression.
Definition sstring.h:3564
sstring(Args &&... args) noexcept(std::is_nothrow_constructible_v< allocator_t, Args... >)
Constructor for the empty string.
Definition sstring.h:3500
constexpr ~sstring()
String destructor.
Definition sstring.h:3592
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:3585
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:1465
Impl & insert(size_t to, const A &expr)
Insert a string expression at the specified position.
Definition sstring.h:2005
Impl & operator<<=(const Op &fillFunction)
Fills a string with the fill method after the end of the string.
Definition sstring.h:2279
Impl & append(const A &expr)
Add a string expression to the end of the string.
Definition sstring.h:1889
Impl & operator<<(const Op &fillFunction)
Calls the passed functor, passing a reference to itself.
Definition sstring.h:2292
Impl & trim(str_piece pattern)
Remove characters included in the passed string at the beginning and end of the string.
Definition sstring.h:1699
Impl & upper_only_ascii()
Convert ASCII characters to uppercase.
Definition sstring.h:1763
Impl & lower_only_ascii()
Convert ASCII characters to lowercase.
Definition sstring.h:1778
Impl & trim_left()
Remove whitespace at the beginning of a string.
Definition sstring.h:1601
Impl & append_printf(const K *format, T &&... args)
Appends sprintf formatted output to the end of the string.
Definition sstring.h:2381
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:1688
Impl & trim_left(str_piece pattern)
Remove characters included in the passed string at the beginning of the string.
Definition sstring.h:1710
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:1662
Impl & prepend(str_piece other)
Add another string to the beginning of the string.
Definition sstring.h:2029
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:2519
my_type & format(const FmtString< fmt_type, T... > &pattern, T &&... args)
Definition sstring.h:2503
Impl & printf(const K *format, T &&... args)
Formats a string using sprintf.
Definition sstring.h:2365
Impl & with(const Op &fillFunction, Args &&... args)
Call a functor with a string and passed arguments.
Definition sstring.h:2601
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:2587
Impl & operator<<(const Op &fillFunction)
Fills a string with the fill method from position zero.
Definition sstring.h:2266
Impl & vformat(str_piece format, T &&... args)
Formats a string using std::vformat.
Definition sstring.h:2535
Impl & change(size_t from, size_t len, const A &expr)
Replace a piece of string with a string expression.
Definition sstring.h:1978
Impl & fill(size_t from, const Op &fillFunction)
Fill a string buffer using a functor.
Definition sstring.h:2238
Impl & change(size_t from, size_t len, str_piece other)
Replace a piece of string with another string.
Definition sstring.h:1962
Impl & remove(size_t from, size_t len)
Remove part of a string.
Definition sstring.h:2018
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:1675
Impl & trim_left(T &&pattern)
Remove characters included in a string literal at the beginning of the string.
Definition sstring.h:1636
Impl & trim_right(T &&pattern)
Remove characters included in a string literal at the end of the string.
Definition sstring.h:1649
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:1754
Impl & append_in(size_t pos, str_piece other)
Add another string starting at the given position.
Definition sstring.h:1929
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:2468
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:1743
Impl & insert(size_t to, str_piece other)
Insert a string at the specified position.
Definition sstring.h:1991
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:2569
Impl & printf_from(size_t from, const K *format, T &&... args)
Appends sprintf formatted output starting at the specified position.
Definition sstring.h:2311
Impl & operator+=(str_piece other)
Add another string to the end of the string.
Definition sstring.h:1900
Impl & trim_right()
Remove whitespace from the end of a string.
Definition sstring.h:1610
Impl & append(str_piece other)
Add another string to the end of the string.
Definition sstring.h:1877
Impl & trim_right(str_piece pattern)
Remove characters included in the passed string from the end of the string.
Definition sstring.h:1721
Impl & trim_with_spaces(str_piece pattern)
Remove characters included in the passed string, as well as whitespace characters,...
Definition sstring.h:1732
K * str() noexcept
Get a pointer to the string buffer.
Definition sstring.h:1574
Impl & prepend(const A &expr)
Add a string expression to the beginning of a string.
Definition sstring.h:2041
Impl & trim()
Remove whitespace from the beginning and end of a string.
Definition sstring.h:1592
Impl & lower()
Convert first plane characters (<0xFFFF) to lowercase Unicode.
Definition sstring.h:1812
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:2058
Impl & upper()
Convert first plane characters (<0xFFFF) to uppercase Unicode.
Definition sstring.h:1797
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:2176
Impl & append_vformatted(str_piece format, T &&... args)
Appends std::vformat-formatted output to the end of the string.
Definition sstring.h:2551
Impl & append_in(size_t pos, const A &expr)
Add a string expression starting at the given position.
Definition sstring.h:1947
my_type & format_from(size_t from, const FmtString< fmt_type, T... > &format, T &&... args)
Definition sstring.h:2439
Impl & trim(T &&pattern)
Remove characters included in a string literal at the beginning and end of the string.
Definition sstring.h:1623
Impl & operator+=(const A &expr)
Add a string expression to the end of the string.
Definition sstring.h:1912
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:1028
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:1115
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:1309
constexpr void init_from_str_other(s_str other)
Initialization from another string object.
Definition sstring.h:1036
constexpr allocator_t & allocator()
Get the allocator.
Definition sstring.h:1005
constexpr void init_symb_repeat(size_t count, K pad)
Character repetition initialization.
Definition sstring.h:1072
constexpr void init_str_expr(const A &expr)
Initialization from a string expression.
Definition sstring.h:1093
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:1279
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:1326
constexpr void init_str_repeat(size_t repeat, s_str pattern)
String repetition initialization.
Definition sstring.h:1052
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:1292
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:1228
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:1347
constexpr s_str_nt to_nts(size_t from=0) const
Get simple_str_nt starting at the given character.
Definition sstring.h:1172
Concept of a memory management type.
Definition sstring.h:1377
Concept of a memory management type.
Definition sstring.h:1357
Concept of a memory management type.
Definition sstring.h:1367
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:953
A type concept that can modify a stored string.
Definition sstring.h:946
A type concept that can store a string.
Definition sstring.h:936
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:4778
hashStrMap< ubs, T, str_exact, A > hashStrMapB
Type of hash dictionary for char8_t strings, case sensitive search.
Definition sstring.h:4732
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:4765
hashStrMap< u16s, T, str_exact, A > hashStrMapU
Hash dictionary type for char16_t strings, case sensitive search.
Definition sstring.h:4772
hashStrMap< u8s, T, str_exact, A > hashStrMapA
Type of hash dictionary for char strings, case sensitive search.
Definition sstring.h:4713
hashStrMap< u32s, T, str_exact, A > hashStrMapUU
Hash dictionary type for char32_t strings, case sensitive search.
Definition sstring.h:4791
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:4744
hashStrMap< wchar_t, T, str_eqlia, A > hashStrMapWIA
Hash dictionary type for wchar_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4758
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:4803
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:839
hashStrMap< ubs, T, str_eqlia, A > hashStrMapBIA
Type of hash dictionary for char8_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4738
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:4725
hashStrMap< wchar_t, T, str_exact, A > hashStrMapW
Hash dictionary type for wchar_t strings, case sensitive search.
Definition sstring.h:4751
hashStrMap< u32s, T, str_eqlia, A > hashStrMapUUIA
Hash dictionary type for char32_t strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4797
hashStrMap< u8s, T, str_eqlia, A > hashStrMapAIA
Type of hash dictionary for char strings, case-insensitive lookup for ASCII characters.
Definition sstring.h:4719
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:4784
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:4643
bool is_end()
Check that the data has not yet run out.
Definition sstring.h:4650
size_t store(K *buffer, size_t size)
Save the next portion of data to the buffer.
Definition sstring.h:4663
Generate a string based on the original one, replacing all ASCII uppercase letters (A-Z) with lowerca...
Definition strexpr.h:6945
Generate a string based on the original one, replacing all ASCII lowercase letters (a-z) with upperca...
Definition strexpr.h:6922
Generates a string based on the original one, replacing all lowercase letters of the first Unicode pl...
Definition sstring.h:900
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:808
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