quill
xchar.h
1 // Formatting library for C++ - optional wchar_t and exotic character 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_XCHAR_H_
9 #define FMTQUILL_XCHAR_H_
10 
11 #include "color.h"
12 #include "format.h"
13 #include "ostream.h"
14 #include "ranges.h"
15 
16 #ifndef FMTQUILL_MODULE
17 # include <cwchar>
18 # if FMTQUILL_USE_LOCALE
19 # include <locale>
20 # endif
21 #endif
22 
23 FMTQUILL_BEGIN_NAMESPACE
24 namespace detail {
25 
26 template <typename T>
27 using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
28 
29 template <typename S, typename = void> struct format_string_char {};
30 
31 template <typename S>
33  S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> {
34  using type = char_t<S>;
35 };
36 
37 template <typename S>
39  S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> {
40  using type = typename S::char_type;
41 };
42 
43 template <typename S>
44 using format_string_char_t = typename format_string_char<S>::type;
45 
46 inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
47  const format_specs& specs, locale_ref loc) -> bool {
48 #if FMTQUILL_USE_LOCALE
49  auto& numpunct =
50  std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
51  auto separator = std::wstring();
52  auto grouping = numpunct.grouping();
53  if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
54  return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
55 #endif
56  return false;
57 }
58 } // namespace detail
59 
60 FMTQUILL_BEGIN_EXPORT
61 
64 using wformat_context = buffered_context<wchar_t>;
67 
68 template <typename Char, typename... T> struct basic_fstring {
69  private:
71 
72  static constexpr int num_static_named_args =
73  detail::count_static_named_args<T...>();
74 
76  Char, static_cast<int>(sizeof...(T)), num_static_named_args,
77  num_static_named_args != detail::count_named_args<T...>()>;
78 
79  using arg_pack = detail::arg_pack<T...>;
80 
81  public:
82  using t = basic_fstring;
83 
84  template <typename S,
85  FMTQUILL_ENABLE_IF(
86  std::is_convertible<const S&, basic_string_view<Char>>::value)>
87  FMTQUILL_CONSTEVAL FMTQUILL_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) {
88  if (FMTQUILL_USE_CONSTEVAL)
89  detail::parse_format_string<Char>(s, checker(s, arg_pack()));
90  }
91  template <typename S,
92  FMTQUILL_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
93  std::is_same<typename S::char_type, Char>::value)>
94  FMTQUILL_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) {
95  FMTQUILL_CONSTEXPR auto sv = basic_string_view<Char>(S());
96  FMTQUILL_CONSTEXPR int ignore =
97  (parse_format_string(sv, checker(sv, arg_pack())), 0);
98  detail::ignore_unused(ignore);
99  }
100  basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {}
101 
102  operator basic_string_view<Char>() const { return str_; }
103  auto get() const -> basic_string_view<Char> { return str_; }
104 };
105 
106 template <typename Char, typename... T>
107 using basic_format_string = basic_fstring<Char, T...>;
108 
109 template <typename... T>
110 using wformat_string = typename basic_format_string<wchar_t, T...>::t;
111 inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
112  return {{s}};
113 }
114 
115 #ifdef __cpp_char8_t
116 template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {};
117 #endif
118 
119 template <typename... T>
120 constexpr auto make_wformat_args(T&... args)
121  -> decltype(fmtquill::make_format_args<wformat_context>(args...)) {
122  return fmtquill::make_format_args<wformat_context>(args...);
123 }
124 
125 #if !FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS
126 inline namespace literals {
127 inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> {
128  return {s};
129 }
130 } // namespace literals
131 #endif
132 
133 template <typename It, typename Sentinel>
134 auto join(It begin, Sentinel end, wstring_view sep)
136  return {begin, end, sep};
137 }
138 
139 template <typename Range, FMTQUILL_ENABLE_IF(!is_tuple_like<Range>::value)>
140 auto join(Range&& range, wstring_view sep)
141  -> join_view<decltype(std::begin(range)), decltype(std::end(range)),
142  wchar_t> {
143  return join(std::begin(range), std::end(range), sep);
144 }
145 
146 template <typename T>
147 auto join(std::initializer_list<T> list, wstring_view sep)
149  return join(std::begin(list), std::end(list), sep);
150 }
151 
152 template <typename Tuple, FMTQUILL_ENABLE_IF(is_tuple_like<Tuple>::value)>
153 auto join(const Tuple& tuple, basic_string_view<wchar_t> sep)
155  return {tuple, sep};
156 }
157 
158 template <typename Char, FMTQUILL_ENABLE_IF(!std::is_same<Char, char>::value)>
159 auto vformat(basic_string_view<Char> fmt,
160  typename detail::vformat_args<Char>::type args)
161  -> std::basic_string<Char> {
162  auto buf = basic_memory_buffer<Char>();
163  detail::vformat_to(buf, fmt, args);
164  return {buf.data(), buf.size()};
165 }
166 
167 template <typename... T>
168 auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
169  return vformat(fmtquill::wstring_view(fmt), fmtquill::make_wformat_args(args...));
170 }
171 
172 template <typename OutputIt, typename... T>
173 auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args)
174  -> OutputIt {
175  return vformat_to(out, fmtquill::wstring_view(fmt),
176  fmtquill::make_wformat_args(args...));
177 }
178 
179 // Pass char_t as a default template parameter instead of using
180 // std::basic_string<char_t<S>> to reduce the symbol size.
181 template <typename S, typename... T,
182  typename Char = detail::format_string_char_t<S>,
183  FMTQUILL_ENABLE_IF(!std::is_same<Char, char>::value &&
184  !std::is_same<Char, wchar_t>::value)>
185 auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
186  return vformat(detail::to_string_view(fmt),
187  fmtquill::make_format_args<buffered_context<Char>>(args...));
188 }
189 
190 template <typename Locale, typename S,
191  typename Char = detail::format_string_char_t<S>,
192  FMTQUILL_ENABLE_IF(detail::is_locale<Locale>::value&&
193  detail::is_exotic_char<Char>::value)>
194 inline auto vformat(const Locale& loc, const S& fmt,
195  typename detail::vformat_args<Char>::type args)
196  -> std::basic_string<Char> {
197  auto buf = basic_memory_buffer<Char>();
198  detail::vformat_to(buf, detail::to_string_view(fmt), args,
199  detail::locale_ref(loc));
200  return {buf.data(), buf.size()};
201 }
202 
203 template <typename Locale, typename S, typename... T,
204  typename Char = detail::format_string_char_t<S>,
205  FMTQUILL_ENABLE_IF(detail::is_locale<Locale>::value&&
206  detail::is_exotic_char<Char>::value)>
207 inline auto format(const Locale& loc, const S& fmt, T&&... args)
208  -> std::basic_string<Char> {
209  return vformat(loc, detail::to_string_view(fmt),
210  fmtquill::make_format_args<buffered_context<Char>>(args...));
211 }
212 
213 template <typename OutputIt, typename S,
214  typename Char = detail::format_string_char_t<S>,
216  detail::is_exotic_char<Char>::value)>
217 auto vformat_to(OutputIt out, const S& fmt,
218  typename detail::vformat_args<Char>::type args) -> OutputIt {
219  auto&& buf = detail::get_buffer<Char>(out);
220  detail::vformat_to(buf, detail::to_string_view(fmt), args);
221  return detail::get_iterator(buf, out);
222 }
223 
224 template <typename OutputIt, typename S, typename... T,
225  typename Char = detail::format_string_char_t<S>,
227  !std::is_same<Char, char>::value &&
228  !std::is_same<Char, wchar_t>::value)>
229 inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
230  return vformat_to(out, detail::to_string_view(fmt),
231  fmtquill::make_format_args<buffered_context<Char>>(args...));
232 }
233 
234 template <typename Locale, typename S, typename OutputIt, typename... Args,
235  typename Char = detail::format_string_char_t<S>,
238  detail::is_exotic_char<Char>::value)>
239 inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt,
240  typename detail::vformat_args<Char>::type args)
241  -> OutputIt {
242  auto&& buf = detail::get_buffer<Char>(out);
243  vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc));
244  return detail::get_iterator(buf, out);
245 }
246 
247 template <typename Locale, typename OutputIt, typename S, typename... T,
248  typename Char = detail::format_string_char_t<S>,
251  detail::is_exotic_char<Char>::value>
252 inline auto format_to(OutputIt out, const Locale& loc, const S& fmt,
253  T&&... args) ->
254  typename std::enable_if<enable, OutputIt>::type {
255  return vformat_to(out, loc, detail::to_string_view(fmt),
256  fmtquill::make_format_args<buffered_context<Char>>(args...));
257 }
258 
259 template <typename OutputIt, typename Char, typename... Args,
261  detail::is_exotic_char<Char>::value)>
262 inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
263  typename detail::vformat_args<Char>::type args)
265  using traits = detail::fixed_buffer_traits;
267  detail::vformat_to(buf, fmt, args);
268  return {buf.out(), buf.count()};
269 }
270 
271 template <typename OutputIt, typename S, typename... T,
272  typename Char = detail::format_string_char_t<S>,
274  detail::is_exotic_char<Char>::value)>
275 inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
277  return vformat_to_n(out, n, fmtquill::basic_string_view<Char>(fmt),
278  fmtquill::make_format_args<buffered_context<Char>>(args...));
279 }
280 
281 template <typename S, typename... T,
282  typename Char = detail::format_string_char_t<S>,
283  FMTQUILL_ENABLE_IF(detail::is_exotic_char<Char>::value)>
284 inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
285  auto buf = detail::counting_buffer<Char>();
286  detail::vformat_to(buf, detail::to_string_view(fmt),
287  fmtquill::make_format_args<buffered_context<Char>>(args...));
288  return buf.count();
289 }
290 
291 inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
292  auto buf = wmemory_buffer();
293  detail::vformat_to(buf, fmt, args);
294  buf.push_back(L'\0');
295  if (std::fputws(buf.data(), f) == -1)
296  FMTQUILL_THROW(system_error(errno, FMTQUILL_STRING("cannot write to file")));
297 }
298 
299 inline void vprint(wstring_view fmt, wformat_args args) {
300  vprint(stdout, fmt, args);
301 }
302 
303 template <typename... T>
304 void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
305  return vprint(f, wstring_view(fmt), fmtquill::make_wformat_args(args...));
306 }
307 
308 template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
309  return vprint(wstring_view(fmt), fmtquill::make_wformat_args(args...));
310 }
311 
312 template <typename... T>
313 void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
314  return print(f, L"{}\n", fmtquill::format(fmt, std::forward<T>(args)...));
315 }
316 
317 template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
318  return print(L"{}\n", fmtquill::format(fmt, std::forward<T>(args)...));
319 }
320 
321 inline auto vformat(text_style ts, wstring_view fmt, wformat_args args)
322  -> std::wstring {
323  auto buf = wmemory_buffer();
324  detail::vformat_to(buf, ts, fmt, args);
325  return {buf.data(), buf.size()};
326 }
327 
328 template <typename... T>
329 inline auto format(text_style ts, wformat_string<T...> fmt, T&&... args)
330  -> std::wstring {
331  return fmtquill::vformat(ts, fmt, fmtquill::make_wformat_args(args...));
332 }
333 
334 template <typename... T>
335 FMTQUILL_DEPRECATED void print(std::FILE* f, text_style ts, wformat_string<T...> fmt,
336  const T&... args) {
337  vprint(f, ts, fmt, fmtquill::make_wformat_args(args...));
338 }
339 
340 template <typename... T>
341 FMTQUILL_DEPRECATED void print(text_style ts, wformat_string<T...> fmt,
342  const T&... args) {
343  return print(stdout, ts, fmt, args...);
344 }
345 
346 inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) {
347  auto buffer = basic_memory_buffer<wchar_t>();
348  detail::vformat_to(buffer, fmt, args);
349  detail::write_buffer(os, buffer);
350 }
351 
352 template <typename... T>
353 void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
354  vprint(os, fmt, fmtquill::make_format_args<buffered_context<wchar_t>>(args...));
355 }
356 
357 template <typename... T>
358 void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
359  print(os, L"{}\n", fmtquill::format(fmt, std::forward<T>(args)...));
360 }
361 
363 template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
364  return format(FMTQUILL_STRING(L"{}"), value);
365 }
366 FMTQUILL_END_EXPORT
367 FMTQUILL_END_NAMESPACE
368 
369 #endif // FMTQUILL_XCHAR_H_
Definition: xchar.h:29
Definition: base.h:860
Definition: format.h:1986
Definition: format.h:3738
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:644
Definition: format.h:126
Definition: format.h:3670
Definition: base.h:1681
Definition: base.h:1865
Definition: xchar.h:68
Definition: base.h:1882
Definition: base.h:2715
Definition: base.h:636
Definition: ranges.h:623
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:523
A view of a collection of formatting arguments.
Definition: base.h:661
A text style consisting of foreground and background colors and emphasis.
Definition: color.h:236
typename V::value_type char_t
String&#39;s character (code unit) type. detail:: is intentional to prevent ADL.
Definition: base.h:961
Definition: base.h:2303
Definition: base.h:2147
Definition: base.h:2011
Definition: base.h:2318
Definition: format.h:4006
Definition: base.h:2876
Definition: format.h:3592
Definition: base.h:1684
Definition: base.h:633
Definition: ranges.h:673