No ranges, as they are a bit ugly to use yettags/3.7.1
@@ -1,11 +1,11 @@ | |||
/*- | |||
* Copyright 2021 Vsevolod Stakhov | |||
/* | |||
* Copyright 2023 Vsevolod Stakhov | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
@@ -53,8 +53,8 @@ constexpr auto find_map(const C &c, const K &k) -> std::optional<std::reference_ | |||
} | |||
template<typename _It> | |||
inline constexpr auto make_string_view_from_it(_It begin, _It end) | |||
template<typename It> | |||
inline constexpr auto make_string_view_from_it(It begin, It end) | |||
{ | |||
using result_type = std::string_view; | |||
@@ -91,6 +91,39 @@ inline auto string_foreach_line(const S &input, const F &functor) | |||
} | |||
} | |||
/** | |||
* Iterate over elements in a string | |||
* @tparam S | |||
* @tparam F | |||
* @param input | |||
* @param delim | |||
* @param functor | |||
* @param ignore_empty | |||
* @return | |||
*/ | |||
template<class S, class D, class F, | |||
typename std::enable_if_t<std::is_invocable_v<F, std::string_view> && std::is_constructible_v<std::string_view, S> && std::is_constructible_v<std::string_view, D>, bool> = true> | |||
inline auto string_foreach_delim(const S &input, const D &delim, const F &functor, const bool ignore_empty = true) | |||
{ | |||
size_t first = 0; | |||
auto sv_input = std::string_view{input}; | |||
auto sv_delim = std::string_view{delim}; | |||
while (first < sv_input.size()) { | |||
const auto second = sv_input.find_first_of(sv_delim, first); | |||
if (first != second || !ignore_empty) { | |||
functor(sv_input.substr(first, second - first)); | |||
} | |||
if (second == std::string_view::npos) { | |||
break; | |||
} | |||
first = second + 1; | |||
} | |||
} | |||
template<class S, typename std::enable_if_t<std::is_constructible_v<std::string_view, S>, bool> = true> | |||
inline auto string_split_on(const S &input, std::string_view::value_type chr) -> std::pair<std::string_view, std::string_view> | |||
{ |
@@ -1,11 +1,11 @@ | |||
/*- | |||
/* | |||
* Copyright 2023 Vsevolod Stakhov | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
@@ -43,4 +43,39 @@ TEST_SUITE("cxx utils") | |||
CHECK(res.second == expected.second); | |||
} | |||
} | |||
TEST_CASE("string_foreach_delim") | |||
{ | |||
std::tuple<std::string_view, std::string_view, std::pair<std::vector<std::string_view>, std::vector<std::string_view>>> cases[] = { | |||
{"test"sv, ","sv, {{"test"}, {"test"}}}, | |||
{"test,test"sv, ","sv, {{"test", "test"}, {"test", "test"}}}, | |||
{"test, test"sv, ", "sv, {{"test", "test"}, {"test", "", "test"}}}, | |||
{"test, test,,"sv, ", "sv, {{"test", "test"}, {"test", "", "test", ""}}}, | |||
}; | |||
for (const auto &c: cases) { | |||
auto res = std::vector<std::string_view>(); | |||
string_foreach_delim(std::get<0>(c), std::get<1>(c), [&](const auto &v) { | |||
res.push_back(v); | |||
}); | |||
auto compare_vec = []<class T>(const std::vector<T> &v1, const std::vector<T> &v2) { | |||
CHECK(v1.size() == v2.size()); | |||
for (size_t i = 0; i < v1.size(); ++i) { | |||
CHECK(v1[i] == v2[i]); | |||
} | |||
}; | |||
compare_vec(res, std::get<2>(c).first); | |||
res.clear(); | |||
// Perform the same test but with no skip empty | |||
string_foreach_delim( | |||
std::get<0>(c), std::get<1>(c), [&](const auto &v) { | |||
res.push_back(v); | |||
}, | |||
false); | |||
compare_vec(res, std::get<2>(c).second); | |||
} | |||
} | |||
} |