// Formatting library for C++ - std::ostream support // // Copyright (c) 2012 - 2016, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #ifndef FMT_OSTREAM_H_ #define FMT_OSTREAM_H_ #include "format.h" #include FMT_BEGIN_NAMESPACE namespace internal { template class formatbuf : public std::basic_streambuf { private: typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::traits_type traits_type; basic_buffer &buffer_; public: formatbuf(basic_buffer &buffer) : buffer_(buffer) {} protected: // The put-area is actually always empty. This makes the implementation // simpler and has the advantage that the streambuf and the buffer are always // in sync and sputc never writes into uninitialized memory. The obvious // disadvantage is that each call to sputc always results in a (virtual) call // to overflow. There is no disadvantage here for sputn since this always // results in a call to xsputn. int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { if (!traits_type::eq_int_type(ch, traits_type::eof())) buffer_.push_back(static_cast(ch)); return ch; } std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { buffer_.append(s, s + count); return count; } }; template struct test_stream : std::basic_ostream { private: struct null; // Hide all operator<< from std::basic_ostream. void operator<<(null); }; // Checks if T has a user-defined operator<< (e.g. not a member of std::ostream). template class is_streamable { private: template static decltype( internal::declval&>() << internal::declval(), std::true_type()) test(int); template static std::false_type test(...); typedef decltype(test(0)) result; public: // std::string operator<< is not considered user-defined because we handle strings // specially. static const bool value = result::value && !std::is_same::value; }; // Disable conversion to int if T has an overloaded operator<< which is a free // function (not a member of std::ostream). template class convert_to_int { public: static const bool value = convert_to_int::value && !is_streamable::value; }; // Write the content of buf to os. template void write(std::basic_ostream &os, basic_buffer &buf) { const Char *data = buf.data(); typedef std::make_unsigned::type UnsignedStreamSize; UnsignedStreamSize size = buf.size(); UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits::max)()); do { UnsignedStreamSize n = size <= max_size ? size : max_size; os.write(data, static_cast(n)); data += n; size -= n; } while (size != 0); } template void format_value(basic_buffer &buffer, const T &value) { internal::formatbuf format_buf(buffer); std::basic_ostream output(&format_buf); output.exceptions(std::ios_base::failbit | std::ios_base::badbit); output << value; buffer.resize(buffer.size()); } // Disable builtin formatting of enums and use operator<< instead. template struct format_enum::value>::type> : std::false_type {}; } // namespace internal // Formats an object of type T that has an overloaded ostream operator<<. template struct formatter::value>::type> : formatter, Char> { template auto format(const T &value, Context &ctx) -> decltype(ctx.out()) { basic_memory_buffer buffer; internal::format_value(buffer, value); basic_string_view str(buffer.data(), buffer.size()); formatter, Char>::format(str, ctx); return ctx.out(); } }; template inline void vprint(std::basic_ostream &os, basic_string_view format_str, basic_format_args::type> args) { basic_memory_buffer buffer; vformat_to(buffer, format_str, args); internal::write(os, buffer); } /** \rst Prints formatted data to the stream *os*. **Example**:: fmt::print(cerr, "Don't {}!", "panic"); \endrst */ template inline void print(std::ostream &os, string_view format_str, const Args & ... args) { vprint(os, format_str, make_format_args(args...)); } template inline void print(std::wostream &os, wstring_view format_str, const Args & ... args) { vprint(os, format_str, make_format_args(args...)); } FMT_END_NAMESPACE #endif // FMT_OSTREAM_H_