]>
Commit | Line | Data |
---|---|---|
1d9454ab JW |
1 | // <format> Formatting -*- C++ -*- |
2 | ||
3 | // Copyright The GNU Toolchain Authors. | |
4 | // | |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
25 | /** @file include/format | |
26 | * This is a Standard C++ Library header. | |
27 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_FORMAT | |
30 | #define _GLIBCXX_FORMAT 1 | |
31 | ||
32 | #pragma GCC system_header | |
33 | ||
34 | #include <bits/requires_hosted.h> // for std::string | |
35 | ||
36 | #if __cplusplus >= 202002L | |
37 | ||
38 | #include <array> | |
39 | #include <charconv> | |
40 | #include <concepts> | |
41 | #include <limits> | |
42 | #include <locale> | |
43 | #include <optional> | |
44 | #include <span> | |
45 | #include <string_view> | |
46 | #include <string> | |
47 | #include <variant> // monostate (TODO: move to bits/utility.h?) | |
48 | #include <bits/ranges_base.h> // input_range, range_reference_t | |
49 | #include <bits/ranges_algobase.h> // ranges::copy | |
50 | #include <bits/stl_iterator.h> // back_insert_iterator | |
51 | #include <bits/stl_pair.h> // __is_pair | |
52 | #include <bits/utility.h> // tuple_size_v | |
53 | #include <ext/numeric_traits.h> // __int_traits | |
54 | ||
2f5c0718 JW |
55 | #if !__has_builtin(__builtin_toupper) |
56 | # include <cctype> | |
57 | #endif | |
58 | ||
1d9454ab JW |
59 | namespace std _GLIBCXX_VISIBILITY(default) |
60 | { | |
61 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
62 | ||
63 | // 201907 Text Formatting, Integration of chrono, printf corner cases. | |
64 | // 202106 std::format improvements. | |
65 | // 202110 Fixing locale handling in chrono formatters, generator-like types. | |
66 | // 202207 Encodings in localized formatting of chrono, basic-format-string. | |
67 | #define __cpp_lib_format 202106L | |
68 | ||
69 | #if __cplusplus > 202002L | |
70 | // 202207 P2286R8 Formatting Ranges | |
71 | // 202207 P2585R1 Improving default container formatting | |
72 | // TODO: #define __cpp_lib_format_ranges 202207L | |
73 | #endif | |
74 | ||
75 | // [format.context], class template basic_format_context | |
76 | template<typename _Out, typename _CharT> class basic_format_context; | |
77 | ||
78 | /// @cond undocumented | |
79 | namespace __format | |
80 | { | |
81 | // Type-erased character sink. | |
b9e5a4b4 | 82 | template<typename _CharT> class _Sink; |
1d9454ab JW |
83 | // Output iterator that writes to a type-erase character sink. |
84 | template<typename _CharT> | |
85 | class _Sink_iter; | |
86 | } // namespace __format | |
87 | /// @endcond | |
88 | ||
89 | using format_context | |
90 | = basic_format_context<__format::_Sink_iter<char>, char>; | |
91 | using wformat_context | |
92 | = basic_format_context<__format::_Sink_iter<wchar_t>, wchar_t>; | |
93 | ||
94 | // [format.args], class template basic_format_args | |
95 | template<typename _Context> class basic_format_args; | |
96 | using format_args = basic_format_args<format_context>; | |
97 | using wformat_args = basic_format_args<wformat_context>; | |
98 | ||
99 | // [format.arguments], arguments | |
100 | // [format.arg], class template basic_format_arg | |
101 | template<typename _Context> | |
102 | class basic_format_arg; | |
103 | ||
104 | // [format.fmt.string], class template basic_format_string | |
105 | ||
106 | /** A compile-time checked format string for the specified argument types. | |
107 | * | |
108 | * @since C++23 but available as an extension in C++20. | |
109 | */ | |
110 | template<typename _CharT, typename... _Args> | |
111 | struct basic_format_string | |
112 | { | |
6c0f9584 JW |
113 | template<typename _Tp> |
114 | requires convertible_to<const _Tp&, basic_string_view<_CharT>> | |
1d9454ab JW |
115 | consteval |
116 | basic_format_string(const _Tp& __s); | |
117 | ||
118 | [[__gnu__::__always_inline__]] | |
119 | constexpr basic_string_view<_CharT> | |
120 | get() const noexcept | |
121 | { return _M_str; } | |
122 | ||
123 | private: | |
124 | basic_string_view<_CharT> _M_str; | |
125 | }; | |
126 | ||
127 | template<typename... _Args> | |
128 | using format_string = basic_format_string<char, type_identity_t<_Args>...>; | |
129 | ||
130 | template<typename... _Args> | |
131 | using wformat_string | |
132 | = basic_format_string<wchar_t, type_identity_t<_Args>...>; | |
133 | ||
134 | // [format.formatter], formatter | |
135 | ||
136 | /// The primary template of std::formatter is disabled. | |
137 | template<typename _Tp, typename _CharT = char> | |
138 | struct formatter | |
139 | { | |
6a9547f3 | 140 | formatter() = delete; // No std::formatter specialization for this type. |
1d9454ab JW |
141 | formatter(const formatter&) = delete; |
142 | formatter& operator=(const formatter&) = delete; | |
143 | }; | |
144 | ||
145 | // [format.error], class format_error | |
146 | class format_error : public runtime_error | |
147 | { | |
148 | public: | |
149 | explicit format_error(const string& __what) : runtime_error(__what) { } | |
150 | explicit format_error(const char* __what) : runtime_error(__what) { } | |
151 | }; | |
152 | ||
153 | /// @cond undocumented | |
154 | [[noreturn]] | |
155 | inline void | |
156 | __throw_format_error(const char* __what) | |
157 | { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); } | |
158 | ||
159 | namespace __format | |
160 | { | |
161 | // XXX use named functions for each constexpr error? | |
162 | ||
163 | [[noreturn]] | |
164 | inline void | |
165 | __unmatched_left_brace_in_format_string() | |
166 | { __throw_format_error("format error: unmatched '{' in format string"); } | |
167 | ||
168 | [[noreturn]] | |
169 | inline void | |
170 | __unmatched_right_brace_in_format_string() | |
171 | { __throw_format_error("format error: unmatched '}' in format string"); } | |
172 | ||
173 | [[noreturn]] | |
174 | inline void | |
175 | __conflicting_indexing_in_format_string() | |
176 | { __throw_format_error("format error: conflicting indexing style in format string"); } | |
177 | ||
178 | [[noreturn]] | |
179 | inline void | |
180 | __invalid_arg_id_in_format_string() | |
181 | { __throw_format_error("format error: invalid arg-id in format string"); } | |
182 | ||
183 | [[noreturn]] | |
184 | inline void | |
185 | __failed_to_parse_format_spec() | |
186 | { __throw_format_error("format error: failed to parse format-spec"); } | |
187 | } // namespace __format | |
481281cc | 188 | /// @endcond |
1d9454ab JW |
189 | |
190 | // [format.parse.ctx], class template basic_format_parse_context | |
191 | template<typename _CharT> class basic_format_parse_context; | |
192 | using format_parse_context = basic_format_parse_context<char>; | |
193 | using wformat_parse_context = basic_format_parse_context<wchar_t>; | |
194 | ||
195 | template<typename _CharT> | |
196 | class basic_format_parse_context | |
197 | { | |
198 | public: | |
199 | using char_type = _CharT; | |
200 | using const_iterator = typename basic_string_view<_CharT>::const_iterator; | |
201 | using iterator = const_iterator; | |
202 | ||
203 | constexpr explicit | |
204 | basic_format_parse_context(basic_string_view<_CharT> __fmt, | |
205 | size_t __num_args = 0) noexcept | |
206 | : _M_begin(__fmt.begin()), _M_end(__fmt.end()), _M_num_args(__num_args) | |
207 | { } | |
208 | ||
209 | basic_format_parse_context(const basic_format_parse_context&) = delete; | |
210 | void operator=(const basic_format_parse_context&) = delete; | |
211 | ||
212 | constexpr const_iterator begin() const noexcept { return _M_begin; } | |
213 | constexpr const_iterator end() const noexcept { return _M_end; } | |
214 | ||
215 | constexpr void | |
216 | advance_to(const_iterator __it) noexcept | |
217 | { _M_begin = __it; } | |
218 | ||
219 | constexpr size_t | |
220 | next_arg_id() | |
221 | { | |
222 | if (_M_indexing == _Manual) | |
223 | __format::__conflicting_indexing_in_format_string(); | |
224 | _M_indexing = _Auto; | |
48e21e87 JW |
225 | |
226 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
227 | // 3825. Missing compile-time argument id check in next_arg_id | |
228 | if (std::is_constant_evaluated()) | |
1d9454ab JW |
229 | if (_M_next_arg_id == _M_num_args) |
230 | __format::__invalid_arg_id_in_format_string(); | |
231 | return _M_next_arg_id++; | |
232 | } | |
233 | ||
234 | constexpr void | |
235 | check_arg_id(size_t __id) | |
236 | { | |
237 | if (_M_indexing == _Auto) | |
238 | __format::__conflicting_indexing_in_format_string(); | |
239 | _M_indexing = _Manual; | |
240 | ||
48e21e87 | 241 | if (std::is_constant_evaluated()) |
1d9454ab JW |
242 | if (__id >= _M_num_args) |
243 | __format::__invalid_arg_id_in_format_string(); | |
244 | } | |
245 | ||
246 | private: | |
247 | iterator _M_begin; | |
248 | iterator _M_end; | |
249 | enum _Indexing { _Unknown, _Manual, _Auto }; | |
250 | _Indexing _M_indexing = _Unknown; | |
251 | size_t _M_next_arg_id = 0; | |
252 | size_t _M_num_args; | |
253 | }; | |
254 | ||
255 | /// @cond undocumented | |
256 | template<typename _Tp, template<typename...> class _Class> | |
257 | static constexpr bool __is_specialization_of = false; | |
258 | template<template<typename...> class _Class, typename... _Args> | |
259 | static constexpr bool __is_specialization_of<_Class<_Args...>, _Class> | |
260 | = true; | |
261 | ||
262 | namespace __format | |
263 | { | |
264 | // pre: first != last | |
265 | template<typename _CharT> | |
266 | constexpr pair<unsigned short, const _CharT*> | |
267 | __parse_integer(const _CharT* __first, const _CharT* __last) | |
268 | { | |
269 | if (__first == __last) | |
270 | __builtin_unreachable(); | |
271 | ||
1d9454ab JW |
272 | if constexpr (is_same_v<_CharT, char>) |
273 | { | |
3bb9f932 JW |
274 | const auto __start = __first; |
275 | unsigned short __val = 0; | |
276 | // N.B. std::from_chars is not constexpr in C++20. | |
277 | if (__detail::__from_chars_alnum<true>(__first, __last, __val, 10) | |
278 | && __first != __start) [[likely]] | |
279 | return {__val, __first}; | |
1d9454ab JW |
280 | } |
281 | else | |
282 | { | |
18169e8e | 283 | constexpr int __n = 32; |
1d9454ab | 284 | char __buf[__n]{}; |
3bb9f932 | 285 | for (int __i = 0; __i < __n && (__first + __i) != __last; ++__i) |
1d9454ab JW |
286 | __buf[__i] = __first[__i]; |
287 | auto [__v, __ptr] = __format::__parse_integer(__buf, __buf + __n); | |
288 | return {__v, __first + (__ptr - __buf)}; | |
289 | } | |
3bb9f932 | 290 | return {0, nullptr}; |
1d9454ab JW |
291 | } |
292 | ||
293 | template<typename _CharT> | |
294 | constexpr pair<unsigned short, const _CharT*> | |
295 | __parse_arg_id(const _CharT* __first, const _CharT* __last) | |
296 | { | |
297 | if (__first == __last) | |
298 | __builtin_unreachable(); | |
299 | ||
300 | if (*__first == '0') | |
301 | return {0, __first + 1}; // No leading zeros allowed, so '0...' == 0 | |
302 | ||
303 | if ('1' <= *__first && *__first <= '9') | |
304 | { | |
305 | const unsigned short __id = *__first - '0'; | |
306 | const auto __next = __first + 1; | |
307 | // Optimize for most likely case of single digit arg-id. | |
308 | if (__next == __last || !('0' <= *__next && *__next <= '9')) | |
309 | return {__id, __next}; | |
310 | else | |
311 | return __format::__parse_integer(__first, __last); | |
312 | } | |
313 | return {0, nullptr}; | |
314 | } | |
315 | ||
316 | enum _Pres_type { | |
317 | _Pres_none = 0, // Default type (not valid for integer presentation types). | |
318 | // Presentation types for integral types (including bool and charT). | |
319 | _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c, | |
320 | // Presentation types for floating-point types. | |
321 | _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_g, _Pres_G, | |
322 | _Pres_p = 0, _Pres_P, // For pointers. | |
323 | _Pres_s = 0, // For strings and bool. | |
324 | _Pres_esc = 0xf, // For strings and charT. | |
325 | }; | |
326 | ||
327 | enum _Align { | |
328 | _Align_default, | |
329 | _Align_left, | |
330 | _Align_right, | |
331 | _Align_centre, | |
332 | }; | |
333 | ||
334 | enum _Sign { | |
335 | _Sign_default, | |
336 | _Sign_plus, | |
337 | _Sign_minus, // XXX does this need to be distinct from _Sign_default? | |
338 | _Sign_space, | |
339 | }; | |
340 | ||
341 | enum _WidthPrec { | |
342 | _WP_none, // No width/prec specified. | |
343 | _WP_value, // Fixed width/prec specified. | |
344 | _WP_from_arg // Use a formatting argument for width/prec. | |
345 | }; | |
346 | ||
347 | template<typename _Context> | |
348 | size_t | |
349 | __int_from_arg(const basic_format_arg<_Context>& __arg); | |
350 | ||
dfc1ea41 JW |
351 | constexpr bool __is_digit(char __c) |
352 | { return std::__detail::__from_chars_alnum_to_val(__c) < 10; } | |
353 | ||
354 | constexpr bool __is_xdigit(char __c) | |
355 | { return std::__detail::__from_chars_alnum_to_val(__c) < 16; } | |
356 | ||
1d9454ab JW |
357 | template<typename _CharT> |
358 | struct _Spec | |
359 | { | |
360 | _Align _M_align : 2; | |
361 | _Sign _M_sign : 2; | |
362 | unsigned _M_alt : 1; | |
363 | unsigned _M_localized : 1; | |
364 | unsigned _M_zero_fill : 1; | |
365 | _WidthPrec _M_width_kind : 2; | |
366 | _WidthPrec _M_prec_kind : 2; | |
367 | _Pres_type _M_type : 4; | |
368 | unsigned short _M_width; | |
369 | unsigned short _M_prec; | |
370 | _CharT _M_fill = ' '; | |
371 | ||
372 | using iterator = typename basic_string_view<_CharT>::iterator; | |
373 | ||
374 | static constexpr _Align | |
375 | _S_align(_CharT __c) noexcept | |
376 | { | |
377 | switch (__c) | |
378 | { | |
379 | case '<': return _Align_left; | |
380 | case '>': return _Align_right; | |
381 | case '^': return _Align_centre; | |
382 | default: return _Align_default; | |
383 | } | |
384 | } | |
385 | ||
386 | // pre: __first != __last | |
387 | constexpr iterator | |
388 | _M_parse_fill_and_align(iterator __first, iterator __last) noexcept | |
389 | { | |
390 | if (*__first != '{') | |
391 | { | |
392 | // TODO: accept any UCS scalar value as fill character. | |
393 | // If narrow source encoding is UTF-8 then accept multibyte char. | |
394 | if (__last - __first >= 2) | |
395 | { | |
396 | if (_Align __align = _S_align(__first[1])) | |
397 | { | |
398 | _M_fill = *__first; | |
399 | _M_align = __align; | |
400 | return __first + 2; | |
401 | } | |
402 | } | |
403 | ||
404 | if (_Align __align = _S_align(__first[0])) | |
405 | { | |
406 | _M_fill = ' '; | |
407 | _M_align = __align; | |
408 | return __first + 1; | |
409 | } | |
410 | } | |
411 | return __first; | |
412 | } | |
413 | ||
414 | static constexpr _Sign | |
415 | _S_sign(_CharT __c) noexcept | |
416 | { | |
417 | switch (__c) | |
418 | { | |
419 | case '+': return _Sign_plus; | |
420 | case '-': return _Sign_minus; | |
421 | case ' ': return _Sign_space; | |
422 | default: return _Sign_default; | |
423 | } | |
424 | } | |
425 | ||
426 | // pre: __first != __last | |
427 | constexpr iterator | |
428 | _M_parse_sign(iterator __first, iterator) noexcept | |
429 | { | |
430 | if (_Sign __sign = _S_sign(*__first)) | |
431 | { | |
432 | _M_sign = __sign; | |
433 | return __first + 1; | |
434 | } | |
435 | return __first; | |
436 | } | |
437 | ||
438 | // pre: *__first is valid | |
439 | constexpr iterator | |
440 | _M_parse_alternate_form(iterator __first, iterator) noexcept | |
441 | { | |
442 | if (*__first == '#') | |
443 | { | |
444 | _M_alt = true; | |
445 | ++__first; | |
446 | } | |
447 | return __first; | |
448 | } | |
449 | ||
450 | // pre: __first != __last | |
451 | constexpr iterator | |
452 | _M_parse_zero_fill(iterator __first, iterator /* __last */) noexcept | |
453 | { | |
454 | if (*__first == '0') | |
455 | { | |
456 | _M_zero_fill = true; | |
457 | ++__first; | |
458 | } | |
459 | return __first; | |
460 | } | |
461 | ||
462 | // pre: __first != __last | |
463 | static constexpr iterator | |
464 | _S_parse_width_or_precision(iterator __first, iterator __last, | |
465 | unsigned short& __val, bool& __arg_id, | |
466 | basic_format_parse_context<_CharT>& __pc) | |
467 | { | |
dfc1ea41 | 468 | if (__format::__is_digit(*__first)) |
1d9454ab JW |
469 | { |
470 | auto [__v, __ptr] = __format::__parse_integer(__first, __last); | |
471 | if (!__ptr) | |
472 | __throw_format_error("format error: invalid width or precision " | |
473 | "in format-spec"); | |
474 | __first = __ptr; | |
475 | __val = __v; | |
476 | } | |
477 | else if (*__first == '{') | |
478 | { | |
479 | __arg_id = true; | |
480 | ++__first; | |
481 | if (__first == __last) | |
482 | __format::__unmatched_left_brace_in_format_string(); | |
483 | if (*__first == '}') | |
484 | __val = __pc.next_arg_id(); | |
485 | else | |
486 | { | |
487 | auto [__v, __ptr] = __format::__parse_arg_id(__first, __last); | |
488 | if (__ptr == nullptr || __ptr == __last || *__ptr != '}') | |
489 | __format::__invalid_arg_id_in_format_string(); | |
490 | __first = __ptr; | |
491 | __pc.check_arg_id(__v); | |
492 | __val = __v; | |
493 | } | |
494 | ++__first; // past the '}' | |
495 | } | |
496 | return __first; | |
497 | } | |
498 | ||
499 | // pre: __first != __last | |
500 | constexpr iterator | |
501 | _M_parse_width(iterator __first, iterator __last, | |
502 | basic_format_parse_context<_CharT>& __pc) | |
503 | { | |
504 | bool __arg_id = false; | |
505 | if (*__first == '0') | |
506 | __throw_format_error("format error: width must be non-zero in " | |
507 | "format string"); | |
508 | auto __next = _S_parse_width_or_precision(__first, __last, _M_width, | |
509 | __arg_id, __pc); | |
510 | if (__next != __first) | |
511 | _M_width_kind = __arg_id ? _WP_from_arg : _WP_value; | |
512 | return __next; | |
513 | } | |
514 | ||
515 | // pre: __first != __last | |
516 | constexpr iterator | |
517 | _M_parse_precision(iterator __first, iterator __last, | |
518 | basic_format_parse_context<_CharT>& __pc) | |
519 | { | |
520 | if (__first[0] != '.') | |
521 | return __first; | |
522 | ||
ecfd8c7f | 523 | iterator __next = ++__first; |
1d9454ab | 524 | bool __arg_id = false; |
ecfd8c7f JW |
525 | if (__next != __last) |
526 | __next = _S_parse_width_or_precision(__first, __last, _M_prec, | |
527 | __arg_id, __pc); | |
1d9454ab JW |
528 | if (__next == __first) |
529 | __throw_format_error("format error: missing precision after '.' in " | |
530 | "format string"); | |
531 | _M_prec_kind = __arg_id ? _WP_from_arg : _WP_value; | |
532 | return __next; | |
533 | } | |
534 | ||
535 | // pre: __first != __last | |
536 | constexpr iterator | |
537 | _M_parse_locale(iterator __first, iterator /* __last */) noexcept | |
538 | { | |
539 | if (*__first == 'L') | |
540 | { | |
541 | _M_localized = true; | |
542 | ++__first; | |
543 | } | |
544 | return __first; | |
545 | } | |
546 | ||
547 | template<typename _Context> | |
548 | size_t | |
549 | _M_get_width(_Context& __ctx) const | |
550 | { | |
551 | size_t __width = 0; | |
552 | if (_M_width_kind == _WP_value) | |
553 | __width = _M_width; | |
554 | else if (_M_width_kind == _WP_from_arg) | |
555 | __width = __format::__int_from_arg(__ctx.arg(_M_width)); | |
556 | return __width; | |
557 | } | |
558 | ||
559 | template<typename _Context> | |
560 | size_t | |
561 | _M_get_precision(_Context& __ctx) const | |
562 | { | |
563 | size_t __prec = -1; | |
564 | if (_M_prec_kind == _WP_value) | |
565 | __prec = _M_prec; | |
566 | else if (_M_prec_kind == _WP_from_arg) | |
567 | __prec = __format::__int_from_arg(__ctx.arg(_M_prec)); | |
568 | return __prec; | |
569 | } | |
570 | }; | |
571 | ||
572 | template<typename _Int> | |
573 | inline char* | |
574 | __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept | |
575 | { | |
576 | if (__i < 0) | |
577 | *__dest = '-'; | |
578 | else if (__sign == _Sign_plus) | |
579 | *__dest = '+'; | |
580 | else if (__sign == _Sign_space) | |
581 | *__dest = ' '; | |
582 | else | |
583 | ++__dest; | |
584 | return __dest; | |
585 | } | |
586 | ||
9247402a | 587 | // Write STR to OUT (and do so efficiently if OUT is a _Sink_iter). |
1d9454ab JW |
588 | template<typename _Out, typename _CharT> |
589 | requires output_iterator<_Out, const _CharT&> | |
590 | inline _Out | |
591 | __write(_Out __out, basic_string_view<_CharT> __str) | |
592 | { | |
593 | if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) | |
594 | { | |
595 | if (__str.size()) | |
596 | __out = __str; | |
597 | } | |
598 | else | |
599 | for (_CharT __c : __str) | |
600 | *__out++ = __c; | |
6c0f9584 | 601 | return __out; |
1d9454ab JW |
602 | } |
603 | ||
604 | // Write STR to OUT with NFILL copies of FILL_CHAR specified by ALIGN. | |
605 | // pre: __align != _Align_default | |
606 | template<typename _Out, typename _CharT> | |
607 | _Out | |
608 | __write_padded(_Out __out, basic_string_view<_CharT> __str, | |
609 | _Align __align, size_t __nfill, _CharT __fill_char) | |
610 | { | |
611 | const size_t __buflen = 0x20; | |
612 | _CharT __padding_chars[__buflen]; | |
2af0f4c3 | 613 | __padding_chars[0] = _CharT(); |
1d9454ab JW |
614 | basic_string_view<_CharT> __padding{__padding_chars, __buflen}; |
615 | ||
616 | auto __pad = [&__padding] (size_t __n, _Out& __o) { | |
617 | if (__n == 0) | |
618 | return; | |
619 | while (__n > __padding.size()) | |
620 | { | |
621 | __o = __format::__write(std::move(__o), __padding); | |
622 | __n -= __padding.size(); | |
623 | } | |
624 | if (__n != 0) | |
625 | __o = __format::__write(std::move(__o), __padding.substr(0, __n)); | |
626 | }; | |
627 | ||
628 | size_t __l, __r, __max; | |
629 | if (__align == _Align_centre) | |
630 | { | |
631 | __l = __nfill / 2; | |
632 | __r = __l + (__nfill & 1); | |
633 | __max = __r; | |
634 | } | |
635 | else if (__align == _Align_right) | |
636 | { | |
637 | __l = __nfill; | |
638 | __r = 0; | |
639 | __max = __l; | |
640 | } | |
641 | else | |
642 | { | |
643 | __l = 0; | |
644 | __r = __nfill; | |
645 | __max = __r; | |
646 | } | |
647 | if (__max < __buflen) | |
648 | __padding.remove_suffix(__buflen - __max); | |
649 | else | |
650 | __max = __buflen; | |
651 | char_traits<_CharT>::assign(__padding_chars, __max, __fill_char); | |
652 | ||
653 | __pad(__l, __out); | |
654 | __out = __format::__write(std::move(__out), __str); | |
655 | __pad(__r, __out); | |
656 | ||
6c0f9584 | 657 | return __out; |
1d9454ab JW |
658 | } |
659 | ||
9247402a JW |
660 | // Write STR to OUT, with alignment and padding as determined by SPEC. |
661 | // pre: __spec._M_align != _Align_default || __align != _Align_default | |
662 | template<typename _CharT, typename _Out> | |
663 | _Out | |
664 | __write_padded_as_spec(basic_string_view<type_identity_t<_CharT>> __str, | |
665 | size_t __estimated_width, | |
666 | basic_format_context<_Out, _CharT>& __fc, | |
667 | const _Spec<_CharT>& __spec, | |
668 | _Align __align = _Align_left) | |
669 | { | |
670 | size_t __width = __spec._M_get_width(__fc); | |
671 | ||
672 | if (__width <= __estimated_width) | |
673 | return __format::__write(__fc.out(), __str); | |
674 | ||
675 | const size_t __nfill = __width - __estimated_width; | |
676 | ||
677 | if (__spec._M_align) | |
678 | __align = __spec._M_align; | |
679 | ||
680 | return __format::__write_padded(__fc.out(), __str, __align, __nfill, | |
681 | __spec._M_fill); | |
682 | } | |
683 | ||
1d9454ab JW |
684 | // A lightweight optional<locale>. |
685 | struct _Optional_locale | |
686 | { | |
687 | [[__gnu__::__always_inline__]] | |
688 | _Optional_locale() : _M_dummy(), _M_hasval(false) { } | |
689 | ||
690 | _Optional_locale(const locale& __loc) noexcept | |
691 | : _M_loc(__loc), _M_hasval(true) | |
692 | { } | |
693 | ||
694 | _Optional_locale(const _Optional_locale& __l) noexcept | |
695 | : _M_dummy(), _M_hasval(__l._M_hasval) | |
696 | { | |
697 | if (_M_hasval) | |
698 | std::construct_at(&_M_loc, __l._M_loc); | |
699 | } | |
700 | ||
701 | _Optional_locale& | |
702 | operator=(const _Optional_locale& __l) noexcept | |
703 | { | |
704 | if (_M_hasval) | |
705 | { | |
706 | if (__l._M_hasval) | |
707 | _M_loc = __l._M_loc; | |
708 | else | |
709 | { | |
710 | _M_loc.~locale(); | |
711 | _M_hasval = false; | |
712 | } | |
713 | } | |
714 | else if (__l._M_hasval) | |
715 | { | |
716 | std::construct_at(&_M_loc, __l._M_loc); | |
717 | _M_hasval = true; | |
718 | } | |
719 | return *this; | |
720 | } | |
721 | ||
722 | ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); } | |
723 | ||
724 | _Optional_locale& | |
725 | operator=(locale&& __loc) noexcept | |
726 | { | |
727 | if (_M_hasval) | |
728 | _M_loc = std::move(__loc); | |
729 | else | |
730 | { | |
731 | std::construct_at(&_M_loc, std::move(__loc)); | |
732 | _M_hasval = true; | |
733 | } | |
734 | return *this; | |
735 | } | |
736 | ||
737 | const locale& | |
738 | value() noexcept | |
739 | { | |
740 | if (!_M_hasval) | |
741 | { | |
742 | std::construct_at(&_M_loc); | |
743 | _M_hasval = true; | |
744 | } | |
745 | return _M_loc; | |
746 | } | |
747 | ||
748 | bool has_value() const noexcept { return _M_hasval; } | |
749 | ||
750 | union { | |
751 | char _M_dummy = '\0'; | |
752 | std::locale _M_loc; | |
753 | }; | |
754 | bool _M_hasval = false; | |
755 | }; | |
756 | ||
757 | template<typename _CharT> | |
758 | concept __char = same_as<_CharT, char> || same_as<_CharT, wchar_t>; | |
759 | ||
760 | template<__char _CharT> | |
761 | struct __formatter_str | |
762 | { | |
763 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
764 | parse(basic_format_parse_context<_CharT>& __pc) | |
765 | { | |
766 | auto __first = __pc.begin(); | |
767 | const auto __last = __pc.end(); | |
768 | _Spec<_CharT> __spec{}; | |
769 | ||
770 | auto __finalize = [this, &__spec] { | |
771 | _M_spec = __spec; | |
772 | }; | |
773 | ||
774 | auto __finished = [&] { | |
775 | if (__first == __last || *__first == '}') | |
776 | { | |
777 | __finalize(); | |
778 | return true; | |
779 | } | |
780 | return false; | |
781 | }; | |
782 | ||
783 | if (__finished()) | |
784 | return __first; | |
785 | ||
786 | __first = __spec._M_parse_fill_and_align(__first, __last); | |
787 | if (__finished()) | |
788 | return __first; | |
789 | ||
790 | __first = __spec._M_parse_width(__first, __last, __pc); | |
791 | if (__finished()) | |
792 | return __first; | |
793 | ||
794 | __first = __spec._M_parse_precision(__first, __last, __pc); | |
795 | if (__finished()) | |
796 | return __first; | |
797 | ||
798 | if (*__first == 's') | |
799 | ++__first; | |
800 | #if __cpp_lib_format_ranges | |
801 | else if (*__first == '?') | |
802 | { | |
803 | __spec._M_type = _Pres_esc; | |
804 | ++__first; | |
805 | } | |
806 | #endif | |
807 | ||
808 | if (__finished()) | |
809 | return __first; | |
810 | ||
811 | __format::__failed_to_parse_format_spec(); | |
812 | } | |
813 | ||
814 | template<typename _Out> | |
9247402a | 815 | _Out |
1d9454ab JW |
816 | format(basic_string_view<_CharT> __s, |
817 | basic_format_context<_Out, _CharT>& __fc) const | |
818 | { | |
819 | if (_M_spec._M_type == _Pres_esc) | |
820 | { | |
628ba410 | 821 | // TODO: C++23 escaped string presentation |
1d9454ab JW |
822 | } |
823 | ||
824 | if (_M_spec._M_width_kind == _WP_none | |
825 | && _M_spec._M_prec_kind == _WP_none) | |
826 | return __format::__write(__fc.out(), __s); | |
827 | ||
828 | size_t __estimated_width = __s.size(); // TODO: Unicode-aware estim. | |
829 | ||
830 | if (_M_spec._M_prec_kind != _WP_none) | |
831 | { | |
832 | size_t __prec = _M_spec._M_get_precision(__fc); | |
833 | if (__estimated_width > __prec) | |
834 | { | |
835 | __s = __s.substr(0, __prec); // TODO: do not split code points | |
836 | __estimated_width = __prec; | |
837 | } | |
838 | } | |
839 | ||
9247402a JW |
840 | return __format::__write_padded_as_spec(__s, __estimated_width, |
841 | __fc, _M_spec); | |
1d9454ab JW |
842 | } |
843 | ||
844 | #if __cpp_lib_format_ranges | |
845 | constexpr void | |
846 | set_debug_format() noexcept | |
847 | { _M_spec._M_type = _Pres_esc; } | |
848 | #endif | |
849 | ||
850 | private: | |
851 | _Spec<_CharT> _M_spec{}; | |
852 | }; | |
853 | ||
854 | template<__char _CharT> | |
855 | struct __formatter_int | |
856 | { | |
857 | // If no presentation type is specified, meaning of "none" depends | |
858 | // whether we are formatting an integer or a char or a bool. | |
859 | static constexpr _Pres_type _AsInteger = _Pres_d; | |
860 | static constexpr _Pres_type _AsBool = _Pres_s; | |
861 | static constexpr _Pres_type _AsChar = _Pres_c; | |
862 | ||
863 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
864 | _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type) | |
865 | { | |
866 | _Spec<_CharT> __spec{}; | |
867 | __spec._M_type = __type; | |
868 | ||
869 | const auto __last = __pc.end(); | |
870 | auto __first = __pc.begin(); | |
871 | ||
872 | auto __finalize = [this, &__spec] { | |
873 | _M_spec = __spec; | |
874 | }; | |
875 | ||
876 | auto __finished = [&] { | |
877 | if (__first == __last || *__first == '}') | |
878 | { | |
879 | __finalize(); | |
880 | return true; | |
881 | } | |
882 | return false; | |
883 | }; | |
884 | ||
885 | if (__finished()) | |
886 | return __first; | |
887 | ||
888 | __first = __spec._M_parse_fill_and_align(__first, __last); | |
889 | if (__finished()) | |
890 | return __first; | |
891 | ||
892 | __first = __spec._M_parse_sign(__first, __last); | |
893 | if (__finished()) | |
894 | return __first; | |
895 | ||
896 | __first = __spec._M_parse_alternate_form(__first, __last); | |
897 | if (__finished()) | |
898 | return __first; | |
899 | ||
900 | __first = __spec._M_parse_zero_fill(__first, __last); | |
901 | if (__finished()) | |
902 | return __first; | |
903 | ||
904 | __first = __spec._M_parse_width(__first, __last, __pc); | |
905 | if (__finished()) | |
906 | return __first; | |
907 | ||
908 | __first = __spec._M_parse_locale(__first, __last); | |
909 | if (__finished()) | |
910 | return __first; | |
911 | ||
912 | switch (*__first) | |
913 | { | |
914 | case 'b': | |
915 | __spec._M_type = _Pres_b; | |
916 | ++__first; | |
917 | break; | |
918 | case 'B': | |
919 | __spec._M_type = _Pres_B; | |
920 | ++__first; | |
921 | break; | |
922 | case 'c': | |
923 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
924 | // 3586. format should not print bool with 'c' | |
925 | if (__type != _AsBool) | |
926 | { | |
927 | __spec._M_type = _Pres_c; | |
928 | ++__first; | |
929 | } | |
930 | break; | |
931 | case 'd': | |
932 | __spec._M_type = _Pres_d; | |
933 | ++__first; | |
934 | break; | |
935 | case 'o': | |
936 | __spec._M_type = _Pres_o; | |
937 | ++__first; | |
938 | break; | |
939 | case 'x': | |
940 | __spec._M_type = _Pres_x; | |
941 | ++__first; | |
942 | break; | |
943 | case 'X': | |
944 | __spec._M_type = _Pres_X; | |
945 | ++__first; | |
946 | break; | |
947 | case 's': | |
948 | if (__type == _AsBool) | |
949 | { | |
950 | __spec._M_type = _Pres_s; // same value (and meaning) as "none" | |
951 | ++__first; | |
952 | } | |
953 | break; | |
954 | #if __cpp_lib_format_ranges | |
955 | case '?': | |
956 | if (__type == _AsChar) | |
957 | { | |
958 | __spec._M_type = _Pres_esc; | |
959 | ++__first; | |
960 | } | |
961 | #endif | |
962 | break; | |
963 | } | |
964 | ||
965 | if (__finished()) | |
966 | return __first; | |
967 | ||
968 | __format::__failed_to_parse_format_spec(); | |
969 | } | |
970 | ||
971 | template<typename _Tp> | |
972 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
973 | _M_parse(basic_format_parse_context<_CharT>& __pc) | |
974 | { | |
975 | if constexpr (is_same_v<_Tp, bool>) | |
976 | { | |
977 | auto __end = _M_do_parse(__pc, _AsBool); | |
978 | if (_M_spec._M_type == _Pres_s) | |
979 | if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill) | |
980 | __throw_format_error("format error: format-spec contains " | |
981 | "invalid formatting options for " | |
982 | "'bool'"); | |
983 | return __end; | |
984 | } | |
985 | else if constexpr (__char<_Tp>) | |
986 | { | |
987 | auto __end = _M_do_parse(__pc, _AsChar); | |
988 | if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc) | |
989 | if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill | |
990 | /* XXX should be invalid? || _M_spec._M_localized */) | |
991 | __throw_format_error("format error: format-spec contains " | |
992 | "invalid formatting options for " | |
993 | "'charT'"); | |
994 | return __end; | |
995 | } | |
996 | else | |
997 | return _M_do_parse(__pc, _AsInteger); | |
998 | } | |
999 | ||
1000 | template<typename _Int, typename _Out> | |
1001 | typename basic_format_context<_Out, _CharT>::iterator | |
1002 | format(_Int __i, basic_format_context<_Out, _CharT>& __fc) const | |
1003 | { | |
1004 | if (_M_spec._M_type == _Pres_c) | |
1005 | return _M_format_character(_S_to_character(__i), __fc); | |
1006 | ||
1007 | char __buf[sizeof(_Int) * __CHAR_BIT__ + 3]; | |
1008 | to_chars_result __res{}; | |
1009 | ||
1010 | string_view __base_prefix; | |
1011 | make_unsigned_t<_Int> __u; | |
1012 | if (__i < 0) | |
1013 | __u = -static_cast<make_unsigned_t<_Int>>(__i); | |
1014 | else | |
1015 | __u = __i; | |
1016 | ||
1017 | char* __start = __buf + 3; | |
1018 | char* const __end = __buf + sizeof(__buf); | |
1019 | char* const __start_digits = __start; | |
1020 | ||
1021 | switch (_M_spec._M_type) | |
1022 | { | |
1023 | case _Pres_b: | |
1024 | case _Pres_B: | |
1025 | __base_prefix = _M_spec._M_type == _Pres_b ? "0b" : "0B"; | |
1026 | __res = to_chars(__start, __end, __u, 2); | |
1027 | break; | |
1028 | #if 0 | |
1029 | case _Pres_c: | |
1030 | return _M_format_character(_S_to_character(__i), __fc); | |
1031 | #endif | |
1032 | case _Pres_none: | |
1033 | // Should not reach here with _Pres_none for bool or charT, so: | |
1034 | [[fallthrough]]; | |
1035 | case _Pres_d: | |
1036 | __res = to_chars(__start, __end, __u, 10); | |
1037 | break; | |
1038 | case _Pres_o: | |
1039 | if (__i != 0) | |
1040 | __base_prefix = "0"; | |
1041 | __res = to_chars(__start, __end, __u, 8); | |
1042 | break; | |
1043 | case _Pres_x: | |
1044 | case _Pres_X: | |
1045 | __base_prefix = _M_spec._M_type == _Pres_x ? "0x" : "0X"; | |
1046 | __res = to_chars(__start, __end, __u, 16); | |
1047 | if (_M_spec._M_type == _Pres_X) | |
1048 | for (auto __p = __start; __p != __res.ptr; ++__p) | |
2f5c0718 | 1049 | #if __has_builtin(__builtin_toupper) |
1d9454ab | 1050 | *__p = __builtin_toupper(*__p); |
2f5c0718 JW |
1051 | #else |
1052 | *__p = std::toupper(*__p); | |
1053 | #endif | |
1d9454ab JW |
1054 | break; |
1055 | default: | |
1056 | __builtin_unreachable(); | |
1057 | } | |
1058 | ||
1059 | if (_M_spec._M_alt && __base_prefix.size()) | |
1060 | { | |
1061 | __start -= __base_prefix.size(); | |
1062 | __builtin_memcpy(__start, __base_prefix.data(), | |
1063 | __base_prefix.size()); | |
1064 | } | |
1065 | __start = __format::__put_sign(__i, _M_spec._M_sign, __start - 1); | |
1066 | ||
1067 | return _M_format_int(string_view(__start, __res.ptr - __start), | |
1068 | __start_digits - __start, __fc); | |
1069 | } | |
1070 | ||
1071 | template<typename _Out> | |
1072 | typename basic_format_context<_Out, _CharT>::iterator | |
1073 | format(bool __i, basic_format_context<_Out, _CharT>& __fc) const | |
1074 | { | |
1075 | if (_M_spec._M_type == _Pres_c) | |
1076 | return _M_format_character(static_cast<unsigned char>(__i), __fc); | |
1077 | if (_M_spec._M_type != _Pres_s) | |
1078 | return format(static_cast<unsigned char>(__i), __fc); | |
1079 | ||
1080 | basic_string<_CharT> __s; | |
1081 | size_t __est_width; | |
1082 | if (_M_spec._M_localized) [[unlikely]] | |
1083 | { | |
1084 | auto& __np = std::use_facet<numpunct<_CharT>>(__fc.locale()); | |
1085 | __s = __i ? __np.truename() : __np.falsename(); | |
1086 | __est_width = __s.size(); // TODO Unicode-aware estimate | |
1087 | } | |
1088 | else | |
1089 | { | |
1090 | if constexpr (is_same_v<char, _CharT>) | |
1091 | __s = __i ? "true" : "false"; | |
1092 | else | |
1093 | __s = __i ? L"true" : L"false"; | |
1094 | __est_width = __s.size(); | |
1095 | } | |
1096 | ||
9247402a JW |
1097 | return __format::__write_padded_as_spec(__s, __est_width, __fc, |
1098 | _M_spec); | |
1d9454ab JW |
1099 | } |
1100 | ||
1101 | template<typename _Out> | |
1102 | typename basic_format_context<_Out, _CharT>::iterator | |
1103 | _M_format_character(_CharT __c, | |
1104 | basic_format_context<_Out, _CharT>& __fc) const | |
1d9454ab | 1105 | { |
9247402a | 1106 | return __format::__write_padded_as_spec({&__c, 1u}, 1, __fc, _M_spec); |
1d9454ab JW |
1107 | } |
1108 | ||
1109 | template<typename _Int> | |
1110 | static _CharT | |
1111 | _S_to_character(_Int __i) | |
1112 | { | |
1113 | using _Traits = __gnu_cxx::__int_traits<_CharT>; | |
1114 | if constexpr (is_signed_v<_Int> == is_signed_v<_CharT>) | |
1115 | { | |
1116 | if (_Traits::__min <= __i && __i <= _Traits::__max) | |
1117 | return static_cast<_CharT>(__i); | |
1118 | } | |
1119 | else if constexpr (is_signed_v<_Int>) | |
1120 | { | |
1121 | if (__i >= 0 && make_unsigned_t<_Int>(__i) <= _Traits::__max) | |
1122 | return static_cast<_CharT>(__i); | |
1123 | } | |
1124 | else if (__i <= make_unsigned_t<_CharT>(_Traits::__max)) | |
1125 | return static_cast<_CharT>(__i); | |
1126 | __throw_format_error("format error: integer not representable as " | |
1127 | "character"); | |
1128 | } | |
1129 | ||
1130 | template<typename _Out> | |
1131 | typename basic_format_context<_Out, _CharT>::iterator | |
1132 | _M_format_int(string_view __narrow_str, size_t __prefix_len, | |
1133 | basic_format_context<_Out, _CharT>& __fc) const | |
1134 | { | |
1135 | size_t __width = _M_spec._M_get_width(__fc); | |
1136 | ||
1137 | _Optional_locale __loc; | |
1138 | ||
1139 | basic_string_view<_CharT> __str; | |
1140 | if constexpr (is_same_v<char, _CharT>) | |
1141 | __str = __narrow_str; | |
1142 | else | |
1143 | { | |
1144 | __loc = __fc.locale(); | |
1145 | auto& __ct = use_facet<ctype<_CharT>>(__loc.value()); | |
1146 | size_t __n = __narrow_str.size(); | |
1147 | auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); | |
1148 | __ct.widen(__narrow_str.data(), __narrow_str.data() + __n, __p); | |
1149 | __str = {__p, __n}; | |
1150 | } | |
1151 | ||
1152 | if (_M_spec._M_localized) | |
1153 | { | |
1154 | if constexpr (is_same_v<char, _CharT>) | |
1155 | __loc = __fc.locale(); | |
1156 | const auto& __l = __loc.value(); | |
1157 | if (__l.name() != "C") | |
1158 | { | |
1159 | auto& __np = use_facet<numpunct<_CharT>>(__l); | |
1160 | string __grp = __np.grouping(); | |
1161 | if (!__grp.empty()) | |
1162 | { | |
48e21e87 | 1163 | size_t __n = __str.size() - __prefix_len; |
1d9454ab | 1164 | auto __p = (_CharT*)__builtin_alloca(2 * __n |
48e21e87 JW |
1165 | * sizeof(_CharT) |
1166 | + __prefix_len); | |
1167 | auto __s = __str.data(); | |
1168 | char_traits<_CharT>::copy(__p, __s, __prefix_len); | |
1169 | __s += __prefix_len; | |
1170 | auto __end = std::__add_grouping(__p + __prefix_len, | |
1d9454ab JW |
1171 | __np.thousands_sep(), |
1172 | __grp.data(), | |
1173 | __grp.size(), | |
48e21e87 | 1174 | __s, __s + __n); |
1d9454ab JW |
1175 | __str = {__p, size_t(__end - __p)}; |
1176 | } | |
1177 | } | |
1178 | } | |
1179 | ||
1180 | if (__width <= __str.size()) | |
1181 | return __format::__write(__fc.out(), __str); | |
1182 | ||
1183 | _CharT __fill_char = _M_spec._M_fill; | |
1184 | _Align __align = _M_spec._M_align; | |
1185 | ||
1186 | size_t __nfill = __width - __str.size(); | |
1187 | auto __out = __fc.out(); | |
1188 | if (__align == _Align_default) | |
1189 | { | |
1190 | __align = _Align_right; | |
1191 | if (_M_spec._M_zero_fill) | |
1192 | { | |
1193 | __fill_char = _CharT('0'); | |
1194 | // Write sign and base prefix before zero filling. | |
1195 | if (__prefix_len != 0) | |
1196 | { | |
1197 | __out = __format::__write(std::move(__out), | |
1198 | __str.substr(0, __prefix_len)); | |
1199 | __str.remove_prefix(__prefix_len); | |
1200 | } | |
1201 | } | |
1202 | else | |
1203 | __fill_char = _CharT(' '); | |
1204 | } | |
1205 | return __format::__write_padded(std::move(__out), __str, | |
1206 | __align, __nfill, __fill_char); | |
1207 | } | |
1208 | ||
1209 | #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ | |
1210 | template<typename _Tp> | |
1211 | using make_unsigned_t | |
1212 | = typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)), | |
1213 | std::make_unsigned<_Tp>, | |
1214 | type_identity<unsigned __int128>>::type; | |
1215 | ||
1216 | // std::to_chars is not overloaded for int128 in strict mode. | |
1217 | template<typename _Int> | |
1218 | static to_chars_result | |
1219 | to_chars(char* __first, char* __last, _Int __value, int __base) | |
1220 | { return std::__to_chars_i<_Int>(__first, __last, __value, __base); } | |
1221 | #endif | |
1222 | ||
1223 | _Spec<_CharT> _M_spec{}; | |
1224 | }; | |
1225 | ||
ce86d967 JW |
1226 | // Decide how 128-bit floating-point types should be formatted (or not). |
1227 | // When supported, the typedef __format::__float128_t is the type that | |
1228 | // format arguments should be converted to for storage in basic_format_arg. | |
1229 | // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported. | |
1230 | // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted | |
1231 | // by converting them to long double (or __ieee128 for powerpc64le). | |
1232 | // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit | |
1233 | // support for _Float128, rather than formatting it as another type. | |
1234 | #undef _GLIBCXX_FORMAT_F128 | |
1235 | ||
1d9454ab | 1236 | #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT |
ce86d967 JW |
1237 | |
1238 | // Format 128-bit floating-point types using __ieee128. | |
1d9454ab | 1239 | using __float128_t = __ieee128; |
1d9454ab | 1240 | # define _GLIBCXX_FORMAT_F128 1 |
1d9454ab | 1241 | |
f69a8299 JW |
1242 | #ifdef __LONG_DOUBLE_IEEE128__ |
1243 | // These overloads exist in the library, but are not declared. | |
1244 | // Make them available as std::__format::to_chars. | |
1245 | to_chars_result | |
1246 | to_chars(char*, char*, __ibm128) noexcept | |
1247 | __asm("_ZSt8to_charsPcS_e"); | |
1248 | ||
1249 | to_chars_result | |
1250 | to_chars(char*, char*, __ibm128, chars_format) noexcept | |
1251 | __asm("_ZSt8to_charsPcS_eSt12chars_format"); | |
1252 | ||
1253 | to_chars_result | |
1254 | to_chars(char*, char*, __ibm128, chars_format, int) noexcept | |
1255 | __asm("_ZSt8to_charsPcS_eSt12chars_formati"); | |
1256 | #elif __cplusplus == 202002L | |
1257 | to_chars_result | |
1258 | to_chars(char*, char*, __ieee128) noexcept | |
1259 | __asm("_ZSt8to_charsPcS_u9__ieee128"); | |
1260 | ||
1261 | to_chars_result | |
1262 | to_chars(char*, char*, __ieee128, chars_format) noexcept | |
1263 | __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_format"); | |
1264 | ||
1265 | to_chars_result | |
1266 | to_chars(char*, char*, __ieee128, chars_format, int) noexcept | |
1267 | __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_formati"); | |
1268 | #endif | |
1269 | ||
ce86d967 | 1270 | #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128 |
1d9454ab | 1271 | |
ce86d967 JW |
1272 | // Format 128-bit floating-point types using long double. |
1273 | using __float128_t = long double; | |
1274 | # define _GLIBCXX_FORMAT_F128 1 | |
1d9454ab | 1275 | |
22cb0fea | 1276 | #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH) |
ce86d967 JW |
1277 | |
1278 | // Format 128-bit floating-point types using _Float128. | |
1279 | using __float128_t = _Float128; | |
1280 | # define _GLIBCXX_FORMAT_F128 2 | |
1d9454ab | 1281 | |
22cb0fea | 1282 | # if __cplusplus == 202002L |
1d9454ab JW |
1283 | // These overloads exist in the library, but are not declared for C++20. |
1284 | // Make them available as std::__format::to_chars. | |
1285 | to_chars_result | |
1286 | to_chars(char*, char*, _Float128) noexcept | |
e176c031 FD |
1287 | # if _GLIBCXX_INLINE_VERSION |
1288 | __asm("_ZNSt3__88to_charsEPcS0_DF128_"); | |
1289 | # else | |
1d9454ab | 1290 | __asm("_ZSt8to_charsPcS_DF128_"); |
e176c031 | 1291 | # endif |
1d9454ab JW |
1292 | |
1293 | to_chars_result | |
1294 | to_chars(char*, char*, _Float128, chars_format) noexcept | |
e176c031 FD |
1295 | # if _GLIBCXX_INLINE_VERSION |
1296 | __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatE"); | |
1297 | # else | |
1d9454ab | 1298 | __asm("_ZSt8to_charsPcS_DF128_St12chars_format"); |
e176c031 | 1299 | # endif |
1d9454ab JW |
1300 | |
1301 | to_chars_result | |
1302 | to_chars(char*, char*, _Float128, chars_format, int) noexcept | |
e176c031 FD |
1303 | # if _GLIBCXX_INLINE_VERSION |
1304 | __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatEi"); | |
1305 | # else | |
1d9454ab | 1306 | __asm("_ZSt8to_charsPcS_DF128_St12chars_formati"); |
e176c031 | 1307 | # endif |
ce86d967 | 1308 | # endif |
1d9454ab JW |
1309 | #endif |
1310 | ||
ce86d967 JW |
1311 | using std::to_chars; |
1312 | ||
1313 | // We can format a floating-point type iff it is usable with to_chars. | |
1314 | template<typename _Tp> | |
1315 | concept __formattable_float = requires (_Tp __t, char* __p) | |
1316 | { __format::to_chars(__p, __p, __t, chars_format::scientific, 6); }; | |
1317 | ||
1d9454ab JW |
1318 | template<__char _CharT> |
1319 | struct __formatter_fp | |
1320 | { | |
1321 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
1322 | parse(basic_format_parse_context<_CharT>& __pc) | |
1323 | { | |
1324 | _Spec<_CharT> __spec{}; | |
1325 | const auto __last = __pc.end(); | |
1326 | auto __first = __pc.begin(); | |
1327 | ||
1328 | auto __finalize = [this, &__spec] { | |
1329 | _M_spec = __spec; | |
1330 | }; | |
1331 | ||
1332 | auto __finished = [&] { | |
1333 | if (__first == __last || *__first == '}') | |
1334 | { | |
1335 | __finalize(); | |
1336 | return true; | |
1337 | } | |
1338 | return false; | |
1339 | }; | |
1340 | ||
1341 | if (__finished()) | |
1342 | return __first; | |
1343 | ||
1344 | __first = __spec._M_parse_fill_and_align(__first, __last); | |
1345 | if (__finished()) | |
1346 | return __first; | |
1347 | ||
1348 | __first = __spec._M_parse_sign(__first, __last); | |
1349 | if (__finished()) | |
1350 | return __first; | |
1351 | ||
1352 | __first = __spec._M_parse_alternate_form(__first, __last); | |
1353 | if (__finished()) | |
1354 | return __first; | |
1355 | ||
1356 | __first = __spec._M_parse_zero_fill(__first, __last); | |
1357 | if (__finished()) | |
1358 | return __first; | |
1359 | ||
1360 | if (__first[0] != '.') | |
1361 | { | |
1362 | __first = __spec._M_parse_width(__first, __last, __pc); | |
1363 | if (__finished()) | |
1364 | return __first; | |
1365 | } | |
1366 | ||
1367 | __first = __spec._M_parse_precision(__first, __last, __pc); | |
1368 | if (__finished()) | |
1369 | return __first; | |
1370 | ||
1371 | __first = __spec._M_parse_locale(__first, __last); | |
1372 | if (__finished()) | |
1373 | return __first; | |
1374 | ||
1375 | switch (*__first) | |
1376 | { | |
1377 | case 'a': | |
1378 | __spec._M_type = _Pres_a; | |
1379 | ++__first; | |
1380 | break; | |
1381 | case 'A': | |
1382 | __spec._M_type = _Pres_A; | |
1383 | ++__first; | |
1384 | break; | |
1385 | case 'e': | |
1386 | __spec._M_type = _Pres_e; | |
1387 | ++__first; | |
1388 | break; | |
1389 | case 'E': | |
1390 | __spec._M_type = _Pres_E; | |
1391 | ++__first; | |
1392 | break; | |
1393 | case 'f': | |
1394 | case 'F': | |
1395 | __spec._M_type = _Pres_f; | |
1396 | ++__first; | |
1397 | break; | |
1398 | case 'g': | |
1399 | __spec._M_type = _Pres_g; | |
1400 | ++__first; | |
1401 | break; | |
1402 | case 'G': | |
1403 | __spec._M_type = _Pres_G; | |
1404 | ++__first; | |
1405 | break; | |
1406 | } | |
1407 | ||
1408 | if (__finished()) | |
1409 | return __first; | |
1410 | ||
1411 | __format::__failed_to_parse_format_spec(); | |
1412 | } | |
1413 | ||
1414 | template<typename _Fp, typename _Out> | |
1415 | typename basic_format_context<_Out, _CharT>::iterator | |
1416 | format(_Fp __v, basic_format_context<_Out, _CharT>& __fc) const | |
1417 | { | |
1418 | std::string __dynbuf; | |
1419 | char __buf[128]; | |
1420 | to_chars_result __res{}; | |
1421 | ||
1422 | size_t __prec = 6; | |
1423 | bool __use_prec = _M_spec._M_prec_kind != _WP_none; | |
1424 | if (__use_prec) | |
1425 | __prec = _M_spec._M_get_precision(__fc); | |
1426 | ||
1427 | char* __start = __buf + 1; // reserve space for sign | |
1428 | char* __end = __buf + sizeof(__buf); | |
1429 | ||
1430 | chars_format __fmt{}; | |
1431 | bool __upper = false; | |
1432 | bool __trailing_zeros = false; | |
50bc490c | 1433 | char __expc = 'e'; |
1d9454ab JW |
1434 | |
1435 | switch (_M_spec._M_type) | |
1436 | { | |
1437 | case _Pres_A: | |
1438 | __upper = true; | |
50bc490c | 1439 | __expc = 'P'; |
1d9454ab JW |
1440 | [[fallthrough]]; |
1441 | case _Pres_a: | |
50bc490c JW |
1442 | if (_M_spec._M_type != _Pres_A) |
1443 | __expc = 'p'; | |
1d9454ab JW |
1444 | __fmt = chars_format::hex; |
1445 | break; | |
1446 | case _Pres_E: | |
1447 | __upper = true; | |
50bc490c | 1448 | __expc = 'E'; |
1d9454ab JW |
1449 | [[fallthrough]]; |
1450 | case _Pres_e: | |
1d9454ab JW |
1451 | __use_prec = true; |
1452 | __fmt = chars_format::scientific; | |
1453 | break; | |
1454 | case _Pres_f: | |
1455 | __use_prec = true; | |
1456 | __fmt = chars_format::fixed; | |
1457 | break; | |
1458 | case _Pres_G: | |
1459 | __upper = true; | |
50bc490c | 1460 | __expc = 'E'; |
1d9454ab JW |
1461 | [[fallthrough]]; |
1462 | case _Pres_g: | |
1463 | __trailing_zeros = true; | |
1d9454ab JW |
1464 | __use_prec = true; |
1465 | __fmt = chars_format::general; | |
1466 | break; | |
1467 | case _Pres_none: | |
1468 | if (__use_prec) | |
1469 | __fmt = chars_format::general; | |
1470 | break; | |
b9e5a4b4 JW |
1471 | default: |
1472 | __builtin_unreachable(); | |
1d9454ab JW |
1473 | } |
1474 | ||
1475 | // Write value into buffer using std::to_chars. | |
1476 | auto __to_chars = [&](char* __b, char* __e) { | |
1477 | if (__use_prec) | |
1478 | return __format::to_chars(__b, __e, __v, __fmt, __prec); | |
1479 | else if (__fmt != chars_format{}) | |
1480 | return __format::to_chars(__b, __e, __v, __fmt); | |
1481 | else | |
1482 | return __format::to_chars(__b, __e, __v); | |
1483 | }; | |
1484 | ||
1485 | // First try using stack buffer. | |
1486 | __res = __to_chars(__start, __end); | |
1487 | ||
1488 | if (__builtin_expect(__res.ec == errc::value_too_large, 0)) | |
1489 | { | |
1490 | // If the buffer is too small it's probably because of a large | |
1491 | // precision, or a very large value in fixed format. | |
bb3ceeb6 | 1492 | size_t __guess = 8 + __prec; |
2d2b05f0 | 1493 | if (__fmt == chars_format::fixed) // +ddd.prec |
bb3ceeb6 | 1494 | { |
2d2b05f0 PD |
1495 | if constexpr (is_same_v<_Fp, float> || is_same_v<_Fp, double> |
1496 | || is_same_v<_Fp, long double>) | |
1497 | { | |
1498 | // The number of digits to the left of the decimal point | |
1499 | // is floor(log10(max(abs(__v),1)))+1 | |
1500 | int __exp{}; | |
1501 | if constexpr (is_same_v<_Fp, float>) | |
1502 | __builtin_frexpf(__v, &__exp); | |
1503 | else if constexpr (is_same_v<_Fp, double>) | |
1504 | __builtin_frexp(__v, &__exp); | |
1505 | else if constexpr (is_same_v<_Fp, long double>) | |
1506 | __builtin_frexpl(__v, &__exp); | |
1507 | if (__exp > 0) | |
1508 | __guess += 1U + __exp * 4004U / 13301U; // log10(2) approx. | |
1509 | } | |
bb3ceeb6 JW |
1510 | else |
1511 | __guess += numeric_limits<_Fp>::max_exponent10; | |
1512 | } | |
1513 | if (__guess <= sizeof(__buf)) [[unlikely]] | |
1514 | __guess = sizeof(__buf) * 2; | |
1d9454ab JW |
1515 | __dynbuf.reserve(__guess); |
1516 | ||
1517 | do | |
1518 | { | |
1519 | auto __overwrite = [&__to_chars, &__res] (char* __p, size_t __n) | |
1520 | { | |
1521 | __res = __to_chars(__p + 1, __p + __n - 1); | |
1522 | return __res.ec == errc{} ? __res.ptr - __p : 0; | |
1523 | }; | |
1524 | ||
1525 | _S_resize_and_overwrite(__dynbuf, __dynbuf.capacity() * 2, | |
1526 | __overwrite); | |
1527 | __start = __dynbuf.data() + 1; // reserve space for sign | |
1528 | __end = __dynbuf.data() + __dynbuf.size(); | |
1529 | } | |
1530 | while (__builtin_expect(__res.ec == errc::value_too_large, 0)); | |
1531 | } | |
1532 | ||
1533 | // Use uppercase for 'A', 'E', and 'G' formats. | |
1534 | if (__upper) | |
1535 | { | |
1536 | for (char* __p = __start; __p != __res.ptr; ++__p) | |
1537 | *__p = std::toupper(*__p); | |
1d9454ab JW |
1538 | } |
1539 | ||
1540 | // Add sign for non-negative values. | |
1541 | if (!__builtin_signbit(__v)) | |
1542 | { | |
1543 | if (_M_spec._M_sign == _Sign_plus) | |
1544 | *--__start = '+'; | |
1545 | else if (_M_spec._M_sign == _Sign_space) | |
1546 | *--__start = ' '; | |
1547 | } | |
1548 | ||
1549 | string_view __narrow_str(__start, __res.ptr - __start); | |
1550 | ||
1551 | // Use alternate form. | |
1552 | if (_M_spec._M_alt && __builtin_isfinite(__v)) | |
1553 | { | |
1554 | string_view __s = __narrow_str; | |
1555 | size_t __z = 0; | |
1556 | size_t __p; | |
1557 | size_t __d = __s.find('.'); | |
1558 | size_t __sigfigs; | |
1559 | if (__d != __s.npos) | |
1560 | { | |
1561 | __p = __s.find(__expc, __d + 1); | |
1562 | if (__p == __s.npos) | |
1563 | __p = __s.size(); | |
1564 | __sigfigs = __p - 1; | |
1565 | } | |
1566 | else | |
1567 | { | |
1568 | __p = __s.find(__expc); | |
1569 | if (__p == __s.npos) | |
1570 | __p = __s.size(); | |
50bc490c | 1571 | __d = __p; // Position where '.' should be inserted. |
1d9454ab JW |
1572 | __sigfigs = __d; |
1573 | } | |
1574 | ||
50bc490c | 1575 | if (__trailing_zeros && __prec != 0) |
1d9454ab | 1576 | { |
dfc1ea41 | 1577 | if (!__format::__is_xdigit(__s[0])) |
1d9454ab | 1578 | --__sigfigs; |
50bc490c | 1579 | __z = __prec - __sigfigs; // Number of zeros to insert. |
1d9454ab JW |
1580 | } |
1581 | ||
1582 | if (size_t __extras = int(__d == __p) + __z) | |
1583 | { | |
18169e8e | 1584 | if (__dynbuf.empty() && __extras <= size_t(__end - __res.ptr)) |
1d9454ab JW |
1585 | { |
1586 | // Move exponent to make space for extra chars. | |
1587 | __builtin_memmove(__start + __p + __extras, | |
1588 | __start + __p, | |
1589 | __s.size() - __p); | |
1590 | ||
1591 | if (__d == __p) | |
1592 | __start[__p++] = '.'; | |
1593 | __builtin_memset(__start + __p, '0', __z); | |
1594 | __narrow_str = {__s.data(), __s.size() + __extras}; | |
1595 | } | |
1596 | else | |
1597 | { | |
1598 | __dynbuf.reserve(__s.size() + __extras); | |
1599 | if (__dynbuf.empty()) | |
1600 | { | |
1601 | __dynbuf = __s.substr(0, __p); | |
1602 | if (__d == __p) | |
1603 | __dynbuf += '.'; | |
1604 | if (__z) | |
1605 | __dynbuf.append(__z, '0'); | |
1606 | } | |
1607 | else | |
1608 | { | |
1609 | __dynbuf.insert(__p, __extras, '0'); | |
1610 | if (__d == __p) | |
1611 | __dynbuf[__p] = '.'; | |
1612 | } | |
1613 | __narrow_str = __dynbuf; | |
1614 | } | |
1615 | } | |
1616 | } | |
1617 | ||
1618 | // TODO move everything below to a new member function that | |
1619 | // doesn't depend on _Fp type. | |
1620 | ||
1621 | ||
1622 | _Optional_locale __loc; | |
1d9454ab | 1623 | basic_string<_CharT> __wstr; |
f48a5423 | 1624 | basic_string_view<_CharT> __str; |
1d9454ab JW |
1625 | if constexpr (is_same_v<_CharT, char>) |
1626 | __str = __narrow_str; | |
1627 | else | |
1628 | { | |
1629 | __loc = __fc.locale(); | |
1630 | auto& __ct = use_facet<ctype<_CharT>>(__loc.value()); | |
1631 | const char* __data = __narrow_str.data(); | |
1632 | auto __overwrite = [&__data, &__ct](_CharT* __p, size_t __n) | |
1633 | { | |
1634 | __ct.widen(__data, __data + __n, __p); | |
1635 | return __n; | |
1636 | }; | |
1637 | _S_resize_and_overwrite(__wstr, __narrow_str.size(), __overwrite); | |
1638 | __str = __wstr; | |
1639 | } | |
1640 | ||
1641 | if (_M_spec._M_localized) | |
1642 | { | |
1643 | if constexpr (is_same_v<char, _CharT>) | |
1644 | __wstr = _M_localize(__str, __expc, __fc.locale()); | |
1645 | else | |
1646 | __wstr = _M_localize(__str, __expc, __loc.value()); | |
f48a5423 JW |
1647 | if (!__wstr.empty()) |
1648 | __str = __wstr; | |
1d9454ab JW |
1649 | } |
1650 | ||
1651 | size_t __width = _M_spec._M_get_width(__fc); | |
1652 | ||
1653 | if (__width <= __str.size()) | |
1654 | return __format::__write(__fc.out(), __str); | |
1655 | ||
1656 | _CharT __fill_char = _M_spec._M_fill; | |
1657 | _Align __align = _M_spec._M_align; | |
1658 | ||
1659 | size_t __nfill = __width - __str.size(); | |
1660 | auto __out = __fc.out(); | |
1661 | if (__align == _Align_default) | |
1662 | { | |
1663 | __align = _Align_right; | |
1664 | if (_M_spec._M_zero_fill && __builtin_isfinite(__v)) | |
1665 | { | |
1666 | __fill_char = _CharT('0'); | |
1667 | // Write sign before zero filling. | |
dfc1ea41 | 1668 | if (!__format::__is_xdigit(__narrow_str[0])) |
1d9454ab JW |
1669 | { |
1670 | *__out++ = __str[0]; | |
1671 | __str.remove_prefix(1); | |
1672 | } | |
1673 | } | |
1674 | else | |
1675 | __fill_char = _CharT(' '); | |
1676 | } | |
1677 | return __format::__write_padded(std::move(__out), __str, | |
1678 | __align, __nfill, __fill_char); | |
1679 | } | |
1680 | ||
1681 | // Locale-specific format. | |
1682 | basic_string<_CharT> | |
1683 | _M_localize(basic_string_view<_CharT> __str, char __expc, | |
1684 | const locale& __loc) const | |
1685 | { | |
1686 | basic_string<_CharT> __lstr; | |
1687 | ||
1688 | if (__loc == locale::classic()) | |
1689 | return __lstr; // Nothing to do. | |
1690 | ||
1691 | const auto& __np = use_facet<numpunct<_CharT>>(__loc); | |
1692 | const _CharT __point = __np.decimal_point(); | |
1693 | const string __grp = __np.grouping(); | |
1694 | ||
1695 | _CharT __dot, __exp; | |
1696 | if constexpr (is_same_v<_CharT, char>) | |
1697 | { | |
1698 | __dot = '.'; | |
1699 | __exp = __expc; | |
1700 | } | |
1701 | else | |
1702 | { | |
1703 | const auto& __ct = use_facet<ctype<_CharT>>(__loc); | |
1704 | __dot = __ct.widen('.'); | |
1705 | __exp = __ct.widen(__expc); | |
1706 | } | |
1707 | ||
1708 | if (__grp.empty() && __point == __dot) | |
1709 | return __lstr; // Locale uses '.' and no grouping. | |
1710 | ||
1711 | size_t __d = __str.find(__dot); | |
1712 | size_t __e = min(__d, __str.find(__exp)); | |
1713 | if (__e == __str.npos) | |
1714 | __e = __str.size(); | |
1715 | const size_t __r = __str.size() - __e; | |
1716 | auto __overwrite = [&](_CharT* __p, size_t) { | |
1717 | auto __end = std::__add_grouping(__p, __np.thousands_sep(), | |
1718 | __grp.data(), __grp.size(), | |
1719 | __str.data(), __str.data() + __e); | |
1720 | if (__r) | |
1721 | { | |
1722 | if (__d != __str.npos) | |
1723 | { | |
1724 | *__end = __point; | |
1725 | ++__end; | |
1726 | ++__e; | |
1727 | } | |
1728 | if (__r > 1) | |
1729 | __end += __str.copy(__end, __str.npos, __e); | |
1730 | } | |
1731 | return (__end - __p); | |
1732 | }; | |
1733 | _S_resize_and_overwrite(__lstr, __e * 2 + __r, __overwrite); | |
1734 | return __lstr; | |
1735 | } | |
1736 | ||
1737 | template<typename _Ch, typename _Func> | |
1738 | static void | |
1739 | _S_resize_and_overwrite(basic_string<_Ch>& __str, size_t __n, _Func __f) | |
1740 | { | |
1741 | #if __cpp_lib_string_resize_and_overwrite | |
1742 | __str.resize_and_overwrite(__n, __f); | |
1743 | #else | |
1744 | __str.resize(__n); | |
1745 | __str.resize(__f(__str.data(), __n)); | |
1746 | #endif | |
1747 | } | |
1748 | ||
1749 | _Spec<_CharT> _M_spec{}; | |
1750 | }; | |
1751 | ||
1752 | } // namespace __format | |
1753 | /// @endcond | |
1754 | ||
1755 | // Format a character. | |
1756 | template<__format::__char _CharT> | |
1757 | struct formatter<_CharT, _CharT> | |
1758 | { | |
1759 | formatter() = default; | |
1760 | ||
1761 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
1762 | parse(basic_format_parse_context<_CharT>& __pc) | |
1763 | { | |
1764 | return _M_f.template _M_parse<_CharT>(__pc); | |
1765 | } | |
1766 | ||
1767 | template<typename _Out> | |
1768 | typename basic_format_context<_Out, _CharT>::iterator | |
1769 | format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const | |
1770 | { | |
1771 | if (_M_f._M_spec._M_type == __format::_Pres_none) | |
1772 | return _M_f._M_format_character(__u, __fc); | |
1773 | else if (_M_f._M_spec._M_type == __format::_Pres_esc) | |
1774 | { | |
1775 | // TODO | |
1776 | return __fc.out(); | |
1777 | } | |
1778 | else | |
1779 | return _M_f.format(__u, __fc); | |
1780 | } | |
1781 | ||
1782 | #if __cpp_lib_format_ranges | |
1783 | constexpr void | |
1784 | set_debug_format() noexcept | |
1785 | { _M_f._M_spec._M_type = __format::_Pres_esc; } | |
1786 | #endif | |
1787 | ||
1788 | private: | |
1789 | __format::__formatter_int<_CharT> _M_f; | |
1790 | }; | |
1791 | ||
1792 | // Format a char value for wide character output. | |
1793 | template<> | |
1794 | struct formatter<char, wchar_t> | |
1795 | { | |
1796 | formatter() = default; | |
1797 | ||
1798 | constexpr typename basic_format_parse_context<wchar_t>::iterator | |
1799 | parse(basic_format_parse_context<wchar_t>& __pc) | |
1800 | { | |
1801 | return _M_f._M_parse<char>(__pc); | |
1802 | } | |
1803 | ||
1804 | template<typename _Out> | |
1805 | typename basic_format_context<_Out, wchar_t>::iterator | |
1806 | format(char __u, basic_format_context<_Out, wchar_t>& __fc) const | |
1807 | { | |
1808 | if (_M_f._M_spec._M_type == __format::_Pres_none) | |
1809 | return _M_f._M_format_character(__u, __fc); | |
1810 | else if (_M_f._M_spec._M_type == __format::_Pres_esc) | |
1811 | { | |
1812 | // TODO | |
1813 | return __fc.out(); | |
1814 | } | |
1815 | else | |
1816 | return _M_f.format(__u, __fc); | |
1817 | } | |
1818 | ||
1819 | constexpr void | |
1820 | set_debug_format() noexcept | |
1821 | { _M_f._M_spec._M_type = __format::_Pres_esc; } | |
1822 | ||
1823 | private: | |
1824 | __format::__formatter_int<wchar_t> _M_f; | |
1825 | }; | |
1826 | ||
1827 | /** Format a string. | |
1828 | * @{ | |
1829 | */ | |
1830 | template<__format::__char _CharT> | |
1831 | struct formatter<_CharT*, _CharT> | |
1832 | { | |
1833 | formatter() = default; | |
1834 | ||
1835 | [[__gnu__::__always_inline__]] | |
1836 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
1837 | parse(basic_format_parse_context<_CharT>& __pc) | |
1838 | { return _M_f.parse(__pc); } | |
1839 | ||
1840 | template<typename _Out> | |
1841 | [[__gnu__::__nonnull__]] | |
1842 | typename basic_format_context<_Out, _CharT>::iterator | |
1843 | format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const | |
1844 | { return _M_f.format(__u, __fc); } | |
1845 | ||
1846 | constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } | |
1847 | ||
1848 | private: | |
1849 | __format::__formatter_str<_CharT> _M_f; | |
1850 | }; | |
1851 | ||
1852 | template<__format::__char _CharT> | |
1853 | struct formatter<const _CharT*, _CharT> | |
1854 | { | |
1855 | formatter() = default; | |
1856 | ||
1857 | [[__gnu__::__always_inline__]] | |
1858 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
1859 | parse(basic_format_parse_context<_CharT>& __pc) | |
1860 | { return _M_f.parse(__pc); } | |
1861 | ||
1862 | template<typename _Out> | |
1863 | [[__gnu__::__nonnull__]] | |
1864 | typename basic_format_context<_Out, _CharT>::iterator | |
1865 | format(const _CharT* __u, | |
1866 | basic_format_context<_Out, _CharT>& __fc) const | |
1867 | { return _M_f.format(__u, __fc); } | |
1868 | ||
1869 | constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } | |
1870 | ||
1871 | private: | |
1872 | __format::__formatter_str<_CharT> _M_f; | |
1873 | }; | |
1874 | ||
1875 | template<__format::__char _CharT, size_t _Nm> | |
1876 | struct formatter<_CharT[_Nm], _CharT> | |
1877 | { | |
1878 | formatter() = default; | |
1879 | ||
1880 | [[__gnu__::__always_inline__]] | |
1881 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
1882 | parse(basic_format_parse_context<_CharT>& __pc) | |
1883 | { return _M_f.parse(__pc); } | |
1884 | ||
1d9454ab JW |
1885 | template<typename _Out> |
1886 | typename basic_format_context<_Out, _CharT>::iterator | |
1887 | format(const _CharT (&__u)[_Nm], | |
1888 | basic_format_context<_Out, _CharT>& __fc) const | |
1889 | { return _M_f.format({__u, _Nm}, __fc); } | |
1890 | ||
1891 | constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } | |
1892 | ||
1893 | private: | |
1894 | __format::__formatter_str<_CharT> _M_f; | |
1895 | }; | |
1896 | ||
1897 | template<typename _Traits, typename _Alloc> | |
1898 | struct formatter<basic_string<char, _Traits, _Alloc>, char> | |
1899 | { | |
1900 | formatter() = default; | |
1901 | ||
1902 | [[__gnu__::__always_inline__]] | |
1903 | constexpr typename basic_format_parse_context<char>::iterator | |
1904 | parse(basic_format_parse_context<char>& __pc) | |
1905 | { return _M_f.parse(__pc); } | |
1906 | ||
1907 | template<typename _Out> | |
1908 | typename basic_format_context<_Out, char>::iterator | |
1909 | format(const basic_string<char, _Traits, _Alloc>& __u, | |
1910 | basic_format_context<_Out, char>& __fc) const | |
1911 | { return _M_f.format(__u, __fc); } | |
1912 | ||
1913 | #if __cpp_lib_format_ranges | |
1914 | constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } | |
1915 | #endif | |
1916 | ||
1917 | private: | |
1918 | __format::__formatter_str<char> _M_f; | |
1919 | }; | |
1920 | ||
1921 | template<typename _Traits, typename _Alloc> | |
1922 | struct formatter<basic_string<wchar_t, _Traits, _Alloc>, wchar_t> | |
1923 | { | |
1924 | formatter() = default; | |
1925 | ||
1926 | [[__gnu__::__always_inline__]] | |
1927 | constexpr typename basic_format_parse_context<wchar_t>::iterator | |
1928 | parse(basic_format_parse_context<wchar_t>& __pc) | |
1929 | { return _M_f.parse(__pc); } | |
1930 | ||
1931 | template<typename _Out> | |
1932 | typename basic_format_context<_Out, wchar_t>::iterator | |
1933 | format(const basic_string<wchar_t, _Traits, _Alloc>& __u, | |
1934 | basic_format_context<_Out, wchar_t>& __fc) const | |
1935 | { return _M_f.format(__u, __fc); } | |
1936 | ||
1937 | #if __cpp_lib_format_ranges | |
1938 | constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } | |
1939 | #endif | |
1940 | ||
1941 | private: | |
1942 | __format::__formatter_str<wchar_t> _M_f; | |
1943 | }; | |
1944 | ||
1945 | template<typename _Traits> | |
1946 | struct formatter<basic_string_view<char, _Traits>, char> | |
1947 | { | |
1948 | formatter() = default; | |
1949 | ||
1950 | [[__gnu__::__always_inline__]] | |
1951 | constexpr typename basic_format_parse_context<char>::iterator | |
1952 | parse(basic_format_parse_context<char>& __pc) | |
1953 | { return _M_f.parse(__pc); } | |
1954 | ||
1955 | template<typename _Out> | |
1956 | typename basic_format_context<_Out, char>::iterator | |
1957 | format(basic_string_view<char, _Traits> __u, | |
1958 | basic_format_context<_Out, char>& __fc) const | |
1959 | { return _M_f.format(__u, __fc); } | |
1960 | ||
1961 | #if __cpp_lib_format_ranges | |
1962 | constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } | |
1963 | #endif | |
1964 | ||
1965 | private: | |
1966 | __format::__formatter_str<char> _M_f; | |
1967 | }; | |
1968 | ||
1969 | template<typename _Traits> | |
1970 | struct formatter<basic_string_view<wchar_t, _Traits>, wchar_t> | |
1971 | { | |
1972 | formatter() = default; | |
1973 | ||
1974 | [[__gnu__::__always_inline__]] | |
1975 | constexpr typename basic_format_parse_context<wchar_t>::iterator | |
1976 | parse(basic_format_parse_context<wchar_t>& __pc) | |
1977 | { return _M_f.parse(__pc); } | |
1978 | ||
1979 | template<typename _Out> | |
1980 | typename basic_format_context<_Out, wchar_t>::iterator | |
1981 | format(basic_string_view<wchar_t, _Traits> __u, | |
1982 | basic_format_context<_Out, wchar_t>& __fc) const | |
1983 | { return _M_f.format(__u, __fc); } | |
1984 | ||
1985 | #if __cpp_lib_format_ranges | |
1986 | constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); } | |
1987 | #endif | |
1988 | ||
1989 | private: | |
1990 | __format::__formatter_str<wchar_t> _M_f; | |
1991 | }; | |
1992 | /// @} | |
1993 | ||
1994 | /// Format an integer. | |
1995 | template<integral _Tp, __format::__char _CharT> | |
1996 | requires (!__is_one_of<_Tp, char, wchar_t, char16_t, char32_t>::value) | |
1997 | struct formatter<_Tp, _CharT> | |
1998 | { | |
1999 | formatter() = default; | |
2000 | ||
2001 | [[__gnu__::__always_inline__]] | |
2002 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
2003 | parse(basic_format_parse_context<_CharT>& __pc) | |
2004 | { | |
2005 | return _M_f.template _M_parse<_Tp>(__pc); | |
2006 | } | |
2007 | ||
2008 | template<typename _Out> | |
2009 | typename basic_format_context<_Out, _CharT>::iterator | |
2010 | format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const | |
2011 | { return _M_f.format(__u, __fc); } | |
2012 | ||
2013 | private: | |
2014 | __format::__formatter_int<_CharT> _M_f; | |
2015 | }; | |
2016 | ||
2017 | #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ | |
2018 | template<typename _Tp, __format::__char _CharT> | |
2019 | requires (__is_one_of<_Tp, __int128, unsigned __int128>::value) | |
2020 | struct formatter<_Tp, _CharT> | |
2021 | { | |
2022 | formatter() = default; | |
2023 | ||
2024 | [[__gnu__::__always_inline__]] | |
2025 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
2026 | parse(basic_format_parse_context<_CharT>& __pc) | |
2027 | { | |
2028 | return _M_f.template _M_parse<_Tp>(__pc); | |
2029 | } | |
2030 | ||
2031 | template<typename _Out> | |
2032 | typename basic_format_context<_Out, _CharT>::iterator | |
2033 | format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const | |
2034 | { return _M_f.format(__u, __fc); } | |
2035 | ||
2036 | private: | |
2037 | __format::__formatter_int<_CharT> _M_f; | |
2038 | }; | |
2039 | #endif | |
2040 | ||
2041 | /// Format a floating-point value. | |
ce86d967 | 2042 | template<__format::__formattable_float _Tp, __format::__char _CharT> |
1d9454ab JW |
2043 | struct formatter<_Tp, _CharT> |
2044 | { | |
2045 | formatter() = default; | |
2046 | ||
2047 | [[__gnu__::__always_inline__]] | |
2048 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
2049 | parse(basic_format_parse_context<_CharT>& __pc) | |
2050 | { return _M_f.parse(__pc); } | |
2051 | ||
2052 | template<typename _Out> | |
2053 | typename basic_format_context<_Out, _CharT>::iterator | |
2054 | format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const | |
2055 | { return _M_f.format(__u, __fc); } | |
2056 | ||
2057 | private: | |
2058 | __format::__formatter_fp<_CharT> _M_f; | |
2059 | }; | |
2060 | ||
2061 | /** Format a pointer. | |
2062 | * @{ | |
2063 | */ | |
2064 | template<__format::__char _CharT> | |
2065 | struct formatter<const void*, _CharT> | |
2066 | { | |
2067 | formatter() = default; | |
2068 | ||
2069 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
2070 | parse(basic_format_parse_context<_CharT>& __pc) | |
2071 | { | |
2072 | __format::_Spec<_CharT> __spec{}; | |
2073 | const auto __last = __pc.end(); | |
2074 | auto __first = __pc.begin(); | |
2075 | ||
2076 | auto __finalize = [this, &__spec] { | |
2077 | _M_spec = __spec; | |
2078 | }; | |
2079 | ||
2080 | auto __finished = [&] { | |
2081 | if (__first == __last || *__first == '}') | |
2082 | { | |
2083 | __finalize(); | |
2084 | return true; | |
2085 | } | |
2086 | return false; | |
2087 | }; | |
2088 | ||
2089 | if (__finished()) | |
2090 | return __first; | |
2091 | ||
2092 | __first = __spec._M_parse_fill_and_align(__first, __last); | |
2093 | if (__finished()) | |
2094 | return __first; | |
2095 | ||
628ba410 JW |
2096 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
2097 | // P2510R3 Formatting pointers | |
b9e5a4b4 JW |
2098 | #if __cplusplus > 202302L || ! defined __STRICT_ANSI__ |
2099 | #define _GLIBCXX_P2518R3 1 | |
2100 | #else | |
2101 | #define _GLIBCXX_P2518R3 0 | |
2102 | #endif | |
628ba410 JW |
2103 | |
2104 | #if _GLIBCXX_P2518R3 | |
1d9454ab JW |
2105 | __first = __spec._M_parse_zero_fill(__first, __last); |
2106 | if (__finished()) | |
2107 | return __first; | |
628ba410 | 2108 | #endif |
1d9454ab JW |
2109 | |
2110 | __first = __spec._M_parse_width(__first, __last, __pc); | |
2111 | ||
628ba410 | 2112 | if (__first != __last) |
1d9454ab | 2113 | { |
628ba410 JW |
2114 | if (*__first == 'p') |
2115 | ++__first; | |
2116 | #if _GLIBCXX_P2518R3 | |
2117 | else if (*__first == 'P') | |
2118 | { | |
2119 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
2120 | // P2510R3 Formatting pointers | |
1d9454ab | 2121 | __spec._M_type = __format::_Pres_P; |
628ba410 JW |
2122 | ++__first; |
2123 | } | |
2124 | #endif | |
1d9454ab JW |
2125 | } |
2126 | ||
2127 | if (__finished()) | |
2128 | return __first; | |
2129 | ||
2130 | __format::__failed_to_parse_format_spec(); | |
2131 | } | |
2132 | ||
2133 | template<typename _Out> | |
2134 | typename basic_format_context<_Out, _CharT>::iterator | |
2135 | format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const | |
2136 | { | |
3bb9f932 | 2137 | auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v); |
1d9454ab JW |
2138 | char __buf[2 + sizeof(__v) * 2]; |
2139 | auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf), | |
2140 | __u, 16); | |
628ba410 | 2141 | int __n = __ptr - __buf; |
1d9454ab JW |
2142 | __buf[0] = '0'; |
2143 | __buf[1] = 'x'; | |
628ba410 JW |
2144 | #if _GLIBCXX_P2518R3 |
2145 | if (_M_spec._M_type == __format::_Pres_P) | |
2146 | { | |
2147 | __buf[1] = 'X'; | |
2148 | for (auto __p = __buf + 2; __p != __ptr; ++__p) | |
2149 | #if __has_builtin(__builtin_toupper) | |
2150 | *__p = __builtin_toupper(*__p); | |
2151 | #else | |
2152 | *__p = std::toupper(*__p); | |
2153 | #endif | |
2154 | } | |
2155 | #endif | |
1d9454ab JW |
2156 | |
2157 | basic_string_view<_CharT> __str; | |
2158 | if constexpr (is_same_v<_CharT, char>) | |
2159 | __str = string_view(__buf, __n); | |
2160 | else | |
2161 | { | |
2162 | const std::locale& __loc = __fc.locale(); | |
2163 | auto& __ct = use_facet<ctype<_CharT>>(__loc); | |
2164 | auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT)); | |
2165 | __ct.widen(__buf, __buf + __n, __p); | |
2166 | __str = wstring_view(__p, __n); | |
2167 | } | |
2168 | ||
628ba410 JW |
2169 | #if _GLIBCXX_P2518R3 |
2170 | if (_M_spec._M_zero_fill) | |
2171 | { | |
2172 | size_t __width = _M_spec._M_get_width(__fc); | |
2173 | if (__width <= __str.size()) | |
2174 | return __format::__write(__fc.out(), __str); | |
2175 | ||
2176 | auto __out = __fc.out(); | |
2177 | // Write "0x" or "0X" prefix before zero-filling. | |
2178 | __out = __format::__write(std::move(__out), __str.substr(0, 2)); | |
2179 | __str.remove_prefix(2); | |
2180 | size_t __nfill = __width - __n; | |
2181 | return __format::__write_padded(std::move(__out), __str, | |
2182 | __format::_Align_right, | |
2183 | __nfill, _CharT('0')); | |
2184 | } | |
2185 | #endif | |
2186 | ||
9247402a JW |
2187 | return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec, |
2188 | __format::_Align_right); | |
1d9454ab JW |
2189 | } |
2190 | ||
2191 | private: | |
9247402a | 2192 | __format::_Spec<_CharT> _M_spec{}; |
1d9454ab JW |
2193 | }; |
2194 | ||
2195 | template<__format::__char _CharT> | |
2196 | struct formatter<void*, _CharT> | |
2197 | { | |
2198 | formatter() = default; | |
2199 | ||
2200 | [[__gnu__::__always_inline__]] | |
2201 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
2202 | parse(basic_format_parse_context<_CharT>& __pc) | |
2203 | { return _M_f.parse(__pc); } | |
2204 | ||
2205 | template<typename _Out> | |
2206 | typename basic_format_context<_Out, _CharT>::iterator | |
2207 | format(void* __v, basic_format_context<_Out, _CharT>& __fc) const | |
2208 | { return _M_f.format(__v, __fc); } | |
2209 | ||
2210 | private: | |
2211 | formatter<const void*, _CharT> _M_f; | |
2212 | }; | |
2213 | ||
2214 | template<__format::__char _CharT> | |
2215 | struct formatter<nullptr_t, _CharT> | |
2216 | { | |
2217 | formatter() = default; | |
2218 | ||
2219 | [[__gnu__::__always_inline__]] | |
2220 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
2221 | parse(basic_format_parse_context<_CharT>& __pc) | |
2222 | { return _M_f.parse(__pc); } | |
2223 | ||
2224 | template<typename _Out> | |
2225 | typename basic_format_context<_Out, _CharT>::iterator | |
2226 | format(nullptr_t, basic_format_context<_Out, _CharT>& __fc) const | |
2227 | { return _M_f.format(nullptr, __fc); } | |
2228 | ||
2229 | private: | |
2230 | formatter<const void*, _CharT> _M_f; | |
2231 | }; | |
2232 | /// @} | |
2233 | ||
2234 | ||
2235 | /// @cond undocumented | |
2236 | namespace __format | |
2237 | { | |
2238 | template<typename _Tp, typename _Context, | |
2239 | typename _Formatter | |
2240 | = typename _Context::template formatter_type<remove_const_t<_Tp>>, | |
2241 | typename _ParseContext | |
2242 | = basic_format_parse_context<typename _Context::char_type>> | |
2243 | concept __parsable_with | |
2244 | = semiregular<_Formatter> | |
2245 | && requires (_Formatter __f, _ParseContext __pc) | |
2246 | { | |
2247 | { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>; | |
2248 | }; | |
2249 | ||
2250 | template<typename _Tp, typename _Context, | |
2251 | typename _Formatter | |
2252 | = typename _Context::template formatter_type<remove_const_t<_Tp>>, | |
2253 | typename _ParseContext | |
2254 | = basic_format_parse_context<typename _Context::char_type>> | |
2255 | concept __formattable_with | |
2256 | = semiregular<_Formatter> | |
2257 | && requires (const _Formatter __cf, _Tp&& __t, _Context __fc) | |
2258 | { | |
2259 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>; | |
2260 | }; | |
2261 | ||
2262 | // An unspecified output iterator type used in the `formattable` concept. | |
2263 | template<typename _CharT> | |
2264 | using _Iter_for = back_insert_iterator<basic_string<_CharT>>; | |
2265 | ||
2266 | template<typename _Tp, typename _CharT, | |
2267 | typename _Context = basic_format_context<_Iter_for<_CharT>, _CharT>> | |
2268 | concept __formattable_impl | |
2269 | = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>; | |
2270 | ||
2271 | } // namespace __format | |
2272 | /// @endcond | |
2273 | ||
a5d4f38f | 2274 | #if __cplusplus > 202002L |
1d9454ab JW |
2275 | // [format.formattable], concept formattable |
2276 | template<typename _Tp, typename _CharT> | |
2277 | concept formattable | |
2278 | = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>; | |
a5d4f38f | 2279 | #endif |
1d9454ab | 2280 | |
a5d4f38f | 2281 | #if __cpp_lib_format_ranges |
1d9454ab JW |
2282 | /// @cond undocumented |
2283 | namespace __format | |
2284 | { | |
2285 | template<typename _Rg, typename _CharT> | |
2286 | concept __const_formattable_range | |
2287 | = ranges::input_range<const _Rg> | |
2288 | && formattable<ranges::range_reference_t<const _Rg>, _CharT>; | |
2289 | ||
2290 | template<typename _Rg, typename _CharT> | |
2291 | using __maybe_const_range | |
2292 | = conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>; | |
2293 | } // namespace __format | |
2294 | /// @endcond | |
a5d4f38f | 2295 | #endif // format_ranges |
1d9454ab JW |
2296 | |
2297 | /// An iterator after the last character written, and the number of | |
2298 | /// characters that would have been written. | |
2299 | template<typename _Out> | |
2300 | struct format_to_n_result | |
2301 | { | |
2302 | _Out out; | |
2303 | iter_difference_t<_Out> size; | |
2304 | }; | |
2305 | ||
2306 | /// @cond undocumented | |
2307 | namespace __format | |
2308 | { | |
2309 | template<typename _CharT> | |
2310 | class _Sink_iter | |
2311 | { | |
2312 | _Sink<_CharT>* _M_sink = nullptr; | |
2313 | ||
2314 | public: | |
2315 | using iterator_category = output_iterator_tag; | |
2316 | using value_type = void; | |
2317 | using difference_type = ptrdiff_t; | |
2318 | using pointer = void; | |
2319 | using reference = void; | |
2320 | ||
2321 | _Sink_iter() = default; | |
2322 | _Sink_iter(const _Sink_iter&) = default; | |
2323 | _Sink_iter& operator=(const _Sink_iter&) = default; | |
2324 | ||
2325 | [[__gnu__::__always_inline__]] | |
2326 | explicit constexpr | |
2327 | _Sink_iter(_Sink<_CharT>& __sink) : _M_sink(std::addressof(__sink)) { } | |
2328 | ||
2329 | [[__gnu__::__always_inline__]] | |
2330 | constexpr _Sink_iter& | |
2331 | operator=(_CharT __c) | |
2332 | { | |
2333 | _M_sink->_M_write(__c); | |
2334 | return *this; | |
2335 | } | |
2336 | ||
2337 | [[__gnu__::__always_inline__]] | |
2338 | constexpr _Sink_iter& | |
2339 | operator=(basic_string_view<_CharT> __s) | |
2340 | { | |
2341 | _M_sink->_M_write(__s); | |
2342 | return *this; | |
2343 | } | |
2344 | ||
2345 | [[__gnu__::__always_inline__]] | |
2346 | constexpr _Sink_iter& | |
2347 | operator*() { return *this; } | |
2348 | ||
2349 | [[__gnu__::__always_inline__]] | |
2350 | constexpr _Sink_iter& | |
2351 | operator++() { return *this; } | |
2352 | ||
2353 | [[__gnu__::__always_inline__]] | |
2354 | constexpr _Sink_iter | |
2355 | operator++(int) { return *this; } | |
2356 | }; | |
2357 | ||
2358 | // Abstract base class for type-erased character sinks. | |
2359 | // All formatting and output is done via this type's iterator, | |
2360 | // to reduce the number of different template instantiations. | |
2361 | template<typename _CharT> | |
2362 | class _Sink | |
2363 | { | |
2364 | friend class _Sink_iter<_CharT>; | |
2365 | ||
2366 | span<_CharT> _M_span; | |
2367 | typename span<_CharT>::iterator _M_next; | |
2368 | ||
2369 | // Called when the span is full, to make more space available. | |
2370 | // Precondition: _M_next != _M_span.begin() | |
2371 | // Postcondition: _M_next != _M_span.end() | |
2372 | virtual void _M_overflow() = 0; | |
2373 | ||
2374 | protected: | |
2375 | // Precondition: __span.size() != 0 | |
2376 | [[__gnu__::__always_inline__]] | |
2377 | explicit constexpr | |
2378 | _Sink(span<_CharT> __span) noexcept | |
2379 | : _M_span(__span), _M_next(__span.begin()) | |
2380 | { } | |
2381 | ||
2382 | // The portion of the span that has been written to. | |
2383 | [[__gnu__::__always_inline__]] | |
2384 | span<_CharT> | |
2385 | _M_used() const noexcept | |
2386 | { return _M_span.first(_M_next - _M_span.begin()); } | |
2387 | ||
2388 | // The portion of the span that has not been written to. | |
2389 | [[__gnu__::__always_inline__]] | |
2390 | constexpr span<_CharT> | |
2391 | _M_unused() const noexcept | |
2392 | { return _M_span.subspan(_M_next - _M_span.begin()); } | |
2393 | ||
2394 | // Use the start of the span as the next write position. | |
2395 | [[__gnu__::__always_inline__]] | |
2396 | constexpr void | |
2397 | _M_rewind() noexcept | |
2398 | { _M_next = _M_span.begin(); } | |
2399 | ||
2400 | // Replace the current output range. | |
2401 | void | |
2402 | _M_reset(span<_CharT> __s, | |
2403 | typename span<_CharT>::iterator __next) noexcept | |
2404 | { | |
2405 | _M_span = __s; | |
2406 | _M_next = __next; | |
2407 | } | |
2408 | ||
2409 | // Called by the iterator for *it++ = c | |
2410 | constexpr void | |
2411 | _M_write(_CharT __c) | |
2412 | { | |
2413 | *_M_next++ = __c; | |
18169e8e | 2414 | if (_M_next - _M_span.begin() == std::ssize(_M_span)) [[unlikely]] |
1d9454ab JW |
2415 | _M_overflow(); |
2416 | } | |
2417 | ||
2418 | constexpr void | |
2419 | _M_write(basic_string_view<_CharT> __s) | |
2420 | { | |
2421 | span __to = _M_unused(); | |
2422 | while (__to.size() <= __s.size()) | |
2423 | { | |
2424 | __s.copy(__to.data(), __to.size()); | |
2425 | _M_next += __to.size(); | |
2426 | __s.remove_prefix(__to.size()); | |
2427 | _M_overflow(); | |
2428 | __to = _M_unused(); | |
2429 | } | |
2430 | if (__s.size()) | |
2431 | { | |
2432 | __s.copy(__to.data(), __s.size()); | |
2433 | _M_next += __s.size(); | |
2434 | } | |
2435 | } | |
2436 | ||
2437 | public: | |
2438 | _Sink(const _Sink&) = delete; | |
2439 | _Sink& operator=(const _Sink&) = delete; | |
2440 | ||
2441 | [[__gnu__::__always_inline__]] | |
2442 | constexpr _Sink_iter<_CharT> | |
2443 | out() noexcept | |
2444 | { return _Sink_iter<_CharT>(*this); } | |
2445 | }; | |
2446 | ||
2447 | // A sink with an internal buffer. This is used to implement concrete sinks. | |
2448 | template<typename _CharT> | |
2449 | class _Buf_sink : public _Sink<_CharT> | |
2450 | { | |
2451 | protected: | |
2452 | _CharT _M_buf[32 * sizeof(void*) / sizeof(_CharT)]; | |
2453 | ||
2454 | [[__gnu__::__always_inline__]] | |
2455 | constexpr | |
2456 | _Buf_sink() noexcept | |
2457 | : _Sink<_CharT>(_M_buf) | |
2458 | { } | |
2459 | }; | |
2460 | ||
2461 | // A sink that fills a sequence (e.g. std::string, std::vector, std::deque). | |
2462 | // Writes to a buffer then appends that to the sequence when it fills up. | |
2463 | template<typename _Seq> | |
2464 | class _Seq_sink : public _Buf_sink<typename _Seq::value_type> | |
2465 | { | |
2466 | using _CharT = typename _Seq::value_type; | |
2467 | ||
2468 | _Seq _M_seq; | |
2469 | ||
2470 | // Transfer buffer contents to the sequence, so buffer can be refilled. | |
2471 | void | |
2472 | _M_overflow() override | |
2473 | { | |
2474 | auto __s = this->_M_used(); | |
2475 | if constexpr (__is_specialization_of<_Seq, basic_string>) | |
2476 | _M_seq.append(__s.data(), __s.size()); | |
2477 | else | |
2478 | _M_seq.insert(_M_seq.end(), __s.begin(), __s.end()); | |
2479 | this->_M_rewind(); | |
2480 | } | |
2481 | ||
2482 | public: | |
2483 | [[__gnu__::__always_inline__]] | |
2484 | _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>) | |
2485 | { } | |
2486 | ||
2487 | _Seq_sink(_Seq&& __s) noexcept(is_nothrow_move_constructible_v<_Seq>) | |
2488 | : _M_seq(std::move(__s)) | |
2489 | { } | |
2490 | ||
2491 | using _Sink<_CharT>::out; | |
2492 | ||
2493 | _Seq | |
2494 | get() && | |
2495 | { | |
003016a4 JW |
2496 | if (this->_M_used().size() != 0) |
2497 | _Seq_sink::_M_overflow(); | |
1d9454ab JW |
2498 | return std::move(_M_seq); |
2499 | } | |
2500 | }; | |
2501 | ||
2502 | template<typename _CharT, typename _Alloc = allocator<_CharT>> | |
2503 | using _Str_sink | |
2504 | = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>; | |
2505 | ||
2506 | // template<typename _CharT, typename _Alloc = allocator<_CharT>> | |
2507 | // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>; | |
2508 | ||
2509 | // A sink that writes to an output iterator. | |
2510 | // Writes to a fixed-size buffer and then flushes to the output iterator | |
2511 | // when the buffer fills up. | |
2512 | template<typename _CharT, typename _OutIter> | |
2513 | class _Iter_sink : public _Buf_sink<_CharT> | |
2514 | { | |
2515 | _OutIter _M_out; | |
2516 | iter_difference_t<_OutIter> _M_max; | |
2517 | ||
2518 | protected: | |
2519 | size_t _M_count = 0; | |
2520 | ||
2521 | void | |
2522 | _M_overflow() override | |
2523 | { | |
0ded30b3 | 2524 | auto __s = this->_M_used(); |
1d9454ab | 2525 | if (_M_max < 0) // No maximum. |
0ded30b3 | 2526 | _M_out = ranges::copy(__s, std::move(_M_out)).out; |
9cce91a6 | 2527 | else if (_M_count < static_cast<size_t>(_M_max)) |
1d9454ab JW |
2528 | { |
2529 | auto __max = _M_max - _M_count; | |
2530 | span<_CharT> __first; | |
0ded30b3 | 2531 | if (__max < __s.size()) |
9cce91a6 | 2532 | __first = __s.first(static_cast<size_t>(__max)); |
1d9454ab | 2533 | else |
0ded30b3 | 2534 | __first = __s; |
1d9454ab JW |
2535 | _M_out = ranges::copy(__first, std::move(_M_out)).out; |
2536 | } | |
2537 | this->_M_rewind(); | |
0ded30b3 | 2538 | _M_count += __s.size(); |
1d9454ab JW |
2539 | } |
2540 | ||
2541 | public: | |
2542 | [[__gnu__::__always_inline__]] | |
2543 | explicit | |
2544 | _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max = -1) | |
2545 | : _M_out(std::move(__out)), _M_max(__max) | |
2546 | { } | |
2547 | ||
2548 | using _Sink<_CharT>::out; | |
2549 | ||
2550 | format_to_n_result<_OutIter> | |
2551 | _M_finish() && | |
2552 | { | |
003016a4 JW |
2553 | if (this->_M_used().size() != 0) |
2554 | _Iter_sink::_M_overflow(); | |
1d9454ab JW |
2555 | iter_difference_t<_OutIter> __count(_M_count); |
2556 | return { std::move(_M_out), __count }; | |
2557 | } | |
2558 | }; | |
2559 | ||
2560 | // Partial specialization for contiguous iterators. | |
2561 | // No buffer is used, characters are written straight to the iterator. | |
2562 | // We do not know the size of the output range, so the span size just grows | |
2563 | // as needed. The end of the span might be an invalid pointer outside the | |
2564 | // valid range, but we never actually call _M_span.end(). This class does | |
2565 | // not introduce any invalid pointer arithmetic or overflows that would not | |
2566 | // have happened anyway. | |
2567 | template<typename _CharT, contiguous_iterator _OutIter> | |
c5ea5aec | 2568 | requires same_as<iter_value_t<_OutIter>, _CharT> |
1d9454ab JW |
2569 | class _Iter_sink<_CharT, _OutIter> : public _Sink<_CharT> |
2570 | { | |
2571 | using uint64_t = __UINTPTR_TYPE__; | |
2572 | _OutIter _M_first; | |
2573 | iter_difference_t<_OutIter> _M_max = -1; | |
2574 | protected: | |
2575 | size_t _M_count = 0; | |
2576 | private: | |
2577 | _CharT _M_buf[64]; // Write here after outputting _M_max characters. | |
2578 | ||
2579 | protected: | |
2580 | void | |
003016a4 | 2581 | _M_overflow() override |
1d9454ab | 2582 | { |
003016a4 JW |
2583 | if (this->_M_unused().size() != 0) |
2584 | return; // No need to switch to internal buffer yet. | |
2585 | ||
0ded30b3 JW |
2586 | auto __s = this->_M_used(); |
2587 | _M_count += __s.size(); | |
1d9454ab JW |
2588 | |
2589 | if (_M_max >= 0) | |
2590 | { | |
2591 | // Span was already sized for the maximum character count, | |
2592 | // if it overflows then any further output must go to the | |
2593 | // internal buffer, to be discarded. | |
2594 | span<_CharT> __buf{_M_buf}; | |
2595 | this->_M_reset(__buf, __buf.begin()); | |
2596 | } | |
2597 | else | |
2598 | { | |
2599 | // No maximum character count. Just extend the span to allow | |
2600 | // writing more characters to it. | |
0ded30b3 | 2601 | this->_M_reset({__s.data(), __s.size() + 1024}, __s.end()); |
1d9454ab JW |
2602 | } |
2603 | } | |
2604 | ||
2605 | private: | |
2606 | static span<_CharT> | |
2607 | _S_make_span(_CharT* __ptr, iter_difference_t<_OutIter> __n, | |
2608 | span<_CharT> __buf) noexcept | |
2609 | { | |
2610 | if (__n == 0) | |
2611 | return __buf; // Only write to the internal buffer. | |
2612 | ||
2613 | if (__n > 0) | |
2614 | { | |
9cce91a6 | 2615 | if constexpr (!is_integral_v<iter_difference_t<_OutIter>> |
1d9454ab JW |
2616 | || sizeof(__n) > sizeof(size_t)) |
2617 | { | |
2618 | // __int128 or __detail::__max_diff_type | |
9cce91a6 | 2619 | auto __m = iter_difference_t<_OutIter>((size_t)-1); |
1d9454ab JW |
2620 | if (__n > __m) |
2621 | __n = __m; | |
2622 | } | |
2623 | return {__ptr, (size_t)__n}; | |
2624 | } | |
2625 | ||
2626 | #if __has_builtin(__builtin_dynamic_object_size) | |
2627 | if (size_t __bytes = __builtin_dynamic_object_size(__ptr, 2)) | |
2628 | return {__ptr, __bytes / sizeof(_CharT)}; | |
2629 | #endif | |
2630 | // Avoid forming a pointer to a different memory page. | |
2631 | uint64_t __off = reinterpret_cast<uint64_t>(__ptr) % 1024; | |
2632 | __n = (1024 - __off) / sizeof(_CharT); | |
2633 | if (__n > 0) [[likely]] | |
2634 | return {__ptr, static_cast<size_t>(__n)}; | |
2635 | else // Misaligned/packed buffer of wchar_t? | |
2636 | return {__ptr, 1}; | |
2637 | } | |
2638 | ||
2639 | public: | |
2640 | explicit | |
2641 | _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __n = -1) noexcept | |
2642 | : _Sink<_CharT>(_S_make_span(std::to_address(__out), __n, _M_buf)), | |
2643 | _M_first(__out), _M_max(__n) | |
2644 | { } | |
2645 | ||
2646 | format_to_n_result<_OutIter> | |
2647 | _M_finish() && | |
2648 | { | |
0ded30b3 | 2649 | auto __s = this->_M_used(); |
003016a4 JW |
2650 | if (__s.data() == _M_buf) |
2651 | { | |
2652 | // Switched to internal buffer, so must have written _M_max. | |
2653 | iter_difference_t<_OutIter> __count(_M_count + __s.size()); | |
2654 | return { _M_first + _M_max, __count }; | |
2655 | } | |
2656 | else // Not using internal buffer yet | |
2657 | { | |
2658 | iter_difference_t<_OutIter> __count(__s.size()); | |
2659 | return { _M_first + __count, __count }; | |
2660 | } | |
1d9454ab JW |
2661 | } |
2662 | }; | |
2663 | ||
2664 | enum _Arg_t : unsigned char { | |
2665 | _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull, | |
2666 | _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle, | |
2667 | _Arg_i128, _Arg_u128, | |
b9e5a4b4 | 2668 | _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused. |
1d9454ab JW |
2669 | #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT |
2670 | _Arg_next_value_, | |
2671 | _Arg_f128 = _Arg_ldbl, | |
dbdce6ad | 2672 | _Arg_ibm128 = _Arg_next_value_, |
1d9454ab JW |
2673 | #else |
2674 | _Arg_f128, | |
2675 | #endif | |
2676 | _Arg_max_ | |
2677 | }; | |
2678 | ||
2679 | template<typename _Context> | |
2680 | struct _Arg_value | |
2681 | { | |
2682 | using _CharT = typename _Context::char_type; | |
2683 | ||
2684 | struct _HandleBase | |
2685 | { | |
2686 | const void* _M_ptr; | |
2687 | void (*_M_func)(); | |
2688 | }; | |
2689 | ||
2690 | union | |
2691 | { | |
2692 | monostate _M_none; | |
2693 | bool _M_bool; | |
2694 | _CharT _M_c; | |
2695 | int _M_i; | |
2696 | unsigned _M_u; | |
2697 | long long _M_ll; | |
2698 | unsigned long long _M_ull; | |
2699 | float _M_flt; | |
2700 | double _M_dbl; | |
2701 | #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous. | |
2702 | long double _M_ldbl; | |
2703 | #endif | |
2704 | const _CharT* _M_str; | |
2705 | basic_string_view<_CharT> _M_sv; | |
2706 | const void* _M_ptr; | |
2707 | _HandleBase _M_handle; | |
2708 | #ifdef __SIZEOF_INT128__ | |
2709 | __int128 _M_i128; | |
2710 | unsigned __int128 _M_u128; | |
2711 | #endif | |
2712 | // TODO _Float16 etc. | |
2713 | #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT | |
2714 | __ieee128 _M_f128; | |
2715 | __ibm128 _M_ibm128; | |
ce86d967 | 2716 | #elif _GLIBCXX_FORMAT_F128 == 2 |
1d9454ab JW |
2717 | __float128_t _M_f128; |
2718 | #endif | |
2719 | }; | |
2720 | ||
2721 | [[__gnu__::__always_inline__]] | |
2722 | _Arg_value() : _M_none() { } | |
2723 | ||
2724 | #if 0 | |
2725 | template<typename _Tp> | |
2726 | _Arg_value(in_place_type_t<_Tp>, _Tp __val) | |
2727 | { _S_get<_Tp>() = __val; } | |
2728 | #endif | |
2729 | ||
2730 | template<typename _Tp, typename _Self> | |
2731 | [[__gnu__::__always_inline__]] | |
2732 | static auto& | |
2733 | _S_get(_Self& __u) noexcept | |
2734 | { | |
2735 | if constexpr (is_same_v<_Tp, bool>) | |
2736 | return __u._M_bool; | |
2737 | else if constexpr (is_same_v<_Tp, _CharT>) | |
2738 | return __u._M_c; | |
2739 | else if constexpr (is_same_v<_Tp, int>) | |
2740 | return __u._M_i; | |
2741 | else if constexpr (is_same_v<_Tp, unsigned>) | |
2742 | return __u._M_u; | |
2743 | else if constexpr (is_same_v<_Tp, long long>) | |
2744 | return __u._M_ll; | |
2745 | else if constexpr (is_same_v<_Tp, unsigned long long>) | |
2746 | return __u._M_ull; | |
2747 | else if constexpr (is_same_v<_Tp, float>) | |
2748 | return __u._M_flt; | |
2749 | else if constexpr (is_same_v<_Tp, double>) | |
2750 | return __u._M_dbl; | |
2751 | #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT | |
2752 | else if constexpr (is_same_v<_Tp, long double>) | |
2753 | return __u._M_ldbl; | |
2754 | #else | |
2755 | else if constexpr (is_same_v<_Tp, __ieee128>) | |
2756 | return __u._M_f128; | |
2757 | else if constexpr (is_same_v<_Tp, __ibm128>) | |
2758 | return __u._M_ibm128; | |
2759 | #endif | |
2760 | else if constexpr (is_same_v<_Tp, const _CharT*>) | |
2761 | return __u._M_str; | |
2762 | else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>) | |
2763 | return __u._M_sv; | |
2764 | else if constexpr (is_same_v<_Tp, const void*>) | |
2765 | return __u._M_ptr; | |
2766 | #ifdef __SIZEOF_INT128__ | |
2767 | else if constexpr (is_same_v<_Tp, __int128>) | |
2768 | return __u._M_i128; | |
2769 | else if constexpr (is_same_v<_Tp, unsigned __int128>) | |
2770 | return __u._M_u128; | |
2771 | #endif | |
ce86d967 | 2772 | #if _GLIBCXX_FORMAT_F128 == 2 |
1d9454ab JW |
2773 | else if constexpr (is_same_v<_Tp, __float128_t>) |
2774 | return __u._M_f128; | |
2775 | #endif | |
2776 | else if constexpr (derived_from<_Tp, _HandleBase>) | |
2777 | return static_cast<_Tp&>(__u._M_handle); | |
2778 | // Otherwise, ill-formed. | |
2779 | } | |
2780 | ||
2781 | template<typename _Tp> | |
2782 | [[__gnu__::__always_inline__]] | |
2783 | auto& | |
2784 | _M_get() noexcept | |
2785 | { return _S_get<_Tp>(*this); } | |
2786 | ||
2787 | template<typename _Tp> | |
2788 | [[__gnu__::__always_inline__]] | |
2789 | const auto& | |
2790 | _M_get() const noexcept | |
2791 | { return _S_get<_Tp>(*this); } | |
2792 | ||
2793 | template<typename _Tp> | |
2794 | [[__gnu__::__always_inline__]] | |
2795 | void | |
2796 | _M_set(_Tp __v) noexcept | |
2797 | { | |
2798 | if constexpr (derived_from<_Tp, _HandleBase>) | |
2799 | std::construct_at(&_M_handle, __v); | |
2800 | else | |
2801 | _S_get<_Tp>(*this) = __v; | |
2802 | } | |
2803 | }; | |
2804 | ||
4024f399 JW |
2805 | // [format.arg.store], class template format-arg-store |
2806 | template<typename _Context, typename... _Args> | |
2807 | class _Arg_store; | |
2808 | ||
1d9454ab JW |
2809 | } // namespace __format |
2810 | /// @endcond | |
2811 | ||
2812 | template<typename _Context> | |
2813 | class basic_format_arg | |
2814 | { | |
2815 | using _CharT = typename _Context::char_type; | |
2816 | ||
2817 | template<typename _Tp> | |
2818 | static constexpr bool __formattable | |
2819 | = __format::__formattable_with<_Tp, _Context>; | |
2820 | ||
2821 | public: | |
2822 | class handle : public __format::_Arg_value<_Context>::_HandleBase | |
2823 | { | |
2f5c0718 | 2824 | using _Base = typename __format::_Arg_value<_Context>::_HandleBase; |
1d9454ab JW |
2825 | |
2826 | // Format as const if possible, to reduce instantiations. | |
2827 | template<typename _Tp> | |
2828 | using __maybe_const_t | |
2829 | = __conditional_t<__format::__formattable_with<_Tp, _Context>, | |
2830 | const _Tp, _Tp>; | |
2831 | ||
2832 | template<typename _Tq> | |
2833 | static void | |
2834 | _S_format(basic_format_parse_context<_CharT>& __parse_ctx, | |
2835 | _Context& __format_ctx, const void* __ptr) | |
2836 | { | |
2837 | using _Td = remove_const_t<_Tq>; | |
2838 | typename _Context::template formatter_type<_Td> __f; | |
2839 | __parse_ctx.advance_to(__f.parse(__parse_ctx)); | |
2840 | _Tq& __val = *const_cast<_Tq*>(static_cast<const _Td*>(__ptr)); | |
2841 | __format_ctx.advance_to(__f.format(__val, __format_ctx)); | |
2842 | } | |
2843 | ||
2844 | template<typename _Tp> | |
2845 | explicit | |
2846 | handle(_Tp& __val) noexcept | |
2847 | { | |
2848 | if constexpr (!__format::__formattable_with<const _Tp, _Context>) | |
2849 | static_assert(!is_const_v<_Tp>, "std::format argument must be " | |
2850 | "non-const for this type"); | |
2851 | ||
2852 | this->_M_ptr = __builtin_addressof(__val); | |
2853 | auto __func = _S_format<__maybe_const_t<_Tp>>; | |
2854 | this->_M_func = reinterpret_cast<void(*)()>(__func); | |
2855 | } | |
2856 | ||
2857 | friend class basic_format_arg<_Context>; | |
2858 | ||
2859 | public: | |
2860 | handle(const handle&) = default; | |
2861 | handle& operator=(const handle&) = default; | |
2862 | ||
2863 | [[__gnu__::__always_inline__]] | |
2864 | void | |
2865 | format(basic_format_parse_context<_CharT>& __pc, _Context& __fc) const | |
2866 | { | |
2867 | using _Func = void(*)(basic_format_parse_context<_CharT>&, | |
2868 | _Context&, const void*); | |
2869 | auto __f = reinterpret_cast<_Func>(this->_M_func); | |
2870 | __f(__pc, __fc, this->_M_ptr); | |
2871 | } | |
2872 | }; | |
2873 | ||
2874 | [[__gnu__::__always_inline__]] | |
2875 | basic_format_arg() noexcept : _M_type(__format::_Arg_none) { } | |
2876 | ||
2877 | [[nodiscard,__gnu__::__always_inline__]] | |
2878 | explicit operator bool() const noexcept | |
2879 | { return _M_type != __format::_Arg_none; } | |
2880 | ||
2881 | private: | |
2882 | template<typename _Ctx> | |
2883 | friend class basic_format_args; | |
2884 | ||
4024f399 JW |
2885 | template<typename _Ctx, typename... _Args> |
2886 | friend class __format::_Arg_store; | |
2887 | ||
1d9454ab JW |
2888 | static_assert(is_trivially_copyable_v<__format::_Arg_value<_Context>>); |
2889 | ||
2890 | __format::_Arg_value<_Context> _M_val; | |
2891 | __format::_Arg_t _M_type; | |
2892 | ||
2893 | // Transform incoming argument type to the type stored in _Arg_value. | |
2894 | // e.g. short -> int, std::string -> std::string_view, | |
2895 | // char[3] -> const char*. | |
2896 | template<typename _Tp> | |
2897 | static consteval auto | |
2898 | _S_to_arg_type() | |
2899 | { | |
2900 | using _Td = remove_const_t<_Tp>; | |
2901 | if constexpr (is_same_v<_Td, bool>) | |
2902 | return type_identity<bool>(); | |
2903 | else if constexpr (is_same_v<_Td, _CharT>) | |
2904 | return type_identity<_CharT>(); | |
2905 | else if constexpr (is_same_v<_Td, char> && is_same_v<_CharT, wchar_t>) | |
2906 | return type_identity<_CharT>(); | |
2907 | #ifdef __SIZEOF_INT128__ // Check before signed/unsigned integer | |
2908 | else if constexpr (is_same_v<_Td, __int128>) | |
2909 | return type_identity<__int128>(); | |
2910 | else if constexpr (is_same_v<_Td, unsigned __int128>) | |
2911 | return type_identity<unsigned __int128>(); | |
2912 | #endif | |
2913 | else if constexpr (__is_signed_integer<_Td>::value) | |
2914 | { | |
2915 | if constexpr (sizeof(_Td) <= sizeof(int)) | |
2916 | return type_identity<int>(); | |
2917 | else if constexpr (sizeof(_Td) <= sizeof(long long)) | |
2918 | return type_identity<long long>(); | |
2919 | } | |
2920 | else if constexpr (__is_unsigned_integer<_Td>::value) | |
2921 | { | |
2922 | if constexpr (sizeof(_Td) <= sizeof(unsigned)) | |
2923 | return type_identity<unsigned>(); | |
2924 | else if constexpr (sizeof(_Td) <= sizeof(unsigned long long)) | |
2925 | return type_identity<unsigned long long>(); | |
2926 | } | |
2927 | else if constexpr (is_same_v<_Td, float>) | |
2928 | return type_identity<float>(); | |
2929 | else if constexpr (is_same_v<_Td, double>) | |
2930 | return type_identity<double>(); | |
2931 | #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT | |
2932 | else if constexpr (is_same_v<_Td, long double>) | |
2933 | return type_identity<long double>(); | |
2934 | #else | |
2935 | else if constexpr (is_same_v<_Td, __ibm128>) | |
2936 | return type_identity<__ibm128>(); | |
2937 | else if constexpr (is_same_v<_Td, __ieee128>) | |
2938 | return type_identity<__ieee128>(); | |
2939 | #endif | |
2940 | ||
2941 | // TODO bfloat16 and float16 | |
2942 | ||
2943 | #ifdef __FLT32_DIG__ | |
2944 | else if constexpr (is_same_v<_Td, _Float32>) | |
2945 | # ifdef _GLIBCXX_FLOAT_IS_IEEE_BINARY32 | |
2946 | return type_identity<float>(); | |
2947 | # else | |
2948 | return type_identity<_Float32>(); | |
2949 | # endif | |
2950 | #endif | |
2951 | #ifdef __FLT64_DIG__ | |
2952 | else if constexpr (is_same_v<_Td, _Float64>) | |
2953 | # ifdef _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 | |
2954 | return type_identity<double>(); | |
2955 | # else | |
2956 | return type_identity<_Float64>(); | |
2957 | # endif | |
2958 | #endif | |
ce86d967 JW |
2959 | #if _GLIBCXX_FORMAT_F128 |
2960 | # if __FLT128_DIG__ | |
1d9454ab JW |
2961 | else if constexpr (is_same_v<_Td, _Float128>) |
2962 | return type_identity<__format::__float128_t>(); | |
ce86d967 JW |
2963 | # endif |
2964 | # if __SIZEOF_FLOAT128__ | |
1d9454ab JW |
2965 | else if constexpr (is_same_v<_Td, __float128>) |
2966 | return type_identity<__format::__float128_t>(); | |
ce86d967 | 2967 | # endif |
1d9454ab JW |
2968 | #endif |
2969 | else if constexpr (__is_specialization_of<_Td, basic_string_view>) | |
2970 | return type_identity<basic_string_view<_CharT>>(); | |
2971 | else if constexpr (__is_specialization_of<_Td, basic_string>) | |
2972 | return type_identity<basic_string_view<_CharT>>(); | |
2973 | else if constexpr (is_same_v<decay_t<_Td>, const _CharT*>) | |
2974 | return type_identity<const _CharT*>(); | |
2975 | else if constexpr (is_same_v<decay_t<_Td>, _CharT*>) | |
2976 | return type_identity<const _CharT*>(); | |
2977 | else if constexpr (is_void_v<remove_pointer_t<_Td>>) | |
2978 | return type_identity<const void*>(); | |
2979 | else if constexpr (is_same_v<_Td, nullptr_t>) | |
2980 | return type_identity<const void*>(); | |
2981 | else | |
2982 | return type_identity<handle>(); | |
2983 | } | |
2984 | ||
2985 | // Transform a formattable type to the appropriate storage type. | |
2986 | template<typename _Tp> | |
2987 | using _Normalize = typename decltype(_S_to_arg_type<_Tp>())::type; | |
2988 | ||
2989 | // Get the _Arg_t value corresponding to a normalized type. | |
2990 | template<typename _Tp> | |
2991 | static consteval __format::_Arg_t | |
2992 | _S_to_enum() | |
2993 | { | |
2994 | using namespace __format; | |
2995 | if constexpr (is_same_v<_Tp, bool>) | |
2996 | return _Arg_bool; | |
2997 | else if constexpr (is_same_v<_Tp, _CharT>) | |
2998 | return _Arg_c; | |
2999 | else if constexpr (is_same_v<_Tp, int>) | |
3000 | return _Arg_i; | |
3001 | else if constexpr (is_same_v<_Tp, unsigned>) | |
3002 | return _Arg_u; | |
3003 | else if constexpr (is_same_v<_Tp, long long>) | |
3004 | return _Arg_ll; | |
3005 | else if constexpr (is_same_v<_Tp, unsigned long long>) | |
3006 | return _Arg_ull; | |
3007 | else if constexpr (is_same_v<_Tp, float>) | |
3008 | return _Arg_flt; | |
3009 | else if constexpr (is_same_v<_Tp, double>) | |
3010 | return _Arg_dbl; | |
3011 | #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT | |
3012 | else if constexpr (is_same_v<_Tp, long double>) | |
3013 | return _Arg_ldbl; | |
3014 | #else | |
3015 | // Don't use _Arg_ldbl for this target, it's ambiguous. | |
3016 | else if constexpr (is_same_v<_Tp, __ibm128>) | |
dbdce6ad | 3017 | return _Arg_ibm128; |
1d9454ab | 3018 | else if constexpr (is_same_v<_Tp, __ieee128>) |
dbdce6ad | 3019 | return _Arg_f128; |
1d9454ab JW |
3020 | #endif |
3021 | else if constexpr (is_same_v<_Tp, const _CharT*>) | |
3022 | return _Arg_str; | |
3023 | else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>) | |
3024 | return _Arg_sv; | |
3025 | else if constexpr (is_same_v<_Tp, const void*>) | |
3026 | return _Arg_ptr; | |
3027 | #ifdef __SIZEOF_INT128__ | |
3028 | else if constexpr (is_same_v<_Tp, __int128>) | |
3029 | return _Arg_i128; | |
3030 | else if constexpr (is_same_v<_Tp, unsigned __int128>) | |
3031 | return _Arg_u128; | |
3032 | #endif | |
3033 | ||
3034 | // N.B. some of these types will never actually be used here, | |
3035 | // because they get normalized to a standard floating-point type. | |
3036 | #if defined __FLT32_DIG__ && ! _GLIBCXX_FLOAT_IS_IEEE_BINARY32 | |
3037 | else if constexpr (is_same_v<_Tp, _Float32>) | |
3038 | return _Arg_f32; | |
3039 | #endif | |
3040 | #if defined __FLT64_DIG__ && ! _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 | |
3041 | else if constexpr (is_same_v<_Tp, _Float64>) | |
3042 | return _Arg_f64; | |
3043 | #endif | |
ce86d967 | 3044 | #if _GLIBCXX_FORMAT_F128 == 2 |
1d9454ab JW |
3045 | else if constexpr (is_same_v<_Tp, __format::__float128_t>) |
3046 | return _Arg_f128; | |
3047 | #endif | |
3048 | else if constexpr (is_same_v<_Tp, handle>) | |
3049 | return _Arg_handle; | |
3050 | } | |
3051 | ||
3052 | template<typename _Tp> | |
3053 | void | |
3054 | _M_set(_Tp __v) noexcept | |
3055 | { | |
3056 | _M_type = _S_to_enum<_Tp>(); | |
3057 | _M_val._M_set(__v); | |
3058 | } | |
3059 | ||
3060 | template<typename _Tp> | |
3061 | requires __format::__formattable_with<_Tp, _Context> | |
3062 | explicit | |
3063 | basic_format_arg(_Tp& __v) noexcept | |
3064 | { | |
3065 | using _Td = _Normalize<_Tp>; | |
3066 | if constexpr (is_same_v<_Td, basic_string_view<_CharT>>) | |
3067 | _M_set(_Td{__v.data(), __v.size()}); | |
3068 | else | |
3069 | _M_set(static_cast<_Td>(__v)); | |
3070 | } | |
3071 | ||
3072 | template<typename _Ctx, typename... _Argz> | |
3073 | friend auto | |
3074 | make_format_args(_Argz&&...) noexcept; | |
3075 | ||
3076 | template<typename _Visitor, typename _Ctx> | |
3077 | friend decltype(auto) | |
3078 | visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>); | |
3079 | ||
3080 | template<typename _Visitor> | |
3081 | decltype(auto) | |
3082 | _M_visit(_Visitor&& __vis, __format::_Arg_t __type) | |
3083 | { | |
3084 | using namespace __format; | |
3085 | switch (__type) | |
3086 | { | |
3087 | case _Arg_none: | |
3088 | return std::forward<_Visitor>(__vis)(_M_val._M_none); | |
3089 | case _Arg_bool: | |
3090 | return std::forward<_Visitor>(__vis)(_M_val._M_bool); | |
3091 | case _Arg_c: | |
3092 | return std::forward<_Visitor>(__vis)(_M_val._M_c); | |
3093 | case _Arg_i: | |
3094 | return std::forward<_Visitor>(__vis)(_M_val._M_i); | |
3095 | case _Arg_u: | |
3096 | return std::forward<_Visitor>(__vis)(_M_val._M_u); | |
3097 | case _Arg_ll: | |
3098 | return std::forward<_Visitor>(__vis)(_M_val._M_ll); | |
3099 | case _Arg_ull: | |
3100 | return std::forward<_Visitor>(__vis)(_M_val._M_ull); | |
8c330fd4 | 3101 | #if __cpp_lib_to_chars // FIXME: need to be able to format these types! |
1d9454ab JW |
3102 | case _Arg_flt: |
3103 | return std::forward<_Visitor>(__vis)(_M_val._M_flt); | |
3104 | case _Arg_dbl: | |
3105 | return std::forward<_Visitor>(__vis)(_M_val._M_dbl); | |
3106 | #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT | |
3107 | case _Arg_ldbl: | |
3108 | return std::forward<_Visitor>(__vis)(_M_val._M_ldbl); | |
3109 | #else | |
3110 | case _Arg_f128: | |
3111 | return std::forward<_Visitor>(__vis)(_M_val._M_f128); | |
3112 | case _Arg_ibm128: | |
3113 | return std::forward<_Visitor>(__vis)(_M_val._M_ibm128); | |
8c330fd4 | 3114 | #endif |
1d9454ab JW |
3115 | #endif |
3116 | case _Arg_str: | |
3117 | return std::forward<_Visitor>(__vis)(_M_val._M_str); | |
3118 | case _Arg_sv: | |
3119 | return std::forward<_Visitor>(__vis)(_M_val._M_sv); | |
3120 | case _Arg_ptr: | |
3121 | return std::forward<_Visitor>(__vis)(_M_val._M_ptr); | |
3122 | case _Arg_handle: | |
3123 | { | |
3124 | auto& __h = static_cast<handle&>(_M_val._M_handle); | |
3125 | return std::forward<_Visitor>(__vis)(__h); | |
3126 | } | |
3127 | #ifdef __SIZEOF_INT128__ | |
3128 | case _Arg_i128: | |
3129 | return std::forward<_Visitor>(__vis)(_M_val._M_i128); | |
3130 | case _Arg_u128: | |
3131 | return std::forward<_Visitor>(__vis)(_M_val._M_u128); | |
3132 | #endif | |
1d9454ab | 3133 | |
ce86d967 | 3134 | #if _GLIBCXX_FORMAT_F128 == 2 |
1d9454ab JW |
3135 | case _Arg_f128: |
3136 | return std::forward<_Visitor>(__vis)(_M_val._M_f128); | |
3137 | #endif | |
b9e5a4b4 JW |
3138 | |
3139 | default: | |
3140 | // _Arg_f16 etc. | |
3141 | __builtin_unreachable(); | |
1d9454ab | 3142 | } |
1d9454ab JW |
3143 | } |
3144 | }; | |
3145 | ||
3146 | template<typename _Visitor, typename _Context> | |
3147 | inline decltype(auto) | |
3148 | visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) | |
3149 | { | |
3150 | return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type); | |
3151 | } | |
3152 | ||
3153 | /// @cond undocumented | |
3154 | namespace __format | |
3155 | { | |
3156 | struct _WidthPrecVisitor | |
3157 | { | |
3158 | template<typename _Tp> | |
3159 | size_t | |
3160 | operator()(_Tp& __arg) const | |
3161 | { | |
3162 | if constexpr (is_same_v<_Tp, monostate>) | |
3163 | __format::__invalid_arg_id_in_format_string(); | |
3164 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
3165 | // 3720. Restrict the valid types of arg-id for width and precision | |
3166 | // 3721. Allow an arg-id with a value of zero for width | |
3167 | else if constexpr (sizeof(_Tp) <= sizeof(long long)) | |
3168 | { | |
7d4f4ce6 JW |
3169 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
3170 | // 3720. Restrict the valid types of arg-id for width and precision | |
1d9454ab JW |
3171 | if constexpr (__is_unsigned_integer<_Tp>::value) |
3172 | return __arg; | |
3173 | else if constexpr (__is_signed_integer<_Tp>::value) | |
3174 | if (__arg >= 0) | |
3175 | return __arg; | |
3176 | } | |
3177 | __throw_format_error("format error: argument used for width or " | |
3178 | "precision must be a non-negative integer"); | |
3179 | } | |
3180 | }; | |
3181 | ||
3182 | template<typename _Context> | |
3183 | inline size_t | |
3184 | __int_from_arg(const basic_format_arg<_Context>& __arg) | |
3185 | { return std::visit_format_arg(_WidthPrecVisitor(), __arg); } | |
3186 | ||
3187 | // Pack _Arg_t enum values into a single 60-bit integer. | |
3188 | template<int _Bits, size_t _Nm> | |
3189 | constexpr auto | |
3190 | __pack_arg_types(const array<_Arg_t, _Nm>& __types) | |
3191 | { | |
0ded30b3 | 3192 | __UINT64_TYPE__ __packed_types = 0; |
1d9454ab | 3193 | for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i) |
0ded30b3 JW |
3194 | __packed_types = (__packed_types << _Bits) | *__i; |
3195 | return __packed_types; | |
1d9454ab JW |
3196 | } |
3197 | } // namespace __format | |
3198 | /// @endcond | |
3199 | ||
3200 | template<typename _Context> | |
3201 | class basic_format_args | |
3202 | { | |
3203 | static constexpr int _S_packed_type_bits = 5; // _Arg_t values [0,20] | |
3204 | static constexpr int _S_packed_type_mask = 0b11111; | |
3205 | static constexpr int _S_max_packed_args = 12; | |
3206 | ||
3207 | static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) ); | |
3208 | ||
1d9454ab | 3209 | template<typename... _Args> |
4024f399 JW |
3210 | using _Store = __format::_Arg_store<_Context, _Args...>; |
3211 | ||
3212 | template<typename _Ctx, typename... _Args> | |
3213 | friend class __format::_Arg_store; | |
1d9454ab JW |
3214 | |
3215 | using uint64_t = __UINT64_TYPE__; | |
3216 | using _Format_arg = basic_format_arg<_Context>; | |
3217 | using _Format_arg_val = __format::_Arg_value<_Context>; | |
3218 | ||
3219 | // If args are packed then the number of args is in _M_packed_size and | |
3220 | // the packed types are in _M_unpacked_size, accessed via _M_type(i). | |
3221 | // If args are not packed then the number of args is in _M_unpacked_size | |
3222 | // and _M_packed_size is zero. | |
3223 | uint64_t _M_packed_size : 4; | |
3224 | uint64_t _M_unpacked_size : 60; | |
3225 | ||
3226 | union { | |
3227 | const _Format_arg_val* _M_values; // Active when _M_packed_size != 0 | |
3228 | const _Format_arg* _M_args; // Active when _M_packed_size == 0 | |
3229 | }; | |
3230 | ||
3231 | size_t | |
3232 | _M_size() const noexcept | |
3233 | { return _M_packed_size ? _M_packed_size : _M_unpacked_size; } | |
3234 | ||
3235 | typename __format::_Arg_t | |
3236 | _M_type(size_t __i) const noexcept | |
3237 | { | |
3238 | uint64_t __t = _M_unpacked_size >> (__i * _S_packed_type_bits); | |
3239 | return static_cast<__format::_Arg_t>(__t & _S_packed_type_mask); | |
3240 | } | |
3241 | ||
3242 | template<typename _Ctx, typename... _Args> | |
3243 | friend auto | |
3244 | make_format_args(_Args&&...) noexcept; | |
3245 | ||
3246 | // An array of _Arg_t enums corresponding to _Args... | |
3247 | template<typename... _Args> | |
3248 | static consteval array<__format::_Arg_t, sizeof...(_Args)> | |
3249 | _S_types_to_pack() | |
3250 | { return {_Format_arg::template _S_to_enum<_Args>()...}; } | |
3251 | ||
3252 | public: | |
3253 | basic_format_args() noexcept = default; | |
3254 | ||
3255 | template<typename... _Args> | |
3256 | basic_format_args(const _Store<_Args...>& __store) noexcept; | |
3257 | ||
3258 | [[nodiscard,__gnu__::__always_inline__]] | |
3259 | basic_format_arg<_Context> | |
3260 | get(size_t __i) const noexcept | |
3261 | { | |
3262 | basic_format_arg<_Context> __arg; | |
3263 | if (__i < _M_packed_size) | |
3264 | { | |
3265 | __arg._M_type = _M_type(__i); | |
3266 | __arg._M_val = _M_values[__i]; | |
3267 | } | |
3268 | else if (_M_packed_size == 0 && __i < _M_unpacked_size) | |
3269 | __arg = _M_args[__i]; | |
3270 | return __arg; | |
3271 | } | |
3272 | }; | |
3273 | ||
4024f399 JW |
3274 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
3275 | // 3810. CTAD for std::basic_format_args | |
3276 | template<typename _Context, typename... _Args> | |
3277 | basic_format_args(__format::_Arg_store<_Context, _Args...>) | |
3278 | -> basic_format_args<_Context>; | |
3279 | ||
3280 | template<typename _Context, typename... _Args> | |
3281 | auto | |
3282 | make_format_args(_Args&&... __fmt_args) noexcept; | |
3283 | ||
1d9454ab | 3284 | // An array of type-erased formatting arguments. |
4024f399 JW |
3285 | template<typename _Context, typename... _Args> |
3286 | class __format::_Arg_store | |
3287 | { | |
3288 | friend std::basic_format_args<_Context>; | |
1d9454ab | 3289 | |
4024f399 JW |
3290 | template<typename _Ctx, typename... _Argz> |
3291 | friend auto | |
3292 | std::make_format_args(_Argz&&...) noexcept; | |
1d9454ab | 3293 | |
4024f399 JW |
3294 | // For a sufficiently small number of arguments we only store values. |
3295 | // basic_format_args can get the types from the _Args pack. | |
3296 | static constexpr bool _S_values_only | |
3297 | = sizeof...(_Args) <= basic_format_args<_Context>::_S_max_packed_args; | |
1d9454ab | 3298 | |
4024f399 JW |
3299 | using _Element_t |
3300 | = __conditional_t<_S_values_only, | |
3301 | __format::_Arg_value<_Context>, | |
3302 | basic_format_arg<_Context>>; | |
1d9454ab | 3303 | |
4024f399 | 3304 | _Element_t _M_args[sizeof...(_Args)]; |
1d9454ab | 3305 | |
4024f399 JW |
3306 | template<typename _Tp> |
3307 | static _Element_t | |
3308 | _S_make_elt(_Tp& __v) | |
3309 | { | |
3310 | basic_format_arg<_Context> __arg(__v); | |
3311 | if constexpr (_S_values_only) | |
3312 | return __arg._M_val; | |
3313 | else | |
3314 | return __arg; | |
3315 | } | |
1d9454ab | 3316 | |
4024f399 JW |
3317 | template<typename... _Tp> |
3318 | requires (sizeof...(_Tp) == sizeof...(_Args)) | |
3319 | [[__gnu__::__always_inline__]] | |
3320 | _Arg_store(_Tp&... __a) noexcept | |
3321 | : _M_args{_S_make_elt(__a)...} | |
3322 | { } | |
3323 | }; | |
1d9454ab JW |
3324 | |
3325 | template<typename _Context> | |
4024f399 JW |
3326 | class __format::_Arg_store<_Context> |
3327 | { }; | |
1d9454ab JW |
3328 | |
3329 | template<typename _Context> | |
3330 | template<typename... _Args> | |
3331 | basic_format_args<_Context>:: | |
3332 | basic_format_args(const _Store<_Args...>& __store) noexcept | |
3333 | { | |
3334 | if constexpr (sizeof...(_Args) == 0) | |
3335 | { | |
3336 | _M_packed_size = 0; | |
3337 | _M_unpacked_size = 0; | |
3338 | _M_args = nullptr; | |
3339 | } | |
3340 | else if constexpr (sizeof...(_Args) <= _S_max_packed_args) | |
3341 | { | |
3342 | // The number of packed arguments: | |
3343 | _M_packed_size = sizeof...(_Args); | |
3344 | // The packed type enums: | |
3345 | _M_unpacked_size | |
3346 | = __format::__pack_arg_types<_S_packed_type_bits>(_S_types_to_pack<_Args...>()); | |
3347 | // The _Arg_value objects. | |
3348 | _M_values = __store._M_args; | |
3349 | } | |
3350 | else | |
3351 | { | |
3352 | // No packed arguments: | |
3353 | _M_packed_size = 0; | |
3354 | // The number of unpacked arguments: | |
3355 | _M_unpacked_size = sizeof...(_Args); | |
3356 | // The basic_format_arg objects: | |
3357 | _M_args = __store._M_args; | |
3358 | } | |
3359 | } | |
3360 | ||
3361 | /// Capture formatting arguments for use by `std::vformat`. | |
3362 | template<typename _Context = format_context, typename... _Args> | |
3363 | [[nodiscard,__gnu__::__always_inline__]] | |
3364 | inline auto | |
3365 | make_format_args(_Args&&... __fmt_args) noexcept | |
3366 | { | |
1d9454ab | 3367 | using _Fmt_arg = basic_format_arg<_Context>; |
4024f399 | 3368 | using _Store = __format::_Arg_store<_Context, typename _Fmt_arg::template |
1d9454ab JW |
3369 | _Normalize<remove_reference_t<_Args>>...>; |
3370 | return _Store(__fmt_args...); | |
3371 | } | |
3372 | ||
3373 | /// Capture formatting arguments for use by `std::vformat` (for wide output). | |
3374 | template<typename... _Args> | |
3375 | [[nodiscard,__gnu__::__always_inline__]] | |
3376 | inline auto | |
3377 | make_wformat_args(_Args&&... __args) noexcept | |
3378 | { return std::make_format_args<wformat_context>(__args...); } | |
3379 | ||
3380 | /// @cond undocumented | |
3381 | namespace __format | |
3382 | { | |
3383 | template<typename _Out, typename _CharT, typename _Context> | |
3384 | _Out | |
3385 | __do_vformat_to(_Out, basic_string_view<_CharT>, | |
3386 | const basic_format_args<_Context>&, | |
3387 | const locale* = nullptr); | |
3388 | } // namespace __format | |
3389 | /// @endcond | |
3390 | ||
3391 | /** Context for std::format and similar functions. | |
3392 | * | |
3393 | * A formatting context contains an output iterator and locale to use | |
3394 | * for the formatting operations. Most programs will never need to use | |
3395 | * this class template explicitly. For typical uses of `std::format` the | |
3396 | * library will use the specializations `std::format_context` (for `char`) | |
3397 | * and `std::wformat_context` (for `wchar_t`). | |
3398 | */ | |
3399 | template<typename _Out, typename _CharT> | |
3400 | class basic_format_context | |
3401 | { | |
3402 | static_assert( output_iterator<_Out, const _CharT&> ); | |
3403 | ||
3404 | basic_format_args<basic_format_context> _M_args; | |
3405 | _Out _M_out; | |
3406 | __format::_Optional_locale _M_loc; | |
3407 | ||
3408 | basic_format_context(basic_format_args<basic_format_context> __args, | |
3409 | _Out __out) | |
3410 | : _M_args(__args), _M_out(std::move(__out)) | |
3411 | { } | |
3412 | ||
3413 | basic_format_context(basic_format_args<basic_format_context> __args, | |
3414 | _Out __out, const std::locale& __loc) | |
3415 | : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc) | |
3416 | { } | |
3417 | ||
cb363fd9 JW |
3418 | template<typename _Out2, typename _CharT2, typename _Context2> |
3419 | friend _Out2 | |
3420 | __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>, | |
3421 | const basic_format_args<_Context2>&, | |
1d9454ab JW |
3422 | const locale*); |
3423 | ||
3424 | public: | |
3425 | basic_format_context() = default; | |
3426 | ~basic_format_context() = default; | |
3427 | ||
3428 | using iterator = _Out; | |
3429 | using char_type = _CharT; | |
3430 | template<typename _Tp> | |
3431 | using formatter_type = formatter<_Tp, _CharT>; | |
3432 | ||
3433 | [[nodiscard]] | |
3434 | basic_format_arg<basic_format_context> | |
3435 | arg(size_t __id) const noexcept | |
3436 | { return _M_args.get(__id); } | |
3437 | ||
3438 | [[nodiscard]] | |
3439 | std::locale locale() { return _M_loc.value(); } | |
3440 | ||
3441 | [[nodiscard]] | |
3442 | iterator out() { return std::move(_M_out); } | |
3443 | ||
3444 | void advance_to(iterator __it) { _M_out = std::move(__it); } | |
3445 | }; | |
3446 | ||
3447 | ||
3448 | /// @cond undocumented | |
3449 | namespace __format | |
3450 | { | |
48e21e87 JW |
3451 | // Abstract base class defining an interface for scanning format strings. |
3452 | // Scan the characters in a format string, dividing it up into strings of | |
3453 | // ordinary characters, escape sequences, and replacement fields. | |
3454 | // Call virtual functions for derived classes to parse format-specifiers | |
3455 | // or write formatted output. | |
1d9454ab JW |
3456 | template<typename _CharT> |
3457 | struct _Scanner | |
3458 | { | |
3459 | using iterator = typename basic_format_parse_context<_CharT>::iterator; | |
3460 | ||
3461 | basic_format_parse_context<_CharT> _M_pc; | |
3462 | ||
3463 | constexpr explicit | |
3464 | _Scanner(basic_string_view<_CharT> __str, size_t __nargs = -1) | |
3465 | : _M_pc(__str, __nargs) | |
3466 | { } | |
3467 | ||
3468 | constexpr iterator begin() const noexcept { return _M_pc.begin(); } | |
3469 | constexpr iterator end() const noexcept { return _M_pc.end(); } | |
3470 | ||
3471 | constexpr void | |
3472 | _M_scan() | |
3473 | { | |
3474 | basic_string_view<_CharT> __fmt = _M_fmt_str(); | |
3475 | ||
3476 | if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] == '}') | |
3477 | { | |
3478 | _M_pc.advance_to(begin() + 1); | |
3479 | _M_format_arg(_M_pc.next_arg_id()); | |
3480 | return; | |
3481 | } | |
3482 | ||
3483 | size_t __lbr = __fmt.find('{'); | |
3484 | size_t __rbr = __fmt.find('}'); | |
3485 | ||
3486 | while (__fmt.size()) | |
3487 | { | |
3488 | auto __cmp = __lbr <=> __rbr; | |
3489 | if (__cmp == 0) | |
3490 | { | |
3491 | _M_on_chars(end()); | |
3492 | _M_pc.advance_to(end()); | |
3493 | return; | |
3494 | } | |
3495 | else if (__cmp < 0) | |
3496 | { | |
3497 | if (__lbr + 1 == __fmt.size() | |
3498 | || (__rbr == __fmt.npos && __fmt[__lbr + 1] != '{')) | |
3499 | __format::__unmatched_left_brace_in_format_string(); | |
3500 | const bool __is_escape = __fmt[__lbr + 1] == '{'; | |
3501 | iterator __last = begin() + __lbr + int(__is_escape); | |
3502 | _M_on_chars(__last); | |
3503 | _M_pc.advance_to(__last + 1); | |
3504 | __fmt = _M_fmt_str(); | |
3505 | if (__is_escape) | |
3506 | { | |
3507 | if (__rbr != __fmt.npos) | |
3508 | __rbr -= __lbr + 2; | |
3509 | __lbr = __fmt.find('{'); | |
3510 | } | |
3511 | else | |
3512 | { | |
3513 | _M_on_replacement_field(); | |
3514 | __fmt = _M_fmt_str(); | |
3515 | __lbr = __fmt.find('{'); | |
3516 | __rbr = __fmt.find('}'); | |
3517 | } | |
3518 | } | |
3519 | else | |
3520 | { | |
3521 | if (++__rbr == __fmt.size() || __fmt[__rbr] != '}') | |
3522 | __format::__unmatched_right_brace_in_format_string(); | |
3523 | iterator __last = begin() + __rbr; | |
3524 | _M_on_chars(__last); | |
3525 | _M_pc.advance_to(__last + 1); | |
3526 | __fmt = _M_fmt_str(); | |
3527 | if (__lbr != __fmt.npos) | |
3528 | __lbr -= __rbr + 1; | |
3529 | __rbr = __fmt.find('}'); | |
3530 | } | |
3531 | } | |
3532 | } | |
3533 | ||
3534 | constexpr basic_string_view<_CharT> | |
3535 | _M_fmt_str() const noexcept | |
3536 | { return {begin(), end()}; } | |
3537 | ||
3538 | constexpr virtual void _M_on_chars(iterator) { } | |
3539 | ||
3540 | constexpr void _M_on_replacement_field() | |
3541 | { | |
3542 | auto __next = begin(); | |
3543 | ||
3544 | size_t __id; | |
3545 | if (*__next == '}') | |
3546 | __id = _M_pc.next_arg_id(); | |
3547 | else if (*__next == ':') | |
3548 | { | |
3549 | __id = _M_pc.next_arg_id(); | |
3550 | _M_pc.advance_to(++__next); | |
3551 | } | |
3552 | else | |
3553 | { | |
3554 | auto [__i, __ptr] = __format::__parse_arg_id(begin(), end()); | |
3555 | if (!__ptr || !(*__ptr == '}' || *__ptr == ':')) | |
3556 | __format::__invalid_arg_id_in_format_string(); | |
3557 | _M_pc.check_arg_id(__id = __i); | |
3558 | if (*__ptr == ':') | |
3559 | { | |
3560 | _M_pc.advance_to(++__ptr); | |
3561 | } | |
3562 | else | |
3563 | _M_pc.advance_to(__ptr); | |
3564 | } | |
3565 | _M_format_arg(__id); | |
5d87f71b JW |
3566 | if (begin() == end() || *begin() != '}') |
3567 | __format::__unmatched_left_brace_in_format_string(); | |
3568 | _M_pc.advance_to(begin() + 1); // Move past '}' | |
1d9454ab JW |
3569 | } |
3570 | ||
3571 | constexpr virtual void _M_format_arg(size_t __id) = 0; | |
3572 | }; | |
3573 | ||
3574 | // Process a format string and format the arguments in the context. | |
3575 | template<typename _Out, typename _CharT> | |
3576 | class _Formatting_scanner : public _Scanner<_CharT> | |
3577 | { | |
3578 | public: | |
3579 | _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc, | |
3580 | basic_string_view<_CharT> __str) | |
3581 | : _Scanner<_CharT>(__str), _M_fc(__fc) | |
3582 | { } | |
3583 | ||
3584 | private: | |
3585 | basic_format_context<_Out, _CharT>& _M_fc; | |
3586 | ||
3587 | using iterator = typename _Scanner<_CharT>::iterator; | |
3588 | ||
96482ffe | 3589 | constexpr void |
1d9454ab JW |
3590 | _M_on_chars(iterator __last) override |
3591 | { | |
3592 | basic_string_view<_CharT> __str(this->begin(), __last); | |
3593 | _M_fc.advance_to(__format::__write(_M_fc.out(), __str)); | |
3594 | } | |
3595 | ||
96482ffe | 3596 | constexpr void |
1d9454ab JW |
3597 | _M_format_arg(size_t __id) override |
3598 | { | |
3599 | using _Context = basic_format_context<_Out, _CharT>; | |
3600 | using handle = typename basic_format_arg<_Context>::handle; | |
3601 | ||
3602 | std::visit_format_arg([this](auto& __arg) { | |
3603 | using _Type = remove_reference_t<decltype(__arg)>; | |
a5d4f38f | 3604 | using _Formatter = typename _Context::template formatter_type<_Type>; |
1d9454ab JW |
3605 | if constexpr (is_same_v<_Type, monostate>) |
3606 | __format::__invalid_arg_id_in_format_string(); | |
3607 | else if constexpr (is_same_v<_Type, handle>) | |
3608 | __arg.format(this->_M_pc, this->_M_fc); | |
a5d4f38f | 3609 | else if constexpr (is_default_constructible_v<_Formatter>) |
1d9454ab | 3610 | { |
a5d4f38f | 3611 | _Formatter __f; |
1d9454ab JW |
3612 | this->_M_pc.advance_to(__f.parse(this->_M_pc)); |
3613 | this->_M_fc.advance_to(__f.format(__arg, this->_M_fc)); | |
3614 | } | |
a5d4f38f JW |
3615 | else |
3616 | static_assert(__format::__formattable_with<_Type, _Context>); | |
1d9454ab JW |
3617 | }, _M_fc.arg(__id)); |
3618 | } | |
3619 | }; | |
3620 | ||
3621 | // Validate a format string for Args. | |
3622 | template<typename _CharT, typename... _Args> | |
3623 | class _Checking_scanner : public _Scanner<_CharT> | |
3624 | { | |
6a9547f3 JW |
3625 | static_assert( |
3626 | (is_default_constructible_v<formatter<_Args, _CharT>> && ...), | |
3627 | "std::formatter must be specialized for each type being formatted"); | |
3628 | ||
1d9454ab JW |
3629 | public: |
3630 | constexpr | |
3631 | _Checking_scanner(basic_string_view<_CharT> __str) | |
3632 | : _Scanner<_CharT>(__str, sizeof...(_Args)) | |
3633 | { } | |
3634 | ||
3635 | private: | |
3636 | constexpr void | |
3637 | _M_format_arg(size_t __id) override | |
3638 | { | |
3639 | if constexpr (sizeof...(_Args) != 0) | |
3640 | { | |
3641 | if (__id < sizeof...(_Args)) | |
3642 | { | |
3643 | _M_parse_format_spec<_Args...>(__id); | |
3644 | return; | |
3645 | } | |
3646 | } | |
3647 | __builtin_unreachable(); | |
3648 | } | |
3649 | ||
6a9547f3 | 3650 | template<typename _Tp, typename... _OtherArgs> |
1d9454ab JW |
3651 | constexpr void |
3652 | _M_parse_format_spec(size_t __id) | |
3653 | { | |
3654 | if (__id == 0) | |
3655 | { | |
6a9547f3 | 3656 | formatter<_Tp, _CharT> __f; |
1d9454ab JW |
3657 | this->_M_pc.advance_to(__f.parse(this->_M_pc)); |
3658 | } | |
6a9547f3 JW |
3659 | else if constexpr (sizeof...(_OtherArgs) != 0) |
3660 | _M_parse_format_spec<_OtherArgs...>(__id - 1); | |
1d9454ab JW |
3661 | else |
3662 | __builtin_unreachable(); | |
3663 | } | |
3664 | }; | |
3665 | ||
3666 | template<typename _Out, typename _CharT, typename _Context> | |
3667 | inline _Out | |
3668 | __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt, | |
3669 | const basic_format_args<_Context>& __args, | |
3670 | const locale* __loc) | |
3671 | { | |
3672 | _Iter_sink<_CharT, _Out> __sink(std::move(__out)); | |
3673 | _Sink_iter<_CharT> __sink_out; | |
3674 | ||
3675 | if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) | |
3676 | __sink_out = __out; // Already a sink iterator, safe to use post-move. | |
3677 | else | |
3678 | __sink_out = __sink.out(); | |
3679 | ||
3680 | auto __ctx = __loc == nullptr | |
3681 | ? _Context(__args, __sink_out) | |
3682 | : _Context(__args, __sink_out, *__loc); | |
3683 | _Formatting_scanner<_Sink_iter<_CharT>, _CharT> __scanner(__ctx, __fmt); | |
3684 | __scanner._M_scan(); | |
3685 | ||
3686 | if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) | |
3687 | return __ctx.out(); | |
3688 | else | |
3689 | return std::move(__sink)._M_finish().out; | |
3690 | } | |
3691 | ||
3692 | } // namespace __format | |
3693 | /// @endcond | |
3694 | ||
3695 | template<typename _CharT, typename... _Args> | |
6c0f9584 JW |
3696 | template<typename _Tp> |
3697 | requires convertible_to<const _Tp&, basic_string_view<_CharT>> | |
1d9454ab JW |
3698 | consteval |
3699 | basic_format_string<_CharT, _Args...>:: | |
3700 | basic_format_string(const _Tp& __s) | |
3701 | : _M_str(__s) | |
3702 | { | |
3703 | __format::_Checking_scanner<_CharT, remove_cvref_t<_Args>...> | |
3704 | __scanner(_M_str); | |
3705 | __scanner._M_scan(); | |
3706 | } | |
3707 | ||
3708 | // [format.functions], formatting functions | |
3709 | ||
3710 | template<typename _Out> requires output_iterator<_Out, const char&> | |
3711 | [[__gnu__::__always_inline__]] | |
3712 | inline _Out | |
3713 | vformat_to(_Out __out, string_view __fmt, format_args __args) | |
3714 | { return __format::__do_vformat_to(std::move(__out), __fmt, __args); } | |
3715 | ||
3716 | template<typename _Out> requires output_iterator<_Out, const wchar_t&> | |
3717 | [[__gnu__::__always_inline__]] | |
3718 | inline _Out | |
3719 | vformat_to(_Out __out, wstring_view __fmt, wformat_args __args) | |
3720 | { return __format::__do_vformat_to(std::move(__out), __fmt, __args); } | |
3721 | ||
3722 | template<typename _Out> requires output_iterator<_Out, const char&> | |
3723 | [[__gnu__::__always_inline__]] | |
3724 | inline _Out | |
3725 | vformat_to(_Out __out, const locale& __loc, string_view __fmt, | |
3726 | format_args __args) | |
3727 | { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); } | |
3728 | ||
3729 | template<typename _Out> requires output_iterator<_Out, const wchar_t&> | |
3730 | [[__gnu__::__always_inline__]] | |
3731 | inline _Out | |
3732 | vformat_to(_Out __out, const locale& __loc, wstring_view __fmt, | |
3733 | wformat_args __args) | |
3734 | { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); } | |
3735 | ||
3736 | [[nodiscard]] | |
3737 | inline string | |
3738 | vformat(string_view __fmt, format_args __args) | |
3739 | { | |
3740 | __format::_Str_sink<char> __buf; | |
3741 | std::vformat_to(__buf.out(), __fmt, __args); | |
3742 | return std::move(__buf).get(); | |
3743 | } | |
3744 | ||
3745 | [[nodiscard]] | |
3746 | inline wstring | |
3747 | vformat(wstring_view __fmt, wformat_args __args) | |
3748 | { | |
3749 | __format::_Str_sink<wchar_t> __buf; | |
3750 | std::vformat_to(__buf.out(), __fmt, __args); | |
3751 | return std::move(__buf).get(); | |
3752 | } | |
3753 | ||
3754 | [[nodiscard]] | |
3755 | inline string | |
3756 | vformat(const locale& __loc, string_view __fmt, format_args __args) | |
3757 | { | |
3758 | __format::_Str_sink<char> __buf; | |
3759 | std::vformat_to(__buf.out(), __loc, __fmt, __args); | |
3760 | return std::move(__buf).get(); | |
3761 | } | |
3762 | ||
3763 | [[nodiscard]] | |
3764 | inline wstring | |
3765 | vformat(const locale& __loc, wstring_view __fmt, wformat_args __args) | |
3766 | { | |
3767 | __format::_Str_sink<wchar_t> __buf; | |
3768 | std::vformat_to(__buf.out(), __loc, __fmt, __args); | |
3769 | return std::move(__buf).get(); | |
3770 | } | |
3771 | ||
3772 | template<typename... _Args> | |
3773 | [[nodiscard]] | |
3774 | inline string | |
3775 | format(format_string<_Args...> __fmt, _Args&&... __args) | |
3776 | { return std::vformat(__fmt.get(), std::make_format_args(__args...)); } | |
3777 | ||
3778 | template<typename... _Args> | |
3779 | [[nodiscard]] | |
3780 | inline wstring | |
3781 | format(wformat_string<_Args...> __fmt, _Args&&... __args) | |
3782 | { return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); } | |
3783 | ||
3784 | template<typename... _Args> | |
3785 | [[nodiscard]] | |
3786 | inline string | |
3787 | format(const locale& __loc, format_string<_Args...> __fmt, | |
3788 | _Args&&... __args) | |
3789 | { | |
3790 | return std::vformat(__loc, __fmt.get(), | |
3791 | std::make_format_args(__args...)); | |
3792 | } | |
3793 | ||
3794 | template<typename... _Args> | |
3795 | [[nodiscard]] | |
3796 | inline wstring | |
3797 | format(const locale& __loc, wformat_string<_Args...> __fmt, | |
3798 | _Args&&... __args) | |
3799 | { | |
3800 | return std::vformat(__loc, __fmt.get(), | |
3801 | std::make_wformat_args(__args...)); | |
3802 | } | |
3803 | ||
3804 | template<typename _Out, typename... _Args> | |
3805 | requires output_iterator<_Out, const char&> | |
3806 | inline _Out | |
3807 | format_to(_Out __out, format_string<_Args...> __fmt, _Args&&... __args) | |
3808 | { | |
3809 | return std::vformat_to(std::move(__out), __fmt.get(), | |
3810 | std::make_format_args(std::forward<_Args>(__args)...)); | |
3811 | } | |
3812 | ||
3813 | template<typename _Out, typename... _Args> | |
3814 | requires output_iterator<_Out, const wchar_t&> | |
3815 | inline _Out | |
3816 | format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&... __args) | |
3817 | { | |
3818 | return std::vformat_to(std::move(__out), __fmt.get(), | |
3819 | std::make_wformat_args(std::forward<_Args>(__args)...)); | |
3820 | } | |
3821 | ||
3822 | template<typename _Out, typename... _Args> | |
3823 | requires output_iterator<_Out, const char&> | |
3824 | inline _Out | |
3825 | format_to(_Out __out, const locale& __loc, format_string<_Args...> __fmt, | |
3826 | _Args&&... __args) | |
3827 | { | |
3828 | return std::vformat_to(std::move(__out), __loc, __fmt.get(), | |
3829 | std::make_format_args(std::forward<_Args>(__args)...)); | |
3830 | } | |
3831 | ||
3832 | template<typename _Out, typename... _Args> | |
3833 | requires output_iterator<_Out, const wchar_t&> | |
3834 | inline _Out | |
3835 | format_to(_Out __out, const locale& __loc, wformat_string<_Args...> __fmt, | |
3836 | _Args&&... __args) | |
3837 | { | |
3838 | return std::vformat_to(std::move(__out), __loc, __fmt.get(), | |
3839 | std::make_wformat_args(std::forward<_Args>(__args)...)); | |
3840 | } | |
3841 | ||
3842 | template<typename _Out, typename... _Args> | |
3843 | requires output_iterator<_Out, const char&> | |
3844 | inline format_to_n_result<_Out> | |
3845 | format_to_n(_Out __out, iter_difference_t<_Out> __n, | |
3846 | format_string<_Args...> __fmt, _Args&&... __args) | |
3847 | { | |
3848 | __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n); | |
3849 | std::vformat_to(__sink.out(), __fmt.get(), | |
3850 | std::make_format_args(__args...)); | |
3851 | return std::move(__sink)._M_finish(); | |
3852 | } | |
3853 | ||
3854 | template<typename _Out, typename... _Args> | |
3855 | requires output_iterator<_Out, const wchar_t&> | |
3856 | inline format_to_n_result<_Out> | |
3857 | format_to_n(_Out __out, iter_difference_t<_Out> __n, | |
3858 | wformat_string<_Args...> __fmt, _Args&&... __args) | |
3859 | { | |
3860 | __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n); | |
3861 | std::vformat_to(__sink.out(), __fmt.get(), | |
3862 | std::make_wformat_args(__args...)); | |
3863 | return std::move(__sink)._M_finish(); | |
3864 | } | |
3865 | ||
3866 | template<typename _Out, typename... _Args> | |
3867 | requires output_iterator<_Out, const char&> | |
3868 | inline format_to_n_result<_Out> | |
3869 | format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc, | |
3870 | format_string<_Args...> __fmt, _Args&&... __args) | |
3871 | { | |
3872 | __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n); | |
3873 | std::vformat_to(__sink.out(), __loc, __fmt.get(), | |
3874 | std::make_format_args(__args...)); | |
3875 | return std::move(__sink)._M_finish(); | |
3876 | } | |
3877 | ||
3878 | template<typename _Out, typename... _Args> | |
3879 | requires output_iterator<_Out, const wchar_t&> | |
3880 | inline format_to_n_result<_Out> | |
3881 | format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc, | |
3882 | wformat_string<_Args...> __fmt, _Args&&... __args) | |
3883 | { | |
3884 | __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n); | |
3885 | std::vformat_to(__sink.out(), __loc, __fmt.get(), | |
3886 | std::make_wformat_args(__args...)); | |
3887 | return std::move(__sink)._M_finish(); | |
3888 | } | |
3889 | ||
3890 | /// @cond undocumented | |
3891 | namespace __format | |
3892 | { | |
3893 | #if 1 | |
3894 | template<typename _CharT> | |
3895 | class _Counting_sink : public _Iter_sink<_CharT, _CharT*> | |
3896 | { | |
3897 | public: | |
3898 | _Counting_sink() : _Iter_sink<_CharT, _CharT*>(nullptr, 0) { } | |
3899 | ||
3900 | [[__gnu__::__always_inline__]] | |
3901 | size_t | |
003016a4 JW |
3902 | count() const |
3903 | { return this->_M_count + this->_M_used().size(); } | |
1d9454ab JW |
3904 | }; |
3905 | #else | |
3906 | template<typename _CharT> | |
3907 | class _Counting_sink : public _Buf_sink<_CharT> | |
3908 | { | |
3909 | size_t _M_count = 0; | |
3910 | ||
3911 | void | |
3912 | _M_overflow() override | |
3913 | { | |
3914 | if (!std::is_constant_evaluated()) | |
3915 | _M_count += this->_M_used().size(); | |
3916 | this->_M_rewind(); | |
3917 | } | |
3918 | ||
3919 | public: | |
3920 | _Counting_sink() = default; | |
3921 | ||
3922 | [[__gnu__::__always_inline__]] | |
3923 | size_t | |
3924 | count() noexcept | |
3925 | { | |
3926 | _Counting_sink::_M_overflow(); | |
3927 | return _M_count; | |
3928 | } | |
3929 | }; | |
3930 | #endif | |
3931 | } // namespace __format | |
481281cc | 3932 | /// @endcond |
1d9454ab JW |
3933 | |
3934 | template<typename... _Args> | |
3935 | [[nodiscard]] | |
3936 | inline size_t | |
3937 | formatted_size(format_string<_Args...> __fmt, _Args&&... __args) | |
3938 | { | |
3939 | __format::_Counting_sink<char> __buf; | |
3940 | std::vformat_to(__buf.out(), __fmt.get(), | |
3941 | std::make_format_args(std::forward<_Args>(__args)...)); | |
3942 | return __buf.count(); | |
3943 | } | |
3944 | ||
3945 | template<typename... _Args> | |
3946 | [[nodiscard]] | |
3947 | inline size_t | |
3948 | formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) | |
3949 | { | |
3950 | __format::_Counting_sink<wchar_t> __buf; | |
3951 | std::vformat_to(__buf.out(), __fmt.get(), | |
3952 | std::make_wformat_args(std::forward<_Args>(__args)...)); | |
3953 | return __buf.count(); | |
3954 | } | |
3955 | ||
3956 | template<typename... _Args> | |
3957 | [[nodiscard]] | |
3958 | inline size_t | |
3959 | formatted_size(const locale& __loc, format_string<_Args...> __fmt, | |
3960 | _Args&&... __args) | |
3961 | { | |
3962 | __format::_Counting_sink<char> __buf; | |
3963 | std::vformat_to(__buf.out(), __loc, __fmt.get(), | |
3964 | std::make_format_args(std::forward<_Args>(__args)...)); | |
3965 | return __buf.count(); | |
3966 | } | |
3967 | ||
3968 | template<typename... _Args> | |
3969 | [[nodiscard]] | |
3970 | inline size_t | |
3971 | formatted_size(const locale& __loc, wformat_string<_Args...> __fmt, | |
3972 | _Args&&... __args) | |
3973 | { | |
3974 | __format::_Counting_sink<wchar_t> __buf; | |
3975 | std::vformat_to(__buf.out(), __loc, __fmt.get(), | |
3976 | std::make_wformat_args(std::forward<_Args>(__args)...)); | |
3977 | return __buf.count(); | |
3978 | } | |
3979 | ||
3980 | #if __cpp_lib_format_ranges | |
3981 | // [format.range], formatting of ranges | |
3982 | // [format.range.fmtkind], variable template format_kind | |
3983 | enum class range_format { | |
3984 | disabled, | |
3985 | map, | |
3986 | set, | |
3987 | sequence, | |
3988 | string, | |
3989 | debug_string | |
3990 | }; | |
3991 | ||
3992 | /// @cond undocumented | |
3993 | template<typename _Rg> | |
3994 | constexpr auto format_kind = not defined(format_kind<_Rg>); | |
3995 | ||
3996 | template<typename _Tp> | |
3997 | consteval range_format | |
3998 | __fmt_kind() | |
3999 | { | |
4000 | using _Ref = ranges::range_reference_t<_Tp>; | |
4001 | if constexpr (is_same_v<remove_cvref_t<_Ref>, _Tp>) | |
4002 | return range_format::disabled; | |
4003 | else if constexpr (requires { typename _Tp::key_type; }) | |
4004 | { | |
4005 | if constexpr (requires { typename _Tp::mapped_type; }) | |
4006 | { | |
4007 | using _Up = remove_cvref_t<_Ref>; | |
4008 | if constexpr (__is_pair<_Up>) | |
4009 | return range_format::map; | |
4010 | else if constexpr (__is_specialization_of<_Up, tuple>) | |
4011 | if constexpr (tuple_size_v<_Up> == 2) | |
4012 | return range_format::map; | |
4013 | } | |
4014 | return range_format::set; | |
4015 | } | |
4016 | else | |
4017 | return range_format::sequence; | |
4018 | } | |
4019 | /// @endcond | |
4020 | ||
4021 | /// A constant determining how a range should be formatted. | |
4022 | template<ranges::input_range _Rg> requires same_as<_Rg, remove_cvref_t<_Rg>> | |
4023 | constexpr range_format format_kind<_Rg> = __fmt_kind<_Rg>(); | |
4024 | ||
4025 | // [format.range.formatter], class template range_formatter | |
4026 | template<typename _Tp, typename _CharT = char> | |
4027 | requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> | |
4028 | class range_formatter; // TODO | |
4029 | ||
4030 | /// @cond undocumented | |
4031 | namespace __format | |
4032 | { | |
4033 | // [format.range.fmtdef], class template range-default-formatter | |
4034 | template<range_format _Kind, ranges::input_range _Rg, typename _CharT> | |
4035 | struct __range_default_formatter; // TODO | |
4036 | } // namespace __format | |
4037 | /// @endcond | |
4038 | ||
4039 | // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr], | |
4040 | // specializations for maps, sets, and strings | |
4041 | template<ranges::input_range _Rg, typename _CharT> | |
4042 | requires (format_kind<_Rg> != range_format::disabled) | |
4043 | && formattable<ranges::range_reference_t<_Rg>, _CharT> | |
4044 | struct formatter<_Rg, _CharT> | |
4045 | : __format::__range_default_formatter<format_kind<_Rg>, _Rg, _CharT> | |
4046 | { }; | |
4047 | #endif // C++23 formatting ranges | |
4048 | ||
4049 | _GLIBCXX_END_NAMESPACE_VERSION | |
4050 | } // namespace std | |
4051 | #endif // C++20 | |
4052 | #endif // _GLIBCXX_FORMAT |