diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -332,6 +332,7 @@ util/moneystr.cpp util/settings.cpp util/strencodings.cpp + util/string.cpp util/system.cpp util/threadnames.cpp util/time.cpp diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -246,6 +246,7 @@ util/moneystr.h \ util/system.h \ util/settings.h \ + util/string.h \ util/threadnames.h \ util/time.h \ util/translation.h \ @@ -552,6 +553,7 @@ util/moneystr.cpp \ util/settings.cpp \ util/strencodings.cpp \ + util/string.cpp \ util/threadnames.cpp \ util/time.cpp \ util/url.cpp \ diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -646,13 +647,9 @@ } case Type::OBJ: case Type::OBJ_USER_KEYS: { - std::string res; - for (size_t i = 0; i < m_inner.size();) { - res += m_inner[i].ToStringObj(oneline); - if (++i < m_inner.size()) { - res += ","; - } - } + const std::string res = Join(m_inner, ",", [&](const RPCArg &i) { + return i.ToStringObj(oneline); + }); if (m_type == Type::OBJ) { return "{" + res + "}"; } else { diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -155,6 +156,20 @@ "1feae06279a60939e028a8d65c10b73071a6f16719274855feb0fd8a6704"); } +BOOST_AUTO_TEST_CASE(util_Join) { + // Normal version + BOOST_CHECK_EQUAL(Join({}, ", "), ""); + BOOST_CHECK_EQUAL(Join({"foo"}, ", "), "foo"); + BOOST_CHECK_EQUAL(Join({"foo", "bar"}, ", "), "foo, bar"); + + // Version with unary operator + const auto op_upper = [](const std::string &s) { return ToUpper(s); }; + BOOST_CHECK_EQUAL(Join({}, ", ", op_upper), ""); + BOOST_CHECK_EQUAL(Join({"foo"}, ", ", op_upper), "FOO"); + BOOST_CHECK_EQUAL(Join({"foo", "bar"}, ", ", op_upper), + "FOO, BAR"); +} + BOOST_AUTO_TEST_CASE(util_FormatParseISO8601DateTime) { BOOST_CHECK_EQUAL(FormatISO8601DateTime(1317425777), "2011-09-30T23:36:17Z"); diff --git a/src/util/string.h b/src/util/string.h new file mode 100644 --- /dev/null +++ b/src/util/string.h @@ -0,0 +1,37 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_STRING_H +#define BITCOIN_UTIL_STRING_H + +#include +#include +#include + +/** + * Join a list of items + * + * @param list The list to join + * @param separator The separator + * @param unary_op Apply this operator to each item in the list + */ +template +std::string Join(const std::vector &list, const std::string &separator, + UnaryOp unary_op) { + std::string ret; + for (size_t i = 0; i < list.size(); ++i) { + if (i > 0) { + ret += separator; + } + ret += unary_op(list.at(i)); + } + return ret; +} + +inline std::string Join(const std::vector &list, + const std::string &separator) { + return Join(list, separator, [](const std::string &i) { return i; }); +} + +#endif // BITCOIN_UTIL_STRING_H diff --git a/src/util/string.cpp b/src/util/string.cpp new file mode 100644 --- /dev/null +++ b/src/util/string.cpp @@ -0,0 +1,5 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include