diff --git a/src/util/string_utils.h b/src/util/string_utils.h index 4e2679f13d3..6c0dd5241c3 100644 --- a/src/util/string_utils.h +++ b/src/util/string_utils.h @@ -47,26 +47,51 @@ std::string trim_from_last_delimiter( /// \param b: Iterator pointing to first item to print /// \param e: Iterator pointing past last item to print /// \param delimiter: Object to print between each item in the iterator range +/// \param transform_func: Transform to apply to the value returned by the +/// iterator /// \return A reference to the ostream that was passed in -template +template < + typename Stream, + typename It, + typename Delimiter, + typename TransformFunc> Stream &join_strings( - Stream &os, + Stream &&os, const It b, const It e, - const Delimiter &delimiter) + const Delimiter &delimiter, + TransformFunc &&transform_func) { if(b==e) { return os; } - os << *b; + os << transform_func(*b); for(auto it=std::next(b); it!=e; ++it) { - os << delimiter << *it; + os << delimiter << transform_func(*it); } return os; } +/// Prints items to an stream, separated by a constant delimiter +/// \tparam It: An iterator type +/// \tparam Delimiter: A delimiter type which supports printing to ostreams +/// \param os: An ostream to write to +/// \param b: Iterator pointing to first item to print +/// \param e: Iterator pointing past last item to print +/// \param delimiter: Object to print between each item in the iterator range +/// \return A reference to the ostream that was passed in +template +Stream & +join_strings(Stream &&os, const It b, const It e, const Delimiter &delimiter) +{ + using value_type = decltype(*b); + // Call auxiliary function with identity function + return join_strings( + os, b, e, delimiter, [](const value_type &x) { return x; }); +} + /// Generic escaping of strings; this is not meant to be a particular /// programming language. std::string escape(const std::string &); diff --git a/unit/Makefile b/unit/Makefile index d6a49237bf7..15bcb89d5c4 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -69,7 +69,8 @@ SRC += analyses/ai/ai.cpp \ util/simplify_expr.cpp \ util/small_map.cpp \ util/small_shared_two_way_ptr.cpp \ - util/std_expr.cpp \ + util/std_expr.cpp \ + util/string_utils/join_string.cpp \ util/string_utils/split_string.cpp \ util/string_utils/strip_string.cpp \ util/symbol_table.cpp \ diff --git a/unit/util/string_utils/join_string.cpp b/unit/util/string_utils/join_string.cpp new file mode 100644 index 00000000000..30a30f59424 --- /dev/null +++ b/unit/util/string_utils/join_string.cpp @@ -0,0 +1,44 @@ +/*******************************************************************\ + +Module: Unit tests of join_string + +Author: Diffblue Ltd. + +\*******************************************************************/ + +/// \file +/// join_string Unit Tests + +#include +#include +#include + +#include +#include + +TEST_CASE( + "join_strings() should apply the function argument its passed to the " + "elements of the container", + "[core][utils][string_utils][join_strings]") +{ + std::vector vec{1, 2, 3}; + auto result = join_strings( + std::ostringstream(), + vec.begin(), + vec.end(), + "-", + [](int x) { return std::to_string(x + 1); }) + .str(); + REQUIRE(result == "2-3-4"); +} + +TEST_CASE( + "join_strings() when passed no function argument should apply the default " + "identity function to the elements of the container", + "[core][utils][string_utils][join_strings]") +{ + std::vector vec{1, 2, 3}; + auto result = + join_strings(std::ostringstream(), vec.begin(), vec.end(), ",").str(); + REQUIRE(result == "1,2,3"); +}