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.exceptions(std::ios_base::failbit | std::ios_base::badbit);
}
template <typename T> 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<basic_string_view<Char>, 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 {
// 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
FMT_MODULE_EXPORT
template <typename Char>
FMT_MODULE_EXPORT template <typename Char>
void vprint(std::basic_ostream<Char>& os,
basic_string_view<type_identity_t<Char>> format_str,
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");
\endrst
*/
FMT_MODULE_EXPORT
template <typename... T>
FMT_MODULE_EXPORT template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... 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 "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 <typename T> 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<test_string> : 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 <typename Output> Output& operator<<(Output& out, abc) {
template <typename Output> auto operator<<(Output& out, abc) -> Output& {
return out << "abc";
}
} // namespace fmt_test
@ -184,7 +186,7 @@ template <typename Output> Output& operator<<(Output& out, abc) {
template <typename T> struct test_template {};
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;
}
@ -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<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) {
std::ofstream ofs;
fmt::print(ofs, "discard");