1 // <format> Formatting -*- C++ -*-
3 // Copyright The GNU Toolchain Authors.
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)
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.
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.
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/>.
25 /** @file include/format
26 * This is a Standard C++ Library header.
29 #ifndef _GLIBCXX_FORMAT
30 #define _GLIBCXX_FORMAT 1
32 #pragma GCC system_header
34 #include <bits/requires_hosted.h> // for std::string
36 #define __glibcxx_want_format
37 #define __glibcxx_want_format_ranges
38 #define __glibcxx_want_format_uchar
39 #include <bits/version.h>
41 #ifdef __cpp_lib_format // C++ >= 20 && HOSTED
50 #include <string_view>
52 #include <variant> // monostate (TODO: move to bits/utility.h?)
53 #include <bits/ranges_base.h> // input_range, range_reference_t
54 #include <bits/ranges_algobase.h> // ranges::copy
55 #include <bits/stl_iterator.h> // back_insert_iterator
56 #include <bits/stl_pair.h> // __is_pair
57 #include <bits/utility.h> // tuple_size_v
58 #include <ext/numeric_traits.h> // __int_traits
60 #if !__has_builtin(__builtin_toupper)
64 namespace std _GLIBCXX_VISIBILITY(default)
66 _GLIBCXX_BEGIN_NAMESPACE_VERSION
68 // [format.context], class template basic_format_context
69 template<typename _Out, typename _CharT> class basic_format_context;
71 /// @cond undocumented
74 // Type-erased character sink.
75 template<typename _CharT> class _Sink;
76 // Output iterator that writes to a type-erase character sink.
77 template<typename _CharT>
80 template<typename _CharT>
81 using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>;
82 } // namespace __format
85 using format_context = __format::__format_context<char>;
86 #ifdef _GLIBCXX_USE_WCHAR_T
87 using wformat_context = __format::__format_context<wchar_t>;
90 // [format.args], class template basic_format_args
91 template<typename _Context> class basic_format_args;
92 using format_args = basic_format_args<format_context>;
93 #ifdef _GLIBCXX_USE_WCHAR_T
94 using wformat_args = basic_format_args<wformat_context>;
97 // [format.arguments], arguments
98 // [format.arg], class template basic_format_arg
99 template<typename _Context>
100 class basic_format_arg;
102 // [format.fmt.string], class template basic_format_string
104 /** A compile-time checked format string for the specified argument types.
106 * @since C++23 but available as an extension in C++20.
108 template<typename _CharT, typename... _Args>
109 struct basic_format_string
111 template<typename _Tp>
112 requires convertible_to<const _Tp&, basic_string_view<_CharT>>
114 basic_format_string(const _Tp& __s);
116 [[__gnu__::__always_inline__]]
117 constexpr basic_string_view<_CharT>
122 basic_string_view<_CharT> _M_str;
125 template<typename... _Args>
126 using format_string = basic_format_string<char, type_identity_t<_Args>...>;
128 #ifdef _GLIBCXX_USE_WCHAR_T
129 template<typename... _Args>
131 = basic_format_string<wchar_t, type_identity_t<_Args>...>;
134 // [format.formatter], formatter
136 /// The primary template of std::formatter is disabled.
137 template<typename _Tp, typename _CharT = char>
140 formatter() = delete; // No std::formatter specialization for this type.
141 formatter(const formatter&) = delete;
142 formatter& operator=(const formatter&) = delete;
145 // [format.error], class format_error
146 class format_error : public runtime_error
149 explicit format_error(const string& __what) : runtime_error(__what) { }
150 explicit format_error(const char* __what) : runtime_error(__what) { }
153 /// @cond undocumented
156 __throw_format_error(const char* __what)
157 { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
161 // XXX use named functions for each constexpr error?
165 __unmatched_left_brace_in_format_string()
166 { __throw_format_error("format error: unmatched '{' in format string"); }
170 __unmatched_right_brace_in_format_string()
171 { __throw_format_error("format error: unmatched '}' in format string"); }
175 __conflicting_indexing_in_format_string()
176 { __throw_format_error("format error: conflicting indexing style in format string"); }
180 __invalid_arg_id_in_format_string()
181 { __throw_format_error("format error: invalid arg-id in format string"); }
185 __failed_to_parse_format_spec()
186 { __throw_format_error("format error: failed to parse format-spec"); }
187 } // namespace __format
190 // [format.parse.ctx], class template basic_format_parse_context
191 template<typename _CharT> class basic_format_parse_context;
192 using format_parse_context = basic_format_parse_context<char>;
193 #ifdef _GLIBCXX_USE_WCHAR_T
194 using wformat_parse_context = basic_format_parse_context<wchar_t>;
197 template<typename _CharT>
198 class basic_format_parse_context
201 using char_type = _CharT;
202 using const_iterator = typename basic_string_view<_CharT>::const_iterator;
203 using iterator = const_iterator;
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)
211 basic_format_parse_context(const basic_format_parse_context&) = delete;
212 void operator=(const basic_format_parse_context&) = delete;
214 constexpr const_iterator begin() const noexcept { return _M_begin; }
215 constexpr const_iterator end() const noexcept { return _M_end; }
218 advance_to(const_iterator __it) noexcept
224 if (_M_indexing == _Manual)
225 __format::__conflicting_indexing_in_format_string();
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++;
237 check_arg_id(size_t __id)
239 if (_M_indexing == _Auto)
240 __format::__conflicting_indexing_in_format_string();
241 _M_indexing = _Manual;
243 if (std::is_constant_evaluated())
244 if (__id >= _M_num_args)
245 __format::__invalid_arg_id_in_format_string();
251 enum _Indexing { _Unknown, _Manual, _Auto };
252 _Indexing _M_indexing = _Unknown;
253 size_t _M_next_arg_id = 0;
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>
266 // pre: first != last
267 template<typename _CharT>
268 constexpr pair<unsigned short, const _CharT*>
269 __parse_integer(const _CharT* __first, const _CharT* __last)
271 if (__first == __last)
272 __builtin_unreachable();
274 if constexpr (is_same_v<_CharT, char>)
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};
285 constexpr int __n = 32;
287 for (int __i = 0; __i < __n && (__first + __i) != __last; ++__i)
288 __buf[__i] = __first[__i];
289 auto [__v, __ptr] = __format::__parse_integer(__buf, __buf + __n);
290 if (__ptr) [[likely]]
291 return {__v, __first + (__ptr - __buf)};
296 template<typename _CharT>
297 constexpr pair<unsigned short, const _CharT*>
298 __parse_arg_id(const _CharT* __first, const _CharT* __last)
300 if (__first == __last)
301 __builtin_unreachable();
304 return {0, __first + 1}; // No leading zeros allowed, so '0...' == 0
306 if ('1' <= *__first && *__first <= '9')
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};
314 return __format::__parse_integer(__first, __last);
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.
340 _Sign_minus, // XXX does this need to be distinct from _Sign_default?
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.
351 __literal_encoding_is_utf8()
353 #ifdef __GNUC_EXECUTION_CHARSET_NAME
354 const char* __enc = __GNUC_EXECUTION_CHARSET_NAME;
355 // GNU iconv allows "ISO-10646/" prefix (case-insensitive).
356 if (__enc[0] == 'I' || __enc[0] == 'i')
358 if ((__enc[1] == 'S' || __enc[1] == 's')
359 && (__enc[2] == 'O' || __enc[2] == 'o'))
362 if (string_view(__enc).starts_with("-10646/"))
371 if ((__enc[0] == 'U' || __enc[0] == 'u')
372 && (__enc[1] == 'T' || __enc[1] == 't')
373 && (__enc[2] == 'F' || __enc[2] == 'f'))
379 return __enc[1] == '\0' || string_view(__enc + 1) == "//";
381 #elif defined __clang_literal_encoding__
382 // Clang accepts "-fexec-charset=utf-8" but the macro is still uppercase.
383 return string_view(__clang_literal_encoding__) == "UTF-8";
388 template<typename _Context>
390 __int_from_arg(const basic_format_arg<_Context>& __arg);
392 constexpr bool __is_digit(char __c)
393 { return std::__detail::__from_chars_alnum_to_val(__c) < 10; }
395 constexpr bool __is_xdigit(char __c)
396 { return std::__detail::__from_chars_alnum_to_val(__c) < 16; }
398 template<typename _CharT>
404 unsigned _M_localized : 1;
405 unsigned _M_zero_fill : 1;
406 _WidthPrec _M_width_kind : 2;
407 _WidthPrec _M_prec_kind : 2;
408 _Pres_type _M_type : 4;
409 unsigned short _M_width;
410 unsigned short _M_prec;
411 _CharT _M_fill = ' ';
413 using iterator = typename basic_string_view<_CharT>::iterator;
415 static constexpr _Align
416 _S_align(_CharT __c) noexcept
420 case '<': return _Align_left;
421 case '>': return _Align_right;
422 case '^': return _Align_centre;
423 default: return _Align_default;
427 // pre: __first != __last
429 _M_parse_fill_and_align(iterator __first, iterator __last) noexcept
433 // TODO: accept any UCS scalar value as fill character.
434 // If narrow source encoding is UTF-8 then accept multibyte char.
435 if (__last - __first >= 2)
437 if (_Align __align = _S_align(__first[1]))
445 if (_Align __align = _S_align(__first[0]))
455 static constexpr _Sign
456 _S_sign(_CharT __c) noexcept
460 case '+': return _Sign_plus;
461 case '-': return _Sign_minus;
462 case ' ': return _Sign_space;
463 default: return _Sign_default;
467 // pre: __first != __last
469 _M_parse_sign(iterator __first, iterator) noexcept
471 if (_Sign __sign = _S_sign(*__first))
479 // pre: *__first is valid
481 _M_parse_alternate_form(iterator __first, iterator) noexcept
491 // pre: __first != __last
493 _M_parse_zero_fill(iterator __first, iterator /* __last */) noexcept
503 // pre: __first != __last
504 static constexpr iterator
505 _S_parse_width_or_precision(iterator __first, iterator __last,
506 unsigned short& __val, bool& __arg_id,
507 basic_format_parse_context<_CharT>& __pc)
509 if (__format::__is_digit(*__first))
511 auto [__v, __ptr] = __format::__parse_integer(__first, __last);
513 __throw_format_error("format error: invalid width or precision "
518 else if (*__first == '{')
522 if (__first == __last)
523 __format::__unmatched_left_brace_in_format_string();
525 __val = __pc.next_arg_id();
528 auto [__v, __ptr] = __format::__parse_arg_id(__first, __last);
529 if (__ptr == nullptr || __ptr == __last || *__ptr != '}')
530 __format::__invalid_arg_id_in_format_string();
532 __pc.check_arg_id(__v);
535 ++__first; // past the '}'
540 // pre: __first != __last
542 _M_parse_width(iterator __first, iterator __last,
543 basic_format_parse_context<_CharT>& __pc)
545 bool __arg_id = false;
547 __throw_format_error("format error: width must be non-zero in "
549 auto __next = _S_parse_width_or_precision(__first, __last, _M_width,
551 if (__next != __first)
552 _M_width_kind = __arg_id ? _WP_from_arg : _WP_value;
556 // pre: __first != __last
558 _M_parse_precision(iterator __first, iterator __last,
559 basic_format_parse_context<_CharT>& __pc)
561 if (__first[0] != '.')
564 iterator __next = ++__first;
565 bool __arg_id = false;
566 if (__next != __last)
567 __next = _S_parse_width_or_precision(__first, __last, _M_prec,
569 if (__next == __first)
570 __throw_format_error("format error: missing precision after '.' in "
572 _M_prec_kind = __arg_id ? _WP_from_arg : _WP_value;
576 // pre: __first != __last
578 _M_parse_locale(iterator __first, iterator /* __last */) noexcept
588 template<typename _Context>
590 _M_get_width(_Context& __ctx) const
593 if (_M_width_kind == _WP_value)
595 else if (_M_width_kind == _WP_from_arg)
596 __width = __format::__int_from_arg(__ctx.arg(_M_width));
600 template<typename _Context>
602 _M_get_precision(_Context& __ctx) const
605 if (_M_prec_kind == _WP_value)
607 else if (_M_prec_kind == _WP_from_arg)
608 __prec = __format::__int_from_arg(__ctx.arg(_M_prec));
613 template<typename _Int>
615 __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept
619 else if (__sign == _Sign_plus)
621 else if (__sign == _Sign_space)
628 // Write STR to OUT (and do so efficiently if OUT is a _Sink_iter).
629 template<typename _Out, typename _CharT>
630 requires output_iterator<_Out, const _CharT&>
632 __write(_Out __out, basic_string_view<_CharT> __str)
634 if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
640 for (_CharT __c : __str)
645 // Write STR to OUT with NFILL copies of FILL_CHAR specified by ALIGN.
646 // pre: __align != _Align_default
647 template<typename _Out, typename _CharT>
649 __write_padded(_Out __out, basic_string_view<_CharT> __str,
650 _Align __align, size_t __nfill, _CharT __fill_char)
652 const size_t __buflen = 0x20;
653 _CharT __padding_chars[__buflen];
654 __padding_chars[0] = _CharT();
655 basic_string_view<_CharT> __padding{__padding_chars, __buflen};
657 auto __pad = [&__padding] (size_t __n, _Out& __o) {
660 while (__n > __padding.size())
662 __o = __format::__write(std::move(__o), __padding);
663 __n -= __padding.size();
666 __o = __format::__write(std::move(__o), __padding.substr(0, __n));
669 size_t __l, __r, __max;
670 if (__align == _Align_centre)
673 __r = __l + (__nfill & 1);
676 else if (__align == _Align_right)
688 if (__max < __buflen)
689 __padding.remove_suffix(__buflen - __max);
692 char_traits<_CharT>::assign(__padding_chars, __max, __fill_char);
695 __out = __format::__write(std::move(__out), __str);
701 // Write STR to OUT, with alignment and padding as determined by SPEC.
702 // pre: __spec._M_align != _Align_default || __align != _Align_default
703 template<typename _CharT, typename _Out>
705 __write_padded_as_spec(basic_string_view<type_identity_t<_CharT>> __str,
706 size_t __estimated_width,
707 basic_format_context<_Out, _CharT>& __fc,
708 const _Spec<_CharT>& __spec,
709 _Align __align = _Align_left)
711 size_t __width = __spec._M_get_width(__fc);
713 if (__width <= __estimated_width)
714 return __format::__write(__fc.out(), __str);
716 const size_t __nfill = __width - __estimated_width;
719 __align = __spec._M_align;
721 return __format::__write_padded(__fc.out(), __str, __align, __nfill,
725 // A lightweight optional<locale>.
726 struct _Optional_locale
728 [[__gnu__::__always_inline__]]
729 _Optional_locale() : _M_dummy(), _M_hasval(false) { }
731 _Optional_locale(const locale& __loc) noexcept
732 : _M_loc(__loc), _M_hasval(true)
735 _Optional_locale(const _Optional_locale& __l) noexcept
736 : _M_dummy(), _M_hasval(__l._M_hasval)
739 std::construct_at(&_M_loc, __l._M_loc);
743 operator=(const _Optional_locale& __l) noexcept
755 else if (__l._M_hasval)
757 std::construct_at(&_M_loc, __l._M_loc);
763 ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); }
766 operator=(locale&& __loc) noexcept
769 _M_loc = std::move(__loc);
772 std::construct_at(&_M_loc, std::move(__loc));
783 std::construct_at(&_M_loc);
789 bool has_value() const noexcept { return _M_hasval; }
792 char _M_dummy = '\0';
795 bool _M_hasval = false;
798 #ifdef _GLIBCXX_USE_WCHAR_T
799 template<typename _CharT>
800 concept __char = same_as<_CharT, char> || same_as<_CharT, wchar_t>;
802 template<typename _CharT>
803 concept __char = same_as<_CharT, char>;
806 template<__char _CharT>
807 struct __formatter_str
809 constexpr typename basic_format_parse_context<_CharT>::iterator
810 parse(basic_format_parse_context<_CharT>& __pc)
812 auto __first = __pc.begin();
813 const auto __last = __pc.end();
814 _Spec<_CharT> __spec{};
816 auto __finalize = [this, &__spec] {
820 auto __finished = [&] {
821 if (__first == __last || *__first == '}')
832 __first = __spec._M_parse_fill_and_align(__first, __last);
836 __first = __spec._M_parse_width(__first, __last, __pc);
840 __first = __spec._M_parse_precision(__first, __last, __pc);
846 #if __cpp_lib_format_ranges
847 else if (*__first == '?')
849 __spec._M_type = _Pres_esc;
857 __format::__failed_to_parse_format_spec();
860 template<typename _Out>
862 format(basic_string_view<_CharT> __s,
863 basic_format_context<_Out, _CharT>& __fc) const
865 if (_M_spec._M_type == _Pres_esc)
867 // TODO: C++23 escaped string presentation
870 if (_M_spec._M_width_kind == _WP_none
871 && _M_spec._M_prec_kind == _WP_none)
872 return __format::__write(__fc.out(), __s);
874 size_t __estimated_width = __s.size(); // TODO: Unicode-aware estim.
876 if (_M_spec._M_prec_kind != _WP_none)
878 size_t __prec = _M_spec._M_get_precision(__fc);
879 if (__estimated_width > __prec)
881 __s = __s.substr(0, __prec); // TODO: do not split code points
882 __estimated_width = __prec;
886 return __format::__write_padded_as_spec(__s, __estimated_width,
890 #if __cpp_lib_format_ranges
892 set_debug_format() noexcept
893 { _M_spec._M_type = _Pres_esc; }
897 _Spec<_CharT> _M_spec{};
900 template<__char _CharT>
901 struct __formatter_int
903 // If no presentation type is specified, meaning of "none" depends
904 // whether we are formatting an integer or a char or a bool.
905 static constexpr _Pres_type _AsInteger = _Pres_d;
906 static constexpr _Pres_type _AsBool = _Pres_s;
907 static constexpr _Pres_type _AsChar = _Pres_c;
909 constexpr typename basic_format_parse_context<_CharT>::iterator
910 _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type)
912 _Spec<_CharT> __spec{};
913 __spec._M_type = __type;
915 const auto __last = __pc.end();
916 auto __first = __pc.begin();
918 auto __finalize = [this, &__spec] {
922 auto __finished = [&] {
923 if (__first == __last || *__first == '}')
934 __first = __spec._M_parse_fill_and_align(__first, __last);
938 __first = __spec._M_parse_sign(__first, __last);
942 __first = __spec._M_parse_alternate_form(__first, __last);
946 __first = __spec._M_parse_zero_fill(__first, __last);
950 __first = __spec._M_parse_width(__first, __last, __pc);
954 __first = __spec._M_parse_locale(__first, __last);
961 __spec._M_type = _Pres_b;
965 __spec._M_type = _Pres_B;
969 // _GLIBCXX_RESOLVE_LIB_DEFECTS
970 // 3586. format should not print bool with 'c'
971 if (__type != _AsBool)
973 __spec._M_type = _Pres_c;
978 __spec._M_type = _Pres_d;
982 __spec._M_type = _Pres_o;
986 __spec._M_type = _Pres_x;
990 __spec._M_type = _Pres_X;
994 if (__type == _AsBool)
996 __spec._M_type = _Pres_s; // same value (and meaning) as "none"
1000 #if __cpp_lib_format_ranges
1002 if (__type == _AsChar)
1004 __spec._M_type = _Pres_esc;
1014 __format::__failed_to_parse_format_spec();
1017 template<typename _Tp>
1018 constexpr typename basic_format_parse_context<_CharT>::iterator
1019 _M_parse(basic_format_parse_context<_CharT>& __pc)
1021 if constexpr (is_same_v<_Tp, bool>)
1023 auto __end = _M_do_parse(__pc, _AsBool);
1024 if (_M_spec._M_type == _Pres_s)
1025 if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill)
1026 __throw_format_error("format error: format-spec contains "
1027 "invalid formatting options for "
1031 else if constexpr (__char<_Tp>)
1033 auto __end = _M_do_parse(__pc, _AsChar);
1034 if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc)
1035 if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill
1036 /* XXX should be invalid? || _M_spec._M_localized */)
1037 __throw_format_error("format error: format-spec contains "
1038 "invalid formatting options for "
1043 return _M_do_parse(__pc, _AsInteger);
1046 template<typename _Int, typename _Out>
1047 typename basic_format_context<_Out, _CharT>::iterator
1048 format(_Int __i, basic_format_context<_Out, _CharT>& __fc) const
1050 if (_M_spec._M_type == _Pres_c)
1051 return _M_format_character(_S_to_character(__i), __fc);
1053 char __buf[sizeof(_Int) * __CHAR_BIT__ + 3];
1054 to_chars_result __res{};
1056 string_view __base_prefix;
1057 make_unsigned_t<_Int> __u;
1059 __u = -static_cast<make_unsigned_t<_Int>>(__i);
1063 char* __start = __buf + 3;
1064 char* const __end = __buf + sizeof(__buf);
1065 char* const __start_digits = __start;
1067 switch (_M_spec._M_type)
1071 __base_prefix = _M_spec._M_type == _Pres_b ? "0b" : "0B";
1072 __res = to_chars(__start, __end, __u, 2);
1076 return _M_format_character(_S_to_character(__i), __fc);
1079 // Should not reach here with _Pres_none for bool or charT, so:
1082 __res = to_chars(__start, __end, __u, 10);
1086 __base_prefix = "0";
1087 __res = to_chars(__start, __end, __u, 8);
1091 __base_prefix = _M_spec._M_type == _Pres_x ? "0x" : "0X";
1092 __res = to_chars(__start, __end, __u, 16);
1093 if (_M_spec._M_type == _Pres_X)
1094 for (auto __p = __start; __p != __res.ptr; ++__p)
1095 #if __has_builtin(__builtin_toupper)
1096 *__p = __builtin_toupper(*__p);
1098 *__p = std::toupper(*__p);
1102 __builtin_unreachable();
1105 if (_M_spec._M_alt && __base_prefix.size())
1107 __start -= __base_prefix.size();
1108 __builtin_memcpy(__start, __base_prefix.data(),
1109 __base_prefix.size());
1111 __start = __format::__put_sign(__i, _M_spec._M_sign, __start - 1);
1113 return _M_format_int(string_view(__start, __res.ptr - __start),
1114 __start_digits - __start, __fc);
1117 template<typename _Out>
1118 typename basic_format_context<_Out, _CharT>::iterator
1119 format(bool __i, basic_format_context<_Out, _CharT>& __fc) const
1121 if (_M_spec._M_type == _Pres_c)
1122 return _M_format_character(static_cast<unsigned char>(__i), __fc);
1123 if (_M_spec._M_type != _Pres_s)
1124 return format(static_cast<unsigned char>(__i), __fc);
1126 basic_string<_CharT> __s;
1128 if (_M_spec._M_localized) [[unlikely]]
1130 auto& __np = std::use_facet<numpunct<_CharT>>(__fc.locale());
1131 __s = __i ? __np.truename() : __np.falsename();
1132 __est_width = __s.size(); // TODO Unicode-aware estimate
1136 if constexpr (is_same_v<char, _CharT>)
1137 __s = __i ? "true" : "false";
1139 __s = __i ? L"true" : L"false";
1140 __est_width = __s.size();
1143 return __format::__write_padded_as_spec(__s, __est_width, __fc,
1147 template<typename _Out>
1148 typename basic_format_context<_Out, _CharT>::iterator
1149 _M_format_character(_CharT __c,
1150 basic_format_context<_Out, _CharT>& __fc) const
1152 return __format::__write_padded_as_spec({&__c, 1u}, 1, __fc, _M_spec);
1155 template<typename _Int>
1157 _S_to_character(_Int __i)
1159 using _Traits = __gnu_cxx::__int_traits<_CharT>;
1160 if constexpr (is_signed_v<_Int> == is_signed_v<_CharT>)
1162 if (_Traits::__min <= __i && __i <= _Traits::__max)
1163 return static_cast<_CharT>(__i);
1165 else if constexpr (is_signed_v<_Int>)
1167 if (__i >= 0 && make_unsigned_t<_Int>(__i) <= _Traits::__max)
1168 return static_cast<_CharT>(__i);
1170 else if (__i <= make_unsigned_t<_CharT>(_Traits::__max))
1171 return static_cast<_CharT>(__i);
1172 __throw_format_error("format error: integer not representable as "
1176 template<typename _Out>
1177 typename basic_format_context<_Out, _CharT>::iterator
1178 _M_format_int(string_view __narrow_str, size_t __prefix_len,
1179 basic_format_context<_Out, _CharT>& __fc) const
1181 size_t __width = _M_spec._M_get_width(__fc);
1183 basic_string_view<_CharT> __str;
1184 if constexpr (is_same_v<char, _CharT>)
1185 __str = __narrow_str;
1186 #ifdef _GLIBCXX_USE_WCHAR_T
1189 size_t __n = __narrow_str.size();
1190 auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
1191 std::__to_wstring_numeric(__narrow_str.data(), __n, __p);
1196 if (_M_spec._M_localized)
1198 const auto& __l = __fc.locale();
1199 if (__l.name() != "C")
1201 auto& __np = use_facet<numpunct<_CharT>>(__l);
1202 string __grp = __np.grouping();
1205 size_t __n = __str.size() - __prefix_len;
1206 auto __p = (_CharT*)__builtin_alloca(2 * __n
1209 auto __s = __str.data();
1210 char_traits<_CharT>::copy(__p, __s, __prefix_len);
1211 __s += __prefix_len;
1212 auto __end = std::__add_grouping(__p + __prefix_len,
1213 __np.thousands_sep(),
1217 __str = {__p, size_t(__end - __p)};
1222 if (__width <= __str.size())
1223 return __format::__write(__fc.out(), __str);
1225 _CharT __fill_char = _M_spec._M_fill;
1226 _Align __align = _M_spec._M_align;
1228 size_t __nfill = __width - __str.size();
1229 auto __out = __fc.out();
1230 if (__align == _Align_default)
1232 __align = _Align_right;
1233 if (_M_spec._M_zero_fill)
1235 __fill_char = _CharT('0');
1236 // Write sign and base prefix before zero filling.
1237 if (__prefix_len != 0)
1239 __out = __format::__write(std::move(__out),
1240 __str.substr(0, __prefix_len));
1241 __str.remove_prefix(__prefix_len);
1245 __fill_char = _CharT(' ');
1247 return __format::__write_padded(std::move(__out), __str,
1248 __align, __nfill, __fill_char);
1251 #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
1252 template<typename _Tp>
1253 using make_unsigned_t
1254 = typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)),
1255 std::make_unsigned<_Tp>,
1256 type_identity<unsigned __int128>>::type;
1258 // std::to_chars is not overloaded for int128 in strict mode.
1259 template<typename _Int>
1260 static to_chars_result
1261 to_chars(char* __first, char* __last, _Int __value, int __base)
1262 { return std::__to_chars_i<_Int>(__first, __last, __value, __base); }
1265 _Spec<_CharT> _M_spec{};
1268 // Decide how 128-bit floating-point types should be formatted (or not).
1269 // When supported, the typedef __format::__float128_t is the type that
1270 // format arguments should be converted to for storage in basic_format_arg.
1271 // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported.
1272 // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted
1273 // by converting them to long double (or __ieee128 for powerpc64le).
1274 // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit
1275 // support for _Float128, rather than formatting it as another type.
1276 #undef _GLIBCXX_FORMAT_F128
1278 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
1280 // Format 128-bit floating-point types using __ieee128.
1281 using __float128_t = __ieee128;
1282 # define _GLIBCXX_FORMAT_F128 1
1284 #ifdef __LONG_DOUBLE_IEEE128__
1285 // These overloads exist in the library, but are not declared.
1286 // Make them available as std::__format::to_chars.
1288 to_chars(char*, char*, __ibm128) noexcept
1289 __asm("_ZSt8to_charsPcS_e");
1292 to_chars(char*, char*, __ibm128, chars_format) noexcept
1293 __asm("_ZSt8to_charsPcS_eSt12chars_format");
1296 to_chars(char*, char*, __ibm128, chars_format, int) noexcept
1297 __asm("_ZSt8to_charsPcS_eSt12chars_formati");
1298 #elif __cplusplus == 202002L
1300 to_chars(char*, char*, __ieee128) noexcept
1301 __asm("_ZSt8to_charsPcS_u9__ieee128");
1304 to_chars(char*, char*, __ieee128, chars_format) noexcept
1305 __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_format");
1308 to_chars(char*, char*, __ieee128, chars_format, int) noexcept
1309 __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_formati");
1312 #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
1314 // Format 128-bit floating-point types using long double.
1315 using __float128_t = long double;
1316 # define _GLIBCXX_FORMAT_F128 1
1318 #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
1320 // Format 128-bit floating-point types using _Float128.
1321 using __float128_t = _Float128;
1322 # define _GLIBCXX_FORMAT_F128 2
1324 # if __cplusplus == 202002L
1325 // These overloads exist in the library, but are not declared for C++20.
1326 // Make them available as std::__format::to_chars.
1328 to_chars(char*, char*, _Float128) noexcept
1329 # if _GLIBCXX_INLINE_VERSION
1330 __asm("_ZNSt3__88to_charsEPcS0_DF128_");
1332 __asm("_ZSt8to_charsPcS_DF128_");
1336 to_chars(char*, char*, _Float128, chars_format) noexcept
1337 # if _GLIBCXX_INLINE_VERSION
1338 __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatE");
1340 __asm("_ZSt8to_charsPcS_DF128_St12chars_format");
1344 to_chars(char*, char*, _Float128, chars_format, int) noexcept
1345 # if _GLIBCXX_INLINE_VERSION
1346 __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatEi");
1348 __asm("_ZSt8to_charsPcS_DF128_St12chars_formati");
1353 using std::to_chars;
1355 // We can format a floating-point type iff it is usable with to_chars.
1356 template<typename _Tp>
1357 concept __formattable_float = requires (_Tp __t, char* __p)
1358 { __format::to_chars(__p, __p, __t, chars_format::scientific, 6); };
1360 template<__char _CharT>
1361 struct __formatter_fp
1363 constexpr typename basic_format_parse_context<_CharT>::iterator
1364 parse(basic_format_parse_context<_CharT>& __pc)
1366 _Spec<_CharT> __spec{};
1367 const auto __last = __pc.end();
1368 auto __first = __pc.begin();
1370 auto __finalize = [this, &__spec] {
1374 auto __finished = [&] {
1375 if (__first == __last || *__first == '}')
1386 __first = __spec._M_parse_fill_and_align(__first, __last);
1390 __first = __spec._M_parse_sign(__first, __last);
1394 __first = __spec._M_parse_alternate_form(__first, __last);
1398 __first = __spec._M_parse_zero_fill(__first, __last);
1402 if (__first[0] != '.')
1404 __first = __spec._M_parse_width(__first, __last, __pc);
1409 __first = __spec._M_parse_precision(__first, __last, __pc);
1413 __first = __spec._M_parse_locale(__first, __last);
1420 __spec._M_type = _Pres_a;
1424 __spec._M_type = _Pres_A;
1428 __spec._M_type = _Pres_e;
1432 __spec._M_type = _Pres_E;
1436 __spec._M_type = _Pres_f;
1440 __spec._M_type = _Pres_F;
1444 __spec._M_type = _Pres_g;
1448 __spec._M_type = _Pres_G;
1456 __format::__failed_to_parse_format_spec();
1459 template<typename _Fp, typename _Out>
1460 typename basic_format_context<_Out, _CharT>::iterator
1461 format(_Fp __v, basic_format_context<_Out, _CharT>& __fc) const
1463 std::string __dynbuf;
1465 to_chars_result __res{};
1468 bool __use_prec = _M_spec._M_prec_kind != _WP_none;
1470 __prec = _M_spec._M_get_precision(__fc);
1472 char* __start = __buf + 1; // reserve space for sign
1473 char* __end = __buf + sizeof(__buf);
1475 chars_format __fmt{};
1476 bool __upper = false;
1477 bool __trailing_zeros = false;
1480 switch (_M_spec._M_type)
1487 if (_M_spec._M_type != _Pres_A)
1489 __fmt = chars_format::hex;
1497 __fmt = chars_format::scientific;
1504 __fmt = chars_format::fixed;
1511 __trailing_zeros = true;
1513 __fmt = chars_format::general;
1517 __fmt = chars_format::general;
1520 __builtin_unreachable();
1523 // Write value into buffer using std::to_chars.
1524 auto __to_chars = [&](char* __b, char* __e) {
1526 return __format::to_chars(__b, __e, __v, __fmt, __prec);
1527 else if (__fmt != chars_format{})
1528 return __format::to_chars(__b, __e, __v, __fmt);
1530 return __format::to_chars(__b, __e, __v);
1533 // First try using stack buffer.
1534 __res = __to_chars(__start, __end);
1536 if (__builtin_expect(__res.ec == errc::value_too_large, 0))
1538 // If the buffer is too small it's probably because of a large
1539 // precision, or a very large value in fixed format.
1540 size_t __guess = 8 + __prec;
1541 if (__fmt == chars_format::fixed) // +ddd.prec
1543 if constexpr (is_same_v<_Fp, float> || is_same_v<_Fp, double>
1544 || is_same_v<_Fp, long double>)
1546 // The number of digits to the left of the decimal point
1547 // is floor(log10(max(abs(__v),1)))+1
1549 if constexpr (is_same_v<_Fp, float>)
1550 __builtin_frexpf(__v, &__exp);
1551 else if constexpr (is_same_v<_Fp, double>)
1552 __builtin_frexp(__v, &__exp);
1553 else if constexpr (is_same_v<_Fp, long double>)
1554 __builtin_frexpl(__v, &__exp);
1556 __guess += 1U + __exp * 4004U / 13301U; // log10(2) approx.
1559 __guess += numeric_limits<_Fp>::max_exponent10;
1561 if (__guess <= sizeof(__buf)) [[unlikely]]
1562 __guess = sizeof(__buf) * 2;
1563 __dynbuf.reserve(__guess);
1567 auto __overwrite = [&__to_chars, &__res] (char* __p, size_t __n)
1569 __res = __to_chars(__p + 1, __p + __n - 1);
1570 return __res.ec == errc{} ? __res.ptr - __p : 0;
1573 __dynbuf.__resize_and_overwrite(__dynbuf.capacity() * 2,
1575 __start = __dynbuf.data() + 1; // reserve space for sign
1576 __end = __dynbuf.data() + __dynbuf.size();
1578 while (__builtin_expect(__res.ec == errc::value_too_large, 0));
1581 // Use uppercase for 'A', 'E', and 'G' formats.
1584 for (char* __p = __start; __p != __res.ptr; ++__p)
1585 *__p = std::toupper(*__p);
1588 // Add sign for non-negative values.
1589 if (!__builtin_signbit(__v))
1591 if (_M_spec._M_sign == _Sign_plus)
1593 else if (_M_spec._M_sign == _Sign_space)
1597 string_view __narrow_str(__start, __res.ptr - __start);
1599 // Use alternate form.
1600 if (_M_spec._M_alt && __builtin_isfinite(__v))
1602 string_view __s = __narrow_str;
1605 size_t __d = __s.find('.');
1607 if (__d != __s.npos)
1609 __p = __s.find(__expc, __d + 1);
1610 if (__p == __s.npos)
1612 __sigfigs = __p - 1;
1616 __p = __s.find(__expc);
1617 if (__p == __s.npos)
1619 __d = __p; // Position where '.' should be inserted.
1623 if (__trailing_zeros && __prec != 0)
1625 if (!__format::__is_xdigit(__s[0]))
1627 __z = __prec - __sigfigs; // Number of zeros to insert.
1630 if (size_t __extras = int(__d == __p) + __z)
1632 if (__dynbuf.empty() && __extras <= size_t(__end - __res.ptr))
1634 // Move exponent to make space for extra chars.
1635 __builtin_memmove(__start + __p + __extras,
1640 __start[__p++] = '.';
1641 __builtin_memset(__start + __p, '0', __z);
1642 __narrow_str = {__s.data(), __s.size() + __extras};
1646 __dynbuf.reserve(__s.size() + __extras);
1647 if (__dynbuf.empty())
1649 __dynbuf = __s.substr(0, __p);
1653 __dynbuf.append(__z, '0');
1657 __dynbuf.insert(__p, __extras, '0');
1659 __dynbuf[__p] = '.';
1661 __narrow_str = __dynbuf;
1666 basic_string<_CharT> __wstr;
1667 basic_string_view<_CharT> __str;
1668 if constexpr (is_same_v<_CharT, char>)
1669 __str = __narrow_str;
1670 #ifdef _GLIBCXX_USE_WCHAR_T
1673 __wstr = std::__to_wstring_numeric(__narrow_str);
1678 if (_M_spec._M_localized)
1680 __wstr = _M_localize(__str, __expc, __fc.locale());
1681 if (!__wstr.empty())
1685 size_t __width = _M_spec._M_get_width(__fc);
1687 if (__width <= __str.size())
1688 return __format::__write(__fc.out(), __str);
1690 _CharT __fill_char = _M_spec._M_fill;
1691 _Align __align = _M_spec._M_align;
1693 size_t __nfill = __width - __str.size();
1694 auto __out = __fc.out();
1695 if (__align == _Align_default)
1697 __align = _Align_right;
1698 if (_M_spec._M_zero_fill && __builtin_isfinite(__v))
1700 __fill_char = _CharT('0');
1701 // Write sign before zero filling.
1702 if (!__format::__is_xdigit(__narrow_str[0]))
1704 *__out++ = __str[0];
1705 __str.remove_prefix(1);
1709 __fill_char = _CharT(' ');
1711 return __format::__write_padded(std::move(__out), __str,
1712 __align, __nfill, __fill_char);
1715 // Locale-specific format.
1716 basic_string<_CharT>
1717 _M_localize(basic_string_view<_CharT> __str, char __expc,
1718 const locale& __loc) const
1720 basic_string<_CharT> __lstr;
1722 if (__loc == locale::classic())
1723 return __lstr; // Nothing to do.
1725 const auto& __np = use_facet<numpunct<_CharT>>(__loc);
1726 const _CharT __point = __np.decimal_point();
1727 const string __grp = __np.grouping();
1729 _CharT __dot, __exp;
1730 if constexpr (is_same_v<_CharT, char>)
1753 __builtin_unreachable();
1757 if (__grp.empty() && __point == __dot)
1758 return __lstr; // Locale uses '.' and no grouping.
1760 size_t __d = __str.find(__dot);
1761 size_t __e = min(__d, __str.find(__exp));
1762 if (__e == __str.npos)
1764 const size_t __r = __str.size() - __e;
1765 auto __overwrite = [&](_CharT* __p, size_t) {
1766 auto __end = std::__add_grouping(__p, __np.thousands_sep(),
1767 __grp.data(), __grp.size(),
1768 __str.data(), __str.data() + __e);
1771 if (__d != __str.npos)
1778 __end += __str.copy(__end, __str.npos, __e);
1780 return (__end - __p);
1782 __lstr.__resize_and_overwrite(__e * 2 + __r, __overwrite);
1786 _Spec<_CharT> _M_spec{};
1789 } // namespace __format
1792 /// Format a character.
1793 template<__format::__char _CharT>
1794 struct formatter<_CharT, _CharT>
1796 formatter() = default;
1798 constexpr typename basic_format_parse_context<_CharT>::iterator
1799 parse(basic_format_parse_context<_CharT>& __pc)
1801 return _M_f.template _M_parse<_CharT>(__pc);
1804 template<typename _Out>
1805 typename basic_format_context<_Out, _CharT>::iterator
1806 format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const
1808 if (_M_f._M_spec._M_type == __format::_Pres_none
1809 || _M_f._M_spec._M_type == __format::_Pres_c)
1810 return _M_f._M_format_character(__u, __fc);
1811 else if (_M_f._M_spec._M_type == __format::_Pres_esc)
1817 return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), __fc);
1820 #if __cpp_lib_format_ranges
1822 set_debug_format() noexcept
1823 { _M_f._M_spec._M_type = __format::_Pres_esc; }
1827 __format::__formatter_int<_CharT> _M_f;
1830 #ifdef _GLIBCXX_USE_WCHAR_T
1831 /// Format a char value for wide character output.
1833 struct formatter<char, wchar_t>
1835 formatter() = default;
1837 constexpr typename basic_format_parse_context<wchar_t>::iterator
1838 parse(basic_format_parse_context<wchar_t>& __pc)
1840 return _M_f._M_parse<char>(__pc);
1843 template<typename _Out>
1844 typename basic_format_context<_Out, wchar_t>::iterator
1845 format(char __u, basic_format_context<_Out, wchar_t>& __fc) const
1847 if (_M_f._M_spec._M_type == __format::_Pres_none
1848 || _M_f._M_spec._M_type == __format::_Pres_c)
1849 return _M_f._M_format_character(__u, __fc);
1850 else if (_M_f._M_spec._M_type == __format::_Pres_esc)
1856 return _M_f.format(static_cast<unsigned char>(__u), __fc);
1859 #if __cpp_lib_format_ranges
1861 set_debug_format() noexcept
1862 { _M_f._M_spec._M_type = __format::_Pres_esc; }
1866 __format::__formatter_int<wchar_t> _M_f;
1868 #endif // USE_WCHAR_T
1870 /** Format a string.
1873 template<__format::__char _CharT>
1874 struct formatter<_CharT*, _CharT>
1876 formatter() = default;
1878 [[__gnu__::__always_inline__]]
1879 constexpr typename basic_format_parse_context<_CharT>::iterator
1880 parse(basic_format_parse_context<_CharT>& __pc)
1881 { return _M_f.parse(__pc); }
1883 template<typename _Out>
1884 [[__gnu__::__nonnull__]]
1885 typename basic_format_context<_Out, _CharT>::iterator
1886 format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const
1887 { return _M_f.format(__u, __fc); }
1889 #if __cpp_lib_format_ranges
1890 constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
1894 __format::__formatter_str<_CharT> _M_f;
1897 template<__format::__char _CharT>
1898 struct formatter<const _CharT*, _CharT>
1900 formatter() = default;
1902 [[__gnu__::__always_inline__]]
1903 constexpr typename basic_format_parse_context<_CharT>::iterator
1904 parse(basic_format_parse_context<_CharT>& __pc)
1905 { return _M_f.parse(__pc); }
1907 template<typename _Out>
1908 [[__gnu__::__nonnull__]]
1909 typename basic_format_context<_Out, _CharT>::iterator
1910 format(const _CharT* __u,
1911 basic_format_context<_Out, _CharT>& __fc) const
1912 { return _M_f.format(__u, __fc); }
1914 #if __cpp_lib_format_ranges
1915 constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
1919 __format::__formatter_str<_CharT> _M_f;
1922 template<__format::__char _CharT, size_t _Nm>
1923 struct formatter<_CharT[_Nm], _CharT>
1925 formatter() = default;
1927 [[__gnu__::__always_inline__]]
1928 constexpr typename basic_format_parse_context<_CharT>::iterator
1929 parse(basic_format_parse_context<_CharT>& __pc)
1930 { return _M_f.parse(__pc); }
1932 template<typename _Out>
1933 typename basic_format_context<_Out, _CharT>::iterator
1934 format(const _CharT (&__u)[_Nm],
1935 basic_format_context<_Out, _CharT>& __fc) const
1936 { return _M_f.format({__u, _Nm}, __fc); }
1938 #if __cpp_lib_format_ranges
1939 constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
1943 __format::__formatter_str<_CharT> _M_f;
1946 template<typename _Traits, typename _Alloc>
1947 struct formatter<basic_string<char, _Traits, _Alloc>, char>
1949 formatter() = default;
1951 [[__gnu__::__always_inline__]]
1952 constexpr typename basic_format_parse_context<char>::iterator
1953 parse(basic_format_parse_context<char>& __pc)
1954 { return _M_f.parse(__pc); }
1956 template<typename _Out>
1957 typename basic_format_context<_Out, char>::iterator
1958 format(const basic_string<char, _Traits, _Alloc>& __u,
1959 basic_format_context<_Out, char>& __fc) const
1960 { return _M_f.format(__u, __fc); }
1962 #if __cpp_lib_format_ranges
1963 constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
1967 __format::__formatter_str<char> _M_f;
1970 #ifdef _GLIBCXX_USE_WCHAR_T
1971 template<typename _Traits, typename _Alloc>
1972 struct formatter<basic_string<wchar_t, _Traits, _Alloc>, wchar_t>
1974 formatter() = default;
1976 [[__gnu__::__always_inline__]]
1977 constexpr typename basic_format_parse_context<wchar_t>::iterator
1978 parse(basic_format_parse_context<wchar_t>& __pc)
1979 { return _M_f.parse(__pc); }
1981 template<typename _Out>
1982 typename basic_format_context<_Out, wchar_t>::iterator
1983 format(const basic_string<wchar_t, _Traits, _Alloc>& __u,
1984 basic_format_context<_Out, wchar_t>& __fc) const
1985 { return _M_f.format(__u, __fc); }
1987 #if __cpp_lib_format_ranges
1988 constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
1992 __format::__formatter_str<wchar_t> _M_f;
1994 #endif // USE_WCHAR_T
1996 template<typename _Traits>
1997 struct formatter<basic_string_view<char, _Traits>, char>
1999 formatter() = default;
2001 [[__gnu__::__always_inline__]]
2002 constexpr typename basic_format_parse_context<char>::iterator
2003 parse(basic_format_parse_context<char>& __pc)
2004 { return _M_f.parse(__pc); }
2006 template<typename _Out>
2007 typename basic_format_context<_Out, char>::iterator
2008 format(basic_string_view<char, _Traits> __u,
2009 basic_format_context<_Out, char>& __fc) const
2010 { return _M_f.format(__u, __fc); }
2012 #if __cpp_lib_format_ranges
2013 constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2017 __format::__formatter_str<char> _M_f;
2020 #ifdef _GLIBCXX_USE_WCHAR_T
2021 template<typename _Traits>
2022 struct formatter<basic_string_view<wchar_t, _Traits>, wchar_t>
2024 formatter() = default;
2026 [[__gnu__::__always_inline__]]
2027 constexpr typename basic_format_parse_context<wchar_t>::iterator
2028 parse(basic_format_parse_context<wchar_t>& __pc)
2029 { return _M_f.parse(__pc); }
2031 template<typename _Out>
2032 typename basic_format_context<_Out, wchar_t>::iterator
2033 format(basic_string_view<wchar_t, _Traits> __u,
2034 basic_format_context<_Out, wchar_t>& __fc) const
2035 { return _M_f.format(__u, __fc); }
2037 #if __cpp_lib_format_ranges
2038 constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2042 __format::__formatter_str<wchar_t> _M_f;
2044 #endif // USE_WCHAR_T
2047 /// Format an integer.
2048 template<integral _Tp, __format::__char _CharT>
2049 requires (!__is_one_of<_Tp, char, wchar_t, char16_t, char32_t>::value)
2050 struct formatter<_Tp, _CharT>
2052 formatter() = default;
2054 [[__gnu__::__always_inline__]]
2055 constexpr typename basic_format_parse_context<_CharT>::iterator
2056 parse(basic_format_parse_context<_CharT>& __pc)
2058 return _M_f.template _M_parse<_Tp>(__pc);
2061 template<typename _Out>
2062 typename basic_format_context<_Out, _CharT>::iterator
2063 format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
2064 { return _M_f.format(__u, __fc); }
2067 __format::__formatter_int<_CharT> _M_f;
2070 #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
2071 template<typename _Tp, __format::__char _CharT>
2072 requires (__is_one_of<_Tp, __int128, unsigned __int128>::value)
2073 struct formatter<_Tp, _CharT>
2075 formatter() = default;
2077 [[__gnu__::__always_inline__]]
2078 constexpr typename basic_format_parse_context<_CharT>::iterator
2079 parse(basic_format_parse_context<_CharT>& __pc)
2081 return _M_f.template _M_parse<_Tp>(__pc);
2084 template<typename _Out>
2085 typename basic_format_context<_Out, _CharT>::iterator
2086 format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
2087 { return _M_f.format(__u, __fc); }
2090 __format::__formatter_int<_CharT> _M_f;
2094 #if defined __glibcxx_to_chars
2095 /// Format a floating-point value.
2096 template<__format::__formattable_float _Tp, __format::__char _CharT>
2097 struct formatter<_Tp, _CharT>
2099 formatter() = default;
2101 [[__gnu__::__always_inline__]]
2102 constexpr typename basic_format_parse_context<_CharT>::iterator
2103 parse(basic_format_parse_context<_CharT>& __pc)
2104 { return _M_f.parse(__pc); }
2106 template<typename _Out>
2107 typename basic_format_context<_Out, _CharT>::iterator
2108 format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
2109 { return _M_f.format(__u, __fc); }
2112 __format::__formatter_fp<_CharT> _M_f;
2115 #if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__
2116 // Reuse __formatter_fp<C>::format<double, Out> for long double.
2117 template<__format::__char _CharT>
2118 struct formatter<long double, _CharT>
2120 formatter() = default;
2122 [[__gnu__::__always_inline__]]
2123 constexpr typename basic_format_parse_context<_CharT>::iterator
2124 parse(basic_format_parse_context<_CharT>& __pc)
2125 { return _M_f.parse(__pc); }
2127 template<typename _Out>
2128 typename basic_format_context<_Out, _CharT>::iterator
2129 format(long double __u, basic_format_context<_Out, _CharT>& __fc) const
2130 { return _M_f.format((double)__u, __fc); }
2133 __format::__formatter_fp<_CharT> _M_f;
2137 #ifdef __STDCPP_FLOAT16_T__
2138 // Reuse __formatter_fp<C>::format<float, Out> for _Float16.
2139 template<__format::__char _CharT>
2140 struct formatter<_Float16, _CharT>
2142 formatter() = default;
2144 [[__gnu__::__always_inline__]]
2145 constexpr typename basic_format_parse_context<_CharT>::iterator
2146 parse(basic_format_parse_context<_CharT>& __pc)
2147 { return _M_f.parse(__pc); }
2149 template<typename _Out>
2150 typename basic_format_context<_Out, _CharT>::iterator
2151 format(_Float16 __u, basic_format_context<_Out, _CharT>& __fc) const
2152 { return _M_f.format((float)__u, __fc); }
2155 __format::__formatter_fp<_CharT> _M_f;
2159 #if defined(__FLT32_DIG__)
2160 // Reuse __formatter_fp<C>::format<float, Out> for _Float32.
2161 template<__format::__char _CharT>
2162 struct formatter<_Float32, _CharT>
2164 formatter() = default;
2166 [[__gnu__::__always_inline__]]
2167 constexpr typename basic_format_parse_context<_CharT>::iterator
2168 parse(basic_format_parse_context<_CharT>& __pc)
2169 { return _M_f.parse(__pc); }
2171 template<typename _Out>
2172 typename basic_format_context<_Out, _CharT>::iterator
2173 format(_Float32 __u, basic_format_context<_Out, _CharT>& __fc) const
2174 { return _M_f.format((float)__u, __fc); }
2177 __format::__formatter_fp<_CharT> _M_f;
2181 #if defined(__FLT64_DIG__)
2182 // Reuse __formatter_fp<C>::format<double, Out> for _Float64.
2183 template<__format::__char _CharT>
2184 struct formatter<_Float64, _CharT>
2186 formatter() = default;
2188 [[__gnu__::__always_inline__]]
2189 constexpr typename basic_format_parse_context<_CharT>::iterator
2190 parse(basic_format_parse_context<_CharT>& __pc)
2191 { return _M_f.parse(__pc); }
2193 template<typename _Out>
2194 typename basic_format_context<_Out, _CharT>::iterator
2195 format(_Float64 __u, basic_format_context<_Out, _CharT>& __fc) const
2196 { return _M_f.format((double)__u, __fc); }
2199 __format::__formatter_fp<_CharT> _M_f;
2203 #if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1
2204 // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128.
2205 template<__format::__char _CharT>
2206 struct formatter<_Float128, _CharT>
2208 formatter() = default;
2210 [[__gnu__::__always_inline__]]
2211 constexpr typename basic_format_parse_context<_CharT>::iterator
2212 parse(basic_format_parse_context<_CharT>& __pc)
2213 { return _M_f.parse(__pc); }
2215 template<typename _Out>
2216 typename basic_format_context<_Out, _CharT>::iterator
2217 format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const
2218 { return _M_f.format((__format::__float128_t)__u, __fc); }
2221 __format::__formatter_fp<_CharT> _M_f;
2225 #ifdef __STDCPP_BFLOAT16_T__
2226 // Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t.
2227 template<__format::__char _CharT>
2228 struct formatter<__gnu_cxx::__bfloat16_t, _CharT>
2230 formatter() = default;
2232 [[__gnu__::__always_inline__]]
2233 constexpr typename basic_format_parse_context<_CharT>::iterator
2234 parse(basic_format_parse_context<_CharT>& __pc)
2235 { return _M_f.parse(__pc); }
2237 template<typename _Out>
2238 typename basic_format_context<_Out, _CharT>::iterator
2239 format(__gnu_cxx::__bfloat16_t __u,
2240 basic_format_context<_Out, _CharT>& __fc) const
2241 { return _M_f.format((float)__u, __fc); }
2244 __format::__formatter_fp<_CharT> _M_f;
2247 #endif // __cpp_lib_to_chars
2249 /** Format a pointer.
2252 template<__format::__char _CharT>
2253 struct formatter<const void*, _CharT>
2255 formatter() = default;
2257 constexpr typename basic_format_parse_context<_CharT>::iterator
2258 parse(basic_format_parse_context<_CharT>& __pc)
2260 __format::_Spec<_CharT> __spec{};
2261 const auto __last = __pc.end();
2262 auto __first = __pc.begin();
2264 auto __finalize = [this, &__spec] {
2268 auto __finished = [&] {
2269 if (__first == __last || *__first == '}')
2280 __first = __spec._M_parse_fill_and_align(__first, __last);
2284 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2285 // P2510R3 Formatting pointers
2286 #if __cplusplus > 202302L || ! defined __STRICT_ANSI__
2287 #define _GLIBCXX_P2518R3 1
2289 #define _GLIBCXX_P2518R3 0
2292 #if _GLIBCXX_P2518R3
2293 __first = __spec._M_parse_zero_fill(__first, __last);
2298 __first = __spec._M_parse_width(__first, __last, __pc);
2300 if (__first != __last)
2302 if (*__first == 'p')
2304 #if _GLIBCXX_P2518R3
2305 else if (*__first == 'P')
2307 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2308 // P2510R3 Formatting pointers
2309 __spec._M_type = __format::_Pres_P;
2318 __format::__failed_to_parse_format_spec();
2321 template<typename _Out>
2322 typename basic_format_context<_Out, _CharT>::iterator
2323 format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
2325 auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
2326 char __buf[2 + sizeof(__v) * 2];
2327 auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
2329 int __n = __ptr - __buf;
2332 #if _GLIBCXX_P2518R3
2333 if (_M_spec._M_type == __format::_Pres_P)
2336 for (auto __p = __buf + 2; __p != __ptr; ++__p)
2337 #if __has_builtin(__builtin_toupper)
2338 *__p = __builtin_toupper(*__p);
2340 *__p = std::toupper(*__p);
2345 basic_string_view<_CharT> __str;
2346 if constexpr (is_same_v<_CharT, char>)
2347 __str = string_view(__buf, __n);
2348 #ifdef _GLIBCXX_USE_WCHAR_T
2351 auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
2352 std::__to_wstring_numeric(__buf, __n, __p);
2353 __str = wstring_view(__p, __n);
2357 #if _GLIBCXX_P2518R3
2358 if (_M_spec._M_zero_fill)
2360 size_t __width = _M_spec._M_get_width(__fc);
2361 if (__width <= __str.size())
2362 return __format::__write(__fc.out(), __str);
2364 auto __out = __fc.out();
2365 // Write "0x" or "0X" prefix before zero-filling.
2366 __out = __format::__write(std::move(__out), __str.substr(0, 2));
2367 __str.remove_prefix(2);
2368 size_t __nfill = __width - __n;
2369 return __format::__write_padded(std::move(__out), __str,
2370 __format::_Align_right,
2371 __nfill, _CharT('0'));
2375 return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
2376 __format::_Align_right);
2380 __format::_Spec<_CharT> _M_spec{};
2383 template<__format::__char _CharT>
2384 struct formatter<void*, _CharT>
2386 formatter() = default;
2388 [[__gnu__::__always_inline__]]
2389 constexpr typename basic_format_parse_context<_CharT>::iterator
2390 parse(basic_format_parse_context<_CharT>& __pc)
2391 { return _M_f.parse(__pc); }
2393 template<typename _Out>
2394 typename basic_format_context<_Out, _CharT>::iterator
2395 format(void* __v, basic_format_context<_Out, _CharT>& __fc) const
2396 { return _M_f.format(__v, __fc); }
2399 formatter<const void*, _CharT> _M_f;
2402 template<__format::__char _CharT>
2403 struct formatter<nullptr_t, _CharT>
2405 formatter() = default;
2407 [[__gnu__::__always_inline__]]
2408 constexpr typename basic_format_parse_context<_CharT>::iterator
2409 parse(basic_format_parse_context<_CharT>& __pc)
2410 { return _M_f.parse(__pc); }
2412 template<typename _Out>
2413 typename basic_format_context<_Out, _CharT>::iterator
2414 format(nullptr_t, basic_format_context<_Out, _CharT>& __fc) const
2415 { return _M_f.format(nullptr, __fc); }
2418 formatter<const void*, _CharT> _M_f;
2423 /// @cond undocumented
2426 template<typename _Tp, typename _Context,
2428 = typename _Context::template formatter_type<remove_const_t<_Tp>>,
2429 typename _ParseContext
2430 = basic_format_parse_context<typename _Context::char_type>>
2431 concept __parsable_with
2432 = semiregular<_Formatter>
2433 && requires (_Formatter __f, _ParseContext __pc)
2435 { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>;
2438 template<typename _Tp, typename _Context,
2440 = typename _Context::template formatter_type<remove_const_t<_Tp>>,
2441 typename _ParseContext
2442 = basic_format_parse_context<typename _Context::char_type>>
2443 concept __formattable_with
2444 = semiregular<_Formatter>
2445 && requires (const _Formatter __cf, _Tp&& __t, _Context __fc)
2447 { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
2450 // An unspecified output iterator type used in the `formattable` concept.
2451 template<typename _CharT>
2452 using _Iter_for = back_insert_iterator<basic_string<_CharT>>;
2454 template<typename _Tp, typename _CharT,
2455 typename _Context = basic_format_context<_Iter_for<_CharT>, _CharT>>
2456 concept __formattable_impl
2457 = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>;
2459 } // namespace __format
2462 #if __cplusplus > 202002L
2463 // [format.formattable], concept formattable
2464 template<typename _Tp, typename _CharT>
2466 = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>;
2469 #if __cpp_lib_format_ranges
2470 /// @cond undocumented
2473 template<typename _Rg, typename _CharT>
2474 concept __const_formattable_range
2475 = ranges::input_range<const _Rg>
2476 && formattable<ranges::range_reference_t<const _Rg>, _CharT>;
2478 template<typename _Rg, typename _CharT>
2479 using __maybe_const_range
2480 = conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>;
2481 } // namespace __format
2483 #endif // format_ranges
2485 /// An iterator after the last character written, and the number of
2486 /// characters that would have been written.
2487 template<typename _Out>
2488 struct format_to_n_result
2491 iter_difference_t<_Out> size;
2494 _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
2495 template<typename, typename> class vector;
2496 _GLIBCXX_END_NAMESPACE_CONTAINER
2498 /// @cond undocumented
2501 template<typename _CharT>
2504 _Sink<_CharT>* _M_sink = nullptr;
2507 using iterator_category = output_iterator_tag;
2508 using value_type = void;
2509 using difference_type = ptrdiff_t;
2510 using pointer = void;
2511 using reference = void;
2513 _Sink_iter() = default;
2514 _Sink_iter(const _Sink_iter&) = default;
2515 _Sink_iter& operator=(const _Sink_iter&) = default;
2517 [[__gnu__::__always_inline__]]
2519 _Sink_iter(_Sink<_CharT>& __sink) : _M_sink(std::addressof(__sink)) { }
2521 [[__gnu__::__always_inline__]]
2522 constexpr _Sink_iter&
2523 operator=(_CharT __c)
2525 _M_sink->_M_write(__c);
2529 [[__gnu__::__always_inline__]]
2530 constexpr _Sink_iter&
2531 operator=(basic_string_view<_CharT> __s)
2533 _M_sink->_M_write(__s);
2537 [[__gnu__::__always_inline__]]
2538 constexpr _Sink_iter&
2539 operator*() { return *this; }
2541 [[__gnu__::__always_inline__]]
2542 constexpr _Sink_iter&
2543 operator++() { return *this; }
2545 [[__gnu__::__always_inline__]]
2546 constexpr _Sink_iter
2547 operator++(int) { return *this; }
2550 _M_reserve(size_t __n) const
2551 { return _M_sink->_M_reserve(__n); }
2554 // Abstract base class for type-erased character sinks.
2555 // All formatting and output is done via this type's iterator,
2556 // to reduce the number of different template instantiations.
2557 template<typename _CharT>
2560 friend class _Sink_iter<_CharT>;
2562 span<_CharT> _M_span;
2563 typename span<_CharT>::iterator _M_next;
2565 // Called when the span is full, to make more space available.
2566 // Precondition: _M_next != _M_span.begin()
2567 // Postcondition: _M_next != _M_span.end()
2568 // TODO: remove the precondition? could make overflow handle it.
2569 virtual void _M_overflow() = 0;
2572 // Precondition: __span.size() != 0
2573 [[__gnu__::__always_inline__]]
2575 _Sink(span<_CharT> __span) noexcept
2576 : _M_span(__span), _M_next(__span.begin())
2579 // The portion of the span that has been written to.
2580 [[__gnu__::__always_inline__]]
2582 _M_used() const noexcept
2583 { return _M_span.first(_M_next - _M_span.begin()); }
2585 // The portion of the span that has not been written to.
2586 [[__gnu__::__always_inline__]]
2587 constexpr span<_CharT>
2588 _M_unused() const noexcept
2589 { return _M_span.subspan(_M_next - _M_span.begin()); }
2591 // Use the start of the span as the next write position.
2592 [[__gnu__::__always_inline__]]
2594 _M_rewind() noexcept
2595 { _M_next = _M_span.begin(); }
2597 // Replace the current output range.
2599 _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept
2602 _M_next = __s.begin() + __pos;
2605 // Called by the iterator for *it++ = c
2607 _M_write(_CharT __c)
2610 if (_M_next - _M_span.begin() == std::ssize(_M_span)) [[unlikely]]
2615 _M_write(basic_string_view<_CharT> __s)
2617 span __to = _M_unused();
2618 while (__to.size() <= __s.size())
2620 __s.copy(__to.data(), __to.size());
2621 _M_next += __to.size();
2622 __s.remove_prefix(__to.size());
2628 __s.copy(__to.data(), __s.size());
2629 _M_next += __s.size();
2633 // A successful _Reservation can be used to directly write
2634 // up to N characters to the sink to avoid unwanted buffering.
2637 // True if the reservation was successful, false otherwise.
2638 explicit operator bool() const noexcept { return _M_sink; }
2639 // A pointer to write directly to the sink.
2640 _CharT* get() const noexcept { return _M_sink->_M_next.operator->(); }
2641 // Add n to the _M_next iterator for the sink.
2642 void _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
2646 // Attempt to reserve space to write n characters to the sink.
2647 // If anything is written to the reservation then there must be a call
2648 // to _M_bump(N2) before any call to another member function of *this,
2649 // where N2 is the number of characters written.
2650 virtual _Reservation
2651 _M_reserve(size_t __n)
2653 if (__n <= _M_unused().size())
2656 if (__n <= _M_span.size()) // Cannot meet the request.
2658 _M_overflow(); // Make more space available.
2659 if (__n <= _M_unused().size())
2665 // Update the next output position after writing directly to the sink.
2666 // pre: no calls to _M_write or _M_overflow since _M_reserve.
2672 _Sink(const _Sink&) = delete;
2673 _Sink& operator=(const _Sink&) = delete;
2675 [[__gnu__::__always_inline__]]
2676 constexpr _Sink_iter<_CharT>
2678 { return _Sink_iter<_CharT>(*this); }
2681 // A sink with an internal buffer. This is used to implement concrete sinks.
2682 template<typename _CharT>
2683 class _Buf_sink : public _Sink<_CharT>
2686 _CharT _M_buf[32 * sizeof(void*) / sizeof(_CharT)];
2688 [[__gnu__::__always_inline__]]
2690 _Buf_sink() noexcept
2691 : _Sink<_CharT>(_M_buf)
2695 using _GLIBCXX_STD_C::vector;
2697 // A sink that fills a sequence (e.g. std::string, std::vector, std::deque).
2698 // Writes to a buffer then appends that to the sequence when it fills up.
2699 template<typename _Seq>
2700 class _Seq_sink final : public _Buf_sink<typename _Seq::value_type>
2702 using _CharT = typename _Seq::value_type;
2706 // Transfer buffer contents to the sequence, so buffer can be refilled.
2708 _M_overflow() override
2710 auto __s = this->_M_used();
2711 if (__s.empty()) [[unlikely]]
2712 return; // Nothing in the buffer to transfer to _M_seq.
2714 // If _M_reserve was called then _M_bump must have been called too.
2715 _GLIBCXX_DEBUG_ASSERT(__s.data() != _M_seq.data());
2717 if constexpr (__is_specialization_of<_Seq, basic_string>)
2718 _M_seq.append(__s.data(), __s.size());
2720 _M_seq.insert(_M_seq.end(), __s.begin(), __s.end());
2722 // Make the whole of _M_buf available for the next write:
2726 typename _Sink<_CharT>::_Reservation
2727 _M_reserve(size_t __n) override
2729 // We might already have n characters available in this->_M_unused(),
2730 // but the whole point of this function is to be an optimization for
2731 // the std::format("{}", x) case. We want to avoid writing to _M_buf
2732 // and then copying that into a basic_string if possible, so this
2733 // function prefers to create space directly in _M_seq rather than
2736 if constexpr (__is_specialization_of<_Seq, basic_string>
2737 || __is_specialization_of<_Seq, vector>)
2739 // Flush the buffer to _M_seq first (should not be needed).
2740 if (this->_M_used().size()) [[unlikely]]
2741 _Seq_sink::_M_overflow();
2743 // Expand _M_seq to make __n new characters available:
2744 const auto __sz = _M_seq.size();
2745 if constexpr (is_same_v<string, _Seq> || is_same_v<wstring, _Seq>)
2746 _M_seq.__resize_and_overwrite(__sz + __n,
2747 [](auto, auto __n2) {
2751 _M_seq.resize(__sz + __n);
2753 // Set _M_used() to be a span over the original part of _M_seq
2754 // and _M_unused() to be the extra capacity we just created:
2755 this->_M_reset(_M_seq, __sz);
2758 else // Try to use the base class' buffer.
2759 return _Sink<_CharT>::_M_reserve(__n);
2763 _M_bump(size_t __n) override
2765 if constexpr (__is_specialization_of<_Seq, basic_string>
2766 || __is_specialization_of<_Seq, vector>)
2768 auto __s = this->_M_used();
2769 _GLIBCXX_DEBUG_ASSERT(__s.data() == _M_seq.data());
2770 // Truncate the sequence to the part that was actually written to:
2771 _M_seq.resize(__s.size() + __n);
2772 // Switch back to using buffer:
2773 this->_M_reset(this->_M_buf);
2778 // TODO: for SSO string, use SSO buffer as initial span, then switch
2779 // to _M_buf if it overflows? Or even do that for all unused capacity?
2781 [[__gnu__::__always_inline__]]
2782 _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>)
2785 _Seq_sink(_Seq&& __s) noexcept(is_nothrow_move_constructible_v<_Seq>)
2786 : _M_seq(std::move(__s))
2789 using _Sink<_CharT>::out;
2794 if (this->_M_used().size() != 0)
2795 _Seq_sink::_M_overflow();
2796 return std::move(_M_seq);
2799 // A writable span that views everything written to the sink.
2800 // Will be either a view over _M_seq or the used part of _M_buf.
2804 auto __s = this->_M_used();
2807 if (__s.size() != 0)
2808 _Seq_sink::_M_overflow();
2815 template<typename _CharT, typename _Alloc = allocator<_CharT>>
2817 = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>;
2819 // template<typename _CharT, typename _Alloc = allocator<_CharT>>
2820 // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>;
2822 // A sink that writes to an output iterator.
2823 // Writes to a fixed-size buffer and then flushes to the output iterator
2824 // when the buffer fills up.
2825 template<typename _CharT, typename _OutIter>
2826 class _Iter_sink : public _Buf_sink<_CharT>
2829 iter_difference_t<_OutIter> _M_max;
2832 size_t _M_count = 0;
2835 _M_overflow() override
2837 auto __s = this->_M_used();
2838 if (_M_max < 0) // No maximum.
2839 _M_out = ranges::copy(__s, std::move(_M_out)).out;
2840 else if (_M_count < static_cast<size_t>(_M_max))
2842 auto __max = _M_max - _M_count;
2843 span<_CharT> __first;
2844 if (__max < __s.size())
2845 __first = __s.first(static_cast<size_t>(__max));
2848 _M_out = ranges::copy(__first, std::move(_M_out)).out;
2851 _M_count += __s.size();
2855 [[__gnu__::__always_inline__]]
2857 _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max = -1)
2858 : _M_out(std::move(__out)), _M_max(__max)
2861 using _Sink<_CharT>::out;
2863 format_to_n_result<_OutIter>
2866 if (this->_M_used().size() != 0)
2867 _Iter_sink::_M_overflow();
2868 iter_difference_t<_OutIter> __count(_M_count);
2869 return { std::move(_M_out), __count };
2873 // Partial specialization for contiguous iterators.
2874 // No buffer is used, characters are written straight to the iterator.
2875 // We do not know the size of the output range, so the span size just grows
2876 // as needed. The end of the span might be an invalid pointer outside the
2877 // valid range, but we never actually call _M_span.end(). This class does
2878 // not introduce any invalid pointer arithmetic or overflows that would not
2879 // have happened anyway.
2880 template<typename _CharT, contiguous_iterator _OutIter>
2881 requires same_as<iter_value_t<_OutIter>, _CharT>
2882 class _Iter_sink<_CharT, _OutIter> : public _Sink<_CharT>
2885 iter_difference_t<_OutIter> _M_max = -1;
2887 size_t _M_count = 0;
2889 _CharT _M_buf[64]; // Write here after outputting _M_max characters.
2893 _M_overflow() override
2895 if (this->_M_unused().size() != 0)
2896 return; // No need to switch to internal buffer yet.
2898 auto __s = this->_M_used();
2902 _M_count += __s.size();
2903 // Span was already sized for the maximum character count,
2904 // if it overflows then any further output must go to the
2905 // internal buffer, to be discarded.
2906 this->_M_reset(this->_M_buf);
2910 // No maximum character count. Just extend the span to allow
2911 // writing more characters to it.
2912 this->_M_reset({__s.data(), __s.size() + 1024}, __s.size());
2916 typename _Sink<_CharT>::_Reservation
2917 _M_reserve(size_t __n) final
2919 auto __avail = this->_M_unused();
2920 if (__n > __avail.size())
2923 return {}; // cannot grow
2925 auto __s = this->_M_used();
2926 this->_M_reset({__s.data(), __s.size() + __n}, __s.size());
2933 _S_make_span(_CharT* __ptr, iter_difference_t<_OutIter> __n,
2934 span<_CharT> __buf) noexcept
2937 return __buf; // Only write to the internal buffer.
2941 if constexpr (!is_integral_v<iter_difference_t<_OutIter>>
2942 || sizeof(__n) > sizeof(size_t))
2944 // __int128 or __detail::__max_diff_type
2945 auto __m = iter_difference_t<_OutIter>((size_t)-1);
2949 return {__ptr, (size_t)__n};
2952 #if __has_builtin(__builtin_dynamic_object_size)
2953 if (size_t __bytes = __builtin_dynamic_object_size(__ptr, 2))
2954 return {__ptr, __bytes / sizeof(_CharT)};
2956 // Avoid forming a pointer to a different memory page.
2957 const auto __off = reinterpret_cast<__UINTPTR_TYPE__>(__ptr) % 1024;
2958 __n = (1024 - __off) / sizeof(_CharT);
2959 if (__n > 0) [[likely]]
2960 return {__ptr, static_cast<size_t>(__n)};
2961 else // Misaligned/packed buffer of wchar_t?
2967 _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __n = -1) noexcept
2968 : _Sink<_CharT>(_S_make_span(std::to_address(__out), __n, _M_buf)),
2969 _M_first(__out), _M_max(__n)
2972 format_to_n_result<_OutIter>
2975 auto __s = this->_M_used();
2976 if (__s.data() == _M_buf)
2978 // Switched to internal buffer, so must have written _M_max.
2979 iter_difference_t<_OutIter> __count(_M_count + __s.size());
2980 return { _M_first + _M_max, __count };
2982 else // Not using internal buffer yet
2984 iter_difference_t<_OutIter> __count(__s.size());
2985 return { _M_first + __count, __count };
2990 enum _Arg_t : unsigned char {
2991 _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
2992 _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle,
2993 _Arg_i128, _Arg_u128,
2994 _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused.
2995 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
2997 _Arg_f128 = _Arg_ldbl,
2998 _Arg_ibm128 = _Arg_next_value_,
3005 template<typename _Context>
3008 using _CharT = typename _Context::char_type;
3024 unsigned long long _M_ull;
3027 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous.
3028 long double _M_ldbl;
3030 const _CharT* _M_str;
3031 basic_string_view<_CharT> _M_sv;
3033 _HandleBase _M_handle;
3034 #ifdef __SIZEOF_INT128__
3036 unsigned __int128 _M_u128;
3038 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3041 #elif _GLIBCXX_FORMAT_F128 == 2
3042 __float128_t _M_f128;
3046 [[__gnu__::__always_inline__]]
3047 _Arg_value() : _M_none() { }
3050 template<typename _Tp>
3051 _Arg_value(in_place_type_t<_Tp>, _Tp __val)
3052 { _S_get<_Tp>() = __val; }
3055 template<typename _Tp, typename _Self>
3056 [[__gnu__::__always_inline__]]
3058 _S_get(_Self& __u) noexcept
3060 if constexpr (is_same_v<_Tp, bool>)
3062 else if constexpr (is_same_v<_Tp, _CharT>)
3064 else if constexpr (is_same_v<_Tp, int>)
3066 else if constexpr (is_same_v<_Tp, unsigned>)
3068 else if constexpr (is_same_v<_Tp, long long>)
3070 else if constexpr (is_same_v<_Tp, unsigned long long>)
3072 else if constexpr (is_same_v<_Tp, float>)
3074 else if constexpr (is_same_v<_Tp, double>)
3076 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3077 else if constexpr (is_same_v<_Tp, long double>)
3080 else if constexpr (is_same_v<_Tp, __ieee128>)
3082 else if constexpr (is_same_v<_Tp, __ibm128>)
3083 return __u._M_ibm128;
3085 else if constexpr (is_same_v<_Tp, const _CharT*>)
3087 else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
3089 else if constexpr (is_same_v<_Tp, const void*>)
3091 #ifdef __SIZEOF_INT128__
3092 else if constexpr (is_same_v<_Tp, __int128>)
3094 else if constexpr (is_same_v<_Tp, unsigned __int128>)
3097 #if _GLIBCXX_FORMAT_F128 == 2
3098 else if constexpr (is_same_v<_Tp, __float128_t>)
3101 else if constexpr (derived_from<_Tp, _HandleBase>)
3102 return static_cast<_Tp&>(__u._M_handle);
3103 // Otherwise, ill-formed.
3106 template<typename _Tp>
3107 [[__gnu__::__always_inline__]]
3110 { return _S_get<_Tp>(*this); }
3112 template<typename _Tp>
3113 [[__gnu__::__always_inline__]]
3115 _M_get() const noexcept
3116 { return _S_get<_Tp>(*this); }
3118 template<typename _Tp>
3119 [[__gnu__::__always_inline__]]
3121 _M_set(_Tp __v) noexcept
3123 if constexpr (derived_from<_Tp, _HandleBase>)
3124 std::construct_at(&_M_handle, __v);
3126 _S_get<_Tp>(*this) = __v;
3130 // [format.arg.store], class template format-arg-store
3131 template<typename _Context, typename... _Args>
3134 } // namespace __format
3137 template<typename _Context>
3138 class basic_format_arg
3140 using _CharT = typename _Context::char_type;
3142 template<typename _Tp>
3143 static constexpr bool __formattable
3144 = __format::__formattable_with<_Tp, _Context>;
3147 class handle : public __format::_Arg_value<_Context>::_HandleBase
3149 using _Base = typename __format::_Arg_value<_Context>::_HandleBase;
3151 // Format as const if possible, to reduce instantiations.
3152 template<typename _Tp>
3153 using __maybe_const_t
3154 = __conditional_t<__format::__formattable_with<_Tp, _Context>,
3157 template<typename _Tq>
3159 _S_format(basic_format_parse_context<_CharT>& __parse_ctx,
3160 _Context& __format_ctx, const void* __ptr)
3162 using _Td = remove_const_t<_Tq>;
3163 typename _Context::template formatter_type<_Td> __f;
3164 __parse_ctx.advance_to(__f.parse(__parse_ctx));
3165 _Tq& __val = *const_cast<_Tq*>(static_cast<const _Td*>(__ptr));
3166 __format_ctx.advance_to(__f.format(__val, __format_ctx));
3169 template<typename _Tp>
3171 handle(_Tp& __val) noexcept
3173 if constexpr (!__format::__formattable_with<const _Tp, _Context>)
3174 static_assert(!is_const_v<_Tp>, "std::format argument must be "
3175 "non-const for this type");
3177 this->_M_ptr = __builtin_addressof(__val);
3178 auto __func = _S_format<__maybe_const_t<_Tp>>;
3179 this->_M_func = reinterpret_cast<void(*)()>(__func);
3182 friend class basic_format_arg<_Context>;
3185 handle(const handle&) = default;
3186 handle& operator=(const handle&) = default;
3188 [[__gnu__::__always_inline__]]
3190 format(basic_format_parse_context<_CharT>& __pc, _Context& __fc) const
3192 using _Func = void(*)(basic_format_parse_context<_CharT>&,
3193 _Context&, const void*);
3194 auto __f = reinterpret_cast<_Func>(this->_M_func);
3195 __f(__pc, __fc, this->_M_ptr);
3199 [[__gnu__::__always_inline__]]
3200 basic_format_arg() noexcept : _M_type(__format::_Arg_none) { }
3202 [[nodiscard,__gnu__::__always_inline__]]
3203 explicit operator bool() const noexcept
3204 { return _M_type != __format::_Arg_none; }
3207 template<typename _Ctx>
3208 friend class basic_format_args;
3210 template<typename _Ctx, typename... _Args>
3211 friend class __format::_Arg_store;
3213 static_assert(is_trivially_copyable_v<__format::_Arg_value<_Context>>);
3215 __format::_Arg_value<_Context> _M_val;
3216 __format::_Arg_t _M_type;
3218 // Transform incoming argument type to the type stored in _Arg_value.
3219 // e.g. short -> int, std::string -> std::string_view,
3220 // char[3] -> const char*.
3221 template<typename _Tp>
3222 static consteval auto
3225 using _Td = remove_const_t<_Tp>;
3226 if constexpr (is_same_v<_Td, bool>)
3227 return type_identity<bool>();
3228 else if constexpr (is_same_v<_Td, _CharT>)
3229 return type_identity<_CharT>();
3230 else if constexpr (is_same_v<_Td, char> && is_same_v<_CharT, wchar_t>)
3231 return type_identity<_CharT>();
3232 #ifdef __SIZEOF_INT128__ // Check before signed/unsigned integer
3233 else if constexpr (is_same_v<_Td, __int128>)
3234 return type_identity<__int128>();
3235 else if constexpr (is_same_v<_Td, unsigned __int128>)
3236 return type_identity<unsigned __int128>();
3238 else if constexpr (__is_signed_integer<_Td>::value)
3240 if constexpr (sizeof(_Td) <= sizeof(int))
3241 return type_identity<int>();
3242 else if constexpr (sizeof(_Td) <= sizeof(long long))
3243 return type_identity<long long>();
3245 else if constexpr (__is_unsigned_integer<_Td>::value)
3247 if constexpr (sizeof(_Td) <= sizeof(unsigned))
3248 return type_identity<unsigned>();
3249 else if constexpr (sizeof(_Td) <= sizeof(unsigned long long))
3250 return type_identity<unsigned long long>();
3252 else if constexpr (is_same_v<_Td, float>)
3253 return type_identity<float>();
3254 else if constexpr (is_same_v<_Td, double>)
3255 return type_identity<double>();
3256 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3257 else if constexpr (is_same_v<_Td, long double>)
3258 return type_identity<long double>();
3260 else if constexpr (is_same_v<_Td, __ibm128>)
3261 return type_identity<__ibm128>();
3262 else if constexpr (is_same_v<_Td, __ieee128>)
3263 return type_identity<__ieee128>();
3266 #if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
3267 else if constexpr (is_same_v<_Td, _Float16>)
3268 return type_identity<float>();
3271 #if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
3272 else if constexpr (is_same_v<_Td, decltype(0.0bf16)>)
3273 return type_identity<float>();
3276 #ifdef __FLT32_DIG__
3277 else if constexpr (is_same_v<_Td, _Float32>)
3278 # ifdef _GLIBCXX_FLOAT_IS_IEEE_BINARY32
3279 return type_identity<float>();
3281 return type_identity<_Float32>();
3284 #ifdef __FLT64_DIG__
3285 else if constexpr (is_same_v<_Td, _Float64>)
3286 # ifdef _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
3287 return type_identity<double>();
3289 return type_identity<_Float64>();
3292 #if _GLIBCXX_FORMAT_F128
3294 else if constexpr (is_same_v<_Td, _Float128>)
3295 return type_identity<__format::__float128_t>();
3297 # if __SIZEOF_FLOAT128__
3298 else if constexpr (is_same_v<_Td, __float128>)
3299 return type_identity<__format::__float128_t>();
3302 else if constexpr (__is_specialization_of<_Td, basic_string_view>
3303 || __is_specialization_of<_Td, basic_string>)
3305 if constexpr (is_same_v<typename _Td::value_type, _CharT>)
3306 return type_identity<basic_string_view<_CharT>>();
3308 return type_identity<handle>();
3310 else if constexpr (is_same_v<decay_t<_Td>, const _CharT*>)
3311 return type_identity<const _CharT*>();
3312 else if constexpr (is_same_v<decay_t<_Td>, _CharT*>)
3313 return type_identity<const _CharT*>();
3314 else if constexpr (is_void_v<remove_pointer_t<_Td>>)
3315 return type_identity<const void*>();
3316 else if constexpr (is_same_v<_Td, nullptr_t>)
3317 return type_identity<const void*>();
3319 return type_identity<handle>();
3322 // Transform a formattable type to the appropriate storage type.
3323 template<typename _Tp>
3324 using _Normalize = typename decltype(_S_to_arg_type<_Tp>())::type;
3326 // Get the _Arg_t value corresponding to a normalized type.
3327 template<typename _Tp>
3328 static consteval __format::_Arg_t
3331 using namespace __format;
3332 if constexpr (is_same_v<_Tp, bool>)
3334 else if constexpr (is_same_v<_Tp, _CharT>)
3336 else if constexpr (is_same_v<_Tp, int>)
3338 else if constexpr (is_same_v<_Tp, unsigned>)
3340 else if constexpr (is_same_v<_Tp, long long>)
3342 else if constexpr (is_same_v<_Tp, unsigned long long>)
3344 else if constexpr (is_same_v<_Tp, float>)
3346 else if constexpr (is_same_v<_Tp, double>)
3348 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3349 else if constexpr (is_same_v<_Tp, long double>)
3352 // Don't use _Arg_ldbl for this target, it's ambiguous.
3353 else if constexpr (is_same_v<_Tp, __ibm128>)
3355 else if constexpr (is_same_v<_Tp, __ieee128>)
3358 else if constexpr (is_same_v<_Tp, const _CharT*>)
3360 else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
3362 else if constexpr (is_same_v<_Tp, const void*>)
3364 #ifdef __SIZEOF_INT128__
3365 else if constexpr (is_same_v<_Tp, __int128>)
3367 else if constexpr (is_same_v<_Tp, unsigned __int128>)
3371 // N.B. some of these types will never actually be used here,
3372 // because they get normalized to a standard floating-point type.
3373 #if defined __FLT32_DIG__ && ! _GLIBCXX_FLOAT_IS_IEEE_BINARY32
3374 else if constexpr (is_same_v<_Tp, _Float32>)
3377 #if defined __FLT64_DIG__ && ! _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
3378 else if constexpr (is_same_v<_Tp, _Float64>)
3381 #if _GLIBCXX_FORMAT_F128 == 2
3382 else if constexpr (is_same_v<_Tp, __format::__float128_t>)
3385 else if constexpr (is_same_v<_Tp, handle>)
3389 template<typename _Tp>
3391 _M_set(_Tp __v) noexcept
3393 _M_type = _S_to_enum<_Tp>();
3397 template<typename _Tp>
3398 requires __format::__formattable_with<_Tp, _Context>
3400 basic_format_arg(_Tp& __v) noexcept
3402 using _Td = _Normalize<_Tp>;
3403 if constexpr (is_same_v<_Td, basic_string_view<_CharT>>)
3404 _M_set(_Td{__v.data(), __v.size()});
3405 else if constexpr (is_same_v<remove_const_t<_Tp>, char>
3406 && is_same_v<_CharT, wchar_t>)
3407 _M_set(static_cast<_Td>(static_cast<unsigned char>(__v)));
3409 _M_set(static_cast<_Td>(__v));
3412 template<typename _Ctx, typename... _Argz>
3414 make_format_args(_Argz&&...) noexcept;
3416 template<typename _Visitor, typename _Ctx>
3417 friend decltype(auto)
3418 visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>);
3420 template<typename _Visitor>
3422 _M_visit(_Visitor&& __vis, __format::_Arg_t __type)
3424 using namespace __format;
3428 return std::forward<_Visitor>(__vis)(_M_val._M_none);
3430 return std::forward<_Visitor>(__vis)(_M_val._M_bool);
3432 return std::forward<_Visitor>(__vis)(_M_val._M_c);
3434 return std::forward<_Visitor>(__vis)(_M_val._M_i);
3436 return std::forward<_Visitor>(__vis)(_M_val._M_u);
3438 return std::forward<_Visitor>(__vis)(_M_val._M_ll);
3440 return std::forward<_Visitor>(__vis)(_M_val._M_ull);
3441 #if __glibcxx_to_chars // FIXME: need to be able to format these types!
3443 return std::forward<_Visitor>(__vis)(_M_val._M_flt);
3445 return std::forward<_Visitor>(__vis)(_M_val._M_dbl);
3446 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3448 return std::forward<_Visitor>(__vis)(_M_val._M_ldbl);
3451 return std::forward<_Visitor>(__vis)(_M_val._M_f128);
3453 return std::forward<_Visitor>(__vis)(_M_val._M_ibm128);
3457 return std::forward<_Visitor>(__vis)(_M_val._M_str);
3459 return std::forward<_Visitor>(__vis)(_M_val._M_sv);
3461 return std::forward<_Visitor>(__vis)(_M_val._M_ptr);
3464 auto& __h = static_cast<handle&>(_M_val._M_handle);
3465 return std::forward<_Visitor>(__vis)(__h);
3467 #ifdef __SIZEOF_INT128__
3469 return std::forward<_Visitor>(__vis)(_M_val._M_i128);
3471 return std::forward<_Visitor>(__vis)(_M_val._M_u128);
3474 #if _GLIBCXX_FORMAT_F128 == 2
3476 return std::forward<_Visitor>(__vis)(_M_val._M_f128);
3481 __builtin_unreachable();
3486 template<typename _Visitor, typename _Context>
3487 inline decltype(auto)
3488 visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg)
3490 return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type);
3493 /// @cond undocumented
3496 struct _WidthPrecVisitor
3498 template<typename _Tp>
3500 operator()(_Tp& __arg) const
3502 if constexpr (is_same_v<_Tp, monostate>)
3503 __format::__invalid_arg_id_in_format_string();
3504 // _GLIBCXX_RESOLVE_LIB_DEFECTS
3505 // 3720. Restrict the valid types of arg-id for width and precision
3506 // 3721. Allow an arg-id with a value of zero for width
3507 else if constexpr (sizeof(_Tp) <= sizeof(long long))
3509 // _GLIBCXX_RESOLVE_LIB_DEFECTS
3510 // 3720. Restrict the valid types of arg-id for width and precision
3511 if constexpr (__is_unsigned_integer<_Tp>::value)
3513 else if constexpr (__is_signed_integer<_Tp>::value)
3517 __throw_format_error("format error: argument used for width or "
3518 "precision must be a non-negative integer");
3522 template<typename _Context>
3524 __int_from_arg(const basic_format_arg<_Context>& __arg)
3525 { return std::visit_format_arg(_WidthPrecVisitor(), __arg); }
3527 // Pack _Arg_t enum values into a single 60-bit integer.
3528 template<int _Bits, size_t _Nm>
3530 __pack_arg_types(const array<_Arg_t, _Nm>& __types)
3532 __UINT64_TYPE__ __packed_types = 0;
3533 for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i)
3534 __packed_types = (__packed_types << _Bits) | *__i;
3535 return __packed_types;
3537 } // namespace __format
3540 template<typename _Context>
3541 class basic_format_args
3543 static constexpr int _S_packed_type_bits = 5; // _Arg_t values [0,20]
3544 static constexpr int _S_packed_type_mask = 0b11111;
3545 static constexpr int _S_max_packed_args = 12;
3547 static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) );
3549 template<typename... _Args>
3550 using _Store = __format::_Arg_store<_Context, _Args...>;
3552 template<typename _Ctx, typename... _Args>
3553 friend class __format::_Arg_store;
3555 using uint64_t = __UINT64_TYPE__;
3556 using _Format_arg = basic_format_arg<_Context>;
3557 using _Format_arg_val = __format::_Arg_value<_Context>;
3559 // If args are packed then the number of args is in _M_packed_size and
3560 // the packed types are in _M_unpacked_size, accessed via _M_type(i).
3561 // If args are not packed then the number of args is in _M_unpacked_size
3562 // and _M_packed_size is zero.
3563 uint64_t _M_packed_size : 4;
3564 uint64_t _M_unpacked_size : 60;
3567 const _Format_arg_val* _M_values; // Active when _M_packed_size != 0
3568 const _Format_arg* _M_args; // Active when _M_packed_size == 0
3572 _M_size() const noexcept
3573 { return _M_packed_size ? _M_packed_size : _M_unpacked_size; }
3575 typename __format::_Arg_t
3576 _M_type(size_t __i) const noexcept
3578 uint64_t __t = _M_unpacked_size >> (__i * _S_packed_type_bits);
3579 return static_cast<__format::_Arg_t>(__t & _S_packed_type_mask);
3582 template<typename _Ctx, typename... _Args>
3584 make_format_args(_Args&&...) noexcept;
3586 // An array of _Arg_t enums corresponding to _Args...
3587 template<typename... _Args>
3588 static consteval array<__format::_Arg_t, sizeof...(_Args)>
3590 { return {_Format_arg::template _S_to_enum<_Args>()...}; }
3593 basic_format_args() noexcept = default;
3595 template<typename... _Args>
3596 basic_format_args(const _Store<_Args...>& __store) noexcept;
3598 [[nodiscard,__gnu__::__always_inline__]]
3599 basic_format_arg<_Context>
3600 get(size_t __i) const noexcept
3602 basic_format_arg<_Context> __arg;
3603 if (__i < _M_packed_size)
3605 __arg._M_type = _M_type(__i);
3606 __arg._M_val = _M_values[__i];
3608 else if (_M_packed_size == 0 && __i < _M_unpacked_size)
3609 __arg = _M_args[__i];
3614 // _GLIBCXX_RESOLVE_LIB_DEFECTS
3615 // 3810. CTAD for std::basic_format_args
3616 template<typename _Context, typename... _Args>
3617 basic_format_args(__format::_Arg_store<_Context, _Args...>)
3618 -> basic_format_args<_Context>;
3620 template<typename _Context, typename... _Args>
3622 make_format_args(_Args&&... __fmt_args) noexcept;
3624 // An array of type-erased formatting arguments.
3625 template<typename _Context, typename... _Args>
3626 class __format::_Arg_store
3628 friend std::basic_format_args<_Context>;
3630 template<typename _Ctx, typename... _Argz>
3632 #if _GLIBCXX_INLINE_VERSION
3633 // Needed for PR c++/59526
3638 make_format_args(_Argz&&...) noexcept;
3640 // For a sufficiently small number of arguments we only store values.
3641 // basic_format_args can get the types from the _Args pack.
3642 static constexpr bool _S_values_only
3643 = sizeof...(_Args) <= basic_format_args<_Context>::_S_max_packed_args;
3646 = __conditional_t<_S_values_only,
3647 __format::_Arg_value<_Context>,
3648 basic_format_arg<_Context>>;
3650 _Element_t _M_args[sizeof...(_Args)];
3652 template<typename _Tp>
3654 _S_make_elt(_Tp& __v)
3656 basic_format_arg<_Context> __arg(__v);
3657 if constexpr (_S_values_only)
3658 return __arg._M_val;
3663 template<typename... _Tp>
3664 requires (sizeof...(_Tp) == sizeof...(_Args))
3665 [[__gnu__::__always_inline__]]
3666 _Arg_store(_Tp&... __a) noexcept
3667 : _M_args{_S_make_elt(__a)...}
3671 template<typename _Context>
3672 class __format::_Arg_store<_Context>
3675 template<typename _Context>
3676 template<typename... _Args>
3678 basic_format_args<_Context>::
3679 basic_format_args(const _Store<_Args...>& __store) noexcept
3681 if constexpr (sizeof...(_Args) == 0)
3684 _M_unpacked_size = 0;
3687 else if constexpr (sizeof...(_Args) <= _S_max_packed_args)
3689 // The number of packed arguments:
3690 _M_packed_size = sizeof...(_Args);
3691 // The packed type enums:
3693 = __format::__pack_arg_types<_S_packed_type_bits>(_S_types_to_pack<_Args...>());
3694 // The _Arg_value objects.
3695 _M_values = __store._M_args;
3699 // No packed arguments:
3701 // The number of unpacked arguments:
3702 _M_unpacked_size = sizeof...(_Args);
3703 // The basic_format_arg objects:
3704 _M_args = __store._M_args;
3708 /// Capture formatting arguments for use by `std::vformat`.
3709 template<typename _Context = format_context, typename... _Args>
3710 [[nodiscard,__gnu__::__always_inline__]]
3712 make_format_args(_Args&&... __fmt_args) noexcept
3714 using _Fmt_arg = basic_format_arg<_Context>;
3715 using _Store = __format::_Arg_store<_Context, typename _Fmt_arg::template
3716 _Normalize<remove_reference_t<_Args>>...>;
3717 return _Store(__fmt_args...);
3720 #ifdef _GLIBCXX_USE_WCHAR_T
3721 /// Capture formatting arguments for use by `std::vformat` (for wide output).
3722 template<typename... _Args>
3723 [[nodiscard,__gnu__::__always_inline__]]
3725 make_wformat_args(_Args&&... __args) noexcept
3726 { return std::make_format_args<wformat_context>(__args...); }
3729 /// @cond undocumented
3732 template<typename _Out, typename _CharT, typename _Context>
3734 __do_vformat_to(_Out, basic_string_view<_CharT>,
3735 const basic_format_args<_Context>&,
3736 const locale* = nullptr);
3737 } // namespace __format
3740 /** Context for std::format and similar functions.
3742 * A formatting context contains an output iterator and locale to use
3743 * for the formatting operations. Most programs will never need to use
3744 * this class template explicitly. For typical uses of `std::format` the
3745 * library will use the specializations `std::format_context` (for `char`)
3746 * and `std::wformat_context` (for `wchar_t`).
3748 template<typename _Out, typename _CharT>
3749 class basic_format_context
3751 static_assert( output_iterator<_Out, const _CharT&> );
3753 basic_format_args<basic_format_context> _M_args;
3755 __format::_Optional_locale _M_loc;
3757 basic_format_context(basic_format_args<basic_format_context> __args,
3759 : _M_args(__args), _M_out(std::move(__out))
3762 basic_format_context(basic_format_args<basic_format_context> __args,
3763 _Out __out, const std::locale& __loc)
3764 : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc)
3767 template<typename _Out2, typename _CharT2, typename _Context2>
3769 __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>,
3770 const basic_format_args<_Context2>&,
3774 basic_format_context() = default;
3775 ~basic_format_context() = default;
3777 using iterator = _Out;
3778 using char_type = _CharT;
3779 template<typename _Tp>
3780 using formatter_type = formatter<_Tp, _CharT>;
3783 basic_format_arg<basic_format_context>
3784 arg(size_t __id) const noexcept
3785 { return _M_args.get(__id); }
3788 std::locale locale() { return _M_loc.value(); }
3791 iterator out() { return std::move(_M_out); }
3793 void advance_to(iterator __it) { _M_out = std::move(__it); }
3797 /// @cond undocumented
3800 // Abstract base class defining an interface for scanning format strings.
3801 // Scan the characters in a format string, dividing it up into strings of
3802 // ordinary characters, escape sequences, and replacement fields.
3803 // Call virtual functions for derived classes to parse format-specifiers
3804 // or write formatted output.
3805 template<typename _CharT>
3808 using iterator = typename basic_format_parse_context<_CharT>::iterator;
3810 basic_format_parse_context<_CharT> _M_pc;
3813 _Scanner(basic_string_view<_CharT> __str, size_t __nargs = -1)
3814 : _M_pc(__str, __nargs)
3817 constexpr iterator begin() const noexcept { return _M_pc.begin(); }
3818 constexpr iterator end() const noexcept { return _M_pc.end(); }
3823 basic_string_view<_CharT> __fmt = _M_fmt_str();
3825 if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] == '}')
3827 _M_pc.advance_to(begin() + 1);
3828 _M_format_arg(_M_pc.next_arg_id());
3832 size_t __lbr = __fmt.find('{');
3833 size_t __rbr = __fmt.find('}');
3835 while (__fmt.size())
3837 auto __cmp = __lbr <=> __rbr;
3841 _M_pc.advance_to(end());
3846 if (__lbr + 1 == __fmt.size()
3847 || (__rbr == __fmt.npos && __fmt[__lbr + 1] != '{'))
3848 __format::__unmatched_left_brace_in_format_string();
3849 const bool __is_escape = __fmt[__lbr + 1] == '{';
3850 iterator __last = begin() + __lbr + int(__is_escape);
3851 _M_on_chars(__last);
3852 _M_pc.advance_to(__last + 1);
3853 __fmt = _M_fmt_str();
3856 if (__rbr != __fmt.npos)
3858 __lbr = __fmt.find('{');
3862 _M_on_replacement_field();
3863 __fmt = _M_fmt_str();
3864 __lbr = __fmt.find('{');
3865 __rbr = __fmt.find('}');
3870 if (++__rbr == __fmt.size() || __fmt[__rbr] != '}')
3871 __format::__unmatched_right_brace_in_format_string();
3872 iterator __last = begin() + __rbr;
3873 _M_on_chars(__last);
3874 _M_pc.advance_to(__last + 1);
3875 __fmt = _M_fmt_str();
3876 if (__lbr != __fmt.npos)
3878 __rbr = __fmt.find('}');
3883 constexpr basic_string_view<_CharT>
3884 _M_fmt_str() const noexcept
3885 { return {begin(), end()}; }
3887 constexpr virtual void _M_on_chars(iterator) { }
3889 constexpr void _M_on_replacement_field()
3891 auto __next = begin();
3895 __id = _M_pc.next_arg_id();
3896 else if (*__next == ':')
3898 __id = _M_pc.next_arg_id();
3899 _M_pc.advance_to(++__next);
3903 auto [__i, __ptr] = __format::__parse_arg_id(begin(), end());
3904 if (!__ptr || !(*__ptr == '}' || *__ptr == ':'))
3905 __format::__invalid_arg_id_in_format_string();
3906 _M_pc.check_arg_id(__id = __i);
3909 _M_pc.advance_to(++__ptr);
3912 _M_pc.advance_to(__ptr);
3914 _M_format_arg(__id);
3915 if (begin() == end() || *begin() != '}')
3916 __format::__unmatched_left_brace_in_format_string();
3917 _M_pc.advance_to(begin() + 1); // Move past '}'
3920 constexpr virtual void _M_format_arg(size_t __id) = 0;
3923 // Process a format string and format the arguments in the context.
3924 template<typename _Out, typename _CharT>
3925 class _Formatting_scanner : public _Scanner<_CharT>
3928 _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc,
3929 basic_string_view<_CharT> __str)
3930 : _Scanner<_CharT>(__str), _M_fc(__fc)
3934 basic_format_context<_Out, _CharT>& _M_fc;
3936 using iterator = typename _Scanner<_CharT>::iterator;
3939 _M_on_chars(iterator __last) override
3941 basic_string_view<_CharT> __str(this->begin(), __last);
3942 _M_fc.advance_to(__format::__write(_M_fc.out(), __str));
3946 _M_format_arg(size_t __id) override
3948 using _Context = basic_format_context<_Out, _CharT>;
3949 using handle = typename basic_format_arg<_Context>::handle;
3951 std::visit_format_arg([this](auto& __arg) {
3952 using _Type = remove_reference_t<decltype(__arg)>;
3953 using _Formatter = typename _Context::template formatter_type<_Type>;
3954 if constexpr (is_same_v<_Type, monostate>)
3955 __format::__invalid_arg_id_in_format_string();
3956 else if constexpr (is_same_v<_Type, handle>)
3957 __arg.format(this->_M_pc, this->_M_fc);
3958 else if constexpr (is_default_constructible_v<_Formatter>)
3961 this->_M_pc.advance_to(__f.parse(this->_M_pc));
3962 this->_M_fc.advance_to(__f.format(__arg, this->_M_fc));
3965 static_assert(__format::__formattable_with<_Type, _Context>);
3966 }, _M_fc.arg(__id));
3970 // Validate a format string for Args.
3971 template<typename _CharT, typename... _Args>
3972 class _Checking_scanner : public _Scanner<_CharT>
3975 (is_default_constructible_v<formatter<_Args, _CharT>> && ...),
3976 "std::formatter must be specialized for each type being formatted");
3980 _Checking_scanner(basic_string_view<_CharT> __str)
3981 : _Scanner<_CharT>(__str, sizeof...(_Args))
3986 _M_format_arg(size_t __id) override
3988 if constexpr (sizeof...(_Args) != 0)
3990 if (__id < sizeof...(_Args))
3992 _M_parse_format_spec<_Args...>(__id);
3996 __builtin_unreachable();
3999 template<typename _Tp, typename... _OtherArgs>
4001 _M_parse_format_spec(size_t __id)
4005 formatter<_Tp, _CharT> __f;
4006 this->_M_pc.advance_to(__f.parse(this->_M_pc));
4008 else if constexpr (sizeof...(_OtherArgs) != 0)
4009 _M_parse_format_spec<_OtherArgs...>(__id - 1);
4011 __builtin_unreachable();
4015 template<typename _Out, typename _CharT, typename _Context>
4017 __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
4018 const basic_format_args<_Context>& __args,
4019 const locale* __loc)
4021 _Iter_sink<_CharT, _Out> __sink(std::move(__out));
4022 _Sink_iter<_CharT> __sink_out;
4024 if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
4025 __sink_out = __out; // Already a sink iterator, safe to use post-move.
4027 __sink_out = __sink.out();
4029 if constexpr (is_same_v<_CharT, char>)
4030 if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] == '}')
4032 bool __done = false;
4033 std::visit_format_arg([&](auto& __arg) {
4034 using _Tp = remove_cvref_t<decltype(__arg)>;
4035 if constexpr (is_same_v<_Tp, bool>)
4037 size_t __len = 4 + !__arg;
4038 const char* __chars[] = { "false", "true" };
4039 if (auto __res = __sink_out._M_reserve(__len))
4041 __builtin_memcpy(__res.get(), __chars[__arg], __len);
4042 __res._M_bump(__len);
4046 else if constexpr (is_same_v<_Tp, char>)
4048 if (auto __res = __sink_out._M_reserve(1))
4050 *__res.get() = __arg;
4055 else if constexpr (is_integral_v<_Tp>)
4057 make_unsigned_t<_Tp> __uval;
4058 const bool __neg = __arg < 0;
4060 __uval = make_unsigned_t<_Tp>(~__arg) + 1u;
4063 const auto __n = __detail::__to_chars_len(__uval) + __neg;
4064 if (auto __res = __sink_out._M_reserve(__n))
4066 auto __ptr = __res.get();
4068 __detail::__to_chars_10_impl(__ptr + (int)__neg, __n,
4074 else if constexpr (is_convertible_v<_Tp, string_view>)
4076 string_view __sv = __arg;
4077 if (auto __res = __sink_out._M_reserve(__sv.size()))
4079 __builtin_memcpy(__res.get(), __sv.data(), __sv.size());
4080 __res._M_bump(__sv.size());
4088 if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
4091 return std::move(__sink)._M_finish().out;
4095 auto __ctx = __loc == nullptr
4096 ? _Context(__args, __sink_out)
4097 : _Context(__args, __sink_out, *__loc);
4098 _Formatting_scanner<_Sink_iter<_CharT>, _CharT> __scanner(__ctx, __fmt);
4099 __scanner._M_scan();
4101 if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
4104 return std::move(__sink)._M_finish().out;
4107 } // namespace __format
4110 template<typename _CharT, typename... _Args>
4111 template<typename _Tp>
4112 requires convertible_to<const _Tp&, basic_string_view<_CharT>>
4114 basic_format_string<_CharT, _Args...>::
4115 basic_format_string(const _Tp& __s)
4118 __format::_Checking_scanner<_CharT, remove_cvref_t<_Args>...>
4120 __scanner._M_scan();
4123 // [format.functions], formatting functions
4125 template<typename _Out> requires output_iterator<_Out, const char&>
4126 [[__gnu__::__always_inline__]]
4128 vformat_to(_Out __out, string_view __fmt, format_args __args)
4129 { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
4131 #ifdef _GLIBCXX_USE_WCHAR_T
4132 template<typename _Out> requires output_iterator<_Out, const wchar_t&>
4133 [[__gnu__::__always_inline__]]
4135 vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
4136 { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
4139 template<typename _Out> requires output_iterator<_Out, const char&>
4140 [[__gnu__::__always_inline__]]
4142 vformat_to(_Out __out, const locale& __loc, string_view __fmt,
4145 return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc);
4148 #ifdef _GLIBCXX_USE_WCHAR_T
4149 template<typename _Out> requires output_iterator<_Out, const wchar_t&>
4150 [[__gnu__::__always_inline__]]
4152 vformat_to(_Out __out, const locale& __loc, wstring_view __fmt,
4153 wformat_args __args)
4155 return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc);
4161 vformat(string_view __fmt, format_args __args)
4163 __format::_Str_sink<char> __buf;
4164 std::vformat_to(__buf.out(), __fmt, __args);
4165 return std::move(__buf).get();
4168 #ifdef _GLIBCXX_USE_WCHAR_T
4171 vformat(wstring_view __fmt, wformat_args __args)
4173 __format::_Str_sink<wchar_t> __buf;
4174 std::vformat_to(__buf.out(), __fmt, __args);
4175 return std::move(__buf).get();
4181 vformat(const locale& __loc, string_view __fmt, format_args __args)
4183 __format::_Str_sink<char> __buf;
4184 std::vformat_to(__buf.out(), __loc, __fmt, __args);
4185 return std::move(__buf).get();
4188 #ifdef _GLIBCXX_USE_WCHAR_T
4191 vformat(const locale& __loc, wstring_view __fmt, wformat_args __args)
4193 __format::_Str_sink<wchar_t> __buf;
4194 std::vformat_to(__buf.out(), __loc, __fmt, __args);
4195 return std::move(__buf).get();
4199 template<typename... _Args>
4202 format(format_string<_Args...> __fmt, _Args&&... __args)
4203 { return std::vformat(__fmt.get(), std::make_format_args(__args...)); }
4205 #ifdef _GLIBCXX_USE_WCHAR_T
4206 template<typename... _Args>
4209 format(wformat_string<_Args...> __fmt, _Args&&... __args)
4210 { return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); }
4213 template<typename... _Args>
4216 format(const locale& __loc, format_string<_Args...> __fmt,
4219 return std::vformat(__loc, __fmt.get(),
4220 std::make_format_args(__args...));
4223 #ifdef _GLIBCXX_USE_WCHAR_T
4224 template<typename... _Args>
4227 format(const locale& __loc, wformat_string<_Args...> __fmt,
4230 return std::vformat(__loc, __fmt.get(),
4231 std::make_wformat_args(__args...));
4235 template<typename _Out, typename... _Args>
4236 requires output_iterator<_Out, const char&>
4238 format_to(_Out __out, format_string<_Args...> __fmt, _Args&&... __args)
4240 return std::vformat_to(std::move(__out), __fmt.get(),
4241 std::make_format_args(std::forward<_Args>(__args)...));
4244 #ifdef _GLIBCXX_USE_WCHAR_T
4245 template<typename _Out, typename... _Args>
4246 requires output_iterator<_Out, const wchar_t&>
4248 format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&... __args)
4250 return std::vformat_to(std::move(__out), __fmt.get(),
4251 std::make_wformat_args(std::forward<_Args>(__args)...));
4255 template<typename _Out, typename... _Args>
4256 requires output_iterator<_Out, const char&>
4258 format_to(_Out __out, const locale& __loc, format_string<_Args...> __fmt,
4261 return std::vformat_to(std::move(__out), __loc, __fmt.get(),
4262 std::make_format_args(std::forward<_Args>(__args)...));
4265 #ifdef _GLIBCXX_USE_WCHAR_T
4266 template<typename _Out, typename... _Args>
4267 requires output_iterator<_Out, const wchar_t&>
4269 format_to(_Out __out, const locale& __loc, wformat_string<_Args...> __fmt,
4272 return std::vformat_to(std::move(__out), __loc, __fmt.get(),
4273 std::make_wformat_args(std::forward<_Args>(__args)...));
4277 template<typename _Out, typename... _Args>
4278 requires output_iterator<_Out, const char&>
4279 inline format_to_n_result<_Out>
4280 format_to_n(_Out __out, iter_difference_t<_Out> __n,
4281 format_string<_Args...> __fmt, _Args&&... __args)
4283 __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n);
4284 std::vformat_to(__sink.out(), __fmt.get(),
4285 std::make_format_args(__args...));
4286 return std::move(__sink)._M_finish();
4289 #ifdef _GLIBCXX_USE_WCHAR_T
4290 template<typename _Out, typename... _Args>
4291 requires output_iterator<_Out, const wchar_t&>
4292 inline format_to_n_result<_Out>
4293 format_to_n(_Out __out, iter_difference_t<_Out> __n,
4294 wformat_string<_Args...> __fmt, _Args&&... __args)
4296 __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n);
4297 std::vformat_to(__sink.out(), __fmt.get(),
4298 std::make_wformat_args(__args...));
4299 return std::move(__sink)._M_finish();
4303 template<typename _Out, typename... _Args>
4304 requires output_iterator<_Out, const char&>
4305 inline format_to_n_result<_Out>
4306 format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc,
4307 format_string<_Args...> __fmt, _Args&&... __args)
4309 __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n);
4310 std::vformat_to(__sink.out(), __loc, __fmt.get(),
4311 std::make_format_args(__args...));
4312 return std::move(__sink)._M_finish();
4315 #ifdef _GLIBCXX_USE_WCHAR_T
4316 template<typename _Out, typename... _Args>
4317 requires output_iterator<_Out, const wchar_t&>
4318 inline format_to_n_result<_Out>
4319 format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc,
4320 wformat_string<_Args...> __fmt, _Args&&... __args)
4322 __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n);
4323 std::vformat_to(__sink.out(), __loc, __fmt.get(),
4324 std::make_wformat_args(__args...));
4325 return std::move(__sink)._M_finish();
4329 /// @cond undocumented
4333 template<typename _CharT>
4334 class _Counting_sink final : public _Iter_sink<_CharT, _CharT*>
4337 _Counting_sink() : _Iter_sink<_CharT, _CharT*>(nullptr, 0) { }
4339 [[__gnu__::__always_inline__]]
4342 { return this->_M_count + this->_M_used().size(); }
4345 template<typename _CharT>
4346 class _Counting_sink : public _Buf_sink<_CharT>
4348 size_t _M_count = 0;
4351 _M_overflow() override
4353 if (!std::is_constant_evaluated())
4354 _M_count += this->_M_used().size();
4359 _Counting_sink() = default;
4361 [[__gnu__::__always_inline__]]
4365 _Counting_sink::_M_overflow();
4370 } // namespace __format
4373 template<typename... _Args>
4376 formatted_size(format_string<_Args...> __fmt, _Args&&... __args)
4378 __format::_Counting_sink<char> __buf;
4379 std::vformat_to(__buf.out(), __fmt.get(),
4380 std::make_format_args(std::forward<_Args>(__args)...));
4381 return __buf.count();
4384 #ifdef _GLIBCXX_USE_WCHAR_T
4385 template<typename... _Args>
4388 formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args)
4390 __format::_Counting_sink<wchar_t> __buf;
4391 std::vformat_to(__buf.out(), __fmt.get(),
4392 std::make_wformat_args(std::forward<_Args>(__args)...));
4393 return __buf.count();
4397 template<typename... _Args>
4400 formatted_size(const locale& __loc, format_string<_Args...> __fmt,
4403 __format::_Counting_sink<char> __buf;
4404 std::vformat_to(__buf.out(), __loc, __fmt.get(),
4405 std::make_format_args(std::forward<_Args>(__args)...));
4406 return __buf.count();
4409 #ifdef _GLIBCXX_USE_WCHAR_T
4410 template<typename... _Args>
4413 formatted_size(const locale& __loc, wformat_string<_Args...> __fmt,
4416 __format::_Counting_sink<wchar_t> __buf;
4417 std::vformat_to(__buf.out(), __loc, __fmt.get(),
4418 std::make_wformat_args(std::forward<_Args>(__args)...));
4419 return __buf.count();
4423 #if __cpp_lib_format_ranges
4424 // [format.range], formatting of ranges
4425 // [format.range.fmtkind], variable template format_kind
4426 enum class range_format {
4435 /// @cond undocumented
4436 template<typename _Rg>
4437 constexpr auto format_kind = not defined(format_kind<_Rg>);
4439 template<typename _Tp>
4440 consteval range_format
4443 using _Ref = ranges::range_reference_t<_Tp>;
4444 if constexpr (is_same_v<remove_cvref_t<_Ref>, _Tp>)
4445 return range_format::disabled;
4446 else if constexpr (requires { typename _Tp::key_type; })
4448 if constexpr (requires { typename _Tp::mapped_type; })
4450 using _Up = remove_cvref_t<_Ref>;
4451 if constexpr (__is_pair<_Up>)
4452 return range_format::map;
4453 else if constexpr (__is_specialization_of<_Up, tuple>)
4454 if constexpr (tuple_size_v<_Up> == 2)
4455 return range_format::map;
4457 return range_format::set;
4460 return range_format::sequence;
4464 /// A constant determining how a range should be formatted.
4465 template<ranges::input_range _Rg> requires same_as<_Rg, remove_cvref_t<_Rg>>
4466 constexpr range_format format_kind<_Rg> = __fmt_kind<_Rg>();
4468 // [format.range.formatter], class template range_formatter
4469 template<typename _Tp, typename _CharT = char>
4470 requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
4471 class range_formatter; // TODO
4473 /// @cond undocumented
4476 // [format.range.fmtdef], class template range-default-formatter
4477 template<range_format _Kind, ranges::input_range _Rg, typename _CharT>
4478 struct __range_default_formatter; // TODO
4479 } // namespace __format
4482 // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr],
4483 // specializations for maps, sets, and strings
4484 template<ranges::input_range _Rg, typename _CharT>
4485 requires (format_kind<_Rg> != range_format::disabled)
4486 && formattable<ranges::range_reference_t<_Rg>, _CharT>
4487 struct formatter<_Rg, _CharT>
4488 : __format::__range_default_formatter<format_kind<_Rg>, _Rg, _CharT>
4490 #endif // C++23 formatting ranges
4492 _GLIBCXX_END_NAMESPACE_VERSION
4494 #endif // __cpp_lib_format
4495 #endif // _GLIBCXX_FORMAT