// Formatting library for C++ - std::ostream support // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #ifndef FMT_OSTREAM_H_ #define FMT_OSTREAM_H_ #include #include "format.h" FMT_BEGIN_NAMESPACE template class basic_printf_parse_context; template class basic_printf_context; namespace detail { template class formatbuf : public std::basic_streambuf { private: using int_type = typename std::basic_streambuf::int_type; using traits_type = typename std::basic_streambuf::traits_type; buffer& buffer_; public: formatbuf(buffer& buf) : buffer_(buf) {} 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; } }; struct converter { template ::value)> converter(T); }; template struct test_stream : std::basic_ostream { private: void_t<> operator<<(converter); }; // Hide insertion operators for built-in types. template void_t<> operator<<(std::basic_ostream&, Char); template void_t<> operator<<(std::basic_ostream&, char); template void_t<> operator<<(std::basic_ostream&, char); template void_t<> operator<<(std::basic_ostream&, signed char); template void_t<> operator<<(std::basic_ostream&, unsigned char); // Checks if T has a user-defined operator<< (e.g. not a member of // std::ostream). template class is_streamable { private: template static bool_constant&>() << std::declval()), void_t<>>::value> test(int); template static std::false_type test(...); using result = decltype(test(0)); public: static const bool value = result::value; }; // Write the content of buf to os. template void write_buffer(std::basic_ostream& os, buffer& buf) { const Char* buf_data = buf.data(); using unsigned_streamsize = std::make_unsigned::type; unsigned_streamsize size = buf.size(); unsigned_streamsize max_size = to_unsigned(max_value()); do { unsigned_streamsize n = size <= max_size ? size : max_size; os.write(buf_data, static_cast(n)); buf_data += n; size -= n; } while (size != 0); } template void format_value(buffer& buf, const T& value, locale_ref loc = locale_ref()) { formatbuf format_buf(buf); std::basic_ostream output(&format_buf); #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) if (loc) output.imbue(loc.get()); #endif output << value; output.exceptions(std::ios_base::failbit | std::ios_base::badbit); buf.try_resize(buf.size()); } // Formats an object of type T that has an overloaded ostream operator<<. template struct fallback_formatter::value>> : private formatter, Char> { FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) -> decltype(ctx.begin()) { return formatter, Char>::parse(ctx); } template >::value)> auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } template auto format(const T& value, basic_format_context& ctx) -> OutputIt { basic_memory_buffer buffer; format_value(buffer, value, ctx.locale()); basic_string_view str(buffer.data(), buffer.size()); return formatter, Char>::format(str, ctx); } template auto format(const T& value, basic_printf_context& ctx) -> OutputIt { basic_memory_buffer buffer; format_value(buffer, value, ctx.locale()); return std::copy(buffer.begin(), buffer.end(), ctx.out()); } }; } // namespace detail template void vprint(std::basic_ostream& os, basic_string_view format_str, basic_format_args>> args) { basic_memory_buffer buffer; detail::vformat_to(buffer, format_str, args); detail::write_buffer(os, buffer); } /** \rst Prints formatted data to the stream *os*. **Example**:: fmt::print(cerr, "Don't {}!", "panic"); \endrst */ template ::value, char_t>> void print(std::basic_ostream& os, const S& format_str, Args&&... args) { vprint(os, to_string_view(format_str), fmt::make_args_checked(format_str, args...)); } FMT_END_NAMESPACE #endif // FMT_OSTREAM_H_