diff --git a/include/fmt/core.h b/include/fmt/core.h index 24e2a718..21be70e0 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -929,6 +929,8 @@ class arg_store { arg_store(const Args &... args) : data_{internal::make_arg(args)...} {} + basic_format_args operator*() const { return *this; } + const value_type *data() const { return data_; } }; diff --git a/include/fmt/format.h b/include/fmt/format.h index 323d6725..0db5dd5d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -619,6 +619,33 @@ constexpr const Char *pointer_from(null_terminating_iterator it) { return it.ptr_; } +// An output iterator that counts the number of objects written to it and +// discards them. +template +class counting_iterator { + private: + std::size_t& count_; + mutable T blackhole_; + + public: + explicit counting_iterator(std::size_t &count): count_(count) {} + counting_iterator(const counting_iterator &other): count_(other.count_) {} + + counting_iterator& operator=(const counting_iterator &other) { + count_ = other.count_; + return *this; + } + + counting_iterator& operator++() { + ++count_; + return *this; + } + + counting_iterator operator++(int) { return ++*this; } + + T &operator*() const { return blackhole_; } +}; + // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template @@ -3036,11 +3063,23 @@ 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 +using context_t = basic_context>; + +template +using format_args_t = basic_format_args>; + +template +inline void vformat_to(OutputIt out, string_view format_str, + format_args_t args) { + using range = output_range; + do_vformat_to>(range(out), format_str, args); +} + +template +inline void format_to(OutputIt out, string_view format_str, + const Args & ... args) { + vformat_to(out, format_str, *make_args>(args...)); } template @@ -3050,15 +3089,6 @@ inline typename std::enable_if::value>::type vformat_to(out, format_str, make_args(args...)); } -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(out), format_str, basic_format_args>(store)); -} - inline std::string vformat(string_view format_str, format_args args) { memory_buffer buffer; vformat_to(buffer, format_str, args); @@ -3081,6 +3111,15 @@ inline typename std::enable_if< (void)invalid_format; return vformat(format_str.value(), make_args(args...)); } + +// Counts the number of characters in the output of format(format_str, args...). +template +inline std::size_t count(string_view format_str, const Args & ... args) { + std::size_t size = 0; + internal::counting_iterator it(size); + format_to(it, format_str, args...); + return size; +} } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS diff --git a/test/format-test.cc b/test/format-test.cc index 6eccd41a..5fc51dcf 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1910,7 +1910,7 @@ TEST(FormatTest, ToString) { EXPECT_EQ("42", fmt::to_string(42)); } -TEST(WriterTest, OutputIterators) { +TEST(FormatTest, OutputIterators) { std::list out; fmt::format_to(std::back_inserter(out), "{}", 42); EXPECT_EQ("42", std::string(out.begin(), out.end())); @@ -1918,3 +1918,7 @@ TEST(WriterTest, OutputIterators) { fmt::format_to(std::ostream_iterator(s), "{}", 42); EXPECT_EQ("42", s.str()); } + +TEST(FormatTest, OutputSize) { + EXPECT_EQ(2, fmt::count("{}", 42)); +}