diff --git a/include/fmt/core.h b/include/fmt/core.h index 561c1b86..4c142816 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -26,6 +26,11 @@ #ifdef __GNUC__ # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ +# define FMT_HAS_GXX_CXX11 1 +# endif +# else +# define FMT_HAS_GXX_CXX11 0 #endif #ifdef _MSC_VER diff --git a/include/fmt/format.h b/include/fmt/format.h index e8e50871..fcd72a44 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3045,6 +3045,60 @@ constexpr fill_spec_factory fill; constexpr format_spec_factory width; constexpr format_spec_factory type; +template +struct arg_join { + It begin; + It end; + basic_string_view sep; + + arg_join(It begin, It end, basic_string_view sep) + : begin(begin), end(end), sep(sep) {} +}; + +template +struct formatter, Char>: + formatter::value_type, Char> { + template + auto format(const arg_join &value, FormatContext &ctx) { + using base = formatter::value_type, Char>; + auto it = value.begin; + auto out = ctx.begin(); + if (it != value.end) { + out = base::format(*it++, ctx); + while (it != value.end) { + out = std::copy(value.sep.begin(), value.sep.end(), out); + ctx.advance_to(out); + out = base::format(*it++, ctx); + } + } + return out; + } +}; + +template +arg_join join(It begin, It end, string_view sep) { + return arg_join(begin, end, sep); +} + +template +arg_join join(It begin, It end, wstring_view sep) { + return arg_join(begin, end, sep); +} + +#if FMT_HAS_GXX_CXX11 +template +auto join(const Range &range, string_view sep) + -> arg_join { + return join(std::begin(range), std::end(range), sep); +} + +template +auto join(const Range &range, wstring_view sep) + -> arg_join { + return join(std::begin(range), std::end(range), sep); +} +#endif + /** \rst Converts *value* to ``std::string`` using the default format for type *T*. diff --git a/test/format-test.cc b/test/format-test.cc index 5fc51dcf..29ae5f91 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -39,7 +39,7 @@ // Test that the library compiles if None is defined to 0 as done by xlib.h. #define None 0 -#include "fmt/core.h" +#include "fmt/format.h" #include "util.h" #include "mock-allocator.h" @@ -1403,6 +1403,29 @@ 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.2f); + v2.push_back(3.4f); + + EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, v1 + 3, ", "))); + EXPECT_EQ("(1)", format("({})", join(v1, v1 + 1, ", "))); + EXPECT_EQ("()", format("({})", join(v1, v1, ", "))); + EXPECT_EQ("(001, 002, 003)", format("({:03})", join(v1, 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, v1 + 3, L", "))); + EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1)); + +#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);