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

source code of include/c++/13/format