simstr 1.2.4
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
830template<StrExpr A, StrExprForType<typename A::symb_type> B>
832 using symb_type = typename A::symb_type;
833 using my_type = expr_choice<A, B>;
834 const A& a;
835 const B& b;
836 bool choice;
837
838 constexpr size_t length() const noexcept {
839 return choice ? a.length() : b.length();
840 }
841 constexpr symb_type* place(symb_type* ptr) const noexcept {
842 return choice ? a.place(ptr) : b.place(ptr);
843 }
844};
845
857template<StrExpr A>
858struct expr_if {
859 using symb_type = typename A::symb_type;
860 using my_type = expr_if<A>;
861 const A& a;
862 bool choice;
863
864 constexpr size_t length() const noexcept {
865 return choice ? a.length() : 0;
866 }
867 constexpr symb_type* place(symb_type* ptr) const noexcept {
868 return choice ? a.place(ptr) : ptr;
869 }
870};
871
918template<StrExpr A, size_t N, bool Compare>
920 using symb_type = typename A::symb_type;
921 const symb_type (&str)[N + 1];
922 const A& a;
923 bool choice;
924
925 constexpr size_t length() const noexcept {
926 return choice == Compare ? a.length() : N;
927 }
928 constexpr symb_type* place(symb_type* ptr) const noexcept {
929 if (choice == Compare) {
930 return a.place(ptr);
931 }
932 if constexpr (N != 0) {
933 std::char_traits<symb_type>::copy(ptr, str, N);
934 }
935 return ptr + N;
936 }
937};
938
983template<typename K, size_t N, size_t M>
985 using symb_type = K;
986 const symb_type (&str_a)[N + 1];
987 const symb_type (&str_b)[M + 1];
988 bool choice;
989
990 constexpr size_t length() const noexcept {
991 return choice ? N : M;
992 }
993 constexpr symb_type* place(symb_type* ptr) const noexcept {
994 if (choice) {
995 if constexpr (N != 0) {
996 std::char_traits<symb_type>::copy(ptr, str_a, N);
997 }
998 return ptr + N;
999 }
1000 if constexpr (M != 0) {
1001 std::char_traits<symb_type>::copy(ptr, str_b, M);
1002 }
1003 return ptr + M;
1004 }
1005};
1006
1036template<StrExpr A, StrExprForType<typename A::symb_type> B>
1037inline constexpr auto e_choice(bool c, const A& a, const B& b) {
1038 return expr_choice<A, B>{a, b, c};
1039}
1040
1046template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1047inline constexpr auto e_choice(bool c, const A& a, T&& str) {
1048 return expr_choice_one_lit<A, N - 1, true>{str, a, c};
1049}
1050
1056template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
1057inline constexpr auto e_choice(bool c, T&& str, const A& a) {
1058 return expr_choice_one_lit<A, N - 1, false>{str, a, c};
1059}
1060
1065template<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>
1066inline constexpr auto e_choice(bool c, T&& str_a, L&& str_b) {
1067 return expr_choice_two_lit<typename const_lit<T>::symb_type, N -1, M - 1>{str_a, str_b, c};
1068}
1069
1112template<StrExpr A>
1113inline constexpr auto e_if(bool c, const A& a) {
1114 return expr_if<A>{a, c};
1115}
1116
1121template<typename T, size_t N = const_lit<T>::Count>
1122inline constexpr auto e_if(bool c, T&& str) {
1123 const typename const_lit<T>::symb_type empty[1] = {0};
1124 return expr_choice_two_lit<typename const_lit<T>::symb_type, N - 1, 0>{str, empty, c};
1125}
1126
1136template<typename K, typename T>
1137struct expr_stdstr {
1138 using symb_type = K;
1139 const T& t_;
1140
1141 expr_stdstr(const T& t) : t_(t){}
1142
1143 constexpr size_t length() const noexcept {
1144 return t_.size();
1145 }
1146 constexpr symb_type* place(symb_type* p) const noexcept {
1147 size_t s = t_.size();
1148 std::char_traits<K>::copy(p, (const K*)t_.data(), s);
1149 return p + s;
1150 }
1151};
1152
1158template<StrExprForType<u8s> A>
1159auto operator+(const A& a, const std::string& s) {
1161}
1162
1168template<StrExprForType<u8s> A>
1169auto operator+(const std::string& s, const A& a) {
1171}
1172
1178template<StrExprForType<u8s> A>
1179auto operator+(const A& a, const std::string_view& s) {
1181}
1182
1188template<StrExprForType<u8s> A>
1189auto operator+(const std::string_view& s, const A& a) {
1191}
1192
1198template<StrExprForType<uws> A>
1199auto operator+(const A& a, const std::wstring& s) {
1201}
1202
1208template<StrExprForType<uws> A>
1209auto operator+(const std::wstring& s, const A& a) {
1211}
1212
1218template<StrExprForType<uws> A>
1219auto operator+(const A& a, const std::wstring_view& s) {
1221}
1222
1228template<StrExprForType<uws> A>
1229auto operator+(const std::wstring_view& s, const A& a) {
1231}
1232
1240template<StrExprForType<wchar_type> A>
1241auto operator+(const A& a, const std::wstring& s) {
1242 return strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring>, true>{a, s};
1243}
1244
1252template<StrExprForType<wchar_type> A>
1253auto operator+(const std::wstring& s, const A& a) {
1255}
1256
1264template<StrExprForType<wchar_type> A>
1265auto operator+(const A& a, const std::wstring_view& s) {
1267}
1268
1276template<StrExprForType<wchar_type> A>
1277auto operator+(const std::wstring_view& s, const A& a) {
1279}
1280
1281}// 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:1037
constexpr auto e_if(bool c, const A &a)
Creating a conditional string expression expr_if.
Definition strexpr.h:1113
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:919
Conditional selection string expression.
Definition strexpr.h:984
Conditional selection string expression.
Definition strexpr.h:831
Conditional selection string expression.
Definition strexpr.h:858
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