xref: /aosp_15_r20/external/fmtlib/include/fmt/xchar.h (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
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 FMT_XCHAR_H_
9 #define FMT_XCHAR_H_
10 
11 #include "color.h"
12 #include "format.h"
13 #include "ostream.h"
14 #include "ranges.h"
15 
16 #ifndef FMT_MODULE
17 #  include <cwchar>
18 #  if FMT_USE_LOCALE
19 #    include <locale>
20 #  endif
21 #endif
22 
23 FMT_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>
32 struct format_string_char<
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>
38 struct format_string_char<
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 FMT_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 FMT_BEGIN_EXPORT
61 
62 using wstring_view = basic_string_view<wchar_t>;
63 using wformat_parse_context = parse_context<wchar_t>;
64 using wformat_context = buffered_context<wchar_t>;
65 using wformat_args = basic_format_args<wformat_context>;
66 using wmemory_buffer = basic_memory_buffer<wchar_t>;
67 
68 template <typename Char, typename... T> struct basic_fstring {
69  private:
70   basic_string_view<Char> str_;
71 
72   static constexpr int num_static_named_args =
73       detail::count_static_named_args<T...>();
74 
75   using checker = detail::format_string_checker<
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             FMT_ENABLE_IF(
86                 std::is_convertible<const S&, basic_string_view<Char>>::value)>
87   FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) {
88     if (FMT_USE_CONSTEVAL)
89       detail::parse_format_string<Char>(s, checker(s, arg_pack()));
90   }
91   template <typename S,
92             FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
93                               std::is_same<typename S::char_type, Char>::value)>
94   FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) {
95     FMT_CONSTEXPR auto sv = basic_string_view<Char>(S());
96     FMT_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 template <> struct is_char<wchar_t> : std::true_type {};
116 template <> struct is_char<char16_t> : std::true_type {};
117 template <> struct is_char<char32_t> : std::true_type {};
118 
119 #ifdef __cpp_char8_t
120 template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {};
121 #endif
122 
123 template <typename... T>
124 constexpr auto make_wformat_args(T&... args)
125     -> decltype(fmt::make_format_args<wformat_context>(args...)) {
126   return fmt::make_format_args<wformat_context>(args...);
127 }
128 
129 #if !FMT_USE_NONTYPE_TEMPLATE_ARGS
130 inline namespace literals {
131 inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> {
132   return {s};
133 }
134 }  // namespace literals
135 #endif
136 
137 template <typename It, typename Sentinel>
138 auto join(It begin, Sentinel end, wstring_view sep)
139     -> join_view<It, Sentinel, wchar_t> {
140   return {begin, end, sep};
141 }
142 
143 template <typename Range>
144 auto join(Range&& range, wstring_view sep)
145     -> join_view<decltype(std::begin(range)), decltype(std::end(range)),
146                  wchar_t> {
147   return join(std::begin(range), std::end(range), sep);
148 }
149 
150 template <typename T>
151 auto join(std::initializer_list<T> list, wstring_view sep)
152     -> join_view<const T*, const T*, wchar_t> {
153   return join(std::begin(list), std::end(list), sep);
154 }
155 
156 template <typename... T>
157 auto join(const std::tuple<T...>& tuple, basic_string_view<wchar_t> sep)
158     -> tuple_join_view<wchar_t, T...> {
159   return {tuple, sep};
160 }
161 
162 template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
163 auto vformat(basic_string_view<Char> fmt,
164              typename detail::vformat_args<Char>::type args)
165     -> std::basic_string<Char> {
166   auto buf = basic_memory_buffer<Char>();
167   detail::vformat_to(buf, fmt, args);
168   return {buf.data(), buf.size()};
169 }
170 
171 template <typename... T>
172 auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
173   return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
174 }
175 
176 template <typename OutputIt, typename... T>
177 auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args)
178     -> OutputIt {
179   return vformat_to(out, fmt::wstring_view(fmt),
180                     fmt::make_wformat_args(args...));
181 }
182 
183 // Pass char_t as a default template parameter instead of using
184 // std::basic_string<char_t<S>> to reduce the symbol size.
185 template <typename S, typename... T,
186           typename Char = detail::format_string_char_t<S>,
187           FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
188                         !std::is_same<Char, wchar_t>::value)>
189 auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
190   return vformat(detail::to_string_view(fmt),
191                  fmt::make_format_args<buffered_context<Char>>(args...));
192 }
193 
194 template <typename S, typename Char = detail::format_string_char_t<S>,
195           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
196 inline auto vformat(detail::locale_ref loc, const S& fmt,
197                     typename detail::vformat_args<Char>::type args)
198     -> std::basic_string<Char> {
199   auto buf = basic_memory_buffer<Char>();
200   detail::vformat_to(buf, detail::to_string_view(fmt), args,
201                      detail::locale_ref(loc));
202   return {buf.data(), buf.size()};
203 }
204 
205 template <typename S, typename... T,
206           typename Char = detail::format_string_char_t<S>,
207           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
208 inline auto format(detail::locale_ref loc, const S& fmt, T&&... args)
209     -> std::basic_string<Char> {
210   return vformat(loc, detail::to_string_view(fmt),
211                  fmt::make_format_args<buffered_context<Char>>(args...));
212 }
213 
214 template <typename OutputIt, typename S,
215           typename Char = detail::format_string_char_t<S>,
216           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
217                             detail::is_exotic_char<Char>::value)>
218 auto vformat_to(OutputIt out, const S& fmt,
219                 typename detail::vformat_args<Char>::type args) -> OutputIt {
220   auto&& buf = detail::get_buffer<Char>(out);
221   detail::vformat_to(buf, detail::to_string_view(fmt), args);
222   return detail::get_iterator(buf, out);
223 }
224 
225 template <typename OutputIt, typename S, typename... T,
226           typename Char = detail::format_string_char_t<S>,
227           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
228                         !std::is_same<Char, char>::value &&
229                         !std::is_same<Char, wchar_t>::value)>
230 inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
231   return vformat_to(out, detail::to_string_view(fmt),
232                     fmt::make_format_args<buffered_context<Char>>(args...));
233 }
234 
235 template <typename S, typename OutputIt, typename... Args,
236           typename Char = detail::format_string_char_t<S>,
237           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
238                             detail::is_exotic_char<Char>::value)>
239 inline auto vformat_to(OutputIt out, detail::locale_ref 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 OutputIt, typename S, typename... T,
248           typename Char = detail::format_string_char_t<S>,
249           bool enable = detail::is_output_iterator<OutputIt, Char>::value &&
250                         detail::is_exotic_char<Char>::value>
251 inline auto format_to(OutputIt out, detail::locale_ref loc, const S& fmt,
252                       T&&... args) ->
253     typename std::enable_if<enable, OutputIt>::type {
254   return vformat_to(out, loc, detail::to_string_view(fmt),
255                     fmt::make_format_args<buffered_context<Char>>(args...));
256 }
257 
258 template <typename OutputIt, typename Char, typename... Args,
259           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
260                             detail::is_exotic_char<Char>::value)>
261 inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
262                          typename detail::vformat_args<Char>::type args)
263     -> format_to_n_result<OutputIt> {
264   using traits = detail::fixed_buffer_traits;
265   auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
266   detail::vformat_to(buf, fmt, args);
267   return {buf.out(), buf.count()};
268 }
269 
270 template <typename OutputIt, typename S, typename... T,
271           typename Char = detail::format_string_char_t<S>,
272           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
273                             detail::is_exotic_char<Char>::value)>
274 inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
275     -> format_to_n_result<OutputIt> {
276   return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt),
277                       fmt::make_format_args<buffered_context<Char>>(args...));
278 }
279 
280 template <typename S, typename... T,
281           typename Char = detail::format_string_char_t<S>,
282           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
283 inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
284   auto buf = detail::counting_buffer<Char>();
285   detail::vformat_to(buf, detail::to_string_view(fmt),
286                      fmt::make_format_args<buffered_context<Char>>(args...));
287   return buf.count();
288 }
289 
290 inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
291   auto buf = wmemory_buffer();
292   detail::vformat_to(buf, fmt, args);
293   buf.push_back(L'\0');
294   if (std::fputws(buf.data(), f) == -1)
295     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
296 }
297 
298 inline void vprint(wstring_view fmt, wformat_args args) {
299   vprint(stdout, fmt, args);
300 }
301 
302 template <typename... T>
303 void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
304   return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
305 }
306 
307 template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
308   return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
309 }
310 
311 template <typename... T>
312 void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
313   return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
314 }
315 
316 template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
317   return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
318 }
319 
320 inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args)
321     -> std::wstring {
322   auto buf = wmemory_buffer();
323   detail::vformat_to(buf, ts, fmt, args);
324   return {buf.data(), buf.size()};
325 }
326 
327 template <typename... T>
328 inline auto format(const text_style& ts, wformat_string<T...> fmt, T&&... args)
329     -> std::wstring {
330   return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...));
331 }
332 
333 template <typename... T>
334 FMT_DEPRECATED void print(std::FILE* f, const text_style& ts,
335                           wformat_string<T...> fmt, const T&... args) {
336   vprint(f, ts, fmt, fmt::make_wformat_args(args...));
337 }
338 
339 template <typename... T>
340 FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt,
341                           const T&... args) {
342   return print(stdout, ts, fmt, args...);
343 }
344 
345 inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) {
346   auto buffer = basic_memory_buffer<wchar_t>();
347   detail::vformat_to(buffer, fmt, args);
348   detail::write_buffer(os, buffer);
349 }
350 
351 template <typename... T>
352 void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
353   vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...));
354 }
355 
356 template <typename... T>
357 void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
358   print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
359 }
360 
361 /// Converts `value` to `std::wstring` using the default format for type `T`.
362 template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
363   return format(FMT_STRING(L"{}"), value);
364 }
365 FMT_END_EXPORT
366 FMT_END_NAMESPACE
367 
368 #endif  // FMT_XCHAR_H_
369