quill
ostream.h
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 FMTQUILL_OSTREAM_H_
9 #define FMTQUILL_OSTREAM_H_
10 
11 #ifndef FMTQUILL_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 #ifdef _MSVC_STL_UPDATE
26 # define FMTQUILL_MSVC_STL_UPDATE _MSVC_STL_UPDATE
27 #elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5
28 # define FMTQUILL_MSVC_STL_UPDATE _MSVC_LANG
29 #else
30 # define FMTQUILL_MSVC_STL_UPDATE 0
31 #endif
32 
33 FMTQUILL_BEGIN_NAMESPACE
34 namespace detail {
35 
36 // Generate a unique explicit instantion in every translation unit using a tag
37 // type in an anonymous namespace.
38 namespace {
39 struct file_access_tag {};
40 } // namespace
41 template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
42 class file_access {
43  friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
44 };
45 
46 #if FMTQUILL_MSVC_STL_UPDATE
47 template class file_access<file_access_tag, std::filebuf,
48  &std::filebuf::_Myfile>;
49 auto get_file(std::filebuf&) -> FILE*;
50 #endif
51 
52 // Write the content of buf to os.
53 // It is a separate function rather than a part of vprint to simplify testing.
54 template <typename Char>
55 void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
56  const Char* buf_data = buf.data();
57  using unsigned_streamsize = make_unsigned_t<std::streamsize>;
58  unsigned_streamsize size = buf.size();
59  unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
60  do {
61  unsigned_streamsize n = size <= max_size ? size : max_size;
62  os.write(buf_data, static_cast<std::streamsize>(n));
63  buf_data += n;
64  size -= n;
65  } while (size != 0);
66 }
67 
68 template <typename T> struct streamed_view {
69  const T& value;
70 };
71 } // namespace detail
72 
73 // Formats an object of type T that has an overloaded ostream operator<<.
74 template <typename Char>
75 struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
76  void set_debug_format() = delete;
77 
78  template <typename T, typename Context>
79  auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
80  auto buffer = basic_memory_buffer<Char>();
81  auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer);
82  auto&& output = std::basic_ostream<Char>(&formatbuf);
83  output.imbue(std::locale::classic()); // The default is always unlocalized.
84  output << value;
85  output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
86  return formatter<basic_string_view<Char>, Char>::format(
87  {buffer.data(), buffer.size()}, ctx);
88  }
89 };
90 
92 
93 template <typename T, typename Char>
94 struct formatter<detail::streamed_view<T>, Char>
95  : basic_ostream_formatter<Char> {
96  template <typename Context>
97  auto format(detail::streamed_view<T> view, Context& ctx) const
98  -> decltype(ctx.out()) {
99  return basic_ostream_formatter<Char>::format(view.value, ctx);
100  }
101 };
102 
111 template <typename T>
112 constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
113  return {value};
114 }
115 
116 inline void vprint(std::ostream& os, string_view fmt, format_args args) {
117  auto buffer = memory_buffer();
118  detail::vformat_to(buffer, fmt, args);
119  FILE* f = nullptr;
120 #if FMTQUILL_MSVC_STL_UPDATE && FMTQUILL_USE_RTTI
121  if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
122  f = detail::get_file(*buf);
123 #elif defined(_WIN32) && defined(__GLIBCXX__) && FMTQUILL_USE_RTTI
124  auto* rdbuf = os.rdbuf();
125  if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
126  f = sfbuf->file();
127  else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
128  f = fbuf->file();
129 #endif
130 #ifdef _WIN32
131  if (f) {
132  int fd = _fileno(f);
133  if (_isatty(fd)) {
134  os.flush();
135  if (detail::write_console(fd, {buffer.data(), buffer.size()})) return;
136  }
137  }
138 #endif
139  detail::ignore_unused(f);
140  detail::write_buffer(os, buffer);
141 }
142 
150 FMTQUILL_EXPORT template <typename... T>
151 void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
152  fmtquill::vargs<T...> vargs = {{args...}};
153  if (detail::const_check(detail::use_utf8)) return vprint(os, fmt.str, vargs);
154  auto buffer = memory_buffer();
155  detail::vformat_to(buffer, fmt.str, vargs);
156  detail::write_buffer(os, buffer);
157 }
158 
159 FMTQUILL_EXPORT template <typename... T>
160 void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
161  fmtquill::print(os, FMTQUILL_STRING("{}\n"),
162  fmtquill::format(fmt, std::forward<T>(args)...));
163 }
164 
165 FMTQUILL_END_NAMESPACE
166 
167 #endif // FMTQUILL_OSTREAM_H_
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:790
Definition: base.h:669
FMTQUILL_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1799
Definition: base.h:2388
Definition: doctest.h:530
Definition: ostream.h:75
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1793
Definition: base.h:2147
Definition: ostream.h:42
Definition: chrono.h:292
Definition: ostream.h:68