diff --git a/lix/libutil/strings.hh b/lix/libutil/strings.hh index 2f865c379..67238824a 100644 --- a/lix/libutil/strings.hh +++ b/lix/libutil/strings.hh @@ -5,6 +5,7 @@ #include "lix/libutil/types.hh" #include +#include namespace nix { @@ -34,7 +35,6 @@ MakeError(FormatError, Error); */ template C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r"); - /** * Concatenate the given strings with a separator between the * elements. @@ -63,6 +63,22 @@ auto concatStrings(Parts && ... parts) } +/** + * Apply a function to the `iterable`'s items and concat them with `separator`. + */ +template +std::string concatMapStringsSep(std::string_view separator, const C & iterable, F fn) +{ + boost::container::small_vector strings; + strings.reserve(iterable.size()); + for (const auto & elem : iterable) { + strings.push_back(fn(elem)); + } + return concatStringsSep(separator, strings); +} + + + /** * Add quotes around a collection of strings. */ diff --git a/tests/unit/libutil/tests.cc b/tests/unit/libutil/tests.cc index 1349be71f..00fcf8269 100644 --- a/tests/unit/libutil/tests.cc +++ b/tests/unit/libutil/tests.cc @@ -667,4 +667,43 @@ namespace nix { ASSERT_EQ(filterANSIEscapes("f๐ˆ๐ˆbรคr", true, 4), "f๐ˆ๐ˆb"); } + /* ---------------------------------------------------------------------------- + * concatMapStringsSep + * --------------------------------------------------------------------------*/ + TEST(concatMapStringsSep, empty) + { + Strings strings; + + ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), ""); + } + + TEST(concatMapStringsSep, justOne) + { + Strings strings; + strings.push_back("this"); + + ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), "this"); + } + + TEST(concatMapStringsSep, two) + { + Strings strings; + strings.push_back("this"); + strings.push_back("that"); + + ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), "this,that"); + } + + TEST(concatMapStringsSep, map) + { + std::map strings; + strings["this"] = "that"; + strings["1"] = "one"; + + ASSERT_EQ( + concatMapStringsSep( + ", ", strings, [](const std::pair & s) { return s.first + " -> " + s.second; }), + "1 -> one, this -> that"); + } + }