From 2d931b14975624af838b54d2bcc79a0a78e888b7 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 24 Jun 2022 09:26:24 -0700 Subject: [PATCH] Add fmt::streamed --- include/fmt/ostream.h | 23 +++++++++++++++++++---- test/ostream-test.cc | 31 +++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/include/fmt/ostream.h b/include/fmt/ostream.h index f58453dd..3292b0ed 100644 --- a/include/fmt/ostream.h +++ b/include/fmt/ostream.h @@ -122,6 +122,9 @@ void format_value(buffer& buf, const T& value, output << value; output.exceptions(std::ios_base::failbit | std::ios_base::badbit); } + +template struct streamed_view { const T& value; }; + } // namespace detail // Formats an object of type T that has an overloaded ostream operator<<. @@ -139,6 +142,20 @@ struct basic_ostream_formatter : formatter, Char> { using ostream_formatter = basic_ostream_formatter; +template +struct formatter> : ostream_formatter { + template + auto format(detail::streamed_view view, + basic_format_context& ctx) const -> OutputIt { + return ostream_formatter::format(view.value, ctx); + } +}; + +template +auto streamed(const T& value) -> detail::streamed_view { + return {value}; +} + namespace detail { // Formats an object of type T that has an overloaded ostream operator<<. @@ -150,8 +167,7 @@ struct fallback_formatter::value>> } // namespace detail -FMT_MODULE_EXPORT -template +FMT_MODULE_EXPORT template void vprint(std::basic_ostream& os, basic_string_view> format_str, basic_format_args>> args) { @@ -169,8 +185,7 @@ void vprint(std::basic_ostream& os, fmt::print(cerr, "Don't {}!", "panic"); \endrst */ -FMT_MODULE_EXPORT -template +FMT_MODULE_EXPORT template void print(std::ostream& os, format_string fmt, T&&... args) { vprint(os, fmt, fmt::make_format_args(args...)); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 6a95b9ce..f88ae936 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -32,12 +32,12 @@ template <> struct formatter : formatter { #include "gtest-extra.h" #include "util.h" -std::ostream& operator<<(std::ostream& os, const date& d) { +auto operator<<(std::ostream& os, const date& d) -> std::ostream& { os << d.year() << '-' << d.month() << '-' << d.day(); return os; } -std::wostream& operator<<(std::wostream& os, const date& d) { +auto operator<<(std::wostream& os, const date& d) -> std::wostream& { os << d.year() << L'-' << d.month() << L'-' << d.day(); return os; } @@ -49,14 +49,16 @@ template type_with_comma_op operator<<(T&, const date&); enum streamable_enum {}; -std::ostream& operator<<(std::ostream& os, streamable_enum) { +auto operator<<(std::ostream& os, streamable_enum) -> std::ostream& { return os << "streamable_enum"; } enum unstreamable_enum {}; struct empty_test {}; -std::ostream& operator<<(std::ostream& os, empty_test) { return os << ""; } +auto operator<<(std::ostream& os, empty_test) -> std::ostream& { + return os << ""; +} namespace fmt { template <> struct formatter : ostream_formatter {}; @@ -130,7 +132,7 @@ TEST(ostream_test, write_to_ostream_max_size) { struct mock_streambuf : std::streambuf { MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n)); - std::streamsize xsputn(const char* s, std::streamsize n) override { + auto xsputn(const char* s, std::streamsize n) -> std::streamsize override { const void* v = s; return xsputn(v, n); } @@ -176,7 +178,7 @@ TEST(ostream_test, constexpr_string) { namespace fmt_test { struct abc {}; -template Output& operator<<(Output& out, abc) { +template auto operator<<(Output& out, abc) -> Output& { return out << "abc"; } } // namespace fmt_test @@ -184,7 +186,7 @@ template Output& operator<<(Output& out, abc) { template struct test_template {}; template -std::ostream& operator<<(std::ostream& os, test_template) { +auto operator<<(std::ostream& os, test_template) -> std::ostream& { return os << 1; } @@ -282,7 +284,7 @@ TEST(ostream_test, range) { struct abstract { virtual ~abstract() = default; virtual void f() = 0; - friend std::ostream& operator<<(std::ostream& os, const abstract&) { + friend auto operator<<(std::ostream& os, const abstract&) -> std::ostream& { return os; } }; @@ -300,6 +302,19 @@ TEST(ostream_test, is_formattable) { EXPECT_TRUE(fmt::is_formattable>()); } +struct streamable_and_unformattable {}; + +auto operator<<(std::ostream& os, streamable_and_unformattable) + -> std::ostream& { + return os << "foo"; +} + +TEST(ostream_test, streamed) { + EXPECT_FALSE(fmt::is_formattable()); + EXPECT_EQ(fmt::format("{}", fmt::streamed(streamable_and_unformattable())), + "foo"); +} + TEST(ostream_test, closed_ofstream) { std::ofstream ofs; fmt::print(ofs, "discard");