From a00006119fe80c6e2e66e280b44f3921e4a965b9 Mon Sep 17 00:00:00 2001 From: olivier80 Date: Wed, 8 Feb 2017 15:55:12 +0100 Subject: [PATCH] Add join argument allowing formating list of values separated by a (#466) Add join argument allowing formating list of values separated by a string. Each value is formated according the format specifier. --- fmt/format.h | 60 +++++++++++++++++++++++++++++++++++++++++++++ test/format-test.cc | 21 ++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/fmt/format.h b/fmt/format.h index 1f5fa26b0f73..ea49eef0f9e7 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3865,6 +3865,66 @@ void BasicFormatter::format(BasicCStringRef format_str) { } write(writer_, start, s); } + +template +struct ArgJoin { + It first; + It last; + BasicCStringRef sep; + + ArgJoin(It first, It last, const BasicCStringRef& sep) : + first(first), + last(last), + sep(sep) {} +}; + +template +ArgJoin join(It first, It last, const BasicCStringRef& sep) { + return ArgJoin(first, last, sep); +} + +template +ArgJoin join(It first, It last, const BasicCStringRef& sep) { + return ArgJoin(first, last, sep); +} + +#if FMT_HAS_GXX_CXX11 +template +auto join(const Range& range, const BasicCStringRef& sep) + -> ArgJoin { + return join(std::begin(range), std::end(range), sep); +} + +template +auto join(const Range& range, const BasicCStringRef& sep) + -> ArgJoin { + return join(std::begin(range), std::end(range), sep); +} +#endif + +template +void format_arg(fmt::BasicFormatter &f, + const Char *&format_str, const ArgJoin& e) { + const Char* end = format_str; + if (*end == ':') + ++end; + while (*end && *end != '}') + ++end; + if (*end != '}') + FMT_THROW(FormatError("missing '}' in format string")); + + It it = e.first; + if (it != e.last) { + const Char* save = format_str; + f.format(format_str, internal::MakeArg >(*it++)); + while (it != e.last) { + f.writer().write(e.sep); + format_str = save; + f.format(format_str, internal::MakeArg >(*it++)); + } + } + format_str = end + 1; +} } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS diff --git a/test/format-test.cc b/test/format-test.cc index 6d4a8fcd22b1..e0d3ea740e2c 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1552,6 +1552,27 @@ TEST(FormatTest, Variadic) { EXPECT_EQ(L"abc1", format(L"{}c{}", L"ab", 1)); } +TEST(FormatTest, JoinArg) { + using fmt::join; + int v1[3] = { 1, 2, 3 }; + std::vector v2; + v2.push_back(1.2); + v2.push_back(3.4); + + EXPECT_EQ("(1, 2, 3)", format("({})", join(v1 + 0, v1 + 3, ", "))); + EXPECT_EQ("(1)", format("({})", join(v1 + 0, v1 + 1, ", "))); + EXPECT_EQ("()", format("({})", join(v1 + 0, v1 + 0, ", "))); + EXPECT_EQ("(001, 002, 003)", format("({:03})", join(v1 + 0, v1 + 3, ", "))); + EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2.begin(), v2.end(), ", "))); + + EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1 + 0, v1 + 3, L", "))); + +#if FMT_HAS_GXX_CXX11 + EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", "))); + EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", "))); +#endif +} + template std::string str(const T &value) { return fmt::format("{}", value);