]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add util::join function
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 13 Jul 2021 18:40:31 +0000 (20:40 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Mon, 19 Jul 2021 06:47:19 +0000 (08:47 +0200)
src/util/string_utils.hpp
unittest/test_util_string_utils.cpp

index 956de8fe2b55d7edb3b6c23b33f735e97f4433f4..aa9fccf51e274285b0e1bd8550b940928fbf84ae 100644 (file)
@@ -35,6 +35,18 @@ namespace util {
 // Return true if `suffix` is a suffix of `string`.
 bool ends_with(nonstd::string_view string, nonstd::string_view suffix);
 
+// Join stringified elements of `container` delimited by `delimiter` into a
+// string. There must exist an `std::string to_string(T::value_type)` function.
+template<typename T>
+std::string join(const T& container, const nonstd::string_view delimiter);
+
+// Join stringified elements between input iterators `begin` and `end` delimited
+// by `delimiter` into a string. There must exist an `std::string
+// to_string(T::value_type)` function.
+template<typename T>
+std::string
+join(const T& begin, const T& end, const nonstd::string_view delimiter);
+
 // Parse a string into a signed integer.
 //
 // Return an error string if `value` cannot be parsed as an int64_t or if the
@@ -83,6 +95,10 @@ bool starts_with(nonstd::string_view string, nonstd::string_view prefix);
 // Strip whitespace from left and right side of a string.
 [[nodiscard]] std::string strip_whitespace(nonstd::string_view string);
 
+// Convert `string` to a string. This function is used when joining
+// `std::string`s with `util::join`.
+std::string to_string(const std::string& string);
+
 // --- Inline implementations ---
 
 inline bool
@@ -90,6 +106,28 @@ ends_with(const nonstd::string_view string, const nonstd::string_view suffix)
 {
   return string.ends_with(suffix);
 }
+
+template<typename T>
+inline std::string
+join(const T& container, const nonstd::string_view delimiter)
+{
+  return join(container.begin(), container.end(), delimiter);
+}
+
+template<typename T>
+inline std::string
+join(const T& begin, const T& end, const nonstd::string_view delimiter)
+{
+  std::string result;
+  for (auto it = begin; it != end; ++it) {
+    if (it != begin) {
+      result.append(delimiter.data(), delimiter.length());
+    }
+    result += to_string(*it);
+  }
+  return result;
+}
+
 inline bool
 starts_with(const char* const string, const nonstd::string_view prefix)
 {
@@ -104,4 +142,11 @@ starts_with(const nonstd::string_view string, const nonstd::string_view prefix)
   return string.starts_with(prefix);
 }
 
+// Convert `string` to `string`. This is used by util::join.
+inline std::string
+to_string(const std::string& string)
+{
+  return string;
+}
+
 } // namespace util
index 25d195656f375f0e8c67c7c6783329b81c3b42cb..058e3a4163e9ea57ed874dc4e1a68eae291d25d6 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <third_party/doctest.h>
 
+#include <vector>
+
 static bool
 operator==(
   std::pair<nonstd::string_view, nonstd::optional<nonstd::string_view>> left,
@@ -48,6 +50,28 @@ TEST_CASE("util::ends_with")
   CHECK_FALSE(util::ends_with("x", "xy"));
 }
 
+TEST_CASE("util::join")
+{
+  {
+    std::vector<std::string> v;
+    CHECK(util::join(v, "|") == "");
+  }
+  {
+    std::vector<std::string> v{"a"};
+    CHECK(util::join(v, "|") == "a");
+  }
+  {
+    std::vector<std::string> v{"a", " b ", "c|"};
+    CHECK(util::join(v, "|") == "a| b |c|");
+    CHECK(util::join(v.begin(), v.end(), "|") == "a| b |c|");
+    CHECK(util::join(v.begin() + 1, v.end(), "|") == " b |c|");
+  }
+  {
+    std::vector<nonstd::string_view> v{"1", "2"};
+    CHECK(util::join(v, " ") == "1 2");
+  }
+}
+
 TEST_CASE("util::parse_signed")
 {
   CHECK(*util::parse_signed("0") == 0);