xref: /aosp_15_r20/external/fmtlib/include/fmt/ostream.h (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
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 #ifndef FMT_MODULE
12 #  include <fstream>  // std::filebuf
13 #endif
14 
15 #ifdef _WIN32
16 #  ifdef __GLIBCXX__
17 #    include <ext/stdio_filebuf.h>
18 #    include <ext/stdio_sync_filebuf.h>
19 #  endif
20 #  include <io.h>
21 #endif
22 
23 #include "chrono.h"  // formatbuf
24 
25 FMT_BEGIN_NAMESPACE
26 namespace detail {
27 
28 // Generate a unique explicit instantion in every translation unit using a tag
29 // type in an anonymous namespace.
30 namespace {
31 struct file_access_tag {};
32 }  // namespace
33 template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
34 class file_access {
35   friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
36 };
37 
38 #if FMT_MSC_VERSION
39 template class file_access<file_access_tag, std::filebuf,
40                            &std::filebuf::_Myfile>;
41 auto get_file(std::filebuf&) -> FILE*;
42 #endif
43 
44 // Write the content of buf to os.
45 // It is a separate function rather than a part of vprint to simplify testing.
46 template <typename Char>
write_buffer(std::basic_ostream<Char> & os,buffer<Char> & buf)47 void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
48   const Char* buf_data = buf.data();
49   using unsigned_streamsize = make_unsigned_t<std::streamsize>;
50   unsigned_streamsize size = buf.size();
51   unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
52   do {
53     unsigned_streamsize n = size <= max_size ? size : max_size;
54     os.write(buf_data, static_cast<std::streamsize>(n));
55     buf_data += n;
56     size -= n;
57   } while (size != 0);
58 }
59 
60 template <typename T> struct streamed_view {
61   const T& value;
62 };
63 }  // namespace detail
64 
65 // Formats an object of type T that has an overloaded ostream operator<<.
66 template <typename Char>
67 struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
68   void set_debug_format() = delete;
69 
70   template <typename T, typename Context>
71   auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
72     auto buffer = basic_memory_buffer<Char>();
73     auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer);
74     auto&& output = std::basic_ostream<Char>(&formatbuf);
75     output.imbue(std::locale::classic());  // The default is always unlocalized.
76     output << value;
77     output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
78     return formatter<basic_string_view<Char>, Char>::format(
79         {buffer.data(), buffer.size()}, ctx);
80   }
81 };
82 
83 using ostream_formatter = basic_ostream_formatter<char>;
84 
85 template <typename T, typename Char>
86 struct formatter<detail::streamed_view<T>, Char>
87     : basic_ostream_formatter<Char> {
88   template <typename Context>
89   auto format(detail::streamed_view<T> view, Context& ctx) const
90       -> decltype(ctx.out()) {
91     return basic_ostream_formatter<Char>::format(view.value, ctx);
92   }
93 };
94 
95 /**
96  * Returns a view that formats `value` via an ostream `operator<<`.
97  *
98  * **Example**:
99  *
100  *     fmt::print("Current thread id: {}\n",
101  *                fmt::streamed(std::this_thread::get_id()));
102  */
103 template <typename T>
104 constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
105   return {value};
106 }
107 
108 inline void vprint(std::ostream& os, string_view fmt, format_args args) {
109   auto buffer = memory_buffer();
110   detail::vformat_to(buffer, fmt, args);
111   FILE* f = nullptr;
112 #if FMT_MSC_VERSION && FMT_USE_RTTI
113   if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
114     f = detail::get_file(*buf);
115 #elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI
116   auto* rdbuf = os.rdbuf();
117   if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
118     f = sfbuf->file();
119   else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
120     f = fbuf->file();
121 #endif
122 #ifdef _WIN32
123   if (f) {
124     int fd = _fileno(f);
125     if (_isatty(fd)) {
126       os.flush();
127       if (detail::write_console(fd, {buffer.data(), buffer.size()})) return;
128     }
129   }
130 #endif
131   detail::ignore_unused(f);
132   detail::write_buffer(os, buffer);
133 }
134 
135 /**
136  * Prints formatted data to the stream `os`.
137  *
138  * **Example**:
139  *
140  *     fmt::print(cerr, "Don't {}!", "panic");
141  */
142 FMT_EXPORT template <typename... T>
143 void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
144   fmt::vargs<T...> vargs = {{args...}};
145   if (detail::use_utf8) return vprint(os, fmt.str, vargs);
146   auto buffer = memory_buffer();
147   detail::vformat_to(buffer, fmt.str, vargs);
148   detail::write_buffer(os, buffer);
149 }
150 
151 FMT_EXPORT template <typename... T>
152 void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
153   fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
154 }
155 
156 FMT_END_NAMESPACE
157 
158 #endif  // FMT_OSTREAM_H_
159