diff --git a/include/fmt/ostream.h b/include/fmt/ostream.h index 0c925585..5f2141fe 100644 --- a/include/fmt/ostream.h +++ b/include/fmt/ostream.h @@ -8,6 +8,7 @@ #ifndef FMT_OSTREAM_H_ #define FMT_OSTREAM_H_ +#include #include #include "format.h" @@ -50,10 +51,42 @@ struct is_streamable< (std::is_convertible::value && !std::is_enum::value)>> : std::false_type {}; +template FILE* get_file(std::basic_filebuf&) { + return nullptr; +} + +#if FMT_MSC_VER +FILE* get_file(std::filebuf& buf); + +// Generate a unique explicit instantion in every translation unit using a tag +// type in an anonymous namespace. +namespace { +struct filebuf_access_tag {}; +} // namespace +template +class filebuf_access { + friend FILE* get_file(std::filebuf& buf) { return buf.*file; } +}; +template class filebuf_access; +#endif + +inline bool write(std::filebuf& buf, fmt::string_view data) { + print(get_file(buf), data); + return true; +} +inline bool write(std::wfilebuf&, fmt::basic_string_view) { + return false; +} + // Write the content of buf to os. // It is a separate function rather than a part of vprint to simplify testing. template void write_buffer(std::basic_ostream& os, buffer& buf) { + if (auto filebuf = dynamic_cast*>(os.rdbuf())) { + if (write(*filebuf, {buf.data(), buf.size()})) return; + } const Char* buf_data = buf.data(); using unsigned_streamsize = std::make_unsigned::type; unsigned_streamsize size = buf.size();