From: Thomas Otto Date: Tue, 3 Mar 2020 22:14:05 +0000 (+0100) Subject: Util: Add split_into_views/split_into_strings functions X-Git-Tag: v4.0~547^2~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4b69de89a41dbf4e6ebcf7f24c070191da51fb68;p=thirdparty%2Fccache.git Util: Add split_into_views/split_into_strings functions --- diff --git a/src/Util.cpp b/src/Util.cpp index 5a2adb655..3ff0bac37 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -89,6 +89,31 @@ path_max(const char* path) #endif } +template +std::vector +split_at(string_view input, const char* separators) +{ + assert(separators != nullptr && separators[0] != '\0'); + + std::vector result; + + size_t start = 0; + while (start < input.size()) { + size_t end = input.find_first_of(separators, start); + + if (end == string_view::npos) { + result.emplace_back(input.data() + start, input.size() - start); + break; + } else if (start != end) { + result.emplace_back(input.data() + start, end - start); + } + + start = end + 1; + } + + return result; +} + } // namespace namespace Util { @@ -538,6 +563,18 @@ remove_extension(string_view path) return path.substr(0, path.length() - get_extension(path).length()); } +std::vector +split_into_views(string_view s, const char* separators) +{ + return split_at(s, separators); +} + +std::vector +split_into_strings(string_view s, const char* separators) +{ + return split_at(s, separators); +} + bool starts_with(string_view string, string_view prefix) { diff --git a/src/Util.hpp b/src/Util.hpp index 62f290baf..f1dbd9418 100644 --- a/src/Util.hpp +++ b/src/Util.hpp @@ -239,6 +239,16 @@ std::string real_path(const std::string& path, // extension as determined by `get_extension()`. nonstd::string_view remove_extension(nonstd::string_view path); +// Split `input` into words at any of the characters listed in `separators`. +// These words are a view into `input`; empty words are omitted. `separators` +// must neither be the empty string nor a nullptr. +std::vector split_into_views(nonstd::string_view input, + const char* separators); + +// Same as `split_into_views` but the words are copied from `input`. +std::vector split_into_strings(nonstd::string_view input, + const char* separators); + // Return true if prefix is a prefix of string. bool starts_with(nonstd::string_view string, nonstd::string_view prefix); diff --git a/unittest/test_Util.cpp b/unittest/test_Util.cpp index 0b0e9a0d0..3fc4d952c 100644 --- a/unittest/test_Util.cpp +++ b/unittest/test_Util.cpp @@ -456,6 +456,88 @@ TEST_CASE("Util::remove_extension") CHECK(Util::remove_extension("/foo/bar/f.abc.txt") == "/foo/bar/f.abc"); } +TEST_CASE("Util::split_into_views") +{ + { + CHECK(Util::split_into_views("", "/").empty()); + } + { + CHECK(Util::split_into_views("///", "/").empty()); + } + { + auto s = Util::split_into_views("a/b", "/"); + REQUIRE(s.size() == 2); + CHECK(s.at(0) == "a"); + CHECK(s.at(1) == "b"); + } + { + auto s = Util::split_into_views("a/b", "x"); + REQUIRE(s.size() == 1); + CHECK(s.at(0) == "a/b"); + } + { + auto s = Util::split_into_views("a/b:c", "/:"); + REQUIRE(s.size() == 3); + CHECK(s.at(0) == "a"); + CHECK(s.at(1) == "b"); + CHECK(s.at(2) == "c"); + } + { + auto s = Util::split_into_views(":a//b..:.c/:/.", "/:."); + REQUIRE(s.size() == 3); + CHECK(s.at(0) == "a"); + CHECK(s.at(1) == "b"); + CHECK(s.at(2) == "c"); + } + { + auto s = Util::split_into_views(".0.1.2.3.4.5.6.7.8.9.", "/:.+_abcdef"); + REQUIRE(s.size() == 10); + CHECK(s.at(0) == "0"); + CHECK(s.at(9) == "9"); + } +} + +TEST_CASE("Util::split_into_strings") +{ + { + CHECK(Util::split_into_strings("", "/").empty()); + } + { + CHECK(Util::split_into_strings("///", "/").empty()); + } + { + auto s = Util::split_into_strings("a/b", "/"); + REQUIRE(s.size() == 2); + CHECK(s.at(0) == "a"); + CHECK(s.at(1) == "b"); + } + { + auto s = Util::split_into_strings("a/b", "x"); + REQUIRE(s.size() == 1); + CHECK(s.at(0) == "a/b"); + } + { + auto s = Util::split_into_strings("a/b:c", "/:"); + REQUIRE(s.size() == 3); + CHECK(s.at(0) == "a"); + CHECK(s.at(1) == "b"); + CHECK(s.at(2) == "c"); + } + { + auto s = Util::split_into_strings(":a//b..:.c/:/.", "/:."); + REQUIRE(s.size() == 3); + CHECK(s.at(0) == "a"); + CHECK(s.at(1) == "b"); + CHECK(s.at(2) == "c"); + } + { + auto s = Util::split_into_strings(".0.1.2.3.4.5.6.7.8.9.", "/:.+_abcdef"); + REQUIRE(s.size() == 10); + CHECK(s.at(0) == "0"); + CHECK(s.at(9) == "9"); + } +} + TEST_CASE("Util::starts_with") { CHECK(Util::starts_with("", ""));