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:
formatbuf(buffer<Char> & buf)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 
xsputn(const Char * s,std::streamsize count)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>
write(std::basic_ostream<Char> & os,buffer<Char> & buf)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 !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
97   if (loc) output.imbue(loc.get<std::locale>());
98   #endif
99   output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
100   output << value;
101   buf.resize(buf.size());
102 }
103 
104 // Formats an object of type T that has an overloaded ostream operator<<.
105 template <typename T, typename Char>
106 struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
107     : formatter<basic_string_view<Char>, Char> {
108   template <typename Context>
109   auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
110     basic_memory_buffer<Char> buffer;
111     format_value(buffer, value, ctx.locale());
112     basic_string_view<Char> str(buffer.data(), buffer.size());
113     return formatter<basic_string_view<Char>, Char>::format(str, ctx);
114   }
115 };
116 }  // namespace internal
117 
118 template <typename Char>
119 void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
120             basic_format_args<buffer_context<type_identity_t<Char>>> args) {
121   basic_memory_buffer<Char> buffer;
122   internal::vformat_to(buffer, format_str, args);
123   internal::write(os, buffer);
124 }
125 
126 /**
127   \rst
128   Prints formatted data to the stream *os*.
129 
130   **Example**::
131 
132     fmt::print(cerr, "Don't {}!", "panic");
133   \endrst
134  */
135 template <typename S, typename... Args,
136           typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
137 void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
138   vprint(os, to_string_view(format_str),
139          internal::make_args_checked<Args...>(format_str, args...));
140 }
141 FMT_END_NAMESPACE
142 
143 #endif  // FMT_OSTREAM_H_
144