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) ==
sizeof(
char16_t);
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<is_one_of_std_
char_v From>
98auto to_one_of_std_char(From* from) {
99 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
101 }
else if constexpr (std::is_same_v<From, ubs>) {
102 return reinterpret_cast<u8s*
>(from);
108template<is_one_of_std_
char_v From>
109auto to_one_of_std_char(
const From* from) {
110 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
112 }
else if constexpr (std::is_same_v<From, ubs>) {
113 return reinterpret_cast<const u8s*
>(from);
120struct to_std_char_type : std::type_identity<K>{};
123struct to_std_char_type<char8_t>{
128struct to_std_char_type<char16_t>{
129 using type = std::conditional_t<
sizeof(char16_t) ==
sizeof(
wchar_t), wchar_t,
void>;
133struct to_std_char_type<char32_t>{
134 using type = std::conditional_t<
sizeof(char32_t) ==
sizeof(
wchar_t), wchar_t,
void>;
138using to_std_char_t =
typename to_std_char_type<K>::type;
141struct to_base_char_type : std::type_identity<K>{};
144struct to_base_char_type<char8_t>{
149struct to_base_char_type<wchar_t>{
150 using type = std::conditional_t<
sizeof(char16_t) ==
sizeof(
wchar_t), char16_t,
char32_t>;
154using to_base_char_t =
typename to_base_char_type<K>::type;
171template<
typename K1,
typename K2>
220template<
typename T>
struct const_lit;
223template<is_one_of_
char_v T,
size_t N>
224struct const_lit<const T(&)[N]> {
226 constexpr static size_t Count = N;
230concept is_const_lit_v =
requires {
231 typename const_lit<T>::symb_type;
236template<
typename K,
typename T>
struct const_lit_for;
238template<
typename K, is_equal_str_type_v<K> P,
size_t N>
239struct const_lit_for<K, const P(&)[N]> {
240 constexpr static size_t Count = N;
243template<
typename K,
size_t N>
244class const_lit_to_array {
247 constexpr size_t find(K s)
const {
248 if constexpr (Idx < N) {
249 return s == symbols_[Idx] ? Idx : find<Idx + 1>(s);
255 constexpr bool exist(K s)
const {
256 if constexpr (Idx < N) {
257 return s == symbols_[Idx] || exist<Idx + 1>(s);
262 const K (&symbols_)[N + 1];
264 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
265 constexpr const_lit_to_array(T&& s)
266 : symbols_((
const K(&)[M])s) {}
268 constexpr bool contain(K s)
const {
271 constexpr size_t index_of(K s)
const {
277concept StrTypeCommon =
requires(
const A& a) {
278 typename std::remove_cvref_t<A>::symb_type;
279 { a.is_empty() } -> std::same_as<bool>;
280 { a.length() } -> std::convertible_to<size_t>;
285concept HasSymbType =
requires {
286 typename std::remove_cvref_t<A>::symb_type;
310template<
typename A,
typename K>
311concept StrType = StrTypeCommon<A> &&
requires(
const A& a) {
312 { a.symbols() } -> std::same_as<const K*>;
313} && std::is_same_v<typename std::remove_cvref_t<A>::symb_type, K>;
315template<
typename T>
struct is_std_string_source : std::false_type{};
317template<
typename K,
typename A>
318struct is_std_string_source<
std::basic_string<K, std::char_traits<K>, A>> : std::true_type{};
321struct is_std_string_source<std::basic_string_view<K, std::char_traits<K>>> : std::true_type{};
324concept is_std_string_source_v = is_std_string_source<T>::value;
327concept StdStrSource = is_std_string_source_v<std::remove_cvref_t<T>>;
329template<
typename T,
typename K>
333concept StrSource = StdStrSource<T> || is_const_lit_v<T> || StrTypeCommon<T>;
336concept StrSourceNoLiteral = StdStrSource<T> || StrTypeCommon<T>;
338template<
typename T>
struct is_std_string : std::false_type{};
340template<
typename K,
typename A>
341struct is_std_string<std::basic_string<K, std::char_traits<K>, A>> : std::true_type{};
344concept is_std_string_v = is_std_string<T>::value;
345template<
typename T,
typename K>
349struct symb_type_from_src {
354template<
typename K,
size_t N>
355struct symb_type_from_src<const K(&)[N]> {
359template<StdStrSource T>
360struct symb_type_from_src<T> {
361 using type =
typename std::remove_cvref_t<T>::value_type;
364template<HasSymbType T>
365struct symb_type_from_src<T> {
366 using type =
typename std::remove_cvref_t<T>::symb_type;
370using symb_type_from_src_t = symb_type_from_src<T>::type;
508 typename std::remove_cvref_t<A>::symb_type;
509 { a.length() } -> std::convertible_to<size_t>;
510 { a.place(std::declval<
typename std::remove_cvref_t<A>::symb_type*>()) } -> std::same_as<typename std::remove_cvref_t<A>::symb_type*>;
524template<
typename A,
typename K>
527template<
typename K,
typename T>
528struct convert_to_strexpr;
530template<
typename A,
typename K>
531concept strexpr_from =
requires(
const A& a) {
532 {convert_to_strexpr<K, std::remove_cvref_t<A>>::convert(a)} ->
StrExprForType<K>;
535template<
typename A,
typename K>
536concept strexpr_std =
requires(
const A& a) {
537 {convert_to_strexpr<K, std::remove_cvref_t<A>>::convert(a)} -> StdStringForType<K>;
540template<
typename A,
typename K>
543template<
typename A,
typename K>
546template<
typename A,
typename K>
547concept to_strexpr_meth =
requires(
const A& a) {
551template<
typename A,
typename K>
552concept to_strexpr_std =
requires(
const A& a) {
553 {a.template to_strexpr<K>()} -> StdStringForType<K>;
556template<
typename A,
typename K>
557concept 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>;
559template<
typename K, strexpr_from<K> T>
560constexpr auto to_strexpr(T&& t) {
561 return convert_to_strexpr<K, std::remove_cvref_t<T>>::convert(std::forward<T>(t));
564template<
typename K, strexpr_for<K> T>
565constexpr typename convert_to_strexpr<K, std::remove_cvref_t<T>>::type to_strexpr(T&& t) {
566 return {std::forward<T>(t)};
569template<
typename K, to_strexpr_type<K> T>
570constexpr typename std::remove_cvref_t<T>::strexpr to_strexpr(T&& t) {
571 return {std::forward<T>(t)};
574template<
typename K, to_strexpr_meth<K> T>
575constexpr auto to_strexpr(T&& t) {
576 return t.template to_strexpr<K>();
580struct expr_stdstr_c {
584 expr_stdstr_c(T t) : t_(std::move(t)){}
586 constexpr size_t length() const noexcept {
589 constexpr symb_type* place(symb_type* p)
const noexcept {
590 size_t s = t_.size();
591 std::char_traits<K>::copy(p, (
const K*)t_.data(), s);
596template<
typename K, strexpr_std<K> T>
597constexpr auto to_strexpr(T&& t) {
598 using type =
decltype(convert_to_strexpr<K, std::remove_cvref_t<T>>::convert(std::forward<T>(t)));
599 return expr_stdstr_c<K, type>{convert_to_strexpr<K, std::remove_cvref_t<T>>::convert(std::forward<T>(t))};
602template<
typename K, to_strexpr_std<K> T>
603constexpr auto to_strexpr(T&& t) {
604 using type =
decltype(t.template to_strexpr<K>());
605 return expr_stdstr_c<K, type>{t.template to_strexpr<K>()};
608template<
typename K,
typename T>
609using convert_to_strexpr_t =
decltype(to_strexpr<K>(std::declval<T>()));
627template<
typename K,
typename Allocator, StrExprForType<K> A>
628constexpr std::basic_string<K, std::char_traits<K>, Allocator> to_std_string(
const A& expr) {
629 std::basic_string<K, std::char_traits<K>, Allocator> res;
630 if (
size_t l = expr.length()) {
631 auto fill = [&](K* ptr,
size_t size) ->
size_t {
632 expr.place((
typename A::symb_type*)ptr);
635 if constexpr (
requires { res.resize_and_overwrite(l, fill); }) {
636 res.resize_and_overwrite(l, fill);
637 }
else if constexpr (
requires{ res._Resize_and_overwrite(l, fill); }) {
639 res._Resize_and_overwrite(l, fill);
642 expr.place((
typename A::symb_type*)res.data());
658template<
typename Impl>
660 template<is_equal_str_type_v<
typename Impl::symb_type> P,
typename Allocator>
661 constexpr operator std::basic_string<P, std::char_traits<P>, Allocator>()
const {
662 return to_std_string<P, Allocator>(*
static_cast<const Impl*
>(
this));
681template<StrExpr A, StrExprForType<
typename A::symb_type> B>
683 using symb_type =
typename A::symb_type;
686 constexpr strexprjoin(
const A& a_,
const B& b_) : a(a_), b(b_){}
687 constexpr size_t length()
const noexcept {
688 return a.length() + b.length();
690 constexpr symb_type* place(symb_type* p)
const noexcept {
691 return (symb_type*)b.place((
typename B::symb_type*)a.place(p));
718template<StrExpr A, StrExprForType<
typename A::symb_type> B>
743template<StrExpr A, StrExprForType<
typename A::symb_type> B,
bool last = true>
745 using symb_type =
typename A::symb_type;
748 template<
typename... Args>
requires (std::is_constructible_v<B, Args...>)
749 constexpr strexprjoin_c(
const A& a_, Args&&... args_) : a(a_), b(std::forward<Args>(args_)...) {}
750 constexpr size_t length()
const noexcept {
751 return a.length() + b.length();
753 constexpr symb_type* place(symb_type* p)
const noexcept {
754 if constexpr (last) {
755 return (symb_type*)b.place((
typename B::symb_type*)a.place(p));
757 return a.place((symb_type*)b.place((
typename B::symb_type*)p));
776template<StrExpr A, convertible_to_strexpr<
typename A::symb_type> B>
778 return {a, to_strexpr<typename A::symb_type>(std::forward<B>(b))};
795template<StrExpr A, convertible_to_strexpr<
typename A::symb_type> B>
797 return {a, to_strexpr<typename A::symb_type>(std::forward<B>(b))};
837 constexpr size_t length()
const noexcept {
840 constexpr symb_type* place(symb_type* p)
const noexcept {
877struct expr_char : expr_to_std_string<expr_char<K>>{
880 constexpr expr_char(K v) : value(v){}
881 constexpr size_t length() const noexcept {
884 constexpr symb_type* place(symb_type* p)
const noexcept {
902template<
typename K, StrExprForType<K> A>
922template<
typename K,
size_t N>
923struct expr_literal : expr_to_std_string<expr_literal<K, N>> {
925 const K (&str)[N + 1];
926 constexpr expr_literal(
const K (&str_)[N + 1]) : str(str_){}
928 constexpr size_t length() const noexcept {
931 constexpr symb_type* place(symb_type* p)
const noexcept {
932 if constexpr (N != 0)
933 std::char_traits<K>::copy(p, str, N);
990template<typename T, size_t N = const_lit<T>::Count>
991constexpr expr_literal<typename const_lit<T>::symb_type,
static_cast<size_t>(N - 1)>
e_t(T&& s) {
995template<
bool first,
typename K,
size_t N,
typename A>
996struct expr_literal_join : expr_to_std_string<expr_literal_join<first, K, N, A>> {
998 using atype =
typename A::symb_type;
999 const K (&str)[N + 1];
1001 constexpr expr_literal_join(
const K (&str_)[N + 1],
const A& a_) : str(str_), a(a_){}
1003 constexpr size_t length() const noexcept {
1004 return N + a.length();
1006 constexpr symb_type* place(symb_type* p)
const noexcept {
1007 if constexpr (N != 0) {
1008 if constexpr (first) {
1009 std::char_traits<K>::copy(p, str, N);
1010 return (symb_type*)a.place((atype*)(p + N));
1012 p = (symb_type*)a.place((atype*)p);
1013 std::char_traits<K>::copy(p, str, N);
1030constexpr expr_literal_join<
false, P, (N - 1), A>
operator+(
const A& a, T&& s) {
1041template<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>
1042constexpr expr_literal_join<
true, P, (N - 1), A>
operator+(T&& s,
const A& a) {
1059template<
typename K,
size_t N,
size_t S = ' '>
1061 using symb_type = K;
1062 constexpr size_t length()
const noexcept {
1065 constexpr symb_type* place(symb_type* p)
const noexcept {
1066 if constexpr (N != 0)
1067 std::char_traits<K>::assign(p, N,
static_cast<K
>(S));
1121 using symb_type = K;
1124 constexpr expr_pad(
size_t len_, K s_) : len(len_), s(s_){}
1125 constexpr size_t length()
const noexcept {
1128 constexpr symb_type* place(symb_type* p)
const noexcept {
1130 std::char_traits<K>::assign(p, len, s);
1153template<
typename K,
size_t N>
1154struct expr_repeat_lit : expr_to_std_string<expr_repeat_lit<K, N>> {
1155 using symb_type = K;
1157 const K (&s)[N + 1];
1158 constexpr expr_repeat_lit(
size_t repeat,
const K (&s_)[N + 1]) : repeat_(repeat), s(s_){}
1159 constexpr size_t length() const noexcept {
1162 constexpr symb_type* place(symb_type* p)
const noexcept {
1164 for (
size_t i = 0; i < repeat_; i++) {
1165 std::char_traits<K>::copy(p, s, N);
1175 using symb_type =
typename A::symb_type;
1178 mutable size_t len_;
1179 constexpr expr_repeat_expr(
size_t repeat,
const A& expr) : repeat_(repeat), expr_(expr){}
1180 constexpr size_t length() const noexcept {
1182 len_ = expr_.length();
1183 return repeat_ * len_;
1187 constexpr symb_type* place(symb_type* p)
const noexcept {
1188 if (repeat_ && len_) {
1189 symb_type* start = p;
1191 for (
size_t i = repeat_; --i; ) {
1192 std::char_traits<symb_type>::copy(p, start, len_);
1213template<typename T, typename K = const_lit<T>::symb_type,
size_t M = const_lit<T>::Count>
requires (M > 0)
1214constexpr expr_repeat_lit<K, M - 1>
e_repeat(T&& s,
size_t l) {
1232constexpr expr_repeat_expr<A>
e_repeat(
const A& s,
size_t l) {
1249template<StrExpr A, StrExprForType<
typename A::symb_type> B>
1251 using symb_type =
typename A::symb_type;
1252 using my_type = expr_choice<A, B>;
1257 constexpr expr_choice(
const A& _a,
const B& _b,
bool _choice) : a(_a), b(_b), choice(_choice){}
1259 constexpr size_t length()
const noexcept {
1260 return choice ? a.length() : b.length();
1262 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1263 return choice ? a.place(ptr) : (symb_type*)b.place((
typename B::symb_type*)ptr);
1280 using symb_type =
typename A::symb_type;
1281 using my_type = expr_if<A>;
1284 constexpr expr_if(
const A& _a,
bool _choice) : a(_a), choice(_choice){}
1286 constexpr size_t length()
const noexcept {
1287 return choice ? a.length() : 0;
1289 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1290 return choice ? a.place(ptr) : ptr;
1340template<
typename L, StrExprForType<L> A,
size_t N,
bool Compare>
1342 using symb_type = L;
1343 const symb_type (&str)[N + 1];
1346 constexpr expr_choice_one_lit(
const symb_type (&_str)[N + 1],
const A& _a,
bool _choice) : str(_str), a(_a), choice(_choice){}
1348 constexpr size_t length()
const noexcept {
1349 return choice == Compare ? a.length() : N;
1351 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1352 if (choice == Compare) {
1353 return (L*)a.place((
typename A::symb_type*)ptr);
1355 if constexpr (N != 0) {
1356 std::char_traits<symb_type>::copy(ptr, str, N);
1406template<
typename K,
size_t N,
typename P,
size_t M>
1408 using symb_type = K;
1409 const K (&str_a)[N + 1];
1410 const P (&str_b)[M + 1];
1412 constexpr expr_choice_two_lit(
const K(&_str_a)[N + 1],
const P(&_str_b)[M + 1],
bool _choice)
1413 : str_a(_str_a), str_b(_str_b), choice(_choice){}
1415 constexpr size_t length()
const noexcept {
1416 return choice ? N : M;
1418 constexpr symb_type* place(symb_type* ptr)
const noexcept {
1420 if constexpr (N != 0) {
1421 std::char_traits<symb_type>::copy(ptr, str_a, N);
1425 if constexpr (M != 0) {
1426 std::char_traits<symb_type>::copy(ptr, (
const K(&)[M + 1])str_b, M);
1461template<StrExpr A, StrExprForType<
typename A::symb_type> B>
1471template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1481template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1490template<typename T, typename L, typename K = typename const_lit<T>::symb_type,
typename P =
typename const_lit<L>::symb_type,
1491 size_t N = const_lit<T>::Count,
size_t M = const_lit_for<typename const_lit<T>::symb_type, L>::Count>
1492 requires is_equal_str_type_v<K, P>
1494 return {str_a, str_b, c};
1548template<typename T, size_t N = const_lit<T>::Count>
1550 using K =
typename const_lit<T>::symb_type;
1551 const K empty[1] = {0};
1564template<
typename K, StdStrSourceForType<K> T>
1566 using symb_type = K;
1569 expr_stdstr(
const T& t) : t_(t){}
1571 constexpr size_t length()
const noexcept {
1574 constexpr symb_type* place(symb_type* p)
const noexcept {
1575 size_t s = t_.size();
1576 std::char_traits<K>::copy(p, (
const K*)t_.data(), s);
1591template<
typename K, StdStrSource T>
1592struct convert_to_strexpr<K, T> {
1597constexpr const size_t npos =
static_cast<size_t>(-1);
1601std::char_traits<K> char_traits_selector(...);
1604using ch_traits =
decltype(char_traits_selector<K>(
int(0)));
1607concept FromIntNumber =
1608 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;
1611concept ToIntNumber = FromIntNumber<T> || is_one_of_type<T, int8_t>::value;
1613template<
typename K,
bool I,
typename T>
1616 std::make_unsigned_t<T> val;
1617 constexpr need_sign(T t) : negate(t < 0), val(t < 0 ?
std::make_unsigned_t<T>{} - t : t) {}
1618 constexpr void after(K*& ptr) {
1624template<
typename K,
typename T>
1625struct need_sign<K, false, T> {
1627 constexpr need_sign(T t) : val(t){}
1628 constexpr void after(K*&) {}
1631template<
typename K,
typename T>
1632constexpr size_t fromInt(K* bufEnd, T val) {
1633 const char* twoDigit =
1634 "0001020304050607080910111213141516171819"
1635 "2021222324252627282930313233343536373839"
1636 "4041424344454647484950515253545556575859"
1637 "6061626364656667686970717273747576777879"
1638 "8081828384858687888990919293949596979899";
1640 need_sign<K, std::is_signed_v<T>, T> store(val);
1642 while (store.val >= 100) {
1643 const char* ptr = twoDigit + (store.val % 100) * 2;
1644 *--itr =
static_cast<K
>(ptr[1]);
1645 *--itr =
static_cast<K
>(ptr[0]);
1648 if (store.val < 10) {
1649 *--itr =
static_cast<K
>(
'0' + store.val);
1651 const char* ptr = twoDigit + store.val * 2;
1652 *--itr =
static_cast<K
>(ptr[1]);
1653 *--itr =
static_cast<K
>(ptr[0]);
1656 return size_t(bufEnd - itr);
1662template<
typename K,
typename T>
1664 using symb_type = K;
1665 using my_type = expr_num<K, T>;
1667 enum { bufSize = 24 };
1668 mutable K buf[bufSize];
1671 constexpr expr_num(T t) : value(t) {}
1672 constexpr expr_num(expr_num&& t) noexcept : value(t.value) {}
1674 constexpr size_t length() const noexcept {
1675 value =
static_cast<T
>(fromInt(buf + bufSize, value));
1676 return static_cast<size_t>(value);
1678 constexpr K* place(K* ptr)
const noexcept {
1679 size_t len =
static_cast<size_t>(value);
1680 ch_traits<K>::copy(ptr, buf + bufSize - len, len);
1695template<
typename K, FromIntNumber T>
1696struct convert_to_strexpr<K, T> {
1697 using type = expr_num<K, T>;
1715template<
typename K, FromIntNumber T>
1722enum class int_align { none, left, right, center };
1723enum class int_plus_sign {none, plus, space};
1724enum class int_prefix {none, lcase, ucase};
1726enum fmt_kinds :
unsigned {
1737template<
typename A,
typename B,
unsigned Kind>
1741 inline static constexpr unsigned kind = Kind;
1745 inline static constexpr unsigned kind = fmt_none;
1748template<
int_align A>
1750 inline static constexpr unsigned kind = fmt_align;
1753template<
size_t W
idth = 0>
1755 inline static constexpr unsigned kind = fmt_width;
1758template<
unsigned Fill = ' '>
1760 inline static constexpr unsigned kind = fmt_fill;
1763template<
int_plus_sign S>
1765 inline static constexpr unsigned kind = fmt_sign;
1769 inline static constexpr unsigned kind = fmt_upper;
1774 inline static constexpr unsigned kind = fmt_prefix;
1778 inline static constexpr unsigned kind = fmt_zero;
1782concept FmtParam =
requires {
1783 {std::remove_cvref_t<T>::kind} -> std::same_as<const unsigned&>;
1786template<FmtParam A, FmtParam B>
1787requires((A::kind & B::kind) == 0)
1788constexpr auto operator | (
const A&,
const B&) {
1789 return fmt_info<A, B, A::kind | B::kind>{};
1792inline constexpr align_info<int_align::left> l;
1793inline constexpr align_info<int_align::right> r;
1794inline constexpr align_info<int_align::center> c;
1797inline constexpr width_info<W> w;
1800inline constexpr fill_info<F> f;
1802inline constexpr sign_info<int_plus_sign::plus> sp;
1803inline constexpr sign_info<int_plus_sign::space> ss;
1804inline constexpr upper_info u;
1805inline constexpr prefix_info<int_prefix::lcase> p;
1806inline constexpr prefix_info<int_prefix::ucase> P;
1807inline constexpr zero_info z;
1809inline constexpr width_info<unsigned(-1)> wp;
1810inline constexpr fmt_default df;
1813struct extract_align : std::false_type {
1814 inline static constexpr int_align align = int_align::none;
1817template<
int_align A>
1818struct extract_align<align_info<A>> : std::true_type {
1819 inline static constexpr int_align align = A;
1822template<
typename A,
typename B,
unsigned U>
1823struct extract_align<fmt_info<A, B, U>> {
1824 inline static constexpr bool in_a = extract_align<A>::value, in_b = extract_align<B>::value, value = in_a | in_b;
1825 inline static constexpr int_align align = extract_align<std::conditional_t<in_a, A, std::conditional_t<in_b, B, align_info<int_align::none>>>>::align;
1829struct extract_width : std::false_type {
1830 inline static constexpr size_t width = 0;
1834struct extract_width<width_info<W>> : std::true_type {
1835 inline static constexpr size_t width = W;
1838template<
typename A,
typename B,
unsigned U>
1839struct extract_width<fmt_info<A, B, U>> {
1840 inline static constexpr bool in_a = extract_width<A>::value, in_b = extract_width<B>::value, value = in_a | in_b;
1841 inline static constexpr size_t width = extract_width<std::conditional_t<in_a, A, std::conditional_t<in_b, B, width_info<0>>>>::width;
1845struct extract_fill : std::false_type {
1846 inline static constexpr unsigned fill =
' ';
1850struct extract_fill<fill_info<F>> : std::true_type {
1851 inline static constexpr unsigned fill = F;
1854template<
typename A,
typename B,
unsigned U>
1855struct extract_fill<fmt_info<A, B, U>> {
1856 inline static constexpr bool in_a = extract_fill<A>::value, in_b = extract_fill<B>::value, value = in_a | in_b;
1857 inline static constexpr unsigned fill = extract_fill<std::conditional_t<in_a, A, std::conditional_t<in_b, B, fill_info<
' '>>>>::fill;
1861struct extract_sign : std::false_type {
1862 inline static constexpr int_plus_sign sign = int_plus_sign::none;
1865template<
int_plus_sign S>
1866struct extract_sign<sign_info<S>> : std::true_type {
1867 inline static constexpr int_plus_sign sign = S;
1870template<
typename A,
typename B,
unsigned U>
1871struct extract_sign<fmt_info<A, B, U>> {
1872 inline static constexpr bool in_a = extract_sign<A>::value, in_b = extract_sign<B>::value, value = in_a | in_b;
1873 inline static constexpr int_plus_sign sign = extract_sign<std::conditional_t<in_a, A, std::conditional_t<in_b, B, sign_info<int_plus_sign::none>>>>::sign;
1877struct extract_upper : std::false_type {};
1880struct extract_upper<upper_info> : std::true_type {};
1882template<
typename A,
typename B,
unsigned U>
1883struct extract_upper<fmt_info<A, B, U>> {
1884 inline static constexpr bool in_a = extract_upper<A>::value, in_b = extract_upper<B>::value,
1885 value = extract_upper<std::conditional_t<in_a, A, std::conditional_t<in_b, B, std::false_type>>>::value;
1889struct extract_prefix : std::false_type{
1890 inline static constexpr int_prefix prefix = int_prefix::none;
1893template<
int_prefix P>
1894struct extract_prefix<prefix_info<P>> : std::true_type {
1895 inline static constexpr int_prefix prefix = P;
1898template<
typename A,
typename B,
unsigned U>
1899struct extract_prefix<fmt_info<A, B, U>> {
1900 inline static constexpr bool in_a = extract_prefix<A>::value, in_b = extract_prefix<B>::value, value = in_a | in_b;
1901 inline static constexpr int_prefix prefix = extract_prefix<std::conditional_t<in_a, A, std::conditional_t<in_b, B, prefix_info<int_prefix::none>>>>::prefix;
1905struct extract_zero : std::false_type{};
1908struct extract_zero<zero_info> : std::true_type {};
1910template<
typename A,
typename B,
unsigned U>
1911struct extract_zero<fmt_info<A, B, U>> {
1912 inline static constexpr bool in_a = extract_zero<A>::value, in_b = extract_zero<B>::value,
1913 value = extract_zero<std::conditional_t<in_a, A, std::conditional_t<in_b, B, std::false_type>>>::value;
1916template<
int_align Align,
unsigned W
idth,
unsigned Fill,
int_plus_sign Sign,
bool Upper,
int_prefix Prefix,
bool Zero>
1918 inline static constexpr int_align align = Align;
1919 inline static constexpr unsigned width = Width;
1920 inline static constexpr unsigned fill = Fill;
1921 inline static constexpr int_plus_sign sign = Sign;
1922 inline static constexpr bool upper = Upper;
1923 inline static constexpr int_prefix prefix = Prefix;
1924 inline static constexpr bool zero = Zero;
1928using p_to_fmt_t = fmt_params<
1929 extract_align<T>::align,
1930 extract_width<T>::width,
1931 extract_fill<T>::fill,
1932 extract_sign<T>::sign,
1933 extract_upper<T>::value,
1934 extract_prefix<T>::prefix,
1935 extract_zero<T>::value>;
1938using to_fmt_t = p_to_fmt_t<std::remove_cvref_t<T>>;
1941struct is_fmt_params : std::false_type{};
1943template<
int_align Align,
unsigned W
idth,
unsigned Fill,
int_plus_sign Sign,
bool Upper,
int_prefix Prefix,
bool Zero>
1944struct is_fmt_params<fmt_params<Align, Width, Fill, Sign, Upper, Prefix, Zero>> : std::true_type{};
1947concept FmtParamSet = is_fmt_params<T>::value;
1951template<f::FmtParam F>
1952constexpr auto operator|(
const F& f, fmt_end) {
1956template<
char C = 0,
char...Chars>
1957constexpr auto parse_fmt_symbol();
1959template<
unsigned N,
char C =
'Z',
char...Chars>
1960constexpr auto parse_width() {
1961 if constexpr (C >=
'0' && C <=
'9') {
1962 return parse_width<N * 10 + C -
'0', Chars...>();
1964 return w<N> | parse_fmt_symbol<C, Chars...>();
1968template<
unsigned N,
char C =
'Z',
char...Chars>
1969constexpr auto parse_fill() {
1970 if constexpr (C >=
'0' && C <=
'9') {
1971 return parse_fill<N * 16 + C -
'0', Chars...>();
1972 }
else if constexpr (C >=
'a' && C <=
'f') {
1973 return parse_fill<N * 16 + C -
'a' + 10, Chars...>();
1974 }
else if constexpr (C >=
'A' && C <=
'F') {
1975 return parse_fill<N * 16 + C -
'A' + 10, Chars...>();
1977 return f<N> | parse_fmt_symbol<C, Chars...>();
1981template<
char C,
char...Chars>
1982constexpr auto parse_fmt_symbol() {
1983 if constexpr (C ==
'0') {
1984 return z | parse_fmt_symbol<Chars...>();
1985 }
else if constexpr (C ==
'a') {
1986 return p | parse_fmt_symbol<Chars...>();
1987 }
else if constexpr (C ==
'A') {
1988 return P | parse_fmt_symbol<Chars...>();
1989 }
else if constexpr (C ==
'b') {
1990 return l | parse_fmt_symbol<Chars...>();
1991 }
else if constexpr (C ==
'c') {
1992 return c | parse_fmt_symbol<Chars...>();
1993 }
else if constexpr (C ==
'd') {
1994 return r | parse_fmt_symbol<Chars...>();
1995 }
else if constexpr (C ==
'e') {
1996 return sp | parse_fmt_symbol<Chars...>();
1997 }
else if constexpr (C ==
'f') {
1998 return ss | parse_fmt_symbol<Chars...>();
1999 }
else if constexpr (C ==
'E') {
2000 return u | parse_fmt_symbol<Chars...>();
2001 }
else if constexpr (C ==
'\'') {
2002 return parse_fmt_symbol<Chars...>();
2003 }
else if constexpr (C ==
'F') {
2004 return parse_fill<0, Chars...>();
2005 }
else if constexpr (C >=
'1' && C <=
'9') {
2006 return parse_width<C -
'0', Chars...>();
2012template<
unsigned R,
typename T>
2013struct fmt_radix_info {};
2015template<
unsigned N,
char C = 0,
char...Chars>
2016constexpr auto parse_radix() {
2017 if constexpr (C >=
'0' && C <=
'9') {
2018 return parse_radix<N * 10 + C -
'0', Chars...>();
2019 }
else if constexpr (C == 0) {
2020 return fmt_radix_info<N, to_fmt_t<fmt_default>>{};
2022 return fmt_radix_info<N,
decltype(parse_fmt_symbol<C, Chars...>())>{};
2026template<
char C1,
char C2,
char C3,
char...Chars>
2027constexpr auto skip_0x() {
2028 static_assert(C1 ==
'0' && C2 ==
'x' &&
"Fmt symbols must begin with 0x");
2029 static_assert(C3 >=
'1' && C3 <=
'9' &&
"Radix must begin with 1-9");
2030 return parse_radix<C3 -
'0', Chars...>();
2035template<
typename K,
bool Ucase>
2036inline constexpr K digits_symbols[36] = {K(
'0'), K(
'1'), K(
'2'), K(
'3'), K(
'4'), K(
'5'), K(
'6'), K(
'7'), K(
'8'), K(
'9'),
2037 K(Ucase ?
'A' :
'a'), K(Ucase ?
'B' :
'b'), K(Ucase ?
'C' :
'c'), K(Ucase ?
'D' :
'd'), K(Ucase ?
'E' :
'e'),
2038 K(Ucase ?
'F' :
'f'), K(Ucase ?
'G' :
'g'), K(Ucase ?
'H' :
'h'), K(Ucase ?
'I' :
'i'), K(Ucase ?
'J' :
'j'),
2039 K(Ucase ?
'K' :
'k'), K(Ucase ?
'L' :
'l'), K(Ucase ?
'M' :
'm'), K(Ucase ?
'N' :
'n'), K(Ucase ?
'O' :
'o'),
2040 K(Ucase ?
'P' :
'p'), K(Ucase ?
'Q' :
'q'), K(Ucase ?
'R' :
'r'), K(Ucase ?
'S' :
's'), K(Ucase ?
'T' :
't'),
2041 K(Ucase ?
'U' :
'u'), K(Ucase ?
'V' :
'v'), K(Ucase ?
'W' :
'w'), K(Ucase ?
'X' :
'x'), K(Ucase ?
'Y' :
'y'),
2042 K(Ucase ?
'Z' :
'z'),
2045template<FromIntNumber T,
unsigned Radix, f::FmtParamSet FP>
requires (Radix > 1 && Radix <= 36)
2046struct expr_integer_src {
2049 constexpr expr_integer_src(T v) : value_(v){}
2050 constexpr expr_integer_src(T v,
unsigned w) : value_(v), width_(w){}
2052 template<is_std_
string_v S>
2055 template<
typename S>
requires std::is_constructible_v<S, empty_expr<typename S::symb_type>>
2059template<is_one_of_
char_v K, FromIntNumber T,
unsigned Radix, f::FmtParamSet FP>
2060requires (Radix > 1 && Radix <= 36)
2062 using symb_type = K;
2064 enum { bufSize = 64 };
2065 mutable K buf[bufSize];
2069 mutable bool negate_{};
2071 constexpr expr_integer(T t) : value_(t){}
2072 constexpr expr_integer(T t,
unsigned w) : value_(t), width_(w){}
2073 constexpr expr_integer(
const expr_integer_src<T, Radix, FP>& v) : value_(v.value_), width_(v.width_){}
2075 constexpr expr_integer(expr_integer&& t) noexcept : value_(t.value_), width_(t.width_){}
2077 constexpr size_t length() const noexcept {
2078 K* bufEnd = std::end(buf), *itr = bufEnd;
2081 need_sign<K, std::is_signed_v<T>, T> store(value_);
2083 *--itr = digits_symbols<K, FP::upper>[store.val % Radix];
2086 if constexpr (std::is_signed_v<T>) {
2087 negate_ = store.negate;
2090 *--itr = digits_symbols<K, FP::upper>[0];
2092 size_t len = bufEnd - itr;
2094 if constexpr (std::is_signed_v<T>) {
2095 if constexpr (FP::sign != f::int_plus_sign::none) {
2103 if constexpr (FP::prefix != f::int_prefix::none && (Radix == 2 || Radix == 8 || Radix == 16)) {
2105 if constexpr (Radix != 8) {
2109 if constexpr (FP::width == unsigned(-1)) {
2110 return std::max<size_t>(width_, len);
2112 return std::max<size_t>(FP::width, len);
2115 constexpr K* place(K* ptr)
const noexcept {
2116 size_t len =
static_cast<size_t>(value_), all_len = len;
2117 if constexpr (std::is_signed_v<T>) {
2118 if constexpr (FP::sign != f::int_plus_sign::none) {
2126 if constexpr (FP::prefix != f::int_prefix::none && (Radix == 2 || Radix == 8 || Radix == 16)) {
2128 if constexpr (Radix != 8) {
2132 if constexpr (FP::zero) {
2133 if constexpr (std::is_signed_v<T>) {
2137 if constexpr (FP::sign == f::int_plus_sign::plus) {
2139 }
else if constexpr (FP::sign == f::int_plus_sign::space) {
2144 if constexpr (FP::prefix != f::int_prefix::none && (Radix == 2 || Radix == 8 || Radix == 16)) {
2146 if constexpr (Radix == 2) {
2147 *ptr++ = FP::prefix == f::int_prefix::lcase ? K(
'b') : K(
'B');
2148 }
else if constexpr (Radix == 16) {
2149 *ptr++ = FP::prefix == f::int_prefix::lcase ? K(
'x') : K(
'X');
2153 if constexpr (FP::width == unsigned(-1)) {
2154 if (width_ > all_len) {
2155 before = width_ - all_len;
2158 if (FP::width > all_len) {
2159 before = FP::width - all_len;
2163 ch_traits<K>::assign(ptr, before, K(
'0'));
2166 ch_traits<K>::copy(ptr, std::end(buf) - len, len);
2169 size_t before = 0, after = 0;
2170 if constexpr (FP::width == unsigned(-1)) {
2171 if (width_ > all_len) {
2172 if constexpr (FP::align == f::int_align::left) {
2173 after = width_ - all_len;
2174 }
else if constexpr (FP::align == f::int_align::center) {
2175 before = (width_ - all_len) / 2;
2176 after = width_ - all_len - before;
2178 before = width_ - all_len;
2182 if (FP::width > all_len) {
2183 if constexpr (FP::align == f::int_align::left) {
2184 after = FP::width - all_len;
2185 }
else if constexpr (FP::align == f::int_align::center) {
2186 before = (FP::width - all_len) / 2;
2187 after = FP::width - all_len - before;
2189 before = FP::width - all_len;
2194 ch_traits<K>::assign(ptr, before, K(FP::fill));
2197 if constexpr (std::is_signed_v<T>) {
2201 if constexpr (FP::sign == f::int_plus_sign::plus) {
2203 }
else if constexpr (FP::sign == f::int_plus_sign::space) {
2208 if constexpr (FP::prefix != f::int_prefix::none && (Radix == 2 || Radix == 8 || Radix == 16)) {
2210 if constexpr (Radix == 2) {
2211 *ptr++ = FP::prefix == f::int_prefix::lcase ? K(
'b') : K(
'B');
2212 }
else if constexpr (Radix == 16) {
2213 *ptr++ = FP::prefix == f::int_prefix::lcase ? K(
'x') : K(
'X');
2216 ch_traits<K>::copy(ptr, std::end(buf) - len, len);
2220 ch_traits<K>::assign(ptr, after, K(FP::fill));
2228template<FromIntNumber T,
unsigned Radix, f::FmtParamSet FP>
requires (Radix > 1 && Radix <= 36)
2229template<is_std_string_v S>
2230expr_integer_src<T, Radix, FP>::operator S()
const {
2231 using st =
typename S::value_type;
2232 using Al =
typename S::allocator_type;
2233 return to_std_string<st, Al>(expr_integer<st, T, Radix, FP>{value_, width_});
2236template<FromIntNumber T,
unsigned Radix, f::FmtParamSet FP>
requires (Radix > 1 && Radix <= 36)
2238expr_integer_src<T, Radix, FP>::operator S()
const {
2239 using st =
typename S::symb_type;
2240 return S{expr_integer<st, T, Radix, FP>{value_, width_}};
2243template<
typename K, FromIntNumber T,
unsigned Radix, f::FmtParamSet FP>
2244struct convert_to_strexpr<K, expr_integer_src<T, Radix, FP>> {
2245 using type = expr_integer<K, T, Radix, FP>;
2248template<
unsigned R,
typename T,
typename F>
2249struct flags_checker {
2251 using flags_t = f::to_fmt_t<F>;
2252 inline static constexpr unsigned Radix = R;
2255template<
typename T,
bool ArgW
idth>
2256concept good_int_flags =
2257 T::Radix > 1 && T::Radix <= 36
2260 && (T::flags_t::align == f::int_align::none || !T::flags_t::zero)
2263 && (std::is_signed_v<typename T::val_t> || T::flags_t::sign == f::int_plus_sign::none)
2266 && (T::flags_t::width == unsigned(-1)) == ArgWidth
2269 && (T::flags_t::prefix == f::int_prefix::none || T::Radix == 2 || T::Radix == 8 || T::Radix == 16);
2378template<
unsigned R, auto fp = f::df, FromIntNumber T>
requires good_int_flags<flags_checker<R, T,
decltype(fp)>,
false>
2380 using fmt_param = f::to_fmt_t<
decltype(fp)>;
2381 return expr_integer_src<T, R, fmt_param>{v};
2387template<
unsigned R, auto fp = f::df, FromIntNumber T>
requires good_int_flags<flags_checker<R, T,
decltype(fp)>,
true>
2389 using fmt_param = f::to_fmt_t<
decltype(fp)>;
2390 return expr_integer_src<T, R, fmt_param>{v, w};
2393template<
typename T,
unsigned R,
typename F>
requires good_int_flags<flags_checker<R, T, F>,
false>
2394auto operator / (T v,
const f::fmt_radix_info<R, F>&) {
2395 return expr_integer_src<T, R, f::to_fmt_t<F>>{v};
2400 using symb_type = K;
2401 mutable u8s buf[40];
2404 constexpr expr_real(
double d) : v(d) {}
2405 constexpr expr_real(
float d) : v(d) {}
2407 size_t length() const noexcept {
2408 auto [ptr, ec] = std::to_chars(buf, buf + std::size(buf), v);
2409 l = ec != std::errc{} ? 0 : ptr - buf;
2412 K* place(K* ptr)
const noexcept {
2413 if constexpr (
sizeof(K) ==
sizeof(buf[0])) {
2414 ch_traits<K>::copy(ptr, (K*)buf, l);
2416 for (
size_t i = 0; i < l; i++) {
2434template<
typename K, std::
floating_po
int T>
2435struct convert_to_strexpr<K, T> {
2436 using type = expr_real<K>;
2450template<
typename K>
requires is_one_of_char_v<K>
2451inline constexpr expr_real<K>
e_num(
double t) {
2455template<FromIntNumber Val,
bool All,
bool Ucase,
bool Ox>
2456struct expr_hex_src {
2457 explicit constexpr expr_hex_src(Val v) : v_(v){}
2461template<
typename K, FromIntNumber Val,
bool All,
bool Ucase,
bool Ox>
2463 using symb_type = K;
2464 mutable need_sign<K, std::is_signed_v<Val>, Val> v_;
2465 mutable K buf_[
sizeof(Val) * 2]{};
2467 explicit constexpr expr_hex(Val v) : v_(v){}
2468 constexpr expr_hex(
const expr_hex_src<Val, All, Ucase, Ox>& v) : v_(v.v_){}
2470 constexpr size_t length() const noexcept {
2471 K *ptr = buf_ + std::size(buf_);
2474 *--ptr = digits_symbols<K, Ucase>[v_.val & 0xF];
2478 *--ptr = digits_symbols<K, Ucase>[v_.val & 0xF];
2483 if constexpr (All) {
2484 if (
size_t need =
sizeof(Val) * 2 - l) {
2485 ch_traits<K>::assign(buf_, need, K(
'0'));
2487 l =
sizeof(Val) * 2;
2493 if constexpr (std::is_signed_v<Val>) {
2494 return l + (Ox ? 2 : 0) + (v_.negate ? 1 : 0);
2496 return l + (Ox ? 2 : 0);
2498 constexpr K* place(K* ptr)
const noexcept {
2499 if constexpr (std::is_signed_v<Val>) {
2508 if constexpr (All) {
2509 ch_traits<K>::copy(ptr, buf_,
sizeof(Val) * 2);
2510 return ptr +
sizeof(Val) * 2;
2512 ch_traits<K>::copy(ptr, buf_ + std::size(buf_) - v_.val, v_.val);
2513 return ptr + v_.val;
2579template<
unsigned Flags = 0, FromIntNumber T>
2581 return expr_hex_src<T, (Flags &
HexFlags::Short) == 0, (Flags & HexFlags::Lcase) == 0, (Flags & HexFlags::No0x) == 0>{v};
2584template<
char c = 0,
char...Chars>
2585constexpr unsigned parse_f16_flags() {
2586 if constexpr (c ==
'1') {
2588 }
else if constexpr (c ==
'2') {
2589 return HexFlags::Lcase | parse_f16_flags<Chars...>();
2590 }
else if constexpr (c ==
'3') {
2591 return HexFlags::No0x | parse_f16_flags<Chars...>();
2600template<FromIntNumber T,
unsigned Flags>
2601constexpr auto operator/(T v,
const f16flags<Flags>&) {
2602 return expr_hex_src<T, (Flags &
HexFlags::Short) == 0, (Flags & HexFlags::Lcase) == 0, (Flags & HexFlags::No0x) == 0>{v};
2605inline namespace literals {
2606template<
char...Chars>
2607constexpr auto operator""_f16() {
2608 return f16flags<parse_f16_flags<Chars...>()>{};
2620template<
typename K,
typename Val,
bool All,
bool Ucase,
bool Ox>
2621struct convert_to_strexpr<K, expr_hex_src<Val, All, Ucase, Ox>> {
2622 using type = expr_hex<K, Val, All, Ucase, Ox>;
2626struct expr_pointer : expr_hex<K, uintptr_t, true, true, true> {
2627 constexpr expr_pointer(
const void* ptr) : expr_hex<K, uintptr_t, true, true, true>((uintptr_t)ptr){}
2638template<
typename K,
typename T>
2639struct convert_to_strexpr<K, const T*> {
2640 using type = expr_pointer<K>;
2643template<
typename K, StrExprForType<K> A,
bool Left>
2645 using symb_type = K;
2649 mutable size_t alen_{};
2650 constexpr expr_fill(K symbol,
size_t width,
const A& a) : symbol_(symbol), width_(width), a_(a){}
2652 constexpr size_t length() const noexcept {
2653 alen_ = a_.length();
2654 return std::max(alen_, width_);
2656 constexpr K* place(K* ptr)
const noexcept {
2657 if (alen_ >= width_) {
2658 return (K*)a_.place((
typename A::symb_type*)ptr);
2660 size_t w = width_ - alen_;
2661 if constexpr (Left) {
2662 ch_traits<K>::assign(ptr, w, symbol_);
2664 return (K*)a_.place((
typename A::symb_type*)ptr);
2666 ptr = (K*)a_.place((
typename A::symb_type*)ptr);
2667 ch_traits<K>::assign(ptr, w, symbol_);
2694template<StrExpr A,
typename K =
typename A::symb_type>
2695expr_fill<K, A, true>
e_fill_left(
const A& a,
size_t width, K symbol = K(
' ')) {
2696 return {symbol, width, a};
2720template<StrExpr A,
typename K =
typename A::symb_type>
2721expr_fill<K, A, false>
e_fill_right(
const A& a,
size_t width, K symbol = K(
' ')) {
2722 return {symbol, width, a};
2741template<
typename K,
typename T,
size_t I,
bool tail,
bool skip_empty>
2742struct expr_join : expr_to_std_string<expr_join<K, T, I, tail, skip_empty>> {
2743 using symb_type = K;
2744 using my_type = expr_join<K, T, I, tail, skip_empty>;
2748 constexpr expr_join(
const T& _s,
const K* _delim) : s(_s), delim(_delim){}
2750 constexpr size_t length() const noexcept {
2752 for (
const auto& t: s) {
2753 size_t len = t.length();
2754 if (len > 0 || !skip_empty) {
2755 if (I > 0 && l > 0) {
2761 return l + (tail && I > 0 && (l > 0 || (!skip_empty && s.size() > 0))? I : 0);
2763 constexpr K* place(K* ptr)
const noexcept {
2768 for (
const auto& t: s) {
2769 size_t copyLen = t.length();
2770 if (I > 0 && write != ptr && (copyLen || !skip_empty)) {
2771 ch_traits<K>::copy(write, delim, I);
2774 ch_traits<K>::copy(write, t.data(), copyLen);
2777 if (I > 0 && tail && (write != ptr || (!skip_empty && s.size() > 0))) {
2778 ch_traits<K>::copy(write, delim, I);
2798template<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>
2799inline constexpr auto e_join(
const T& s, L&& d) {
2800 return expr_join<K, T, I - 1, tail, skip_empty>{s, d};
2804concept is_const_pattern = N > 1 && N <= 17;
2806template<
typename K,
size_t I>
2808 constexpr static const size_t value = size_t(K(~0x7F)) << ((I - 1) *
sizeof(K) * 8) | _ascii_mask<K, I - 1>::value;
2812struct _ascii_mask<K, 0> {
2813 constexpr static const size_t value = 0;
2818 using uns = std::make_unsigned_t<K>;
2819 constexpr static const size_t WIDTH =
sizeof(size_t) /
sizeof(uns);
2820 constexpr static const size_t VALUE = _ascii_mask<uns, WIDTH>::value;
2824constexpr inline bool isAsciiUpper(K k) {
2825 return k >=
'A' && k <=
'Z';
2829constexpr inline bool isAsciiLower(K k) {
2830 return k >=
'a' && k <=
'z';
2834constexpr inline K makeAsciiLower(K k) {
2835 return isAsciiUpper(k) ? k | 0x20 : k;
2839constexpr inline K makeAsciiUpper(K k) {
2840 return isAsciiLower(k) ? k & ~0x20 : k;
2843enum TrimSides { TrimLeft = 1, TrimRight = 2, TrimAll = 3 };
2844template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces = false>
2845struct trim_operator;
2848struct digits_selector {
2849 using wider_type = uint16_t;
2853struct digits_selector<2> {
2854 using wider_type = uint32_t;
2858struct digits_selector<4> {
2859 using wider_type = uint64_t;
2873template<
bool CanNegate,
bool CheckOverflow,
typename T>
2874struct result_type_selector {
2879struct result_type_selector<true, false, T> {
2880 using type = std::make_unsigned_t<T>;
2883template<
unsigned Base>
2884constexpr unsigned digit_width() {
2903template<
typename T,
unsigned Base>
2904constexpr unsigned max_overflow_digits = (
sizeof(T) * CHAR_BIT) / digit_width<Base>();
2907struct convert_result {
2914 inline static constexpr uint8_t NUMBERS[] = {
2915 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,
2916 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,
2917 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,
2918 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,
2919 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,
2920 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,
2921 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,
2922 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,
2923 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,
2924 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
2926 template<
typename K,
unsigned Base>
2927 static constexpr std::make_unsigned_t<K> toDigit(K s) {
2928 auto us =
static_cast<std::make_unsigned_t<K>
>(s);
2929 if constexpr (Base <= 10) {
2932 if constexpr (
sizeof(K) == 1) {
2935 return us < 256 ? NUMBERS[us] : us;
2940 template<
typename K, ToIntNumber T,
unsigned Base,
bool CheckOverflow>
2942 static constexpr convert_result<T> parse(
const K* start,
const K* current,
const K* end,
bool negate) {
2943 using u_type = std::make_unsigned_t<T>;
2944 #ifndef HAS_BUILTIN_OVERFLOW
2945 u_type maxMult = 0, maxAdd = 0;
2946 if constexpr (CheckOverflow) {
2947 maxMult = std::numeric_limits<u_type>::max() / Base;
2948 maxAdd = std::numeric_limits<u_type>::max() % Base;
2952 unsigned maxDigits = max_overflow_digits<u_type, Base>;
2954 const K* from = current;
2956 bool no_need_check_o_f = !CheckOverflow || end - current <= maxDigits;
2958 if (no_need_check_o_f) {
2960 const u_type digit = toDigit<K, Base>(*current);
2961 if (digit >= Base) {
2964 number = number * Base + digit;
2965 if (++current == end) {
2971 for (;maxDigits; maxDigits--) {
2972 const u_type digit = toDigit<K, Base>(*current);
2973 if (digit >= Base) {
2976 number = number * Base + digit;
2983 const u_type digit = toDigit<K, Base>(*current);
2984 if (digit >= Base) {
2987 #ifdef HAS_BUILTIN_OVERFLOW
2988 if (__builtin_mul_overflow(number, Base, &number) ||
2989 __builtin_add_overflow(number, digit, &number)) {
2991 if (number < maxMult || (number == maxMult && number < maxAdd)) {
2992 number = number * Base + digit;
2996 while(++current < end) {
2997 if (toDigit<K, Base>(*current) >= Base) {
3003 if (++current == end) {
3011 if constexpr (std::is_signed_v<T>) {
3012 result = negate ? 0 - number : number;
3013 if constexpr (CheckOverflow) {
3015 if (number > (u_type)std::numeric_limits<T>::max() + (negate ? 1 : 0)) {
3026 return {result, error, size_t(current - start)};
3033 template<
typename K, ToIntNumber T,
unsigned Base = 0,
bool CheckOverflow = true,
bool SkipWs = true,
bool AllowSign = true>
3034 requires(Base == -1 || (Base < 37 && Base != 1))
3035 static constexpr convert_result<T> to_integer(
const K* start,
size_t len)
noexcept {
3036 const K *ptr = start, *end = ptr + len;
3037 bool negate =
false;
3038 if constexpr (SkipWs) {
3039 while (ptr < end && std::make_unsigned_t<K>(*ptr) <=
' ')
3043 if constexpr (std::is_signed_v<T>) {
3044 if constexpr (AllowSign) {
3049 }
else if (*ptr ==
'-') {
3061 }
else if constexpr (AllowSign) {
3070 if constexpr (Base == 0 || Base == -1) {
3074 if (*ptr ==
'x' || *ptr ==
'X') {
3075 return parse<K, T, 16, CheckOverflow>(start, ++ptr, end, negate);
3077 if constexpr (Base == -1) {
3078 if (*ptr ==
'b' || *ptr ==
'B') {
3079 return parse<K, T, 2, CheckOverflow>(start, ++ptr, end, negate);
3081 if (*ptr ==
'o' || *ptr ==
'O') {
3082 return parse<K, T, 8, CheckOverflow>(start, ++ptr, end, negate);
3085 return parse<K, T, 8, CheckOverflow>(start, --ptr, end, negate);
3089 return parse<K, T, 10, CheckOverflow>(start, ptr, end, negate);
3091 return parse<K, T, Base, CheckOverflow>(start, ptr, end, negate);
3097template<
typename K,
typename Impl>
3098class null_terminated {
3106 constexpr const K* c_str()
const {
return static_cast<const Impl*
>(
this)->symbols(); }
3109template<
typename K,
typename Impl,
bool Mutable>
class buffer_pointers;
3119template<
typename K,
typename Impl>
3120class buffer_pointers<K, Impl, false> {
3121 constexpr const Impl& d()
const {
return *
static_cast<const Impl*
>(
this); }
3129 constexpr const K* data()
const {
return d().symbols(); }
3136 constexpr const K* begin()
const {
return d().symbols(); }
3143 constexpr const K* end()
const {
return d().symbols() + d().length(); }
3150 constexpr const K* cbegin()
const {
return d().symbols(); }
3157 constexpr const K* cend()
const {
return d().symbols() + d().length(); }
3160template<
typename K,
typename Impl>
3161class buffer_pointers<K, Impl, true> :
public buffer_pointers<K, Impl, false> {
3162 constexpr Impl& d() {
return *
static_cast<Impl*
>(
this); }
3163 using base = buffer_pointers<K, Impl, false>;
3171 constexpr const K* data()
const {
return base::data(); }
3178 constexpr const K* begin()
const {
return base::begin(); }
3185 constexpr const K* end()
const {
return base::end(); }
3192 constexpr const K* cbegin()
const {
return base::cbegin(); }
3199 constexpr const K* cend()
const {
return base::cend(); }
3206 constexpr K* data() {
return d().str(); }
3213 constexpr K* begin() {
return d().str(); }
3220 constexpr K* end() {
return d().str() + d().length(); }
3229template<
typename K,
typename StrSrc>
3231 using str_t = StrSrc;
3236 constexpr SplitterBase(str_t text, str_t delim) : text_(text), delim_(delim) {}
3242 return text_.length() == str::npos;
3251 if (!text_.length()) {
3256 }
else if (text_.length() == str::npos) {
3257 return {
nullptr, 0};
3259 size_t pos = text_.find(delim_),
next = 0;
3260 if (pos == str::npos) {
3261 pos = text_.length();
3264 next = pos + delim_.length();
3266 str_t result{text_.str, pos};
3279inline constexpr from_end to_end{0};
3282concept first_index_in_str = std::is_same_v<T, from_end> || std::is_convertible_v<T, size_t>;
3285concept last_index_in_str = first_index_in_str<T> || std::is_same_v<T, from_begin>;
3311template<
typename K,
typename StrRef,
typename Impl,
bool Mutable>
3312class str_src_algs :
public buffer_pointers<K, Impl, Mutable> {
3313 constexpr const Impl& d()
const noexcept {
3314 return *
static_cast<const Impl*
>(
this);
3316 constexpr size_t _len()
const noexcept {
3317 return d().length();
3319 constexpr const K* _str()
const noexcept {
3320 return d().symbols();
3322 constexpr bool _is_empty()
const noexcept {
3323 return d().is_empty();
3327 using symb_type = K;
3328 using str_piece = StrRef;
3329 using traits = ch_traits<K>;
3330 using uns_type = std::make_unsigned_t<K>;
3331 using my_type = Impl;
3332 using base = str_src_algs<K, StrRef, Impl, Mutable>;
3333 str_src_algs() =
default;
3347 constexpr K*
place(K* ptr)
const noexcept {
3348 size_t myLen = _len();
3349 traits::copy(ptr, _str(), myLen);
3363 size_t tlen = std::min(_len(), bufSize - 1);
3364 traits::copy(buffer, _str(), tlen);
3384 constexpr std::basic_string_view<D>
to_sv() const noexcept {
3385 return {(
const D*)_str(), _len()};
3394 constexpr operator std::basic_string_view<D, Traits>()
const {
3395 return {(
const D*)_str(), _len()};
3403 template<
typename D = K,
typename Traits = std::
char_traits<D>,
typename Allocator = std::allocator<D>>
requires is_equal_str_type_v<K, D>
3404 constexpr std::basic_string<D, Traits, Allocator>
to_string()
const {
3405 return {(
const D*)_str(), _len()};
3414 constexpr operator std::basic_string<D, Traits, Allocator>()
const {
3415 return {(
const D*)_str(), _len()};
3423 constexpr operator str_piece() const noexcept {
3424 return str_piece{_str(), _len()};
3432 constexpr str_piece
to_str() const noexcept {
3433 return {_str(), _len()};
3458 [[deprecated(
"Use 'slice' or [start, end] in C++23")]]
3459 constexpr str_piece
operator()(ptrdiff_t from, ptrdiff_t len = 0) const noexcept {
3460 size_t myLen = _len(), idxStart = from >= 0 ? from : (ptrdiff_t)myLen > -from ? myLen + from : 0,
3461 idxEnd = len > 0 ? idxStart + len : (ptrdiff_t)myLen > -len ? myLen + len : 0;
3464 if (idxStart > idxEnd)
3466 return str_piece{_str() + idxStart, idxEnd - idxStart};
3500 template<first_index_in_str S, last_index_in_str E>
3501 constexpr str_piece
slice(S start, E end)
const noexcept {
3502 size_t idxStart, idxEnd, len = _len();
3503 if constexpr (std::is_same_v<S, from_end>) {
3504 idxStart = start.idx_ >= len ? 0 : len - start.idx_;
3506 idxStart = std::min(
size_t(start), len);
3509 if constexpr (std::is_same_v<E, from_begin>) {
3510 idxEnd = std::max(idxStart, std::min(end.idx_, len));
3511 }
else if constexpr (std::is_same_v<E, from_end>) {
3512 idxEnd = std::max(idxStart, end.idx_ >= len ? 0 : len - end.idx_);
3515 idxEnd = len - idxStart <= e ? len : idxStart + e;
3518 return str_piece{_str() + idxStart, idxEnd - idxStart};
3521#if defined(__cpp_multidimensional_subscript) && __cpp_multidimensional_subscript >= 202211L
3526 template<first_index_in_str S, last_index_in_str E>
3527 constexpr str_piece operator[](S start, E end)
const noexcept {
3528 return slice(start, end);
3535 constexpr str_piece
prefix(
size_t count)
const noexcept {
3536 return slice(0, count);
3542 constexpr str_piece
suffix(
size_t count)
const noexcept {
3543 return slice(from_end(count), to_end);
3555 [[deprecated(
"Use 'slice' or [start, end] in C++23")]]
3556 constexpr str_piece
mid(
size_t from,
size_t len = -1) const noexcept {
3557 size_t myLen = _len(), idxStart = from, idxEnd = from > std::numeric_limits<size_t>::max() - len ? myLen : from + len;
3560 if (idxStart > idxEnd)
3562 return str_piece{_str() + idxStart, idxEnd - idxStart};
3578 constexpr str_piece
from_to(
size_t from,
size_t to)
const noexcept {
3579 return str_piece{_str() + from, to - from};
3591 constexpr str_piece
until(str_piece pattern,
size_t offset = 0) const noexcept {
3611 constexpr K
at(ptrdiff_t idx)
const {
3612 return _str()[idx >= 0 ? idx : _len() + idx];
3616 constexpr int compare(
const K* text,
size_t len)
const {
3617 size_t myLen = _len();
3618 int cmp = traits::compare(_str(), text, std::min(myLen, len));
3619 return cmp == 0 ? (myLen > len ? 1 : myLen == len ? 0 : -1) : cmp;
3630 return compare(o.symbols(), o.length());
3641 size_t myLen = _len(), idx = 0;
3642 const K* ptr = _str();
3643 for (; idx < myLen; idx++) {
3644 uns_type s1 = (uns_type)text[idx];
3648 uns_type s2 = (uns_type)ptr[idx];
3651 }
else if (s1 > s2) {
3655 return text[idx] == 0 ? 0 : -1;
3658 constexpr bool equal(
const K* text,
size_t len)
const noexcept {
3659 return len == _len() && traits::compare(_str(), text, len) == 0;
3669 constexpr bool equal(str_piece other)
const noexcept {
3670 return equal(other.symbols(), other.length());
3681 return equal(other._str(), other._len());
3690 return compare(other._str(), other._len()) <=> 0;
3698 template<typename T, size_t N = const_lit_for<K, T>::Count>
3700 return N - 1 == _len() && traits::compare(_str(), (
const K*)other, N - 1) == 0;
3708 template<typename T, size_t N = const_lit_for<K, T>::Count>
3710 size_t myLen = _len();
3711 int cmp = traits::compare(_str(), (
const K*)other, std::min(myLen, N - 1));
3712 int res = cmp == 0 ? (myLen > N - 1 ? 1 : myLen == N - 1 ? 0 : -1) : cmp;
3718 constexpr int compare_ia(
const K* text,
size_t len)
const noexcept {
3720 return _is_empty() ? 0 : 1;
3721 size_t myLen = _len(), checkLen = std::min(myLen, len);
3722 const uns_type *ptr1 =
reinterpret_cast<const uns_type*
>(_str()), *ptr2 =
reinterpret_cast<const uns_type*
>(text);
3723 while (checkLen--) {
3724 uns_type s1 = *ptr1++, s2 = *ptr2++;
3727 s1 = makeAsciiLower(s1);
3728 s2 = makeAsciiLower(s2);
3734 return myLen == len ? 0 : myLen > len ? 1 : -1;
3745 return compare_ia(text.symbols(), text.length());
3756 constexpr bool equal_ia(str_piece text)
const noexcept {
3757 return text.length() == _len() && compare_ia(text.symbols(), text.length()) == 0;
3767 constexpr bool less_ia(str_piece text)
const noexcept {
3768 return compare_ia(text.symbols(), text.length()) < 0;
3771 constexpr size_t find(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
3772 size_t lenText = _len();
3775 if (!lenPattern || offset >= lenText || offset + lenPattern > lenText)
3778 const K *text = _str(), *last = text + lenText - lenPattern, first = pattern[0];
3780 for (
const K* fnd = text + offset;; ++fnd) {
3781 fnd = traits::find(fnd, last - fnd, first);
3784 if (traits::compare(fnd + 1, pattern, lenPattern) == 0)
3785 return static_cast<size_t>(fnd - text);
3798 constexpr size_t find(str_piece pattern,
size_t offset = 0) const noexcept {
3799 return find(pattern.symbols(), pattern.length(), offset);
3817 template<
typename Exc,
typename ... Args>
requires std::is_constructible_v<Exc, Args...>
3818 constexpr size_t find_or_throw(str_piece pattern,
size_t offset = 0, Args&& ... args)
const {
3819 if (
auto fnd = find(pattern.symbols(), pattern.length(), offset); fnd != str::npos) {
3822 throw Exc(std::forward<Args>(args)...);
3834 constexpr size_t find_end(str_piece pattern,
size_t offset = 0) const noexcept {
3835 size_t fnd = find(pattern.symbols(), pattern.length(), offset);
3836 return fnd == str::npos ? fnd : fnd + pattern.length();
3848 constexpr size_t find_or_all(str_piece pattern,
size_t offset = 0) const noexcept {
3849 auto fnd = find(pattern.symbols(), pattern.length(), offset);
3850 return fnd == str::npos ? _len() : fnd;
3863 auto fnd = find(pattern.symbols(), pattern.length(), offset);
3864 return fnd == str::npos ? _len() : fnd + pattern.length();
3867 constexpr size_t find_last(
const K* pattern,
size_t lenPattern,
size_t offset)
const noexcept {
3868 if (lenPattern == 1)
3869 return find_last(pattern[0], offset);
3870 size_t lenText = std::min(_len(), offset);
3873 if (!lenPattern || lenPattern > lenText)
3877 const K *text = _str() + lenPattern, last = pattern[lenPattern];
3878 lenText -= lenPattern;
3880 if (text[--lenText] == last) {
3881 if (traits::compare(text + lenText - lenPattern, pattern, lenPattern) == 0) {
3898 constexpr size_t find_last(str_piece pattern,
size_t offset = -1) const noexcept {
3899 return find_last(pattern.symbols(), pattern.length(), offset);
3912 size_t fnd = find_last(pattern.symbols(), pattern.length(), offset);
3913 return fnd == str::npos ? fnd : fnd + pattern.length();
3926 auto fnd = find_last(pattern.symbols(), pattern.length(), offset);
3927 return fnd == str::npos ? _len() : fnd;
3940 size_t fnd = find_last(pattern.symbols(), pattern.length(), offset);
3941 return fnd == str::npos ? _len() : fnd + pattern.length();
3953 constexpr bool contains(str_piece pattern,
size_t offset = 0) const noexcept {
3954 return find(pattern, offset) != str::npos;
3966 constexpr size_t find(K s,
size_t offset = 0) const noexcept {
3967 size_t len = _len();
3969 const K *
str = _str(), *fnd = traits::find(
str + offset, len - offset, s);
3971 return static_cast<size_t>(fnd -
str);
3986 size_t len = _len();
3988 const K *
str = _str(), *fnd = traits::find(
str + offset, len - offset, s);
3990 return static_cast<size_t>(fnd -
str);
3995 template<
typename Op>
3996 constexpr void for_all_finded(
const Op& op,
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
3999 while (maxCount-- > 0) {
4000 size_t fnd = find(pattern, patternLen, offset);
4001 if (fnd == str::npos)
4004 offset = fnd + patternLen;
4019 template<
typename Op>
4020 constexpr void for_all_finded(
const Op& op, str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
4021 for_all_finded(op, pattern.symbols(), pattern.length(), offset, maxCount);
4024 template<
typename To = std::vector<
size_t>>
4025 constexpr To find_all(
const K* pattern,
size_t patternLen,
size_t offset,
size_t maxCount)
const {
4027 for_all_finded([&](
auto f) { result.emplace_back(f); }, pattern, patternLen, offset, maxCount);
4042 template<
typename To = std::vector<
size_t>>
4043 constexpr To
find_all(str_piece pattern,
size_t offset = 0,
size_t maxCount = 0)
const {
4044 return find_all(pattern.symbols(), pattern.length(), offset, maxCount);
4046 template<
typename To = std::vector<
size_t>>
4047 constexpr void find_all_to(To& to,
const K* pattern,
size_t len,
size_t offset = 0,
size_t maxCount = 0)
const {
4048 return for_all_finded([&](
size_t pos) {
4049 to.emplace_back(pos);
4050 }, pattern, len, offset, maxCount);
4062 constexpr size_t find_last(K s,
size_t offset = -1) const noexcept {
4063 size_t len = std::min(_len(), offset);
4064 const K *text = _str();
4066 if (text[--len] == s)
4081 constexpr size_t find_first_of(str_piece pattern,
size_t offset = 0) const noexcept {
4082 return std::basic_string_view<K>{_str(), _len()}.find_first_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
4094 constexpr std::pair<size_t, size_t>
find_first_of_idx(str_piece pattern,
size_t offset = 0) const noexcept {
4095 const K* text = _str();
4096 size_t fnd = std::basic_string_view<K>{text, _len()}.find_first_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
4097 return {fnd, fnd == std::basic_string<K>::npos ? fnd : pattern.find(text[fnd]) };
4110 return std::basic_string_view<K>{_str(), _len()}.find_first_not_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
4122 constexpr size_t find_last_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
4123 return std::basic_string_view<K>{_str(), _len()}.find_last_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
4135 constexpr std::pair<size_t, size_t>
find_last_of_idx(str_piece pattern,
size_t offset = str::npos)
const noexcept {
4136 const K* text = _str();
4137 size_t fnd = std::basic_string_view<K>{text, _len()}.find_last_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
4138 return {fnd, fnd == std::basic_string<K>::npos ? fnd : pattern.find(text[fnd]) };
4150 constexpr size_t find_last_not_of(str_piece pattern,
size_t offset = str::npos)
const noexcept {
4151 return std::basic_string_view<K>{_str(), _len()}.find_last_not_of(std::basic_string_view<K>{pattern.str, pattern.len}, offset);
4163 [[deprecated(
"Use substring(start, end)")]]
4164 constexpr my_type
substr(ptrdiff_t from, ptrdiff_t len = 0)
const {
4165 return my_type{d()(from, len)};
4175 template<
typename T, first_index_in_str S, last_index_in_str E>
requires std::is_constructible_v<T, str_piece>
4177 str_piece res =
slice(start, end);
4178 if constexpr (std::is_constructible_v<T, const my_type&> && !std::is_same_v<T, str_piece>) {
4179 if (res.is_same(*
this)) {
4189 template<first_index_in_str S, last_index_in_str E>
4190 constexpr my_type
substring(S start, E end)
const noexcept {
4203 [[deprecated(
"Use slice_to(start, end)")]]
4204 constexpr my_type
str_mid(
size_t from,
size_t len = -1)
const {
4205 return my_type{d().mid(from, len)};
4235 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
4237 auto [res, err, _] = int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
4268 template<ToIntNumber T,
bool CheckOverflow = true,
unsigned Base = 0,
bool SkipWs = true,
bool AllowSign = true>
4269 constexpr convert_result<T>
to_int() const noexcept {
4270 return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
4278 template<
bool SkipWS = true,
bool AllowPlus = true>
4279 requires(
sizeof(K) == 1 &&
4280 requires { std::from_chars(std::declval<K*>(), std::declval<K*>(), std::declval<double&>()); })
4282 size_t len = _len();
4283 const K* ptr = _str();
4284 if constexpr (SkipWS) {
4285 while (len && uns_type(*ptr) <=
' ') {
4290 if constexpr (AllowPlus) {
4291 if (len && *ptr == K(
'+')) {
4299 if constexpr (
requires { std::from_chars(std::declval<K*>(), std::declval<K*>(), std::declval<double&>()); }) {
4301 if (std::from_chars((
const K*)ptr, (
const K*)ptr + len, d).ec == std::errc{}) {
4313 template<
bool SkipWS = true>
4314 requires(
sizeof(K) == 1 &&
4315 requires { std::from_chars(std::declval<K*>(), std::declval<K*>(), std::declval<double&>()); })
4317 size_t len = _len();
4318 const K* ptr = _str();
4319 if constexpr (SkipWS) {
4320 while (len && uns_type(*ptr) <=
' ') {
4326 if constexpr (
requires { std::from_chars(std::declval<K*>(), std::declval<K*>(), std::declval<double&>()); }) {
4328 if (std::from_chars((
const K*)ptr, (
const K*)ptr + len, d, std::chars_format::hex).ec == std::errc{}) {
4343 template<ToIntNumber T>
4348 template<
typename T,
typename Op>
4349 constexpr T splitf(
const K* delimiter,
size_t lendelimiter,
const Op& beforeFunc,
size_t offset)
const {
4350 size_t mylen = _len();
4351 std::conditional_t<std::is_same_v<T, void>, char, T> results;
4352 str_piece me{_str(), mylen};
4353 for (
size_t i = 0;; i++) {
4354 size_t beginOfDelim = find(delimiter, lendelimiter, offset);
4355 if (beginOfDelim == str::npos) {
4356 str_piece last{me.symbols() + offset, me.length() - offset};
4357 if constexpr (std::is_invocable_v<Op, str_piece&>) {
4360 if constexpr (
requires { results.emplace_back(last); }) {
4361 if (last.is_same(me)) {
4364 results.emplace_back(d());
4366 results.emplace_back(last);
4368 }
else if constexpr (
requires { results.push_back(last); }) {
4369 if (last.is_same(me)) {
4372 results.push_back(d());
4374 results.push_back(last);
4376 }
else if constexpr (
requires {results[i] = last;} &&
requires{std::size(results);}) {
4377 if (i < std::size(results)) {
4378 if (last.is_same(me)) {
4388 str_piece piece{me.symbols() + offset, beginOfDelim - offset};
4389 if constexpr (std::is_invocable_v<Op, str_piece&>) {
4392 if constexpr (
requires { results.emplace_back(piece); }) {
4393 results.emplace_back(piece);
4394 }
else if constexpr (
requires { results.push_back(piece); }) {
4395 results.push_back(piece);
4396 }
else if constexpr (
requires { results[i] = piece; } &&
requires{std::size(results);}) {
4397 if (i < std::size(results)) {
4399 if (i == results.size() - 1) {
4404 offset = beginOfDelim + lendelimiter;
4406 if constexpr (!std::is_same_v<T, void>) {
4440 template<
typename T,
typename Op>
4441 constexpr T
splitf(str_piece delimiter,
const Op& beforeFunc,
size_t offset = 0)
const {
4442 return splitf<T>(delimiter.symbols(), delimiter.length(), beforeFunc, offset);
4456 template<
typename T>
4457 constexpr T
split(str_piece delimiter,
size_t offset = 0)
const {
4458 return splitf<T>(delimiter.symbols(), delimiter.length(), 0, offset);
4463 constexpr bool starts_with(
const K* prefix,
size_t l)
const noexcept {
4464 return _len() >= l && 0 == traits::compare(_str(), prefix, l);
4482 return _len() >
prefix.length() &&
4484 trim_operator<TrimSides::TrimLeft, K, size_t(-1),
true>{}.isTrim(_str()[
prefix.length()]);
4495 return _len() >
prefix.length() &&
4497 trim_operator<TrimSides::TrimLeft, K, 0, false>{next_symbol}.isTrim(_str()[
prefix.length()]);
4499 template<typename T, size_t N = const_lit_for<K, T>::Count,
StrType<K> From>
requires is_const_pattern<N>
4500 constexpr bool starts_with_and_oneof(str_piece prefix, T&& next_symbol)
const noexcept {
4501 return _len() >= N &&
4502 starts_with(prefix) &&
4503 trim_operator<TrimSides::TrimLeft, K, N - 1,
false>{next_symbol}.isTrim(_str()[prefix.length()]);
4506 constexpr bool starts_with_ia(
const K* prefix,
size_t len)
const noexcept {
4507 size_t myLen = _len();
4511 const K* ptr1 = _str();
4513 K s1 = *ptr1++, s2 = *prefix++;
4516 if (makeAsciiLower(s1) != makeAsciiLower(s2))
4528 return starts_with_ia(
prefix.symbols(),
prefix.length());
4537 return _len() >
prefix.length() &&
4538 starts_with_ia(
prefix) &&
4539 trim_operator<TrimSides::TrimLeft, K, size_t(-1),
true>{}.isTrim(_str()[
prefix.length()]);
4550 return _len() >
prefix.length() &&
4551 starts_with_ia(
prefix) &&
4552 trim_operator<TrimSides::TrimLeft, K, 0, false>{next_symbol}.isTrim(_str()[
prefix.length()]);
4554 template<typename T, size_t N = const_lit_for<K, T>::Count,
StrType<K> From>
requires is_const_pattern<N>
4555 constexpr bool starts_with_ia_and_oneof(str_piece prefix, T&& next_symbol)
const noexcept {
4556 return _len() >= N &&
4557 starts_with_ia(prefix) &&
4558 trim_operator<TrimSides::TrimLeft, K, N - 1,
false>{next_symbol}.isTrim(_str()[prefix.length()]);
4563 constexpr bool prefix_in(
const K* text,
size_t len)
const noexcept {
4564 size_t myLen = _len();
4567 return !myLen || 0 == traits::compare(text, _str(), myLen);
4576 return prefix_in(text.symbols(), text.length());
4580 constexpr bool ends_with(
const K* suffix,
size_t len)
const noexcept {
4581 size_t myLen = _len();
4582 return len <= myLen && traits::compare(_str() + myLen - len, suffix, len) == 0;
4595 constexpr bool ends_with_ia(
const K* suffix,
size_t len)
const noexcept {
4596 size_t myLen = _len();
4600 const K* ptr1 = _str() + myLen - len;
4602 K s1 = *ptr1++, s2 = *suffix++;
4605 if (makeAsciiLower(s1) != makeAsciiLower(s2))
4617 return ends_with_ia(
suffix.symbols(),
suffix.length());
4626 if (std::is_constant_evaluated()) {
4627 for (
size_t idx = 0; idx < _len(); idx++) {
4628 if (uns_type(_str()[idx]) > 127) {
4634 const int sl = ascii_mask<K>::WIDTH;
4635 const size_t mask = ascii_mask<K>::VALUE;
4636 size_t len = _len();
4637 const uns_type* ptr =
reinterpret_cast<const uns_type*
>(_str());
4638 if constexpr (sl > 1) {
4639 const size_t roundMask =
sizeof(size_t) - 1;
4640 while (len >= sl && (
reinterpret_cast<size_t>(ptr) & roundMask) != 0) {
4646 if (*
reinterpret_cast<const size_t*
>(ptr) & mask)
4666 template<
typename R = my_type>
4668 return R::upperred_only_ascii_from(d());
4678 template<
typename R = my_type>
4680 return R::lowered_only_ascii_from(d());
4698 template<
typename R = my_type>
4699 R
replaced(str_piece pattern, str_piece repl,
size_t offset = 0,
size_t maxCount = 0)
const {
4700 return R::replaced_from(d(), pattern, repl, offset, maxCount);
4714 template<
typename R = str_piece>
4716 if (starts_with(
prefix)) {
4733 template<
typename R = str_piece>
4735 if (starts_with_ia(
prefix)) {
4752 template<
typename R = str_piece>
4771 template<
typename R = str_piece>
4773 if (ends_with_ia(
suffix)) {
4779 template<StrType<K> From>
4780 constexpr static my_type make_trim_op(
const From& from,
const auto& opTrim) {
4781 str_piece sfrom = from, newPos = opTrim(sfrom);
4782 if (newPos.is_same(sfrom)) {
4786 return my_type{newPos};
4788 template<TrimS
ides S, StrType<K> From>
4789 constexpr static my_type trim_static(
const From& from) {
4790 return make_trim_op(from, trim_operator<S, K,
static_cast<size_t>(-1),
true>{});
4793 template<TrimSides S, bool withSpaces, typename T, size_t N = const_lit_for<K, T>::Count, StrType<K> From>
4794 requires is_const_pattern<N>
4795 constexpr static my_type trim_static(
const From& from, T&& pattern) {
4796 return make_trim_op(from, trim_operator<S, K, N - 1, withSpaces>{pattern});
4799 template<TrimS
ides S,
bool withSpaces, StrType<K> From>
4800 constexpr static my_type trim_static(
const From& from, str_piece pattern) {
4801 return make_trim_op(from, trim_operator<S, K, 0, withSpaces>{{pattern}});
4811 template<
typename R = str_piece>
4813 return R::template trim_static<TrimSides::TrimAll>(d());
4823 template<
typename R = str_piece>
4825 return R::template trim_static<TrimSides::TrimLeft>(d());
4835 template<
typename R = str_piece>
4837 return R::template trim_static<TrimSides::TrimRight>(d());
4849 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
4850 requires is_const_pattern<N>
4852 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
4864 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
4865 requires is_const_pattern<N>
4867 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
4879 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
4880 requires is_const_pattern<N>
4882 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
4901 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
4902 requires is_const_pattern<N>
4904 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
4920 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
4921 requires is_const_pattern<N>
4923 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
4939 template<typename R = str_piece, typename T, size_t N = const_lit_for<K, T>::Count>
4940 requires is_const_pattern<N>
4942 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
4957 template<
typename R = str_piece>
4959 return R::template trim_static<TrimSides::TrimAll, false>(d(), pattern);
4971 template<
typename R = str_piece>
4973 return R::template trim_static<TrimSides::TrimLeft, false>(d(), pattern);
4985 template<
typename R = str_piece>
4987 return R::template trim_static<TrimSides::TrimRight, false>(d(), pattern);
5003 template<
typename R = str_piece>
5005 return R::template trim_static<TrimSides::TrimAll, true>(d(), pattern);
5021 template<
typename R = str_piece>
5023 return R::template trim_static<TrimSides::TrimLeft, true>(d(), pattern);
5039 template<
typename R = str_piece>
5041 return R::template trim_static<TrimSides::TrimRight, true>(d(), pattern);
5055 template<
typename R = str_piece>
5057 str_piece res = *
this;
5058 while(res.starts_with(
prefix)) {
5059 res.remove_prefix(
prefix.length());
5060 if (--max_count == 0) {
5078 template<
typename R = str_piece>
5080 str_piece res = *
this;
5081 while(res.starts_with_ia(
prefix)) {
5082 res.remove_prefix(
prefix.length());
5083 if (--max_count == 0) {
5101 template<
typename R = str_piece>
5103 str_piece res = *
this;
5104 while(res.ends_with(
suffix)) {
5105 res.remove_suffix(
suffix.length());
5121 template<
typename R = str_piece>
5123 str_piece res = *
this;
5124 while(res.ends_with_ia(
suffix)) {
5125 res.remove_suffix(
suffix.length());
5144template<
size_t N>
requires (N > 1)
5145struct find_all_container {
5146 static constexpr size_t max_capacity = N;
5147 size_t positions_[N];
5150 constexpr void emplace_back(
size_t pos) {
5151 positions_[added_++] = pos;
5174struct str_src : str_src_algs<K, str_src<K>, str_src<K>, false> {
5175 using symb_type = K;
5176 using my_type = str_src<K>;
5178 const symb_type* str;
5181 str_src() =
default;
5186 template<typename T, size_t N = const_lit_for<K, T>::Count>
5187 constexpr str_src(T&& v) noexcept : str((
const K*)v), len(N - 1) {}
5193 constexpr str_src(
const K* p,
size_t l) noexcept : str(p), len(l) {}
5195 template<StrType<K> T>
5196 constexpr str_src(T&& t) :
str(t.symbols()), len(t.length()){}
5202 template<
typename A>
5203 constexpr str_src(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : str(s.data()), len(s.length()) {}
5208 constexpr str_src(
const std::basic_string_view<K, std::char_traits<K>>& s) noexcept : str(s.data()), len(s.length()) {}
5221 constexpr const symb_type*
symbols() const noexcept {
5237 constexpr bool is_same(str_src<K> other)
const noexcept {
5238 return str == other.str && len == other.len;
5247 return str >= other.str && str + len <= other.str + other.len;
5310struct str_src_nt : str_src<K>, null_terminated<K, str_src_nt<K>> {
5311 using symb_type = K;
5312 using my_type = str_src_nt<K>;
5313 using base = str_src<K>;
5315 constexpr static const K empty_string[1] = {0};
5317 str_src_nt() =
default;
5334 template<
typename T>
requires std::is_same_v<std::remove_const_t<std::remove_pointer_t<std::remove_cvref_t<T>>>, K>
5337 base::str = base::len ? p : empty_string;
5343 template<typename T, size_t N = const_lit_for<K, T>::Count>
5344 constexpr str_src_nt(T&& v) noexcept : base(std::forward<T>(v)) {}
5350 constexpr str_src_nt(
const K* p,
size_t l) noexcept : base(p, l) {}
5352 template<StrType<K> T>
5355 base::len = t.length();
5361 template<
typename A>
5362 constexpr str_src_nt(
const std::basic_string<K, std::char_traits<K>, A>& s) noexcept : base(s) {}
5364 static const my_type empty_str;
5374 if (from > base::len) {
5377 return {base::str + from, base::len - from};
5382inline const str_src_nt<K> str_src_nt<K>::empty_str{str_src_nt<K>::empty_string, 0};
5383template<
typename K>
struct simple_str_selector;
5385inline namespace literals {
5445template<
char...Chars>
5446SS_CONSTEVAL
auto operator""_fmt() {
5447 return f::skip_0x<Chars...>();
5452#ifndef IN_FULL_SIMSTR
5455using simple_str = str_src<K>;
5458struct simple_str_selector {
5459 using type = simple_str<K>;
5463using simple_str_nt = str_src_nt<K>;
5466using Splitter = SplitterBase<K, str_src<K>>;
5468using ssa = str_src<u8s>;
5469using ssb = str_src<ubs>;
5470using ssw = str_src<wchar_t>;
5471using ssu = str_src<u16s>;
5472using ssuu = str_src<u32s>;
5473using stra = str_src_nt<u8s>;
5474using strb = str_src_nt<ubs>;
5475using strw = str_src_nt<wchar_t>;
5476using stru = str_src_nt<u16s>;
5477using struu = str_src_nt<u32s>;
5480consteval 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) {
5481 if constexpr (std::is_same_v<K, u8s>)
5483 if constexpr (std::is_same_v<K, ubs>)
5485 if constexpr (std::is_same_v<K, uws>)
5487 if constexpr (std::is_same_v<K, u16s>)
5489 if constexpr (std::is_same_v<K, u32s>)
5493#define uni_string(K, p) select_str<K>(p, u8##p, L##p, u##p, U##p)
5495inline namespace literals {
5568template<
typename K,
bool withSpaces>
5569struct CheckSpaceTrim {
5570 constexpr bool is_trim_spaces(K s)
const {
5571 return s ==
' ' || (s >= 9 && s <= 13);
5575struct CheckSpaceTrim<K, false> {
5576 constexpr bool is_trim_spaces(K)
const {
5582struct CheckSymbolsTrim {
5584 constexpr bool is_trim_symbols(K s)
const {
5585 return symbols.len != 0 && str_src<K>::traits::find(symbols.str, symbols.len, s) !=
nullptr;
5589template<
typename K,
size_t N>
5590struct CheckConstSymbolsTrim {
5591 const const_lit_to_array<K, N> symbols;
5593 template<typename T, size_t M = const_lit_for<K, T>::Count>
requires (M == N + 1)
5594 constexpr CheckConstSymbolsTrim(T&& s) : symbols(std::forward<T>(s)) {}
5596 constexpr bool is_trim_symbols(K s)
const noexcept {
5597 return symbols.contain(s);
5602struct CheckConstSymbolsTrim<K, 0> {
5603 constexpr bool is_trim_symbols(K)
const {
5608template<
typename K,
size_t N>
5609struct SymbSelector {
5610 using type = CheckConstSymbolsTrim<K, N>;
5614struct SymbSelector<K, 0> {
5615 using type = CheckSymbolsTrim<K>;
5619struct SymbSelector<K, static_cast<size_t>(-1)> {
5620 using type = CheckConstSymbolsTrim<K, 0>;
5623template<TrimS
ides S,
typename K,
size_t N,
bool withSpaces>
5624struct trim_operator : SymbSelector<K, N>::type, CheckSpaceTrim<K, withSpaces> {
5625 constexpr bool isTrim(K s)
const {
5626 return CheckSpaceTrim<K, withSpaces>::is_trim_spaces(s) || SymbSelector<K, N>::type::is_trim_symbols(s);
5628 constexpr str_src<K> operator()(str_src<K> from)
const {
5629 if constexpr ((S & TrimSides::TrimLeft) != 0) {
5631 if (isTrim(*from.str)) {
5638 if constexpr ((S & TrimSides::TrimRight) != 0) {
5639 const K* back = from.str + from.len - 1;
5641 if (isTrim(*back)) {
5652template<TrimS
ides S,
typename K>
5653using SimpleTrim = trim_operator<S, K, size_t(-1),
true>;
5655template<TrimSides S = TrimSides::TrimAll, bool withSpaces = false, typename K, typename T, size_t N = const_lit_for<K, T>::Count>
5656 requires is_const_pattern<N>
5657constexpr inline auto trimOp(T&& pattern) {
5658 return trim_operator<S, K, N - 1, withSpaces>{pattern};
5661template<TrimS
ides S = TrimS
ides::TrimAll,
bool withSpaces = false,
typename K>
5662constexpr inline auto trimOp(str_src<K> pattern) {
5663 return trim_operator<S, K, 0, withSpaces>{pattern};
5666static constexpr size_t FIND_CACHE_SIZE = 16;
5668template<
typename K,
size_t N,
size_t L>
5669struct expr_replaces : expr_to_std_string<expr_replaces<K, N, L>> {
5670 using symb_type = K;
5671 using my_type = expr_replaces<K, N, L>;
5673 const K(&pattern)[N + 1];
5674 const K(&repl)[L + 1];
5675 mutable find_all_container<FIND_CACHE_SIZE> matches_;
5676 mutable size_t last_;
5678 constexpr expr_replaces(str_src<K> w,
const K(&p)[N + 1],
const K(&r)[L + 1]) : what(w), pattern(p), repl(r) {}
5680 constexpr size_t length()
const {
5681 size_t l = what.length();
5682 if constexpr (N == L) {
5685 what.find_all_to(matches_, pattern, N, 0, FIND_CACHE_SIZE);
5686 if (matches_.added_) {
5687 last_ = matches_.positions_[matches_.added_ - 1] + N;
5688 l += int(L - N) * matches_.added_;
5690 if (matches_.added_ == FIND_CACHE_SIZE) {
5692 size_t next = what.find(pattern, N, last_);
5693 if (next == str::npos) {
5702 matches_.added_ = -1;
5706 constexpr K* place(K* ptr)
const noexcept {
5707 if constexpr (N == L) {
5708 const K* from = what.symbols();
5709 for (
size_t start = 0; start < what.length();) {
5710 size_t next = what.find(pattern, N, start);
5711 if (next == str::npos) {
5712 next = what.length();
5714 size_t delta = next - start;
5715 ch_traits<K>::copy(ptr, from + start, delta);
5717 ch_traits<K>::copy(ptr, repl, L);
5723 if (matches_.added_ == 0) {
5724 return what.place(ptr);
5725 }
else if (matches_.added_ ==
size_t(-1)) {
5729 const K* from = what.symbols();
5730 for (
size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
5731 ch_traits<K>::copy(ptr, from + start, offset - start);
5732 ptr += offset - start;
5733 ch_traits<K>::copy(ptr, repl, L);
5736 if (start >= last_) {
5737 size_t tail = what.length() - last_;
5738 ch_traits<K>::copy(ptr, from + last_, tail);
5742 offset = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern, N, start);
5762template<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>
5765 return expr_replaces<K, N - 1, L - 1>{std::forward<A>(w), p, r};
5777 using symb_type = K;
5782 mutable find_all_container<FIND_CACHE_SIZE> matches_;
5783 mutable size_t last_;
5796 constexpr size_t length()
const {
5798 if (!plen || plen == rlen) {
5801 what.find_all_to(matches_, pattern.
symbols(), plen, 0, FIND_CACHE_SIZE);
5802 if (matches_.added_) {
5803 last_ = matches_.positions_[matches_.added_ - 1] + plen;
5804 l += int(rlen - plen) * matches_.added_;
5806 if (matches_.added_ == FIND_CACHE_SIZE) {
5808 size_t next = what.find(pattern.
symbols(), plen, last_);
5809 if (next == str::npos) {
5812 last_ = next + plen;
5818 matches_.added_ = -1;
5822 constexpr K* place(K* ptr)
const noexcept {
5825 const K* from = what.
symbols();
5826 for (
size_t start = 0; start < what.
length();) {
5827 size_t next = what.find(pattern, start);
5828 if (next == str::npos) {
5831 size_t delta = next - start;
5832 ch_traits<K>::copy(ptr, from + start, delta);
5834 ch_traits<K>::copy(ptr, repl.
symbols(), rlen);
5836 start = next + plen;
5840 if (matches_.added_ == 0) {
5841 return what.
place(ptr);
5842 }
else if (matches_.added_ == -1) {
5846 const K* from = what.
symbols();
5847 for (
size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
5848 ch_traits<K>::copy(ptr, from + start, offset - start);
5849 ptr += offset - start;
5850 ch_traits<K>::copy(ptr, repl.
symbols(), rlen);
5852 start = offset + plen;
5853 if (start >= last_) {
5854 size_t tail = what.
length() - start;
5855 ch_traits<K>::copy(ptr, from + start, tail);
5859 offset = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern.
symbols(), plen, start);
5881template<
typename K, StrExprForType<K> E>
5883 using symb_type = K;
5887 mutable size_t replLen;
5888 mutable find_all_container<FIND_CACHE_SIZE> matches_;
5889 mutable size_t last_;
5903 constexpr size_t length()
const {
5908 matches_.positions_[0] = what.find(pattern);
5909 if (matches_.positions_[0] == -1) {
5913 matches_.added_ = 1;
5915 replLen = expr.length();
5916 if (replLen == plen) {
5920 what.find_all_to(matches_, pattern.
symbols(), plen, matches_.positions_[0] + plen, FIND_CACHE_SIZE - 1);
5922 last_ = matches_.positions_[matches_.added_ - 1] + plen;
5923 l += int(replLen - plen) * matches_.added_;
5925 if (matches_.added_ == FIND_CACHE_SIZE) {
5927 size_t next = what.find(pattern.
symbols(), plen, last_);
5928 if (next == str::npos) {
5931 last_ = next + plen;
5932 l += replLen - plen;
5936 matches_.added_ = -1;
5940 constexpr K* place(K* ptr)
const noexcept {
5941 if (matches_.added_ == 0) {
5943 return what.
place(ptr);
5944 }
else if (matches_.added_ == -1) {
5948 size_t plen = pattern.
length();
5949 const K* from = what.
symbols();
5950 ch_traits<K>::copy(ptr, from, matches_.positions_[0]);
5951 ptr += matches_.positions_[0];
5952 const K* repl = ptr;
5953 expr.
place((
typename E::symb_type*)ptr);
5955 size_t start = matches_.positions_[0] + plen;
5957 if (plen == replLen) {
5959 size_t next = what.find(pattern, start);
5960 if (next == str::npos) {
5963 size_t delta = next - start;
5964 ch_traits<K>::copy(ptr, from + start, delta);
5966 ch_traits<K>::copy(ptr, repl, replLen);
5968 start = next + plen;
5971 for (
size_t idx = 1;;) {
5972 if (start >= last_) {
5975 size_t next = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern, start);
5976 size_t delta = next - start;
5977 ch_traits<K>::copy(ptr, from + start, delta);
5979 ch_traits<K>::copy(ptr, repl, replLen);
5981 start = next + plen;
5984 size_t tail = what.
length() - start;
5985 ch_traits<K>::copy(ptr, from + start, tail);
6003template<StrSource A,
typename K = symb_type_from_src_t<A>,
typename T,
typename X>
6004 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>))
6024template<StrSource A,
typename K = symb_type_from_src_t<A>,
typename T, StrExprForType<K> E>
6025 requires std::is_constructible_v<str_src<K>, T>
6026constexpr auto e_repl(A&& w, T&& p,
const E& expr) {
6031template<
bool UseVectorForReplace>
6032struct replace_search_result_store {
6034 std::pair<size_t, size_t> replaces_[16];
6038struct replace_search_result_store<true> : std::vector<std::pair<size_t, size_t>> {};
6042template<
typename K,
size_t N,
bool UseVectorForReplace>
6043struct expr_replace_const_symbols : expr_to_std_string<expr_replace_const_symbols<K, N, UseVectorForReplace>> {
6044 using symb_type = K;
6045 inline static const int BIT_SEARCH_TRESHHOLD = 4;
6046 const K pattern_[N];
6047 const str_src<K> source_;
6048 const str_src<K> replaces_[N];
6050 mutable replace_search_result_store<UseVectorForReplace> search_results_;
6052 [[_no_unique_address]]
6053 uu8s bit_mask_[N >= BIT_SEARCH_TRESHHOLD ? (
sizeof(K) == 1 ? 32 : 64) : 0]{};
6055 template<
typename ... Repl>
requires (
sizeof...(Repl) == N * 2)
6056 constexpr expr_replace_const_symbols(str_src<K> source, Repl&& ... repl) : expr_replace_const_symbols(0, source, std::forward<Repl>(repl)...) {}
6058 size_t length()
const {
6059 size_t l = source_.length();
6060 auto [fnd, num] = find_first_of(source_.str, source_.len);
6061 if (fnd == str::npos) {
6064 l += replaces_[num].len - 1;
6065 if constexpr (UseVectorForReplace) {
6066 search_results_.reserve((l >> 4) + 8);
6067 search_results_.emplace_back(fnd, num);
6068 for (
size_t start = fnd + 1;;) {
6069 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6070 if (fnd == str::npos) {
6073 search_results_.emplace_back(fnd, idx);
6075 l += replaces_[idx].len - 1;
6078 const size_t max_store = std::size(search_results_.replaces_);
6079 search_results_.replaces_[0] = {fnd, num};
6080 search_results_.count_++;
6081 for (
size_t start = fnd + 1;;) {
6082 auto [found, idx] = find_first_of(source_.str, source_.len, start);
6083 if (found == str::npos) {
6086 if (search_results_.count_ < max_store) {
6087 search_results_.replaces_[search_results_.count_] = {found, idx};
6089 l += replaces_[idx].len - 1;
6090 search_results_.count_++;
6096 K* place(K* ptr)
const noexcept {
6098 const K* text = source_.str;
6099 if constexpr (UseVectorForReplace) {
6100 for (
const auto& [pos, num] : search_results_) {
6101 size_t delta = pos - start;
6102 ch_traits<K>::copy(ptr, text + start, delta);
6104 ptr = replaces_[num].place(ptr);
6108 const size_t max_store = std::size(search_results_.replaces_);
6109 size_t founded = search_results_.count_;
6110 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
6111 const auto [pos, num] = search_results_.replaces_[idx];
6112 size_t delta = pos - start;
6113 ch_traits<K>::copy(ptr, text + start, delta);
6115 ptr = replaces_[num].place(ptr);
6118 if (founded > max_store) {
6119 founded -= max_store;
6121 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6122 size_t delta = fnd - start;
6123 ch_traits<K>::copy(ptr, text + start, delta);
6125 ptr = replaces_[idx].place(ptr);
6130 size_t tail = source_.len - start;
6131 ch_traits<K>::copy(ptr, text + start, tail);
6136 template<
typename ... Repl>
6137 constexpr expr_replace_const_symbols(
int, str_src<K> source, K s, str_src<K> r, Repl&&... repl) :
6138 expr_replace_const_symbols(0, source, std::forward<Repl>(repl)..., std::make_pair(s, r)){}
6140 template<
typename ... Repl>
requires (
sizeof...(Repl) == N)
6141 constexpr expr_replace_const_symbols(
int, str_src<K> source, Repl&&... repl) :
6142 source_(source), pattern_ {repl.first...}, replaces_{repl.second...}
6144 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6145 for (
size_t idx = 0; idx < N; idx++) {
6146 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
6147 if constexpr (
sizeof(K) == 1) {
6148 bit_mask_[s >> 3] |= 1 << (s & 7);
6150 if (std::make_unsigned_t<const K>(pattern_[idx]) > 255) {
6151 bit_mask_[32 + (s >> 3)] |= 1 << (s & 7);
6153 bit_mask_[s >> 3] |= 1 << (s & 7);
6160 template<
size_t Idx>
6161 size_t index_of(K s)
const {
6162 if constexpr (Idx < N) {
6163 return pattern_[Idx] == s ? Idx : index_of<Idx + 1>(s);
6167 bool is_in_mask(uu8s s)
const {
6168 return (bit_mask_[s >> 3] & (1 <<(s & 7))) != 0;
6170 bool is_in_mask2(uu8s s)
const {
6171 return (bit_mask_[32 + (s >> 3)] & (1 <<(s & 7))) != 0;
6173 bool is_in_pattern(K s,
size_t& idx)
const {
6174 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6175 if constexpr (
sizeof(K) == 1) {
6176 if (is_in_mask(s)) {
6177 idx = index_of<0>(s);
6181 if (std::make_unsigned_t<const K>(s) > 255) {
6182 if (is_in_mask2(s)) {
6183 return (idx = index_of<0>(s)) != -1;
6186 if (is_in_mask(s)) {
6187 idx = index_of<0>(s);
6195 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
6196 if constexpr (N >= BIT_SEARCH_TRESHHOLD) {
6198 while (offset < len) {
6199 if (is_in_pattern(text[offset], idx)) {
6200 return {offset, idx};
6205 while (offset < len) {
6206 if (
size_t idx = index_of<0>(text[offset]); idx != -1) {
6207 return {offset, idx};
6255template<
bool UseVector = false, StrSource A,
typename K = symb_type_from_src_t<A>,
typename ... Repl>
6256 requires (
sizeof...(Repl) % 2 == 0)
6258 return expr_replace_const_symbols<K,
sizeof...(Repl) / 2, UseVector>(std::forward<A>(src), std::forward<Repl>(other)...);
6300template<
typename K,
bool UseVectorForReplace = false>
6302 using symb_type = K;
6303 using str_t =
typename simple_str_selector<K>::type;
6304 inline static const int BIT_SEARCH_TRESHHOLD = 4;
6307 const std::vector<std::pair<K, str_t>>& replaces_;
6309 std::basic_string<K, ch_traits<K>, std::allocator<K>> pattern_;
6311 mutable replace_search_result_store<UseVectorForReplace> search_results_;
6313 uu8s bit_mask_[
sizeof(K) == 1 ? 32 : 64]{};
6342 : source_(source), replaces_(repl)
6344 size_t pattern_len = replaces_.size();
6345 pattern_.resize(pattern_len);
6346 K* pattern = pattern_.data();
6348 for (
size_t idx = 0; idx < replaces_.size(); idx++) {
6349 *pattern++ = replaces_[idx].first;
6352 if (pattern_len >= BIT_SEARCH_TRESHHOLD) {
6353 for (
size_t idx = 0; idx < pattern_len; idx++) {
6354 uu8s s =
static_cast<uu8s
>(pattern_[idx]);
6355 if constexpr (
sizeof(K) == 1) {
6356 bit_mask_[s >> 3] |= (1 << (s & 7));
6358 if (std::make_unsigned_t<K>(pattern_[idx]) > 255) {
6359 bit_mask_[32 + (s >> 3)] |= (1 << (s & 7));
6361 bit_mask_[s >> 3] |= (1 << (s & 7));
6368 size_t length()
const {
6369 size_t l = source_.
length();
6370 auto [fnd, num] = find_first_of(source_.str, source_.len);
6371 if (fnd == str::npos) {
6374 l += replaces_[num].second.len - 1;
6375 if constexpr (UseVectorForReplace) {
6376 search_results_.reserve((l >> 4) + 8);
6377 search_results_.emplace_back(fnd, num);
6378 for (
size_t start = fnd + 1;;) {
6379 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6380 if (fnd == str::npos) {
6383 search_results_.emplace_back(fnd, idx);
6385 l += replaces_[idx].second.len - 1;
6388 const size_t max_store = std::size(search_results_.replaces_);
6389 search_results_.replaces_[0] = {fnd, num};
6390 search_results_.count_++;
6391 for (
size_t start = fnd + 1;;) {
6392 auto [found, idx] = find_first_of(source_.str, source_.len, start);
6393 if (found == str::npos) {
6396 if (search_results_.count_ < max_store) {
6397 search_results_.replaces_[search_results_.count_] = {found, idx};
6399 l += replaces_[idx].second.len - 1;
6400 search_results_.count_++;
6406 K* place(K* ptr)
const noexcept {
6408 const K* text = source_.str;
6409 if constexpr (UseVectorForReplace) {
6410 for (
const auto& [pos, num] : search_results_) {
6411 size_t delta = pos - start;
6412 ch_traits<K>::copy(ptr, text + start, delta);
6414 ptr = replaces_[num].second.place(ptr);
6418 const size_t max_store = std::size(search_results_.replaces_);
6419 size_t founded = search_results_.count_;
6420 for (
size_t idx = 0, stop = std::min(founded, max_store); idx < stop; idx++) {
6421 const auto [pos, num] = search_results_.replaces_[idx];
6422 size_t delta = pos - start;
6423 ch_traits<K>::copy(ptr, text + start, delta);
6425 ptr = replaces_[num].second.place(ptr);
6428 if (founded > max_store) {
6429 founded -= max_store;
6431 auto [fnd, idx] = find_first_of(source_.str, source_.len, start);
6432 size_t delta = fnd - start;
6433 ch_traits<K>::copy(ptr, text + start, delta);
6435 ptr = replaces_[idx].second.place(ptr);
6440 size_t tail = source_.len - start;
6441 ch_traits<K>::copy(ptr, text + start, tail);
6446 size_t index_of(K s)
const {
6447 return pattern_.find(s);
6450 bool is_in_mask(uu8s s)
const {
6451 return (bit_mask_[s >> 3] & (1 << (s & 7))) != 0;
6453 bool is_in_mask2(uu8s s)
const {
6454 return (bit_mask_[32 + (s >> 3)] & (1 << (s & 7))) != 0;
6457 bool is_in_pattern(K s,
size_t& idx)
const {
6458 if constexpr (
sizeof(K) == 1) {
6459 if (is_in_mask(s)) {
6464 if (std::make_unsigned_t<const K>(s) > 255) {
6465 if (is_in_mask2(s)) {
6466 return (idx = index_of(s)) != -1;
6469 if (is_in_mask(s)) {
6478 std::pair<size_t, size_t> find_first_of(
const K* text,
size_t len,
size_t offset = 0)
const {
6479 size_t pl = pattern_.length();
6480 if (pl >= BIT_SEARCH_TRESHHOLD) {
6482 while (offset < len) {
6483 if (is_in_pattern(text[offset], idx)) {
6484 return {offset, idx};
6489 while (offset < len) {
6490 if (
size_t idx = index_of(text[offset]); idx != -1) {
6491 return {offset, idx};
6500template<
typename K, StrExprForType<K> T>
6503 force_copy(
const T& t) : t_(t){}
6506template<
typename K,
typename T>
6507struct symb_type_from_src<force_copy<K, T>> {
6513force_copy(T&&) -> force_copy<typename T::symb_type, T>;
6515template<
typename K,
typename T>
6516constexpr auto to_subst(T&& t) {
6517 return to_strexpr<K>(std::forward<T>(t));
6520template<
typename K,
typename T,
size_t N>
6521constexpr auto to_subst(
const T(&t)[N]) {
6522 return expr_literal<T, N - 1>{t};
6525template<
typename K, StrExprForType<K> T>
6526constexpr decltype(
auto) to_subst(T&& t) {
6527 return std::forward<T>(t);
6530template<
typename K,
typename T>
6531constexpr T to_subst(
const force_copy<K, T>& t) {
6535template<
typename K,
typename T>
6536constexpr T to_subst(force_copy<K, T>&& t) {
6540template<
typename K,
typename T>
6541constexpr T to_subst(force_copy<K, T>& t) {
6545template<
typename K,
typename T>
6546using to_str_exp_t =
decltype(to_subst<K>(std::declval<T>()));
6555template<
typename K,
typename G,
typename Arg,
typename...Args>
6557 using symb_type = K;
6558 using store_t = std::tuple<to_str_exp_t<K, Args>...>;
6559 using arg_t = to_str_exp_t<K, Arg>;
6560 to_str_exp_t<K, G> glue_;
6563 mutable size_t glue_len_;
6597 : glue_(to_subst<K>(
std::forward<G>(glue)))
6598 , arg_(to_subst<K>(
std::forward<Arg>(arg)))
6599 , args_(to_subst<K>(
std::forward<Args>(args))...) {}
6601 constexpr size_t length() const noexcept {
6602 return [
this]<
size_t...Indexes>(std::index_sequence<Indexes...>) {
6603 glue_len_ = glue_.length();
6604 size_t l = arg_.length() + glue_len_ *
sizeof...(Args);
6605 ((l += std::get<Indexes>(args_).length()),...);
6607 }(std::make_index_sequence<
sizeof...(Args)>());
6609 constexpr K* place(K* ptr)
const noexcept {
6610 return [
this]<
size_t...Indexes>(K* ptr, std::index_sequence<Indexes...>) {
6611 ptr = (K*)arg_.place((
typename std::remove_cvref_t<arg_t>::symb_type*)ptr);
6612 const K* glueStart = ptr;
6613 ptr = glue_.place(ptr);
6616 ptr = (K*)std::get<Indexes>(args_).place((
typename std::remove_cvref_t<std::tuple_element_t<Indexes, store_t>>::symb_type*)ptr),
6617 glue_len_ > 0 && Indexes <
sizeof...(Args) - 1 ? (ch_traits<K>::copy(ptr, glueStart, glue_len_), ptr += glue_len_) :
nullptr
6621 }(ptr, std::make_index_sequence<
sizeof...(Args)>());
6625template<
typename T,
typename ... Args>
requires (
sizeof...(Args) > 1)
6626e_concat(T&&, Args&&...) -> e_concat<symb_type_from_src_t<T>, T, Args...>;
6628struct parse_subst_string_error {
6629 parse_subst_string_error(
const char*){}
6634template<
typename K,
size_t NParams>
6635constexpr size_t parse_pattern_string(str_src<K> pattern,
auto&& add_part,
auto&& add_param) {
6636 char used_args[NParams] = {0};
6637 const K* first = pattern.begin(), *last = pattern.end(), *start = first;
6640 auto find = [](
const K* from,
const K* last, K s) {
6641 while (from != last) {
6649 size_t idx_in_params = 0;
6651 while (first != last) {
6652 const K* open_pos = first;
6653 if (*first !=
'{') {
6654 open_pos = find(first, last,
'{');
6657 const K* close_pos = find(first, open_pos,
'}');
6658 if (close_pos == open_pos) {
6659 unsigned len = open_pos - first;
6660 add_part(first - start, len);
6665 if (close_pos == open_pos || *close_pos !=
'}') {
6666 throw parse_subst_string_error{
"unescaped }"};
6668 unsigned len = close_pos - first;
6669 add_part(first - start, len);
6671 first = ++close_pos;
6673 if (open_pos == last) {
6677 if (++open_pos == last) {
6678 throw parse_subst_string_error{
"unescaped {"};
6680 if (*open_pos ==
'}') {
6681 if (idx_in_params == -1) {
6682 throw parse_subst_string_error{
"already used param ids"};
6684 if (idx_in_params == NParams) {
6685 throw parse_subst_string_error{
"too many params"};
6687 used_args[idx_in_params] = 1;
6688 add_param(idx_in_params++);
6689 first = open_pos + 1;
6690 }
else if (*open_pos ==
'{') {
6691 add_part(open_pos - start, 1);
6693 first = open_pos + 1;
6695 if (idx_in_params != 0 && idx_in_params != -1) {
6696 throw parse_subst_string_error{
"already used non id params"};
6699 const K* end = find(open_pos, last,
'}');
6701 throw parse_subst_string_error{
"not found }"};
6703 auto [p, err, _] = str_src<K>(open_pos, end - open_pos).template to_int<unsigned, true, 10, false, false>();
6704 if (err != IntConvertResult::Success || p < 1 || p > NParams) {
6705 throw parse_subst_string_error{
"bad param id"};
6712 for (
auto c : used_args) {
6714 throw parse_subst_string_error{
"unused param"};
6723 unsigned is_param: 1;
6725 portion() =
default;
6727 constexpr void set_param(
unsigned param) {
6728 if (param >= (1 << 16)) {
6729 throw parse_subst_string_error{
"the parameter id is too large"};
6734 constexpr void set_part(
unsigned from,
unsigned l) {
6735 if (from >= (1 << 16) || len >= (1 << 15)) {
6736 throw parse_subst_string_error{
"the string part is too large"};
6744template<
typename K,
size_t PtLen,
size_t NParams>
6745struct subst_params {
6746 const K(&source_)[PtLen];
6747 unsigned all_len_{};
6751 portion portions_[1 + ((PtLen - 2) * 2 / 3)]{};
6753 consteval subst_params(
const K(&pattern)[PtLen]) : source_(pattern) {
6754 all_len_ = parse_pattern_string<K, NParams>(pattern,
6755 [
this](
unsigned from,
unsigned len) {
6756 portions_[actual_++].set_part(from, len);
6757 }, [
this](
unsigned param) {
6758 portions_[actual_++].set_param(param);
6770template<
typename K,
size_t PtLen,
typename ... Args>
6772 inline static constexpr size_t NParams =
sizeof...(Args);
6773 using symb_type = K;
6774 using store_t = std::tuple<to_str_exp_t<K, Args>...>;
6776 const details::subst_params<K, PtLen, NParams>& subst_;
6818 constexpr e_subst(
const details::subst_params<K, PtLen, NParams>& subst, Args&&...args)
6820 , args_(to_subst<K>(
std::forward<Args>(args))...){}
6822 constexpr size_t length() const noexcept {
6823 return [
this]<
size_t...Indexes>(std::index_sequence<Indexes...>) {
6825 size_t expr_length_[NParams] = {};
6826 ((expr_length_[idx++] = std::get<Indexes>(args_).length()),...);
6827 size_t l = subst_.all_len_;
6828 for (idx = 0; idx < subst_.actual_; idx++) {
6829 if (subst_.portions_[idx].is_param) {
6830 l += expr_length_[subst_.portions_[idx].start];
6834 }(std::make_index_sequence<
sizeof...(Args)>());
6836 template<
size_t Idx>
6837 constexpr K* place_idx(K* ptr,
size_t idx)
const noexcept {
6839 return (K*)std::get<Idx>(args_).place((
typename std::remove_cvref_t<std::tuple_element_t<Idx, store_t>>::symb_type*)ptr);
6841 if constexpr (Idx < NParams - 1) {
6842 return place_idx<Idx + 1>(ptr, idx);
6846 constexpr K* place(K* ptr)
const noexcept {
6847 for (
size_t idx = 0; idx < subst_.actual_; idx++) {
6848 if (subst_.portions_[idx].is_param) {
6849 ptr = place_idx<0>(ptr, subst_.portions_[idx].start);
6851 ch_traits<K>::copy(ptr, subst_.source_ + subst_.portions_[idx].start, subst_.portions_[idx].len);
6852 ptr += subst_.portions_[idx].len;
6860template<
typename K,
size_t N,
typename...Args>
requires (
sizeof...(Args) > 0)
6861e_subst(
const K(&)[N], Args&&...) -> e_subst<K, N, Args...>;
6868template<
typename K,
typename ... Args>
6870 inline static constexpr size_t Nparams =
sizeof...(Args);
6871 using symb_type = K;
6872 using store_t = std::tuple<to_str_exp_t<K, Args>...>;
6874 details::portion portions_[Nparams * 3];
6875 std::vector<details::portion> more_portions_;
6919 , args_(to_subst<K>(
std::forward<Args>(args))...) {
6921 all_len_ = details::parse_pattern_string<K, Nparams>(pattern_, [
this](
unsigned from,
unsigned len) {
6922 if (actual_ < std::size(portions_)) {
6923 portions_[actual_++].set_part(from, len);
6925 if (actual_ == std::size(portions_)) {
6926 more_portions_.reserve((pattern_.len - 1) * 2 / 3 - std::size(portions_));
6928 more_portions_.emplace_back().set_part(from, len);
6930 }, [
this](
unsigned param) {
6931 if (actual_ < std::size(portions_)) {
6932 portions_[actual_++].set_param(param);
6934 if (actual_ == std::size(portions_)) {
6935 more_portions_.reserve((pattern_.len - 1) * 2 / 3 - std::size(portions_));
6937 more_portions_.emplace_back().set_param(param);
6942 constexpr size_t length() const noexcept {
6943 return [
this]<
size_t...Indexes>(std::index_sequence<Indexes...>) {
6945 size_t expr_length_[Nparams] = {};
6946 ((expr_length_[idx++] = std::get<Indexes>(args_).length()),...);
6947 size_t l = all_len_;
6948 for (idx = 0; idx < actual_; idx++) {
6949 if (portions_[idx].is_param) {
6950 l += expr_length_[portions_[idx].start];
6953 for (
const auto& p : more_portions_) {
6955 l += expr_length_[p.start];
6959 }(std::make_index_sequence<
sizeof...(Args)>());
6961 template<
size_t Idx>
6962 constexpr K* place_idx(K* ptr,
size_t idx)
const noexcept {
6964 return (K*)std::get<Idx>(args_).place((
typename std::remove_cvref_t<std::tuple_element_t<Idx, store_t>>::symb_type*)ptr);
6966 if constexpr (Idx < Nparams - 1) {
6967 return place_idx<Idx + 1>(ptr, idx);
6971 constexpr K* place(K* ptr)
const noexcept {
6972 for (
size_t idx = 0; idx < actual_; idx++) {
6973 if (portions_[idx].is_param) {
6974 ptr = place_idx<0>(ptr, portions_[idx].start);
6976 ch_traits<K>::copy(ptr, pattern_.
symbols() + portions_[idx].start, portions_[idx].len);
6977 ptr += portions_[idx].len;
6980 for (
const auto& p : more_portions_) {
6982 ptr = place_idx<0>(ptr, p.start);
6984 const K* from = pattern_.
symbols() + p.start;
6985 for (
size_t idx = p.len; idx--;) {
6996template<StrSourceNoLiteral T,
typename...Args>
requires (
sizeof...(Args) > 0)
6997e_vsubst(T&&, Args&&...) -> e_vsubst<symb_type_from_src_t<T>, Args...>;
6999template<is_one_of_
char_v K,
bool upper>
7000struct expr_change_case_ascii : expr_to_std_string<expr_change_case_ascii<K, upper>>{
7001 using symb_type = K;
7005 template<StrSource S>
7006 expr_change_case_ascii(S&& s) : src_(std::forward<S>(s)){}
7008 constexpr size_t length() const noexcept {
7009 return src_.length();
7011 constexpr K* place(K* ptr)
const noexcept {
7012 const K* read = src_.str;
7013 for (
size_t l = src_.len; l--;) {
7014 if constexpr (upper) {
7015 *ptr++ = makeAsciiUpper(*read++);
7017 *ptr++ = makeAsciiLower(*read++);
7038template<is_one_of_
char_v K>
7040 using base = expr_change_case_ascii<K, true>;
7044template<StrSource S>
7061template<is_one_of_
char_v K>
7063 using base = expr_change_case_ascii<K, false>;
7067template<StrSource S>
7108template<
typename K,
typename A, StrExprForType<K> E>
7109std::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) {
7110 size_t expr_length = expr.length();
7112 str.erase(from, count);
7115 size_t str_length =
str.length();
7116 if (from > str_length) {
7119 if (count > str_length || from + count > str_length) {
7120 count = str_length - from;
7122 size_t new_length = str_length - count + expr_length;
7123 size_t tail_length = str_length - count - from;
7125 if (new_length <= str_length) {
7126 K* data =
str.data();
7127 expr.place((
typename E::symb_type*)data + from);
7128 if (expr_length < count) {
7130 std::char_traits<K>::move(data + from + expr_length, data + from + count, tail_length);
7132 str.resize(new_length);
7135 auto fill = [&](K* data, size_t) ->
size_t {
7137 std::char_traits<K>::move(data + from + expr_length, data + from + count, tail_length);
7139 expr.place((
typename E::symb_type*)data + from);
7142 if constexpr (
requires{
str.resize_and_overwrite(new_length, fill);}) {
7143 str.resize_and_overwrite(new_length, fill);
7144 }
else if constexpr (
requires{
str._Resize_and_overwrite(new_length, fill);}) {
7145 str._Resize_and_overwrite(new_length, fill);
7147 str.resize(new_length);
7148 fill(
str.data(), 0);
7181template<
typename K,
typename A, StrExprForType<K> E>
7182std::basic_string<K, std::char_traits<K>, A>&
append(std::basic_string<K, std::char_traits<K>, A>&
str,
const E& expr) {
7214template<
typename K,
typename A, StrExprForType<K> E>
7215std::basic_string<K, std::char_traits<K>, A>&
prepend(std::basic_string<K, std::char_traits<K>, A>&
str,
const E& expr) {
7249template<
typename K,
typename A, StrExprForType<K> E>
7250std::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) {
7278template<
typename K,
typename A, StrExprForType<K> E>
7279std::basic_string<K, std::char_traits<K>, A>&
overwrite(std::basic_string<K, std::char_traits<K>, A>&
str,
const E& expr) {
7280 if (
size_t expr_length = expr.length()) {
7281 if (expr_length <=
str.length()) {
7282 K* data =
str.data();
7283 expr.place((
typename E::symb_type*)data);
7284 str.resize(expr_length);
7286 auto fill = [&](K* data, size_t) ->
size_t {
7287 expr.place((
typename E::symb_type*)data);
7290 if constexpr (
requires{
str.resize_and_overwrite(expr_length, fill);}) {
7291 str.resize_and_overwrite(expr_length, fill);
7292 }
else if constexpr (
requires{
str._Resize_and_overwrite(expr_length, fill);}) {
7293 str._Resize_and_overwrite(expr_length, fill);
7295 str.resize(expr_length);
7296 expr.place((
typename E::symb_type*)
str.data());
7307template<
typename K,
typename A,
typename E>
7308struct replace_grow_helper {
7309 using my_type = std::basic_string<K, std::char_traits<K>, A>;
7311 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)
7312 :
str(src), source(src), pattern(p), repl(const_cast<K*>(r)), replLen(rl), maxCount(mc), delta(d), expr(e) {}
7315 const str_src<K> source;
7316 const str_src<K> pattern;
7318 const size_t replLen;
7325 K* reserve_for_copy{};
7326 size_t end_of_piece{};
7327 size_t total_length{};
7329 std::optional<my_type> dst;
7332 size_t found[16] = {offset};
7335 offset += pattern.len;
7338 for (; idx < std::size(found) && maxCount > 0; idx++, maxCount--) {
7339 found[idx] = source.find(pattern, offset);
7340 if (found[idx] == npos) {
7343 offset = found[idx] + pattern.len;
7346 if (idx == std::size(found) && maxCount > 0 && (offset = source.find(pattern, offset)) != str::npos) {
7351 if (!reserve_for_copy) {
7354 end_of_piece = source.length();
7355 total_length = end_of_piece + all_delta;
7357 if (total_length <= str.capacity()) {
7362 dst_str = &dst.emplace();
7364 auto fill = [
this](K* p, size_t) ->
size_t {
7365 reserve_for_copy = p;
7366 return total_length;
7368 if constexpr (
requires{dst_str->_Resize_and_overwrite(total_length, fill);}) {
7369 dst_str->_Resize_and_overwrite(total_length, fill);
7370 }
else if constexpr (
requires{dst_str->resize_and_overwrite(total_length, fill);}) {
7371 dst_str->resize_and_overwrite(total_length, fill);
7373 dst_str->resize(total_length);
7374 reserve_for_copy = dst_str->data();
7377 const K* src_start = str.c_str();
7379 size_t pos = found[idx] + pattern.len;
7380 size_t lenOfPiece = end_of_piece - pos;
7381 ch_traits<K>::move(reserve_for_copy + pos + all_delta, src_start + pos, lenOfPiece);
7382 if constexpr (std::is_same_v<E, int>) {
7383 ch_traits<K>::copy(reserve_for_copy + pos + all_delta - replLen, repl, replLen);
7386 repl = reserve_for_copy + pos + all_delta - replLen;
7389 ch_traits<K>::copy(reserve_for_copy + pos + all_delta - replLen, repl, replLen);
7393 end_of_piece = found[idx];
7395 if (!all_delta && reserve_for_copy != src_start) {
7396 ch_traits<K>::copy(reserve_for_copy, src_start, found[0]);
7397 str = std::move(*dst);
7438template<
typename K,
typename A, StrExprForType<K> E,
typename T>
7439requires (std::is_constructible_v<str_src<K>, T>)
7440std::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) {
7445 str_src<K> spattern{std::forward<T>(pattern)};
7446 offset = src.find(pattern, offset);
7447 if (offset == npos) {
7450 size_t replLen = repl.length();
7452 if (spattern.len == replLen) {
7455 K* ptr =
str.data();
7456 replStart = ptr + offset;
7457 repl.place(replStart);
7459 while (--max_count) {
7460 offset = src.find(spattern, offset + replLen);
7463 ch_traits<K>::copy(ptr + offset, replStart, replLen);
7465 }
else if (spattern.len > replLen) {
7468 K* ptr =
str.data();
7469 replStart = ptr + offset;
7470 repl.place(replStart);
7471 size_t posWrite = offset + replLen;
7472 offset += spattern.len;
7474 while (--max_count) {
7475 size_t idx = src.find(spattern, offset);
7478 size_t lenOfPiece = idx - offset;
7479 ch_traits<K>::move(ptr + posWrite, ptr + offset, lenOfPiece);
7480 posWrite += lenOfPiece;
7481 ch_traits<K>::copy(ptr + posWrite, replStart, replLen);
7482 posWrite += replLen;
7483 offset = idx + spattern.len;
7485 size_t tailLen = src.len - offset;
7486 ch_traits<K>::move(ptr + posWrite, ptr + offset, tailLen);
7487 str.resize(posWrite + tailLen);
7489 details::replace_grow_helper<K, A, E>(
str, spattern,
nullptr, replLen, max_count, replLen - spattern.len, repl).replace(offset);
7514template<
typename K,
typename A>
7515std::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) {
7520 offset = src.find(pattern, offset);
7521 if (offset == npos) {
7524 if (pattern.len == repl.len) {
7527 K* ptr =
str.data();
7528 while (max_count--) {
7529 ch_traits<K>::copy(ptr + offset, repl.str, repl.len);
7530 offset = src.find(pattern, offset + repl.len);
7534 }
else if (pattern.len > repl.len) {
7537 K* ptr =
str.data();
7538 ch_traits<K>::copy(ptr + offset, repl.str, repl.len);
7539 size_t posWrite = offset + repl.len;
7540 offset += pattern.len;
7542 while (--max_count) {
7543 size_t idx = src.find(pattern, offset);
7546 size_t lenOfPiece = idx - offset;
7547 ch_traits<K>::move(ptr + posWrite, ptr + offset, lenOfPiece);
7548 posWrite += lenOfPiece;
7549 ch_traits<K>::copy(ptr + posWrite, repl.str, repl.len);
7550 posWrite += repl.len;
7551 offset = idx + pattern.len;
7553 size_t tailLen = src.len - offset;
7554 ch_traits<K>::move(ptr + posWrite, ptr + offset, tailLen);
7555 str.resize(posWrite + tailLen);
7557 details::replace_grow_helper<K, A, int>(
str, pattern, repl.str, repl.len, max_count, repl.len - pattern.len, 0).replace(offset);
7562template<
typename K,
typename A,
typename T,
typename M>
7563requires (std::is_constructible_v<str_src<K>, T> && std::is_constructible_v<str_src<K>, M>)
7564std::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) {
7565 return replace(
str,
str_src<K>{std::forward<T>(pattern)}, str_src<K>{std::forward<M>(repl)}, offset, max_count);
7580template<
typename K,
typename A>
7581std::basic_string<K, std::char_traits<K>, A>&
make_ascii_upper(std::basic_string<K, std::char_traits<K>, A>&
str,
size_t from = 0,
size_t to = -1) {
7582 for (K *ptr =
str.data() + std::min(from,
str.length()), *end =
str.data() + std::min(to,
str.length()); ptr < end; ptr++) {
7584 if (isAsciiLower(s)) {
7603template<
typename K,
typename A>
7604std::basic_string<K, std::char_traits<K>, A>&
make_ascii_lower(std::basic_string<K, std::char_traits<K>, A>&
str,
size_t from = 0,
size_t to = -1) {
7605 for (K *ptr =
str.data() + std::min(from,
str.length()), *end =
str.data() + std::min(to,
str.length()); ptr < end; ptr++) {
7607 if (isAsciiUpper(s)) {
7642template<simstr::StdStrSource T>
7674template<
typename K,
typename A, simstr::StrExprForType<K> E>
7675std::basic_string<K, std::char_traits<K>, A>& operator |=(std::basic_string<K, std::char_traits<K>, A>& str,
const E& expr) {
7706template<
typename K,
typename A, simstr::StrExprForType<K> E>
7707std::basic_string<K, std::char_traits<K>, A>& operator ^=(std::basic_string<K, std::char_traits<K>, A>& str,
const E& expr) {
Класс для последовательного получения подстрок по заданному разделителю.
Определения strexpr.h:3230
constexpr bool is_done() const
Узнать, не закончились ли подстроки.
Определения strexpr.h:3241
constexpr str_t next()
Получить следующую подстроку.
Определения strexpr.h:3250
constexpr R trimmed_right_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения strexpr.h:5040
constexpr size_t find_last(K s, size_t offset=-1) const noexcept
Найти последнее вхождения символа в этой строке.
Определения strexpr.h:4062
constexpr int compare_ia(str_piece text) const noexcept
Сравнение строк посимвольно без учёта регистра ASCII символов.
Определения strexpr.h:3744
constexpr int compare(str_piece o) const
Сравнение строк посимвольно.
Определения strexpr.h:3629
constexpr size_t find(K s, size_t offset=0) const noexcept
Найти символ в этой строке.
Определения strexpr.h:3966
constexpr std::optional< R > strip_suffix(str_piece suffix) const
Получить строку без суффикса, если она заканчивается им.
Определения strexpr.h:4753
constexpr bool ends_with(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой.
Определения strexpr.h:4590
constexpr bool operator==(const base &other) const noexcept
Оператор сравнение строк на равенство.
Определения strexpr.h:3680
constexpr std::basic_string_view< D > to_sv() const noexcept
Конвертировать в std::basic_string_view.
Определения strexpr.h:3384
constexpr T slice_to(S start, E end) const noexcept
Получить результат slice и поместить его в объект заданного типа.
Определения strexpr.h:4176
constexpr bool starts_with_ia_and_ws(str_piece prefix) const noexcept
Проверить, начинается ли строка с указанной подстроки без учета регистра ASCII, за которой следует не...
Определения strexpr.h:4536
constexpr R trimmed_right() const
Получить строку с удалением пробельных символов справа.
Определения strexpr.h:4836
constexpr R trimmed_prefix_ia(str_piece prefix, size_t max_count=0) const
Возвращает строку, в которой удалено начало строки, если она начинается с указанного префикса без учё...
Определения strexpr.h:5079
constexpr size_t find_end_or_all(str_piece pattern, size_t offset=0) const noexcept
Найти конец первого вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:3862
constexpr bool starts_with(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки.
Определения strexpr.h:4472
constexpr bool equal(str_piece other) const noexcept
Сравнение строк на равенство.
Определения strexpr.h:3669
void copy_to(K *buffer, size_t bufSize)
Копировать строку в указанный буфер.
Определения strexpr.h:3362
constexpr str_piece until(str_piece pattern, size_t offset=0) const noexcept
Получить подстроку str_src от начала и до первого найденного вхождения указанной подстроки.
Определения strexpr.h:3591
constexpr R trimmed(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, слева и справа.
Определения strexpr.h:4958
constexpr T as_int() const noexcept
Преобразовать строку в число заданного типа.
Определения strexpr.h:4236
constexpr str_piece prefix(size_t count) const noexcept
Обертка вокруг slice(0, count).
Определения strexpr.h:3535
constexpr my_type substring(S start, E end) const noexcept
Обёртка вокруг slice_to<my_type>
Определения strexpr.h:4190
constexpr bool less_ia(str_piece text) const noexcept
Меньше ли строка другой строки посимвольно без учёта регистра ASCII символов.
Определения strexpr.h:3767
constexpr T split(str_piece delimiter, size_t offset=0) const
Разделить строку на подстроки по заданному разделителю.
Определения strexpr.h:4457
constexpr R trimmed_right_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения strexpr.h:4941
constexpr str_piece mid(size_t from, size_t len=-1) const noexcept
Получить часть строки как "кусок строки".
Определения strexpr.h:3556
constexpr my_type substr(ptrdiff_t from, ptrdiff_t len=0) const
Получить подстроку. Работает аналогично operator(), только результат выдает того же типа,...
Определения strexpr.h:4164
R upperred_only_ascii() const
Получить копию строки в верхнем регистре ASCII символов.
Определения strexpr.h:4667
constexpr str_piece to_str() const noexcept
Преобразовать себя в "кусок строки", включающий всю строку.
Определения strexpr.h:3432
constexpr bool starts_with_and_ws(str_piece prefix) const noexcept
Проверить, начинается ли строка с указанной подстроки, за которой следует ней пробельный ASCII символ...
Определения strexpr.h:4481
constexpr str_piece from_to(size_t from, size_t to) const noexcept
Получить подстроку str_src с позиции от from до позиции to (не включая её).
Определения strexpr.h:3578
constexpr R trimmed_left_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения strexpr.h:5022
R replaced(str_piece pattern, str_piece repl, size_t offset=0, size_t maxCount=0) const
Получить копию строки с заменёнными вхождениями подстрок.
Определения strexpr.h:4699
constexpr int strcmp(const K *text) const
Сравнение с C-строкой посимвольно.
Определения strexpr.h:3640
constexpr R trimmed_left() const
Получить строку с удалением пробельных символов слева.
Определения strexpr.h:4824
constexpr bool ends_with_ia(str_piece suffix) const noexcept
Заканчивается ли строка указанной подстрокой без учёта регистра ASCII символов.
Определения strexpr.h:4616
constexpr size_t find_first_not_of(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа не из заданного набора символов.
Определения strexpr.h:4109
constexpr size_t find_first_of(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа из заданного набора символов.
Определения strexpr.h:4081
constexpr R trimmed_right(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, справа.
Определения strexpr.h:4986
constexpr R trimmed_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения strexpr.h:4903
constexpr str_piece suffix(size_t count) const noexcept
Обертка вокруг slice(from_end(count), to_end).
Определения strexpr.h:3542
constexpr size_t find_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Найти начало последнего вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:3925
constexpr R trimmed_prefix(str_piece prefix, size_t max_count=0) const
Возвращает строку, в которой удалено начало строки, если она начинается с указанного префикса.
Определения strexpr.h:5056
constexpr bool starts_with_ia(str_piece prefix) const noexcept
Начинается ли строка с заданной подстроки без учёта регистра ASCII символов.
Определения strexpr.h:4527
constexpr str_piece slice(S start, E end) const noexcept
Получить часть строки как "str_src".
Определения strexpr.h:3501
constexpr R trimmed_left_with_spaces(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, а также пробельных символов,...
Определения strexpr.h:4922
constexpr size_t find_last(str_piece pattern, size_t offset=-1) const noexcept
Найти начало последнего вхождения подстроки в этой строке.
Определения strexpr.h:3898
constexpr size_t find_last_of(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа из заданного набора символов.
Определения strexpr.h:4122
constexpr size_t find_or_all(K s, size_t offset=0) const noexcept
Найти символ в этой строке или конец строки.
Определения strexpr.h:3985
constexpr size_t find_last_not_of(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа не из заданного набора символов.
Определения strexpr.h:4150
std::optional< double > to_double() const noexcept
Преобразовать строку в double.
Определения strexpr.h:4281
constexpr void for_all_finded(const Op &op, str_piece pattern, size_t offset=0, size_t maxCount=0) const
Вызвать функтор для всех найденных вхождений подстроки в этой строке.
Определения strexpr.h:4020
constexpr size_t find_end(str_piece pattern, size_t offset=0) const noexcept
Найти конец вхождения подстроки в этой строке.
Определения strexpr.h:3834
std::optional< double > to_double_hex() const noexcept
Преобразовать строку в 16ричной записи в double. Пока работает только для char.
Определения strexpr.h:4316
constexpr std::optional< R > strip_prefix(str_piece prefix) const
Получить строку без префикса, если она начинается с него.
Определения strexpr.h:4715
constexpr bool operator!() const noexcept
Проверка на пустоту.
Определения strexpr.h:3598
constexpr R trimmed() const
Получить строку с удалением пробельных символов слева и справа.
Определения strexpr.h:4812
constexpr size_t size() const
Размер строки в символах.
Определения strexpr.h:3373
constexpr To find_all(str_piece pattern, size_t offset=0, size_t maxCount=0) const
Найти все вхождения подстроки в этой строке.
Определения strexpr.h:4043
constexpr my_type str_mid(size_t from, size_t len=-1) const
Получить часть строки объектом того же типа, к которому применён метод, аналогично mid.
Определения strexpr.h:4204
constexpr size_t find_end_of_last(str_piece pattern, size_t offset=-1) const noexcept
Найти конец последнего вхождения подстроки в этой строке.
Определения strexpr.h:3911
constexpr std::pair< size_t, size_t > find_first_of_idx(str_piece pattern, size_t offset=0) const noexcept
Найти первое вхождение символа из заданного набора символов.
Определения strexpr.h:4094
constexpr bool is_ascii() const noexcept
Содержит ли строка только ASCII символы.
Определения strexpr.h:4623
constexpr size_t find(str_piece pattern, size_t offset=0) const noexcept
Найти начало первого вхождения подстроки в этой строке.
Определения strexpr.h:3798
constexpr SplitterBase< K, str_piece > splitter(str_piece delimiter) const
Получить объект Splitter по заданному разделителю, который позволяет последовательно получать подстро...
Определения strexpr.h:5139
constexpr std::pair< size_t, size_t > find_last_of_idx(str_piece pattern, size_t offset=str::npos) const noexcept
Найти последнее вхождение символа из заданного набора символов.
Определения strexpr.h:4135
constexpr R trimmed_left(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, слева.
Определения strexpr.h:4866
constexpr size_t find_or_all(str_piece pattern, size_t offset=0) const noexcept
Найти начало первого вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:3848
constexpr R trimmed_left(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, слева.
Определения strexpr.h:4972
constexpr bool operator==(T &&other) const noexcept
Оператор сравнения строки и строкового литерала на равенство.
Определения strexpr.h:3699
constexpr auto operator<=>(const base &other) const noexcept
Оператор сравнения строк.
Определения strexpr.h:3689
constexpr bool contains(str_piece pattern, size_t offset=0) const noexcept
Содержит ли строка указанную подстроку.
Определения strexpr.h:3953
constexpr R trimmed_suffix_ia(str_piece suffix) const
Возвращает строку, в которой удалён конец строки, если она заканчивается указанным суффиксом без учёт...
Определения strexpr.h:5122
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len=0) const noexcept
Получить часть строки как "str_src".
Определения strexpr.h:3459
constexpr K at(ptrdiff_t idx) const
Получить символ на заданной позиции .
Определения strexpr.h:3611
R lowered_only_ascii() const
Получить копию строки в нижнем регистре ASCII символов.
Определения strexpr.h:4679
constexpr R trimmed_with_spaces(str_piece pattern) const
Получить строку с удалением символов, заданных другой строкой, а также пробельных символов,...
Определения strexpr.h:5004
constexpr auto operator<=>(T &&other) const noexcept
Оператор сравнения строки и строкового литерала.
Определения strexpr.h:3709
constexpr std::basic_string< D, Traits, Allocator > to_string() const
Конвертировать в std::basic_string.
Определения strexpr.h:3404
constexpr R trimmed_right(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, справа.
Определения strexpr.h:4881
constexpr T splitf(str_piece delimiter, const Op &beforeFunc, size_t offset=0) const
Разделить строку на части по заданному разделителю, с возможным применением функтора к каждой подстро...
Определения strexpr.h:4441
constexpr R trimmed(T &&pattern) const
Получить строку с удалением символов, заданных строковым литералом, слева и справа.
Определения strexpr.h:4851
constexpr size_t find_end_of_last_or_all(str_piece pattern, size_t offset=-1) const noexcept
Найти конец последнего вхождения подстроки в этой строке или конец строки.
Определения strexpr.h:3939
constexpr bool prefix_in(str_piece text) const noexcept
Является ли эта строка началом другой строки.
Определения strexpr.h:4575
constexpr std::optional< R > strip_prefix_ia(str_piece prefix) const
Получить строку без префикса, если она начинается с него без учёта регистра ASCII символов.
Определения strexpr.h:4734
constexpr bool starts_with_ia_and_oneof(str_piece prefix, str_piece next_symbol) const noexcept
Проверить, начинается ли строка с указанной подстроки без учета регистра ASCII, за которой следует од...
Определения strexpr.h:4549
constexpr size_t find_or_throw(str_piece pattern, size_t offset=0, Args &&... args) const
Найти начало первого вхождения подстроки в этой строке или выкинуть исключение.
Определения strexpr.h:3818
constexpr std::optional< R > strip_suffix_ia(str_piece suffix) const
Получить строку без суффикса, если она заканчивается им без учёта регистра ASCII символов.
Определения strexpr.h:4772
constexpr R trimmed_suffix(str_piece suffix) const
Возвращает строку, в которой удалён конец строки, если она заканчивается указанным суффиксом.
Определения strexpr.h:5102
constexpr K * place(K *ptr) const noexcept
Копировать строку в указанный буфер.
Определения strexpr.h:3347
constexpr convert_result< T > to_int() const noexcept
Преобразовать строку в число заданного типа.
Определения strexpr.h:4269
constexpr bool equal_ia(str_piece text) const noexcept
Равна ли строка другой строке посимвольно без учёта регистра ASCII символов.
Определения strexpr.h:3756
constexpr void as_number(T &t) const
Преобразовать строку в целое число.
Определения strexpr.h:4344
constexpr bool starts_with_and_oneof(str_piece prefix, str_piece next_symbol) const noexcept
Проверить, начинается ли строка с указанной подстроки, за которой следует один из указанных символов.
Определения strexpr.h:4494
Концепт строкового выражения, совместимого с заданным типом символов.
Определения strexpr.h:525
Концепт "Строковых выражений".
Определения strexpr.h:507
Базовая концепция строкового объекта.
Определения strexpr.h:311
Проверка, являются ли два типа совместимыми строковыми типами.
Определения strexpr.h:172
constexpr expr_if< A > e_if(bool c, const A &a)
Создание условного строкового выражения expr_if.
Определения strexpr.h:1540
simstr::expr_stdstr< typename T::value_type, T > operator+(const T &str)
Унарный оператор+ для преобразования стандартных строк в строковые выражения.
Определения strexpr.h:7643
constexpr expr_spaces< uws, N > e_spcw()
Генерирует строку из N wchar_t пробелов.
Определения strexpr.h:1104
expr_fill< K, A, true > e_fill_left(const A &a, size_t width, K symbol=K(' '))
Создает выражение, которое дополняет указанное строковое выражение до заданной длины заданным символо...
Определения strexpr.h:2695
constexpr empty_expr< uws > eew
Пустое строковое выражение типа wchar_t.
Определения strexpr.h:862
constexpr expr_spaces< u8s, N > e_spca()
Генерирует строку из N char пробелов.
Определения strexpr.h:1086
constexpr empty_expr< u32s > eeuu
Пустое строковое выражение типа char32_t.
Определения strexpr.h:874
constexpr expr_num< K, T > e_num(T t)
Преобразование целого числа в строковое выражение.
Определения strexpr.h:1716
HexFlags
Флаги для функции e_hex.
Определения strexpr.h:2523
constexpr auto e_hex(T v)
Создает объект, который может преобразовываться в строковое выражение, генерирующее 16ричное представ...
Определения strexpr.h:2580
constexpr strexprjoin< A, B > operator+(const A &a, const B &b)
Оператор сложения двух произвольных строковых выражения для одинакового типа символов.
Определения strexpr.h:719
constexpr expr_repeat_lit< K, M - 1 > e_repeat(T &&s, size_t l)
Генерирует строку из l строковых констант s типа K.
Определения strexpr.h:1214
constexpr expr_literal< typename const_lit< T >::symb_type, static_cast< size_t >(N - 1)> e_t(T &&s)
Преобразует строковый литерал в строковое выражение.
Определения strexpr.h:991
expr_fill< K, A, false > e_fill_right(const A &a, size_t width, K symbol=K(' '))
Создает выражение, которое дополняет указанное строковое выражение до заданной длины заданным символо...
Определения strexpr.h:2721
constexpr expr_choice< A, B > e_choice(bool c, const A &a, const B &b)
Создание условного строкового выражения expr_choice.
Определения strexpr.h:1462
constexpr expr_char< K > e_char(K s)
Генерирует строку из 1 заданного символа.
Определения strexpr.h:918
constexpr empty_expr< u8s > eea
Пустое строковое выражение типа char.
Определения strexpr.h:850
constexpr expr_pad< K > e_c(size_t l, K s)
Генерирует строку из l символов s типа K.
Определения strexpr.h:1149
constexpr empty_expr< u16s > eeu
Пустое строковое выражение типа char16_t.
Определения strexpr.h:868
auto e_repl_const_symbols(A &&src, Repl &&... other)
Возвращает строковое выражение, генерирующее строку, в которой заданные символы заменены на заданные ...
Определения strexpr.h:6257
constexpr auto e_int(T v)
Создает объект, который преобразовывается в строковое выражение, генерирующее строковое представление...
Определения strexpr.h:2379
constexpr empty_expr< u8s > eeb
Пустое строковое выражение типа char8_t.
Определения strexpr.h:856
constexpr auto e_repl(A &&w, T &&p, X &&r)
Получить строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки.
Определения strexpr.h:5764
constexpr auto e_join(const T &s, L &&d)
Получить строковое выражение, конкатенирующее строки в контейнере в одну строку с заданным разделител...
Определения strexpr.h:2799
@ Short
without leading zeroes
Определения strexpr.h:2524
Небольшое пространство для методов работы со стандартными строками.
Определения strexpr.h:1596
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:7182
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:7215
std::basic_string< K, std::char_traits< K >, A > & make_ascii_upper(std::basic_string< K, std::char_traits< K >, A > &str, size_t from=0, size_t to=-1)
Изменить строчные ASCII символы строки (a-z) на прописные.
Определения strexpr.h:7581
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:7109
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:7440
std::basic_string< K, std::char_traits< K >, A > & make_ascii_lower(std::basic_string< K, std::char_traits< K >, A > &str, size_t from=0, size_t to=-1)
Изменить прописные ASCII символы строки (A-Z) на строчные.
Определения strexpr.h:7604
std::basic_string< K, std::char_traits< K >, A > & overwrite(std::basic_string< K, std::char_traits< K >, A > &str, const E &expr)
Переписать всю строку заданным строковым выражением, при необходимости изменив размер строки.
Определения strexpr.h:7279
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:7250
Пространство имён для объектов библиотеки
Определения sstring.cpp:12
IntConvertResult
Перечисление с возможными результатами преобразования строки в целое число
Определения strexpr.h:2866
@ Overflow
Переполнение, число не помещается в заданный тип
Определения strexpr.h:2869
@ Success
Успешно
Определения strexpr.h:2867
@ NotNumber
Вообще не число
Определения strexpr.h:2870
@ BadSymbolAtTail
Число закончилось не числовым символом
Определения strexpr.h:2868
Некоторые методы для работы с стандартными строками.
Определения strexpr.h:7622
Генерирует строку на основе исходной, заменяя все ASCII прописные буквы (A-Z) на строчные.
Определения strexpr.h:7062
Генерирует строку на основе исходной, заменяя все ASCII строчные буквы (a-z) на прописные.
Определения strexpr.h:7039
constexpr e_concat(G &&glue, Arg &&arg, Args &&...args)
Создание строкового выражения, объединяющего указанные строковые выражения, с использованием заданног...
Определения strexpr.h:6596
constexpr e_subst(const details::subst_params< K, PtLen, NParams > &subst, Args &&...args)
Создает строковое выражение, которое подставляет в заданные места в строковом литерале - образце знач...
Определения strexpr.h:6818
constexpr e_vsubst(str_src< K > pattern, Args &&...args)
Создает строковое выражение, которое подставляет в заданные места в строке-образце,...
Определения strexpr.h:6917
"Пустое" строковое выражение.
Определения strexpr.h:835
Строковое выражение условного выбора.
Определения strexpr.h:1341
Строковое выражение условного выбора.
Определения strexpr.h:1407
Строковое выражение условного выбора.
Определения strexpr.h:1250
Строковое выражение условного выбора.
Определения strexpr.h:1279
Тип строкового выражения, возвращающего N заданных символов.
Определения strexpr.h:1120
constexpr expr_replace_symbols(str_t source, const std::vector< std::pair< K, str_t > > &repl)
Конструктор выражения.
Определения strexpr.h:6341
Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки на строковое выр...
Определения strexpr.h:5882
constexpr expr_replaced_e(str_src< K > w, str_src< K > p, const E &e)
Конструктор.
Определения strexpr.h:5901
Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки на другую строку...
Определения strexpr.h:5776
constexpr expr_replaced(str_src< K > w, str_src< K > p, str_src< K > r)
Конструктор.
Определения strexpr.h:5794
Тип строкового выражения, возвращающего N заданных символов.
Определения strexpr.h:1060
Тип для использования std::basic_string и std::basic_string_view как источников в строковых выражения...
Определения strexpr.h:1565
Базовый класс для преобразования строковых выражений в стандартные строки
Определения strexpr.h:659
Класс, заявляющий, что ссылается на нуль-терминированную строку.
Определения strexpr.h:5310
constexpr my_type to_nts(size_t from)
Получить нуль-терминированную строку, сдвинув начало на заданное количество символов.
Определения strexpr.h:5373
constexpr str_src_nt(T &&v) noexcept
Конструктор из строкового литерала.
Определения strexpr.h:5344
constexpr str_src_nt(T &&p) noexcept
Явный конструктор из С-строки.
Определения strexpr.h:5335
constexpr str_src_nt(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения strexpr.h:5362
constexpr str_src_nt(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения strexpr.h:5350
Простейший класс иммутабельной не владеющей строки.
Определения strexpr.h:5174
constexpr str_src(const std::basic_string< K, std::char_traits< K >, A > &s) noexcept
Конструктор из std::basic_string.
Определения strexpr.h:5203
constexpr bool is_empty() const noexcept
Проверить, не пуста ли строка.
Определения strexpr.h:5228
constexpr size_t length() const noexcept
Получить длину строки.
Определения strexpr.h:5214
constexpr K operator[](size_t idx) const
Получить символ из указанной позиции. Проверка границ не выполняется.
Определения strexpr.h:5257
constexpr my_type & remove_prefix(size_t delta)
Сдвигает начало строки на заданное количество символов.
Определения strexpr.h:5268
constexpr str_src(const K *p, size_t l) noexcept
Конструктор из указателя и длины.
Определения strexpr.h:5193
constexpr bool is_same(str_src< K > other) const noexcept
Проверить, не указывают ли два объекта на одну строку.
Определения strexpr.h:5237
constexpr str_src(const std::basic_string_view< K, std::char_traits< K > > &s) noexcept
Конструктор из std::basic_string_view.
Определения strexpr.h:5208
constexpr const symb_type * symbols() const noexcept
Получить указатель на константный буфер с символами строки.
Определения strexpr.h:5221
constexpr my_type & remove_suffix(size_t delta)
Укорачивает строку на заданное количество символов.
Определения strexpr.h:5281
constexpr bool is_part_of(str_src< K > other) const noexcept
Проверить, не является ли строка частью другой строки.
Определения strexpr.h:5246
constexpr str_src(T &&v) noexcept
Конструктор из строкового литерала.
Определения strexpr.h:5187
Конкатенация ссылки на строковое выражение и значения строкового выражения.
Определения strexpr.h:744
Шаблонный класс для конкатенации двух строковых выражений в одно с помощью operator +
Определения strexpr.h:682