-/*-
- * 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,
}
-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;
}
}
+/**
+ * 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>
{
-/*-
+/*
* 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,
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);
+ }
+ }
}
\ No newline at end of file