Доработана работа с constexpr. Дополнена документация.

This commit is contained in:
Aleksandr Orefkov 2026-01-04 12:20:36 +03:00
parent 3a86c9c221
commit de7461dcd5
8 changed files with 598 additions and 424 deletions

View File

@ -5,7 +5,7 @@ include(FetchContent)
project( project(
simstr simstr
VERSION 1.3.0 VERSION 1.3.1
DESCRIPTION "Yet another modern C++ string library" DESCRIPTION "Yet another modern C++ string library"
HOMEPAGE_URL "https://github.com/orefkov/simstr" HOMEPAGE_URL "https://github.com/orefkov/simstr"
LANGUAGES CXX LANGUAGES CXX

View File

@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 1.3.0 PROJECT_NUMBER = 1.3.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewers a # for a project that appears at the top of each page and should give viewers a

View File

@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 1.3.0 PROJECT_NUMBER = 1.3.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewers a # for a project that appears at the top of each page and should give viewers a

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* /*
* ver. 1.3.0 * ver. 1.3.1
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
* База для строковых конкатенаций через выражения времени компиляции * База для строковых конкатенаций через выражения времени компиляции
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
@ -49,10 +49,10 @@ using u32s = char32_t;
using uu8s = std::make_unsigned<u8s>::type; using uu8s = std::make_unsigned<u8s>::type;
template<typename K> template<typename K>
inline 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>; 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>;
template<typename K> template<typename K>
inline 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>; 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>;
template<typename From> template<typename From>
requires (is_one_of_std_char_v<From>) requires (is_one_of_std_char_v<From>)
@ -143,7 +143,7 @@ template<typename K, size_t N>
class const_lit_to_array { class const_lit_to_array {
template<size_t Idx> template<size_t Idx>
size_t find(K s) const { constexpr size_t find(K s) const {
if constexpr (Idx < N) { if constexpr (Idx < N) {
return s == symbols_[Idx] ? Idx : find<Idx + 1>(s); return s == symbols_[Idx] ? Idx : find<Idx + 1>(s);
} }
@ -151,7 +151,7 @@ class const_lit_to_array {
} }
template<size_t Idx> template<size_t Idx>
bool exist(K s) const { constexpr bool exist(K s) const {
if constexpr (Idx < N) { if constexpr (Idx < N) {
return s == symbols_[Idx] || exist<Idx + 1>(s); return s == symbols_[Idx] || exist<Idx + 1>(s);
} }
@ -412,8 +412,8 @@ struct strexprjoin {
* expressions, which are then materialized into the final result in one call. * expressions, which are then materialized into the final result in one call.
*/ */
template<StrExpr A, StrExprForType<typename A::symb_type> B> template<StrExpr A, StrExprForType<typename A::symb_type> B>
inline auto operator+(const A& a, const B& b) { constexpr strexprjoin<A, B> operator+(const A& a, const B& b) {
return strexprjoin<A, B>{a, b}; return {a, b};
} }
/*! /*!
@ -566,8 +566,8 @@ struct expr_char {
* ``` * ```
*/ */
template<typename K, StrExprForType<K> A> template<typename K, StrExprForType<K> A>
constexpr inline auto operator+(const A& a, K s) { constexpr strexprjoin_c<A, expr_char<K>> operator+(const A& a, K s) {
return strexprjoin_c<A, expr_char<K>>{a, s}; return {a, s};
} }
/*! /*!
@ -581,8 +581,8 @@ constexpr inline auto operator+(const A& a, K s) {
* @return string expression for a single character string. * @return string expression for a single character string.
*/ */
template<typename K> template<typename K>
constexpr inline auto e_char(K s) { constexpr expr_char<K> e_char(K s) {
return expr_char<K>{s}; return {s};
} }
template<typename K, size_t N> template<typename K, size_t N>
@ -652,8 +652,8 @@ struct expr_literal {
* All these methods work and give the same result. Which one to use is a matter of taste. * All these methods work and give the same result. Which one to use is a matter of taste.
*/ */
template<typename T, size_t N = const_lit<T>::Count> template<typename T, size_t N = const_lit<T>::Count>
constexpr inline auto e_t(T&& s) { constexpr expr_literal<typename const_lit<T>::symb_type, static_cast<size_t>(N - 1)> e_t(T&& s) {
return expr_literal<typename const_lit<T>::symb_type, static_cast<size_t>(N - 1)>{s}; return {s};
} }
template<bool first, typename K, size_t N, typename A> template<bool first, typename K, size_t N, typename A>
@ -692,8 +692,8 @@ struct expr_literal_join {
* @return A string expression concatenating the operands. * @return A string expression concatenating the operands.
*/ */
template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count> template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count>
constexpr inline auto operator+(const A& a, T&& s) { constexpr expr_literal_join<false, K, (N - 1), A> operator+(const A& a, T&& s) {
return expr_literal_join<false, K, (N - 1), A>{s, a}; return {s, a};
} }
/*! /*!
@ -704,8 +704,8 @@ constexpr inline auto operator+(const A& a, T&& s) {
* @return A string expression concatenating the operands. * @return A string expression concatenating the operands.
*/ */
template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count> template<StrExpr A, typename K = typename A::symb_type, typename T, size_t N = const_lit_for<K, T>::Count>
constexpr inline auto operator+(T&& s, const A& a) { constexpr expr_literal_join<true, K, (N - 1), A> operator+(T&& s, const A& a) {
return expr_literal_join<true, K, (N - 1), A>{s, a}; return {s, a};
} }
/*! /*!
@ -748,8 +748,8 @@ struct expr_spaces {
* ``` * ```
*/ */
template<size_t N> template<size_t N>
constexpr inline auto e_spca() { constexpr expr_spaces<u8s, N> e_spca() {
return expr_spaces<u8s, N>(); return {};
} }
/*! /*!
@ -766,8 +766,8 @@ constexpr inline auto e_spca() {
* ``` * ```
*/ */
template<size_t N> template<size_t N>
constexpr inline auto e_spcw() { constexpr expr_spaces<uws, N> e_spcw() {
return expr_spaces<uws, N>(); return {};
} }
/*! /*!
@ -810,8 +810,8 @@ struct expr_pad {
* @return a string expression that generates a string of l characters k. * @return a string expression that generates a string of l characters k.
*/ */
template<typename K> template<typename K>
constexpr inline auto e_c(size_t l, K s) { constexpr expr_pad<K> e_c(size_t l, K s) {
return expr_pad<K>{ l, s }; return { l, s };
} }
template<typename K, size_t N> template<typename K, size_t N>
@ -861,8 +861,8 @@ struct expr_repeat_expr {
* @return a string expression generating a string of l strings s * @return a string expression generating a string of l strings s
*/ */
template<typename T, typename K = const_lit<T>::symb_type, size_t M = const_lit<T>::Count> requires (M > 0) template<typename T, typename K = const_lit<T>::symb_type, size_t M = const_lit<T>::Count> requires (M > 0)
constexpr inline auto e_repeat(T&& s, size_t l) { constexpr expr_repeat_lit<K, M - 1> e_repeat(T&& s, size_t l) {
return expr_repeat_lit<K, M - 1>{ l, s }; return { l, s };
} }
/*! /*!
@ -879,8 +879,8 @@ constexpr inline auto e_repeat(T&& s, size_t l) {
* @return a string expression generating a string of l string expressions s * @return a string expression generating a string of l string expressions s
*/ */
template<StrExpr A> template<StrExpr A>
constexpr inline auto e_repeat(const A& s, size_t l) { constexpr expr_repeat_expr<A> e_repeat(const A& s, size_t l) {
return expr_repeat_expr<A>{ l, s }; return { l, s };
} }
/*! /*!
@ -1103,8 +1103,8 @@ struct expr_choice_two_lit {
* which is not optimal and will reduce performance. (This is checked in the "Build Full Func Name" benchmark) * which is not optimal and will reduce performance. (This is checked in the "Build Full Func Name" benchmark)
*/ */
template<StrExpr A, StrExprForType<typename A::symb_type> B> template<StrExpr A, StrExprForType<typename A::symb_type> B>
inline constexpr auto e_choice(bool c, const A& a, const B& b) { constexpr expr_choice<A, B> e_choice(bool c, const A& a, const B& b) {
return expr_choice<A, B>{a, b, c}; return {a, b, c};
} }
/*! /*!
@ -1113,8 +1113,8 @@ inline constexpr auto e_choice(bool c, const A& a, const B& b) {
* @en @brief Overload e_choice when the third argument is a string literal. * @en @brief Overload e_choice when the third argument is a string literal.
*/ */
template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count> template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
inline constexpr auto e_choice(bool c, const A& a, T&& str) { constexpr expr_choice_one_lit<A, N - 1, true> e_choice(bool c, const A& a, T&& str) {
return expr_choice_one_lit<A, N - 1, true>{str, a, c}; return {str, a, c};
} }
/*! /*!
@ -1123,8 +1123,8 @@ inline constexpr auto e_choice(bool c, const A& a, T&& str) {
* @en @brief Overload e_choice when the second argument is a string literal. * @en @brief Overload e_choice when the second argument is a string literal.
*/ */
template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count> template<StrExpr A, typename T, size_t N = const_lit_for<typename A::symb_type, T>::Count>
inline constexpr auto e_choice(bool c, T&& str, const A& a) { constexpr expr_choice_one_lit<A, N - 1, false> e_choice(bool c, T&& str, const A& a) {
return expr_choice_one_lit<A, N - 1, false>{str, a, c}; return {str, a, c};
} }
/*! /*!
* @ingroup StrExprs * @ingroup StrExprs
@ -1132,8 +1132,8 @@ inline constexpr auto e_choice(bool c, T&& str, const A& a) {
* @en @brief Overload e_choice when the second and third arguments are string literals. * @en @brief Overload e_choice when the second and third arguments are string literals.
*/ */
template<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> template<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>
inline constexpr auto e_choice(bool c, T&& str_a, L&& str_b) { constexpr expr_choice_two_lit<typename const_lit<T>::symb_type, N -1, M - 1> e_choice(bool c, T&& str_a, L&& str_b) {
return expr_choice_two_lit<typename const_lit<T>::symb_type, N -1, M - 1>{str_a, str_b, c}; return {str_a, str_b, c};
} }
/*! /*!
@ -1179,8 +1179,8 @@ inline constexpr auto e_choice(bool c, T&& str_a, L&& str_b) {
* which is not optimal and will reduce performance. (This example is tested in the "Build Full Func Name" benchmark) * which is not optimal and will reduce performance. (This example is tested in the "Build Full Func Name" benchmark)
*/ */
template<StrExpr A> template<StrExpr A>
inline constexpr auto e_if(bool c, const A& a) { constexpr expr_if<A> e_if(bool c, const A& a) {
return expr_if<A>{a, c}; return {a, c};
} }
/*! /*!
* @ingroup StrExprs * @ingroup StrExprs
@ -1188,7 +1188,7 @@ inline constexpr auto e_if(bool c, const A& a) {
* @en @brief Overload e_if when the second argument is a string literal. * @en @brief Overload e_if when the second argument is a string literal.
*/ */
template<typename T, size_t N = const_lit<T>::Count> template<typename T, size_t N = const_lit<T>::Count>
inline constexpr auto e_if(bool c, T&& str) { constexpr auto e_if(bool c, T&& str) {
const typename const_lit<T>::symb_type empty[1] = {0}; const typename const_lit<T>::symb_type empty[1] = {0};
return expr_choice_two_lit<typename const_lit<T>::symb_type, N - 1, 0>{str, empty, c}; return expr_choice_two_lit<typename const_lit<T>::symb_type, N - 1, 0>{str, empty, c};
} }
@ -1225,8 +1225,8 @@ struct expr_stdstr {
* @en @brief Addition operator for char string expression and std::string. * @en @brief Addition operator for char string expression and std::string.
*/ */
template<StrExprForType<u8s> A> template<StrExprForType<u8s> A>
auto operator+(const A& a, const std::string& s) { constexpr strexprjoin_c<A, expr_stdstr<u8s, std::string>, true> operator+(const A& a, const std::string& s) {
return strexprjoin_c<A, expr_stdstr<u8s, std::string>, true>{a, s}; return {a, s};
} }
/*! /*!
@ -1235,8 +1235,8 @@ auto operator+(const A& a, const std::string& s) {
* @en @brief Addition operator for std::string and char string expression. * @en @brief Addition operator for std::string and char string expression.
*/ */
template<StrExprForType<u8s> A> template<StrExprForType<u8s> A>
auto operator+(const std::string& s, const A& a) { constexpr strexprjoin_c<A, expr_stdstr<u8s, std::string>, false> operator+(const std::string& s, const A& a) {
return strexprjoin_c<A, expr_stdstr<u8s, std::string>, false>{a, s}; return {a, s};
} }
/*! /*!
@ -1245,8 +1245,8 @@ auto operator+(const std::string& s, const A& a) {
* @en @brief Addition operator for char string expression and std::string_view. * @en @brief Addition operator for char string expression and std::string_view.
*/ */
template<StrExprForType<u8s> A> template<StrExprForType<u8s> A>
auto operator+(const A& a, const std::string_view& s) { constexpr strexprjoin_c<A, expr_stdstr<u8s, std::string_view>, true> operator+(const A& a, const std::string_view& s) {
return strexprjoin_c<A, expr_stdstr<u8s, std::string_view>, true>{a, s}; return {a, s};
} }
/*! /*!
@ -1255,8 +1255,8 @@ auto operator+(const A& a, const std::string_view& s) {
* @en @brief Addition operator for std::string_view and char string expression. * @en @brief Addition operator for std::string_view and char string expression.
*/ */
template<StrExprForType<u8s> A> template<StrExprForType<u8s> A>
auto operator+(const std::string_view& s, const A& a) { constexpr strexprjoin_c<A, expr_stdstr<u8s, std::string_view>, false> operator+(const std::string_view& s, const A& a) {
return strexprjoin_c<A, expr_stdstr<u8s, std::string_view>, false>{a, s}; return {a, s};
} }
/*! /*!
@ -1265,8 +1265,8 @@ auto operator+(const std::string_view& s, const A& a) {
* @en @brief Addition operator for wchar_t string expression and std::wstring. * @en @brief Addition operator for wchar_t string expression and std::wstring.
*/ */
template<StrExprForType<uws> A> template<StrExprForType<uws> A>
auto operator+(const A& a, const std::wstring& s) { constexpr strexprjoin_c<A, expr_stdstr<uws, std::wstring>, true> operator+(const A& a, const std::wstring& s) {
return strexprjoin_c<A, expr_stdstr<uws, std::wstring>, true>{a, s}; return {a, s};
} }
/*! /*!
@ -1275,8 +1275,8 @@ auto operator+(const A& a, const std::wstring& s) {
* @en @brief Addition operator for std::wstring and wchar_t string expression. * @en @brief Addition operator for std::wstring and wchar_t string expression.
*/ */
template<StrExprForType<uws> A> template<StrExprForType<uws> A>
auto operator+(const std::wstring& s, const A& a) { constexpr strexprjoin_c<A, expr_stdstr<uws, std::wstring>, false> operator+(const std::wstring& s, const A& a) {
return strexprjoin_c<A, expr_stdstr<uws, std::wstring>, false>{a, s}; return {a, s};
} }
/*! /*!
@ -1285,8 +1285,8 @@ auto operator+(const std::wstring& s, const A& a) {
* @en @brief Addition operator for wchar_t string expression and std::wstring_view. * @en @brief Addition operator for wchar_t string expression and std::wstring_view.
*/ */
template<StrExprForType<uws> A> template<StrExprForType<uws> A>
auto operator+(const A& a, const std::wstring_view& s) { constexpr strexprjoin_c<A, expr_stdstr<uws, std::wstring_view>, true> operator+(const A& a, const std::wstring_view& s) {
return strexprjoin_c<A, expr_stdstr<uws, std::wstring_view>, true>{a, s}; return {a, s};
} }
/*! /*!
@ -1295,8 +1295,8 @@ auto operator+(const A& a, const std::wstring_view& s) {
* @en @brief Addition operator for std::wstring_view and wchar_t string expression. * @en @brief Addition operator for std::wstring_view and wchar_t string expression.
*/ */
template<StrExprForType<uws> A> template<StrExprForType<uws> A>
auto operator+(const std::wstring_view& s, const A& a) { constexpr strexprjoin_c<A, expr_stdstr<uws, std::wstring_view>, false> operator+(const std::wstring_view& s, const A& a) {
return strexprjoin_c<A, expr_stdstr<uws, std::wstring_view>, false>{a, s}; return {a, s};
} }
/*! /*!
@ -1307,8 +1307,8 @@ auto operator+(const std::wstring_view& s, const A& a) {
* char32_t, depending on the compiler) and std::wstring. * char32_t, depending on the compiler) and std::wstring.
*/ */
template<StrExprForType<wchar_type> A> template<StrExprForType<wchar_type> A>
auto operator+(const A& a, const std::wstring& s) { constexpr strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring>, true> operator+(const A& a, const std::wstring& s) {
return strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring>, true>{a, s}; return {a, s};
} }
/*! /*!
@ -1319,8 +1319,8 @@ auto operator+(const A& a, const std::wstring& s) {
* (char16_t or char32_t, depending on the compiler). * (char16_t or char32_t, depending on the compiler).
*/ */
template<StrExprForType<wchar_type> A> template<StrExprForType<wchar_type> A>
auto operator+(const std::wstring& s, const A& a) { constexpr strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring>, false> operator+(const std::wstring& s, const A& a) {
return strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring>, false>{a, s}; return {a, s};
} }
/*! /*!
@ -1331,8 +1331,8 @@ auto operator+(const std::wstring& s, const A& a) {
* char32_t, depending on the compiler) and std::wstring_view. * char32_t, depending on the compiler) and std::wstring_view.
*/ */
template<StrExprForType<wchar_type> A> template<StrExprForType<wchar_type> A>
auto operator+(const A& a, const std::wstring_view& s) { constexpr strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring_view>, true> operator+(const A& a, const std::wstring_view& s) {
return strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring_view>, true>{a, s}; return {a, s};
} }
/*! /*!
@ -1343,8 +1343,8 @@ auto operator+(const A& a, const std::wstring_view& s) {
* (char16_t or char32_t, depending on the compiler). * (char16_t or char32_t, depending on the compiler).
*/ */
template<StrExprForType<wchar_type> A> template<StrExprForType<wchar_type> A>
auto operator+(const std::wstring_view& s, const A& a) { constexpr strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring_view>, false> operator+(const std::wstring_view& s, const A& a) {
return strexprjoin_c<A, expr_stdstr<wchar_type, std::wstring_view>, false>{a, s}; return {a, s};
} }
}// namespace simstr }// namespace simstr

View File

@ -1,7 +1,7 @@
# simstr - String object and function library # simstr - String object and function library
[![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml) [![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
Version 1.3.0. Version 1.3.1.
<span class="obfuscator"><a href="readme_ru.md">On Russian | По-русски</a></span> <span class="obfuscator"><a href="readme_ru.md">On Russian | По-русски</a></span>
@ -71,6 +71,8 @@ then the simstr approach will also be clear to you.
you can simply include the files in your project. Building also requires [simdutf](https://github.com/simdutf/simdutf) (when using CMake you can simply include the files in your project. Building also requires [simdutf](https://github.com/simdutf/simdutf) (when using CMake
it is downloaded automatically). it is downloaded automatically).
The library is included in [vcpkg](https://vcpkg.io), use as `orefkov-simstr`.
`simstr` requires a compiler of standard no lower than C++20 to work - concepts and std::format are used. `simstr` requires a compiler of standard no lower than C++20 to work - concepts and std::format are used.
The work was tested under Windows on MSVC-19 and Clang-19, under Linux - on GCC-13 and Clang-21. The work was tested under Windows on MSVC-19 and Clang-19, under Linux - on GCC-13 and Clang-21.
The work in WASM was also tested, built in Emscripten 4.0.6, Clang-21. The work in WASM was also tested, built in Emscripten 4.0.6, Clang-21.

View File

@ -1,7 +1,7 @@
# simstr - библиотека строковых объектов и функций # simstr - библиотека строковых объектов и функций
[![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml) [![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
Версия 1.3.0. Версия 1.3.1.
<span class="obfuscator"><a href="readme.md">On English | По-английски</a></span> <span class="obfuscator"><a href="readme.md">On English | По-английски</a></span>
@ -71,10 +71,13 @@
можно просто включить файлы в свой проект. Для сборки также требуется [simdutf](https://github.com/simdutf/simdutf) (при использовании CMake можно просто включить файлы в свой проект. Для сборки также требуется [simdutf](https://github.com/simdutf/simdutf) (при использовании CMake
скачивается автоматически). скачивается автоматически).
Библиотека включена в [vcpkg](https://vcpkg.io), подключается как `orefkov-simstr`.
Для работы `simstr` требуется компилятор стандарта не ниже С++20 - используются концепты и std::format. Для работы `simstr` требуется компилятор стандарта не ниже С++20 - используются концепты и std::format.
Работа проверялась под Windows на MSVC-19 и Clang-19, под Linux - на GCC-13 и Clang-21. Работа проверялась под Windows на MSVC-19 и Clang-19, под Linux - на GCC-13 и Clang-21.
Также проверялась работа в WASM, сборка в Emscripten 4.0.6, Clang-21. Также проверялась работа в WASM, сборка в Emscripten 4.0.6, Clang-21.
## Удобная отладка ## Удобная отладка
Вместе с библиотекой поставляются два файла, делающие просмотр simstr строковых объектов в отладчиках Вместе с библиотекой поставляются два файла, делающие просмотр simstr строковых объектов в отладчиках
более удобным.\ более удобным.\

View File

@ -522,42 +522,42 @@ TEST(SimStr, IsAscii) {
} }
TEST(SimStr, ChangeCase) { TEST(SimStr, ChangeCase) {
EXPECT_EQ(ssa{"TEST"}.uppered_only_ascii<stringa>(), "TEST"); EXPECT_EQ(ssa{"TEST"}.upperred_only_ascii<stringa>(), "TEST");
EXPECT_EQ(ssa{"Test"}.uppered_only_ascii<stringa>(), "TEST"); EXPECT_EQ(ssa{"Test"}.upperred_only_ascii<stringa>(), "TEST");
EXPECT_EQ(ssa{"test"}.lowered_only_ascii<stringa>(), "test"); EXPECT_EQ(ssa{"test"}.lowered_only_ascii<stringa>(), "test");
EXPECT_EQ(ssa{"Test"}.lowered_only_ascii<stringa>(), "test"); EXPECT_EQ(ssa{"Test"}.lowered_only_ascii<stringa>(), "test");
EXPECT_EQ(ssa{"TestПрОвЕрКа"}.uppered_only_ascii<stringa>(), "TESTПрОвЕрКа"); EXPECT_EQ(ssa{"TestПрОвЕрКа"}.upperred_only_ascii<stringa>(), "TESTПрОвЕрКа");
EXPECT_EQ(ssa{"TestПрОвЕрКа"}.lowered_only_ascii<stringa>(), "testПрОвЕрКа"); EXPECT_EQ(ssa{"TestПрОвЕрКа"}.lowered_only_ascii<stringa>(), "testПрОвЕрКа");
EXPECT_EQ(ssa{"TestПрОвЕрКа"}.uppered<stringa>(), "TESTПРОВЕРКА"); EXPECT_EQ(ssa{"TestПрОвЕрКа"}.upperred<stringa>(), "TESTПРОВЕРКА");
EXPECT_EQ(ssa{"tesTПрОвЕрКа"}.lowered<stringa>(), "testпроверка"); EXPECT_EQ(ssa{"tesTПрОвЕрКа"}.lowered<stringa>(), "testпроверка");
EXPECT_EQ(ssa{"TEST"}.uppered<stringa>(), "TEST"); EXPECT_EQ(ssa{"TEST"}.upperred<stringa>(), "TEST");
EXPECT_EQ(ssa{"test"}.lowered<stringa>(), "test"); EXPECT_EQ(ssa{"test"}.lowered<stringa>(), "test");
EXPECT_EQ(ssa{"TESTПРОВЕРКА"}.uppered<stringa>(), "TESTПРОВЕРКА"); EXPECT_EQ(ssa{"TESTПРОВЕРКА"}.upperred<stringa>(), "TESTПРОВЕРКА");
EXPECT_EQ(ssa{"testпроверка"}.lowered<stringa>(), "testпроверка"); EXPECT_EQ(ssa{"testпроверка"}.lowered<stringa>(), "testпроверка");
EXPECT_EQ(ssa{"tesTİiȺⱥȾⱦẞßΩФывAsd"}.lowered<stringa>(), "testiiⱥⱥⱦⱦßßωфывasd"); EXPECT_EQ(ssa{"tesTİiȺⱥȾⱦẞßΩФывAsd"}.lowered<stringa>(), "testiiⱥⱥⱦⱦßßωфывasd");
EXPECT_EQ(ssa{"testⱢɱⱮɽⱤWas"}.uppered<stringa>(), "TESTⱢⱮⱮⱤⱤWAS"); EXPECT_EQ(ssa{"testⱢɱⱮɽⱤWas"}.upperred<stringa>(), "TESTⱢⱮⱮⱤⱤWAS");
EXPECT_EQ(ssu{u"TEST"}.uppered_only_ascii<stringu>(), u"TEST"); EXPECT_EQ(ssu{u"TEST"}.upperred_only_ascii<stringu>(), u"TEST");
EXPECT_EQ(ssu{u"test"}.lowered_only_ascii<stringu>(), u"test"); EXPECT_EQ(ssu{u"test"}.lowered_only_ascii<stringu>(), u"test");
EXPECT_EQ(ssu{u"Test"}.uppered_only_ascii<stringu>(), u"TEST"); EXPECT_EQ(ssu{u"Test"}.upperred_only_ascii<stringu>(), u"TEST");
EXPECT_EQ(ssu{u"Test"}.lowered_only_ascii<stringu>(), u"test"); EXPECT_EQ(ssu{u"Test"}.lowered_only_ascii<stringu>(), u"test");
EXPECT_EQ(ssu{u"TestПрОвЕрКа"}.uppered_only_ascii<stringu>(), u"TESTПрОвЕрКа"); EXPECT_EQ(ssu{u"TestПрОвЕрКа"}.upperred_only_ascii<stringu>(), u"TESTПрОвЕрКа");
EXPECT_EQ(ssu{u"TestПрОвЕрКа"}.lowered_only_ascii<stringu>(), u"testПрОвЕрКа"); EXPECT_EQ(ssu{u"TestПрОвЕрКа"}.lowered_only_ascii<stringu>(), u"testПрОвЕрКа");
EXPECT_EQ(ssu{u"TestПрОвЕрКа"}.uppered<stringu>(), u"TESTПРОВЕРКА"); EXPECT_EQ(ssu{u"TestПрОвЕрКа"}.upperred<stringu>(), u"TESTПРОВЕРКА");
EXPECT_EQ(ssu{u"tesTПрОвЕрКа"}.lowered<stringu>(), u"testпроверка"); EXPECT_EQ(ssu{u"tesTПрОвЕрКа"}.lowered<stringu>(), u"testпроверка");
EXPECT_EQ(ssu{u"tesTİiȺⱥȾⱦẞßΩФывAsd"}.lowered<stringu>(), u"testiiⱥⱥⱦⱦßßωфывasd"); EXPECT_EQ(ssu{u"tesTİiȺⱥȾⱦẞßΩФывAsd"}.lowered<stringu>(), u"testiiⱥⱥⱦⱦßßωфывasd");
EXPECT_EQ(ssu{u"testⱢɱⱮɽⱤWas"}.uppered<stringu>(), u"TESTⱢⱮⱮⱤⱤWAS"); EXPECT_EQ(ssu{u"testⱢɱⱮɽⱤWas"}.upperred<stringu>(), u"TESTⱢⱮⱮⱤⱤWAS");
EXPECT_EQ(ssw{L"TEST"}.uppered_only_ascii<stringw>(), L"TEST"); EXPECT_EQ(ssw{L"TEST"}.upperred_only_ascii<stringw>(), L"TEST");
EXPECT_EQ(ssw{L"test"}.lowered_only_ascii<stringw>(), L"test"); EXPECT_EQ(ssw{L"test"}.lowered_only_ascii<stringw>(), L"test");
EXPECT_EQ(ssw{L"Test"}.uppered_only_ascii<stringw>(), L"TEST"); EXPECT_EQ(ssw{L"Test"}.upperred_only_ascii<stringw>(), L"TEST");
EXPECT_EQ(ssw{L"Test"}.lowered_only_ascii<stringw>(), L"test"); EXPECT_EQ(ssw{L"Test"}.lowered_only_ascii<stringw>(), L"test");
EXPECT_EQ(ssw{L"TestПрОвЕрКа"}.uppered_only_ascii<stringw>(), L"TESTПрОвЕрКа"); EXPECT_EQ(ssw{L"TestПрОвЕрКа"}.upperred_only_ascii<stringw>(), L"TESTПрОвЕрКа");
EXPECT_EQ(ssw{L"TestПрОвЕрКа"}.lowered_only_ascii<stringw>(), L"testПрОвЕрКа"); EXPECT_EQ(ssw{L"TestПрОвЕрКа"}.lowered_only_ascii<stringw>(), L"testПрОвЕрКа");
EXPECT_EQ(ssw{L"TestПрОвЕрКа"}.uppered<stringw>(), L"TESTПРОВЕРКА"); EXPECT_EQ(ssw{L"TestПрОвЕрКа"}.upperred<stringw>(), L"TESTПРОВЕРКА");
EXPECT_EQ(ssw{L"tesTПрОвЕрКа"}.lowered<stringw>(), L"testпроверка"); EXPECT_EQ(ssw{L"tesTПрОвЕрКа"}.lowered<stringw>(), L"testпроверка");
EXPECT_EQ(ssw{L"tesTİiȺⱥȾⱦẞßΩФывAsd"}.lowered<stringw>(), L"testiiⱥⱥⱦⱦßßωфывasd"); EXPECT_EQ(ssw{L"tesTİiȺⱥȾⱦẞßΩФывAsd"}.lowered<stringw>(), L"testiiⱥⱥⱦⱦßßωфывasd");
EXPECT_EQ(ssw{L"testⱢɱⱮɽⱤWas"}.uppered<stringw>(), L"TESTⱢⱮⱮⱤⱤWAS"); EXPECT_EQ(ssw{L"testⱢɱⱮɽⱤWas"}.upperred<stringw>(), L"TESTⱢⱮⱮⱤⱤWAS");
} }
TEST(SimStr, Replace) { TEST(SimStr, Replace) {
@ -1775,4 +1775,13 @@ TEST(SimStr, ExprRepeat) {
EXPECT_EQ(lstringa<40>{e_repeat("aa"_ss + t + "_", 3)}, "aa1_aa1_aa1_"); EXPECT_EQ(lstringa<40>{e_repeat("aa"_ss + t + "_", 3)}, "aa1_aa1_aa1_");
} }
TEST(SimStr, Constexpr) {
constexpr ssa tt = " asd "_ss.trimmed();
static_assert(tt == "asd");
constexpr stringa aa{"asd"};
static_assert(aa == "asd");
static_assert(aa.length() == 3);
constexpr stringa bb = "";
}
} // namespace simstr::tests } // namespace simstr::tests