mirror of https://github.com/orefkov/simstr.git
Compare commits
4 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
e9eaa6c4cb | |
|
|
00a4a008a9 | |
|
|
86deccbac3 | |
|
|
a779aa7320 |
|
|
@ -5,7 +5,7 @@ include(FetchContent)
|
|||
|
||||
project(
|
||||
simstr
|
||||
VERSION 1.8.1
|
||||
VERSION 1.9.1
|
||||
DESCRIPTION "Yet another modern C++ string library"
|
||||
HOMEPAGE_URL "https://github.com/orefkov/simstr"
|
||||
LANGUAGES CXX
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* Бенчмарки
|
||||
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ struct result_info {
|
|||
}
|
||||
// Текущее положение поставим сразу за cpuinfo и откинем завершающие переводы строк
|
||||
// We will put the current position immediately after cpuinfo and discard the final line feeds
|
||||
current_text_ = current_text_(cpu_info_.end() - current_text_.begin() + 1).trimmed_right("\n");
|
||||
current_text_ = current_text_.get(cpu_info_.end() - current_text_.begin() + 1, to_end).trimmed_right("\n");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -96,11 +96,11 @@ results_vector get_results_infos() {
|
|||
// В начале имени файла может идти число и дефис, для сортировки, уберём их
|
||||
// At the beginning of the file name there can be a number and a hyphen, for sorting, remove them
|
||||
if (auto delimiter = fileName.find('-'); delimiter + 1 > 1) {
|
||||
if (fileName(0, delimiter).to_int<unsigned, false, 10, false, false>().ec == IntConvertResult::Success) {
|
||||
if (fileName.prefix(delimiter).to_int<unsigned, false, 10, false, false>().ec == IntConvertResult::Success) {
|
||||
fileName.remove_prefix(delimiter + 1);
|
||||
}
|
||||
}
|
||||
results.emplace_back(get_file_content(lstringa<128>{dirForResults + f}), fileName(0, -suffix.length()));
|
||||
results.emplace_back(get_file_content(lstringa<128>{dirForResults + f}), fileName.get(0, from_end(suffix.length())));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
|
|
@ -117,7 +117,7 @@ void write_platforms_cpu(out_t& out, const results_vector& results) {
|
|||
for (const auto& r : results) {
|
||||
size_t rp = r.cpu_info_.find('(') + 1, lp = r.cpu_info_.find(')', rp);
|
||||
ssa shortCpuInfo = r.cpu_info_.from_to(rp, lp);
|
||||
ssa cpuInfo = r.cpu_info_(lp + 2);
|
||||
ssa cpuInfo = r.cpu_info_.get(lp + 2, to_end);
|
||||
out += e_subst(R"--(
|
||||
<li><span class="platform">{}</span><span class="tooltip">{}<span class="tooltiptext">{}</span></span> Include in charts: <input type="checkbox" id="pl{}" checked onchange="buildCharts()"/></li>)--",
|
||||
r.platform_, shortCpuInfo, cpuInfo, counter++);
|
||||
|
|
@ -167,7 +167,7 @@ ssa extract_name_result(ssa line, ssa& result) {
|
|||
line.len = ns;
|
||||
if (inNs) {
|
||||
size_t end = line.find_last(' ');
|
||||
result = line(end + 1);
|
||||
result = line.get(end + 1, to_end);
|
||||
if (auto rp = line.find("/repeats"); rp != str::npos) {
|
||||
line.len = rp;
|
||||
} else {
|
||||
|
|
@ -182,7 +182,7 @@ ssa extract_name_result(ssa line, ssa& result) {
|
|||
ssa extract_comment(ssa commentsText, ssa benchmarkName) {
|
||||
size_t idx = commentsText.find_end(lstringa<120>{"- " + benchmarkName + "\n"});
|
||||
if (idx != str::npos) {
|
||||
if (commentsText[idx] != '\n' && commentsText(idx, 2) != "- ") {
|
||||
if (commentsText[idx] != '\n' && commentsText.get(idx, 2) != "- ") {
|
||||
return commentsText.from_to(idx, commentsText.find("\n\n", idx));
|
||||
}
|
||||
}
|
||||
|
|
@ -206,7 +206,7 @@ std::pair<ssa, size_t> extract_source_for_benchmark(ssa benchName, ssa sourceTex
|
|||
}();
|
||||
|
||||
size_t delim = benchName.find_last('/');
|
||||
if (delim != str::npos && benchName(delim + 1).to_int<unsigned, false, 10, false, false>().ec == IntConvertResult::Success) {
|
||||
if (delim != str::npos && benchName.get(delim + 1, to_end).to_int<unsigned, false, 10, false, false>().ec == IntConvertResult::Success) {
|
||||
benchName.len = delim;
|
||||
}
|
||||
auto [it, not_exist] = textes.try_emplace(benchName, stringa{}, 0);
|
||||
|
|
@ -218,7 +218,7 @@ std::pair<ssa, size_t> extract_source_for_benchmark(ssa benchName, ssa sourceTex
|
|||
std::cerr << "Can not found benchmark function name for " << benchName << std::endl;
|
||||
return {stra::empty_str, 0};
|
||||
}
|
||||
start = sourceText(0, start).find('(', sourceText.find_last('\n', start - 1));
|
||||
start = sourceText.prefix(start).find('(', sourceText.find_last('\n', start - 1));
|
||||
if (start == str::npos) {
|
||||
std::cerr << "Can not found benchmark function name for " << benchName << std::endl;
|
||||
return {stra::empty_str, 0};
|
||||
|
|
@ -237,7 +237,7 @@ std::pair<ssa, size_t> extract_source_for_benchmark(ssa benchName, ssa sourceTex
|
|||
}
|
||||
start = sourceText.find_last('\n', start);
|
||||
size_t templ_start = sourceText.find_last('\n', start) + 1;
|
||||
if (sourceText(templ_start).starts_with("template")) {
|
||||
if (sourceText.get(templ_start, to_end).starts_with("template")) {
|
||||
start = templ_start;
|
||||
} else {
|
||||
start++;
|
||||
|
|
@ -261,7 +261,7 @@ std::pair<ssa, size_t> extract_source_for_benchmark(ssa benchName, ssa sourceTex
|
|||
throw std::runtime_error{"Not found end of func"};
|
||||
}
|
||||
lstringa<2048> text{sourceText.from_to(beginLine, end + indent.length() + 1), indent, "\n"};
|
||||
func_it->second.first = repl_html_symbols(text(1));
|
||||
func_it->second.first = repl_html_symbols(text.get(1, to_end));
|
||||
} else {
|
||||
end = sourceText.find("\n}\n", start);
|
||||
func_it->second.first = repl_html_symbols(sourceText.from_to(start, end + 2));
|
||||
|
|
@ -274,7 +274,7 @@ std::pair<ssa, size_t> extract_source_for_benchmark(ssa benchName, ssa sourceTex
|
|||
}
|
||||
|
||||
void write_benchmarks(out_t& out, const results_vector& results, ssa sourceText, ssa commentsText) {
|
||||
ssa releaseVersion = sourceText(sourceText.find_end("\n * ver. ")).until("\n").trimmed();
|
||||
ssa releaseVersion = sourceText.get(sourceText.find_end("\n * ver. "), to_end).until("\n").trimmed();
|
||||
if (!releaseVersion) {
|
||||
std::cerr << "Not found release version in sources" << std::endl;
|
||||
throw std::runtime_error{"Not found release version in sources"};
|
||||
|
|
@ -292,7 +292,7 @@ void write_benchmarks(out_t& out, const results_vector& results, ssa sourceText,
|
|||
while(!splitters[0].is_done()) {
|
||||
ssa line = splitters[0].next(), benchName, result;
|
||||
if (auto rm = line.find("_mean"); rm != str::npos) {
|
||||
benchName = extract_name_result(line, result)(0, rm);
|
||||
benchName = extract_name_result(line, result).prefix(rm);
|
||||
auto [source, line_num] = extract_source_for_benchmark(benchName, sourceText);
|
||||
auto comment = extract_comment(commentsText, benchName);
|
||||
// Нужно вывести название бенча и коммент
|
||||
|
|
@ -312,12 +312,12 @@ void write_benchmarks(out_t& out, const results_vector& results, ssa sourceText,
|
|||
throw std::runtime_error{"Not expected end of file"};
|
||||
}
|
||||
line = splitters[idx].next();
|
||||
ssa rbench_name = extract_name_result(line, result)(0, rm);
|
||||
ssa rbench_name = extract_name_result(line, result).prefix(rm);
|
||||
if (rbench_name != benchName) {
|
||||
while (line.find("_mean") == str::npos && !splitters[idx].is_done()) {
|
||||
line = splitters[idx].next();
|
||||
}
|
||||
rbench_name = extract_name_result(line, result)(0, rm);
|
||||
rbench_name = extract_name_result(line, result).prefix(rm);
|
||||
if (rbench_name != benchName) {
|
||||
std::cerr << "In results for " << results[idx].platform_ << " benchmark '" << rbench_name
|
||||
<< "' does not match with other results" << std::endl;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
|
|||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 1.8.1
|
||||
PROJECT_NUMBER = 1.9.1
|
||||
|
||||
# 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
|
||||
|
|
@ -2928,7 +2928,7 @@ MAX_DOT_GRAPH_DEPTH = 0
|
|||
|
||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
||||
# makes dot run faster, but since only newer versions of dot (>1.8.20) support
|
||||
# this, this feature is disabled by default.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
|
|||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 1.8.1
|
||||
PROJECT_NUMBER = 1.9.1
|
||||
|
||||
# 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
|
||||
|
|
@ -2928,7 +2928,7 @@ MAX_DOT_GRAPH_DEPTH = 0
|
|||
|
||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
||||
# makes dot run faster, but since only newer versions of dot (>1.8.20) support
|
||||
# this, this feature is disabled by default.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* Классы для работы со строками
|
||||
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
|
||||
|
|
@ -3257,7 +3257,7 @@ public:
|
|||
}
|
||||
/*!
|
||||
* @ru @brief Определить длину строки.
|
||||
* Ищет символ 0 в буфере строки до его ёмкости, после чего устаналивает длину строки по найденному 0.
|
||||
* Ищет символ 0 в буфере строки до его ёмкости, после чего устанавливает длину строки по найденному 0.
|
||||
* @en @brief Determine the length of the string.
|
||||
* Searches for the character 0 in the string buffer to its capacity, and then sets the length of the string to the found 0.
|
||||
*/
|
||||
|
|
@ -3283,7 +3283,7 @@ public:
|
|||
if (is_alloced() && capacity_ > need_capacity) {
|
||||
K* newData = size_ <= LocalCapacity ? local_ : alloc_place(need_capacity);
|
||||
traits::copy(newData, data_, size_ + 1);
|
||||
base_storable::allocator().deallocate(to_real_address(data_));
|
||||
dealloc();
|
||||
data_ = newData;
|
||||
|
||||
if (size_ > LocalCapacity) {
|
||||
|
|
@ -4365,8 +4365,7 @@ public:
|
|||
}
|
||||
|
||||
auto erase(const InStore& key) {
|
||||
auto it = hash_t::find(key);
|
||||
if (it != hash_t::end()) {
|
||||
if (auto it = hash_t::find(key); it != hash_t::end()) {
|
||||
((sstring<K>*)it->first.node)->~sstring();
|
||||
hash_t::erase(it);
|
||||
return 1;
|
||||
|
|
@ -4378,15 +4377,151 @@ public:
|
|||
return erase(toStoreType(key));
|
||||
}
|
||||
|
||||
bool lookup(simple_str<K> txt, T& val) const {
|
||||
auto it = find(txt);
|
||||
if (it != hash_t::end()) {
|
||||
/*!
|
||||
* @ru @brief Поиск и извлечение значения.
|
||||
* @param key - искомый ключ.
|
||||
* @param val - ссылка на приёмник значения.
|
||||
* @details Если ключ существует, присваивает переданной ссылке хранимое значение и возвращает true.
|
||||
* Иначе возвращает false.
|
||||
* @en @brief Finding and retrieving the value.
|
||||
* @param key - the key you are looking for.
|
||||
* @param val - reference to the value receiver.
|
||||
* @details If the key exists, assigns the stored value to the passed reference and returns true.
|
||||
* Otherwise returns false.
|
||||
*/
|
||||
template<typename Dst> requires std::is_assignable_v<T, Dst>
|
||||
bool lookup(simple_str<K> key, Dst& val) const {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
val = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Поиск и извлечение значения.
|
||||
* @param key - искомый ключ.
|
||||
* @details Если ключ существует, присваивает переданной ссылке хранимое значение и возвращает true.
|
||||
* Иначе возвращает false.
|
||||
* @en @brief Finding and retrieving the value.
|
||||
* @param key - the key you are looking for.
|
||||
* @param val - reference to the value receiver.
|
||||
* @details If the key exists, assigns the stored value to the passed reference and returns true.
|
||||
* Otherwise returns false.
|
||||
*/
|
||||
template<typename Dst> requires std::is_assignable_v<T, Dst>
|
||||
bool lookup(const InStore& key, Dst& val) const {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
val = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Поиск и извлечение значения.
|
||||
* @param key - искомый ключ.
|
||||
* @details Если ключ существует, возвращает std::optional указанного типа с копией значения.
|
||||
* Иначе возвращает std::nullopt.
|
||||
* @en @brief Finding and retrieving the value.
|
||||
* @param key - the key you are looking for.
|
||||
* @details If the key exists, return a std::optional of the specified type with a copy of the value.
|
||||
* Otherwise returns std::nullopt.
|
||||
*/
|
||||
template<typename Dst = T> requires std::is_constructible_v<Dst, T>
|
||||
std::optional<Dst> get(simple_str<K> key) const {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Поиск и извлечение значения.
|
||||
* @param key - искомый ключ.
|
||||
* @details Если ключ существует, возвращает std::optional указанного типа с копией значения.
|
||||
* Иначе возвращает std::nullopt.
|
||||
* @en @brief Finding and retrieving the value.
|
||||
* @param s - the key you are looking for.
|
||||
* @details If the key exists, return a std::optional of the specified type with a copy of the value.
|
||||
* Otherwise returns std::nullopt.
|
||||
*/
|
||||
template<typename Dst = T> requires std::is_constructible_v<Dst, T>
|
||||
std::optional<Dst> get(const InStore& key) const {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Поиск существующего значения.
|
||||
* @param key - искомый ключ.
|
||||
* @details Если ключ существует, возвращает указатель на хранимое значение.
|
||||
* Иначе возвращает nullptr.
|
||||
* @en @brief Finding an existing value.
|
||||
* @param s - the key you are looking for.
|
||||
* @details If the key exists, returns a pointer to the stored value.
|
||||
* Otherwise returns nullptr.
|
||||
*/
|
||||
T* existed(simple_str<K> key) {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
return std::addressof(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Поиск существующего значения.
|
||||
* @param key - искомый ключ.
|
||||
* @details Если ключ существует, возвращает указатель на хранимое значение.
|
||||
* Иначе возвращает nullptr.
|
||||
* @en @brief Finding an existing value.
|
||||
* @param s - the key you are looking for.
|
||||
* @details If the key exists, returns a pointer to the stored value.
|
||||
* Otherwise returns nullptr.
|
||||
*/
|
||||
T* existed(const InStore& key) {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
return std::addressof(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Поиск существующего значения.
|
||||
* @param key - искомый ключ.
|
||||
* @details Если ключ существует, возвращает константный указатель на хранимое значение.
|
||||
* Иначе возвращает nullptr.
|
||||
* @en @brief Finding an existing value.
|
||||
* @param s - the key you are looking for.
|
||||
* @details If the key exists, returns a constant pointer to the stored value.
|
||||
* Otherwise returns nullptr.
|
||||
*/
|
||||
const T* existed(simple_str<K> key) const {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
return std::addressof(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Поиск существующего значения.
|
||||
* @param key - искомый ключ.
|
||||
* @details Если ключ существует, возвращает константный указатель на хранимое значение.
|
||||
* Иначе возвращает nullptr.
|
||||
* @en @brief Finding an existing value.
|
||||
* @param s - the key you are looking for.
|
||||
* @details If the key exists, returns a constant pointer to the stored value.
|
||||
* Otherwise returns nullptr.
|
||||
*/
|
||||
const T* existed(const InStore& key) const {
|
||||
if (auto it = find(key); it != hash_t::end()) {
|
||||
return std::addressof(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (auto& k: *this)
|
||||
((sstring<K>*)k.first.node)->~sstring();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* База для строковых конкатенаций через выражения времени компиляции
|
||||
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
|
||||
|
|
@ -3274,6 +3274,20 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct from_begin {
|
||||
size_t idx_;
|
||||
};
|
||||
struct from_end {
|
||||
size_t idx_;
|
||||
};
|
||||
inline constexpr from_end to_end{0};
|
||||
|
||||
template<typename T>
|
||||
concept first_index_in_str = std::is_same_v<T, from_end> || std::is_convertible_v<T, size_t>;
|
||||
|
||||
template<typename T>
|
||||
concept last_index_in_str = first_index_in_str<T> || std::is_same_v<T, from_begin>;
|
||||
|
||||
/*!
|
||||
* @ru @brief Класс с базовыми константными строковыми алгоритмами.
|
||||
* @details Является базой для классов, могущих выполнять константные операции со строками.
|
||||
|
|
@ -3445,6 +3459,7 @@ public:
|
|||
* "0123456789"_ss(-4, -1) == "678";
|
||||
* ```
|
||||
*/
|
||||
[[deprecated("Use 'get' or [start, end] in C++23")]]
|
||||
constexpr str_piece operator()(ptrdiff_t from, ptrdiff_t len = 0) const noexcept {
|
||||
size_t myLen = _len(), idxStart = from >= 0 ? from : (ptrdiff_t)myLen > -from ? myLen + from : 0,
|
||||
idxEnd = len > 0 ? idxStart + len : (ptrdiff_t)myLen > -len ? myLen + len : 0;
|
||||
|
|
@ -3454,6 +3469,83 @@ public:
|
|||
idxStart = idxEnd;
|
||||
return str_piece{_str() + idxStart, idxEnd - idxStart};
|
||||
}
|
||||
|
||||
/*!
|
||||
* @ru @brief Получить часть строки как "str_src".
|
||||
* @param start - начальная позиция в строке.
|
||||
* @param end - конечная позиция в строке.
|
||||
* @return Подстроку, str_src.
|
||||
* @details В качестве начальной позиции может задаваться или число - отсчитывается от начала строки, но не далее её конца,
|
||||
* или `from_end(число)` - отсчитывается от конца строки, но не ранее её начала.
|
||||
* В качестве конечной позиции может задаваться или число - отсчитывается от начальной позиции, но не далее конца строки,
|
||||
* или `from_end(число)` - отсчитывается от конца строки, но не ранее начальной позиции,
|
||||
* или `from_begin(число)` - отсчитывается от начала строки, но не ранее начальной позиции и не далее конца строки.
|
||||
* Также можно использовать `to_end` - эквивалентно from_end(0).
|
||||
* @en @brief Get part of a string as "str_src".
|
||||
* @param start - starting position in the string.
|
||||
* @param end - the end position in the string.
|
||||
* @return Substring, str_src.
|
||||
* @details Either a number can be specified as the starting position - it is counted from the beginning of the string, but not further than its end,
|
||||
* or `from_end(number)` - counted from the end of the string, but not earlier than its beginning.
|
||||
* The ending position can be either a number - counted from the starting position, but not further than the end of the string,
|
||||
* or `from_end(number)` - counted from the end of the string, but not earlier than the starting position,
|
||||
* or `from_begin(number)` - counted from the beginning of the string, but not earlier than the starting position and not further than the end of the string.
|
||||
* You can also use `to_end` - equivalent to from_end(0).
|
||||
* @~
|
||||
* ```cpp
|
||||
* "0123456789"_ss.get(5, 2) == "56";
|
||||
* "0123456789"_ss.get(5, to_end) == "56789";
|
||||
* "0123456789"_ss.get(5, from_end(1)) == "5678";
|
||||
* "0123456789"_ss.get(from_end(3), to_end) == "789";
|
||||
* "0123456789"_ss.get(from_end(3), 2) == "78";
|
||||
* "0123456789"_ss.get(from_end(4), from_end(1)) == "678";
|
||||
* ```
|
||||
*/
|
||||
template<first_index_in_str S, last_index_in_str E>
|
||||
constexpr str_piece get(S start, E end) const noexcept {
|
||||
size_t idxStart, idxEnd, len = _len();
|
||||
if constexpr (std::is_same_v<S, from_end>) {
|
||||
idxStart = start.idx_ > len ? 0 : len - start.idx_;
|
||||
} else {
|
||||
idxStart = std::min(size_t(start), len);
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<E, from_begin>) {
|
||||
idxEnd = std::max(idxStart, std::min(end.idx_, len));
|
||||
} else if constexpr (std::is_same_v<E, from_end>) {
|
||||
idxEnd = std::max(idxStart, end.idx_ > len ? 0 : len - end.idx_);
|
||||
} else {
|
||||
size_t e = end;
|
||||
idxEnd = len - idxStart < e ? len : idxStart + e;
|
||||
}
|
||||
|
||||
return str_piece{_str() + idxStart, idxEnd - idxStart};
|
||||
}
|
||||
|
||||
#if defined(__cpp_multidimensional_subscript) && __cpp_multidimensional_subscript >= 202211L
|
||||
/*!
|
||||
* @ru @brief Обертка вокруг `get` в виде многомерного оператора [].
|
||||
* @en @brief Wraps `get` as a multidimensional operator [].
|
||||
*/
|
||||
template<first_index_in_str S, last_index_in_str E>
|
||||
constexpr str_piece operator[](S start, E end) const noexcept {
|
||||
return get(start, end);
|
||||
}
|
||||
#endif
|
||||
/*!
|
||||
* @ru @brief Обертка вокруг `get(0, count)`.
|
||||
* @en @brief Wraps `get(0, count)`.
|
||||
*/
|
||||
constexpr str_piece prefix(size_t count) const noexcept {
|
||||
return get(0, count);
|
||||
}
|
||||
/*!
|
||||
* @ru @brief Обертка вокруг `get(from_end(count), to_end)`.
|
||||
* @en @brief Wraps `get(from_end(count), to_end)`.
|
||||
*/
|
||||
constexpr str_piece suffix(size_t count) const noexcept {
|
||||
return get(from_end(count), to_end);
|
||||
}
|
||||
/*!
|
||||
* @ru @brief Получить часть строки как "кусок строки".
|
||||
* @param from - количество символов от начала строки. При превышении размера строки вернёт пустую строку.
|
||||
|
|
@ -3500,7 +3592,7 @@ public:
|
|||
* @return Substring, str_src.
|
||||
*/
|
||||
constexpr str_piece until(str_piece pattern, size_t offset = 0) const noexcept {
|
||||
return (*this)(0, find_or_all(pattern, offset));
|
||||
return get(0, find_or_all(pattern, offset));
|
||||
}
|
||||
/*!
|
||||
* @ru @brief Проверка на пустоту.
|
||||
|
|
@ -3726,7 +3818,7 @@ public:
|
|||
* @return size_t - the position of the beginning of the substring occurrence, or throws an Exc exception if not found.
|
||||
*/
|
||||
template<typename Exc, typename ... Args> requires std::is_constructible_v<Exc, Args...>
|
||||
constexpr size_t find_or_throw(str_piece pattern, size_t offset = 0, Args&& ... args) const noexcept {
|
||||
constexpr size_t find_or_throw(str_piece pattern, size_t offset = 0, Args&& ... args) const {
|
||||
if (auto fnd = find(pattern.symbols(), pattern.length(), offset); fnd != str::npos) {
|
||||
return fnd;
|
||||
}
|
||||
|
|
@ -4071,9 +4163,14 @@ public:
|
|||
* @param len - the number of characters in the resulting "chunk". If less than or equal to zero, then count len characters from the end of the string.
|
||||
* @return my_type - a substring, an object of the same type to which the method is applied.
|
||||
*/
|
||||
[[deprecated("Use sub(start, end)")]]
|
||||
constexpr my_type substr(ptrdiff_t from, ptrdiff_t len = 0) const { // индексация в code units | indexing in code units
|
||||
return my_type{d()(from, len)};
|
||||
}
|
||||
template<first_index_in_str S, last_index_in_str E>
|
||||
constexpr my_type sub(S start, E end) const noexcept {
|
||||
return my_type{get(start, end)};
|
||||
}
|
||||
/*!
|
||||
* @ru @brief Получить часть строки объектом того же типа, к которому применён метод, аналогично mid.
|
||||
* @param from - количество символов от начала строки. При превышении размера строки вернёт пустую строку.
|
||||
|
|
@ -4597,7 +4694,7 @@ public:
|
|||
template<typename R = str_piece>
|
||||
constexpr std::optional<R> strip_prefix(str_piece prefix) const {
|
||||
if (starts_with(prefix)) {
|
||||
return R{operator()(prefix.length())};
|
||||
return R{get(prefix.length(), to_end)};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
@ -4616,7 +4713,7 @@ public:
|
|||
template<typename R = str_piece>
|
||||
constexpr std::optional<R> strip_prefix_ia(str_piece prefix) const {
|
||||
if (starts_with_ia(prefix)) {
|
||||
return R{operator()(prefix.length())};
|
||||
return R{get(prefix.length(), to_end)};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
@ -4635,7 +4732,7 @@ public:
|
|||
template<typename R = str_piece>
|
||||
constexpr std::optional<R> strip_suffix(str_piece suffix) const {
|
||||
if (ends_with(suffix)) {
|
||||
return R{operator()(0, -suffix.length())};
|
||||
return R{get(0, from_end{suffix.length()})};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
@ -4654,7 +4751,7 @@ public:
|
|||
template<typename R = str_piece>
|
||||
constexpr std::optional<R> strip_suffix_ia(str_piece suffix) const {
|
||||
if (ends_with_ia(suffix)) {
|
||||
return R{operator()(0, -suffix.length())};
|
||||
return R{get(0, from_end{suffix.length()})};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
@ -4939,7 +5036,7 @@ public:
|
|||
constexpr R trimmed_prefix(str_piece prefix, size_t max_count = 0) const {
|
||||
str_piece res = *this;
|
||||
while(res.starts_with(prefix)) {
|
||||
res = res(prefix.length());
|
||||
res.remove_prefix(prefix.length());
|
||||
if (--max_count == 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -4962,7 +5059,7 @@ public:
|
|||
constexpr R trimmed_prefix_ia(str_piece prefix, size_t max_count = 0) const {
|
||||
str_piece res = *this;
|
||||
while(res.starts_with_ia(prefix)) {
|
||||
res = res(prefix.length());
|
||||
res.remove_prefix(prefix.length());
|
||||
if (--max_count == 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -4985,7 +5082,7 @@ public:
|
|||
constexpr R trimmed_suffix(str_piece suffix) const {
|
||||
str_piece res = *this;
|
||||
while(res.ends_with(suffix)) {
|
||||
res = res(0, -suffix.length());
|
||||
res.remove_suffix(suffix.length());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
@ -5005,7 +5102,7 @@ public:
|
|||
constexpr R trimmed_suffix_ia(str_piece suffix) const {
|
||||
str_piece res = *this;
|
||||
while(res.ends_with_ia(suffix)) {
|
||||
res = res(0, -suffix.length());
|
||||
res.remove_suffix(suffix.length());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
|
||||
|
||||
Version 1.8.1.
|
||||
Version 1.9.1
|
||||
|
||||
<h2>Speed up your work with strings by 2-10 times!</h2>
|
||||
|
||||
|
|
@ -325,8 +325,8 @@ function(add_simstr)
|
|||
simstr
|
||||
GIT_REPOSITORY https://github.com/orefkov/simstr.git
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_TAG tags/rel1.8.1 # Specify the desired release
|
||||
FIND_PACKAGE_ARGS NAMES simstr 1.8.1
|
||||
GIT_TAG tags/rel1.9.1# Specify the desired release
|
||||
FIND_PACKAGE_ARGS NAMES simstr 1.9.1
|
||||
)
|
||||
FetchContent_MakeAvailable(simstr)
|
||||
endfunction()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
|
||||
|
||||
Версия 1.8.1.
|
||||
Версия 1.9.1
|
||||
|
||||
<h2>Ускорь работу со строками в 2-10 раз!</h2>
|
||||
|
||||
|
|
@ -326,8 +326,8 @@ function(add_simstr)
|
|||
simstr
|
||||
GIT_REPOSITORY https://github.com/orefkov/simstr.git
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_TAG tags/rel1.8.1 # Укажите нужный релиз
|
||||
FIND_PACKAGE_ARGS NAMES simstr 1.8.1
|
||||
GIT_TAG tags/rel1.9.1# Укажите нужный релиз
|
||||
FIND_PACKAGE_ARGS NAMES simstr 1.9.1
|
||||
)
|
||||
FetchContent_MakeAvailable(simstr)
|
||||
endfunction()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* Реализация строковых функций
|
||||
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* Тесты simstr
|
||||
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
|
||||
|
|
@ -452,4 +452,22 @@ TEST(StrExpr, StartWithAnd) {
|
|||
EXPECT_TRUE("Begin[ --end"_ss.starts_with_ia_and_oneof("begin", "/*[]"_ss));
|
||||
}
|
||||
|
||||
TEST(SimStr, Get) {
|
||||
ssa testa{"test"};
|
||||
EXPECT_EQ(testa.get(1, to_end), "est");
|
||||
EXPECT_EQ(testa.get(1, 2), "es");
|
||||
EXPECT_EQ(testa.get(1, from_end(1)), "es");
|
||||
EXPECT_EQ(testa.get(1, from_end(10)), "");
|
||||
EXPECT_EQ(testa.get(from_end(3), from_end(1)), "es");
|
||||
|
||||
ssu testu{u"test"};
|
||||
EXPECT_EQ(testu.get(1, to_end), u"est");
|
||||
EXPECT_EQ(testu.get(1, 2), u"es");
|
||||
EXPECT_EQ(testu.get(from_end(3), from_end(1)), u"es");
|
||||
|
||||
ssw testw{L"test"};
|
||||
EXPECT_EQ(testw.get(1, to_end), L"est");
|
||||
EXPECT_EQ(testw.get(1, 2), L"es");
|
||||
EXPECT_EQ(testw.get(from_end(3), from_end(1)), L"es");
|
||||
}
|
||||
} // namespace simstr::tests
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* Тесты simstr
|
||||
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
|
||||
|
|
@ -274,6 +274,7 @@ TEST(SimStr, SimpleFind) {
|
|||
EXPECT_EQ("abccccc"_ss.find_last("ab"), 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(SimStr, SubPiece) {
|
||||
ssa testa{"test"};
|
||||
EXPECT_EQ(testa(1), "est");
|
||||
|
|
@ -289,39 +290,83 @@ TEST(SimStr, SubPiece) {
|
|||
EXPECT_EQ(testw(1), L"est");
|
||||
EXPECT_EQ(testw(1, 2), L"es");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(SimStr, Get) {
|
||||
ssa testa{"test"};
|
||||
EXPECT_EQ(testa.get(1, to_end), "est");
|
||||
EXPECT_EQ(testa.get(1, 2), "es");
|
||||
EXPECT_EQ(testa.get(1, from_end(1)), "es");
|
||||
EXPECT_EQ(testa.get(1, from_end(10)), "");
|
||||
|
||||
ssu testu{u"test"};
|
||||
EXPECT_EQ(testu.get(1, to_end), u"est");
|
||||
EXPECT_EQ(testu.get(1, 2), u"es");
|
||||
|
||||
ssw testw{L"test"};
|
||||
EXPECT_EQ(testw.get(1, to_end), L"est");
|
||||
EXPECT_EQ(testw.get(1, 2), L"es");
|
||||
}
|
||||
|
||||
TEST(SimStr, SimpleSubstr) {
|
||||
ssa testa = "test";
|
||||
#if 0
|
||||
EXPECT_EQ(testa.substr(1, 0), "est");
|
||||
EXPECT_EQ(testa.substr(1, 2), "es");
|
||||
EXPECT_EQ(testa.substr(0, -1), "tes");
|
||||
EXPECT_EQ(testa.substr(-2), "st");
|
||||
EXPECT_EQ(testa.substr(-3, 2), "es");
|
||||
EXPECT_EQ(testa.substr(-3, -1), "es");
|
||||
#endif
|
||||
EXPECT_EQ(testa.sub(1, to_end), "est");
|
||||
EXPECT_EQ(testa.sub(1, 2), "es");
|
||||
EXPECT_EQ(testa.sub(0, from_end(1)), "tes");
|
||||
EXPECT_EQ(testa.sub(from_end(2), to_end), "st");
|
||||
EXPECT_EQ(testa.sub(from_end(3), 2), "es");
|
||||
EXPECT_EQ(testa.sub(from_end(3), from_end(1)), "es");
|
||||
|
||||
EXPECT_EQ(testa.str_mid(1), "est");
|
||||
EXPECT_EQ(testa.str_mid(1, 0), "");
|
||||
EXPECT_EQ(testa.str_mid(1, 2), "es");
|
||||
EXPECT_EQ(testa.str_mid(2, 2), "st");
|
||||
|
||||
ssu testu = u"test";
|
||||
#if 0
|
||||
EXPECT_EQ(testu.substr(1, 0), u"est");
|
||||
EXPECT_EQ(testu.substr(1, 2), u"es");
|
||||
EXPECT_EQ(testu.substr(0, -1), u"tes");
|
||||
EXPECT_EQ(testu.substr(-2), u"st");
|
||||
EXPECT_EQ(testu.substr(-3, 2), u"es");
|
||||
EXPECT_EQ(testu.substr(-3, -1), u"es");
|
||||
#endif
|
||||
EXPECT_EQ(testu.sub(1, to_end), u"est");
|
||||
EXPECT_EQ(testu.sub(1, 2), u"es");
|
||||
EXPECT_EQ(testu.sub(0, from_end(1)), u"tes");
|
||||
EXPECT_EQ(testu.sub(from_end(2), to_end), u"st");
|
||||
EXPECT_EQ(testu.sub(from_end(3), 2), u"es");
|
||||
EXPECT_EQ(testu.sub(from_end(3), from_end(1)), u"es");
|
||||
|
||||
EXPECT_EQ(testu.str_mid(1), u"est");
|
||||
EXPECT_EQ(testu.str_mid(1, 0), u"");
|
||||
EXPECT_EQ(testu.str_mid(1, 2), u"es");
|
||||
EXPECT_EQ(testu.str_mid(2, 2), u"st");
|
||||
|
||||
ssw testw = L"test";
|
||||
#if 0
|
||||
EXPECT_EQ(testw.substr(1, 0), L"est");
|
||||
EXPECT_EQ(testw.substr(1, 2), L"es");
|
||||
EXPECT_EQ(testw.substr(0, -1), L"tes");
|
||||
EXPECT_EQ(testw.substr(-2), L"st");
|
||||
EXPECT_EQ(testw.substr(-3, 2), L"es");
|
||||
EXPECT_EQ(testw.substr(-3, -1), L"es");
|
||||
#endif
|
||||
EXPECT_EQ(testw.sub(1, to_end), L"est");
|
||||
EXPECT_EQ(testw.sub(1, 2), L"es");
|
||||
EXPECT_EQ(testw.sub(0, from_end(1)), L"tes");
|
||||
EXPECT_EQ(testw.sub(from_end(2), to_end), L"st");
|
||||
EXPECT_EQ(testw.sub(from_end(3), 2), L"es");
|
||||
EXPECT_EQ(testw.sub(from_end(3), from_end(1)), L"es");
|
||||
|
||||
EXPECT_EQ(testw.str_mid(1), L"est");
|
||||
EXPECT_EQ(testw.str_mid(1, 0), L"");
|
||||
EXPECT_EQ(testw.str_mid(1, 2), L"es");
|
||||
|
|
@ -330,7 +375,7 @@ TEST(SimStr, SimpleSubstr) {
|
|||
|
||||
TEST(SimStr, ToInt) {
|
||||
EXPECT_EQ(ssa{" 123"}.as_int<int>(), 123);
|
||||
EXPECT_EQ(ssa{" 123"}(0, -1).as_int<int>(), 12);
|
||||
EXPECT_EQ(ssa{" 123"}.get(0, from_end(1)).as_int<int>(), 12);
|
||||
EXPECT_EQ(ssa{"+123"}.as_int<int>(), 123);
|
||||
EXPECT_EQ(ssa{" -123aa"}.as_int<int>(), -123);
|
||||
EXPECT_EQ(ssa{"123"}.as_int<size_t>(), 123u);
|
||||
|
|
@ -813,7 +858,7 @@ TEST(SimStr, AssignSstring) {
|
|||
EXPECT_EQ(test = ssa{"other"}, "other");
|
||||
EXPECT_EQ(test = stringa{"trtr"_ss + 10}, "trtr10");
|
||||
EXPECT_EQ(test = "trtr"_ss + 20, "trtr20");
|
||||
EXPECT_EQ(test = test(2), "tr20");
|
||||
EXPECT_EQ(test = test.get(2, to_end), "tr20");
|
||||
EXPECT_EQ(test = lstringa<10>{"func"}, "func");
|
||||
EXPECT_EQ(test = lstringsa<10>{"func"}, "func");
|
||||
lstringsa<10> sample{15, "1234"};
|
||||
|
|
@ -942,10 +987,10 @@ TEST(SimStr, LStringAssign) {
|
|||
test = lstringa<1>{"next step"};
|
||||
EXPECT_EQ(test, "next step");
|
||||
|
||||
test = test(0);
|
||||
test = test.get(0, to_end);
|
||||
EXPECT_EQ(test, "next step");
|
||||
|
||||
test = test(1, 2);
|
||||
test = test.get(1, 2);
|
||||
EXPECT_EQ(test, "ex");
|
||||
|
||||
test = e_c(100, 'a');
|
||||
|
|
@ -1405,7 +1450,7 @@ TEST(SimStr, LStrJoinAndExpressions) {
|
|||
buffer.prepend(e_choice(test.length() > 2, eea + 99, eea + 12.1 + "asd"));
|
||||
EXPECT_EQ(buffer, "99asd<>fgh<>jkl");
|
||||
|
||||
buffer.change(2, 4, test(0, 3) + "__" + 1 + ',');
|
||||
buffer.change(2, 4, test.get(0, 3) + "__" + 1 + ',');
|
||||
EXPECT_EQ(buffer, "99>as__1,>fgh<>jkl");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* ver. 1.8.1
|
||||
* ver. 1.9.1
|
||||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||||
* Тесты simstr
|
||||
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
|
||||
|
|
|
|||
Loading…
Reference in New Issue