simstr 1.0
Yet another strings library
 
Загрузка...
Поиск...
Не найдено
strexpr.h
1/*
2 * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
3 * ver. 1.0
4 * База для строковых конкатенаций через выражения времени компиляции
5 */
6#pragma once
7#include <cstdlib>
8#include <string>
9#include <string_view>
10#include <type_traits>
11#include <concepts>
12#include <utility>
13
17namespace simstr {
18
19// Выводим типы для 16 и 32 битных символов в зависимости от размера wchar_t
20inline constexpr bool wchar_is_u16 = sizeof(wchar_t) == 2;
21
22using wchar_type = std::conditional<wchar_is_u16, char16_t, char32_t>::type;
23
24inline wchar_type* to_w(wchar_t* p) {
25 return (reinterpret_cast<wchar_type*>(p));
26}
27
28inline const wchar_type* to_w(const wchar_t* p) {
29 return (reinterpret_cast<const wchar_type*>(p));
30}
31
32inline wchar_t* from_w(wchar_type* p) {
33 return (reinterpret_cast<wchar_t*>(p));
34}
35
36inline const wchar_t* from_w(const wchar_type* p) {
37 return (reinterpret_cast<const wchar_t*>(p));
38}
39
40using u8s = char;
41using uws = wchar_t;
42using u16s = char16_t;
43using u32s = char32_t;
44
45using uu8s = std::make_unsigned<u8s>::type;
46
47template<typename K>
48inline 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>;
49
50template<typename K>
51inline 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>;
52
53template<typename From>
54requires (is_one_of_std_char_v<From>)
55auto to_one_of_std_char(From* from) {
56 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
57 return from;
58 } else {
59 return from_w(from);
60 }
61}
62template<typename From>
63requires (is_one_of_std_char_v<From>)
64auto to_one_of_std_char(const From* from) {
65 if constexpr (std::is_same_v<From, u8s> || std::is_same_v<From, wchar_t>) {
66 return from;
67 } else {
68 return from_w(from);
69 }
70}
71
72/*
73Вспомогательные шаблоны для определения строковых литералов.
74Используются для того, чтобы в параметрах функций ограничивать типы строго как `const K(&)[N]`
75Если пишем
76template<size_t N>
77void func(const char(&lit)[N]);
78то в такую функцию можно будет передать не константный буфер, что может вызывать ошибку:
79
80// Выделили место под символы
81char buf[100];
82// Как то наполнили буфер, допустим, до половины.
83
84stringa text = buf;
85Тут компилятор приведет buf из типа char[100] в тип const char[100] и вызовет конструктор
86для строкового литерала, в text запишется просто указатель на buf и длина 100.
87
88Поэтому такие параметры объявляем как
89template<typename T, typename K = typename const_lit<T>::symb_type, size_t N = const_lit<T>::Count>
90void func(T&& lit);
91
92Тогда компилятор будет подставлять для T точный тип параметра без попыток привести тип к другому типу,
93и выражение с параметром char[100] - не скомпилируется.
94*/
95
96template<typename T> struct const_lit; // sfinae отработает, так как не найдёт определения
97// Для правильных типов параметров есть определение, в виде специализации шаблона
98template<typename T, size_t N>
99 requires(is_one_of_char_v<T>)
100struct const_lit<const T(&)[N]> {
101 using symb_type = T;
102 constexpr static size_t Count = N;
103};
104
105// Тут ещё дополнительно ограничиваем тип литерала
106template<typename K, typename T> struct const_lit_for;
107
108template<typename K, size_t N>
109 requires(is_one_of_char_v<K>)
110struct const_lit_for<K, const K(&)[N]> {
111 constexpr static size_t Count = N;
112};
113
114template<typename K, size_t N>
115class const_lit_to_array {
116
117 template<size_t Idx>
118 size_t find(K s) const {
119 if constexpr (Idx < N) {
120 return s == symbols_[Idx] ? Idx : find<Idx + 1>(s);
121 }
122 return -1;
123 }
124
125 template<size_t Idx>
126 bool exist(K s) const {
127 if constexpr (Idx < N) {
128 return s == symbols_[Idx] || exist<Idx + 1>(s);
129 }
130 return false;
131 }
132public:
133 const K (&symbols_)[N + 1];
134
135 template<typename T, size_t M = const_lit_for<K, T>::Count> requires (M == N + 1)
136 constexpr const_lit_to_array(T&& s)
137 : symbols_(s) {}
138
139 constexpr bool contain(K s) const {
140 return exist<0>(s);
141 }
142 constexpr size_t index_of(K s) const {
143 return find<0>(s);
144 }
145};
146
158template<typename A, typename K>
159concept StrType = requires(const A& a) {
160 { a.is_empty() } -> std::same_as<bool>;
161 { a.length() } -> std::convertible_to<size_t>;
162 { a.symbols() } -> std::same_as<const K*>;
163} && std::is_same_v<typename std::remove_cvref_t<A>::symb_type, K>;
164
221
227template<typename A>
228concept StrExpr = requires(const A& a) {
229 typename A::symb_type;
230 { a.length() } -> std::convertible_to<size_t>;
231 { a.place(std::declval<typename A::symb_type*>()) } -> std::same_as<typename A::symb_type*>;
232};
233
241template<typename A, typename K>
242concept StrExprForType = StrExpr<A> && std::is_same_v<K, typename A::symb_type>;
243
244/*
245* Шаблонные классы для создания строковых выражений из нескольких источников
246* Благодаря компиляторно-шаблонной "магии" позволяют максимально эффективно
247* получать результирующую строку - сначала вычисляется длина результирующей строки,
248* потом один раз выделяется память для результата, после символы помещаются в
249* выделенную память.
250* Для конкатенация двух объектов строковых выражений в один
251*/
252
262template<StrExpr A, StrExprForType<typename A::symb_type> B>
263struct strexprjoin {
264 using symb_type = typename A::symb_type;
265 const A& a;
266 const B& b;
267 constexpr strexprjoin(const A& a_, const B& b_) : a(a_), b(b_){}
268 constexpr size_t length() const noexcept {
269 return a.length() + b.length();
270 }
271 constexpr symb_type* place(symb_type* p) const noexcept {
272 return b.place(a.place(p));
273 }
274 constexpr symb_type* len_and_place(symb_type* p) const noexcept {
275 a.length();
276 b.length();
277 return place(p);
278 }
279};
280
294template<StrExpr A, StrExprForType<typename A::symb_type> B>
295inline auto operator+(const A& a, const B& b) {
296 return strexprjoin<A, B>{a, b};
297}
298
310template<StrExpr A, StrExprForType<typename A::symb_type> B, bool last = true>
311struct strexprjoin_c {
312 using symb_type = typename A::symb_type;
313 const A& a;
314 B b;
315 template<typename... Args>
316 constexpr strexprjoin_c(const A& a_, Args&&... args_) : a(a_), b(std::forward<Args>(args_)...) {}
317 constexpr size_t length() const noexcept {
318 return a.length() + b.length();
319 }
320 constexpr symb_type* place(symb_type* p) const noexcept {
321 if constexpr (last) {
322 return b.place(a.place(p));
323 } else {
324 return a.place(b.place(p));
325 }
326 }
327 constexpr symb_type* len_and_place(symb_type* p) const noexcept {
328 a.length();
329 b.length();
330 return place(p);
331 }
332};
333
334template<typename T, typename K = void, typename... Types>
335struct is_one_of_type {
336 static constexpr bool value = std::is_same_v<T, K> || is_one_of_type<T, Types...>::value;
337};
338template<typename T>
339struct is_one_of_type<T, void> : std::false_type {};
340
364template<typename K>
366 using symb_type = K;
367 constexpr size_t length() const noexcept {
368 return 0;
369 }
370 constexpr symb_type* place(symb_type* p) const noexcept {
371 return p;
372 }
373};
374
379inline constexpr empty_expr<u8s> eea{};
384inline constexpr empty_expr<uws> eew{};
389inline constexpr empty_expr<u16s> eeu{};
394inline constexpr empty_expr<u32s> eeuu{};
395
396template<typename K>
397struct expr_char {
398 using symb_type = K;
399 K value;
400 expr_char(K v) : value(v){}
401 constexpr size_t length() const noexcept {
402 return 1;
403 }
404 constexpr symb_type* place(symb_type* p) const noexcept {
405 *p++ = value;
406 return p;
407 }
408};
409
419template<typename K, StrExprForType<K> A>
420constexpr inline auto operator+(const A& a, K s) {
421 return strexprjoin_c<A, expr_char<K>>{a, s};
422}
423
430template<typename K>
431constexpr inline auto e_char(K s) {
432 return expr_char<K>{s};
433}
434
435template<typename K, size_t N>
436struct expr_literal {
437 using symb_type = K;
438 const K (&str)[N + 1];
439 constexpr size_t length() const noexcept {
440 return N;
441 }
442 constexpr symb_type* place(symb_type* p) const noexcept {
443 if constexpr (N != 0)
444 std::char_traits<K>::copy(p, str, N);
445 return p + N;
446 }
447};
448
476template<typename T, size_t N = const_lit<T>::Count>
477constexpr inline auto e_t(T&& s) {
478 return expr_literal<typename const_lit<T>::symb_type, static_cast<size_t>(N - 1)>{s};
479}
480
481template<bool first, typename K, size_t N, typename A>
482struct expr_literal_join {
483 using symb_type = K;
484 const K (&str)[N + 1];
485 const A& a;
486 constexpr size_t length() const noexcept {
487 return N + a.length();
488 }
489 constexpr symb_type* place(symb_type* p) const noexcept {
490 if constexpr (N != 0) {
491 if constexpr (first) {
492 std::char_traits<K>::copy(p, str, N);
493 return a.place(p + N);
494 } else {
495 p = a.place(p);
496 std::char_traits<K>::copy(p, str, N);
497 return p + N;
498 }
499 } else {
500 return a.place(p);
501 }
502 }
503 constexpr symb_type* len_and_place(symb_type* p) const noexcept {
504 a.length();
505 return place(p);
506 }
507};
508
514template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count>
515constexpr inline auto operator+(const A& a, T&& s) {
516 return expr_literal_join<false, K, (N - 1), A>{s, a};
517}
518
524template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count>
525constexpr inline auto operator+(T&& s, const A& a) {
526 return expr_literal_join<true, K, (N - 1), A>{s, a};
527}
528
537template<typename K, size_t N, size_t S = ' '>
539 using symb_type = K;
540 constexpr size_t length() const noexcept {
541 return N;
542 }
543 constexpr symb_type* place(symb_type* p) const noexcept {
544 if constexpr (N != 0)
545 std::char_traits<K>::assign(p, N, static_cast<K>(S));
546 return p + N;
547 }
548};
549
560template<size_t N>
561constexpr inline auto e_spca() {
562 return expr_spaces<u8s, N>();
563}
564
575template<size_t N>
576constexpr inline auto e_spcw() {
577 return expr_spaces<uws, N>();
578}
579
587template<typename K>
588struct expr_pad {
589 using symb_type = K;
590 size_t len;
591 K s;
592 constexpr size_t length() const noexcept {
593 return len;
594 }
595 constexpr symb_type* place(symb_type* p) const noexcept {
596 if (len)
597 std::char_traits<K>::assign(p, len, s);
598 return p + len;
599 }
600};
601
610template<typename K>
611constexpr inline auto e_c(size_t l, K s) {
612 return expr_pad<K>{ l, s };
613}
614
623template<StrExpr A, StrExprForType<typename A::symb_type> B>
625 using symb_type = typename A::symb_type;
626 using my_type = expr_choice<A, B>;
627 const A& a;
628 const B& b;
629 bool choice;
630
631 constexpr size_t length() const noexcept {
632 return choice ? a.length() : b.length();
633 }
634 constexpr symb_type* place(symb_type* ptr) const noexcept {
635 return choice ? a.place(ptr) : b.place(ptr);
636 }
637};
638
646template<StrExpr A>
647struct expr_if {
648 using symb_type = typename A::symb_type;
649 using my_type = expr_if<A>;
650 const A& a;
651 bool choice;
652
653 constexpr size_t length() const noexcept {
654 return choice ? a.length() : 0;
655 }
656 constexpr symb_type* place(symb_type* ptr) const noexcept {
657 return choice ? a.place(ptr) : ptr;
658 }
659};
660
686template<StrExpr A, size_t N, bool Compare>
688 using symb_type = typename A::symb_type;
689 const symb_type (&str)[N + 1];
690 const A& a;
691 bool choice;
692
693 constexpr size_t length() const noexcept {
694 return choice == Compare ? a.length() : N;
695 }
696 constexpr symb_type* place(symb_type* ptr) const noexcept {
697 if (choice == Compare) {
698 return a.place(ptr);
699 }
700 if constexpr (N != 0) {
701 std::char_traits<symb_type>::copy(ptr, str, N);
702 }
703 return ptr + N;
704 }
705};
706
731template<typename K, size_t N, size_t M>
733 using symb_type = K;
734 const symb_type (&str_a)[N + 1];
735 const symb_type (&str_b)[M + 1];
736 bool choice;
737
738 constexpr size_t length() const noexcept {
739 return choice ? N : M;
740 }
741 constexpr symb_type* place(symb_type* ptr) const noexcept {
742 if (choice) {
743 if constexpr (N != 0) {
744 std::char_traits<symb_type>::copy(ptr, str_a, N);
745 }
746 return ptr + N;
747 }
748 if constexpr (M != 0) {
749 std::char_traits<symb_type>::copy(ptr, str_b, M);
750 }
751 return ptr + M;
752 }
753};
754
775template<StrExpr A, StrExprForType<typename A::symb_type> B>
776inline constexpr auto e_choice(bool c, const A& a, const B& b) {
777 return expr_choice<A, B>{a, b, c};
778}
779
784template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
785inline constexpr auto e_choice(bool c, const A& a, T&& str) {
786 return expr_choice_one_lit<A, N - 1, true>{str, a, c};
787}
788
793template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
794inline constexpr auto e_choice(bool c, T&& str, const A& a) {
795 return expr_choice_one_lit<A, N - 1, false>{str, a, c};
796}
797
801template<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>
802inline constexpr auto e_choice(bool c, T&& str_a, L&& str_b) {
803 return expr_choice_two_lit<typename const_lit<T>::symb_type, N -1, M - 1>{str_a, str_b, c};
804}
805
837template<StrExpr A>
838inline constexpr auto e_if(bool c, const A& a) {
839 return expr_if<A>{a, c};
840}
841
845template<typename T, size_t N = const_lit<T>::Count>
846inline constexpr auto e_if(bool c, T&& str) {
847 const typename const_lit<T>::symb_type empty[1] = {0};
848 return expr_choice_two_lit<typename const_lit<T>::symb_type, N - 1, 0>{str, empty, c};
849}
850
857template<typename K, typename T>
858struct expr_stdstr {
859 using symb_type = K;
860 const T& t_;
861
862 expr_stdstr(const T& t) : t_(t){}
863
864 constexpr size_t length() const noexcept {
865 return t_.size();
866 }
867 constexpr symb_type* place(symb_type* p) const noexcept {
868 size_t s = t_.size();
869 std::char_traits<K>::copy(p, (const K*)t_.data(), s);
870 return p + s;
871 }
872};
873
878template<StrExprForType<u8s> A>
879auto operator+(const A& a, const std::string& s) {
881}
882
887template<StrExprForType<u8s> A>
888auto operator+(const std::string& s, const A& a) {
890}
891
896template<StrExprForType<u8s> A>
897auto operator+(const A& a, const std::string_view& s) {
899}
900
905template<StrExprForType<u8s> A>
906auto operator+(const std::string_view& s, const A& a) {
908}
909
914template<StrExprForType<uws> A>
915auto operator+(const A& a, const std::wstring& s) {
917}
918
923template<StrExprForType<uws> A>
924auto operator+(const std::wstring& s, const A& a) {
926}
927
932template<StrExprForType<uws> A>
933auto operator+(const A& a, const std::wstring_view& s) {
935}
936
941template<StrExprForType<uws> A>
942auto operator+(const std::wstring_view& s, const A& a) {
944}
945
951template<StrExprForType<wchar_type> A>
952auto operator+(const A& a, const std::wstring& s) {
953 return strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring>, true>{a, s};
954}
955
961template<StrExprForType<wchar_type> A>
962auto operator+(const std::wstring& s, const A& a) {
964}
965
971template<StrExprForType<wchar_type> A>
972auto operator+(const A& a, const std::wstring_view& s) {
974}
975
981template<StrExprForType<wchar_type> A>
982auto operator+(const std::wstring_view& s, const A& a) {
984}
985
986}// namespace simstr
Концепт строкового выражения заданного типа символов
Определения strexpr.h:242
Концепт "Строковых выражений".
Определения strexpr.h:228
Базовая концепция строкового объекта.
Определения strexpr.h:159
constexpr auto e_spca()
Генерирует строку из N char пробелов
Определения strexpr.h:561
constexpr auto e_char(K s)
Генерирует строку из 1 заданного символа
Определения strexpr.h:431
constexpr empty_expr< uws > eew
Пустое строковое выражение типа wchar_t.
Определения strexpr.h:384
constexpr auto e_c(size_t l, K s)
Генерирует строку из l символов s типа K.
Определения strexpr.h:611
constexpr empty_expr< u32s > eeuu
Пустое строковое выражение типа char32_t.
Определения strexpr.h:394
constexpr auto e_t(T &&s)
Преобразует строковый литерал в строковое выражение.
Определения strexpr.h:477
constexpr auto e_choice(bool c, const A &a, const B &b)
Создание условного строкового выражения expr_choice.
Определения strexpr.h:776
constexpr auto e_if(bool c, const A &a)
Создание условного строкового выражения expr_if.
Определения strexpr.h:838
constexpr empty_expr< u8s > eea
Пустое строковое выражение типа char.
Определения strexpr.h:379
constexpr empty_expr< u16s > eeu
Пустое строковое выражение типа char16_t.
Определения strexpr.h:389
constexpr auto operator+(const A &a, T s)
Оператор конкатенации для строкового выражения и целого числа.
Определения sstring.h:4633
constexpr auto e_spcw()
Генерирует строку из N wchar_t пробелов
Определения strexpr.h:576
Пространство имён для объектов библиотеки
Определения sstring.cpp:10
"Пустое" строковое выражение
Определения strexpr.h:365
Строковое выражение условного выбора
Определения strexpr.h:687
Строковое выражение условного выбора
Определения strexpr.h:732
Строковое выражение условного выбора
Определения strexpr.h:624
Строковое выражение условного выбора
Определения strexpr.h:647
Тип строкового выражения, возвращающего N заданных символов.
Определения strexpr.h:588
Тип строкового выражения, возвращающего N заданных символов.
Определения strexpr.h:538
Конкатенация ссылки на строковое выражение и значения строкового выражения
Определения strexpr.h:311
Шаблонный класс для конкатенации двух строковых выражений в одно с помощью operator +
Определения strexpr.h:263