20#if defined __has_builtin
21# if __has_builtin(__builtin_mul_overflow) && __has_builtin(__builtin_add_overflow)
22# define HAS_BUILTIN_OVERFLOW
27#define _no_unique_address msvc::no_unique_address
28#define decl_empty_bases __declspec(empty_bases)
30#define _no_unique_address no_unique_address
31#define decl_empty_bases
43#define SS_CONSTEVAL constexpr
45#define SS_CONSTEVAL consteval
56inline constexpr bool wchar_is_u16 =
sizeof(wchar_t) == 2;
58using wchar_type = std::conditional<wchar_is_u16, char16_t, char32_t>::type;
60inline wchar_type* to_w(
wchar_t* p) {
61 return (
reinterpret_cast<wchar_type*
>(p));
64inline const wchar_type* to_w(
const wchar_t* p) {
65 return (
reinterpret_cast<const wchar_type*
>(p));
68inline wchar_t* from_w(wchar_type* p) {
69 return (
reinterpret_cast<wchar_t*
>(p));
72inline const wchar_t* from_w(
const wchar_type* p) {
73 return (
reinterpret_cast<const wchar_t*
>(p));
82using uu8s = std::make_unsigned<u8s>::type;
84template<
typename T,
typename K = void,
typename... Types>
85struct is_one_of_type {
86 static constexpr bool value = std::is_same_v<T, K> || is_one_of_type<T, Types...>::value;
89struct is_one_of_type<T, void> : std::false_type {};
92constexpr bool is_one_of_char_v = is_one_of_type<K, u8s, ubs, wchar_t, u16s, u32s>::value;
95constexpr bool is_one_of_std_char_v = is_one_of_type<K, u8s, ubs, wchar_t, wchar_type>::value;
97template<
typename From>
98requires (is_one_of_std_char_v<From>)
99auto to_one_of_std_char(From* from) {
100 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
102 }
else if constexpr (std::is_same_v<From, ubs>) {
103 return reinterpret_cast<u8s*
>(from);
108template<
typename From>
109requires (is_one_of_std_char_v<From>)
110auto to_one_of_std_char(
const From* from) {
111 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
113 }
else if constexpr (std::is_same_v<From, ubs>) {
114 return reinterpret_cast<const u8s*
>(from);
135template<
typename K1,
typename K2>
136constexpr bool is_equal_str_type_v = is_one_of_char_v<K1> && is_one_of_char_v<K2> &&
sizeof(K1) ==
sizeof(K2);
184template<
typename T>
struct const_lit;
187template<
typename T,
size_t N>
188 requires(is_one_of_char_v<T>)
189struct const_lit<
const T(&)[N]> {
191 constexpr static size_t Count = N;
195concept is_const_lit_v =
requires {
196 typename const_lit<T>::symb_type;
201template<
typename K,
typename T>
struct const_lit_for;
203template<
typename K,
typename P,
size_t N>
205struct const_lit_for<K,
const P(&)[N]> {
206 constexpr static size_t Count = N;
209template<
typename K,
size_t N>
210class const_lit_to_array {
213 constexpr size_t find(K s)
const {
214 if constexpr (Idx < N) {
215 return s == symbols_[Idx] ? Idx : find<Idx + 1>(s);
221 constexpr bool exist(K s)
const {
222 if constexpr (Idx < N) {
223 return s == symbols_[Idx] || exist<Idx + 1>(s);
228 const K (&symbols_)[N + 1];
230 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
231 constexpr const_lit_to_array(T&& s)
234 constexpr bool contain(K s)
const {
237 constexpr size_t index_of(K s)
const {
263template<
typename A,
typename K>
265 { a.is_empty() } -> std::same_as<bool>;
266 { a.length() } -> std::convertible_to<size_t>;
267 { a.symbols() } -> std::same_as<const K*>;
268} && std::is_same_v<typename std::remove_cvref_t<A>::symb_type, K>;
401 typename A::symb_type;
402 { a.length() } -> std::convertible_to<size_t>;
403 { a.place(std::declval<typename A::symb_type*>()) } -> std::same_as<typename A::symb_type*>;
417template<
typename A,
typename K>
436template<
typename K,
typename Allocator, StrExpr A>
437constexpr std::basic_string<K, std::char_traits<K>, Allocator> to_std_string(
const A& expr) {
438 std::basic_string<K, std::char_traits<K>, Allocator> res;
439 if (
size_t l = expr.length()) {
440 auto fill = [&](K* ptr,
size_t size) ->
size_t {
441 expr.place((
typename A::symb_type*)ptr);
444 if constexpr (
requires { res.resize_and_overwrite(l, fill); }) {
445 res.resize_and_overwrite(l, fill);
446 }
else if constexpr (
requires{ res._Resize_and_overwrite(l, fill); }) {
448 res._Resize_and_overwrite(l, fill);
451 expr.place((
typename A::symb_type*)res.data());
467template<
typename Impl>
469 template<
typename P,
typename Allocator>
471 constexpr operator std::basic_string<P, std::char_traits<P>, Allocator>()
const {
472 return to_std_string<P, Allocator>(*
static_cast<const Impl*
>(
this));
491template<StrExpr A, StrExprForType<
typename A::symb_type> B>
493 using symb_type =
typename A::symb_type;
496 constexpr strexprjoin(
const A& a_,
const B& b_) : a(a_), b(b_){}
497 constexpr size_t length()
const noexcept {
498 return a.length() + b.length();
500 constexpr symb_type* place(symb_type* p)
const noexcept {
501 return (symb_type*)b.place((
typename B::symb_type*)a.place(p));
528template<StrExpr A, StrExprForType<
typename A::symb_type> B>
553template<StrExpr A, StrExprForType<
typename A::symb_type> B,
bool last = true>
555 using symb_type =
typename A::symb_type;
558 template<
typename... Args>
559 constexpr strexprjoin_c(
const A& a_, Args&&... args_) : a(a_), b(std::forward<Args>(args_)...) {}
560 constexpr size_t length()
const noexcept {
561 return a.length() + b.length();
563 constexpr symb_type* place(symb_type* p)
const noexcept {
564 if constexpr (last) {
565 return (symb_type*)b.place((
typename B::symb_type*)a.place(p));
567 return a.place((symb_type*)b.place((
typename B::symb_type*)p));
611 constexpr size_t length()
const noexcept {
614 constexpr symb_type* place(symb_type* p)
const noexcept {
651struct expr_char : expr_to_std_string<expr_char<K>>{
654 constexpr expr_char(K v) : value(v){}
655 constexpr size_t length() const noexcept {
658 constexpr symb_type* place(symb_type* p)
const noexcept {
676template<
typename K, StrExprForType<K> A>
696template<
typename K,
size_t N>
697struct expr_literal : expr_to_std_string<expr_literal<K, N>> {
699 const K (&str)[N + 1];
700 constexpr expr_literal(
const K (&str_)[N + 1]) : str(str_){}
702 constexpr size_t length() const noexcept {
705 constexpr symb_type* place(symb_type* p)
const noexcept {
706 if constexpr (N != 0)
707 std::char_traits<K>::copy(p, str, N);
764template<typename T, size_t N = const_lit<T>::Count>
765constexpr expr_literal<typename const_lit<T>::symb_type,
static_cast<size_t>(N - 1)>
e_t(T&& s) {
769template<
bool first,
typename K,
size_t N,
typename A>
770struct expr_literal_join : expr_to_std_string<expr_literal_join<first, K, N, A>> {
772 using atype =
typename A::symb_type;
773 const K (&str)[N + 1];
775 constexpr expr_literal_join(
const K (&str_)[N + 1],
const A& a_) : str(str_), a(a_){}
777 constexpr size_t length() const noexcept {
778 return N + a.length();
780 constexpr symb_type* place(symb_type* p)
const noexcept {
781 if constexpr (N != 0) {
782 if constexpr (first) {
783 std::char_traits<K>::copy(p, str, N);
784 return (symb_type*)a.place((atype*)(p + N));
786 p = (symb_type*)a.place((atype*)p);
787 std::char_traits<K>::copy(p, str, N);
804constexpr expr_literal_join<
false, P, (N - 1), A>
operator+(
const A& a, T&& s) {
816constexpr expr_literal_join<
true, P, (N - 1), A>
operator+(T&& s,
const A& a) {
833template<
typename K,
size_t N,
size_t S = ' '>
836 constexpr size_t length()
const noexcept {
839 constexpr symb_type* place(symb_type* p)
const noexcept {
840 if constexpr (N != 0)
841 std::char_traits<K>::assign(p, N,
static_cast<K
>(S));
898 constexpr expr_pad(
size_t len_, K s_) : len(len_), s(s_){}
899 constexpr size_t length()
const noexcept {
902 constexpr symb_type* place(symb_type* p)
const noexcept {
904 std::char_traits<K>::assign(p, len, s);
927template<
typename K,
size_t N>
928struct expr_repeat_lit : expr_to_std_string<expr_repeat_lit<K, N>> {
932 constexpr expr_repeat_lit(
size_t repeat,
const K (&s_)[N + 1]) : repeat_(repeat), s(s_){}
933 constexpr size_t length() const noexcept {
936 constexpr symb_type* place(symb_type* p)
const noexcept {
938 for (
size_t i = 0; i < repeat_; i++) {
939 std::char_traits<K>::copy(p, s, N);
949 using symb_type =
typename A::symb_type;
952 constexpr expr_repeat_expr(
size_t repeat,
const A& expr) : repeat_(repeat), expr_(expr){}
953 constexpr size_t length() const noexcept {
955 return repeat_ * expr_.length();
959 constexpr symb_type* place(symb_type* p)
const noexcept {
962 return expr_.place(p);
964 symb_type* start = p;
966 size_t len = size_t(p - start);
968 for (
size_t i = 1; i < repeat_; i++) {
969 std::char_traits<symb_type>::copy(p, start, len);
991template<typename T, typename K = const_lit<T>::symb_type,
size_t M = const_lit<T>::Count>
requires (M > 0)
992constexpr expr_repeat_lit<K, M - 1>
e_repeat(T&& s,
size_t l) {
1010constexpr expr_repeat_expr<A>
e_repeat(
const A& s,
size_t l) {
1027template<StrExpr A, StrExprForType<
typename A::symb_type> B>
1029 using symb_type =
typename A::symb_type;
1030 using my_type = expr_choice<A, B>;
1035 constexpr expr_choice(
const A& _a,
const B& _b,
bool _choice) : a(_a), b(_b), choice(_choice){}
1037 constexpr size_t length()
const noexcept {
1038 return choice ? a.length() : b.length();
1040 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1041 return choice ? a.place(ptr) : (symb_type*)b.place((
typename B::symb_type*)ptr);
1058 using symb_type =
typename A::symb_type;
1059 using my_type = expr_if<A>;
1062 constexpr expr_if(
const A& _a,
bool _choice) : a(_a), choice(_choice){}
1064 constexpr size_t length()
const noexcept {
1065 return choice ? a.length() : 0;
1067 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1068 return choice ? a.place(ptr) : ptr;
1118template<
typename L, StrExprForType<L> A,
size_t N,
bool Compare>
1120 using symb_type = L;
1121 const symb_type (&str)[N + 1];
1124 constexpr expr_choice_one_lit(
const symb_type (&_str)[N + 1],
const A& _a,
bool _choice) : str(_str), a(_a), choice(_choice){}
1126 constexpr size_t length()
const noexcept {
1127 return choice == Compare ? a.length() : N;
1129 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1130 if (choice == Compare) {
1131 return (L*)a.place((
typename A::symb_type*)ptr);
1133 if constexpr (N != 0) {
1134 std::char_traits<symb_type>::copy(ptr, str, N);
1184template<
typename K,
size_t N,
typename P,
size_t M>
1186 using symb_type = K;
1187 const K (&str_a)[N + 1];
1188 const P (&str_b)[M + 1];
1190 constexpr expr_choice_two_lit(
const K(&_str_a)[N + 1],
const P(&_str_b)[M + 1],
bool _choice)
1191 : str_a(_str_a), str_b(_str_b), choice(_choice){}
1193 constexpr size_t length()
const noexcept {
1194 return choice ? N : M;
1196 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1198 if constexpr (N != 0) {
1199 std::char_traits<symb_type>::copy(ptr, str_a, N);
1203 if constexpr (M != 0) {
1204 std::char_traits<symb_type>::copy(ptr, (
const K(&)[M + 1])str_b, M);
1239template<StrExpr A, StrExprForType<
typename A::symb_type> B>
1249template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1259template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1268template<typename T, typename L, typename K = typename const_lit<T>::symb_type,
typename P =
typename const_lit<L>::symb_type,
1269 size_t N = const_lit<T>::Count,
size_t M = const_lit_for<typename const_lit<T>::symb_type, L>::Count>
1272 return {str_a, str_b, c};
1326template<typename T, size_t N = const_lit<T>::Count>
1328 using K =
typename const_lit<T>::symb_type;
1329 const K empty[1] = {0};
1333template<
typename T>
struct is_std_string_source : std::false_type{};
1335template<
typename K,
typename A>
1336struct is_std_string_source<std::basic_string<K, std::char_traits<K>, A>> : std::true_type{};
1339struct is_std_string_source<std::basic_string_view<K, std::char_traits<K>>> : std::true_type{};
1342constexpr bool is_std_string_source_v = is_std_string_source<T>::value;
1345concept StdStrSource = is_std_string_source_v<std::remove_cvref_t<T>>;
1358 using symb_type = K;
1361 expr_stdstr(
const T& t) : t_(t){}
1363 constexpr size_t length()
const noexcept {
1366 constexpr symb_type* place(symb_type* p)
const noexcept {
1367 size_t s = t_.size();
1368 std::char_traits<K>::copy(p, (
const K*)t_.data(), s);
1378template<StdStrSource T, StrExprForType<
typename T::value_type> A>
1388template<StdStrSource T, StrExprForType<
typename T::value_type> A>
1394constexpr const size_t npos =
static_cast<size_t>(-1);
1398struct ch_traits : std::char_traits<K>{};
1401concept FromIntNumber =
1402 is_one_of_type<std::remove_cv_t<T>,
unsigned char, int, short, long,
long long, unsigned,
unsigned short,
unsigned long,
unsigned long long>::value;
1405concept ToIntNumber = FromIntNumber<T> || is_one_of_type<T, int8_t>::value;
1407template<
typename K,
bool I,
typename T>
1410 std::make_unsigned_t<T> val;
1411 need_sign(T t) : negate(t < 0), val(t < 0 ? std::make_unsigned_t<T>{} - t : t) {}
1412 void after(K*& ptr) {
1418template<
typename K,
typename T>
1419struct need_sign<K, false, T> {
1421 need_sign(T t) : val(t){}
1425template<
typename K,
typename T>
1426constexpr size_t fromInt(K* bufEnd, T val) {
1427 const char* twoDigit =
1428 "0001020304050607080910111213141516171819"
1429 "2021222324252627282930313233343536373839"
1430 "4041424344454647484950515253545556575859"
1431 "6061626364656667686970717273747576777879"
1432 "8081828384858687888990919293949596979899";
1434 need_sign<K, std::is_signed_v<T>, T> store(val);
1436 while (store.val >= 100) {
1437 const char* ptr = twoDigit + (store.val % 100) * 2;
1438 *--itr =
static_cast<K
>(ptr[1]);
1439 *--itr =
static_cast<K
>(ptr[0]);
1442 if (store.val < 10) {
1443 *--itr =
static_cast<K
>(
'0' + store.val);
1445 const char* ptr = twoDigit + store.val * 2;
1446 *--itr =
static_cast<K
>(ptr[1]);
1447 *--itr =
static_cast<K
>(ptr[0]);
1450 return size_t(bufEnd - itr);
1456template<
typename K,
typename T>
1458 using symb_type = K;
1459 using my_type = expr_num<K, T>;
1461 enum { bufSize = 24 };
1463 mutable K buf[bufSize];
1465 constexpr expr_num(T t) : value(t) {}
1466 constexpr expr_num(expr_num<K, T>&& t) : value(t.value) {}
1468 size_t length() const noexcept {
1469 value = (T)fromInt(buf + bufSize, value);
1470 return (
size_t)value;
1472 K* place(K* ptr)
const noexcept {
1473 size_t len = (size_t)value;
1474 ch_traits<K>::copy(ptr, buf + bufSize - len, len);
1490template<StrExpr A, FromIntNumber T>
1506template<StrExpr A, FromIntNumber T>
1526template<
typename K, FromIntNumber T>
1532struct expr_real : expr_to_std_string<expr_real<K>> {
1533 using symb_type = K;
1534 mutable u8s buf[40];
1537 constexpr expr_real(
double d) : v(d) {}
1538 constexpr expr_real(
float d) : v(d) {}
1540 size_t length() const noexcept {
1541 auto [ptr, ec] = std::to_chars(buf, buf + std::size(buf), v);
1542 l = ec != std::errc{} ? 0 : ptr - buf;
1545 K* place(K* ptr)
const noexcept {
1546 if constexpr (
sizeof(K) ==
sizeof(buf[0])) {
1547 ch_traits<K>::copy(ptr, (K*)buf, l);
1549 for (
size_t i = 0; i < l; i++) {
1568template<StrExpr A,
typename R>
1569 requires(std::is_same_v<R, double> || std::is_same_v<R, float>)
1570inline constexpr strexprjoin_c<A, expr_real<typename A::symb_type>>
operator+(
const A& a, R s) {
1585template<StrExpr A,
typename R>
1586 requires(std::is_same_v<R, double> || std::is_same_v<R, float>)
1587inline constexpr strexprjoin_c<A, expr_real<typename A::symb_type>,
false>
operator+(R s,
const A& a) {
1602template<
typename K>
requires is_one_of_char_v<K>
1603inline constexpr expr_real<K>
e_num(
double t) {
1607template<
typename K,
bool Ucase>
1608constexpr K hex_symbols[16] = {K(
'0'), K(
'1'), K(
'2'), K(
'3'), K(
'4'), K(
'5'), K(
'6'),
1609 K(
'7'), K(
'8'), K(
'9'), K(Ucase ?
'A' :
'a'), K(Ucase ?
'B' :
'b'), K(Ucase ?
'C' :
'c'),
1610 K(Ucase ?
'D' :
'd'), K(Ucase ?
'E' :
'e'), K(Ucase ?
'F' :
'f')};
1612template<
typename K, FromIntNumber Val,
bool All,
bool Ucase,
bool Ox>
1614 using symb_type = K;
1615 mutable need_sign<K, std::is_signed_v<Val>, Val> v_;
1616 mutable K buf_[
sizeof(Val) * 2];
1618 explicit constexpr expr_hex(Val v) : v_(v){}
1620 constexpr size_t length() const noexcept {
1621 K *ptr = buf_ + std::size(buf_);
1624 *--ptr = hex_symbols<K, Ucase>[v_.val & 0xF];
1628 *--ptr = hex_symbols<K, Ucase>[v_.val & 0xF];
1633 if constexpr (All) {
1634 if (
size_t need =
sizeof(Val) * 2 - l) {
1635 ch_traits<K>::assign(buf_, need, K(
'0'));
1637 l =
sizeof(Val) * 2;
1643 if constexpr (std::is_signed_v<Val>) {
1644 return l + (Ox ? 2 : 0) + (v_.negate ? 1 : 0);
1646 return l + (Ox ? 2 : 0);
1648 constexpr K* place(K* ptr)
const noexcept {
1649 if constexpr (std::is_signed_v<Val>) {
1658 if constexpr (All) {
1659 ch_traits<K>::copy(ptr, buf_,
sizeof(Val) * 2);
1660 return ptr +
sizeof(Val) * 2;
1662 ch_traits<K>::copy(ptr, buf_ + std::size(buf_) - v_.val, v_.val);
1663 return ptr + v_.val;
1668template<
typename Val,
bool All,
bool Ucase,
bool Ox>
1669requires std::is_unsigned_v<Val>
1670struct expr_hex_src {
1671 explicit constexpr expr_hex_src(Val v) : v_(v){}
1703template<
unsigned Flags = 0, FromIntNumber T>
1705 return expr_hex_src<T, (Flags &
HexFlags::Short) == 0, (Flags & HexFlags::Lcase) == 0, (Flags & HexFlags::No0x) == 0>{v};
1717template<StrExpr A,
typename Val,
bool All,
bool Ucase,
bool Ox>
1718constexpr strexprjoin_c<A, expr_hex<typename A::symb_type, Val, All, Ucase, Ox>,
true>
operator+(
const A& a,
const expr_hex_src<Val, All, Ucase, Ox>& b) {
1719 return {a, expr_hex<typename A::symb_type, Val, All, Ucase, Ox>{b.v_}};
1731template<StrExpr A,
typename Val,
bool All,
bool Ucase,
bool Ox>
1732constexpr strexprjoin_c<A, expr_hex<typename A::symb_type, Val, All, Ucase, Ox>,
false>
operator+(
const expr_hex_src<Val, All, Ucase, Ox>& b,
const A& a) {
1733 return {a, expr_hex<typename A::symb_type, Val, All, Ucase, Ox>{b.v_}};
1747 return {a, (uintptr_t)b};
1761 return {a, (uintptr_t)b};
1764template<
typename K, StrExprForType<K> A,
bool Left>
1765struct expr_fill : expr_to_std_string<expr_fill<K, A, Left>>{
1766 using symb_type = K;
1770 mutable size_t alen_{};
1771 constexpr expr_fill(K symbol,
size_t width,
const A& a) : symbol_(symbol), width_(width), a_(a){}
1773 constexpr size_t length() const noexcept {
1774 alen_ = a_.length();
1775 return std::max(alen_, width_);
1777 constexpr K* place(K* ptr)
const noexcept {
1778 if (alen_ >= width_) {
1779 return (K*)a_.place((
typename A::symb_type*)ptr);
1781 size_t w = width_ - alen_;
1782 if constexpr (Left) {
1783 ch_traits<K>::assign(ptr, w, symbol_);
1785 return (K*)a_.place((
typename A::symb_type*)ptr);
1787 ptr = (K*)a_.place((
typename A::symb_type*)ptr);
1788 ch_traits<K>::assign(ptr, w, symbol_);
1815template<StrExpr A,
typename K =
typename A::symb_type>
1816expr_fill<K, A, true>
e_fill_left(
const A& a,
size_t width, K symbol = K(
' ')) {
1817 return {symbol, width, a};
1841template<StrExpr A,
typename K =
typename A::symb_type>
1842expr_fill<K, A, false>
e_fill_right(
const A& a,
size_t width, K symbol = K(
' ')) {
1843 return {symbol, width, a};
1862template<
typename K,
typename T,
size_t I,
bool tail,
bool skip_empty>
1863struct expr_join : expr_to_std_string<expr_join<K, T, I, tail, skip_empty>> {
1864 using symb_type = K;
1865 using my_type = expr_join<K, T, I, tail, skip_empty>;
1869 constexpr expr_join(
const T& _s,
const K* _delim) : s(_s), delim(_delim){}
1871 constexpr size_t length() const noexcept {
1873 for (
const auto& t: s) {
1874 size_t len = t.length();
1875 if (len > 0 || !skip_empty) {
1876 if (I > 0 && l > 0) {
1882 return l + (tail && I > 0 && (l > 0 || (!skip_empty && s.size() > 0))? I : 0);
1884 constexpr K* place(K* ptr)
const noexcept {
1889 for (
const auto& t: s) {
1890 size_t copyLen = t.length();
1891 if (I > 0 && write != ptr && (copyLen || !skip_empty)) {
1892 ch_traits<K>::copy(write, delim, I);
1895 ch_traits<K>::copy(write, t.data(), copyLen);
1898 if (I > 0 && tail && (write != ptr || (!skip_empty && s.size() > 0))) {
1899 ch_traits<K>::copy(write, delim, I);
1919template<bool tail = false, bool skip_empty = false, typename L, typename K = typename const_lit<L>::symb_type,
size_t I = const_lit<L>::Count,
typename T>
1920inline constexpr auto e_join(
const T& s, L&& d) {
1921 return expr_join<K, T, I - 1, tail, skip_empty>{s, d};
1925concept is_const_pattern = N > 1 && N <= 17;
1927template<
typename K,
size_t I>
1929 constexpr static const size_t value = size_t(K(~0x7F)) << ((I - 1) *
sizeof(K) * 8) | _ascii_mask<K, I - 1>::value;
1933struct _ascii_mask<K, 0> {
1934 constexpr static const size_t value = 0;
1939 using uns = std::make_unsigned_t<K>;
1940 constexpr static const size_t WIDTH =
sizeof(size_t) /
sizeof(uns);
1941 constexpr static const size_t VALUE = _ascii_mask<uns, WIDTH>::value;
1945constexpr inline bool isAsciiUpper(K k) {
1946 return k >=
'A' && k <=
'Z';
1950constexpr inline bool isAsciiLower(K k) {
1951 return k >=
'a' && k <=
'z';
1955constexpr inline K makeAsciiLower(K k) {
1956 return isAsciiUpper(k) ? k | 0x20 : k;
1960constexpr inline K makeAsciiUpper(K k) {
1961 return isAsciiLower(k) ? k & ~0x20 : k;
1964enum TrimSides { TrimLeft = 1, TrimRight = 2, TrimAll = 3 };
1965template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces = false>
1966struct trim_operator;
1969struct digits_selector {
1970 using wider_type = uint16_t;
1974struct digits_selector<2> {
1975 using wider_type = uint32_t;
1979struct digits_selector<4> {
1980 using wider_type = uint64_t;
1994template<
bool CanNegate,
bool CheckOverflow,
typename T>
1995struct result_type_selector {
2000struct result_type_selector<true, false, T> {
2001 using type = std::make_unsigned_t<T>;
2004template<
unsigned Base>
2005constexpr unsigned digit_width() {
2024template<
typename T,
unsigned Base>
2025constexpr unsigned max_overflow_digits = (
sizeof(T) * CHAR_BIT) / digit_width<Base>();
2028struct convert_result {
2035 inline static const uint8_t NUMBERS[] = {
2036 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2037 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3,
2038 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
2039 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16,
2040 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, 255, 255,
2041 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2042 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2043 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2044 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
2045 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
2047 template<
typename K,
unsigned Base>
2048 static constexpr std::make_unsigned_t<K> toDigit(K s) {
2049 auto us =
static_cast<std::make_unsigned_t<K>
>(s);
2050 if constexpr (Base <= 10) {
2053 if constexpr (
sizeof(K) == 1) {
2056 return us < 256 ? NUMBERS[us] : us;
2061 template<
typename K, ToIntNumber T,
unsigned Base,
bool CheckOverflow>
2063 static constexpr convert_result<T> parse(
const K* start,
const K* current,
const K* end,
bool negate) {
2064 using u_type = std::make_unsigned_t<T>;
2065 #ifndef HAS_BUILTIN_OVERFLOW
2066 u_type maxMult = 0, maxAdd = 0;
2067 if constexpr (CheckOverflow) {
2068 maxMult = std::numeric_limits<u_type>::max() / Base;
2069 maxAdd = std::numeric_limits<u_type>::max() % Base;
2073 unsigned maxDigits = max_overflow_digits<u_type, Base>;
2075 const K* from = current;
2077 bool no_need_check_o_f = !CheckOverflow || end - current <= maxDigits;
2079 if (no_need_check_o_f) {
2081 const u_type digit = toDigit<K, Base>(*current);
2082 if (digit >= Base) {
2085 number = number * Base + digit;
2086 if (++current == end) {
2092 for (;maxDigits; maxDigits--) {
2093 const u_type digit = toDigit<K, Base>(*current);
2094 if (digit >= Base) {
2097 number = number * Base + digit;
2104 const u_type digit = toDigit<K, Base>(*current);
2105 if (digit >= Base) {
2108 #ifdef HAS_BUILTIN_OVERFLOW
2109 if (__builtin_mul_overflow(number, Base, &number) ||
2110 __builtin_add_overflow(number, digit, &number)) {
2112 if (number < maxMult || (number == maxMult && number < maxAdd)) {
2113 number = number * Base + digit;
2117 while(++current < end) {
2118 if (toDigit<K, Base>(*current) >= Base) {
2124 if (++current == end) {
2132 if constexpr (std::is_signed_v<T>) {
2133 result = negate ? 0 - number : number;
2134 if constexpr (CheckOverflow) {
2136 if (number > std::numeric_limits<T>::max() + (negate ? 1 : 0)) {
2147 return {result, error, size_t(current - start)};
2154 template<
typename K, ToIntNumber T,
unsigned Base = 0,
bool CheckOverflow = true,
bool SkipWs = true,
bool AllowSign = true>
2155 requires(Base == -1 || (Base < 37 && Base != 1))
2156 static constexpr convert_result<T> to_integer(
const K* start,
size_t len)
noexcept {
2157 const K *ptr = start, *end = ptr + len;
2158 bool negate =
false;
2159 if constexpr (SkipWs) {
2160 while (ptr < end && std::make_unsigned_t<K>(*ptr) <=
' ')
2164 if constexpr (std::is_signed_v<T>) {
2165 if constexpr (AllowSign) {
2170 }
else if (*ptr ==
'-') {
2182 }
else if constexpr (AllowSign) {
2191 if constexpr (Base == 0 || Base == -1) {
2195 if (*ptr ==
'x' || *ptr ==
'X') {
2196 return parse<K, T, 16, CheckOverflow>(start, ++ptr, end, negate);
2198 if constexpr (Base == -1) {
2199 if (*ptr ==
'b' || *ptr ==
'B') {
2200 return parse<K, T, 2, CheckOverflow>(start, ++ptr, end, negate);
2202 if (*ptr ==
'o' || *ptr ==
'O') {
2203 return parse<K, T, 8, CheckOverflow>(start, ++ptr, end, negate);
2206 return parse<K, T, 8, CheckOverflow>(start, --ptr, end, negate);
2210 return parse<K, T, 10, CheckOverflow>(start, ptr, end, negate);
2212 return parse<K, T, Base, CheckOverflow>(start, ptr, end, negate);
2218template<
typename K,
typename Impl>
2219class null_terminated {
2227 constexpr const K* c_str()
const {
return static_cast<const Impl*
>(
this)->symbols(); }
2230template<
typename K,
typename Impl,
bool Mutable>
class buffer_pointers;
2240template<
typename K,
typename Impl>
2241class buffer_pointers<K, Impl, false> {
2242 constexpr const Impl& d()
const {
return *
static_cast<const Impl*
>(
this); }
2250 constexpr const K* data()
const {
return d().symbols(); }
2257 constexpr const K* begin()
const {
return d().symbols(); }
2264 constexpr const K* end()
const {
return d().symbols() + d().length(); }
2271 constexpr const K* cbegin()
const {
return d().symbols(); }
2278 constexpr const K* cend()
const {
return d().symbols() + d().length(); }
2281template<
typename K,
typename Impl>
2282class buffer_pointers<K, Impl, true> :
public buffer_pointers<K, Impl, false> {
2283 constexpr Impl& d() {
return *
static_cast<Impl*
>(
this); }
2284 using base = buffer_pointers<K, Impl, false>;
2292 constexpr const K* data()
const {
return base::data(); }
2299 constexpr const K* begin()
const {
return base::begin(); }
2306 constexpr const K* end()
const {
return base::end(); }
2313 constexpr const K* cbegin()
const {
return base::cbegin(); }
2320 constexpr const K* cend()
const {
return base::cend(); }
2327 constexpr K* data() {
return d().str(); }
2334 constexpr K* begin() {
return d().str(); }
2341 constexpr K* end() {
return d().str() + d().length(); }
2350template<
typename K,
typename StrSrc>
2352 using str_t = StrSrc;
2357 constexpr SplitterBase(str_t text, str_t delim) : text_(text), delim_(delim) {}
2363 return text_.length() == str::npos;
2372 if (!text_.length()) {
2377 }
else if (text_.length() == str::npos) {
2378 return {
nullptr, 0};
2380 size_t pos = text_.find(delim_),
next = 0;
2381 if (pos == str::npos) {
2382 pos = text_.length();
2385 next = pos + delim_.length();
2387 str_t result{text_.str, pos};
2418template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
2419class str_src_algs :
public buffer_pointers<K, Impl, Mutable> {
2420 constexpr const Impl& d()
const noexcept {
2421 return *
static_cast<const Impl*
>(
this);
2423 constexpr size_t _len()
const noexcept {
2424 return d().length();
2426 constexpr const K* _str()
const noexcept {
2427 return d().symbols();
2429 constexpr bool _is_empty()
const noexcept {
2430 return d().is_empty();
2434 using symb_type = K;
2435 using str_piece = StrRef;
2436 using traits = ch_traits<K>;
2437 using uns_type = std::make_unsigned_t<K>;
2438 using my_type = Impl;
2439 using base = str_src_algs<K, StrRef, Impl, Mutable>;
2440 str_src_algs() =
default;
2454 constexpr K*
place(K* ptr)
const noexcept {
2455 size_t myLen = _len();
2456 traits::copy(ptr, _str(), myLen);
2470 size_t tlen = std::min(_len(), bufSize - 1);
2471 traits::copy(buffer, _str(), tlen);
2491 constexpr std::basic_string_view<D>
to_sv() const noexcept {
2492 return {(
const D*)_str(), _len()};
2501 constexpr operator std::basic_string_view<D, Traits>()
const {
2502 return {(
const D*)_str(), _len()};
2510 template<
typename D = K,
typename Traits = std::
char_traits<D>,
typename Allocator = std::allocator<D>>
requires is_equal_str_type_v<K, D>
2511 constexpr std::basic_string<D, Traits, Allocator>
to_string()
const {
2512 return {(
const D*)_str(), _len()};
2521 constexpr operator std::basic_string<D, Traits, Allocator>()
const {
2522 return {(
const D*)_str(), _len()};
2530 constexpr operator str_piece() const noexcept {
2531 return str_piece{_str(), _len()};
2539 constexpr str_piece
to_str() const noexcept {
2540 return {_str(), _len()};
2565 constexpr str_piece
operator()(ptrdiff_t from, ptrdiff_t len = 0) const noexcept {
2566 size_t myLen = _len(), idxStart = from >= 0 ? from : myLen > -from ? myLen + from : 0,
2567 idxEnd = len > 0 ? idxStart + len : myLen > -len ? myLen + len : 0;
2570 if (idxStart > idxEnd)
2572 return str_piece{_str() + idxStart, idxEnd - idxStart};
2584 constexpr str_piece
mid(
size_t from,
size_t len = -1) const noexcept {
2585 size_t myLen = _len(), idxStart = from, idxEnd = from > std::numeric_limits<size_t>::max() - len ? myLen : from + len;
2588 if (idxStart > idxEnd)
2590 return str_piece{_str() + idxStart, idxEnd - idxStart};
2606 constexpr str_piece
from_to(
size_t from,
size_t to)
const noexcept {
2607 return str_piece{_str() + from, to - from};
2626 constexpr K
at(ptrdiff_t idx)
const {
2627 return _str()[idx >= 0 ? idx : _len() + idx];
2631 constexpr int compare(
const K* text,
size_t len)
const {
2632 size_t myLen = _len();
2633 int cmp = traits::compare(_str(), text, std::min(myLen, len));
2634 return cmp == 0 ? (myLen > len ? 1 : myLen == len ? 0 : -1) : cmp;
2645 return compare(o.symbols(), o.length());
2656 size_t myLen = _len(), idx = 0;
2657 const K* ptr = _str();
2658 for (; idx < myLen; idx++) {
2659 uns_type s1 = (uns_type)text[idx];
2663 uns_type s2 = (uns_type)ptr[idx];
2666 }
else if (s1 > s2) {
2670 return text[idx] == 0 ? 0 : -1;
2673 constexpr bool equal(
const K* text,
size_t len)
const noexcept {
2674 return len == _len() && traits::compare(_str(), text, len) == 0;
2684 constexpr bool equal(str_piece other)
const noexcept {
2685 return equal(other.symbols(), other.length());
2696 return equal(other._str(), other._len());
2705 return compare(other._str(), other._len()) <=> 0;
2713 template<typename T, size_t N = const_lit_for<K, T>::Count>
2715 return N - 1 == _len() && traits::compare(_str(), other, N - 1) == 0;
2723 template<typename T, size_t N = const_lit_for<K, T>::Count>
2725 size_t myLen = _len();
2726 int cmp = traits::compare(_str(), other, std::min(myLen, N - 1));
2727 int res = cmp == 0 ? (myLen > N - 1 ? 1 : myLen == N - 1 ? 0 : -1) : cmp;
2733 constexpr int compare_ia(
const K* text,
size_t len)
const noexcept {
2735 return _is_empty() ? 0 : 1;
2736 size_t myLen = _len(), checkLen = std::min(myLen, len);
2737 const uns_type *ptr1 =
reinterpret_cast<const uns_type*
>(_str()), *ptr2 =
reinterpret_cast<const uns_type*
>(text);
2738 while (checkLen--) {
2739 uns_type s1 = *ptr1++, s2 = *ptr2++;
2742 s1 = makeAsciiLower(s1);
2743 s2 = makeAsciiLower(s2);
2749 return myLen == len ? 0 : myLen > len ? 1 : -1;
2760 return compare_ia(text.symbols(), text.length());
2771 constexpr bool equal_ia(str_piece text)
const noexcept {
2772 return text.length() == _len() && compare_ia(text.symbols(), text.length()) == 0;
2782 constexpr bool less_ia(str_piece text)
const noexcept {
2783 return compare_ia(text.symbols(), text.length()) < 0;
2786 constexpr size_t find(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
2787 size_t lenText = _len();
2790 if (!lenPattern || offset >= lenText || offset + lenPattern > lenText)
2793 const K *text = _str(), *last = text + lenText - lenPattern, first = pattern[0];
2795 for (
const K* fnd = text + offset;; ++fnd) {
2796 fnd = traits::find(fnd, last - fnd, first);
2799 if (traits::compare(fnd + 1, pattern, lenPattern) == 0)
2800 return static_cast<size_t>(fnd - text);
2813 constexpr size_t find(str_piece pattern,
size_t offset = 0) const noexcept {
2814 return find(pattern.symbols(), pattern.length(), offset);
2832 template<
typename Exc,
typename ... Args>
requires std::is_constructible_v<Exc, Args...>
2833 constexpr size_t find_or_throw(str_piece pattern,
size_t offset = 0, Args&& ... args)
const noexcept {
2834 if (
auto fnd = find(pattern.symbols(), pattern.length(), offset); fnd != str::npos) {
2837 throw Exc(std::forward<Args>(args)...);
2849 constexpr size_t find_end(str_piece pattern,
size_t offset = 0) const noexcept {
2850 size_t fnd = find(pattern.symbols(), pattern.length(), offset);
2851 return fnd == str::npos ? fnd : fnd + pattern.length();
2863 constexpr size_t find_or_all(str_piece pattern,
size_t offset = 0) const noexcept {
2864 auto fnd = find(pattern.symbols(), pattern.length(), offset);
2865 return fnd == str::npos ? _len() : fnd;
2878 auto fnd = find(pattern.symbols(), pattern.length(), offset);
2879 return fnd == str::npos ? _len() : fnd + pattern.length();
2882 constexpr size_t find_last(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
2883 if (lenPattern == 1)
2884 return find_last(pattern[0], offset);
2885 size_t lenText = std::min(_len(), offset);
2888 if (!lenPattern || lenPattern > lenText)
2892 const K *text = _str() + lenPattern, last = pattern[lenPattern];
2893 lenText -= lenPattern;
2895 if (text[--lenText] == last) {
2896 if (traits::compare(text + lenText - lenPattern, pattern, lenPattern) == 0) {
2913 constexpr size_t find_last(str_piece pattern,
size_t offset = -1) const noexcept {
2914 return find_last(pattern.symbols(), pattern.length(), offset);
2927 size_t fnd = find_last(pattern.symbols(), pattern.length(), offset);
2928 return fnd == str::npos ? fnd : fnd + pattern.length();
2941 auto fnd = find_last(pattern.symbols(), pattern.length(), offset);
2942 return fnd == str::npos ? _len() : fnd;
2955 size_t fnd = find_last(pattern.symbols(), pattern.length(), offset);
2956 return fnd == str::npos ? _len() : fnd + pattern.length();
2968 constexpr bool contains(str_piece pattern,
size_t offset = 0) const noexcept {
2969 return find(pattern, offset) != str::npos;
2981 constexpr size_t find(K s,
size_t offset = 0) const noexcept {
2982 size_t len = _len();
2984 const K *
str = _str(), *fnd = traits::find(
str + offset, len - offset, s);
2986 return static_cast<size_t>(fnd -
str);
3001 size_t len = _len();
3003 const K *
str = _str(), *fnd = traits::find(
str + offset, len - offset, s);
3005 return static_cast<size_t>(fnd -
str);
3010 template<
typename Op>
3011 constexpr void for_all_finded(
const Op& op,
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
3014 while (maxCount-- > 0) {
3015 size_t fnd = find(pattern, patternLen, offset);
3016 if (fnd == str::npos)
3019 offset = fnd + patternLen;
3034 template<
typename Op>
3035 constexpr void for_all_finded(
const Op& op, str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
3036 for_all_finded(op, pattern.symbols(), pattern.length(), offset, maxCount);
3039 template<
typename To = std::vector<
size_t>>
3040 constexpr To find_all(
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
3042 for_all_finded([&](
auto f) { result.emplace_back(f); }, pattern, patternLen, offset, maxCount);
3057 template<
typename To = std::vector<
size_t>>
3058 constexpr To
find_all(str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
3059 return find_all(pattern.symbols(), pattern.length(), offset, maxCount);
3061 template<
typename To = std::vector<
size_t>>
3062 constexpr void find_all_to(To& to,
const K* pattern,
size_t len,
size_t offset = 0,
size_t maxCount = 0)
const {
3063 return for_all_finded([&](
size_t pos) {
3064 to.emplace_back(pos);
3065 }, pattern, len, offset, maxCount);
3077 constexpr size_t find_last(K s,
size_t offset = -1) const noexcept {
3078 size_t len = std::min(_len(), offset);
3079 const K *text = _str();
3081 if (text[--len] == s)
3096 constexpr size_t find_first_of(str_piece pattern,
size_t offset = 0) const noexcept {
3097 return std::string_view{_str(), _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
3109 constexpr std::pair<size_t, size_t>
find_first_of_idx(str_piece pattern,
size_t offset = 0) const noexcept {
3110 const K* text = _str();
3111 size_t fnd = std::string_view{text, _len()}.find_first_of(std::string_view{pattern.str, pattern.len}, offset);
3112 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
3125 return std::string_view{_str(), _len()}.find_first_not_of(std::string_view{pattern.str, pattern.len}, offset);
3137 constexpr size_t find_last_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
3138 return std::string_view{_str(), _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
3150 constexpr std::pair<size_t, size_t>
find_last_of_idx(str_piece pattern,
size_t offset = str::npos)
const noexcept {
3151 const K* text = _str();
3152 size_t fnd = std::string_view{text, _len()}.find_last_of(std::string_view{pattern.str, pattern.len}, offset);
3153 return {fnd, fnd == std::string::npos ? fnd : pattern.find(text[fnd]) };
3165 constexpr size_t find_last_not_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
3166 return std::string_view{_str(), _len()}.find_last_not_of(std::string_view{pattern.str, pattern.len}, offset);
3178 constexpr my_type
substr(ptrdiff_t from, ptrdiff_t len = 0)
const {
3179 return my_type{d()(from, len)};
3191 constexpr my_type
str_mid(
size_t from,
size_t len = -1)
const {
3192 return my_type{d().mid(from, len)};
3222 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
3224 auto [res, err, _] = int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
3255 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
3256 constexpr convert_result<T>
to_int() const noexcept {
3257 return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
3265 template<
bool SkipWS = true,
bool AllowPlus = true>
requires (
sizeof(K) == 1)
3267 size_t len = _len();
3268 const K* ptr = _str();
3269 if constexpr (SkipWS) {
3270 while (len && uns_type(*ptr) <=
' ') {
3275 if constexpr (AllowPlus) {
3276 if (len && *ptr == K(
'+')) {
3285 if (std::from_chars((
const u8s*)ptr, (
const u8s*)ptr + len, d).ec == std::errc{}) {
3296 template<
bool SkipWS = true>
requires (
sizeof(K) == 1)
3298 size_t len = _len();
3299 const K* ptr = _str();
3300 if constexpr (SkipWS) {
3301 while (len && uns_type(*ptr) <=
' ') {
3308 if (std::from_chars(ptr, ptr + len, d, std::chars_format::hex).ec == std::errc{}) {
3322 template<ToIntNumber T>
3327 template<
typename T,
typename Op>
3328 constexpr T splitf(
const K* delimiter,
size_t lendelimiter,
const Op& beforeFunc,
size_t offset)
const {
3329 size_t mylen = _len();
3330 std::conditional_t<std::is_same_v<T, void>, char, T> results;
3331 str_piece me{_str(), mylen};
3332 for (
int i = 0;; i++) {
3333 size_t beginOfDelim = find(delimiter, lendelimiter, offset);
3334 if (beginOfDelim == str::npos) {
3335 str_piece last{me.symbols() + offset, me.length() - offset};
3336 if constexpr (std::is_invocable_v<Op, str_piece&>) {
3339 if constexpr (
requires { results.emplace_back(last); }) {
3340 if (last.is_same(me)) {
3343 results.emplace_back(d());
3345 results.emplace_back(last);
3347 }
else if constexpr (
requires { results.push_back(last); }) {
3348 if (last.is_same(me)) {
3351 results.push_back(d());
3353 results.push_back(last);
3355 }
else if constexpr (
requires {results[i] = last;} &&
requires{std::size(results);}) {
3356 if (i < std::size(results)) {
3357 if (last.is_same(me)) {
3367 str_piece piece{me.symbols() + offset, beginOfDelim - offset};
3368 if constexpr (std::is_invocable_v<Op, str_piece&>) {
3371 if constexpr (
requires { results.emplace_back(piece); }) {
3372 results.emplace_back(piece);
3373 }
else if constexpr (
requires { results.push_back(piece); }) {
3374 results.push_back(piece);
3375 }
else if constexpr (
requires { results[i] = piece; } &&
requires{std::size(results);}) {
3376 if (i < std::size(results)) {
3378 if (i == results.size() - 1) {
3383 offset = beginOfDelim + lendelimiter;
3385 if constexpr (!std::is_same_v<T, void>) {
3419 template<
typename T,
typename Op>
3420 constexpr T
splitf(str_piece delimiter,
const Op& beforeFunc,
size_t offset = 0)
const {
3421 return splitf<T>(delimiter.symbols(), delimiter.length(), beforeFunc, offset);
3435 template<
typename T>
3436 constexpr T
split(str_piece delimiter,
size_t offset = 0)
const {
3437 return splitf<T>(delimiter.symbols(), delimiter.length(), 0, offset);
3442 constexpr bool starts_with(
const K* prefix,
size_t l)
const noexcept {
3443 return _len() >= l && 0 == traits::compare(_str(), prefix, l);
3452 return starts_with(prefix.symbols(), prefix.length());
3455 constexpr bool starts_with_ia(
const K* prefix,
size_t len)
const noexcept {
3456 size_t myLen = _len();
3460 const K* ptr1 = _str();
3462 K s1 = *ptr1++, s2 = *prefix++;
3465 if (makeAsciiLower(s1) != makeAsciiLower(s2))
3477 return starts_with_ia(prefix.symbols(), prefix.length());
3482 constexpr bool prefix_in(
const K* text,
size_t len)
const noexcept {
3483 size_t myLen = _len();
3486 return !myLen || 0 == traits::compare(text, _str(), myLen);
3495 return prefix_in(text.symbols(), text.length());
3499 constexpr bool ends_with(
const K* suffix,
size_t len)
const noexcept {
3500 size_t myLen = _len();
3501 return len <= myLen && traits::compare(_str() + myLen - len, suffix, len) == 0;
3510 return ends_with(suffix.symbols(), suffix.length());
3514 constexpr bool ends_with_ia(
const K* suffix,
size_t len)
const noexcept {
3515 size_t myLen = _len();
3519 const K* ptr1 = _str() + myLen - len;
3521 K s1 = *ptr1++, s2 = *suffix++;
3524 if (makeAsciiLower(s1) != makeAsciiLower(s2))
3536 return ends_with_ia(suffix.symbols(), suffix.length());
3545 const int sl = ascii_mask<K>::WIDTH;
3546 const size_t mask = ascii_mask<K>::VALUE;
3547 size_t len = _len();
3548 const uns_type* ptr =
reinterpret_cast<const uns_type*
>(_str());
3549 if constexpr (sl > 1) {
3550 const size_t roundMask =
sizeof(size_t) - 1;
3551 while (len >= sl && (
reinterpret_cast<size_t>(ptr) & roundMask) != 0) {
3557 if (*
reinterpret_cast<const size_t*
>(ptr) & mask)
3577 template<
typename R = my_type>
3579 return R::upperred_only_ascii_from(d());
3589 template<
typename R = my_type>
3591 return R::lowered_only_ascii_from(d());
3609 template<
typename R = my_type>
3610 R
replaced(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0)
const {
3611 return R::replaced_from(d(), pattern, repl, offset, maxCount);
3614 template<StrType<K> From>
3615 constexpr static my_type make_trim_op(
const From& from,
const auto& opTrim) {
3616 str_piece sfrom = from, newPos = opTrim(sfrom);
3617 if (newPos.is_same(sfrom)) {
3621 return my_type{newPos};
3623 template<TrimS
ides S, StrType<K> From>
3624 constexpr static my_type trim_static(
const From& from) {
3625 return make_trim_op(from, trim_operator<S, K,
static_cast<size_t>(-1),
true>{});
3628 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count, StrType<K> From>
3629 requires is_const_pattern<N>
3630 constexpr static my_type trim_static(
const From& from, T&& pattern) {
3631 return make_trim_op(from, trim_operator<S, K, N - 1, withSpaces>{pattern});
3634 template<TrimS
ides S,
bool withSpaces, StrType<K> From>
3635 constexpr static my_type trim_static(
const From& from, str_piece pattern) {
3636 return make_trim_op(from, trim_operator<S, K, 0, withSpaces>{{pattern}});
3646 template<
typename R = str_piece>
3648 return R::template trim_static<TrimSides::TrimAll>(d());
3658 template<
typename R = str_piece>
3660 return R::template trim_static<TrimSides::TrimLeft>(d());
3670 template<
typename R = str_piece>
3672 return R::template trim_static<TrimSides::TrimRight>(d());
3684 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3685 requires is_const_pattern<N>
3687 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
3699 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3700 requires is_const_pattern<N>
3702 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
3714 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3715 requires is_const_pattern<N>
3717 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
3736 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3737 requires is_const_pattern<N>
3739 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
3755 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3756 requires is_const_pattern<N>
3758 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
3774 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3775 requires is_const_pattern<N>
3777 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
3792 template<
typename R = str_piece>
3794 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
3806 template<
typename R = str_piece>
3808 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
3820 template<
typename R = str_piece>
3822 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
3838 template<
typename R = str_piece>
3840 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
3856 template<
typename R = str_piece>
3858 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
3874 template<
typename R = str_piece>
3876 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
3894template<
size_t N>
requires (N > 1)
3895struct find_all_container {
3896 static constexpr size_t max_capacity = N;
3897 size_t positions_[N];
3900 void emplace_back(
size_t pos) {
3901 positions_[added_++] = pos;
3924struct str_src : str_src_algs<K, str_src<K>, str_src<K>, false> {
3925 using symb_type = K;
3926 using my_type = str_src<K>;
3928 const symb_type* str;
3931 str_src() =
default;
3936 template<typename T, size_t N = const_lit_for<K, T>::Count>
3937 constexpr str_src(T&& v) noexcept : str(v), len(N - 1) {}
3943 constexpr str_src(
const K* p,
size_t l) noexcept : str(p), len(l) {}
3945 template<StrType<K> T>
3946 constexpr str_src(T&& t) :
str(t.symbols()), len(t.length()){}
3952 template<
typename A>
3953 constexpr str_src(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : str(s.data()), len(s.length()) {}
3958 constexpr str_src(
const std::basic_string_view<K, std::char_traits<K>>& s) noexcept : str(s.data()), len(s.length()) {}
3971 constexpr const symb_type*
symbols() const noexcept {
3987 constexpr bool is_same(str_src<K> other)
const noexcept {
3988 return str == other.str && len == other.len;
3997 return str >= other.str && str + len <= other.str + other.len;
4060struct str_src_nt : str_src<K>, null_terminated<K, str_src_nt<K>> {
4061 using symb_type = K;
4062 using my_type = str_src_nt<K>;
4063 using base = str_src<K>;
4065 constexpr static const K empty_string[1] = {0};
4067 str_src_nt() =
default;
4084 template<
typename T>
requires std::is_same_v<std::remove_const_t<std::remove_pointer_t<std::remove_cvref_t<T>>>, K>
4087 base::str = base::len ? p : empty_string;
4093 template<typename T, size_t N = const_lit_for<K, T>::Count>
4094 constexpr str_src_nt(T&& v) noexcept : base(std::forward<T>(v)) {}
4100 constexpr str_src_nt(
const K* p,
size_t l) noexcept : base(p, l) {}
4102 template<StrType<K> T>
4105 base::len = t.length();
4111 template<
typename A>
4112 constexpr str_src_nt(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : base(s) {}
4114 static const my_type empty_str;
4124 if (from > base::len) {
4127 return {base::str + from, base::len - from};
4132inline const str_src_nt<K> str_src_nt<K>::empty_str{str_src_nt<K>::empty_string, 0};
4133template<
typename K>
struct simple_str_selector;
4135#ifndef IN_FULL_SIMSTR
4138using simple_str = str_src<K>;
4141struct simple_str_selector {
4142 using type = simple_str<K>;
4146using simple_str_nt = str_src_nt<K>;
4149using Splitter = SplitterBase<K, str_src<K>>;
4151using ssa = str_src<u8s>;
4152using ssb = str_src<ubs>;
4153using ssw = str_src<wchar_t>;
4154using ssu = str_src<u16s>;
4155using ssuu = str_src<u32s>;
4156using stra = str_src_nt<u8s>;
4157using strb = str_src_nt<ubs>;
4158using strw = str_src_nt<wchar_t>;
4159using stru = str_src_nt<u16s>;
4160using struu = str_src_nt<u32s>;
4162inline namespace literals {
4235template<
typename K,
bool withSpaces>
4236struct CheckSpaceTrim {
4237 constexpr bool is_trim_spaces(K s)
const {
4238 return s ==
' ' || (s >= 9 && s <= 13);
4242struct CheckSpaceTrim<K, false> {
4243 constexpr bool is_trim_spaces(K)
const {
4249struct CheckSymbolsTrim {
4251 constexpr bool is_trim_symbols(K s)
const {
4252 return symbols.len != 0 && str_src<K>::traits::find(symbols.str, symbols.len, s) !=
nullptr;
4256template<
typename K,
size_t N>
4257struct CheckConstSymbolsTrim {
4258 const const_lit_to_array<K, N> symbols;
4260 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
4261 constexpr CheckConstSymbolsTrim(T&& s) : symbols(std::forward<T>(s)) {}
4263 constexpr bool is_trim_symbols(K s)
const noexcept {
4264 return symbols.contain(s);
4269struct CheckConstSymbolsTrim<K, 0> {
4270 constexpr bool is_trim_symbols(K)
const {
4275template<
typename K,
size_t N>
4276struct SymbSelector {
4277 using type = CheckConstSymbolsTrim<K, N>;
4281struct SymbSelector<K, 0> {
4282 using type = CheckSymbolsTrim<K>;
4286struct SymbSelector<K, static_cast<size_t>(-1)> {
4287 using type = CheckConstSymbolsTrim<K, 0>;
4290template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces>
4291struct trim_operator : SymbSelector<K, N>::type, CheckSpaceTrim<K, withSpaces> {
4292 constexpr bool isTrim(K s)
const {
4293 return CheckSpaceTrim<K, withSpaces>::is_trim_spaces(s) || SymbSelector<K, N>::type::is_trim_symbols(s);
4295 constexpr str_src<K> operator()(str_src<K> from)
const {
4296 if constexpr ((S & TrimSides::TrimLeft) != 0) {
4298 if (isTrim(*from.str)) {
4305 if constexpr ((S & TrimSides::TrimRight) != 0) {
4306 const K* back = from.str + from.len - 1;
4308 if (isTrim(*back)) {
4319template<TrimS
ides S,
typename K>
4320using SimpleTrim = trim_operator<S, K, size_t(-1),
true>;
4322template<TrimSides S = TrimSides::TrimAll, bool withSpaces = false, typename K, typename T, size_t N = const_lit_for<K, T>::Count>
4323 requires is_const_pattern<N>
4324constexpr inline auto trimOp(T&& pattern) {
4325 return trim_operator<S, K, N - 1, withSpaces>{pattern};
4328template<TrimS
ides S = TrimS
ides::TrimAll,
bool withSpaces = false,
typename K>
4329constexpr inline auto trimOp(str_src<K> pattern) {
4330 return trim_operator<S, K, 0, withSpaces>{pattern};
4334concept StrSource = StdStrSource<T> ||
requires {
4335 typename std::remove_cvref_t<T>::symb_type;
4339struct to_src_str_base {
4340 using symb_type =
typename T::symb_type;
4341 static str_src<symb_type> get(
const T& s) {
4342 return {s.symbols(), s.length()};
4346struct to_src_str_base_none {};
4349struct to_src_str : std::conditional_t<StrSource<T>, to_src_str_base<T>, to_src_str_base_none> {
4352template<
typename K,
typename T,
typename A>
4353struct to_src_str<std::basic_string<K, T, A>> {
4354 using symb_type = K;
4355 static str_src<K> get(
const std::basic_string<K, T, A>& s) {
4356 return {s.data(), s.length()};
4360template<
typename K,
typename T>
4361struct to_src_str<std::basic_string_view<K, T>> {
4362 using symb_type = K;
4363 static str_src<K> get(
const std::basic_string_view<K, T>& s) {
4364 return {s.data(), s.length()};
4369using src_str_t = to_src_str<std::remove_cvref_t<T>>::symb_type;
4372auto get_str_src_from(T&& t) {
4373 return to_src_str<std::remove_cvref_t<T>>::get(std::forward<T>(t));
4376static constexpr size_t FIND_CACHE_SIZE = 16;
4378template<
typename K,
size_t N,
size_t L>
4379struct expr_replaces : expr_to_std_string<expr_replaces<K, N, L>> {
4380 using symb_type = K;
4381 using my_type = expr_replaces<K, N, L>;
4383 const K(&pattern)[N + 1];
4384 const K(&repl)[L + 1];
4385 mutable find_all_container<FIND_CACHE_SIZE> matches_;
4386 mutable size_t last_;
4388 constexpr expr_replaces(str_src<K> w,
const K(&p)[N + 1],
const K(&r)[L + 1]) : what(w), pattern(p), repl(r) {}
4390 constexpr size_t length()
const {
4391 size_t l = what.length();
4392 if constexpr (N == L) {
4395 what.find_all_to(matches_, pattern, N, 0, FIND_CACHE_SIZE);
4396 if (matches_.added_) {
4397 last_ = matches_.positions_[matches_.added_ - 1] + N;
4398 l += int(L - N) * matches_.added_;
4400 if (matches_.added_ == FIND_CACHE_SIZE) {
4402 size_t next = what.find(pattern, N, last_);
4403 if (next == str::npos) {
4412 matches_.added_ = -1;
4416 constexpr K* place(K* ptr)
const noexcept {
4417 if constexpr (N == L) {
4418 const K* from = what.symbols();
4419 for (
size_t start = 0; start < what.length();) {
4420 size_t next = what.find(pattern, N, start);
4421 if (next == str::npos) {
4422 next = what.length();
4424 size_t delta = next - start;
4425 ch_traits<K>::copy(ptr, from + start, delta);
4427 ch_traits<K>::copy(ptr, repl, L);
4433 if (matches_.added_ == 0) {
4434 return what.place(ptr);
4435 }
else if (matches_.added_ == -1) {
4439 const K* from = what.symbols();
4440 for (
size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
4441 ch_traits<K>::copy(ptr, from + start, offset - start);
4442 ptr += offset - start;
4443 ch_traits<K>::copy(ptr, repl, L);
4446 if (start >= last_) {
4447 size_t tail = what.length() - last_;
4448 ch_traits<K>::copy(ptr, from + last_, tail);
4452 offset = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern, N, start);
4472template<StrSource A,
typename K = src_str_t<A>,
typename T,
size_t N = const_lit_for<K, T>::Count,
typename X,
size_t L = const_lit_for<K, X>::Count>
4475 return expr_replaces<K, N - 1, L - 1>{get_str_src_from(std::forward<A>(w)), p, r};
4487 using symb_type = K;
4492 mutable find_all_container<FIND_CACHE_SIZE> matches_;
4493 mutable size_t last_;
4506 constexpr size_t length()
const {
4508 if (!plen || plen == rlen) {
4511 what.find_all_to(matches_, pattern.
symbols(), plen, 0, FIND_CACHE_SIZE);
4512 if (matches_.added_) {
4513 last_ = matches_.positions_[matches_.added_ - 1] + plen;
4514 l += int(rlen - plen) * matches_.added_;
4516 if (matches_.added_ == FIND_CACHE_SIZE) {
4518 size_t next = what.find(pattern.
symbols(), plen, last_);
4519 if (next == str::npos) {
4522 last_ = next + plen;
4528 matches_.added_ = -1;
4532 constexpr K* place(K* ptr)
const noexcept {
4535 const K* from = what.
symbols();
4536 for (
size_t start = 0; start < what.
length();) {
4537 size_t next = what.find(pattern, start);
4538 if (next == str::npos) {
4541 size_t delta = next - start;
4542 ch_traits<K>::copy(ptr, from + start, delta);
4544 ch_traits<K>::copy(ptr, repl.
symbols(), rlen);
4546 start = next + plen;
4550 if (matches_.added_ == 0) {
4551 return what.
place(ptr);
4552 }
else if (matches_.added_ == -1) {
4556 const K* from = what.
symbols();
4557 for (
size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
4558 ch_traits<K>::copy(ptr, from + start, offset - start);
4559 ptr += offset - start;
4560 ch_traits<K>::copy(ptr, repl.
symbols(), rlen);
4562 start = offset + plen;
4563 if (start >= last_) {
4564 size_t tail = what.
length() - start;
4565 ch_traits<K>::copy(ptr, from + start, tail);
4569 offset = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern.
symbols(), plen, start);
4591template<
typename K, StrExprForType<K> E>
4593 using symb_type = K;
4597 mutable size_t replLen;
4598 mutable find_all_container<FIND_CACHE_SIZE> matches_;
4599 mutable size_t last_;
4613 constexpr size_t length()
const {
4618 matches_.positions_[0] = what.find(pattern);
4619 if (matches_.positions_[0] == -1) {
4623 matches_.added_ = 1;
4625 replLen = expr.length();
4626 if (replLen == plen) {
4630 what.find_all_to(matches_, pattern.
symbols(), plen, matches_.positions_[0] + plen, FIND_CACHE_SIZE - 1);
4632 last_ = matches_.positions_[matches_.added_ - 1] + plen;
4633 l += int(replLen - plen) * matches_.added_;
4635 if (matches_.added_ == FIND_CACHE_SIZE) {
4637 size_t next = what.find(pattern.
symbols(), plen, last_);
4638 if (next == str::npos) {
4641 last_ = next + plen;
4642 l += replLen - plen;
4646 matches_.added_ = -1;
4650 constexpr K* place(K* ptr)
const noexcept {
4651 if (matches_.added_ == 0) {
4653 return what.
place(ptr);
4654 }
else if (matches_.added_ == -1) {
4658 size_t plen = pattern.
length();
4659 const K* from = what.
symbols();
4660 ch_traits<K>::copy(ptr, from, matches_.positions_[0]);
4661 ptr += matches_.positions_[0];
4662 const K* repl = ptr;
4663 expr.
place((
typename E::symb_type*)ptr);
4665 size_t start = matches_.positions_[0] + plen;
4667 if (plen == replLen) {
4669 size_t next = what.find(pattern, start);
4670 if (next == str::npos) {
4673 size_t delta = next - start;
4674 ch_traits<K>::copy(ptr, from + start, delta);
4676 ch_traits<K>::copy(ptr, repl, replLen);
4678 start = next + plen;
4681 for (
size_t idx = 1;;) {
4682 if (start >= last_) {
4685 size_t next = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern, start);
4686 size_t delta = next - start;
4687 ch_traits<K>::copy(ptr, from + start, delta);
4689 ch_traits<K>::copy(ptr, repl, replLen);
4691 start = next + plen;
4694 size_t tail = what.
length() - start;
4695 ch_traits<K>::copy(ptr, from + start, tail);
4713template<StrSource A,
typename K = src_str_t<A>,
typename T,
typename X>
4714 requires (std::is_constructible_v<str_src<K>, T> && std::is_constructible_v<str_src<K>, X> && (!is_const_lit_v<T> || !is_const_lit_v<X>))
4718 return expr_replaced<K>{get_str_src_from(std::forward<A>(w)), pattern, repl};
4734template<StrSource A,
typename K = src_str_t<A>,
typename T, StrExprForType<K> E>
4735 requires std::is_constructible_v<str_src<K>, T>
4736constexpr auto e_repl(A&& w, T&& p,
const E& expr) {
4741template<
bool UseVectorForReplace>
4742struct replace_search_result_store {
4744 std::pair<size_t, size_t> replaces_[16];
4748struct replace_search_result_store<true> : std::vector<std::pair<size_t, size_t>> {};
4752template<
typename K,
size_t N,
bool UseVectorForReplace>
4753struct expr_replace_const_symbols : expr_to_std_string<expr_replace_const_symbols<K, N, UseVectorForReplace>> {
4754 using symb_type = K;
4755 inline static const int BIT_SEARCH_TRESHHOLD = 4;
4756 const K pattern_[N];
4757 const str_src<K> source_;
4758 const str_src<K> replaces_[N];
4760 mutable replace_search_result_store<UseVectorForReplace> search_results_;
4762 [[_no_unique_address]]
4763 uu8s bit_mask_[N >= BIT_SEARCH_TRESHHOLD ? (
sizeof(K) == 1 ? 32 : 64) : 0]{};
4765 template<
typename ... Repl>
requires (
sizeof...(Repl) == N * 2)
4766 constexpr expr_replace_const_symbols(str_src<K> source, Repl&& ... repl) : expr_replace_const_symbols(0, source, std::forward<Repl>(repl)...) {}
4768 size_t length()
const {
4769 size_t l = source_.length();
4770 auto [fnd, num] = find_first_of(source_.str, source_.len);
4771 if (fnd == str::npos) {
4774 l += replaces_[num].len - 1;
4775 if constexpr (UseVectorForReplace) {
4776 search_results_.reserve((l >> 4) + 8);
4777 search_results_.emplace_back(fnd, num);
4778 for (
size_t start = fnd + 1;;) {
4779 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
4780 if (fnd == str::npos) {
4783 search_results_.emplace_back(fnd, idx);
4785 l += replaces_[idx].len - 1;
4788 const size_t max_store = std::size(search_results_.replaces_);
4789 search_results_.replaces_[0] = {fnd, num};
4790 search_results_.count_++;
4791 for (
size_t start = fnd + 1;;) {
4792 auto [found, idx] = find_first_of(source_.str, source_.len, start);
4793 if (found == str::npos) {
4796 if (search_results_.count_ < max_store) {
4797 search_results_.replaces_[search_results_.count_] = {found, idx};
4799 l += replaces_[idx].len - 1;
4800 search_results_.count_++;
4806 K* place(K* ptr)
const noexcept {
4808 const K* text = source_.str;
4809 if constexpr (UseVectorForReplace) {
4810 for (
const auto& [pos, num] : search_results_) {
4811 size_t delta = pos - start;
4812 ch_traits<K>::copy(ptr, text + start, delta);
4814 ptr = replaces_[num].place(ptr);
4818 const size_t max_store = std::size(search_results_.replaces_);
4819 size_t founded = search_results_.count_;
4820 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
4821 const auto [pos, num] = search_results_.replaces_[idx];
4822 size_t delta = pos - start;
4823 ch_traits<K>::copy(ptr, text + start, delta);
4825 ptr = replaces_[num].place(ptr);
4828 if (founded > max_store) {
4829 founded -= max_store;
4831 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
4832 size_t delta = fnd - start;
4833 ch_traits<K>::copy(ptr, text + start, delta);
4835 ptr = replaces_[idx].place(ptr);
4840 size_t tail = source_.len - start;
4841 ch_traits<K>::copy(ptr, text + start, tail);
4846 template<
typename ... Repl>
4847 constexpr expr_replace_const_symbols(
int, str_src<K> source, K s, str_src<K> r, Repl&&... repl) :
4848 expr_replace_const_symbols(0, source, std::forward<Repl>(repl)..., std::make_pair(s, r)){}
4850 template<
typename ... Repl>
requires (
sizeof...(Repl) == N)
4851 constexpr expr_replace_const_symbols(
int, str_src<K> source, Repl&&... repl) :
4852 source_(source), pattern_ {repl.first...}, replaces_{repl.second...}
4854 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
4855 for (
size_t idx = 0; idx < N; idx++) {
4856 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
4857 if constexpr (
sizeof(K) == 1) {
4858 bit_mask_[s >> 3] |= 1 << (s & 7);
4860 if (std::make_unsigned_t<const K>(pattern_[idx]) > 255) {
4861 bit_mask_[32 + (s >> 3)] |= 1 << (s & 7);
4863 bit_mask_[s >> 3] |= 1 << (s & 7);
4870 template<
size_t Idx>
4871 size_t index_of(K s)
const {
4872 if constexpr (Idx < N) {
4873 return pattern_[Idx] == s ? Idx : index_of<Idx + 1>(s);
4877 bool is_in_mask(uu8s s)
const {
4878 return (bit_mask_[s >> 3] & (1 <<(s & 7))) != 0;
4880 bool is_in_mask2(uu8s s)
const {
4881 return (bit_mask_[32 + (s >> 3)] & (1 <<(s & 7))) != 0;
4884 bool is_in_pattern(K s,
size_t& idx)
const {
4885 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
4886 if constexpr (
sizeof(K) == 1) {
4887 if (is_in_mask(s)) {
4888 idx = index_of<0>(s);
4892 if (std::make_unsigned_t<const K>(s) > 255) {
4893 if (is_in_mask2(s)) {
4894 return (idx = index_of<0>(s)) != -1;
4897 if (is_in_mask(s)) {
4898 idx = index_of<0>(s);
4906 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
4907 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
4909 while (offset < len) {
4910 if (is_in_pattern(text[offset], idx)) {
4911 return {offset, idx};
4916 while (offset < len) {
4917 if (
size_t idx = index_of<0>(text[offset]); idx != -1) {
4918 return {offset, idx};
4966template<
bool UseVector = false, StrSource A,
typename K = src_str_t<A>,
typename ... Repl>
4967 requires (
sizeof...(Repl) % 2 == 0)
4969 return expr_replace_const_symbols<K,
sizeof...(Repl) / 2, UseVector>(get_str_src_from(std::forward<A>(src)), std::forward<Repl>(other)...);
5011template<
typename K,
bool UseVectorForReplace = false>
5013 using symb_type = K;
5014 using str_t =
typename simple_str_selector<K>::type;
5015 inline static const int BIT_SEARCH_TRESHHOLD = 4;
5018 const std::vector<std::pair<K, str_t>>& replaces_;
5020 std::basic_string<K, ch_traits<K>, std::allocator<K>> pattern_;
5022 mutable replace_search_result_store<UseVectorForReplace> search_results_;
5024 uu8s bit_mask_[
sizeof(K) == 1 ? 32 : 64]{};
5053 : source_(source), replaces_(repl)
5055 size_t pattern_len = replaces_.size();
5056 pattern_.resize(pattern_len);
5057 K* pattern = pattern_.data();
5059 for (
size_t idx = 0; idx < replaces_.size(); idx++) {
5060 *pattern++ = replaces_[idx].first;
5063 if (pattern_len >= BIT_SEARCH_TRESHHOLD) {
5064 for (
size_t idx = 0; idx < pattern_len; idx++) {
5065 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
5066 if constexpr (
sizeof(K) == 1) {
5067 bit_mask_[s >> 3] |= (1 << (s & 7));
5069 if (std::make_unsigned_t<K>(pattern_[idx]) > 255) {
5070 bit_mask_[32 + (s >> 3)] |= (1 << (s & 7));
5072 bit_mask_[s >> 3] |= (1 << (s & 7));
5079 size_t length()
const {
5080 size_t l = source_.
length();
5081 auto [fnd, num] = find_first_of(source_.str, source_.len);
5082 if (fnd == str::npos) {
5085 l += replaces_[num].second.len - 1;
5086 if constexpr (UseVectorForReplace) {
5087 search_results_.reserve((l >> 4) + 8);
5088 search_results_.emplace_back(fnd, num);
5089 for (
size_t start = fnd + 1;;) {
5090 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5091 if (fnd == str::npos) {
5094 search_results_.emplace_back(fnd, idx);
5096 l += replaces_[idx].second.len - 1;
5099 const size_t max_store = std::size(search_results_.replaces_);
5100 search_results_.replaces_[0] = {fnd, num};
5101 search_results_.count_++;
5102 for (
size_t start = fnd + 1;;) {
5103 auto [found, idx] = find_first_of(source_.str, source_.len, start);
5104 if (found == str::npos) {
5107 if (search_results_.count_ < max_store) {
5108 search_results_.replaces_[search_results_.count_] = {found, idx};
5110 l += replaces_[idx].second.len - 1;
5111 search_results_.count_++;
5117 K* place(K* ptr)
const noexcept {
5119 const K* text = source_.str;
5120 if constexpr (UseVectorForReplace) {
5121 for (
const auto& [pos, num] : search_results_) {
5122 size_t delta = pos - start;
5123 ch_traits<K>::copy(ptr, text + start, delta);
5125 ptr = replaces_[num].second.place(ptr);
5129 const size_t max_store = std::size(search_results_.replaces_);
5130 size_t founded = search_results_.count_;
5131 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
5132 const auto [pos, num] = search_results_.replaces_[idx];
5133 size_t delta = pos - start;
5134 ch_traits<K>::copy(ptr, text + start, delta);
5136 ptr = replaces_[num].second.place(ptr);
5139 if (founded > max_store) {
5140 founded -= max_store;
5142 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5143 size_t delta = fnd - start;
5144 ch_traits<K>::copy(ptr, text + start, delta);
5146 ptr = replaces_[idx].second.place(ptr);
5151 size_t tail = source_.len - start;
5152 ch_traits<K>::copy(ptr, text + start, tail);
5157 size_t index_of(K s)
const {
5158 return pattern_.find(s);
5161 bool is_in_mask(uu8s s)
const {
5162 return (bit_mask_[s >> 3] & (1 << (s & 7))) != 0;
5164 bool is_in_mask2(uu8s s)
const {
5165 return (bit_mask_[32 + (s >> 3)] & (1 << (s & 7))) != 0;
5168 bool is_in_pattern(K s,
size_t& idx)
const {
5169 if constexpr (
sizeof(K) == 1) {
5170 if (is_in_mask(s)) {
5175 if (std::make_unsigned_t<const K>(s) > 255) {
5176 if (is_in_mask2(s)) {
5177 return (idx = index_of(s)) != -1;
5180 if (is_in_mask(s)) {
5189 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
5190 size_t pl = pattern_.length();
5191 if (pl >= BIT_SEARCH_TRESHHOLD) {
5193 while (offset < len) {
5194 if (is_in_pattern(text[offset], idx)) {
5195 return {offset, idx};
5200 while (offset < len) {
5201 if (
size_t idx = index_of(text[offset]); idx != -1) {
5202 return {offset, idx};
5249template<
typename K,
typename A, StrExprForType<K> E>
5250std::basic_string<K, std::char_traits<K>, A>&
change(std::basic_string<K, std::char_traits<K>, A>&
str,
size_t from,
size_t count,
const E& expr) {
5251 size_t expr_length = expr.length();
5253 str.erase(from, count);
5256 size_t str_length =
str.length();
5257 if (from > str_length) {
5260 if (from + count > str_length) {
5261 count = str_length - from;
5263 size_t new_length = str_length - count + expr_length;
5264 size_t tail_length = str_length - count - from;
5266 if (new_length <= str_length) {
5267 K* data =
str.data();
5268 expr.place((
typename E::symb_type*)data + from);
5269 if (expr_length < count) {
5271 std::char_traits<K>::move(data + from + expr_length, data + from + count, tail_length);
5273 str.resize(new_length);
5276 auto fill = [&](K* data, size_t) ->
size_t {
5278 std::char_traits<K>::move(data + from + expr_length, data + from + count, tail_length);
5280 expr.place((
typename E::symb_type*)data + from);
5283 if constexpr (
requires{
str.resize_and_overwrite(new_length, fill);}) {
5284 str.resize_and_overwrite(new_length, fill);
5285 }
else if constexpr (
requires{
str._Resize_and_overwrite(new_length, fill);}) {
5286 str._Resize_and_overwrite(new_length, fill);
5288 str.resize(new_length);
5289 fill(
str.data(), 0);
5322template<
typename K,
typename A, StrExprForType<K> E>
5323std::basic_string<K, std::char_traits<K>, A>&
append(std::basic_string<K, std::char_traits<K>, A>&
str,
const E& expr) {
5355template<
typename K,
typename A, StrExprForType<K> E>
5356std::basic_string<K, std::char_traits<K>, A>&
prepend(std::basic_string<K, std::char_traits<K>, A>&
str,
const E& expr) {
5390template<
typename K,
typename A, StrExprForType<K> E>
5391std::basic_string<K, std::char_traits<K>, A>&
insert(std::basic_string<K, std::char_traits<K>, A>&
str,
size_t from,
const E& expr) {
5397template<
typename K,
typename A,
typename E>
5398struct replace_grow_helper {
5399 using my_type = std::basic_string<K, std::char_traits<K>, A>;
5401 replace_grow_helper(my_type& src,
str_src<K> p,
const K* r,
size_t rl,
size_t mc,
size_t d,
const E& e)
5402 :
str(src), source(src), pattern(p), repl(const_cast<K*>(r)), replLen(rl), maxCount(mc), delta(d), expr(e) {}
5405 const str_src<K> source;
5406 const str_src<K> pattern;
5408 const size_t replLen;
5415 K* reserve_for_copy{};
5416 size_t end_of_piece{};
5417 size_t total_length{};
5419 std::optional<my_type> dst;
5422 size_t found[16] = {offset};
5425 offset += pattern.len;
5428 for (; idx < std::size(found) && maxCount > 0; idx++, maxCount--) {
5429 found[idx] = source.find(pattern, offset);
5430 if (found[idx] == npos) {
5433 offset = found[idx] + pattern.len;
5436 if (idx == std::size(found) && maxCount > 0 && (offset = source.find(pattern, offset)) != str::npos) {
5441 if (!reserve_for_copy) {
5444 end_of_piece = source.length();
5445 total_length = end_of_piece + all_delta;
5447 if (total_length <= str.capacity()) {
5452 dst_str = &dst.emplace();
5454 auto fill = [
this](K* p, size_t) ->
size_t {
5455 reserve_for_copy = p;
5456 return total_length;
5458 if constexpr (
requires{dst_str->_Resize_and_overwrite(total_length, fill);}) {
5459 dst_str->_Resize_and_overwrite(total_length, fill);
5460 }
else if constexpr (
requires{dst_str->resize_and_overwrite(total_length, fill);}) {
5461 dst_str->resize_and_overwrite(total_length, fill);
5463 dst_str->resize(total_length);
5464 reserve_for_copy = dst_str->data();
5467 K* dst_start = reserve_for_copy;
5468 const K* src_start = str.c_str();
5470 size_t pos = found[idx] + pattern.len;
5471 size_t lenOfPiece = end_of_piece - pos;
5472 ch_traits<K>::move(dst_start + pos + all_delta, src_start + pos, lenOfPiece);
5473 if constexpr (std::is_same_v<E, int>) {
5474 ch_traits<K>::copy(dst_start + pos + all_delta - replLen, repl, replLen);
5477 repl = dst_start + pos + all_delta - replLen;
5480 ch_traits<K>::copy(dst_start + pos + all_delta - replLen, repl, replLen);
5484 end_of_piece = found[idx];
5486 if (!all_delta && reserve_for_copy != src_start) {
5487 ch_traits<K>::copy(dst_start, src_start, found[0]);
5488 str = std::move(*dst);
5529template<
typename K,
typename A, StrExprForType<K> E,
typename T>
5530requires (std::is_constructible_v<str_src<K>, T>)
5531std::basic_string<K, std::char_traits<K>, A>&
replace(std::basic_string<K, std::char_traits<K>, A>&
str, T&& pattern,
const E& repl,
size_t offset = 0,
size_t max_count = -1) {
5536 str_src<K> spattern{std::forward<T>(pattern)};
5537 offset = src.find(pattern, offset);
5538 if (offset == npos) {
5541 size_t replLen = repl.length();
5543 if (spattern.len == replLen) {
5546 K* ptr =
str.data();
5547 replStart = ptr + offset;
5548 repl.place(replStart);
5550 while (--max_count) {
5551 offset = src.find(spattern, offset + replLen);
5554 ch_traits<K>::copy(ptr + offset, replStart, replLen);
5556 }
else if (spattern.len > replLen) {
5559 K* ptr =
str.data();
5560 replStart = ptr + offset;
5561 repl.place(replStart);
5562 size_t posWrite = offset + replLen;
5563 offset += spattern.len;
5565 while (--max_count) {
5566 size_t idx = src.find(spattern, offset);
5569 size_t lenOfPiece = idx - offset;
5570 ch_traits<K>::move(ptr + posWrite, ptr + offset, lenOfPiece);
5571 posWrite += lenOfPiece;
5572 ch_traits<K>::copy(ptr + posWrite, replStart, replLen);
5573 posWrite += replLen;
5574 offset = idx + spattern.len;
5576 size_t tailLen = src.len - offset;
5577 ch_traits<K>::move(ptr + posWrite, ptr + offset, tailLen);
5578 str.resize(posWrite + tailLen);
5580 details::replace_grow_helper<K, A, E>(
str, spattern,
nullptr, replLen, max_count, replLen - spattern.len, repl).replace(offset);
5605template<
typename K,
typename A>
5606std::basic_string<K, std::char_traits<K>, A>&
replace(std::basic_string<K, std::char_traits<K>, A>&
str,
str_src<K> pattern,
str_src<K> repl,
size_t offset = 0,
size_t max_count = -1) {
5611 offset = src.find(pattern, offset);
5612 if (offset == npos) {
5615 if (pattern.len == repl.len) {
5618 K* ptr =
str.data();
5619 while (max_count--) {
5620 ch_traits<K>::copy(ptr + offset, repl.str, repl.len);
5621 offset = src.find(pattern, offset + repl.len);
5625 }
else if (pattern.len > repl.len) {
5628 K* ptr =
str.data();
5629 ch_traits<K>::copy(ptr + offset, repl.str, repl.len);
5630 size_t posWrite = offset + repl.len;
5631 offset += pattern.len;
5633 while (--max_count) {
5634 size_t idx = src.find(pattern, offset);
5637 size_t lenOfPiece = idx - offset;
5638 ch_traits<K>::move(ptr + posWrite, ptr + offset, lenOfPiece);
5639 posWrite += lenOfPiece;
5640 ch_traits<K>::copy(ptr + posWrite, repl.str, repl.len);
5641 posWrite += repl.len;
5642 offset = idx + pattern.len;
5644 size_t tailLen = src.len - offset;
5645 ch_traits<K>::move(ptr + posWrite, ptr + offset, tailLen);
5646 str.resize(posWrite + tailLen);
5648 details::replace_grow_helper<K, A, int>(
str, pattern, repl.str, repl.len, max_count, repl.len - pattern.len, 0).replace(offset);
5653template<
typename K,
typename A,
typename T,
typename M>
5654requires (std::is_constructible_v<str_src<K>, T> && std::is_constructible_v<str_src<K>, M>)
5655std::basic_string<K, std::char_traits<K>, A>& replace(std::basic_string<K, std::char_traits<K>, A>&
str, T&& pattern, M&& repl,
size_t offset = 0,
size_t max_count = -1) {
5656 return replace(
str,
str_src<K>{std::forward<T>(pattern)}, str_src<K>{std::forward<M>(repl)}, offset, max_count);
5683template<simstr::StdStrSource T>
5716template<
typename K,
typename A, simstr::StrExprForType<K> E>
5717std::basic_string<K, std::char_traits<K>, A>& operator |=(std::basic_string<K, std::char_traits<K>, A>& str,
const E& expr) {
5749template<
typename K,
typename A, simstr::StrExprForType<K> E>
5750std::basic_string<K, std::char_traits<K>, A>& operator ^=(std::basic_string<K, std::char_traits<K>, A>& str,
const E& expr) {
Class for sequentially obtaining substrings by a given delimiter.
Definition strexpr.h:2351
constexpr bool is_done() const
Find out if substrings are running out.
Definition strexpr.h:2362
constexpr str_t next()
Get the next substring.
Definition strexpr.h:2371
std::optional< double > to_double_hex() const noexcept
Convert string in hex form to double.
Definition strexpr.h:3297
constexpr size_t find_last(K s, size_t offset=-1) const noexcept
Find the last occurrence of a character in this string.
Definition strexpr.h:3077
R trimmed_right() const
Get a string with whitespace removed on the right.
Definition strexpr.h:3671
constexpr int compare_ia(str_piece text) const noexcept
Compare strings character by character and not case sensitive ASCII characters.
Definition strexpr.h:2759
constexpr int compare(str_piece o) const
Compare strings character by character.
Definition strexpr.h:2644
constexpr size_t find(K s, size_t offset=0) const noexcept
Find a character in this string.
Definition strexpr.h:2981
constexpr bool ends_with(str_piece suffix) const noexcept
Whether the string ends with the specified substring.
Definition strexpr.h:3509
R trimmed(str_piece pattern) const
Get a string with characters specified by another string removed, left and right.
Definition strexpr.h:3793
R trimmed_left(str_piece pattern) const
Get a string with characters specified by another string removed from the left.
Definition strexpr.h:3807
constexpr bool operator==(const base &other) const noexcept
Operator comparing strings for equality.
Definition strexpr.h:2695
constexpr std::basic_string_view< D > to_sv() const noexcept
Convert to std::basic_string_view.
Definition strexpr.h:2491
R trimmed_left() const
Get a string with whitespace removed on the left.
Definition strexpr.h:3659
constexpr size_t find_end_or_all(str_piece pattern, size_t offset=0) const noexcept
Find the end of the first occurrence of a substring in this string, or the end of a string.
Definition strexpr.h:2877
constexpr bool starts_with(str_piece prefix) const noexcept
Whether the string begins with the given substring.
Definition strexpr.h:3451
constexpr bool equal(str_piece other) const noexcept
String comparison for equality.
Definition strexpr.h:2684
void copy_to(K *buffer, size_t bufSize)
Copy the string to the specified buffer.
Definition strexpr.h:2469
constexpr size_t find_or_throw(str_piece pattern, size_t offset=0, Args &&... args) const noexcept
Find the beginning of the first occurrence of a substring in this string or throw an exception.
Definition strexpr.h:2833
constexpr T as_int() const noexcept
Convert a string to a number of the given type.
Definition strexpr.h:3223
constexpr bool less_ia(str_piece text) const noexcept
Whether a string is smaller than another string, character-by-character-insensitive,...
Definition strexpr.h:2782
constexpr T split(str_piece delimiter, size_t offset=0) const
Split a string into substrings using a given delimiter.
Definition strexpr.h:3436
constexpr str_piece mid(size_t from, size_t len=-1) const noexcept
Get part of a string as "string chunk".
Definition strexpr.h:2584
constexpr my_type substr(ptrdiff_t from, ptrdiff_t len=0) const
Get a substring. Works similarly to operator(), only the result is the same type as the method applie...
Definition strexpr.h:3178
R upperred_only_ascii() const
Get a copy of the string in uppercase ASCII characters.
Definition strexpr.h:3578
constexpr str_piece to_str() const noexcept
Convert itself to a "string chunk" that includes the entire string.
Definition strexpr.h:2539
constexpr str_piece from_to(size_t from, size_t to) const noexcept
Get the substring str_src from position from to position to (not including it).
Definition strexpr.h:2606
R replaced(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0) const
Get a copy of the string with occurrences of substrings replaced.
Definition strexpr.h:3610
constexpr int strcmp(const K *text) const
Compare with C-string character by character.
Definition strexpr.h:2655
constexpr bool ends_with_ia(str_piece suffix) const noexcept
Whether the string ends with the specified substring in a case-insensitive ASCII character.
Definition strexpr.h:3535
constexpr size_t find_first_not_of(str_piece pattern, size_t offset=0) const noexcept
Find the first occurrence of a character not from the given character set.
Definition strexpr.h:3124
constexpr size_t find_first_of(str_piece pattern, size_t offset=0) const noexcept
Find the first occurrence of a character from a given character set.
Definition strexpr.h:3096
constexpr size_t find_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Find the beginning of the last occurrence of a substring in this string or the end of the string.
Definition strexpr.h:2940
R trimmed_with_spaces(str_piece pattern) const
Get a string, removing characters specified by another string, as well as whitespace characters,...
Definition strexpr.h:3839
constexpr bool starts_with_ia(str_piece prefix) const noexcept
Whether the string begins with the given substring in a case-insensitive ASCII character.
Definition strexpr.h:3476
constexpr size_t find_last(str_piece pattern, size_t offset=-1) const noexcept
Find the beginning of the last occurrence of a substring in this string.
Definition strexpr.h:2913
constexpr size_t find_last_of(str_piece pattern, size_t offset=str::npos) const noexcept
Find the last occurrence of a character from a given character set.
Definition strexpr.h:3137
constexpr size_t find_or_all(K s, size_t offset=0) const noexcept
Find a character in this string or the end of a string.
Definition strexpr.h:3000
constexpr size_t find_last_not_of(str_piece pattern, size_t offset=str::npos) const noexcept
Find the last occurrence of a character not from the given character set.
Definition strexpr.h:3165
constexpr void for_all_finded(const Op &op, str_piece pattern, size_t offset=0, size_t maxCount=0) const
Call a functor on all found occurrences of a substring in this string.
Definition strexpr.h:3035
constexpr size_t find_end(str_piece pattern, size_t offset=0) const noexcept
Find the end of the occurrence of a substring in this string.
Definition strexpr.h:2849
constexpr bool operator!() const noexcept
Check for emptiness.
Definition strexpr.h:2613
R trimmed(T &&pattern) const
Get a string with the characters specified by the string literal removed from the left and right.
Definition strexpr.h:3686
constexpr R trimmed() const
Get a string with whitespace removed on the left and right.
Definition strexpr.h:3647
constexpr size_t size() const
The size of the string in characters.
Definition strexpr.h:2480
R trimmed_right(str_piece pattern) const
Get a string with characters specified by another string removed to the right.
Definition strexpr.h:3821
constexpr To find_all(str_piece pattern, size_t offset=0, size_t maxCount=0) const
Find all occurrences of a substring in this string.
Definition strexpr.h:3058
constexpr my_type str_mid(size_t from, size_t len=-1) const
Get part of a string with an object of the same type to which the method is applied,...
Definition strexpr.h:3191
constexpr size_t find_end_of_last(str_piece pattern, size_t offset=-1) const noexcept
Find the end of the last occurrence of a substring in this string.
Definition strexpr.h:2926
constexpr std::pair< size_t, size_t > find_first_of_idx(str_piece pattern, size_t offset=0) const noexcept
Find the first occurrence of a character from a given character set.
Definition strexpr.h:3109
constexpr bool is_ascii() const noexcept
Whether the string contains only ASCII characters.
Definition strexpr.h:3542
constexpr size_t find(str_piece pattern, size_t offset=0) const noexcept
Find the beginning of the first occurrence of a substring in this string.
Definition strexpr.h:2813
constexpr SplitterBase< K, str_piece > splitter(str_piece delimiter) const
Retrieve a Splitter object by the given splitter, which allows sequential get substrings using the ne...
Definition strexpr.h:3889
constexpr std::pair< size_t, size_t > find_last_of_idx(str_piece pattern, size_t offset=str::npos) const noexcept
Find the last occurrence of a character from a given character set.
Definition strexpr.h:3150
R trimmed_left(T &&pattern) const
Get a string with the characters specified by the string literal removed from the left.
Definition strexpr.h:3701
R trimmed_with_spaces(T &&pattern) const
Get a string with the characters specified by the string literal removed, as well as whitespace chara...
Definition strexpr.h:3738
std::optional< double > to_double() const noexcept
Convert string to double.
Definition strexpr.h:3266
constexpr size_t find_or_all(str_piece pattern, size_t offset=0) const noexcept
Find the beginning of the first occurrence of a substring in this string or the end of the string.
Definition strexpr.h:2863
constexpr bool operator==(T &&other) const noexcept
Operator for comparing a string and a string literal for equality.
Definition strexpr.h:2714
R trimmed_right_with_spaces(str_piece pattern) const
Get a string, removing characters specified by another string, as well as whitespace characters,...
Definition strexpr.h:3875
constexpr auto operator<=>(const base &other) const noexcept
String comparison operator.
Definition strexpr.h:2704
constexpr bool contains(str_piece pattern, size_t offset=0) const noexcept
Whether the string contains the specified substring.
Definition strexpr.h:2968
R trimmed_right(T &&pattern) const
Get a string with the characters specified by the string literal removed from the right.
Definition strexpr.h:3716
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len=0) const noexcept
Get part of a string as "str_src".
Definition strexpr.h:2565
constexpr K at(ptrdiff_t idx) const
Get the character at the given position.
Definition strexpr.h:2626
R lowered_only_ascii() const
Get a copy of the string in lowercase ASCII characters.
Definition strexpr.h:3590
R trimmed_right_with_spaces(T &&pattern) const
Get a string with the characters specified by the string literal removed, as well as whitespace chara...
Definition strexpr.h:3776
constexpr auto operator<=>(T &&other) const noexcept
Comparison operator between a string and a string literal.
Definition strexpr.h:2724
constexpr std::basic_string< D, Traits, Allocator > to_string() const
Convert to std::basic_string.
Definition strexpr.h:2511
constexpr T splitf(str_piece delimiter, const Op &beforeFunc, size_t offset=0) const
Split a string into parts at a given delimiter, possibly applying a functor to each substring.
Definition strexpr.h:3420
R trimmed_left_with_spaces(T &&pattern) const
Get a string with the characters specified by the string literal removed, as well as whitespace chara...
Definition strexpr.h:3757
constexpr size_t find_end_of_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Find the end of the last occurrence of a substring in this string, or the end of a string.
Definition strexpr.h:2954
constexpr bool prefix_in(str_piece text) const noexcept
Whether this string is the beginning of another string.
Definition strexpr.h:3494
R trimmed_left_with_spaces(str_piece pattern) const
Get a string, removing characters specified by another string, as well as whitespace characters,...
Definition strexpr.h:3857
constexpr K * place(K *ptr) const noexcept
Copy the string to the specified buffer.
Definition strexpr.h:2454
constexpr convert_result< T > to_int() const noexcept
Convert a string to a number of the given type.
Definition strexpr.h:3256
constexpr bool equal_ia(str_piece text) const noexcept
Whether a string is equal to another string, character-by-character-insensitive, of ASCII characters.
Definition strexpr.h:2771
constexpr void as_number(T &t) const
Convert a string to an integer.
Definition strexpr.h:3323
The concept of a string expression compatible with a given character type.
Definition strexpr.h:418
Concept of "String Expressions".
Definition strexpr.h:400
Base concept of string object.
Definition strexpr.h:264
constexpr expr_if< A > e_if(bool c, const A &a)
Creating a conditional string expression expr_if.
Definition strexpr.h:1318
simstr::expr_stdstr< typename T::value_type, T > operator+(const T &str)
Unary operator + for converting standard strings to string expressions.
Definition strexpr.h:5684
constexpr expr_spaces< uws, N > e_spcw()
Generates a string of N wchar_t spaces.
Definition strexpr.h:878
expr_fill< K, A, true > e_fill_left(const A &a, size_t width, K symbol=K(' '))
Creates an expression that expands the specified string expression to the specified length given char...
Definition strexpr.h:1816
constexpr empty_expr< uws > eew
Empty string expression of type wchar_t.
Definition strexpr.h:636
constexpr expr_spaces< u8s, N > e_spca()
Generates a string of N char spaces.
Definition strexpr.h:860
constexpr empty_expr< u32s > eeuu
Empty string expression of type char32_t.
Definition strexpr.h:648
constexpr expr_num< K, T > e_num(T t)
Convert an integer to a string expression.
Definition strexpr.h:1527
constexpr bool is_equal_str_type_v
Checks whether two types are compatible string types.
Definition strexpr.h:136
HexFlags
Flags for the e_hex function.
Definition strexpr.h:1680
constexpr auto e_hex(T v)
Allows you to concatenate text and a unsigned number in hexadecimal.
Definition strexpr.h:1704
constexpr strexprjoin< A, B > operator+(const A &a, const B &b)
An addition operator for two arbitrary string expressions of the same character type.
Definition strexpr.h:529
constexpr expr_repeat_lit< K, M - 1 > e_repeat(T &&s, size_t l)
Generate a string from l string constants s of type K.
Definition strexpr.h:992
constexpr expr_literal< typename const_lit< T >::symb_type, static_cast< size_t >(N - 1)> e_t(T &&s)
Converts a string literal to a string expression.
Definition strexpr.h:765
expr_fill< K, A, false > e_fill_right(const A &a, size_t width, K symbol=K(' '))
Creates an expression that expands the specified string expression to the specified length given char...
Definition strexpr.h:1842
constexpr expr_choice< A, B > e_choice(bool c, const A &a, const B &b)
Create a conditional string expression expr_choice.
Definition strexpr.h:1240
constexpr expr_char< K > e_char(K s)
Generates a string of 1 given character.
Definition strexpr.h:692
constexpr empty_expr< u8s > eea
Empty string expression of type char.
Definition strexpr.h:624
constexpr expr_pad< K > e_c(size_t l, K s)
Generates a string of l characters s of type K.
Definition strexpr.h:923
constexpr empty_expr< u16s > eeu
Empty string expression of type char16_t.
Definition strexpr.h:642
auto e_repl_const_symbols(A &&src, Repl &&... other)
Returns a string expression that generates a string containing the given characters replaced with giv...
Definition strexpr.h:4968
constexpr empty_expr< u8s > eeb
Empty string expression of type char8_t.
Definition strexpr.h:630
constexpr auto e_repl(A &&w, T &&p, X &&r)
Get a string expression that generates a string with all occurrences of a given substring replaced.
Definition strexpr.h:4474
constexpr auto e_join(const T &s, L &&d)
Get a string expression concatenating the strings in the container into a single string with the give...
Definition strexpr.h:1920
@ Short
without leading zeroes
Definition strexpr.h:1681
Small namespace for standard string methods.
Definition strexpr.h:1393
std::basic_string< K, std::char_traits< K >, A > & append(std::basic_string< K, std::char_traits< K >, A > &str, const E &expr)
Append a string expression to a standard string.
Definition strexpr.h:5323
std::basic_string< K, std::char_traits< K >, A > & prepend(std::basic_string< K, std::char_traits< K >, A > &str, const E &expr)
Insert a string expression at the beginning of a standard string.
Definition strexpr.h:5356
std::basic_string< K, std::char_traits< K >, A > & change(std::basic_string< K, std::char_traits< K >, A > &str, size_t from, size_t count, const E &expr)
Replace a portion of a standard string with the given string expression.
Definition strexpr.h:5250
std::basic_string< K, std::char_traits< K >, A > & replace(std::basic_string< K, std::char_traits< K >, A > &str, T &&pattern, const E &repl, size_t offset=0, size_t max_count=-1)
A function for searching for substrings in a standard string and replacing the found occurrences with...
Definition strexpr.h:5531
std::basic_string< K, std::char_traits< K >, A > & insert(std::basic_string< K, std::char_traits< K >, A > &str, size_t from, const E &expr)
Insert a string expression at the specified position in a standard string.
Definition strexpr.h:5391
Library namespace.
Definition sstring.cpp:12
IntConvertResult
Enumeration with possible results of converting a string to an integer.
Definition strexpr.h:1987
@ Overflow
Переполнение, число не помещается в заданный тип
Definition strexpr.h:1990
@ Success
Успешно
Definition strexpr.h:1988
@ NotNumber
Вообще не число
Definition strexpr.h:1991
@ BadSymbolAtTail
Число закончилось не числовым символом
Definition strexpr.h:1989
An "empty" string expression.
Definition strexpr.h:609
Conditional selection string expression.
Definition strexpr.h:1119
Conditional selection string expression.
Definition strexpr.h:1185
Conditional selection string expression.
Definition strexpr.h:1028
Conditional selection string expression.
Definition strexpr.h:1057
A type of string expression that returns N specified characters.
Definition strexpr.h:894
constexpr expr_replace_symbols(str_t source, const std::vector< std::pair< K, str_t > > &repl)
Expression constructor.
Definition strexpr.h:5052
A string expression that generates a string replacing all occurrences of the given substring to strin...
Definition strexpr.h:4592
constexpr expr_replaced_e(str_src< K > w, str_src< K > p, const E &e)
Constructor.
Definition strexpr.h:4611
A string expression that generates a string replacing all occurrences of the given substring to anoth...
Definition strexpr.h:4486
constexpr expr_replaced(str_src< K > w, str_src< K > p, str_src< K > r)
Constructor.
Definition strexpr.h:4504
A type of string expression that returns N specified characters.
Definition strexpr.h:834
A type for using std::string and std::string_view as sources in string expressions.
Definition strexpr.h:1357
Base class for converting string expressions to standard strings.
Definition strexpr.h:468
A class that claims to refer to a null-terminated string.
Definition strexpr.h:4060
constexpr my_type to_nts(size_t from)
Get a null-terminated string by shifting the start by the specified number of characters.
Definition strexpr.h:4123
constexpr str_src_nt(T &&v) noexcept
Constructor from a string literal.
Definition strexpr.h:4094
constexpr str_src_nt(T &&p) noexcept
Explicit constructor from C-string.
Definition strexpr.h:4085
constexpr str_src_nt(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Constructor from std::basic_string.
Definition strexpr.h:4112
constexpr str_src_nt(const K *p, size_t l) noexcept
Constructor from pointer and length.
Definition strexpr.h:4100
The simplest class of an immutable non-owning string.
Definition strexpr.h:3924
constexpr str_src(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Constructor from std::basic_string.
Definition strexpr.h:3953
constexpr bool is_empty() const noexcept
Check if a string is empty.
Definition strexpr.h:3978
constexpr size_t length() const noexcept
Get the length of the string.
Definition strexpr.h:3964
constexpr K operator[](size_t idx) const
Get the character from the specified position. Bounds checking is not performed.
Definition strexpr.h:4007
constexpr my_type & remove_prefix(size_t delta)
Shifts the start of a line by the specified number of characters.
Definition strexpr.h:4018
constexpr str_src(const K *p, size_t l) noexcept
Constructor from pointer and length.
Definition strexpr.h:3943
constexpr bool is_same(str_src< K > other) const noexcept
Check if two objects point to the same string.
Definition strexpr.h:3987
constexpr str_src(const std::basic_string_view< K, std::char_traits< K > > &s) noexcept
Constructor from std::basic_string_view.
Definition strexpr.h:3958
constexpr const symb_type * symbols() const noexcept
Get a pointer to a constant buffer containing string characters.
Definition strexpr.h:3971
constexpr my_type & remove_suffix(size_t delta)
Shortens the string by the specified number of characters.
Definition strexpr.h:4031
constexpr bool is_part_of(str_src< K > other) const noexcept
Check if a string is part of another string.
Definition strexpr.h:3996
constexpr str_src(T &&v) noexcept
Constructor from a string literal.
Definition strexpr.h:3937
Concatenation of a reference to a string expression and the value of the string expression.
Definition strexpr.h:554
Template class for concatenating two string expressions into one using operator +
Definition strexpr.h:492