Commit | Line | Data |
---|---|---|
05aa7e19 JG |
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 | ||
bd9231e4 | 11 | #include "color.h" |
05aa7e19 | 12 | #include "format.h" |
bd9231e4 JG |
13 | #include "ranges.h" |
14 | ||
15 | #ifndef FMT_MODULE | |
16 | # include <cwchar> | |
17 | # if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) | |
18 | # include <locale> | |
19 | # endif | |
20 | #endif | |
05aa7e19 JG |
21 | |
22 | FMT_BEGIN_NAMESPACE | |
23 | namespace detail { | |
bd9231e4 | 24 | |
05aa7e19 JG |
25 | template <typename T> |
26 | using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; | |
bd9231e4 JG |
27 | |
28 | template <typename S, typename = void> struct format_string_char {}; | |
29 | ||
30 | template <typename S> | |
31 | struct format_string_char< | |
32 | S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> { | |
33 | using type = char_t<S>; | |
34 | }; | |
35 | ||
36 | template <typename S> | |
37 | struct format_string_char<S, enable_if_t<is_compile_string<S>::value>> { | |
38 | using type = typename S::char_type; | |
39 | }; | |
40 | ||
41 | template <typename S> | |
42 | using format_string_char_t = typename format_string_char<S>::type; | |
43 | ||
44 | inline auto write_loc(basic_appender<wchar_t> out, loc_value value, | |
45 | const format_specs& specs, locale_ref loc) -> bool { | |
46 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | |
47 | auto& numpunct = | |
48 | std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>()); | |
49 | auto separator = std::wstring(); | |
50 | auto grouping = numpunct.grouping(); | |
51 | if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); | |
52 | return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}}); | |
53 | #endif | |
54 | return false; | |
05aa7e19 | 55 | } |
bd9231e4 | 56 | } // namespace detail |
05aa7e19 | 57 | |
bd9231e4 | 58 | FMT_BEGIN_EXPORT |
05aa7e19 JG |
59 | |
60 | using wstring_view = basic_string_view<wchar_t>; | |
61 | using wformat_parse_context = basic_format_parse_context<wchar_t>; | |
bd9231e4 | 62 | using wformat_context = buffered_context<wchar_t>; |
05aa7e19 JG |
63 | using wformat_args = basic_format_args<wformat_context>; |
64 | using wmemory_buffer = basic_memory_buffer<wchar_t>; | |
65 | ||
66 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 | |
67 | // Workaround broken conversion on older gcc. | |
68 | template <typename... Args> using wformat_string = wstring_view; | |
8b75cd77 | 69 | inline auto runtime(wstring_view s) -> wstring_view { return s; } |
05aa7e19 JG |
70 | #else |
71 | template <typename... Args> | |
72 | using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>; | |
bd9231e4 JG |
73 | inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> { |
74 | return {{s}}; | |
75 | } | |
05aa7e19 JG |
76 | #endif |
77 | ||
78 | template <> struct is_char<wchar_t> : std::true_type {}; | |
05aa7e19 JG |
79 | template <> struct is_char<char16_t> : std::true_type {}; |
80 | template <> struct is_char<char32_t> : std::true_type {}; | |
81 | ||
bd9231e4 JG |
82 | #ifdef __cpp_char8_t |
83 | template <> | |
84 | struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled()> {}; | |
85 | #endif | |
86 | ||
87 | template <typename... T> | |
88 | constexpr auto make_wformat_args(T&... args) | |
89 | -> decltype(fmt::make_format_args<wformat_context>(args...)) { | |
90 | return fmt::make_format_args<wformat_context>(args...); | |
05aa7e19 JG |
91 | } |
92 | ||
93 | inline namespace literals { | |
8b75cd77 | 94 | #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS |
bd9231e4 JG |
95 | constexpr auto operator""_a(const wchar_t* s, size_t) |
96 | -> detail::udl_arg<wchar_t> { | |
05aa7e19 JG |
97 | return {s}; |
98 | } | |
99 | #endif | |
100 | } // namespace literals | |
101 | ||
102 | template <typename It, typename Sentinel> | |
103 | auto join(It begin, Sentinel end, wstring_view sep) | |
104 | -> join_view<It, Sentinel, wchar_t> { | |
105 | return {begin, end, sep}; | |
106 | } | |
107 | ||
108 | template <typename Range> | |
109 | auto join(Range&& range, wstring_view sep) | |
110 | -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>, | |
111 | wchar_t> { | |
112 | return join(std::begin(range), std::end(range), sep); | |
113 | } | |
114 | ||
115 | template <typename T> | |
116 | auto join(std::initializer_list<T> list, wstring_view sep) | |
117 | -> join_view<const T*, const T*, wchar_t> { | |
118 | return join(std::begin(list), std::end(list), sep); | |
119 | } | |
120 | ||
bd9231e4 JG |
121 | template <typename... T> |
122 | auto join(const std::tuple<T...>& tuple, basic_string_view<wchar_t> sep) | |
123 | -> tuple_join_view<wchar_t, T...> { | |
124 | return {tuple, sep}; | |
125 | } | |
126 | ||
05aa7e19 JG |
127 | template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> |
128 | auto vformat(basic_string_view<Char> format_str, | |
bd9231e4 | 129 | typename detail::vformat_args<Char>::type args) |
05aa7e19 | 130 | -> std::basic_string<Char> { |
bd9231e4 JG |
131 | auto buf = basic_memory_buffer<Char>(); |
132 | detail::vformat_to(buf, format_str, args); | |
133 | return to_string(buf); | |
05aa7e19 JG |
134 | } |
135 | ||
8b75cd77 JG |
136 | template <typename... T> |
137 | auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { | |
138 | return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); | |
139 | } | |
140 | ||
bd9231e4 JG |
141 | template <typename OutputIt, typename... T> |
142 | auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args) | |
143 | -> OutputIt { | |
144 | return vformat_to(out, fmt::wstring_view(fmt), | |
145 | fmt::make_wformat_args(args...)); | |
146 | } | |
147 | ||
05aa7e19 JG |
148 | // Pass char_t as a default template parameter instead of using |
149 | // std::basic_string<char_t<S>> to reduce the symbol size. | |
bd9231e4 JG |
150 | template <typename S, typename... T, |
151 | typename Char = detail::format_string_char_t<S>, | |
8b75cd77 JG |
152 | FMT_ENABLE_IF(!std::is_same<Char, char>::value && |
153 | !std::is_same<Char, wchar_t>::value)> | |
bd9231e4 | 154 | auto format(const S& format_str, T&&... args) -> std::basic_string<Char> { |
8b75cd77 | 155 | return vformat(detail::to_string_view(format_str), |
bd9231e4 | 156 | fmt::make_format_args<buffered_context<Char>>(args...)); |
05aa7e19 JG |
157 | } |
158 | ||
bd9231e4 JG |
159 | template <typename Locale, typename S, |
160 | typename Char = detail::format_string_char_t<S>, | |
05aa7e19 JG |
161 | FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
162 | detail::is_exotic_char<Char>::value)> | |
bd9231e4 JG |
163 | inline auto vformat(const Locale& loc, const S& format_str, |
164 | typename detail::vformat_args<Char>::type args) | |
05aa7e19 | 165 | -> std::basic_string<Char> { |
8b75cd77 | 166 | return detail::vformat(loc, detail::to_string_view(format_str), args); |
05aa7e19 JG |
167 | } |
168 | ||
bd9231e4 JG |
169 | template <typename Locale, typename S, typename... T, |
170 | typename Char = detail::format_string_char_t<S>, | |
05aa7e19 JG |
171 | FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
172 | detail::is_exotic_char<Char>::value)> | |
bd9231e4 | 173 | inline auto format(const Locale& loc, const S& format_str, T&&... args) |
05aa7e19 | 174 | -> std::basic_string<Char> { |
bd9231e4 JG |
175 | return detail::vformat( |
176 | loc, detail::to_string_view(format_str), | |
177 | fmt::make_format_args<buffered_context<Char>>(args...)); | |
05aa7e19 JG |
178 | } |
179 | ||
bd9231e4 JG |
180 | template <typename OutputIt, typename S, |
181 | typename Char = detail::format_string_char_t<S>, | |
05aa7e19 JG |
182 | FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
183 | detail::is_exotic_char<Char>::value)> | |
184 | auto vformat_to(OutputIt out, const S& format_str, | |
bd9231e4 | 185 | typename detail::vformat_args<Char>::type args) -> OutputIt { |
05aa7e19 | 186 | auto&& buf = detail::get_buffer<Char>(out); |
8b75cd77 | 187 | detail::vformat_to(buf, detail::to_string_view(format_str), args); |
bd9231e4 | 188 | return detail::get_iterator(buf, out); |
05aa7e19 JG |
189 | } |
190 | ||
bd9231e4 JG |
191 | template <typename OutputIt, typename S, typename... T, |
192 | typename Char = detail::format_string_char_t<S>, | |
193 | FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value && | |
194 | !std::is_same<Char, char>::value && | |
195 | !std::is_same<Char, wchar_t>::value)> | |
196 | inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { | |
8b75cd77 | 197 | return vformat_to(out, detail::to_string_view(fmt), |
bd9231e4 | 198 | fmt::make_format_args<buffered_context<Char>>(args...)); |
05aa7e19 JG |
199 | } |
200 | ||
201 | template <typename Locale, typename S, typename OutputIt, typename... Args, | |
bd9231e4 | 202 | typename Char = detail::format_string_char_t<S>, |
05aa7e19 JG |
203 | FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
204 | detail::is_locale<Locale>::value&& | |
205 | detail::is_exotic_char<Char>::value)> | |
bd9231e4 JG |
206 | inline auto vformat_to(OutputIt out, const Locale& loc, const S& format_str, |
207 | typename detail::vformat_args<Char>::type args) | |
208 | -> OutputIt { | |
05aa7e19 | 209 | auto&& buf = detail::get_buffer<Char>(out); |
8b75cd77 JG |
210 | vformat_to(buf, detail::to_string_view(format_str), args, |
211 | detail::locale_ref(loc)); | |
bd9231e4 | 212 | return detail::get_iterator(buf, out); |
05aa7e19 JG |
213 | } |
214 | ||
bd9231e4 JG |
215 | template <typename OutputIt, typename Locale, typename S, typename... T, |
216 | typename Char = detail::format_string_char_t<S>, | |
217 | bool enable = detail::is_output_iterator<OutputIt, Char>::value && | |
218 | detail::is_locale<Locale>::value && | |
219 | detail::is_exotic_char<Char>::value> | |
05aa7e19 | 220 | inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, |
bd9231e4 | 221 | T&&... args) -> |
05aa7e19 | 222 | typename std::enable_if<enable, OutputIt>::type { |
bd9231e4 JG |
223 | return vformat_to(out, loc, detail::to_string_view(format_str), |
224 | fmt::make_format_args<buffered_context<Char>>(args...)); | |
05aa7e19 JG |
225 | } |
226 | ||
227 | template <typename OutputIt, typename Char, typename... Args, | |
228 | FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | |
229 | detail::is_exotic_char<Char>::value)> | |
bd9231e4 JG |
230 | inline auto vformat_to_n(OutputIt out, size_t n, |
231 | basic_string_view<Char> format_str, | |
232 | typename detail::vformat_args<Char>::type args) | |
05aa7e19 | 233 | -> format_to_n_result<OutputIt> { |
bd9231e4 JG |
234 | using traits = detail::fixed_buffer_traits; |
235 | auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n); | |
05aa7e19 JG |
236 | detail::vformat_to(buf, format_str, args); |
237 | return {buf.out(), buf.count()}; | |
238 | } | |
239 | ||
bd9231e4 JG |
240 | template <typename OutputIt, typename S, typename... T, |
241 | typename Char = detail::format_string_char_t<S>, | |
05aa7e19 JG |
242 | FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
243 | detail::is_exotic_char<Char>::value)> | |
bd9231e4 JG |
244 | inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) |
245 | -> format_to_n_result<OutputIt> { | |
246 | return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt), | |
247 | fmt::make_format_args<buffered_context<Char>>(args...)); | |
05aa7e19 JG |
248 | } |
249 | ||
bd9231e4 JG |
250 | template <typename S, typename... T, |
251 | typename Char = detail::format_string_char_t<S>, | |
05aa7e19 | 252 | FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> |
bd9231e4 JG |
253 | inline auto formatted_size(const S& fmt, T&&... args) -> size_t { |
254 | auto buf = detail::counting_buffer<Char>(); | |
8b75cd77 | 255 | detail::vformat_to(buf, detail::to_string_view(fmt), |
bd9231e4 | 256 | fmt::make_format_args<buffered_context<Char>>(args...)); |
05aa7e19 JG |
257 | return buf.count(); |
258 | } | |
259 | ||
260 | inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { | |
bd9231e4 JG |
261 | auto buf = wmemory_buffer(); |
262 | detail::vformat_to(buf, fmt, args); | |
263 | buf.push_back(L'\0'); | |
264 | if (std::fputws(buf.data(), f) == -1) | |
05aa7e19 JG |
265 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); |
266 | } | |
267 | ||
268 | inline void vprint(wstring_view fmt, wformat_args args) { | |
269 | vprint(stdout, fmt, args); | |
270 | } | |
271 | ||
272 | template <typename... T> | |
273 | void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { | |
274 | return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); | |
275 | } | |
276 | ||
277 | template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { | |
278 | return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); | |
279 | } | |
280 | ||
bd9231e4 JG |
281 | template <typename... T> |
282 | void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) { | |
283 | return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); | |
284 | } | |
285 | ||
286 | template <typename... T> void println(wformat_string<T...> fmt, T&&... args) { | |
287 | return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); | |
288 | } | |
289 | ||
290 | inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) | |
291 | -> std::wstring { | |
292 | auto buf = wmemory_buffer(); | |
293 | detail::vformat_to(buf, ts, fmt, args); | |
294 | return fmt::to_string(buf); | |
295 | } | |
296 | ||
297 | template <typename... T> | |
298 | inline auto format(const text_style& ts, wformat_string<T...> fmt, T&&... args) | |
299 | -> std::wstring { | |
300 | return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); | |
301 | } | |
302 | ||
303 | template <typename... T> | |
304 | FMT_DEPRECATED void print(std::FILE* f, const text_style& ts, | |
305 | wformat_string<T...> fmt, const T&... args) { | |
306 | vprint(f, ts, fmt, fmt::make_wformat_args(args...)); | |
307 | } | |
308 | ||
309 | template <typename... T> | |
310 | FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt, | |
311 | const T&... args) { | |
312 | return print(stdout, ts, fmt, args...); | |
313 | } | |
314 | ||
315 | /// Converts `value` to `std::wstring` using the default format for type `T`. | |
05aa7e19 JG |
316 | template <typename T> inline auto to_wstring(const T& value) -> std::wstring { |
317 | return format(FMT_STRING(L"{}"), value); | |
318 | } | |
bd9231e4 | 319 | FMT_END_EXPORT |
05aa7e19 JG |
320 | FMT_END_NAMESPACE |
321 | ||
322 | #endif // FMT_XCHAR_H_ |