1 // Formatting library for C++ - std::ostream support 2 // 3 // Copyright (c) 2012 - present, Victor Zverovich 4 // All rights reserved. 5 // 6 // For the license information refer to format.h. 7 8 #ifndef FMT_OSTREAM_H_ 9 #define FMT_OSTREAM_H_ 10 11 #include <ostream> 12 #include "format.h" 13 14 FMT_BEGIN_NAMESPACE 15 namespace internal { 16 17 template <class Char> class formatbuf : public std::basic_streambuf<Char> { 18 private: 19 using int_type = typename std::basic_streambuf<Char>::int_type; 20 using traits_type = typename std::basic_streambuf<Char>::traits_type; 21 22 buffer<Char>& buffer_; 23 24 public: 25 formatbuf(buffer<Char>& buf) : buffer_(buf) {} 26 27 protected: 28 // The put-area is actually always empty. This makes the implementation 29 // simpler and has the advantage that the streambuf and the buffer are always 30 // in sync and sputc never writes into uninitialized memory. The obvious 31 // disadvantage is that each call to sputc always results in a (virtual) call 32 // to overflow. There is no disadvantage here for sputn since this always 33 // results in a call to xsputn. 34 35 int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { 36 if (!traits_type::eq_int_type(ch, traits_type::eof())) 37 buffer_.push_back(static_cast<Char>(ch)); 38 return ch; 39 } 40 41 std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE { 42 buffer_.append(s, s + count); 43 return count; 44 } 45 }; 46 47 template <typename Char> struct test_stream : std::basic_ostream<Char> { 48 private: 49 // Hide all operator<< from std::basic_ostream<Char>. 50 void_t<> operator<<(null<>); 51 void_t<> operator<<(const Char*); 52 53 template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value && 54 !std::is_enum<T>::value)> 55 void_t<> operator<<(T); 56 }; 57 58 // Checks if T has a user-defined operator<< (e.g. not a member of 59 // std::ostream). 60 template <typename T, typename Char> class is_streamable { 61 private: 62 template <typename U> 63 static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>() 64 << std::declval<U>()), 65 void_t<>>::value> 66 test(int); 67 68 template <typename> static std::false_type test(...); 69 70 using result = decltype(test<T>(0)); 71 72 public: 73 static const bool value = result::value; 74 }; 75 76 // Write the content of buf to os. 77 template <typename Char> 78 void write(std::basic_ostream<Char>& os, buffer<Char>& buf) { 79 const Char* buf_data = buf.data(); 80 using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; 81 unsigned_streamsize size = buf.size(); 82 unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); 83 do { 84 unsigned_streamsize n = size <= max_size ? size : max_size; 85 os.write(buf_data, static_cast<std::streamsize>(n)); 86 buf_data += n; 87 size -= n; 88 } while (size != 0); 89 } 90 91 template <typename Char, typename T> 92 void format_value(buffer<Char>& buf, const T& value, 93 locale_ref loc = locale_ref()) { 94 formatbuf<Char> format_buf(buf); 95 std::basic_ostream<Char> output(&format_buf); 96 if (loc) output.imbue(loc.get<std::locale>()); 97 output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 98 output << value; 99 buf.resize(buf.size()); 100 } 101 102 // Formats an object of type T that has an overloaded ostream operator<<. 103 template <typename T, typename Char> 104 struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>> 105 : formatter<basic_string_view<Char>, Char> { 106 template <typename Context> 107 auto format(const T& value, Context& ctx) -> decltype(ctx.out()) { 108 basic_memory_buffer<Char> buffer; 109 format_value(buffer, value, ctx.locale()); 110 basic_string_view<Char> str(buffer.data(), buffer.size()); 111 return formatter<basic_string_view<Char>, Char>::format(str, ctx); 112 } 113 }; 114 } // namespace internal 115 116 template <typename Char> 117 void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str, 118 basic_format_args<buffer_context<Char>> args) { 119 basic_memory_buffer<Char> buffer; 120 internal::vformat_to(buffer, format_str, args); 121 internal::write(os, buffer); 122 } 123 124 /** 125 \rst 126 Prints formatted data to the stream *os*. 127 128 **Example**:: 129 130 fmt::print(cerr, "Don't {}!", "panic"); 131 \endrst 132 */ 133 template <typename S, typename... Args, 134 typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>> 135 void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) { 136 vprint(os, to_string_view(format_str), 137 {internal::make_args_checked<Args...>(format_str, args...)}); 138 } 139 FMT_END_NAMESPACE 140 141 #endif // FMT_OSTREAM_H_ 142