Browse Source

[Feature] Add utility to split string like stuff for C++ code

No ranges, as they are a bit ugly to use yet
tags/3.7.1
Vsevolod Stakhov 9 months ago
parent
commit
a0987ff8ad
No account linked to committer's email address
2 changed files with 75 additions and 7 deletions
  1. 38
    5
      src/libutil/cxx/util.hxx
  2. 37
    2
      src/libutil/cxx/util_tests.cxx

+ 38
- 5
src/libutil/cxx/util.hxx View File

@@ -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>
{

+ 37
- 2
src/libutil/cxx/util_tests.cxx View File

@@ -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);
}
}
}

Loading…
Cancel
Save