Add fmt::streamed

This commit is contained in:
Victor Zverovich
2022-06-24 09:26:24 -07:00
parent 0506a5733d
commit 2d931b1497
2 changed files with 42 additions and 12 deletions

View File

@@ -122,6 +122,9 @@ void format_value(buffer<Char>& buf, const T& value,
output << value; output << value;
output.exceptions(std::ios_base::failbit | std::ios_base::badbit); output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
} }
template <typename T> struct streamed_view { const T& value; };
} // namespace detail } // namespace detail
// Formats an object of type T that has an overloaded ostream operator<<. // Formats an object of type T that has an overloaded ostream operator<<.
@@ -139,6 +142,20 @@ struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
using ostream_formatter = basic_ostream_formatter<char>; using ostream_formatter = basic_ostream_formatter<char>;
template <typename T>
struct formatter<detail::streamed_view<T>> : ostream_formatter {
template <typename OutputIt>
auto format(detail::streamed_view<T> view,
basic_format_context<OutputIt, char>& ctx) const -> OutputIt {
return ostream_formatter::format(view.value, ctx);
}
};
template <typename T>
auto streamed(const T& value) -> detail::streamed_view<T> {
return {value};
}
namespace detail { namespace detail {
// Formats an object of type T that has an overloaded ostream operator<<. // Formats an object of type T that has an overloaded ostream operator<<.
@@ -150,8 +167,7 @@ struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
} // namespace detail } // namespace detail
FMT_MODULE_EXPORT FMT_MODULE_EXPORT template <typename Char>
template <typename Char>
void vprint(std::basic_ostream<Char>& os, void vprint(std::basic_ostream<Char>& os,
basic_string_view<type_identity_t<Char>> format_str, basic_string_view<type_identity_t<Char>> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) { basic_format_args<buffer_context<type_identity_t<Char>>> args) {
@@ -169,8 +185,7 @@ void vprint(std::basic_ostream<Char>& os,
fmt::print(cerr, "Don't {}!", "panic"); fmt::print(cerr, "Don't {}!", "panic");
\endrst \endrst
*/ */
FMT_MODULE_EXPORT FMT_MODULE_EXPORT template <typename... T>
template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... args) { void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
vprint(os, fmt, fmt::make_format_args(args...)); vprint(os, fmt, fmt::make_format_args(args...));
} }

View File

@@ -32,12 +32,12 @@ template <> struct formatter<test> : formatter<int> {
#include "gtest-extra.h" #include "gtest-extra.h"
#include "util.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(); os << d.year() << '-' << d.month() << '-' << d.day();
return os; 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(); os << d.year() << L'-' << d.month() << L'-' << d.day();
return os; return os;
} }
@@ -49,14 +49,16 @@ template <typename T> type_with_comma_op operator<<(T&, const date&);
enum streamable_enum {}; enum streamable_enum {};
std::ostream& operator<<(std::ostream& os, streamable_enum) { auto operator<<(std::ostream& os, streamable_enum) -> std::ostream& {
return os << "streamable_enum"; return os << "streamable_enum";
} }
enum unstreamable_enum {}; enum unstreamable_enum {};
struct empty_test {}; 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 { namespace fmt {
template <> struct formatter<test_string> : ostream_formatter {}; template <> struct formatter<test_string> : ostream_formatter {};
@@ -130,7 +132,7 @@ TEST(ostream_test, write_to_ostream_max_size) {
struct mock_streambuf : std::streambuf { struct mock_streambuf : std::streambuf {
MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n)); 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; const void* v = s;
return xsputn(v, n); return xsputn(v, n);
} }
@@ -176,7 +178,7 @@ TEST(ostream_test, constexpr_string) {
namespace fmt_test { namespace fmt_test {
struct abc {}; struct abc {};
template <typename Output> Output& operator<<(Output& out, abc) { template <typename Output> auto operator<<(Output& out, abc) -> Output& {
return out << "abc"; return out << "abc";
} }
} // namespace fmt_test } // namespace fmt_test
@@ -184,7 +186,7 @@ template <typename Output> Output& operator<<(Output& out, abc) {
template <typename T> struct test_template {}; template <typename T> struct test_template {};
template <typename T> template <typename T>
std::ostream& operator<<(std::ostream& os, test_template<T>) { auto operator<<(std::ostream& os, test_template<T>) -> std::ostream& {
return os << 1; return os << 1;
} }
@@ -282,7 +284,7 @@ TEST(ostream_test, range) {
struct abstract { struct abstract {
virtual ~abstract() = default; virtual ~abstract() = default;
virtual void f() = 0; 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; return os;
} }
}; };
@@ -300,6 +302,19 @@ TEST(ostream_test, is_formattable) {
EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>()); EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>());
} }
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<streamable_and_unformattable>());
EXPECT_EQ(fmt::format("{}", fmt::streamed(streamable_and_unformattable())),
"foo");
}
TEST(ostream_test, closed_ofstream) { TEST(ostream_test, closed_ofstream) {
std::ofstream ofs; std::ofstream ofs;
fmt::print(ofs, "discard"); fmt::print(ofs, "discard");