From 4e1d1b5ffa3aa182fc129304b7d1a3018848d761 Mon Sep 17 00:00:00 2001 From: Aleksandr Orefkov Date: Thu, 5 Feb 2026 12:05:49 +0300 Subject: [PATCH] Some small fixes. --- include/simstr/strexpr.h | 65 ++++++++++++++++++++++++---------------- readme.md | 1 + readme_ru.md | 1 + tests/test_expr_only.cpp | 2 ++ tests/test_str.cpp | 10 +++++-- 5 files changed, 51 insertions(+), 28 deletions(-) diff --git a/include/simstr/strexpr.h b/include/simstr/strexpr.h index 3b78302..1664406 100644 --- a/include/simstr/strexpr.h +++ b/include/simstr/strexpr.h @@ -53,7 +53,7 @@ namespace simstr { // Выводим типы для 16 и 32 битных символов в зависимости от размера wchar_t // Infer types for 16 and 32 bit characters depending on the size of wchar_t -inline constexpr bool wchar_is_u16 = sizeof(wchar_t) == 2; +inline constexpr bool wchar_is_u16 = sizeof(wchar_t) == sizeof(char16_t); using wchar_type = std::conditional::type; @@ -94,8 +94,7 @@ concept is_one_of_char_v = is_one_of_type::val template concept is_one_of_std_char_v = is_one_of_type::value; -template -requires (is_one_of_std_char_v) +template auto to_one_of_std_char(From* from) { if constexpr (std::is_same_v || std::is_same_v) { return from; @@ -105,8 +104,8 @@ auto to_one_of_std_char(From* from) { return from_w(from); } } -template -requires (is_one_of_std_char_v) + +template auto to_one_of_std_char(const From* from) { if constexpr (std::is_same_v || std::is_same_v) { return from; @@ -184,8 +183,7 @@ and an expression with the char[100] parameter will not compile. template struct const_lit; // sfinae отработает, так как не найдёт определения | sfinae will work because it won't find a definition // Для правильных типов параметров есть определение, в виде специализации шаблона // There is a definition for the correct parameter types, in the form of a template specialization -template - requires(is_one_of_char_v) +template struct const_lit { using symb_type = T; constexpr static size_t Count = N; @@ -200,8 +198,7 @@ concept is_const_lit_v = requires { // Here we further restrict the type of the literal template struct const_lit_for; -template - requires(is_equal_str_type_v) +template P, size_t N> struct const_lit_for { constexpr static size_t Count = N; }; @@ -623,8 +620,7 @@ constexpr std::basic_string, Allocator> to_std_string(con */ template struct expr_to_std_string { - template - requires is_equal_str_type_v + template P, typename Allocator> constexpr operator std::basic_string, Allocator>() const { return to_std_string(*static_cast(this)); } @@ -793,11 +789,9 @@ inline constexpr strexprjoin_c * * @ru Пример: @en Example: @~ * ```cpp - * result = shost + e_choice(sserv.is_empty(), eea, ":" + sserv); - * ``` - * - * ```cpp - * result += "E" + e_choice(adjusted_exponent > 0, "+"_ss, eea) + adjusted_exponent; + * // строковые литералы и числа не являются строковыми выражениями, нам надо с чего то начать операцию сложения со строковым выражением + * // string literals and numbers are not string expressions, we need to start the addition operation with a string expression somewhere + * result = eea + "Count is " + count; * ``` */ template @@ -1534,7 +1528,7 @@ constexpr auto e_if(bool c, T&& str) { * @tparam K is a symbol. * @tparam T - source type. */ -template requires is_equal_str_type_v +template T> struct expr_stdstr { using symb_type = K; const T& t_; @@ -1552,11 +1546,11 @@ struct expr_stdstr { }; /*! - * @ru @brief Специализация шаблона для преобразования целых чисел в строковое выражение, позволяет использовать их в + * @ru @brief Специализация шаблона для преобразования стандартный строк в строковое выражение, позволяет использовать их в * операциях конкатенации со строковыми выражениями. * @tparam K - тип символов строкового выражения. * @tparam T - тип числа. - * @en @brief A template specialization for converting integers to string expressions, allowing their use in + * @en @brief A template specialization for converting standard strings to string expressions, allowing their use in * concatenation operations with string expressions. * @tparam K - the character type of the string expression. * @tparam T - the number type. @@ -2003,7 +1997,7 @@ constexpr auto skip_0x() { } // namespace f template -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'), +inline 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'), K(Ucase ? 'A' : 'a'), K(Ucase ? 'B' : 'b'), K(Ucase ? 'C' : 'c'), K(Ucase ? 'D' : 'd'), K(Ucase ? 'E' : 'e'), K(Ucase ? 'F' : 'f'), K(Ucase ? 'G' : 'g'), K(Ucase ? 'H' : 'h'), K(Ucase ? 'I' : 'i'), K(Ucase ? 'J' : 'j'), K(Ucase ? 'K' : 'k'), K(Ucase ? 'L' : 'l'), K(Ucase ? 'M' : 'm'), K(Ucase ? 'N' : 'n'), K(Ucase ? 'O' : 'o'), @@ -2012,13 +2006,18 @@ constexpr K digits_symbols[36] = {K('0'), K('1'), K('2'), K('3'), K('4'), K('5') K(Ucase ? 'Z' : 'z'), }; -template -requires (Radix > 1 && Radix <= 36) +template requires (Radix > 1 && Radix <= 36) struct expr_integer_src { T value_; unsigned width_{}; constexpr expr_integer_src(T v) : value_(v){} constexpr expr_integer_src(T v, unsigned w) : value_(v), width_(w){} + + template + operator S() const; + + template requires std::is_constructible_v> + operator S() const; }; template @@ -2191,6 +2190,21 @@ struct expr_integer : expr_to_std_string> { } }; +template requires (Radix > 1 && Radix <= 36) +template +expr_integer_src::operator S() const { + using st = typename S::value_type; + using Al = typename S::allocator_type; + return to_std_string(expr_integer{value_, width_}); +} + +template requires (Radix > 1 && Radix <= 36) +template requires std::is_constructible_v> +expr_integer_src::operator S() const { + using st = typename S::symb_type; + return S{expr_integer{value_, width_}}; +} + template struct convert_to_strexpr> { using type = expr_integer; @@ -2292,8 +2306,7 @@ concept good_int_flags = * Так как после `F` все символы воспринимаются как hex код символа разделителя, при необходимости его использования * лучше ставить его в конце литерала форматирования, или отделять '. *
- * @en @brief Creates a set of radix and flags that can be applied to integers - * numbers to set formatting parameters using the division operator: `num / 0xFormatOptions_fmt`. + * @en It is also possible to write this function in a shortened form: `num / 0xFormatOptions_fmt`. * Formatting parameters are set as follows: first comes `0x`, then the radix written in * decimal form. Next may be symbols indicating various flags: * - b when setting the field width, align to the left, analogous to f::l. @@ -4967,11 +4980,11 @@ inline namespace literals { * ``` */ template -consteval auto operator""_fmt() { +SS_CONSTEVAL auto operator""_fmt() { return f::skip_0x(); } -} +} // namespace literals #ifndef IN_FULL_SIMSTR diff --git a/readme.md b/readme.md index 0b6e67d..68620c2 100644 --- a/readme.md +++ b/readme.md @@ -299,6 +299,7 @@ When connecting only `strexpr.h` - the types `simple_str` and `simple_str_nt< ## Articles - [Overview and introduction](docs/overview.md) +- [So how do you quickly concatenate strings?](https://orefkov.github.io/simstr/articles/fast_concat.html) - [Overview article on Habr](https://habr.com/ru/articles/935590) (on Russian) - [Description of the applied technique "Expression Templates"](https://habr.com/ru/articles/936468/)(on Russian) diff --git a/readme_ru.md b/readme_ru.md index 4503e3a..81975c6 100644 --- a/readme_ru.md +++ b/readme_ru.md @@ -300,6 +300,7 @@ int split_and_calc_total_sim(ssa numbers, ssa delimiter) { ## Статьи - [Обзор и введение](docs/overview_ru.md) +- [Так как же всё-таки быстро конкатенировать строки?](https://orefkov.github.io/simstr/articles/fast_concat_ru.html) - [Обзорная статья на Хабре](https://habr.com/ru/articles/935590) - [Описание применяемой техники "Expression Templates"](https://habr.com/ru/articles/936468/) diff --git a/tests/test_expr_only.cpp b/tests/test_expr_only.cpp index 14e586a..ff8057d 100644 --- a/tests/test_expr_only.cpp +++ b/tests/test_expr_only.cpp @@ -402,6 +402,8 @@ TEST(StrExpr, EInt) { TEST(StrExpr, EIntFmt) { std::string test = "'0x"_ss + 10 / 0x16E08_fmt + "' " + 10 / 0x11'8EF5f_fmt; EXPECT_EQ(test, "'0x0000000A' _______A"); + test = 100 / 0x2a010_fmt; + EXPECT_EQ(test, "0b01100100"); } } // namespace simstr::tests diff --git a/tests/test_str.cpp b/tests/test_str.cpp index 9674ae0..b465dc2 100644 --- a/tests/test_str.cpp +++ b/tests/test_str.cpp @@ -1999,11 +1999,17 @@ TEST(SimStr, Subst) { EXPECT_EQ(u16t, u"Test 1 from 100, success."); } -void check_equal(stra a, stra b) { - EXPECT_EQ(a, b); +TEST(SimStr, EIntFmt) { + stringa test = "'0x"_ss + 10 / 0x16E08_fmt + "' " + 10 / 0x11'8EF5f_fmt; + EXPECT_EQ(test, "'0x0000000A' _______A"); + test = 100 / 0x2a010_fmt; + EXPECT_EQ(test, "0b01100100"); } #ifndef _MSC_VER +void check_equal(stra a, stra b) { + EXPECT_EQ(a, b); +} inline constexpr cestring ce_sample = "sample " + e_subst("test = {}", e_hex(10)) + ", done"; TEST(SimStr, ConstEval) {