From e1b1e3bc201a2945e928b45282e8dcb46ab809d2 Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Tue, 13 Jul 2021 20:40:31 +0200 Subject: [PATCH] Add util::join function --- src/util/string_utils.hpp | 45 +++++++++++++++++++++++++++++ unittest/test_util_string_utils.cpp | 24 +++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/util/string_utils.hpp b/src/util/string_utils.hpp index 956de8fe2..aa9fccf51 100644 --- a/src/util/string_utils.hpp +++ b/src/util/string_utils.hpp @@ -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 +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 +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 +inline std::string +join(const T& container, const nonstd::string_view delimiter) +{ + return join(container.begin(), container.end(), delimiter); +} + +template +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 diff --git a/unittest/test_util_string_utils.cpp b/unittest/test_util_string_utils.cpp index 25d195656..058e3a416 100644 --- a/unittest/test_util_string_utils.cpp +++ b/unittest/test_util_string_utils.cpp @@ -20,6 +20,8 @@ #include +#include + static bool operator==( std::pair> left, @@ -48,6 +50,28 @@ TEST_CASE("util::ends_with") CHECK_FALSE(util::ends_with("x", "xy")); } +TEST_CASE("util::join") +{ + { + std::vector v; + CHECK(util::join(v, "|") == ""); + } + { + std::vector v{"a"}; + CHECK(util::join(v, "|") == "a"); + } + { + std::vector 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 v{"1", "2"}; + CHECK(util::join(v, " ") == "1 2"); + } +} + TEST_CASE("util::parse_signed") { CHECK(*util::parse_signed("0") == 0); -- 2.47.3