From 322736d3bb7be17ebb7e56ba265c300e276f43a1 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 15 Jan 2018 12:46:44 -0800 Subject: [PATCH] Add support for arbitrary output iterators --- include/fmt/core.h | 35 +++++++++++++++++++++-------------- include/fmt/format.h | 21 +++++++++++++-------- test/format-test.cc | 5 ++++- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 939da9fd..24e2a718 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -832,25 +832,32 @@ inline Container &get_container(std::back_insert_iterator it) { } } // namespace internal -// A range where begin() returns back_insert_iterator. -template -class back_insert_range { +template +class output_range { private: - Container &container_; + OutputIt it_; + + // Unused yet. + using sentinel = void; + sentinel end() const; public: - using iterator = std::back_insert_iterator; + using value_type = T; + + explicit output_range(OutputIt it): it_(it) {} + OutputIt begin() const { return it_; } +}; + +// A range where begin() returns back_insert_iterator. +template +class back_insert_range: + public output_range> { + using base = output_range>; + public: using value_type = typename Container::value_type; - struct sentinel { - friend bool operator!=(sentinel, iterator) { return false; } - friend bool operator!=(iterator, sentinel) { return false; } - }; - - back_insert_range(Container &c) : container_(c) {} - - iterator begin() const { return std::back_inserter(container_); } - sentinel end() const { return sentinel(); } + using base::base; + back_insert_range(Container &c): base(std::back_inserter(c)) {} }; // Formatting context. diff --git a/include/fmt/format.h b/include/fmt/format.h index 27a39072..323d6725 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2023,7 +2023,7 @@ class arg_formatter: public internal::arg_formatter_base { \endrst */ arg_formatter(basic_context &ctx, format_specs &spec) - : base(Range(internal::get_container(ctx.begin())), spec), ctx_(ctx) {} + : base(Range(ctx.begin()), spec), ctx_(ctx) {} using base::operator(); @@ -3036,6 +3036,13 @@ inline void format_to(wmemory_buffer &buf, wstring_view format_str, vformat_to(buf, format_str, make_args(args...)); } +template +typename std::enable_if::value>::type + vformat_to(std::back_insert_iterator out, + string_view format_str, + basic_format_args args) { +} + template inline typename std::enable_if::value>::type format_to(std::back_insert_iterator out, @@ -3043,15 +3050,13 @@ inline typename std::enable_if::value>::type vformat_to(out, format_str, make_args(args...)); } -template -inline typename std::enable_if::value>::type - format_to(std::back_insert_iterator out, - string_view format_str, const Args & ... args) { - using range = back_insert_range; +template +inline void format_to(OutputIt out, string_view format_str, + const Args & ... args) { + using range = output_range; auto store = make_args>(args...); do_vformat_to>( - range(internal::get_container(out)), format_str, - basic_format_args>(store)); + range(out), format_str, basic_format_args>(store)); } inline std::string vformat(string_view format_str, format_args args) { diff --git a/test/format-test.cc b/test/format-test.cc index b3c5f549..6eccd41a 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1910,8 +1910,11 @@ TEST(FormatTest, ToString) { EXPECT_EQ("42", fmt::to_string(42)); } -TEST(WriterTest, NoncontiguousIterator) { +TEST(WriterTest, OutputIterators) { std::list out; fmt::format_to(std::back_inserter(out), "{}", 42); EXPECT_EQ("42", std::string(out.begin(), out.end())); + std::stringstream s; + fmt::format_to(std::ostream_iterator(s), "{}", 42); + EXPECT_EQ("42", s.str()); }