simstr 1.2.9
Yet another strings library
 
Loading...
Searching...
No Matches
strexpr.h
1/*
2 * ver. 1.2.4
3 * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
4 * База для строковых конкатенаций через выражения времени компиляции
5 * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
6 * Base for string concatenations via compile-time expressions
7 */
8#pragma once
9#include <cstdlib>
10#include <string>
11#include <string_view>
12#include <type_traits>
13#include <concepts>
14#include <utility>
15
20namespace simstr {
21
22// Выводим типы для 16 и 32 битных символов в зависимости от размера wchar_t
23// Infer types for 16 and 32 bit characters depending on the size of wchar_t
24inline constexpr bool wchar_is_u16 = sizeof(wchar_t) == 2;
25
26using wchar_type = std::conditional<wchar_is_u16, char16_t, char32_t>::type;
27
28inline wchar_type* to_w(wchar_t* p) {
29 return (reinterpret_cast<wchar_type*>(p));
30}
31
32inline const wchar_type* to_w(const wchar_t* p) {
33 return (reinterpret_cast<const wchar_type*>(p));
34}
35
36inline wchar_t* from_w(wchar_type* p) {
37 return (reinterpret_cast<wchar_t*>(p));
38}
39
40inline const wchar_t* from_w(const wchar_type* p) {
41 return (reinterpret_cast<const wchar_t*>(p));
42}
43
44using u8s = char;
45using uws = wchar_t;
46using u16s = char16_t;
47using u32s = char32_t;
48
49using uu8s = std::make_unsigned<u8s>::type;
50
51template<typename K>
52inline constexpr bool is_one_of_char_v = std::is_same_v<K, u8s> || std::is_same_v<K, wchar_t> || std::is_same_v<K, u16s> || std::is_same_v<K, u32s>;
53
54template<typename K>
55inline constexpr bool is_one_of_std_char_v = std::is_same_v<K, u8s> || std::is_same_v<K, wchar_t> || std::is_same_v<K, wchar_type>;
56
57template<typename From>
58requires (is_one_of_std_char_v<From>)
59auto to_one_of_std_char(From* from) {
60 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
61 return from;
62 } else {
63 return from_w(from);
64 }
65}
66template<typename From>
67requires (is_one_of_std_char_v<From>)
68auto to_one_of_std_char(const From* from) {
69 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
70 return from;
71 } else {
72 return from_w(from);
73 }
74}
75
76/*
77Вспомогательные шаблоны для определения строковых литералов.
78Используются для того, чтобы в параметрах функций ограничивать типы строго как `const K(&)[N]`
79Если пишем
80template<size_t N>
81void func(const char(&lit)[N]);
82то в такую функцию можно будет передать не константный буфер, что может вызывать ошибку:
83
84// Выделили место под символы
85char buf[100];
86// Как то наполнили буфер, допустим, до половины.
87
88stringa text = buf;
89Тут компилятор приведет buf из типа char[100] в тип const char[100] и вызовет конструктор
90для строкового литерала, в text запишется просто указатель на buf и длина 100.
91
92Поэтому такие параметры объявляем как
93template<typename T, typename K = typename const_lit<T>::symb_type, size_t N = const_lit<T>::Count>
94void func(T&& lit);
95
96Тогда компилятор будет подставлять для T точный тип параметра без попыток привести тип к другому типу,
97и выражение с параметром char[100] - не скомпилируется.
98
99Helper templates for defining string literals.
100They are used to limit types in function parameters strictly as `const K(&)[N]`
101If we write
102template<size_t N>
103void func(const char(&lit)[N]);
104then it will be possible to pass a non-constant buffer to such a function, which may cause an error:
105
106// Allocate space for symbols
107char buf[100];
108// Somehow the buffer was filled, say, to half.
109
110stringa text = buf;
111Here the compiler will convert buf from type char[100] to type const char[100] and call the constructor
112for a string literal, text will simply contain a pointer to buf and length 100.
113
114Therefore, we declare such parameters as
115template<typename T, typename K = typename const_lit<T>::symb_type, size_t N = const_lit<T>::Count>
116void func(T&& lit);
117
118Then the compiler will substitute for T the exact type of the parameter without attempting to cast the type to another type,
119and an expression with the char[100] parameter will not compile.
120*/
121
122template<typename T> struct const_lit; // sfinae отработает, так как не найдёт определения | sfinae will work because it won't find a definition
123// Для правильных типов параметров есть определение, в виде специализации шаблона
124// There is a definition for the correct parameter types, in the form of a template specialization
125template<typename T, size_t N>
126 requires(is_one_of_char_v<T>)
127struct const_lit<const T(&)[N]> {
128 using symb_type = T;
129 constexpr static size_t Count = N;
130};
131
132// Тут ещё дополнительно ограничиваем тип литерала
133// Here we further restrict the type of the literal
134template<typename K, typename T> struct const_lit_for;
135
136template<typename K, size_t N>
137 requires(is_one_of_char_v<K>)
138struct const_lit_for<K, const K(&)[N]> {
139 constexpr static size_t Count = N;
140};
141
142template<typename K, size_t N>
143class const_lit_to_array {
144
145 template<size_t Idx>
146 size_t find(K s) const {
147 if constexpr (Idx < N) {
148 return s == symbols_[Idx] ? Idx : find<Idx + 1>(s);
149 }
150 return -1;
151 }
152
153 template<size_t Idx>
154 bool exist(K s) const {
155 if constexpr (Idx < N) {
156 return s == symbols_[Idx] || exist<Idx + 1>(s);
157 }
158 return false;
159 }
160public:
161 const K (&symbols_)[N + 1];
162
163 template<typename T, size_t M = const_lit_for<K, T>::Count> requires (M == N + 1)
164 constexpr const_lit_to_array(T&& s)
165 : symbols_(s) {}
166
167 constexpr bool contain(K s) const {
168 return exist<0>(s);
169 }
170 constexpr size_t index_of(K s) const {
171 return find<0>(s);
172 }
173};
174
196template<typename A, typename K>
197concept StrType = requires(const A& a) {
198 { a.is_empty() } -> std::same_as<bool>;
199 { a.length() } -> std::convertible_to<size_t>;
200 { a.symbols() } -> std::same_as<const K*>;
201} && std::is_same_v<typename std::remove_cvref_t<A>::symb_type, K>;
202
312
320template<typename A>
321concept StrExpr = requires(const A& a) {
322 typename A::symb_type;
323 { a.length() } -> std::convertible_to<size_t>;
324 { a.place(std::declval<typename A::symb_type*>()) } -> std::same_as<typename A::symb_type*>;
325};
326
338template<typename A, typename K>
339concept StrExprForType = StrExpr<A> && std::is_same_v<K, typename A::symb_type>;
340
341/*
342* Шаблонные классы для создания строковых выражений из нескольких источников.
343* Благодаря компиляторно-шаблонной "магии" позволяют максимально эффективно
344* получать результирующую строку - сначала вычисляется длина результирующей строки,
345* потом один раз выделяется память для результата, после символы помещаются в
346* выделенную память.
347* Для конкатенация двух объектов строковых выражений в один
348
349* Template classes for creating string expressions from multiple sources.
350* Thanks to compiler-template "magic" they allow you to maximize efficiency
351* get the resulting string - first the length of the resulting string is calculated,
352* then memory is allocated once for the result, after which the characters are placed in
353* allocated memory.
354* For concatenating two string expression objects into one.
355*/
356
372template<StrExpr A, StrExprForType<typename A::symb_type> B>
373struct strexprjoin {
374 using symb_type = typename A::symb_type;
375 const A& a;
376 const B& b;
377 constexpr strexprjoin(const A& a_, const B& b_) : a(a_), b(b_){}
378 constexpr size_t length() const noexcept {
379 return a.length() + b.length();
380 }
381 constexpr symb_type* place(symb_type* p) const noexcept {
382 return b.place(a.place(p));
383 }
384 constexpr symb_type* len_and_place(symb_type* p) const noexcept {
385 a.length();
386 b.length();
387 return place(p);
388 }
389};
390
414template<StrExpr A, StrExprForType<typename A::symb_type> B>
415inline auto operator+(const A& a, const B& b) {
416 return strexprjoin<A, B>{a, b};
417}
418
439template<StrExpr A, StrExprForType<typename A::symb_type> B, bool last = true>
440struct strexprjoin_c {
441 using symb_type = typename A::symb_type;
442 const A& a;
443 B b;
444 template<typename... Args>
445 constexpr strexprjoin_c(const A& a_, Args&&... args_) : a(a_), b(std::forward<Args>(args_)...) {}
446 constexpr size_t length() const noexcept {
447 return a.length() + b.length();
448 }
449 constexpr symb_type* place(symb_type* p) const noexcept {
450 if constexpr (last) {
451 return b.place(a.place(p));
452 } else {
453 return a.place(b.place(p));
454 }
455 }
456 constexpr symb_type* len_and_place(symb_type* p) const noexcept {
457 a.length();
458 b.length();
459 return place(p);
460 }
461};
462
463template<typename T, typename K = void, typename... Types>
464struct is_one_of_type {
465 static constexpr bool value = std::is_same_v<T, K> || is_one_of_type<T, Types...>::value;
466};
467template<typename T>
468struct is_one_of_type<T, void> : std::false_type {};
469
506template<typename K>
508 using symb_type = K;
509 constexpr size_t length() const noexcept {
510 return 0;
511 }
512 constexpr symb_type* place(symb_type* p) const noexcept {
513 return p;
514 }
515};
516
522inline constexpr empty_expr<u8s> eea{};
528inline constexpr empty_expr<uws> eew{};
534inline constexpr empty_expr<u16s> eeu{};
540inline constexpr empty_expr<u32s> eeuu{};
541
542template<typename K>
543struct expr_char {
544 using symb_type = K;
545 K value;
546 expr_char(K v) : value(v){}
547 constexpr size_t length() const noexcept {
548 return 1;
549 }
550 constexpr symb_type* place(symb_type* p) const noexcept {
551 *p++ = value;
552 return p;
553 }
554};
555
568template<typename K, StrExprForType<K> A>
569constexpr inline auto operator+(const A& a, K s) {
570 return strexprjoin_c<A, expr_char<K>>{a, s};
571}
572
583template<typename K>
584constexpr inline auto e_char(K s) {
585 return expr_char<K>{s};
586}
587
588template<typename K, size_t N>
589struct expr_literal {
590 using symb_type = K;
591 const K (&str)[N + 1];
592 constexpr size_t length() const noexcept {
593 return N;
594 }
595 constexpr symb_type* place(symb_type* p) const noexcept {
596 if constexpr (N != 0)
597 std::char_traits<K>::copy(p, str, N);
598 return p + N;
599 }
600};
601
654template<typename T, size_t N = const_lit<T>::Count>
655constexpr inline auto e_t(T&& s) {
656 return expr_literal<typename const_lit<T>::symb_type, static_cast<size_t>(N - 1)>{s};
657}
658
659template<bool first, typename K, size_t N, typename A>
660struct expr_literal_join {
661 using symb_type = K;
662 const K (&str)[N + 1];
663 const A& a;
664 constexpr size_t length() const noexcept {
665 return N + a.length();
666 }
667 constexpr symb_type* place(symb_type* p) const noexcept {
668 if constexpr (N != 0) {
669 if constexpr (first) {
670 std::char_traits<K>::copy(p, str, N);
671 return a.place(p + N);
672 } else {
673 p = a.place(p);
674 std::char_traits<K>::copy(p, str, N);
675 return p + N;
676 }
677 } else {
678 return a.place(p);
679 }
680 }
681 constexpr symb_type* len_and_place(symb_type* p) const noexcept {
682 a.length();
683 return place(p);
684 }
685};
686
694template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count>
695constexpr inline auto operator+(const A& a, T&& s) {
696 return expr_literal_join<false, K, (N - 1), A>{s, a};
697}
698
706template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count>
707constexpr inline auto operator+(T&& s, const A& a) {
708 return expr_literal_join<true, K, (N - 1), A>{s, a};
709}
710
724template<typename K, size_t N, size_t S = ' '>
726 using symb_type = K;
727 constexpr size_t length() const noexcept {
728 return N;
729 }
730 constexpr symb_type* place(symb_type* p) const noexcept {
731 if constexpr (N != 0)
732 std::char_traits<K>::assign(p, N, static_cast<K>(S));
733 return p + N;
734 }
735};
736
750template<size_t N>
751constexpr inline auto e_spca() {
752 return expr_spaces<u8s, N>();
753}
754
768template<size_t N>
769constexpr inline auto e_spcw() {
770 return expr_spaces<uws, N>();
771}
772
784template<typename K>
785struct expr_pad {
786 using symb_type = K;
787 size_t len;
788 K s;
789 constexpr size_t length() const noexcept {
790 return len;
791 }
792 constexpr symb_type* place(symb_type* p) const noexcept {
793 if (len)
794 std::char_traits<K>::assign(p, len, s);
795 return p + len;
796 }
797};
798
812template<typename K>
813constexpr inline auto e_c(size_t l, K s) {
814 return expr_pad<K>{ l, s };
815}
816
817template<typename K, size_t N>
818struct expr_repeat_lit {
819 using symb_type = K;
820 size_t repeat_;
821 const K (&s)[N + 1];
822 constexpr size_t length() const noexcept {
823 return N * repeat_;
824 }
825 constexpr symb_type* place(symb_type* p) const noexcept {
826 for (size_t i = 0; i < repeat_; i++) {
827 std::char_traits<K>::copy(p, s, N);
828 p += N;
829 }
830 return p;
831 }
832};
833
834template<StrExpr A>
835struct expr_repeat_expr {
836 using symb_type = typename A::symb_type;
837 size_t repeat_;
838 const A& expr_;
839 constexpr size_t length() const noexcept {
840 return repeat_ * expr_.length();
841 }
842 constexpr symb_type* place(symb_type* p) const noexcept {
843 for (size_t i = 0; i < repeat_; i++) {
844 p = expr_.place(p);
845 }
846 return p;
847 }
848};
849
863template<typename T, typename K = const_lit<T>::symb_type, size_t M = const_lit<T>::Count> requires (M > 0)
864constexpr inline auto e_repeat(T&& s, size_t l) {
865 return expr_repeat_lit<K, M - 1>{ l, s };
866}
867
881template<StrExpr A>
882constexpr inline auto e_repeat(const A& s, size_t l) {
883 return expr_repeat_expr<A>{ l, s };
884}
885
899template<StrExpr A, StrExprForType<typename A::symb_type> B>
901 using symb_type = typename A::symb_type;
902 using my_type = expr_choice<A, B>;
903 const A& a;
904 const B& b;
905 bool choice;
906
907 constexpr size_t length() const noexcept {
908 return choice ? a.length() : b.length();
909 }
910 constexpr symb_type* place(symb_type* ptr) const noexcept {
911 return choice ? a.place(ptr) : b.place(ptr);
912 }
913};
914
926template<StrExpr A>
927struct expr_if {
928 using symb_type = typename A::symb_type;
929 using my_type = expr_if<A>;
930 const A& a;
931 bool choice;
932
933 constexpr size_t length() const noexcept {
934 return choice ? a.length() : 0;
935 }
936 constexpr symb_type* place(symb_type* ptr) const noexcept {
937 return choice ? a.place(ptr) : ptr;
938 }
939};
940
987template<StrExpr A, size_t N, bool Compare>
989 using symb_type = typename A::symb_type;
990 const symb_type (&str)[N + 1];
991 const A& a;
992 bool choice;
993
994 constexpr size_t length() const noexcept {
995 return choice == Compare ? a.length() : N;
996 }
997 constexpr symb_type* place(symb_type* ptr) const noexcept {
998 if (choice == Compare) {
999 return a.place(ptr);
1000 }
1001 if constexpr (N != 0) {
1002 std::char_traits<symb_type>::copy(ptr, str, N);
1003 }
1004 return ptr + N;
1005 }
1006};
1007
1052template<typename K, size_t N, size_t M>
1054 using symb_type = K;
1055 const symb_type (&str_a)[N + 1];
1056 const symb_type (&str_b)[M + 1];
1057 bool choice;
1058
1059 constexpr size_t length() const noexcept {
1060 return choice ? N : M;
1061 }
1062 constexpr symb_type* place(symb_type* ptr) const noexcept {
1063 if (choice) {
1064 if constexpr (N != 0) {
1065 std::char_traits<symb_type>::copy(ptr, str_a, N);
1066 }
1067 return ptr + N;
1068 }
1069 if constexpr (M != 0) {
1070 std::char_traits<symb_type>::copy(ptr, str_b, M);
1071 }
1072 return ptr + M;
1073 }
1074};
1075
1105template<StrExpr A, StrExprForType<typename A::symb_type> B>
1106inline constexpr auto e_choice(bool c, const A& a, const B& b) {
1107 return expr_choice<A, B>{a, b, c};
1108}
1109
1115template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1116inline constexpr auto e_choice(bool c, const A& a, T&& str) {
1117 return expr_choice_one_lit<A, N - 1, true>{str, a, c};
1118}
1119
1125template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1126inline constexpr auto e_choice(bool c, T&& str, const A& a) {
1127 return expr_choice_one_lit<A, N - 1, false>{str, a, c};
1128}
1129
1134template<typename T, typename L, size_t N = const_lit<T>::Count, size_t M = const_lit_for<typename const_lit<T>::symb_type, L>::Count>
1135inline constexpr auto e_choice(bool c, T&& str_a, L&& str_b) {
1136 return expr_choice_two_lit<typename const_lit<T>::symb_type, N -1, M - 1>{str_a, str_b, c};
1137}
1138
1181template<StrExpr A>
1182inline constexpr auto e_if(bool c, const A& a) {
1183 return expr_if<A>{a, c};
1184}
1185
1190template<typename T, size_t N = const_lit<T>::Count>
1191inline constexpr auto e_if(bool c, T&& str) {
1192 const typename const_lit<T>::symb_type empty[1] = {0};
1193 return expr_choice_two_lit<typename const_lit<T>::symb_type, N - 1, 0>{str, empty, c};
1194}
1195
1205template<typename K, typename T>
1206struct expr_stdstr {
1207 using symb_type = K;
1208 const T& t_;
1209
1210 expr_stdstr(const T& t) : t_(t){}
1211
1212 constexpr size_t length() const noexcept {
1213 return t_.size();
1214 }
1215 constexpr symb_type* place(symb_type* p) const noexcept {
1216 size_t s = t_.size();
1217 std::char_traits<K>::copy(p, (const K*)t_.data(), s);
1218 return p + s;
1219 }
1220};
1221
1227template<StrExprForType<u8s> A>
1228auto operator+(const A& a, const std::string& s) {
1230}
1231
1237template<StrExprForType<u8s> A>
1238auto operator+(const std::string& s, const A& a) {
1240}
1241
1247template<StrExprForType<u8s> A>
1248auto operator+(const A& a, const std::string_view& s) {
1250}
1251
1257template<StrExprForType<u8s> A>
1258auto operator+(const std::string_view& s, const A& a) {
1260}
1261
1267template<StrExprForType<uws> A>
1268auto operator+(const A& a, const std::wstring& s) {
1270}
1271
1277template<StrExprForType<uws> A>
1278auto operator+(const std::wstring& s, const A& a) {
1280}
1281
1287template<StrExprForType<uws> A>
1288auto operator+(const A& a, const std::wstring_view& s) {
1290}
1291
1297template<StrExprForType<uws> A>
1298auto operator+(const std::wstring_view& s, const A& a) {
1300}
1301
1309template<StrExprForType<wchar_type> A>
1310auto operator+(const A& a, const std::wstring& s) {
1311 return strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring>, true>{a, s};
1312}
1313
1321template<StrExprForType<wchar_type> A>
1322auto operator+(const std::wstring& s, const A& a) {
1324}
1325
1333template<StrExprForType<wchar_type> A>
1334auto operator+(const A& a, const std::wstring_view& s) {
1336}
1337
1345template<StrExprForType<wchar_type> A>
1346auto operator+(const std::wstring_view& s, const A& a) {
1348}
1349
1350}// namespace simstr
The concept of a string expression of a given character type.
Definition strexpr.h:339
Concept of "String Expressions".
Definition strexpr.h:321
Base concept of string object.
Definition strexpr.h:197
constexpr auto e_spca()
Generates a string of N char spaces.
Definition strexpr.h:751
constexpr auto e_char(K s)
Generates a string of 1 given character.
Definition strexpr.h:584
constexpr empty_expr< uws > eew
Empty string expression of type wchar_t.
Definition strexpr.h:528
constexpr auto e_c(size_t l, K s)
Generates a string of l characters s of type K.
Definition strexpr.h:813
constexpr empty_expr< u32s > eeuu
Empty string expression of type char32_t.
Definition strexpr.h:540
constexpr auto e_t(T &&s)
Converts a string literal to a string expression.
Definition strexpr.h:655
constexpr auto e_choice(bool c, const A &a, const B &b)
Create a conditional string expression expr_choice.
Definition strexpr.h:1106
constexpr auto e_if(bool c, const A &a)
Creating a conditional string expression expr_if.
Definition strexpr.h:1182
constexpr auto e_repeat(T &&s, size_t l)
Generate a string from l string constants s of type K.
Definition strexpr.h:864
constexpr empty_expr< u8s > eea
Empty string expression of type char.
Definition strexpr.h:522
constexpr empty_expr< u16s > eeu
Empty string expression of type char16_t.
Definition strexpr.h:534
constexpr auto operator+(const A &a, T s)
Concatenation operator for string expression and integer.
Definition sstring.h:5660
constexpr auto e_spcw()
Generates a string of N wchar_t spaces.
Definition strexpr.h:769
Library namespace.
Definition sstring.cpp:10
An "empty" string expression.
Definition strexpr.h:507
Conditional selection string expression.
Definition strexpr.h:988
Conditional selection string expression.
Definition strexpr.h:1053
Conditional selection string expression.
Definition strexpr.h:900
Conditional selection string expression.
Definition strexpr.h:927
A type of string expression that returns N specified characters.
Definition strexpr.h:785
A type of string expression that returns N specified characters.
Definition strexpr.h:725
Concatenation of a reference to a string expression and the value of the string expression.
Definition strexpr.h:440
Template class for concatenating two string expressions into one using operator +
Definition strexpr.h:373