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 {};
92concept is_one_of_char_v = is_one_of_type<K, u8s, ubs, wchar_t, u16s, u32s>::value;
95concept 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>
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>
204 requires(is_equal_str_type_v<K, P>)
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 {
243concept StrTypeCommon =
requires(
const A& a) {
244 typename std::remove_cvref_t<A>::symb_type;
245 { a.is_empty() } -> std::same_as<bool>;
246 { a.length() } -> std::convertible_to<size_t>;
251concept HasSymbType =
requires {
252 typename std::remove_cvref_t<A>::symb_type;
276template<
typename A,
typename K>
277concept StrType = StrTypeCommon<A> &&
requires(
const A& a) {
278 { a.symbols() } -> std::same_as<const K*>;
279} && std::is_same_v<typename std::remove_cvref_t<A>::symb_type, K>;
281template<
typename T>
struct is_std_string_source : std::false_type{};
283template<
typename K,
typename A>
284struct is_std_string_source<std::basic_string<K, std::char_traits<K>, A>> : std::true_type{};
287struct is_std_string_source<std::basic_string_view<K, std::char_traits<K>>> : std::true_type{};
290concept is_std_string_source_v = is_std_string_source<T>::value;
293concept StdStrSource = is_std_string_source_v<std::remove_cvref_t<T>>;
295template<
typename T,
typename K>
299concept StrSource = StdStrSource<T> || is_const_lit_v<T> || StrTypeCommon<T>;
301template<
typename T>
struct is_std_string : std::false_type{};
303template<
typename K,
typename A>
304struct is_std_string<std::basic_string<K, std::char_traits<K>, A>> : std::true_type{};
307concept is_std_string_v = is_std_string<T>::value;
308template<
typename T,
typename K>
312struct symb_type_from_src {
317template<
typename K,
size_t N>
318struct symb_type_from_src<const K(&)[N]> {
322template<StdStrSource T>
323struct symb_type_from_src<T> {
324 using type =
typename std::remove_cvref_t<T>::value_type;
327template<HasSymbType T>
328struct symb_type_from_src<T> {
329 using type =
typename std::remove_cvref_t<T>::symb_type;
333using symb_type_from_src_t = symb_type_from_src<T>::type;
471 typename std::remove_cvref_t<A>::symb_type;
472 { a.length() } -> std::convertible_to<size_t>;
473 { a.place(std::declval<
typename std::remove_cvref_t<A>::symb_type*>()) } -> std::same_as<typename std::remove_cvref_t<A>::symb_type*>;
487template<
typename A,
typename K>
493template<
typename K,
typename T>
494struct convert_to_strexpr;
496template<
typename A,
typename K>
497concept strexpr_from =
requires(
const A& a) {
498 {convert_to_strexpr<K, std::remove_cvref_t<A>>::convert(a)} ->
StrExprForType<K>;
501template<
typename A,
typename K>
502concept strexpr_std =
requires(
const A& a) {
503 {convert_to_strexpr<K, std::remove_cvref_t<A>>::convert(a)} -> StdStringForType<K>;
506template<
typename A,
typename K>
509template<
typename A,
typename K>
512template<
typename A,
typename K>
513concept to_strexpr_meth =
requires(
const A& a) {
517template<
typename A,
typename K>
518concept to_strexpr_std =
requires(
const A& a) {
519 {a.template to_strexpr<K>()} -> StdStringForType<K>;
522template<
typename A,
typename K>
523concept convertible_to_strexpr = strexpr_for<A, K> || strexpr_from<A, K> || strexpr_std<A, K> || to_strexpr_type<A, K> || to_strexpr_meth<A, K> || to_strexpr_std<A, K>;
525template<
typename K, strexpr_from<K> T>
526constexpr auto to_strexpr(T&& t) {
527 return convert_to_strexpr<K, std::remove_cvref_t<T>>::convert(std::forward<T>(t));
530template<
typename K, strexpr_for<K> T>
531constexpr typename convert_to_strexpr<K, std::remove_cvref_t<T>>::type to_strexpr(T&& t) {
532 return {std::forward<T>(t)};
535template<
typename K, to_strexpr_type<K> T>
536constexpr typename std::remove_cvref_t<T>::strexpr to_strexpr(T&& t) {
537 return {std::forward<T>(t)};
540template<
typename K, to_strexpr_meth<K> T>
541constexpr auto to_strexpr(T&& t) {
542 return t.template to_strexpr<K>();
546struct expr_stdstr_c {
550 expr_stdstr_c(T t) : t_(std::move(t)){}
552 constexpr size_t length() const noexcept {
555 constexpr symb_type* place(symb_type* p)
const noexcept {
556 size_t s = t_.size();
557 std::char_traits<K>::copy(p, (
const K*)t_.data(), s);
562template<
typename K, strexpr_std<K> T>
563constexpr auto to_strexpr(T&& t) {
564 using type =
decltype(convert_to_strexpr<K, std::remove_cvref_t<T>>::convert(std::forward<T>(t)));
565 return expr_stdstr_c<K, type>{convert_to_strexpr<K, std::remove_cvref_t<T>>::convert(std::forward<T>(t))};
568template<
typename K, to_strexpr_std<K> T>
569constexpr auto to_strexpr(T&& t) {
570 using type =
decltype(t.template to_strexpr<K>());
571 return expr_stdstr_c<K, type>{t.template to_strexpr<K>()};
574template<
typename K,
typename T>
575using convert_to_strexpr_t =
decltype(to_strexpr<K>(std::declval<T>()));
593template<
typename K,
typename Allocator, StrExpr A>
594constexpr std::basic_string<K, std::char_traits<K>, Allocator> to_std_string(
const A& expr) {
595 std::basic_string<K, std::char_traits<K>, Allocator> res;
596 if (
size_t l = expr.length()) {
597 auto fill = [&](K* ptr,
size_t size) ->
size_t {
598 expr.place((
typename A::symb_type*)ptr);
601 if constexpr (
requires { res.resize_and_overwrite(l, fill); }) {
602 res.resize_and_overwrite(l, fill);
603 }
else if constexpr (
requires{ res._Resize_and_overwrite(l, fill); }) {
605 res._Resize_and_overwrite(l, fill);
608 expr.place((
typename A::symb_type*)res.data());
624template<
typename Impl>
626 template<
typename P,
typename Allocator>
628 constexpr operator std::basic_string<P, std::char_traits<P>, Allocator>()
const {
629 return to_std_string<P, Allocator>(*
static_cast<const Impl*
>(
this));
648template<StrExpr A, StrExprForType<
typename A::symb_type> B>
650 using symb_type =
typename A::symb_type;
653 constexpr strexprjoin(
const A& a_,
const B& b_) : a(a_), b(b_){}
654 constexpr size_t length()
const noexcept {
655 return a.length() + b.length();
657 constexpr symb_type* place(symb_type* p)
const noexcept {
658 return (symb_type*)b.place((
typename B::symb_type*)a.place(p));
685template<StrExpr A, StrExprForType<
typename A::symb_type> B>
710template<StrExpr A, StrExprForType<
typename A::symb_type> B,
bool last = true>
712 using symb_type =
typename A::symb_type;
715 template<
typename... Args>
716 constexpr strexprjoin_c(
const A& a_, Args&&... args_) : a(a_), b(std::forward<Args>(args_)...) {}
717 constexpr size_t length()
const noexcept {
718 return a.length() + b.length();
720 constexpr symb_type* place(symb_type* p)
const noexcept {
721 if constexpr (last) {
722 return (symb_type*)b.place((
typename B::symb_type*)a.place(p));
724 return a.place((symb_type*)b.place((
typename B::symb_type*)p));
743template<StrExpr A, convertible_to_strexpr<
typename A::symb_type> B>
745 return {a, to_strexpr<typename A::symb_type>(std::forward<B>(b))};
762template<StrExpr A, convertible_to_strexpr<
typename A::symb_type> B>
764 return {a, to_strexpr<typename A::symb_type>(std::forward<B>(b))};
806 constexpr size_t length()
const noexcept {
809 constexpr symb_type* place(symb_type* p)
const noexcept {
846struct expr_char : expr_to_std_string<expr_char<K>>{
849 constexpr expr_char(K v) : value(v){}
850 constexpr size_t length() const noexcept {
853 constexpr symb_type* place(symb_type* p)
const noexcept {
871template<
typename K, StrExprForType<K> A>
891template<
typename K,
size_t N>
892struct expr_literal : expr_to_std_string<expr_literal<K, N>> {
894 const K (&str)[N + 1];
895 constexpr expr_literal(
const K (&str_)[N + 1]) : str(str_){}
897 constexpr size_t length() const noexcept {
900 constexpr symb_type* place(symb_type* p)
const noexcept {
901 if constexpr (N != 0)
902 std::char_traits<K>::copy(p, str, N);
959template<typename T, size_t N = const_lit<T>::Count>
960constexpr expr_literal<typename const_lit<T>::symb_type,
static_cast<size_t>(N - 1)>
e_t(T&& s) {
964template<
bool first,
typename K,
size_t N,
typename A>
965struct expr_literal_join : expr_to_std_string<expr_literal_join<first, K, N, A>> {
967 using atype =
typename A::symb_type;
968 const K (&str)[N + 1];
970 constexpr expr_literal_join(
const K (&str_)[N + 1],
const A& a_) : str(str_), a(a_){}
972 constexpr size_t length() const noexcept {
973 return N + a.length();
975 constexpr symb_type* place(symb_type* p)
const noexcept {
976 if constexpr (N != 0) {
977 if constexpr (first) {
978 std::char_traits<K>::copy(p, str, N);
979 return (symb_type*)a.place((atype*)(p + N));
981 p = (symb_type*)a.place((atype*)p);
982 std::char_traits<K>::copy(p, str, N);
999constexpr expr_literal_join<
false, P, (N - 1), A>
operator+(
const A& a, T&& s) {
1010template<StrExpr A, typename T, typename P = typename const_lit<T>::symb_type,
size_t N = const_lit<T>::Count>
requires is_equal_str_type_v<typename A::symb_type, P>
1011constexpr expr_literal_join<
true, P, (N - 1), A>
operator+(T&& s,
const A& a) {
1028template<
typename K,
size_t N,
size_t S = ' '>
1030 using symb_type = K;
1031 constexpr size_t length()
const noexcept {
1034 constexpr symb_type* place(symb_type* p)
const noexcept {
1035 if constexpr (N != 0)
1036 std::char_traits<K>::assign(p, N,
static_cast<K
>(S));
1090 using symb_type = K;
1093 constexpr expr_pad(
size_t len_, K s_) : len(len_), s(s_){}
1094 constexpr size_t length()
const noexcept {
1097 constexpr symb_type* place(symb_type* p)
const noexcept {
1099 std::char_traits<K>::assign(p, len, s);
1122template<
typename K,
size_t N>
1123struct expr_repeat_lit : expr_to_std_string<expr_repeat_lit<K, N>> {
1124 using symb_type = K;
1126 const K (&s)[N + 1];
1127 constexpr expr_repeat_lit(
size_t repeat,
const K (&s_)[N + 1]) : repeat_(repeat), s(s_){}
1128 constexpr size_t length() const noexcept {
1131 constexpr symb_type* place(symb_type* p)
const noexcept {
1133 for (
size_t i = 0; i < repeat_; i++) {
1134 std::char_traits<K>::copy(p, s, N);
1144 using symb_type =
typename A::symb_type;
1147 constexpr expr_repeat_expr(
size_t repeat,
const A& expr) : repeat_(repeat), expr_(expr){}
1148 constexpr size_t length() const noexcept {
1150 return repeat_ * expr_.length();
1154 constexpr symb_type* place(symb_type* p)
const noexcept {
1157 return expr_.place(p);
1159 symb_type* start = p;
1161 size_t len = size_t(p - start);
1163 for (
size_t i = 1; i < repeat_; i++) {
1164 std::char_traits<symb_type>::copy(p, start, len);
1186template<typename T, typename K = const_lit<T>::symb_type,
size_t M = const_lit<T>::Count>
requires (M > 0)
1187constexpr expr_repeat_lit<K, M - 1>
e_repeat(T&& s,
size_t l) {
1205constexpr expr_repeat_expr<A>
e_repeat(
const A& s,
size_t l) {
1222template<StrExpr A, StrExprForType<
typename A::symb_type> B>
1224 using symb_type =
typename A::symb_type;
1225 using my_type = expr_choice<A, B>;
1230 constexpr expr_choice(
const A& _a,
const B& _b,
bool _choice) : a(_a), b(_b), choice(_choice){}
1232 constexpr size_t length()
const noexcept {
1233 return choice ? a.length() : b.length();
1235 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1236 return choice ? a.place(ptr) : (symb_type*)b.place((
typename B::symb_type*)ptr);
1253 using symb_type =
typename A::symb_type;
1254 using my_type = expr_if<A>;
1257 constexpr expr_if(
const A& _a,
bool _choice) : a(_a), choice(_choice){}
1259 constexpr size_t length()
const noexcept {
1260 return choice ? a.length() : 0;
1262 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1263 return choice ? a.place(ptr) : ptr;
1313template<
typename L, StrExprForType<L> A,
size_t N,
bool Compare>
1315 using symb_type = L;
1316 const symb_type (&str)[N + 1];
1319 constexpr expr_choice_one_lit(
const symb_type (&_str)[N + 1],
const A& _a,
bool _choice) : str(_str), a(_a), choice(_choice){}
1321 constexpr size_t length()
const noexcept {
1322 return choice == Compare ? a.length() : N;
1324 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1325 if (choice == Compare) {
1326 return (L*)a.place((
typename A::symb_type*)ptr);
1328 if constexpr (N != 0) {
1329 std::char_traits<symb_type>::copy(ptr, str, N);
1379template<
typename K,
size_t N,
typename P,
size_t M>
1381 using symb_type = K;
1382 const K (&str_a)[N + 1];
1383 const P (&str_b)[M + 1];
1385 constexpr expr_choice_two_lit(
const K(&_str_a)[N + 1],
const P(&_str_b)[M + 1],
bool _choice)
1386 : str_a(_str_a), str_b(_str_b), choice(_choice){}
1388 constexpr size_t length()
const noexcept {
1389 return choice ? N : M;
1391 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1393 if constexpr (N != 0) {
1394 std::char_traits<symb_type>::copy(ptr, str_a, N);
1398 if constexpr (M != 0) {
1399 std::char_traits<symb_type>::copy(ptr, (
const K(&)[M + 1])str_b, M);
1434template<StrExpr A, StrExprForType<
typename A::symb_type> B>
1444template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1454template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1463template<typename T, typename L, typename K = typename const_lit<T>::symb_type,
typename P =
typename const_lit<L>::symb_type,
1464 size_t N = const_lit<T>::Count,
size_t M = const_lit_for<typename const_lit<T>::symb_type, L>::Count>
1465 requires is_equal_str_type_v<K, P>
1467 return {str_a, str_b, c};
1521template<typename T, size_t N = const_lit<T>::Count>
1523 using K =
typename const_lit<T>::symb_type;
1524 const K empty[1] = {0};
1537template<
typename K, StdStrSource T>
requires is_equal_str_type_v<K, typename T::value_type>
1539 using symb_type = K;
1542 expr_stdstr(
const T& t) : t_(t){}
1544 constexpr size_t length()
const noexcept {
1547 constexpr symb_type* place(symb_type* p)
const noexcept {
1548 size_t s = t_.size();
1549 std::char_traits<K>::copy(p, (
const K*)t_.data(), s);
1564template<
typename K, StdStrSource T>
1565struct convert_to_strexpr<K, T> {
1570constexpr const size_t npos =
static_cast<size_t>(-1);
1574struct ch_traits : std::char_traits<K>{};
1577concept FromIntNumber =
1578 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;
1581concept ToIntNumber = FromIntNumber<T> || is_one_of_type<T, int8_t>::value;
1583template<
typename K,
bool I,
typename T>
1586 std::make_unsigned_t<T> val;
1587 constexpr need_sign(T t) : negate(t < 0), val(t < 0 ? std::make_unsigned_t<T>{} - t : t) {}
1588 constexpr void after(K*& ptr) {
1594template<
typename K,
typename T>
1595struct need_sign<K, false, T> {
1597 constexpr need_sign(T t) : val(t){}
1598 constexpr void after(K*&) {}
1601template<
typename K,
typename T>
1602constexpr size_t fromInt(K* bufEnd, T val) {
1603 const char* twoDigit =
1604 "0001020304050607080910111213141516171819"
1605 "2021222324252627282930313233343536373839"
1606 "4041424344454647484950515253545556575859"
1607 "6061626364656667686970717273747576777879"
1608 "8081828384858687888990919293949596979899";
1610 need_sign<K, std::is_signed_v<T>, T> store(val);
1612 while (store.val >= 100) {
1613 const char* ptr = twoDigit + (store.val % 100) * 2;
1614 *--itr =
static_cast<K
>(ptr[1]);
1615 *--itr =
static_cast<K
>(ptr[0]);
1618 if (store.val < 10) {
1619 *--itr =
static_cast<K
>(
'0' + store.val);
1621 const char* ptr = twoDigit + store.val * 2;
1622 *--itr =
static_cast<K
>(ptr[1]);
1623 *--itr =
static_cast<K
>(ptr[0]);
1626 return size_t(bufEnd - itr);
1632template<
typename K,
typename T>
1634 using symb_type = K;
1635 using my_type = expr_num<K, T>;
1637 enum { bufSize = 24 };
1639 mutable K buf[bufSize];
1641 constexpr expr_num(T t) : value(t) {}
1642 constexpr expr_num(expr_num<K, T>&& t) : value(t.value) {}
1644 constexpr size_t length() const noexcept {
1645 value = (T)fromInt(buf + bufSize, value);
1646 return (
size_t)value;
1648 constexpr K* place(K* ptr)
const noexcept {
1649 size_t len = (size_t)value;
1650 ch_traits<K>::copy(ptr, buf + bufSize - len, len);
1665template<
typename K, FromIntNumber T>
1666struct convert_to_strexpr<K, T> {
1667 using type = expr_num<K, T>;
1685template<
typename K, FromIntNumber T>
1691struct expr_real : expr_to_std_string<expr_real<K>> {
1692 using symb_type = K;
1693 mutable u8s buf[40];
1696 constexpr expr_real(
double d) : v(d) {}
1697 constexpr expr_real(
float d) : v(d) {}
1699 size_t length() const noexcept {
1700 auto [ptr, ec] = std::to_chars(buf, buf + std::size(buf), v);
1701 l = ec != std::errc{} ? 0 : ptr - buf;
1704 K* place(K* ptr)
const noexcept {
1705 if constexpr (
sizeof(K) ==
sizeof(buf[0])) {
1706 ch_traits<K>::copy(ptr, (K*)buf, l);
1708 for (
size_t i = 0; i < l; i++) {
1726template<
typename K, std::
floating_po
int T>
1727struct convert_to_strexpr<K, T> {
1728 using type = expr_real<K>;
1742template<
typename K>
requires is_one_of_char_v<K>
1743inline constexpr expr_real<K>
e_num(
double t) {
1747template<FromIntNumber Val,
bool All,
bool Ucase,
bool Ox>
1748struct expr_hex_src {
1749 explicit constexpr expr_hex_src(Val v) : v_(v){}
1753template<
typename K,
bool Ucase>
1754constexpr K hex_symbols[16] = {K(
'0'), K(
'1'), K(
'2'), K(
'3'), K(
'4'), K(
'5'), K(
'6'),
1755 K(
'7'), K(
'8'), K(
'9'), K(Ucase ?
'A' :
'a'), K(Ucase ?
'B' :
'b'), K(Ucase ?
'C' :
'c'),
1756 K(Ucase ?
'D' :
'd'), K(Ucase ?
'E' :
'e'), K(Ucase ?
'F' :
'f')};
1758template<
typename K, FromIntNumber Val,
bool All,
bool Ucase,
bool Ox>
1760 using symb_type = K;
1761 mutable need_sign<K, std::is_signed_v<Val>, Val> v_;
1762 mutable K buf_[
sizeof(Val) * 2]{};
1764 explicit constexpr expr_hex(Val v) : v_(v){}
1765 constexpr expr_hex(
const expr_hex_src<Val, All, Ucase, Ox>& v) : v_(v.v_){}
1767 constexpr size_t length() const noexcept {
1768 K *ptr = buf_ + std::size(buf_);
1771 *--ptr = hex_symbols<K, Ucase>[v_.val & 0xF];
1775 *--ptr = hex_symbols<K, Ucase>[v_.val & 0xF];
1780 if constexpr (All) {
1781 if (
size_t need =
sizeof(Val) * 2 - l) {
1782 ch_traits<K>::assign(buf_, need, K(
'0'));
1784 l =
sizeof(Val) * 2;
1790 if constexpr (std::is_signed_v<Val>) {
1791 return l + (Ox ? 2 : 0) + (v_.negate ? 1 : 0);
1793 return l + (Ox ? 2 : 0);
1795 constexpr K* place(K* ptr)
const noexcept {
1796 if constexpr (std::is_signed_v<Val>) {
1805 if constexpr (All) {
1806 ch_traits<K>::copy(ptr, buf_,
sizeof(Val) * 2);
1807 return ptr +
sizeof(Val) * 2;
1809 ch_traits<K>::copy(ptr, buf_ + std::size(buf_) - v_.val, v_.val);
1810 return ptr + v_.val;
1843template<
unsigned Flags = 0, FromIntNumber T>
1845 return expr_hex_src<T, (Flags &
HexFlags::Short) == 0, (Flags & HexFlags::Lcase) == 0, (Flags & HexFlags::No0x) == 0>{v};
1856template<
typename K,
typename Val,
bool All,
bool Ucase,
bool Ox>
1857struct convert_to_strexpr<K, expr_hex_src<Val, All, Ucase, Ox>> {
1858 using type = expr_hex<K, Val, All, Ucase, Ox>;
1862struct expr_pointer : expr_hex<K, uintptr_t, true, true, true> {
1863 constexpr expr_pointer(
const void* ptr) : expr_hex<K, uintptr_t, true, true, true>((uintptr_t)ptr){}
1874template<
typename K,
typename T>
1875struct convert_to_strexpr<K, const T*> {
1876 using type = expr_pointer<K>;
1879template<
typename K, StrExprForType<K> A,
bool Left>
1881 using symb_type = K;
1885 mutable size_t alen_{};
1886 constexpr expr_fill(K symbol,
size_t width,
const A& a) : symbol_(symbol), width_(width), a_(a){}
1888 constexpr size_t length() const noexcept {
1889 alen_ = a_.length();
1890 return std::max(alen_, width_);
1892 constexpr K* place(K* ptr)
const noexcept {
1893 if (alen_ >= width_) {
1894 return (K*)a_.place((
typename A::symb_type*)ptr);
1896 size_t w = width_ - alen_;
1897 if constexpr (Left) {
1898 ch_traits<K>::assign(ptr, w, symbol_);
1900 return (K*)a_.place((
typename A::symb_type*)ptr);
1902 ptr = (K*)a_.place((
typename A::symb_type*)ptr);
1903 ch_traits<K>::assign(ptr, w, symbol_);
1930template<StrExpr A,
typename K =
typename A::symb_type>
1931expr_fill<K, A, true>
e_fill_left(
const A& a,
size_t width, K symbol = K(
' ')) {
1932 return {symbol, width, a};
1956template<StrExpr A,
typename K =
typename A::symb_type>
1957expr_fill<K, A, false>
e_fill_right(
const A& a,
size_t width, K symbol = K(
' ')) {
1958 return {symbol, width, a};
1977template<
typename K,
typename T,
size_t I,
bool tail,
bool skip_empty>
1978struct expr_join : expr_to_std_string<expr_join<K, T, I, tail, skip_empty>> {
1979 using symb_type = K;
1980 using my_type = expr_join<K, T, I, tail, skip_empty>;
1984 constexpr expr_join(
const T& _s,
const K* _delim) : s(_s), delim(_delim){}
1986 constexpr size_t length() const noexcept {
1988 for (
const auto& t: s) {
1989 size_t len = t.length();
1990 if (len > 0 || !skip_empty) {
1991 if (I > 0 && l > 0) {
1997 return l + (tail && I > 0 && (l > 0 || (!skip_empty && s.size() > 0))? I : 0);
1999 constexpr K* place(K* ptr)
const noexcept {
2004 for (
const auto& t: s) {
2005 size_t copyLen = t.length();
2006 if (I > 0 && write != ptr && (copyLen || !skip_empty)) {
2007 ch_traits<K>::copy(write, delim, I);
2010 ch_traits<K>::copy(write, t.data(), copyLen);
2013 if (I > 0 && tail && (write != ptr || (!skip_empty && s.size() > 0))) {
2014 ch_traits<K>::copy(write, delim, I);
2034template<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>
2035inline constexpr auto e_join(
const T& s, L&& d) {
2036 return expr_join<K, T, I - 1, tail, skip_empty>{s, d};
2040concept is_const_pattern = N > 1 && N <= 17;
2042template<
typename K,
size_t I>
2044 constexpr static const size_t value = size_t(K(~0x7F)) << ((I - 1) *
sizeof(K) * 8) | _ascii_mask<K, I - 1>::value;
2048struct _ascii_mask<K, 0> {
2049 constexpr static const size_t value = 0;
2054 using uns = std::make_unsigned_t<K>;
2055 constexpr static const size_t WIDTH =
sizeof(size_t) /
sizeof(uns);
2056 constexpr static const size_t VALUE = _ascii_mask<uns, WIDTH>::value;
2060constexpr inline bool isAsciiUpper(K k) {
2061 return k >=
'A' && k <=
'Z';
2065constexpr inline bool isAsciiLower(K k) {
2066 return k >=
'a' && k <=
'z';
2070constexpr inline K makeAsciiLower(K k) {
2071 return isAsciiUpper(k) ? k | 0x20 : k;
2075constexpr inline K makeAsciiUpper(K k) {
2076 return isAsciiLower(k) ? k & ~0x20 : k;
2079enum TrimSides { TrimLeft = 1, TrimRight = 2, TrimAll = 3 };
2080template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces = false>
2081struct trim_operator;
2084struct digits_selector {
2085 using wider_type = uint16_t;
2089struct digits_selector<2> {
2090 using wider_type = uint32_t;
2094struct digits_selector<4> {
2095 using wider_type = uint64_t;
2109template<
bool CanNegate,
bool CheckOverflow,
typename T>
2110struct result_type_selector {
2115struct result_type_selector<true, false, T> {
2116 using type = std::make_unsigned_t<T>;
2119template<
unsigned Base>
2120constexpr unsigned digit_width() {
2139template<
typename T,
unsigned Base>
2140constexpr unsigned max_overflow_digits = (
sizeof(T) * CHAR_BIT) / digit_width<Base>();
2143struct convert_result {
2150 inline static constexpr uint8_t NUMBERS[] = {
2151 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,
2152 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,
2153 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,
2154 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,
2155 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,
2156 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,
2157 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,
2158 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,
2159 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,
2160 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
2162 template<
typename K,
unsigned Base>
2163 static constexpr std::make_unsigned_t<K> toDigit(K s) {
2164 auto us =
static_cast<std::make_unsigned_t<K>
>(s);
2165 if constexpr (Base <= 10) {
2168 if constexpr (
sizeof(K) == 1) {
2171 return us < 256 ? NUMBERS[us] : us;
2176 template<
typename K, ToIntNumber T,
unsigned Base,
bool CheckOverflow>
2178 static constexpr convert_result<T> parse(
const K* start,
const K* current,
const K* end,
bool negate) {
2179 using u_type = std::make_unsigned_t<T>;
2180 #ifndef HAS_BUILTIN_OVERFLOW
2181 u_type maxMult = 0, maxAdd = 0;
2182 if constexpr (CheckOverflow) {
2183 maxMult = std::numeric_limits<u_type>::max() / Base;
2184 maxAdd = std::numeric_limits<u_type>::max() % Base;
2188 unsigned maxDigits = max_overflow_digits<u_type, Base>;
2190 const K* from = current;
2192 bool no_need_check_o_f = !CheckOverflow || end - current <= maxDigits;
2194 if (no_need_check_o_f) {
2196 const u_type digit = toDigit<K, Base>(*current);
2197 if (digit >= Base) {
2200 number = number * Base + digit;
2201 if (++current == end) {
2207 for (;maxDigits; maxDigits--) {
2208 const u_type digit = toDigit<K, Base>(*current);
2209 if (digit >= Base) {
2212 number = number * Base + digit;
2219 const u_type digit = toDigit<K, Base>(*current);
2220 if (digit >= Base) {
2223 #ifdef HAS_BUILTIN_OVERFLOW
2224 if (__builtin_mul_overflow(number, Base, &number) ||
2225 __builtin_add_overflow(number, digit, &number)) {
2227 if (number < maxMult || (number == maxMult && number < maxAdd)) {
2228 number = number * Base + digit;
2232 while(++current < end) {
2233 if (toDigit<K, Base>(*current) >= Base) {
2239 if (++current == end) {
2247 if constexpr (std::is_signed_v<T>) {
2248 result = negate ? 0 - number : number;
2249 if constexpr (CheckOverflow) {
2251 if (number > std::numeric_limits<T>::max() + (negate ? 1 : 0)) {
2262 return {result, error, size_t(current - start)};
2269 template<
typename K, ToIntNumber T,
unsigned Base = 0,
bool CheckOverflow = true,
bool SkipWs = true,
bool AllowSign = true>
2270 requires(Base == -1 || (Base < 37 && Base != 1))
2271 static constexpr convert_result<T> to_integer(
const K* start,
size_t len)
noexcept {
2272 const K *ptr = start, *end = ptr + len;
2273 bool negate =
false;
2274 if constexpr (SkipWs) {
2275 while (ptr < end && std::make_unsigned_t<K>(*ptr) <=
' ')
2279 if constexpr (std::is_signed_v<T>) {
2280 if constexpr (AllowSign) {
2285 }
else if (*ptr ==
'-') {
2297 }
else if constexpr (AllowSign) {
2306 if constexpr (Base == 0 || Base == -1) {
2310 if (*ptr ==
'x' || *ptr ==
'X') {
2311 return parse<K, T, 16, CheckOverflow>(start, ++ptr, end, negate);
2313 if constexpr (Base == -1) {
2314 if (*ptr ==
'b' || *ptr ==
'B') {
2315 return parse<K, T, 2, CheckOverflow>(start, ++ptr, end, negate);
2317 if (*ptr ==
'o' || *ptr ==
'O') {
2318 return parse<K, T, 8, CheckOverflow>(start, ++ptr, end, negate);
2321 return parse<K, T, 8, CheckOverflow>(start, --ptr, end, negate);
2325 return parse<K, T, 10, CheckOverflow>(start, ptr, end, negate);
2327 return parse<K, T, Base, CheckOverflow>(start, ptr, end, negate);
2333template<
typename K,
typename Impl>
2334class null_terminated {
2342 constexpr const K* c_str()
const {
return static_cast<const Impl*
>(
this)->symbols(); }
2345template<
typename K,
typename Impl,
bool Mutable>
class buffer_pointers;
2355template<
typename K,
typename Impl>
2356class buffer_pointers<K, Impl, false> {
2357 constexpr const Impl& d()
const {
return *
static_cast<const Impl*
>(
this); }
2365 constexpr const K* data()
const {
return d().symbols(); }
2372 constexpr const K* begin()
const {
return d().symbols(); }
2379 constexpr const K* end()
const {
return d().symbols() + d().length(); }
2386 constexpr const K* cbegin()
const {
return d().symbols(); }
2393 constexpr const K* cend()
const {
return d().symbols() + d().length(); }
2396template<
typename K,
typename Impl>
2397class buffer_pointers<K, Impl, true> :
public buffer_pointers<K, Impl, false> {
2398 constexpr Impl& d() {
return *
static_cast<Impl*
>(
this); }
2399 using base = buffer_pointers<K, Impl, false>;
2407 constexpr const K* data()
const {
return base::data(); }
2414 constexpr const K* begin()
const {
return base::begin(); }
2421 constexpr const K* end()
const {
return base::end(); }
2428 constexpr const K* cbegin()
const {
return base::cbegin(); }
2435 constexpr const K* cend()
const {
return base::cend(); }
2442 constexpr K* data() {
return d().str(); }
2449 constexpr K* begin() {
return d().str(); }
2456 constexpr K* end() {
return d().str() + d().length(); }
2465template<
typename K,
typename StrSrc>
2467 using str_t = StrSrc;
2472 constexpr SplitterBase(str_t text, str_t delim) : text_(text), delim_(delim) {}
2478 return text_.length() == str::npos;
2487 if (!text_.length()) {
2492 }
else if (text_.length() == str::npos) {
2493 return {
nullptr, 0};
2495 size_t pos = text_.find(delim_),
next = 0;
2496 if (pos == str::npos) {
2497 pos = text_.length();
2500 next = pos + delim_.length();
2502 str_t result{text_.str, pos};
2533template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
2534class str_src_algs :
public buffer_pointers<K, Impl, Mutable> {
2535 constexpr const Impl& d()
const noexcept {
2536 return *
static_cast<const Impl*
>(
this);
2538 constexpr size_t _len()
const noexcept {
2539 return d().length();
2541 constexpr const K* _str()
const noexcept {
2542 return d().symbols();
2544 constexpr bool _is_empty()
const noexcept {
2545 return d().is_empty();
2549 using symb_type = K;
2550 using str_piece = StrRef;
2551 using traits = ch_traits<K>;
2552 using uns_type = std::make_unsigned_t<K>;
2553 using my_type = Impl;
2554 using base = str_src_algs<K, StrRef, Impl, Mutable>;
2555 str_src_algs() =
default;
2569 constexpr K*
place(K* ptr)
const noexcept {
2570 size_t myLen = _len();
2571 traits::copy(ptr, _str(), myLen);
2585 size_t tlen = std::min(_len(), bufSize - 1);
2586 traits::copy(buffer, _str(), tlen);
2606 constexpr std::basic_string_view<D>
to_sv() const noexcept {
2607 return {(
const D*)_str(), _len()};
2616 constexpr operator std::basic_string_view<D, Traits>()
const {
2617 return {(
const D*)_str(), _len()};
2625 template<
typename D = K,
typename Traits = std::
char_traits<D>,
typename Allocator = std::allocator<D>>
requires is_equal_str_type_v<K, D>
2626 constexpr std::basic_string<D, Traits, Allocator>
to_string()
const {
2627 return {(
const D*)_str(), _len()};
2636 constexpr operator std::basic_string<D, Traits, Allocator>()
const {
2637 return {(
const D*)_str(), _len()};
2645 constexpr operator str_piece() const noexcept {
2646 return str_piece{_str(), _len()};
2654 constexpr str_piece
to_str() const noexcept {
2655 return {_str(), _len()};
2680 constexpr str_piece
operator()(ptrdiff_t from, ptrdiff_t len = 0) const noexcept {
2681 size_t myLen = _len(), idxStart = from >= 0 ? from : myLen > -from ? myLen + from : 0,
2682 idxEnd = len > 0 ? idxStart + len : myLen > -len ? myLen + len : 0;
2685 if (idxStart > idxEnd)
2687 return str_piece{_str() + idxStart, idxEnd - idxStart};
2699 constexpr str_piece
mid(
size_t from,
size_t len = -1) const noexcept {
2700 size_t myLen = _len(), idxStart = from, idxEnd = from > std::numeric_limits<size_t>::max() - len ? myLen : from + len;
2703 if (idxStart > idxEnd)
2705 return str_piece{_str() + idxStart, idxEnd - idxStart};
2721 constexpr str_piece
from_to(
size_t from,
size_t to)
const noexcept {
2722 return str_piece{_str() + from, to - from};
2741 constexpr K
at(ptrdiff_t idx)
const {
2742 return _str()[idx >= 0 ? idx : _len() + idx];
2746 constexpr int compare(
const K* text,
size_t len)
const {
2747 size_t myLen = _len();
2748 int cmp = traits::compare(_str(), text, std::min(myLen, len));
2749 return cmp == 0 ? (myLen > len ? 1 : myLen == len ? 0 : -1) : cmp;
2760 return compare(o.symbols(), o.length());
2771 size_t myLen = _len(), idx = 0;
2772 const K* ptr = _str();
2773 for (; idx < myLen; idx++) {
2774 uns_type s1 = (uns_type)text[idx];
2778 uns_type s2 = (uns_type)ptr[idx];
2781 }
else if (s1 > s2) {
2785 return text[idx] == 0 ? 0 : -1;
2788 constexpr bool equal(
const K* text,
size_t len)
const noexcept {
2789 return len == _len() && traits::compare(_str(), text, len) == 0;
2799 constexpr bool equal(str_piece other)
const noexcept {
2800 return equal(other.symbols(), other.length());
2811 return equal(other._str(), other._len());
2820 return compare(other._str(), other._len()) <=> 0;
2828 template<typename T, size_t N = const_lit_for<K, T>::Count>
2830 return N - 1 == _len() && traits::compare(_str(), other, N - 1) == 0;
2838 template<typename T, size_t N = const_lit_for<K, T>::Count>
2840 size_t myLen = _len();
2841 int cmp = traits::compare(_str(), other, std::min(myLen, N - 1));
2842 int res = cmp == 0 ? (myLen > N - 1 ? 1 : myLen == N - 1 ? 0 : -1) : cmp;
2848 constexpr int compare_ia(
const K* text,
size_t len)
const noexcept {
2850 return _is_empty() ? 0 : 1;
2851 size_t myLen = _len(), checkLen = std::min(myLen, len);
2852 const uns_type *ptr1 =
reinterpret_cast<const uns_type*
>(_str()), *ptr2 =
reinterpret_cast<const uns_type*
>(text);
2853 while (checkLen--) {
2854 uns_type s1 = *ptr1++, s2 = *ptr2++;
2857 s1 = makeAsciiLower(s1);
2858 s2 = makeAsciiLower(s2);
2864 return myLen == len ? 0 : myLen > len ? 1 : -1;
2875 return compare_ia(text.symbols(), text.length());
2886 constexpr bool equal_ia(str_piece text)
const noexcept {
2887 return text.length() == _len() && compare_ia(text.symbols(), text.length()) == 0;
2897 constexpr bool less_ia(str_piece text)
const noexcept {
2898 return compare_ia(text.symbols(), text.length()) < 0;
2901 constexpr size_t find(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
2902 size_t lenText = _len();
2905 if (!lenPattern || offset >= lenText || offset + lenPattern > lenText)
2908 const K *text = _str(), *last = text + lenText - lenPattern, first = pattern[0];
2910 for (
const K* fnd = text + offset;; ++fnd) {
2911 fnd = traits::find(fnd, last - fnd, first);
2914 if (traits::compare(fnd + 1, pattern, lenPattern) == 0)
2915 return static_cast<size_t>(fnd - text);
2928 constexpr size_t find(str_piece pattern,
size_t offset = 0) const noexcept {
2929 return find(pattern.symbols(), pattern.length(), offset);
2947 template<
typename Exc,
typename ... Args>
requires std::is_constructible_v<Exc, Args...>
2948 constexpr size_t find_or_throw(str_piece pattern,
size_t offset = 0, Args&& ... args)
const noexcept {
2949 if (
auto fnd = find(pattern.symbols(), pattern.length(), offset); fnd != str::npos) {
2952 throw Exc(std::forward<Args>(args)...);
2964 constexpr size_t find_end(str_piece pattern,
size_t offset = 0) const noexcept {
2965 size_t fnd = find(pattern.symbols(), pattern.length(), offset);
2966 return fnd == str::npos ? fnd : fnd + pattern.length();
2978 constexpr size_t find_or_all(str_piece pattern,
size_t offset = 0) const noexcept {
2979 auto fnd = find(pattern.symbols(), pattern.length(), offset);
2980 return fnd == str::npos ? _len() : fnd;
2993 auto fnd = find(pattern.symbols(), pattern.length(), offset);
2994 return fnd == str::npos ? _len() : fnd + pattern.length();
2997 constexpr size_t find_last(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
2998 if (lenPattern == 1)
2999 return find_last(pattern[0], offset);
3000 size_t lenText = std::min(_len(), offset);
3003 if (!lenPattern || lenPattern > lenText)
3007 const K *text = _str() + lenPattern, last = pattern[lenPattern];
3008 lenText -= lenPattern;
3010 if (text[--lenText] == last) {
3011 if (traits::compare(text + lenText - lenPattern, pattern, lenPattern) == 0) {
3028 constexpr size_t find_last(str_piece pattern,
size_t offset = -1) const noexcept {
3029 return find_last(pattern.symbols(), pattern.length(), offset);
3042 size_t fnd = find_last(pattern.symbols(), pattern.length(), offset);
3043 return fnd == str::npos ? fnd : fnd + pattern.length();
3056 auto fnd = find_last(pattern.symbols(), pattern.length(), offset);
3057 return fnd == str::npos ? _len() : fnd;
3070 size_t fnd = find_last(pattern.symbols(), pattern.length(), offset);
3071 return fnd == str::npos ? _len() : fnd + pattern.length();
3083 constexpr bool contains(str_piece pattern,
size_t offset = 0) const noexcept {
3084 return find(pattern, offset) != str::npos;
3096 constexpr size_t find(K s,
size_t offset = 0) const noexcept {
3097 size_t len = _len();
3099 const K *
str = _str(), *fnd = traits::find(
str + offset, len - offset, s);
3101 return static_cast<size_t>(fnd -
str);
3116 size_t len = _len();
3118 const K *
str = _str(), *fnd = traits::find(
str + offset, len - offset, s);
3120 return static_cast<size_t>(fnd -
str);
3125 template<
typename Op>
3126 constexpr void for_all_finded(
const Op& op,
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
3129 while (maxCount-- > 0) {
3130 size_t fnd = find(pattern, patternLen, offset);
3131 if (fnd == str::npos)
3134 offset = fnd + patternLen;
3149 template<
typename Op>
3150 constexpr void for_all_finded(
const Op& op, str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
3151 for_all_finded(op, pattern.symbols(), pattern.length(), offset, maxCount);
3154 template<
typename To = std::vector<
size_t>>
3155 constexpr To find_all(
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
3157 for_all_finded([&](
auto f) { result.emplace_back(f); }, pattern, patternLen, offset, maxCount);
3172 template<
typename To = std::vector<
size_t>>
3173 constexpr To
find_all(str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
3174 return find_all(pattern.symbols(), pattern.length(), offset, maxCount);
3176 template<
typename To = std::vector<
size_t>>
3177 constexpr void find_all_to(To& to,
const K* pattern,
size_t len,
size_t offset = 0,
size_t maxCount = 0)
const {
3178 return for_all_finded([&](
size_t pos) {
3179 to.emplace_back(pos);
3180 }, pattern, len, offset, maxCount);
3192 constexpr size_t find_last(K s,
size_t offset = -1) const noexcept {
3193 size_t len = std::min(_len(), offset);
3194 const K *text = _str();
3196 if (text[--len] == s)
3211 constexpr size_t find_first_of(str_piece pattern,
size_t offset = 0) const noexcept {
3212 return std::basic_string_view<K>{_str(), _len()}.find_first_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
3224 constexpr std::pair<size_t, size_t>
find_first_of_idx(str_piece pattern,
size_t offset = 0) const noexcept {
3225 const K* text = _str();
3226 size_t fnd = std::basic_string_view<K>{text, _len()}.find_first_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
3227 return {fnd, fnd == std::basic_string<K>::npos ? fnd : pattern.find(text[fnd]) };
3240 return std::basic_string_view<K>{_str(), _len()}.find_first_not_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
3252 constexpr size_t find_last_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
3253 return std::basic_string_view<K>{_str(), _len()}.find_last_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
3265 constexpr std::pair<size_t, size_t>
find_last_of_idx(str_piece pattern,
size_t offset = str::npos)
const noexcept {
3266 const K* text = _str();
3267 size_t fnd = std::basic_string_view<K>{text, _len()}.find_last_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
3268 return {fnd, fnd == std::basic_string<K>::npos ? fnd : pattern.find(text[fnd]) };
3280 constexpr size_t find_last_not_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
3281 return std::basic_string_view<K>{_str(), _len()}.find_last_not_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
3293 constexpr my_type
substr(ptrdiff_t from, ptrdiff_t len = 0)
const {
3294 return my_type{d()(from, len)};
3306 constexpr my_type
str_mid(
size_t from,
size_t len = -1)
const {
3307 return my_type{d().mid(from, len)};
3337 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
3339 auto [res, err, _] = int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
3370 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
3371 constexpr convert_result<T>
to_int() const noexcept {
3372 return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
3380 template<
bool SkipWS = true,
bool AllowPlus = true>
requires (
sizeof(K) == 1)
3382 size_t len = _len();
3383 const K* ptr = _str();
3384 if constexpr (SkipWS) {
3385 while (len && uns_type(*ptr) <=
' ') {
3390 if constexpr (AllowPlus) {
3391 if (len && *ptr == K(
'+')) {
3400 if (std::from_chars((
const u8s*)ptr, (
const u8s*)ptr + len, d).ec == std::errc{}) {
3411 template<
bool SkipWS = true>
requires (
sizeof(K) == 1)
3413 size_t len = _len();
3414 const K* ptr = _str();
3415 if constexpr (SkipWS) {
3416 while (len && uns_type(*ptr) <=
' ') {
3423 if (std::from_chars(ptr, ptr + len, d, std::chars_format::hex).ec == std::errc{}) {
3437 template<ToIntNumber T>
3442 template<
typename T,
typename Op>
3443 constexpr T splitf(
const K* delimiter,
size_t lendelimiter,
const Op& beforeFunc,
size_t offset)
const {
3444 size_t mylen = _len();
3445 std::conditional_t<std::is_same_v<T, void>, char, T> results;
3446 str_piece me{_str(), mylen};
3447 for (
int i = 0;; i++) {
3448 size_t beginOfDelim = find(delimiter, lendelimiter, offset);
3449 if (beginOfDelim == str::npos) {
3450 str_piece last{me.symbols() + offset, me.length() - offset};
3451 if constexpr (std::is_invocable_v<Op, str_piece&>) {
3454 if constexpr (
requires { results.emplace_back(last); }) {
3455 if (last.is_same(me)) {
3458 results.emplace_back(d());
3460 results.emplace_back(last);
3462 }
else if constexpr (
requires { results.push_back(last); }) {
3463 if (last.is_same(me)) {
3466 results.push_back(d());
3468 results.push_back(last);
3470 }
else if constexpr (
requires {results[i] = last;} &&
requires{std::size(results);}) {
3471 if (i < std::size(results)) {
3472 if (last.is_same(me)) {
3482 str_piece piece{me.symbols() + offset, beginOfDelim - offset};
3483 if constexpr (std::is_invocable_v<Op, str_piece&>) {
3486 if constexpr (
requires { results.emplace_back(piece); }) {
3487 results.emplace_back(piece);
3488 }
else if constexpr (
requires { results.push_back(piece); }) {
3489 results.push_back(piece);
3490 }
else if constexpr (
requires { results[i] = piece; } &&
requires{std::size(results);}) {
3491 if (i < std::size(results)) {
3493 if (i == results.size() - 1) {
3498 offset = beginOfDelim + lendelimiter;
3500 if constexpr (!std::is_same_v<T, void>) {
3534 template<
typename T,
typename Op>
3535 constexpr T
splitf(str_piece delimiter,
const Op& beforeFunc,
size_t offset = 0)
const {
3536 return splitf<T>(delimiter.symbols(), delimiter.length(), beforeFunc, offset);
3550 template<
typename T>
3551 constexpr T
split(str_piece delimiter,
size_t offset = 0)
const {
3552 return splitf<T>(delimiter.symbols(), delimiter.length(), 0, offset);
3557 constexpr bool starts_with(
const K* prefix,
size_t l)
const noexcept {
3558 return _len() >= l && 0 == traits::compare(_str(), prefix, l);
3567 return starts_with(prefix.symbols(), prefix.length());
3570 constexpr bool starts_with_ia(
const K* prefix,
size_t len)
const noexcept {
3571 size_t myLen = _len();
3575 const K* ptr1 = _str();
3577 K s1 = *ptr1++, s2 = *prefix++;
3580 if (makeAsciiLower(s1) != makeAsciiLower(s2))
3592 return starts_with_ia(prefix.symbols(), prefix.length());
3597 constexpr bool prefix_in(
const K* text,
size_t len)
const noexcept {
3598 size_t myLen = _len();
3601 return !myLen || 0 == traits::compare(text, _str(), myLen);
3610 return prefix_in(text.symbols(), text.length());
3614 constexpr bool ends_with(
const K* suffix,
size_t len)
const noexcept {
3615 size_t myLen = _len();
3616 return len <= myLen && traits::compare(_str() + myLen - len, suffix, len) == 0;
3625 return ends_with(suffix.symbols(), suffix.length());
3629 constexpr bool ends_with_ia(
const K* suffix,
size_t len)
const noexcept {
3630 size_t myLen = _len();
3634 const K* ptr1 = _str() + myLen - len;
3636 K s1 = *ptr1++, s2 = *suffix++;
3639 if (makeAsciiLower(s1) != makeAsciiLower(s2))
3651 return ends_with_ia(suffix.symbols(), suffix.length());
3660 if (std::is_constant_evaluated()) {
3661 for (
size_t idx = 0; idx < _len(); idx++) {
3662 if (uns_type(_str()[idx]) > 127) {
3668 const int sl = ascii_mask<K>::WIDTH;
3669 const size_t mask = ascii_mask<K>::VALUE;
3670 size_t len = _len();
3671 const uns_type* ptr =
reinterpret_cast<const uns_type*
>(_str());
3672 if constexpr (sl > 1) {
3673 const size_t roundMask =
sizeof(size_t) - 1;
3674 while (len >= sl && (
reinterpret_cast<size_t>(ptr) & roundMask) != 0) {
3680 if (*
reinterpret_cast<const size_t*
>(ptr) & mask)
3700 template<
typename R = my_type>
3702 return R::upperred_only_ascii_from(d());
3712 template<
typename R = my_type>
3714 return R::lowered_only_ascii_from(d());
3732 template<
typename R = my_type>
3733 R
replaced(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0)
const {
3734 return R::replaced_from(d(), pattern, repl, offset, maxCount);
3737 template<StrType<K> From>
3738 constexpr static my_type make_trim_op(
const From& from,
const auto& opTrim) {
3739 str_piece sfrom = from, newPos = opTrim(sfrom);
3740 if (newPos.is_same(sfrom)) {
3744 return my_type{newPos};
3746 template<TrimS
ides S, StrType<K> From>
3747 constexpr static my_type trim_static(
const From& from) {
3748 return make_trim_op(from, trim_operator<S, K,
static_cast<size_t>(-1),
true>{});
3751 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count, StrType<K> From>
3752 requires is_const_pattern<N>
3753 constexpr static my_type trim_static(
const From& from, T&& pattern) {
3754 return make_trim_op(from, trim_operator<S, K, N - 1, withSpaces>{pattern});
3757 template<TrimS
ides S,
bool withSpaces, StrType<K> From>
3758 constexpr static my_type trim_static(
const From& from, str_piece pattern) {
3759 return make_trim_op(from, trim_operator<S, K, 0, withSpaces>{{pattern}});
3769 template<
typename R = str_piece>
3771 return R::template trim_static<TrimSides::TrimAll>(d());
3781 template<
typename R = str_piece>
3783 return R::template trim_static<TrimSides::TrimLeft>(d());
3793 template<
typename R = str_piece>
3795 return R::template trim_static<TrimSides::TrimRight>(d());
3807 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3808 requires is_const_pattern<N>
3810 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
3822 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3823 requires is_const_pattern<N>
3825 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
3837 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3838 requires is_const_pattern<N>
3840 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
3859 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3860 requires is_const_pattern<N>
3862 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
3878 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3879 requires is_const_pattern<N>
3881 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
3897 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
3898 requires is_const_pattern<N>
3900 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
3915 template<
typename R = str_piece>
3917 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
3929 template<
typename R = str_piece>
3931 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
3943 template<
typename R = str_piece>
3945 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
3961 template<
typename R = str_piece>
3963 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
3979 template<
typename R = str_piece>
3981 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
3997 template<
typename R = str_piece>
3999 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
4017template<
size_t N>
requires (N > 1)
4018struct find_all_container {
4019 static constexpr size_t max_capacity = N;
4020 size_t positions_[N];
4023 void emplace_back(
size_t pos) {
4024 positions_[added_++] = pos;
4047struct str_src : str_src_algs<K, str_src<K>, str_src<K>, false> {
4048 using symb_type = K;
4049 using my_type = str_src<K>;
4051 const symb_type* str;
4054 str_src() =
default;
4059 template<typename T, size_t N = const_lit_for<K, T>::Count>
4060 constexpr str_src(T&& v) noexcept : str(v), len(N - 1) {}
4066 constexpr str_src(
const K* p,
size_t l) noexcept : str(p), len(l) {}
4068 template<StrType<K> T>
4069 constexpr str_src(T&& t) :
str(t.symbols()), len(t.length()){}
4075 template<
typename A>
4076 constexpr str_src(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : str(s.data()), len(s.length()) {}
4081 constexpr str_src(
const std::basic_string_view<K, std::char_traits<K>>& s) noexcept : str(s.data()), len(s.length()) {}
4094 constexpr const symb_type*
symbols() const noexcept {
4110 constexpr bool is_same(str_src<K> other)
const noexcept {
4111 return str == other.str && len == other.len;
4120 return str >= other.str && str + len <= other.str + other.len;
4183struct str_src_nt : str_src<K>, null_terminated<K, str_src_nt<K>> {
4184 using symb_type = K;
4185 using my_type = str_src_nt<K>;
4186 using base = str_src<K>;
4188 constexpr static const K empty_string[1] = {0};
4190 str_src_nt() =
default;
4207 template<
typename T>
requires std::is_same_v<std::remove_const_t<std::remove_pointer_t<std::remove_cvref_t<T>>>, K>
4210 base::str = base::len ? p : empty_string;
4216 template<typename T, size_t N = const_lit_for<K, T>::Count>
4217 constexpr str_src_nt(T&& v) noexcept : base(std::forward<T>(v)) {}
4223 constexpr str_src_nt(
const K* p,
size_t l) noexcept : base(p, l) {}
4225 template<StrType<K> T>
4228 base::len = t.length();
4234 template<
typename A>
4235 constexpr str_src_nt(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : base(s) {}
4237 static const my_type empty_str;
4247 if (from > base::len) {
4250 return {base::str + from, base::len - from};
4255inline const str_src_nt<K> str_src_nt<K>::empty_str{str_src_nt<K>::empty_string, 0};
4256template<
typename K>
struct simple_str_selector;
4258#ifndef IN_FULL_SIMSTR
4261using simple_str = str_src<K>;
4264struct simple_str_selector {
4265 using type = simple_str<K>;
4269using simple_str_nt = str_src_nt<K>;
4272using Splitter = SplitterBase<K, str_src<K>>;
4274using ssa = str_src<u8s>;
4275using ssb = str_src<ubs>;
4276using ssw = str_src<wchar_t>;
4277using ssu = str_src<u16s>;
4278using ssuu = str_src<u32s>;
4279using stra = str_src_nt<u8s>;
4280using strb = str_src_nt<ubs>;
4281using strw = str_src_nt<wchar_t>;
4282using stru = str_src_nt<u16s>;
4283using struu = str_src_nt<u32s>;
4286consteval simple_str_nt<K> select_str(simple_str_nt<u8s> s8, simple_str_nt<ubs> sb, simple_str_nt<uws> sw, simple_str_nt<u16s> s16, simple_str_nt<u32s> s32) {
4287 if constexpr (std::is_same_v<K, u8s>)
4289 if constexpr (std::is_same_v<K, ubs>)
4291 if constexpr (std::is_same_v<K, uws>)
4293 if constexpr (std::is_same_v<K, u16s>)
4295 if constexpr (std::is_same_v<K, u32s>)
4299#define uni_string(K, p) select_str<K>(p, u8##p, L##p, u##p, U##p)
4301inline namespace literals {
4374template<
typename K,
bool withSpaces>
4375struct CheckSpaceTrim {
4376 constexpr bool is_trim_spaces(K s)
const {
4377 return s ==
' ' || (s >= 9 && s <= 13);
4381struct CheckSpaceTrim<K, false> {
4382 constexpr bool is_trim_spaces(K)
const {
4388struct CheckSymbolsTrim {
4390 constexpr bool is_trim_symbols(K s)
const {
4391 return symbols.len != 0 && str_src<K>::traits::find(symbols.str, symbols.len, s) !=
nullptr;
4395template<
typename K,
size_t N>
4396struct CheckConstSymbolsTrim {
4397 const const_lit_to_array<K, N> symbols;
4399 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
4400 constexpr CheckConstSymbolsTrim(T&& s) : symbols(std::forward<T>(s)) {}
4402 constexpr bool is_trim_symbols(K s)
const noexcept {
4403 return symbols.contain(s);
4408struct CheckConstSymbolsTrim<K, 0> {
4409 constexpr bool is_trim_symbols(K)
const {
4414template<
typename K,
size_t N>
4415struct SymbSelector {
4416 using type = CheckConstSymbolsTrim<K, N>;
4420struct SymbSelector<K, 0> {
4421 using type = CheckSymbolsTrim<K>;
4425struct SymbSelector<K, static_cast<size_t>(-1)> {
4426 using type = CheckConstSymbolsTrim<K, 0>;
4429template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces>
4430struct trim_operator : SymbSelector<K, N>::type, CheckSpaceTrim<K, withSpaces> {
4431 constexpr bool isTrim(K s)
const {
4432 return CheckSpaceTrim<K, withSpaces>::is_trim_spaces(s) || SymbSelector<K, N>::type::is_trim_symbols(s);
4434 constexpr str_src<K> operator()(str_src<K> from)
const {
4435 if constexpr ((S & TrimSides::TrimLeft) != 0) {
4437 if (isTrim(*from.str)) {
4444 if constexpr ((S & TrimSides::TrimRight) != 0) {
4445 const K* back = from.str + from.len - 1;
4447 if (isTrim(*back)) {
4458template<TrimS
ides S,
typename K>
4459using SimpleTrim = trim_operator<S, K, size_t(-1),
true>;
4461template<TrimSides S = TrimSides::TrimAll, bool withSpaces = false, typename K, typename T, size_t N = const_lit_for<K, T>::Count>
4462 requires is_const_pattern<N>
4463constexpr inline auto trimOp(T&& pattern) {
4464 return trim_operator<S, K, N - 1, withSpaces>{pattern};
4467template<TrimS
ides S = TrimS
ides::TrimAll,
bool withSpaces = false,
typename K>
4468constexpr inline auto trimOp(str_src<K> pattern) {
4469 return trim_operator<S, K, 0, withSpaces>{pattern};
4472static constexpr size_t FIND_CACHE_SIZE = 16;
4474template<
typename K,
size_t N,
size_t L>
4475struct expr_replaces : expr_to_std_string<expr_replaces<K, N, L>> {
4476 using symb_type = K;
4477 using my_type = expr_replaces<K, N, L>;
4479 const K(&pattern)[N + 1];
4480 const K(&repl)[L + 1];
4481 mutable find_all_container<FIND_CACHE_SIZE> matches_;
4482 mutable size_t last_;
4484 constexpr expr_replaces(str_src<K> w,
const K(&p)[N + 1],
const K(&r)[L + 1]) : what(w), pattern(p), repl(r) {}
4486 constexpr size_t length()
const {
4487 size_t l = what.length();
4488 if constexpr (N == L) {
4491 what.find_all_to(matches_, pattern, N, 0, FIND_CACHE_SIZE);
4492 if (matches_.added_) {
4493 last_ = matches_.positions_[matches_.added_ - 1] + N;
4494 l += int(L - N) * matches_.added_;
4496 if (matches_.added_ == FIND_CACHE_SIZE) {
4498 size_t next = what.find(pattern, N, last_);
4499 if (next == str::npos) {
4508 matches_.added_ = -1;
4512 constexpr K* place(K* ptr)
const noexcept {
4513 if constexpr (N == L) {
4514 const K* from = what.symbols();
4515 for (
size_t start = 0; start < what.length();) {
4516 size_t next = what.find(pattern, N, start);
4517 if (next == str::npos) {
4518 next = what.length();
4520 size_t delta = next - start;
4521 ch_traits<K>::copy(ptr, from + start, delta);
4523 ch_traits<K>::copy(ptr, repl, L);
4529 if (matches_.added_ == 0) {
4530 return what.place(ptr);
4531 }
else if (matches_.added_ == -1) {
4535 const K* from = what.symbols();
4536 for (
size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
4537 ch_traits<K>::copy(ptr, from + start, offset - start);
4538 ptr += offset - start;
4539 ch_traits<K>::copy(ptr, repl, L);
4542 if (start >= last_) {
4543 size_t tail = what.length() - last_;
4544 ch_traits<K>::copy(ptr, from + last_, tail);
4548 offset = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern, N, start);
4568template<StrSource A,
typename K = symb_type_from_src_t<A>,
typename T,
size_t N = const_lit_for<K, T>::Count,
typename X,
size_t L = const_lit_for<K, X>::Count>
4571 return expr_replaces<K, N - 1, L - 1>{std::forward<A>(w), p, r};
4583 using symb_type = K;
4588 mutable find_all_container<FIND_CACHE_SIZE> matches_;
4589 mutable size_t last_;
4602 constexpr size_t length()
const {
4604 if (!plen || plen == rlen) {
4607 what.find_all_to(matches_, pattern.
symbols(), plen, 0, FIND_CACHE_SIZE);
4608 if (matches_.added_) {
4609 last_ = matches_.positions_[matches_.added_ - 1] + plen;
4610 l += int(rlen - plen) * matches_.added_;
4612 if (matches_.added_ == FIND_CACHE_SIZE) {
4614 size_t next = what.find(pattern.
symbols(), plen, last_);
4615 if (next == str::npos) {
4618 last_ = next + plen;
4624 matches_.added_ = -1;
4628 constexpr K* place(K* ptr)
const noexcept {
4631 const K* from = what.
symbols();
4632 for (
size_t start = 0; start < what.
length();) {
4633 size_t next = what.find(pattern, start);
4634 if (next == str::npos) {
4637 size_t delta = next - start;
4638 ch_traits<K>::copy(ptr, from + start, delta);
4640 ch_traits<K>::copy(ptr, repl.
symbols(), rlen);
4642 start = next + plen;
4646 if (matches_.added_ == 0) {
4647 return what.
place(ptr);
4648 }
else if (matches_.added_ == -1) {
4652 const K* from = what.
symbols();
4653 for (
size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
4654 ch_traits<K>::copy(ptr, from + start, offset - start);
4655 ptr += offset - start;
4656 ch_traits<K>::copy(ptr, repl.
symbols(), rlen);
4658 start = offset + plen;
4659 if (start >= last_) {
4660 size_t tail = what.
length() - start;
4661 ch_traits<K>::copy(ptr, from + start, tail);
4665 offset = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern.
symbols(), plen, start);
4687template<
typename K, StrExprForType<K> E>
4689 using symb_type = K;
4693 mutable size_t replLen;
4694 mutable find_all_container<FIND_CACHE_SIZE> matches_;
4695 mutable size_t last_;
4709 constexpr size_t length()
const {
4714 matches_.positions_[0] = what.find(pattern);
4715 if (matches_.positions_[0] == -1) {
4719 matches_.added_ = 1;
4721 replLen = expr.length();
4722 if (replLen == plen) {
4726 what.find_all_to(matches_, pattern.
symbols(), plen, matches_.positions_[0] + plen, FIND_CACHE_SIZE - 1);
4728 last_ = matches_.positions_[matches_.added_ - 1] + plen;
4729 l += int(replLen - plen) * matches_.added_;
4731 if (matches_.added_ == FIND_CACHE_SIZE) {
4733 size_t next = what.find(pattern.
symbols(), plen, last_);
4734 if (next == str::npos) {
4737 last_ = next + plen;
4738 l += replLen - plen;
4742 matches_.added_ = -1;
4746 constexpr K* place(K* ptr)
const noexcept {
4747 if (matches_.added_ == 0) {
4749 return what.
place(ptr);
4750 }
else if (matches_.added_ == -1) {
4754 size_t plen = pattern.
length();
4755 const K* from = what.
symbols();
4756 ch_traits<K>::copy(ptr, from, matches_.positions_[0]);
4757 ptr += matches_.positions_[0];
4758 const K* repl = ptr;
4759 expr.
place((
typename E::symb_type*)ptr);
4761 size_t start = matches_.positions_[0] + plen;
4763 if (plen == replLen) {
4765 size_t next = what.find(pattern, start);
4766 if (next == str::npos) {
4769 size_t delta = next - start;
4770 ch_traits<K>::copy(ptr, from + start, delta);
4772 ch_traits<K>::copy(ptr, repl, replLen);
4774 start = next + plen;
4777 for (
size_t idx = 1;;) {
4778 if (start >= last_) {
4781 size_t next = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern, start);
4782 size_t delta = next - start;
4783 ch_traits<K>::copy(ptr, from + start, delta);
4785 ch_traits<K>::copy(ptr, repl, replLen);
4787 start = next + plen;
4790 size_t tail = what.
length() - start;
4791 ch_traits<K>::copy(ptr, from + start, tail);
4809template<StrSource A,
typename K = symb_type_from_src_t<A>,
typename T,
typename X>
4810 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>))
4830template<StrSource A,
typename K = symb_type_from_src_t<A>,
typename T, StrExprForType<K> E>
4831 requires std::is_constructible_v<str_src<K>, T>
4832constexpr auto e_repl(A&& w, T&& p,
const E& expr) {
4837template<
bool UseVectorForReplace>
4838struct replace_search_result_store {
4840 std::pair<size_t, size_t> replaces_[16];
4844struct replace_search_result_store<true> : std::vector<std::pair<size_t, size_t>> {};
4848template<
typename K,
size_t N,
bool UseVectorForReplace>
4849struct expr_replace_const_symbols : expr_to_std_string<expr_replace_const_symbols<K, N, UseVectorForReplace>> {
4850 using symb_type = K;
4851 inline static const int BIT_SEARCH_TRESHHOLD = 4;
4852 const K pattern_[N];
4853 const str_src<K> source_;
4854 const str_src<K> replaces_[N];
4856 mutable replace_search_result_store<UseVectorForReplace> search_results_;
4858 [[_no_unique_address]]
4859 uu8s bit_mask_[N >= BIT_SEARCH_TRESHHOLD ? (
sizeof(K) == 1 ? 32 : 64) : 0]{};
4861 template<
typename ... Repl>
requires (
sizeof...(Repl) == N * 2)
4862 constexpr expr_replace_const_symbols(str_src<K> source, Repl&& ... repl) : expr_replace_const_symbols(0, source, std::forward<Repl>(repl)...) {}
4864 size_t length()
const {
4865 size_t l = source_.length();
4866 auto [fnd, num] = find_first_of(source_.str, source_.len);
4867 if (fnd == str::npos) {
4870 l += replaces_[num].len - 1;
4871 if constexpr (UseVectorForReplace) {
4872 search_results_.reserve((l >> 4) + 8);
4873 search_results_.emplace_back(fnd, num);
4874 for (
size_t start = fnd + 1;;) {
4875 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
4876 if (fnd == str::npos) {
4879 search_results_.emplace_back(fnd, idx);
4881 l += replaces_[idx].len - 1;
4884 const size_t max_store = std::size(search_results_.replaces_);
4885 search_results_.replaces_[0] = {fnd, num};
4886 search_results_.count_++;
4887 for (
size_t start = fnd + 1;;) {
4888 auto [found, idx] = find_first_of(source_.str, source_.len, start);
4889 if (found == str::npos) {
4892 if (search_results_.count_ < max_store) {
4893 search_results_.replaces_[search_results_.count_] = {found, idx};
4895 l += replaces_[idx].len - 1;
4896 search_results_.count_++;
4902 K* place(K* ptr)
const noexcept {
4904 const K* text = source_.str;
4905 if constexpr (UseVectorForReplace) {
4906 for (
const auto& [pos, num] : search_results_) {
4907 size_t delta = pos - start;
4908 ch_traits<K>::copy(ptr, text + start, delta);
4910 ptr = replaces_[num].place(ptr);
4914 const size_t max_store = std::size(search_results_.replaces_);
4915 size_t founded = search_results_.count_;
4916 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
4917 const auto [pos, num] = search_results_.replaces_[idx];
4918 size_t delta = pos - start;
4919 ch_traits<K>::copy(ptr, text + start, delta);
4921 ptr = replaces_[num].place(ptr);
4924 if (founded > max_store) {
4925 founded -= max_store;
4927 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
4928 size_t delta = fnd - start;
4929 ch_traits<K>::copy(ptr, text + start, delta);
4931 ptr = replaces_[idx].place(ptr);
4936 size_t tail = source_.len - start;
4937 ch_traits<K>::copy(ptr, text + start, tail);
4942 template<
typename ... Repl>
4943 constexpr expr_replace_const_symbols(
int, str_src<K> source, K s, str_src<K> r, Repl&&... repl) :
4944 expr_replace_const_symbols(0, source, std::forward<Repl>(repl)..., std::make_pair(s, r)){}
4946 template<
typename ... Repl>
requires (
sizeof...(Repl) == N)
4947 constexpr expr_replace_const_symbols(
int, str_src<K> source, Repl&&... repl) :
4948 source_(source), pattern_ {repl.first...}, replaces_{repl.second...}
4950 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
4951 for (
size_t idx = 0; idx < N; idx++) {
4952 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
4953 if constexpr (
sizeof(K) == 1) {
4954 bit_mask_[s >> 3] |= 1 << (s & 7);
4956 if (std::make_unsigned_t<const K>(pattern_[idx]) > 255) {
4957 bit_mask_[32 + (s >> 3)] |= 1 << (s & 7);
4959 bit_mask_[s >> 3] |= 1 << (s & 7);
4966 template<
size_t Idx>
4967 size_t index_of(K s)
const {
4968 if constexpr (Idx < N) {
4969 return pattern_[Idx] == s ? Idx : index_of<Idx + 1>(s);
4973 bool is_in_mask(uu8s s)
const {
4974 return (bit_mask_[s >> 3] & (1 <<(s & 7))) != 0;
4976 bool is_in_mask2(uu8s s)
const {
4977 return (bit_mask_[32 + (s >> 3)] & (1 <<(s & 7))) != 0;
4979 bool is_in_pattern(K s,
size_t& idx)
const {
4980 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
4981 if constexpr (
sizeof(K) == 1) {
4982 if (is_in_mask(s)) {
4983 idx = index_of<0>(s);
4987 if (std::make_unsigned_t<const K>(s) > 255) {
4988 if (is_in_mask2(s)) {
4989 return (idx = index_of<0>(s)) != -1;
4992 if (is_in_mask(s)) {
4993 idx = index_of<0>(s);
5001 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
5002 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
5004 while (offset < len) {
5005 if (is_in_pattern(text[offset], idx)) {
5006 return {offset, idx};
5011 while (offset < len) {
5012 if (
size_t idx = index_of<0>(text[offset]); idx != -1) {
5013 return {offset, idx};
5061template<
bool UseVector = false, StrSource A,
typename K = symb_type_from_src_t<A>,
typename ... Repl>
5062 requires (
sizeof...(Repl) % 2 == 0)
5064 return expr_replace_const_symbols<K,
sizeof...(Repl) / 2, UseVector>(std::forward<A>(src), std::forward<Repl>(other)...);
5106template<
typename K,
bool UseVectorForReplace = false>
5108 using symb_type = K;
5109 using str_t =
typename simple_str_selector<K>::type;
5110 inline static const int BIT_SEARCH_TRESHHOLD = 4;
5113 const std::vector<std::pair<K, str_t>>& replaces_;
5115 std::basic_string<K, ch_traits<K>, std::allocator<K>> pattern_;
5117 mutable replace_search_result_store<UseVectorForReplace> search_results_;
5119 uu8s bit_mask_[
sizeof(K) == 1 ? 32 : 64]{};
5148 : source_(source), replaces_(repl)
5150 size_t pattern_len = replaces_.size();
5151 pattern_.resize(pattern_len);
5152 K* pattern = pattern_.data();
5154 for (
size_t idx = 0; idx < replaces_.size(); idx++) {
5155 *pattern++ = replaces_[idx].first;
5158 if (pattern_len >= BIT_SEARCH_TRESHHOLD) {
5159 for (
size_t idx = 0; idx < pattern_len; idx++) {
5160 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
5161 if constexpr (
sizeof(K) == 1) {
5162 bit_mask_[s >> 3] |= (1 << (s & 7));
5164 if (std::make_unsigned_t<K>(pattern_[idx]) > 255) {
5165 bit_mask_[32 + (s >> 3)] |= (1 << (s & 7));
5167 bit_mask_[s >> 3] |= (1 << (s & 7));
5174 size_t length()
const {
5175 size_t l = source_.
length();
5176 auto [fnd, num] = find_first_of(source_.str, source_.len);
5177 if (fnd == str::npos) {
5180 l += replaces_[num].second.len - 1;
5181 if constexpr (UseVectorForReplace) {
5182 search_results_.reserve((l >> 4) + 8);
5183 search_results_.emplace_back(fnd, num);
5184 for (
size_t start = fnd + 1;;) {
5185 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5186 if (fnd == str::npos) {
5189 search_results_.emplace_back(fnd, idx);
5191 l += replaces_[idx].second.len - 1;
5194 const size_t max_store = std::size(search_results_.replaces_);
5195 search_results_.replaces_[0] = {fnd, num};
5196 search_results_.count_++;
5197 for (
size_t start = fnd + 1;;) {
5198 auto [found, idx] = find_first_of(source_.str, source_.len, start);
5199 if (found == str::npos) {
5202 if (search_results_.count_ < max_store) {
5203 search_results_.replaces_[search_results_.count_] = {found, idx};
5205 l += replaces_[idx].second.len - 1;
5206 search_results_.count_++;
5212 K* place(K* ptr)
const noexcept {
5214 const K* text = source_.str;
5215 if constexpr (UseVectorForReplace) {
5216 for (
const auto& [pos, num] : search_results_) {
5217 size_t delta = pos - start;
5218 ch_traits<K>::copy(ptr, text + start, delta);
5220 ptr = replaces_[num].second.place(ptr);
5224 const size_t max_store = std::size(search_results_.replaces_);
5225 size_t founded = search_results_.count_;
5226 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
5227 const auto [pos, num] = search_results_.replaces_[idx];
5228 size_t delta = pos - start;
5229 ch_traits<K>::copy(ptr, text + start, delta);
5231 ptr = replaces_[num].second.place(ptr);
5234 if (founded > max_store) {
5235 founded -= max_store;
5237 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
5238 size_t delta = fnd - start;
5239 ch_traits<K>::copy(ptr, text + start, delta);
5241 ptr = replaces_[idx].second.place(ptr);
5246 size_t tail = source_.len - start;
5247 ch_traits<K>::copy(ptr, text + start, tail);
5252 size_t index_of(K s)
const {
5253 return pattern_.find(s);
5256 bool is_in_mask(uu8s s)
const {
5257 return (bit_mask_[s >> 3] & (1 << (s & 7))) != 0;
5259 bool is_in_mask2(uu8s s)
const {
5260 return (bit_mask_[32 + (s >> 3)] & (1 << (s & 7))) != 0;
5263 bool is_in_pattern(K s,
size_t& idx)
const {
5264 if constexpr (
sizeof(K) == 1) {
5265 if (is_in_mask(s)) {
5270 if (std::make_unsigned_t<const K>(s) > 255) {
5271 if (is_in_mask2(s)) {
5272 return (idx = index_of(s)) != -1;
5275 if (is_in_mask(s)) {
5284 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
5285 size_t pl = pattern_.length();
5286 if (pl >= BIT_SEARCH_TRESHHOLD) {
5288 while (offset < len) {
5289 if (is_in_pattern(text[offset], idx)) {
5290 return {offset, idx};
5295 while (offset < len) {
5296 if (
size_t idx = index_of(text[offset]); idx != -1) {
5297 return {offset, idx};
5306template<
typename K, StrExprForType<K> T>
5309 force_copy(
const T& t) : t_(t){}
5312template<
typename K,
typename T>
5313struct symb_type_from_src<force_copy<K, T>> {
5319force_copy(T&&) -> force_copy<typename T::symb_type, T>;
5321template<
typename K,
typename T>
5322constexpr auto to_subst(T&& t) {
5323 return to_strexpr<K>(std::forward<T>(t));
5326template<
typename K,
typename T,
size_t N>
5327constexpr auto to_subst(
const T(&t)[N]) {
5328 return expr_literal<T, N - 1>{t};
5331template<
typename K, StrExprForType<K> T>
5332constexpr decltype(
auto) to_subst(T&& t) {
5333 return std::forward<T>(t);
5336template<
typename K,
typename T>
5337constexpr T to_subst(
const force_copy<K, T>& t) {
5341template<
typename K,
typename T>
5342constexpr T to_subst(force_copy<K, T>&& t) {
5346template<
typename K,
typename T>
5347constexpr T to_subst(force_copy<K, T>& t) {
5351template<
typename K,
typename T>
5352using to_str_exp_t =
decltype(to_subst<K>(std::declval<T>()));
5365template<
typename K,
typename G,
typename Arg,
typename...Args>
5367 using symb_type = K;
5368 using store_t = std::tuple<Args...>;
5372 mutable size_t glue_len_;
5374 constexpr expr_concat(G&& glue, Arg&& arg, Args&&...args) : glue_(std::forward<G>(glue)), arg_(std::forward<Arg>(arg)), args_(std::forward<Args>(args)...) {}
5376 constexpr size_t length()
const noexcept {
5377 return [
this]<
size_t...Indexes>(std::index_sequence<Indexes...>) {
5378 glue_len_ = glue_.length();
5379 size_t l = arg_.length() + glue_len_ *
sizeof...(Args);
5380 ((l += std::get<Indexes>(args_).length()),...);
5382 }(std::make_index_sequence<
sizeof...(Args)>());
5384 constexpr K* place(K* ptr)
const noexcept {
5385 return [
this]<
size_t...Indexes>(K* ptr, std::index_sequence<Indexes...>) {
5386 ptr = (K*)arg_.place((
typename std::remove_cvref_t<Arg>::symb_type*)ptr);
5387 const K* glueStart = ptr;
5388 ptr = glue_.place(ptr);
5391 ptr = (K*)std::get<Indexes>(args_).place((
typename std::remove_cvref_t<std::tuple_element_t<Indexes, store_t>>::symb_type*)ptr),
5392 glue_len_ > 0 && Indexes <
sizeof...(Args) - 1 ? (ch_traits<K>::copy(ptr, glueStart, glue_len_), ptr += glue_len_) :
nullptr
5396 }(ptr, std::make_index_sequence<
sizeof...(Args)>());
5440template<
typename T,
typename K = symb_type_from_src_t<T>,
typename ... Args>
requires (
sizeof...(Args) > 1)
5442 return { to_subst<K>(std::forward<T>(glue)), to_subst<K>(std::forward<Args>(args))...};
5447template<
typename K,
typename Pt,
typename...Args>
5448struct subst_params {
5449 struct parse_subst_string_error {
5450 parse_subst_string_error(
const char*){}
5456 unsigned is_param: 1;
5458 portion() =
default;
5460 constexpr void set_param(
unsigned param) {
5461 if (param >= (1 << 16)) {
5462 throw parse_subst_string_error{
"the parameter id is too large"};
5467 constexpr void set_part(
unsigned from,
unsigned l) {
5468 if (from >= (1 << 16) || len >= (1 << 15)) {
5469 throw parse_subst_string_error{
"the string part is too large"};
5477 inline static constexpr size_t NParams =
sizeof...(Args);
5478 inline static constexpr size_t PtLen = const_lit<Pt>::Count;
5481 unsigned all_len_{};
5485 portion portions_[2 + PtLen / 3 * 2]{};
5487 consteval subst_params(Pt&& pattern) : source_(pattern) {
5488 const K* first = pattern;
5489 const K* last = first + PtLen - 1;
5490 char used_args[NParams] = {0};
5492 auto find = [](
const K* from,
const K* last, K s) {
5493 while (from != last) {
5501 size_t idx_in_data = 0, idx_in_params = 0;
5503 while (first != last) {
5505 const K* open_pos = first;
5506 if (*first !=
'{') {
5507 open_pos = find(first, last,
'{');
5510 const K* close_pos = find(first, open_pos,
'}');
5511 if (close_pos == open_pos) {
5512 if (open_pos < last && open_pos[1] ==
'{') {
5513 unsigned len = open_pos - first + 1;
5514 portions_[idx_in_data++].set_part(first - pattern, len);
5516 first = open_pos + 2;
5518 }
else if (
unsigned len = open_pos - first) {
5519 portions_[idx_in_data++].set_part(first - pattern, len);
5525 if (close_pos == open_pos || *close_pos !=
'}') {
5526 throw parse_subst_string_error{
"unescaped }"};
5528 unsigned len = close_pos - first;
5529 portions_[idx_in_data++].set_part(first - pattern, len);
5531 first = ++close_pos;
5533 if (open_pos == last) {
5541 if (++open_pos == last) {
5542 throw parse_subst_string_error{
"unescaped {"};
5544 if (*open_pos ==
'}') {
5545 if (idx_in_params == -1) {
5546 throw parse_subst_string_error{
"already used param ids"};
5548 used_args[idx_in_params]++;
5549 portions_[idx_in_data++].set_param(idx_in_params++);
5550 first = open_pos + 1;
5551 }
else if (*open_pos ==
'{') {
5552 portions_[idx_in_data++].set_part(open_pos - pattern, 1);
5554 first = open_pos + 1;
5556 if (idx_in_params != 0 && idx_in_params != -1) {
5557 throw parse_subst_string_error{
"already used non id params"};
5560 const K* end = find(open_pos, last,
'}');
5562 throw parse_subst_string_error{
"not found }"};
5564 auto [p, err, _] = str_src<K>(open_pos, end - open_pos).template to_int<unsigned, true, 10, false, false>();
5565 if (err != IntConvertResult::Success || p < 1 || p > NParams) {
5566 throw parse_subst_string_error{
"bad param id"};
5569 portions_[idx_in_data++].set_param(p);
5573 for (
auto c : used_args) {
5575 throw parse_subst_string_error{
"unused param"};
5578 actual_ = idx_in_data;
5584template<
typename K,
typename Pt,
typename ... Args>
5585struct expr_subst : expr_to_std_string<expr_subst<K, Pt, Args...>> {
5586 inline static constexpr size_t Nparams =
sizeof...(Args);
5587 using symb_type = K;
5588 using store_t = std::tuple<to_str_exp_t<K, Args>...>;
5590 const details::subst_params<K, Pt, Args...>& subst_;
5593 constexpr expr_subst(
const details::subst_params<K, Pt, Args...>& subst, Args&&...args)
5595 , args_(to_subst<K>(std::forward<Args>(args))...){}
5597 constexpr size_t length() const noexcept {
5598 return [
this]<
size_t...Indexes>(std::index_sequence<Indexes...>) {
5600 size_t expr_length_[Nparams] = {};
5601 ((expr_length_[idx++] = std::get<Indexes>(args_).length()),...);
5602 size_t l = subst_.all_len_;
5603 for (idx = 0; idx < subst_.actual_; idx++) {
5604 if (subst_.portions_[idx].is_param) {
5605 l += expr_length_[subst_.portions_[idx].start];
5609 }(std::make_index_sequence<
sizeof...(Args)>());
5611 template<
size_t Idx>
5612 constexpr K* place_idx(K* ptr,
size_t idx)
const noexcept {
5614 return (K*)std::get<Idx>(args_).place((
typename std::remove_cvref_t<std::tuple_element_t<Idx, store_t>>::symb_type*)ptr);
5616 if constexpr (Idx < Nparams - 1) {
5617 return place_idx<Idx + 1>(ptr, idx);
5622 constexpr K* place(K* ptr)
const noexcept {
5623 for (
size_t idx = 0; idx < subst_.actual_; idx++) {
5624 if (subst_.portions_[idx].is_param) {
5625 ptr = place_idx<0>(ptr, subst_.portions_[idx].start);
5627 ch_traits<K>::copy(ptr, subst_.source_ + subst_.portions_[idx].start, subst_.portions_[idx].len);
5628 ptr += subst_.portions_[idx].len;
5685template<
typename T,
typename...Args>
requires (
sizeof...(Args) > 0)
5686constexpr auto e_subst(T&& str_pattern,
const details::subst_params<
typename const_lit<T>::symb_type, std::type_identity_t<T>, std::type_identity_t<Args>...>& pattern, Args&&...args) {
5687 return expr_subst<typename const_lit<T>::symb_type, T, Args...>{pattern, std::forward<Args>(args)...};
5690#define S_FRM(s) s, s
5730template<
typename K,
typename A, StrExprForType<K> E>
5731std::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) {
5732 size_t expr_length = expr.length();
5734 str.erase(from, count);
5737 size_t str_length =
str.length();
5738 if (from > str_length) {
5741 if (from + count > str_length) {
5742 count = str_length - from;
5744 size_t new_length = str_length - count + expr_length;
5745 size_t tail_length = str_length - count - from;
5747 if (new_length <= str_length) {
5748 K* data =
str.data();
5749 expr.place((
typename E::symb_type*)data + from);
5750 if (expr_length < count) {
5752 std::char_traits<K>::move(data + from + expr_length, data + from + count, tail_length);
5754 str.resize(new_length);
5757 auto fill = [&](K* data, size_t) ->
size_t {
5759 std::char_traits<K>::move(data + from + expr_length, data + from + count, tail_length);
5761 expr.place((
typename E::symb_type*)data + from);
5764 if constexpr (
requires{
str.resize_and_overwrite(new_length, fill);}) {
5765 str.resize_and_overwrite(new_length, fill);
5766 }
else if constexpr (
requires{
str._Resize_and_overwrite(new_length, fill);}) {
5767 str._Resize_and_overwrite(new_length, fill);
5769 str.resize(new_length);
5770 fill(
str.data(), 0);
5803template<
typename K,
typename A, StrExprForType<K> E>
5804std::basic_string<K, std::char_traits<K>, A>&
append(std::basic_string<K, std::char_traits<K>, A>&
str,
const E& expr) {
5836template<
typename K,
typename A, StrExprForType<K> E>
5837std::basic_string<K, std::char_traits<K>, A>&
prepend(std::basic_string<K, std::char_traits<K>, A>&
str,
const E& expr) {
5871template<
typename K,
typename A, StrExprForType<K> E>
5872std::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) {
5878template<
typename K,
typename A,
typename E>
5879struct replace_grow_helper {
5880 using my_type = std::basic_string<K, std::char_traits<K>, A>;
5882 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)
5883 :
str(src), source(src), pattern(p), repl(const_cast<K*>(r)), replLen(rl), maxCount(mc), delta(d), expr(e) {}
5886 const str_src<K> source;
5887 const str_src<K> pattern;
5889 const size_t replLen;
5896 K* reserve_for_copy{};
5897 size_t end_of_piece{};
5898 size_t total_length{};
5900 std::optional<my_type> dst;
5903 size_t found[16] = {offset};
5906 offset += pattern.len;
5909 for (; idx < std::size(found) && maxCount > 0; idx++, maxCount--) {
5910 found[idx] = source.find(pattern, offset);
5911 if (found[idx] == npos) {
5914 offset = found[idx] + pattern.len;
5917 if (idx == std::size(found) && maxCount > 0 && (offset = source.find(pattern, offset)) != str::npos) {
5922 if (!reserve_for_copy) {
5925 end_of_piece = source.length();
5926 total_length = end_of_piece + all_delta;
5928 if (total_length <= str.capacity()) {
5933 dst_str = &dst.emplace();
5935 auto fill = [
this](K* p, size_t) ->
size_t {
5936 reserve_for_copy = p;
5937 return total_length;
5939 if constexpr (
requires{dst_str->_Resize_and_overwrite(total_length, fill);}) {
5940 dst_str->_Resize_and_overwrite(total_length, fill);
5941 }
else if constexpr (
requires{dst_str->resize_and_overwrite(total_length, fill);}) {
5942 dst_str->resize_and_overwrite(total_length, fill);
5944 dst_str->resize(total_length);
5945 reserve_for_copy = dst_str->data();
5948 const K* src_start = str.c_str();
5950 size_t pos = found[idx] + pattern.len;
5951 size_t lenOfPiece = end_of_piece - pos;
5952 ch_traits<K>::move(reserve_for_copy + pos + all_delta, src_start + pos, lenOfPiece);
5953 if constexpr (std::is_same_v<E, int>) {
5954 ch_traits<K>::copy(reserve_for_copy + pos + all_delta - replLen, repl, replLen);
5957 repl = reserve_for_copy + pos + all_delta - replLen;
5960 ch_traits<K>::copy(reserve_for_copy + pos + all_delta - replLen, repl, replLen);
5964 end_of_piece = found[idx];
5966 if (!all_delta && reserve_for_copy != src_start) {
5967 ch_traits<K>::copy(reserve_for_copy, src_start, found[0]);
5968 str = std::move(*dst);
6009template<
typename K,
typename A, StrExprForType<K> E,
typename T>
6010requires (std::is_constructible_v<str_src<K>, T>)
6011std::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) {
6016 str_src<K> spattern{std::forward<T>(pattern)};
6017 offset = src.find(pattern, offset);
6018 if (offset == npos) {
6021 size_t replLen = repl.length();
6023 if (spattern.len == replLen) {
6026 K* ptr =
str.data();
6027 replStart = ptr + offset;
6028 repl.place(replStart);
6030 while (--max_count) {
6031 offset = src.find(spattern, offset + replLen);
6034 ch_traits<K>::copy(ptr + offset, replStart, replLen);
6036 }
else if (spattern.len > replLen) {
6039 K* ptr =
str.data();
6040 replStart = ptr + offset;
6041 repl.place(replStart);
6042 size_t posWrite = offset + replLen;
6043 offset += spattern.len;
6045 while (--max_count) {
6046 size_t idx = src.find(spattern, offset);
6049 size_t lenOfPiece = idx - offset;
6050 ch_traits<K>::move(ptr + posWrite, ptr + offset, lenOfPiece);
6051 posWrite += lenOfPiece;
6052 ch_traits<K>::copy(ptr + posWrite, replStart, replLen);
6053 posWrite += replLen;
6054 offset = idx + spattern.len;
6056 size_t tailLen = src.len - offset;
6057 ch_traits<K>::move(ptr + posWrite, ptr + offset, tailLen);
6058 str.resize(posWrite + tailLen);
6060 details::replace_grow_helper<K, A, E>(
str, spattern,
nullptr, replLen, max_count, replLen - spattern.len, repl).replace(offset);
6085template<
typename K,
typename A>
6086std::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) {
6091 offset = src.find(pattern, offset);
6092 if (offset == npos) {
6095 if (pattern.len == repl.len) {
6098 K* ptr =
str.data();
6099 while (max_count--) {
6100 ch_traits<K>::copy(ptr + offset, repl.str, repl.len);
6101 offset = src.find(pattern, offset + repl.len);
6105 }
else if (pattern.len > repl.len) {
6108 K* ptr =
str.data();
6109 ch_traits<K>::copy(ptr + offset, repl.str, repl.len);
6110 size_t posWrite = offset + repl.len;
6111 offset += pattern.len;
6113 while (--max_count) {
6114 size_t idx = src.find(pattern, offset);
6117 size_t lenOfPiece = idx - offset;
6118 ch_traits<K>::move(ptr + posWrite, ptr + offset, lenOfPiece);
6119 posWrite += lenOfPiece;
6120 ch_traits<K>::copy(ptr + posWrite, repl.str, repl.len);
6121 posWrite += repl.len;
6122 offset = idx + pattern.len;
6124 size_t tailLen = src.len - offset;
6125 ch_traits<K>::move(ptr + posWrite, ptr + offset, tailLen);
6126 str.resize(posWrite + tailLen);
6128 details::replace_grow_helper<K, A, int>(
str, pattern, repl.str, repl.len, max_count, repl.len - pattern.len, 0).replace(offset);
6133template<
typename K,
typename A,
typename T,
typename M>
6134requires (std::is_constructible_v<str_src<K>, T> && std::is_constructible_v<str_src<K>, M>)
6135std::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) {
6136 return replace(
str,
str_src<K>{std::forward<T>(pattern)}, str_src<K>{std::forward<M>(repl)}, offset, max_count);
6163template<simstr::StdStrSource T>
6196template<
typename K,
typename A, simstr::StrExprForType<K> E>
6197std::basic_string<K, std::char_traits<K>, A>& operator |=(std::basic_string<K, std::char_traits<K>, A>& str,
const E& expr) {
6229template<
typename K,
typename A, simstr::StrExprForType<K> E>
6230std::basic_string<K, std::char_traits<K>, A>& operator ^=(std::basic_string<K, std::char_traits<K>, A>& str,
const E& expr) {
Класс для последовательного получения подстрок по заданному разделителю.
Определения strexpr.h:2466
constexpr bool is_done() const
Узнать, не закончились ли подстроки.
Определения strexpr.h:2477
constexpr str_t next()
Получить следующую подстроку.
Определения strexpr.h:2486
std::optional< double > to_double_hex() const noexcept
Преобразовать строку в 16ричной записи в double. Пока работает только для char.
Определения strexpr.h:3412
constexpr size_t find_last(K s, size_t offset=-1) const noexcept
Найти последнее вхождения символа в этой строке.
Определения strexpr.h:3192
R trimmed_right() const
Получить строку с удалением пробельных символов справа.
Определения strexpr.h:3794
constexpr int compare_ia(str_piece text) const noexcept
Сравнение строк посимвольно без учёта регистра ASCII символов.
Определения strexpr.h:2874
constexpr int compare(str_piece o) const
Сравнение строк посимвольно.
Определения strexpr.h:2759
constexpr size_t find(K s, size_t offset=0) const noexcept
Найти символ в этой строке.
Определения strexpr.h:3096
constexpr bool ends_with(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой.
Определения strexpr.h:3624
R trimmed(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, слева и справа.
Определения strexpr.h:3916
R trimmed_left(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, слева.
Определения strexpr.h:3930
constexpr bool operator==(const base &other) const noexcept
Оператор сравнение строк на равенство.
Определения strexpr.h:2810
constexpr std::basic_string_view< D > to_sv() const noexcept
Конвертировать в std::basic_string_view.
Определения strexpr.h:2606
R trimmed_left() const
Получить строку с удалением пробельных символов слева.
Определения strexpr.h:3782
constexpr size_t find_end_or_all(str_piece pattern, size_t offset=0) const noexcept
Найти конец первого вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:2992
constexpr bool starts_with(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки.
Определения strexpr.h:3566
constexpr bool equal(str_piece other) const noexcept
Сравнение строк на равенство.
Определения strexpr.h:2799
void copy_to(K *buffer, size_t bufSize)
Копировать строку в указанный буфер.
Определения strexpr.h:2584
constexpr size_t find_or_throw(str_piece pattern, size_t offset=0, Args &&... args) const noexcept
Найти начало первого вхождения подстроки в этой строке или выкинуть исключение.
Определения strexpr.h:2948
constexpr T as_int() const noexcept
Преобразовать строку в число заданного типа.
Определения strexpr.h:3338
constexpr bool less_ia(str_piece text) const noexcept
Меньше ли строка другой строки посимвольно без учёта регистра ASCII символов.
Определения strexpr.h:2897
constexpr T split(str_piece delimiter, size_t offset=0) const
Разделить строку на подстроки по заданному разделителю.
Определения strexpr.h:3551
constexpr str_piece mid(size_t from, size_t len=-1) const noexcept
Получить часть строки как "кусок строки".
Определения strexpr.h:2699
constexpr my_type substr(ptrdiff_t from, ptrdiff_t len=0) const
Получить подстроку. Работает аналогично operator(), только результат выдает того же типа,...
Определения strexpr.h:3293
R upperred_only_ascii() const
Получить копию строки в верхнем регистре ASCII символов.
Определения strexpr.h:3701
constexpr str_piece to_str() const noexcept
Преобразовать себя в "кусок строки", включающий всю строку.
Определения strexpr.h:2654
constexpr str_piece from_to(size_t from, size_t to) const noexcept
Получить подстроку str_src с позиции от from до позиции to (не включая её).
Определения strexpr.h:2721
R replaced(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0) const
Получить копию строки с заменёнными вхождениями подстрок.
Определения strexpr.h:3733
constexpr int strcmp(const K *text) const
Сравнение с C-строкой посимвольно.
Определения strexpr.h:2770
constexpr bool ends_with_ia(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой без учёта регистра ASCII символов.
Определения strexpr.h:3650
constexpr size_t find_first_not_of(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа не из заданного набора символов.
Определения strexpr.h:3239
constexpr size_t find_first_of(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа из заданного набора символов.
Определения strexpr.h:3211
constexpr size_t find_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Найти начало последнего вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:3055
R trimmed_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения strexpr.h:3962
constexpr bool starts_with_ia(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки без учёта регистра ASCII символов.
Определения strexpr.h:3591
constexpr size_t find_last(str_piece pattern, size_t offset=-1) const noexcept
Найти начало последнего вхождения подстроки в этой строке.
Определения strexpr.h:3028
constexpr size_t find_last_of(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа из заданного набора символов.
Определения strexpr.h:3252
constexpr size_t find_or_all(K s, size_t offset=0) const noexcept
Найти символ в этой строке или конец строки.
Определения strexpr.h:3115
constexpr size_t find_last_not_of(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа не из заданного набора символов.
Определения strexpr.h:3280
constexpr void for_all_finded(const Op &op, str_piece pattern, size_t offset=0, size_t maxCount=0) const
Вызвать функтор для всех найденных вхождений подстроки в этой строке.
Определения strexpr.h:3150
constexpr size_t find_end(str_piece pattern, size_t offset=0) const noexcept
Найти конец вхождения подстроки в этой строке.
Определения strexpr.h:2964
constexpr bool operator!() const noexcept
Проверка на пустоту.
Определения strexpr.h:2728
R trimmed(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, слева и справа.
Определения strexpr.h:3809
constexpr R trimmed() const
Получить строку с удалением пробельных символов слева и справа.
Определения strexpr.h:3770
constexpr size_t size() const
Размер строки в символах.
Определения strexpr.h:2595
R trimmed_right(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, справа.
Определения strexpr.h:3944
constexpr To find_all(str_piece pattern, size_t offset=0, size_t maxCount=0) const
Найти все вхождения подстроки в этой строке.
Определения strexpr.h:3173
constexpr my_type str_mid(size_t from, size_t len=-1) const
Получить часть строки объектом того же типа, к которому применён метод, аналогично mid.
Определения strexpr.h:3306
constexpr size_t find_end_of_last(str_piece pattern, size_t offset=-1) const noexcept
Найти конец последнего вхождения подстроки в этой строке.
Определения strexpr.h:3041
constexpr std::pair< size_t, size_t > find_first_of_idx(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа из заданного набора символов.
Определения strexpr.h:3224
constexpr bool is_ascii() const noexcept
Содержит ли строка только ASCII символы.
Определения strexpr.h:3657
constexpr size_t find(str_piece pattern, size_t offset=0) const noexcept
Найти начало первого вхождения подстроки в этой строке.
Определения strexpr.h:2928
constexpr SplitterBase< K, str_piece > splitter(str_piece delimiter) const
Получить объект Splitter по заданному разделителю, который позволяет последовательно получать подстро...
Определения strexpr.h:4012
constexpr std::pair< size_t, size_t > find_last_of_idx(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа из заданного набора символов.
Определения strexpr.h:3265
R trimmed_left(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, слева.
Определения strexpr.h:3824
R trimmed_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения strexpr.h:3861
std::optional< double > to_double() const noexcept
Преобразовать строку в double.
Определения strexpr.h:3381
constexpr size_t find_or_all(str_piece pattern, size_t offset=0) const noexcept
Найти начало первого вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:2978
constexpr bool operator==(T &&other) const noexcept
Оператор сравнения строки и строкового литерала на равенство.
Определения strexpr.h:2829
R trimmed_right_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения strexpr.h:3998
constexpr auto operator<=>(const base &other) const noexcept
Оператор сравнения строк.
Определения strexpr.h:2819
constexpr bool contains(str_piece pattern, size_t offset=0) const noexcept
Содержит ли строка указанную подстроку.
Определения strexpr.h:3083
R trimmed_right(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, справа.
Определения strexpr.h:3839
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len=0) const noexcept
Получить часть строки как "str_src".
Определения strexpr.h:2680
constexpr K at(ptrdiff_t idx) const
Получить символ на заданной позиции .
Определения strexpr.h:2741
R lowered_only_ascii() const
Получить копию строки в нижнем регистре ASCII символов.
Определения strexpr.h:3713
R trimmed_right_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения strexpr.h:3899
constexpr auto operator<=>(T &&other) const noexcept
Оператор сравнения строки и строкового литерала.
Определения strexpr.h:2839
constexpr std::basic_string< D, Traits, Allocator > to_string() const
Конвертировать в std::basic_string.
Определения strexpr.h:2626
constexpr T splitf(str_piece delimiter, const Op &beforeFunc, size_t offset=0) const
Разделить строку на части по заданному разделителю, с возможным применением функтора к каждой подстро...
Определения strexpr.h:3535
R trimmed_left_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения strexpr.h:3880
constexpr size_t find_end_of_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Найти конец последнего вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:3069
constexpr bool prefix_in(str_piece text) const noexcept
Является ли эта строка началом другой строки.
Определения strexpr.h:3609
R trimmed_left_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения strexpr.h:3980
constexpr K * place(K *ptr) const noexcept
Копировать строку в указанный буфер.
Определения strexpr.h:2569
constexpr convert_result< T > to_int() const noexcept
Преобразовать строку в число заданного типа.
Определения strexpr.h:3371
constexpr bool equal_ia(str_piece text) const noexcept
Равна ли строка другой строке посимвольно без учёта регистра ASCII символов.
Определения strexpr.h:2886
constexpr void as_number(T &t) const
Преобразовать строку в целое число.
Определения strexpr.h:3438
Концепт строкового выражения, совместимого с заданным типом символов.
Определения strexpr.h:488
Концепт "Строковых выражений".
Определения strexpr.h:470
Базовая концепция строкового объекта.
Определения strexpr.h:277
Проверка, являются ли два типа совместимыми строковыми типами.
Определения strexpr.h:136
constexpr expr_if< A > e_if(bool c, const A &a)
Создание условного строкового выражения expr_if.
Определения strexpr.h:1513
simstr::expr_stdstr< typename T::value_type, T > operator+(const T &str)
Унарный оператор+ для преобразования стандартных строк в строковые выражения.
Определения strexpr.h:6164
constexpr expr_spaces< uws, N > e_spcw()
Генерирует строку из N wchar_t пробелов.
Определения strexpr.h:1073
expr_fill< K, A, true > e_fill_left(const A &a, size_t width, K symbol=K(' '))
Создает выражение, которое дополняет указанное строковое выражение до заданной длины заданным символо...
Определения strexpr.h:1931
constexpr empty_expr< uws > eew
Пустое строковое выражение типа wchar_t.
Определения strexpr.h:831
constexpr expr_spaces< u8s, N > e_spca()
Генерирует строку из N char пробелов.
Определения strexpr.h:1055
constexpr empty_expr< u32s > eeuu
Пустое строковое выражение типа char32_t.
Определения strexpr.h:843
constexpr expr_num< K, T > e_num(T t)
Преобразование целого числа в строковое выражение.
Определения strexpr.h:1686
HexFlags
Флаги для функции e_hex.
Определения strexpr.h:1820
constexpr auto e_hex(T v)
Позволяет конкатенировать текст и беззнаковое число в 16-ричном виде.
Определения strexpr.h:1844
constexpr expr_concat< K, to_str_exp_t< K, T >, to_str_exp_t< K, Args >... > e_concat(T &&glue, Args &&...args)
Создание строкового выражения, объединяющего указанные строковые выражения, с использованием заданног...
Определения strexpr.h:5441
constexpr strexprjoin< A, B > operator+(const A &a, const B &b)
Оператор сложения двух произвольных строковых выражения для одинакового типа символов.
Определения strexpr.h:686
constexpr expr_repeat_lit< K, M - 1 > e_repeat(T &&s, size_t l)
Генерирует строку из l строковых констант s типа K.
Определения strexpr.h:1187
constexpr expr_literal< typename const_lit< T >::symb_type, static_cast< size_t >(N - 1)> e_t(T &&s)
Преобразует строковый литерал в строковое выражение.
Определения strexpr.h:960
expr_fill< K, A, false > e_fill_right(const A &a, size_t width, K symbol=K(' '))
Создает выражение, которое дополняет указанное строковое выражение до заданной длины заданным символо...
Определения strexpr.h:1957
constexpr expr_choice< A, B > e_choice(bool c, const A &a, const B &b)
Создание условного строкового выражения expr_choice.
Определения strexpr.h:1435
constexpr expr_char< K > e_char(K s)
Генерирует строку из 1 заданного символа.
Определения strexpr.h:887
constexpr empty_expr< u8s > eea
Пустое строковое выражение типа char.
Определения strexpr.h:819
constexpr expr_pad< K > e_c(size_t l, K s)
Генерирует строку из l символов s типа K.
Определения strexpr.h:1118
constexpr empty_expr< u16s > eeu
Пустое строковое выражение типа char16_t.
Определения strexpr.h:837
auto e_repl_const_symbols(A &&src, Repl &&... other)
Возвращает строковое выражение, генерирующее строку, в которой заданные символы заменены на заданные ...
Определения strexpr.h:5063
constexpr empty_expr< u8s > eeb
Пустое строковое выражение типа char8_t.
Определения strexpr.h:825
constexpr auto e_subst(T &&str_pattern, const details::subst_params< typename const_lit< T >::symb_type, std::type_identity_t< T >, std::type_identity_t< Args >... > &pattern, Args &&...args)
Создает строковое выражение, которое подставляет в заданные места в строковом литерале - образце знач...
Определения strexpr.h:5686
constexpr auto e_repl(A &&w, T &&p, X &&r)
Получить строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки.
Определения strexpr.h:4570
constexpr auto e_join(const T &s, L &&d)
Получить строковое выражение, конкатенирующее строки в контейнере в одну строку с заданным разделител...
Определения strexpr.h:2035
@ Short
without leading zeroes
Определения strexpr.h:1821
Небольшое пространство для методов работы со стандартными строками.
Определения strexpr.h:1569
std::basic_string< K, std::char_traits< K >, A > & append(std::basic_string< K, std::char_traits< K >, A > &str, const E &expr)
Добавить к стандартной строке строковое выражение.
Определения strexpr.h:5804
std::basic_string< K, std::char_traits< K >, A > & prepend(std::basic_string< K, std::char_traits< K >, A > &str, const E &expr)
Вставить строковое выражение в начало стандартной строки.
Определения strexpr.h:5837
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)
Изменить часть стандартной строки на заданное строковое выражение.
Определения strexpr.h:5731
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)
Функция поиска подстрок в стандартной строке и замены найденных вхождений на значение строкового выра...
Определения strexpr.h:6011
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)
Вставить строковое выражение в указанную позицию стандартной строки.
Определения strexpr.h:5872
Пространство имён для объектов библиотеки
Определения sstring.cpp:12
IntConvertResult
Перечисление с возможными результатами преобразования строки в целое число
Определения strexpr.h:2102
@ Overflow
Переполнение, число не помещается в заданный тип
Определения strexpr.h:2105
@ Success
Успешно
Определения strexpr.h:2103
@ NotNumber
Вообще не число
Определения strexpr.h:2106
@ BadSymbolAtTail
Число закончилось не числовым символом
Определения strexpr.h:2104
"Пустое" строковое выражение.
Определения strexpr.h:804
Строковое выражение условного выбора.
Определения strexpr.h:1314
Строковое выражение условного выбора.
Определения strexpr.h:1380
Строковое выражение условного выбора.
Определения strexpr.h:1223
Строковое выражение для объединения более чем одного строкового выражения, с указанием разделителя....
Определения strexpr.h:5366
Строковое выражение условного выбора.
Определения strexpr.h:1252
Тип строкового выражения, возвращающего N заданных символов.
Определения strexpr.h:1089
constexpr expr_replace_symbols(str_t source, const std::vector< std::pair< K, str_t > > &repl)
Конструктор выражения.
Определения strexpr.h:5147
Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки на строковое выр...
Определения strexpr.h:4688
constexpr expr_replaced_e(str_src< K > w, str_src< K > p, const E &e)
Конструктор.
Определения strexpr.h:4707
Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки на другую строку...
Определения strexpr.h:4582
constexpr expr_replaced(str_src< K > w, str_src< K > p, str_src< K > r)
Конструктор.
Определения strexpr.h:4600
Тип строкового выражения, возвращающего N заданных символов.
Определения strexpr.h:1029
Тип для использования std::basic_string и std::basic_string_view как источников в строковых выражения...
Определения strexpr.h:1538
Базовый класс для преобразования строковых выражений в стандартные строки
Определения strexpr.h:625
Класс, заявляющий, что ссылается на нуль-терминированную строку.
Определения strexpr.h:4183
constexpr my_type to_nts(size_t from)
Получить нуль-терминированную строку, сдвинув начало на заданное количество символов.
Определения strexpr.h:4246
constexpr str_src_nt(T &&v) noexcept
Конструктор из строкового литерала.
Определения strexpr.h:4217
constexpr str_src_nt(T &&p) noexcept
Явный конструктор из С-строки.
Определения strexpr.h:4208
constexpr str_src_nt(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения strexpr.h:4235
constexpr str_src_nt(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения strexpr.h:4223
Простейший класс иммутабельной не владеющей строки.
Определения strexpr.h:4047
constexpr str_src(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения strexpr.h:4076
constexpr bool is_empty() const noexcept
Проверить, не пуста ли строка.
Определения strexpr.h:4101
constexpr size_t length() const noexcept
Получить длину строки.
Определения strexpr.h:4087
constexpr K operator[](size_t idx) const
Получить символ из указанной позиции. Проверка границ не выполняется.
Определения strexpr.h:4130
constexpr my_type & remove_prefix(size_t delta)
Сдвигает начало строки на заданное количество символов.
Определения strexpr.h:4141
constexpr str_src(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения strexpr.h:4066
constexpr bool is_same(str_src< K > other) const noexcept
Проверить, не указывают ли два объекта на одну строку.
Определения strexpr.h:4110
constexpr str_src(const std::basic_string_view< K, std::char_traits< K > > &s) noexcept
Конструктор из std::basic_string_view.
Определения strexpr.h:4081
constexpr const symb_type * symbols() const noexcept
Получить указатель на константный буфер с символами строки.
Определения strexpr.h:4094
constexpr my_type & remove_suffix(size_t delta)
Укорачивает строку на заданное количество символов.
Определения strexpr.h:4154
constexpr bool is_part_of(str_src< K > other) const noexcept
Проверить, не является ли строка частью другой строки.
Определения strexpr.h:4119
constexpr str_src(T &&v) noexcept
Конструктор из строкового литерала.
Определения strexpr.h:4060
Конкатенация ссылки на строковое выражение и значения строкового выражения.
Определения strexpr.h:711
Шаблонный класс для конкатенации двух строковых выражений в одно с помощью operator +
Определения strexpr.h:649