blob: 84b31cc5547ff8004d962cc308241d6db8dbc36e [file] [log] [blame]
Thomas Psota6bf79382019-09-16 16:42:15 +02001// 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 "format.h"
12#include <ostream>
13
14FMT_BEGIN_NAMESPACE
15namespace internal {
16
17template <class Char>
18class formatbuf : public std::basic_streambuf<Char> {
19 private:
20 typedef typename std::basic_streambuf<Char>::int_type int_type;
21 typedef typename std::basic_streambuf<Char>::traits_type traits_type;
22
23 basic_buffer<Char> &buffer_;
24
25 public:
26 formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
27
28 protected:
29 // The put-area is actually always empty. This makes the implementation
30 // simpler and has the advantage that the streambuf and the buffer are always
31 // in sync and sputc never writes into uninitialized memory. The obvious
32 // disadvantage is that each call to sputc always results in a (virtual) call
33 // to overflow. There is no disadvantage here for sputn since this always
34 // results in a call to xsputn.
35
36 int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
37 if (!traits_type::eq_int_type(ch, traits_type::eof()))
38 buffer_.push_back(static_cast<Char>(ch));
39 return ch;
40 }
41
42 std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
43 buffer_.append(s, s + count);
44 return count;
45 }
46};
47
48template <typename Char>
49struct test_stream : std::basic_ostream<Char> {
50 private:
51 struct null;
52 // Hide all operator<< from std::basic_ostream<Char>.
53 void operator<<(null);
54};
55
56// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
57template <typename T, typename Char>
58class is_streamable {
59 private:
60 template <typename U>
61 static decltype(
62 internal::declval<test_stream<Char>&>()
63 << internal::declval<U>(), std::true_type()) test(int);
64
65 template <typename>
66 static std::false_type test(...);
67
68 typedef decltype(test<T>(0)) result;
69
70 public:
71 static const bool value = result::value;
72};
73
74// Write the content of buf to os.
75template <typename Char>
76void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
77 const Char *data = buf.data();
78 typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
79 UnsignedStreamSize size = buf.size();
80 UnsignedStreamSize max_size =
81 internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
82 do {
83 UnsignedStreamSize n = size <= max_size ? size : max_size;
84 os.write(data, static_cast<std::streamsize>(n));
85 data += n;
86 size -= n;
87 } while (size != 0);
88}
89
90template <typename Char, typename T>
91void format_value(basic_buffer<Char> &buffer, const T &value) {
92 internal::formatbuf<Char> format_buf(buffer);
93 std::basic_ostream<Char> output(&format_buf);
94 output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
95 output << value;
96 buffer.resize(buffer.size());
97}
98} // namespace internal
99
100// Disable conversion to int if T has an overloaded operator<< which is a free
101// function (not a member of std::ostream).
102template <typename T, typename Char>
103struct convert_to_int<T, Char, void> {
104 static const bool value =
105 convert_to_int<T, Char, int>::value &&
106 !internal::is_streamable<T, Char>::value;
107};
108
109// Formats an object of type T that has an overloaded ostream operator<<.
110template <typename T, typename Char>
111struct formatter<T, Char,
112 typename std::enable_if<
113 internal::is_streamable<T, Char>::value &&
114 !internal::format_type<
115 typename buffer_context<Char>::type, T>::value>::type>
116 : formatter<basic_string_view<Char>, Char> {
117
118 template <typename Context>
119 auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
120 basic_memory_buffer<Char> buffer;
121 internal::format_value(buffer, value);
122 basic_string_view<Char> str(buffer.data(), buffer.size());
123 return formatter<basic_string_view<Char>, Char>::format(str, ctx);
124 }
125};
126
127template <typename Char>
128inline void vprint(std::basic_ostream<Char> &os,
129 basic_string_view<Char> format_str,
130 basic_format_args<typename buffer_context<Char>::type> args) {
131 basic_memory_buffer<Char> buffer;
132 internal::vformat_to(buffer, format_str, args);
133 internal::write(os, buffer);
134}
135/**
136 \rst
137 Prints formatted data to the stream *os*.
138
139 **Example**::
140
141 fmt::print(cerr, "Don't {}!", "panic");
142 \endrst
143 */
144template <typename S, typename... Args>
145inline typename std::enable_if<internal::is_string<S>::value>::type
146print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
147 const Args & ... args) {
148 internal::checked_args<S, Args...> ca(format_str, args...);
149 vprint(os, to_string_view(format_str), *ca);
150}
151FMT_END_NAMESPACE
152
153#endif // FMT_OSTREAM_H_