libstdc++
format
Go to the documentation of this file.
1 // <format> Formatting -*- C++ -*-
2 
3 // Copyright The GNU Toolchain Authors.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file include/format
26  * This is a Standard C++ Library header.
27  */
28 
29 #ifndef _GLIBCXX_FORMAT
30 #define _GLIBCXX_FORMAT 1
31 
32 #ifdef _GLIBCXX_SYSHDR
33 #pragma GCC system_header
34 #endif
35 
36 #include <bits/requires_hosted.h> // for std::string
37 
38 #define __glibcxx_want_format
39 #define __glibcxx_want_format_ranges
40 #define __glibcxx_want_format_uchar
41 #include <bits/version.h>
42 
43 #ifdef __cpp_lib_format // C++ >= 20 && HOSTED
44 
45 #include <array>
46 #include <charconv>
47 #include <concepts>
48 #include <limits>
49 #include <locale>
50 #include <optional>
51 #include <span>
52 #include <string_view>
53 #include <string>
54 #include <bits/monostate.h>
55 #include <bits/formatfwd.h>
56 #include <bits/ranges_base.h> // input_range, range_reference_t
57 #include <bits/ranges_util.h> // subrange
58 #include <bits/ranges_algobase.h> // ranges::copy
59 #include <bits/stl_iterator.h> // back_insert_iterator
60 #include <bits/stl_pair.h> // __is_pair
61 #include <bits/unicode.h> // __is_scalar_value, _Utf_view, etc.
62 #include <bits/utility.h> // tuple_size_v
63 #include <ext/numeric_traits.h> // __int_traits
64 
65 #if !__has_builtin(__builtin_toupper)
66 # include <cctype>
67 #endif
68 
69 #pragma GCC diagnostic push
70 #pragma GCC diagnostic ignored "-Wpedantic" // __int128
71 #pragma GCC diagnostic ignored "-Wc++23-extensions" // bf16
72 
73 namespace std _GLIBCXX_VISIBILITY(default)
74 {
75 _GLIBCXX_BEGIN_NAMESPACE_VERSION
76 
77  // [format.fmt.string], class template basic_format_string
78  template<typename _CharT, typename... _Args> struct basic_format_string;
79 
80 /// @cond undocumented
81 namespace __format
82 {
83  // STATICALLY-WIDEN, see C++20 [time.general]
84  // It doesn't matter for format strings (which can only be char or wchar_t)
85  // but this returns the narrow string for anything that isn't wchar_t. This
86  // is done because const char* can be inserted into any ostream type, and
87  // will be widened at runtime if necessary.
88  template<typename _CharT>
89  consteval auto
90  _Widen(const char* __narrow, const wchar_t* __wide)
91  {
92  if constexpr (is_same_v<_CharT, wchar_t>)
93  return __wide;
94  else
95  return __narrow;
96  }
97 #define _GLIBCXX_WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
98 #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S)
99 
100  // Size for stack located buffer
101  template<typename _CharT>
102  constexpr size_t __stackbuf_size = 32 * sizeof(void*) / sizeof(_CharT);
103 
104  // Type-erased character sinks.
105  template<typename _CharT> class _Sink;
106  template<typename _CharT> class _Fixedbuf_sink;
107  template<typename _Seq> class _Seq_sink;
108 
109  template<typename _CharT, typename _Alloc = allocator<_CharT>>
110  using _Str_sink
111  = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>;
112 
113  // template<typename _CharT, typename _Alloc = allocator<_CharT>>
114  // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>;
115 
116  // Output iterator that writes to a type-erase character sink.
117  template<typename _CharT>
118  class _Sink_iter;
119 
120  // An unspecified output iterator type used in the `formattable` concept.
121  template<typename _CharT>
122  struct _Iter_for
123  { using type = back_insert_iterator<basic_string<_CharT>>; };
124 
125  template<typename _CharT>
126  using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>;
127 
128  template<typename _CharT>
129  struct _Runtime_format_string
130  {
131  [[__gnu__::__always_inline__]]
132  _Runtime_format_string(basic_string_view<_CharT> __s) noexcept
133  : _M_str(__s) { }
134 
135  _Runtime_format_string(const _Runtime_format_string&) = delete;
136  void operator=(const _Runtime_format_string&) = delete;
137 
138  private:
139  basic_string_view<_CharT> _M_str;
140 
141  template<typename, typename...> friend struct std::basic_format_string;
142  };
143 
144 } // namespace __format
145 /// @endcond
146 
147  using format_context = __format::__format_context<char>;
148 #ifdef _GLIBCXX_USE_WCHAR_T
149  using wformat_context = __format::__format_context<wchar_t>;
150 #endif
151 
152  // [format.args], class template basic_format_args
153  template<typename _Context> class basic_format_args;
154  using format_args = basic_format_args<format_context>;
155 #ifdef _GLIBCXX_USE_WCHAR_T
156  using wformat_args = basic_format_args<wformat_context>;
157 #endif
158 
159  // [format.arguments], arguments
160  // [format.arg], class template basic_format_arg
161  template<typename _Context>
162  class basic_format_arg;
163 
164  /** A compile-time checked format string for the specified argument types.
165  *
166  * @since C++23 but available as an extension in C++20.
167  */
168  template<typename _CharT, typename... _Args>
169  struct basic_format_string
170  {
171  template<typename _Tp>
172  requires convertible_to<const _Tp&, basic_string_view<_CharT>>
173  consteval
174  basic_format_string(const _Tp& __s);
175 
176  [[__gnu__::__always_inline__]]
177  basic_format_string(__format::_Runtime_format_string<_CharT> __s) noexcept
178  : _M_str(__s._M_str)
179  { }
180 
181  [[__gnu__::__always_inline__]]
182  constexpr basic_string_view<_CharT>
183  get() const noexcept
184  { return _M_str; }
185 
186  private:
187  basic_string_view<_CharT> _M_str;
188  };
189 
190  template<typename... _Args>
191  using format_string = basic_format_string<char, type_identity_t<_Args>...>;
192 
193 #ifdef _GLIBCXX_USE_WCHAR_T
194  template<typename... _Args>
195  using wformat_string
196  = basic_format_string<wchar_t, type_identity_t<_Args>...>;
197 #endif
198 
199 #if __cpp_lib_format >= 202311L // >= C++26
200  [[__gnu__::__always_inline__]]
201  inline __format::_Runtime_format_string<char>
202  runtime_format(string_view __fmt) noexcept
203  { return __fmt; }
204 
205 #ifdef _GLIBCXX_USE_WCHAR_T
206  [[__gnu__::__always_inline__]]
207  inline __format::_Runtime_format_string<wchar_t>
208  runtime_format(wstring_view __fmt) noexcept
209  { return __fmt; }
210 #endif
211 #endif // C++26
212 
213  // [format.formatter], formatter
214 
215  /// The primary template of std::formatter is disabled.
216  template<typename _Tp, typename _CharT>
217  struct formatter
218  {
219  formatter() = delete; // No std::formatter specialization for this type.
220  formatter(const formatter&) = delete;
221  formatter& operator=(const formatter&) = delete;
222  };
223 
224  // [format.error], class format_error
225  class format_error : public runtime_error
226  {
227  public:
228  explicit format_error(const string& __what) : runtime_error(__what) { }
229  explicit format_error(const char* __what) : runtime_error(__what) { }
230  };
231 
232  /// @cond undocumented
233  [[noreturn]]
234  inline void
235  __throw_format_error(const char* __what)
236  { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
237 
238 namespace __format
239 {
240  // XXX use named functions for each constexpr error?
241 
242  [[noreturn]]
243  inline void
244  __unmatched_left_brace_in_format_string()
245  { __throw_format_error("format error: unmatched '{' in format string"); }
246 
247  [[noreturn]]
248  inline void
249  __unmatched_right_brace_in_format_string()
250  { __throw_format_error("format error: unmatched '}' in format string"); }
251 
252  [[noreturn]]
253  inline void
254  __conflicting_indexing_in_format_string()
255  { __throw_format_error("format error: conflicting indexing style in format string"); }
256 
257  [[noreturn]]
258  inline void
259  __invalid_arg_id_in_format_string()
260  { __throw_format_error("format error: invalid arg-id in format string"); }
261 
262  [[noreturn]]
263  inline void
264  __failed_to_parse_format_spec()
265  { __throw_format_error("format error: failed to parse format-spec"); }
266 
267  template<typename _CharT> class _Scanner;
268 
269 } // namespace __format
270  /// @endcond
271 
272  // [format.parse.ctx], class template basic_format_parse_context
273  template<typename _CharT> class basic_format_parse_context;
274  using format_parse_context = basic_format_parse_context<char>;
275 #ifdef _GLIBCXX_USE_WCHAR_T
276  using wformat_parse_context = basic_format_parse_context<wchar_t>;
277 #endif
278 
279  template<typename _CharT>
280  class basic_format_parse_context
281  {
282  public:
283  using char_type = _CharT;
284  using const_iterator = typename basic_string_view<_CharT>::const_iterator;
285  using iterator = const_iterator;
286 
287  constexpr explicit
288  basic_format_parse_context(basic_string_view<_CharT> __fmt) noexcept
289  : _M_begin(__fmt.begin()), _M_end(__fmt.end())
290  { }
291 
292  basic_format_parse_context(const basic_format_parse_context&) = delete;
293  void operator=(const basic_format_parse_context&) = delete;
294 
295  constexpr const_iterator begin() const noexcept { return _M_begin; }
296  constexpr const_iterator end() const noexcept { return _M_end; }
297 
298  constexpr void
299  advance_to(const_iterator __it) noexcept
300  { _M_begin = __it; }
301 
302  constexpr size_t
303  next_arg_id()
304  {
305  if (_M_indexing == _Manual)
306  __format::__conflicting_indexing_in_format_string();
307  _M_indexing = _Auto;
308 
309  // _GLIBCXX_RESOLVE_LIB_DEFECTS
310  // 3825. Missing compile-time argument id check in next_arg_id
311  if (std::is_constant_evaluated())
312  if (_M_next_arg_id == _M_num_args)
313  __format::__invalid_arg_id_in_format_string();
314  return _M_next_arg_id++;
315  }
316 
317  constexpr void
318  check_arg_id(size_t __id)
319  {
320  if (_M_indexing == _Auto)
321  __format::__conflicting_indexing_in_format_string();
322  _M_indexing = _Manual;
323 
324  if (std::is_constant_evaluated())
325  if (__id >= _M_num_args)
326  __format::__invalid_arg_id_in_format_string();
327  }
328 
329 #if __cpp_lib_format >= 202305L
330  template<typename... _Ts>
331  constexpr void
332  check_dynamic_spec(size_t __id) noexcept
333  {
334  static_assert(__valid_types_for_check_dynamic_spec<_Ts...>(),
335  "template arguments for check_dynamic_spec<Ts...>(id) "
336  "must be unique and must be one of the allowed types");
337  if consteval {
338  __check_dynamic_spec<_Ts...>(__id);
339  }
340  }
341 
342  constexpr void
343  check_dynamic_spec_integral(size_t __id) noexcept
344  {
345  if consteval {
346  __check_dynamic_spec<int, unsigned, long long,
347  unsigned long long>(__id);
348  }
349  }
350 
351  constexpr void
352  check_dynamic_spec_string(size_t __id) noexcept
353  {
354  if consteval {
355  __check_dynamic_spec<const _CharT*, basic_string_view<_CharT>>(__id);
356  }
357  }
358 
359  private:
360  // True if _Tp occurs exactly once in _Ts.
361  template<typename _Tp, typename... _Ts>
362  static constexpr bool __once = (is_same_v<_Tp, _Ts> + ...) == 1;
363 
364  template<typename... _Ts>
365  consteval bool
366  __valid_types_for_check_dynamic_spec()
367  {
368  // _GLIBCXX_RESOLVE_LIB_DEFECTS
369  // 4142. check_dynamic_spec should require at least one type
370  if constexpr (sizeof...(_Ts) == 0)
371  return false;
372  else
373  {
374  // The types in Ts... are unique. Each type in Ts... is one of
375  // bool, char_type, int, unsigned int, long long int,
376  // unsigned long long int, float, double, long double,
377  // const char_type*, basic_string_view<char_type>, or const void*.
378  unsigned __sum
379  = __once<bool, _Ts...>
380  + __once<char_type, _Ts...>
381  + __once<int, _Ts...>
382  + __once<unsigned int, _Ts...>
383  + __once<long long int, _Ts...>
384  + __once<unsigned long long int, _Ts...>
385  + __once<float, _Ts...>
386  + __once<double, _Ts...>
387  + __once<long double, _Ts...>
388  + __once<const char_type*, _Ts...>
389  + __once<basic_string_view<char_type>, _Ts...>
390  + __once<const void*, _Ts...>;
391  return __sum == sizeof...(_Ts);
392  }
393  }
394 
395  template<typename... _Ts>
396  consteval void
397  __check_dynamic_spec(size_t __id) noexcept;
398 
399  // This must not be constexpr.
400  static void __invalid_dynamic_spec(const char*);
401 
402  friend __format::_Scanner<_CharT>;
403 #endif
404 
405  // This constructor should only be used by the implementation.
406  constexpr explicit
407  basic_format_parse_context(basic_string_view<_CharT> __fmt,
408  size_t __num_args) noexcept
409  : _M_begin(__fmt.begin()), _M_end(__fmt.end()), _M_num_args(__num_args)
410  { }
411 
412  private:
413  iterator _M_begin;
414  iterator _M_end;
415  enum _Indexing { _Unknown, _Manual, _Auto };
416  _Indexing _M_indexing = _Unknown;
417  size_t _M_next_arg_id = 0;
418  size_t _M_num_args = 0;
419  };
420 
421 /// @cond undocumented
422  template<typename _Tp, template<typename...> class _Class>
423  constexpr bool __is_specialization_of = false;
424  template<template<typename...> class _Class, typename... _Args>
425  constexpr bool __is_specialization_of<_Class<_Args...>, _Class> = true;
426 
427 namespace __format
428 {
429  // pre: first != last
430  template<typename _CharT>
431  constexpr pair<unsigned short, const _CharT*>
432  __parse_integer(const _CharT* __first, const _CharT* __last)
433  {
434  if (__first == __last)
435  __builtin_unreachable();
436 
437  if constexpr (is_same_v<_CharT, char>)
438  {
439  const auto __start = __first;
440  unsigned short __val = 0;
441  // N.B. std::from_chars is not constexpr in C++20.
442  if (__detail::__from_chars_alnum<true>(__first, __last, __val, 10)
443  && __first != __start) [[likely]]
444  return {__val, __first};
445  }
446  else
447  {
448  constexpr int __n = 32;
449  char __buf[__n]{};
450  for (int __i = 0; __i < __n && (__first + __i) != __last; ++__i)
451  __buf[__i] = __first[__i];
452  auto [__v, __ptr] = __format::__parse_integer(__buf, __buf + __n);
453  if (__ptr) [[likely]]
454  return {__v, __first + (__ptr - __buf)};
455  }
456  return {0, nullptr};
457  }
458 
459  template<typename _CharT>
460  constexpr pair<unsigned short, const _CharT*>
461  __parse_arg_id(const _CharT* __first, const _CharT* __last)
462  {
463  if (__first == __last)
464  __builtin_unreachable();
465 
466  if (*__first == '0')
467  return {0, __first + 1}; // No leading zeros allowed, so '0...' == 0
468 
469  if ('1' <= *__first && *__first <= '9')
470  {
471  const unsigned short __id = *__first - '0';
472  const auto __next = __first + 1;
473  // Optimize for most likely case of single digit arg-id.
474  if (__next == __last || !('0' <= *__next && *__next <= '9'))
475  return {__id, __next};
476  else
477  return __format::__parse_integer(__first, __last);
478  }
479  return {0, nullptr};
480  }
481 
482  enum _Pres_type {
483  _Pres_none = 0, // Default type (not valid for integer presentation types).
484  // Presentation types for integral types (including bool and charT).
485  _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c,
486  // Presentation types for floating-point types.
487  _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G,
488  _Pres_p = 0, _Pres_P, // For pointers.
489  _Pres_s = 0, // For strings, bool
490  _Pres_seq = 0, _Pres_str, // For ranges
491  _Pres_esc = 0xf, // For strings, charT and ranges
492  };
493 
494  enum _Align {
495  _Align_default,
496  _Align_left,
497  _Align_right,
498  _Align_centre,
499  };
500 
501  enum _Sign {
502  _Sign_default,
503  _Sign_plus,
504  _Sign_minus, // XXX does this need to be distinct from _Sign_default?
505  _Sign_space,
506  };
507 
508  enum _WidthPrec {
509  _WP_none, // No width/prec specified.
510  _WP_value, // Fixed width/prec specified.
511  _WP_from_arg // Use a formatting argument for width/prec.
512  };
513 
514  template<typename _Context>
515  size_t
516  __int_from_arg(const basic_format_arg<_Context>& __arg);
517 
518  constexpr bool __is_digit(char __c)
519  { return std::__detail::__from_chars_alnum_to_val(__c) < 10; }
520 
521  constexpr bool __is_xdigit(char __c)
522  { return std::__detail::__from_chars_alnum_to_val(__c) < 16; }
523 
524  template<typename _CharT>
525  struct _Spec
526  {
527  _Align _M_align : 2;
528  _Sign _M_sign : 2;
529  unsigned _M_alt : 1;
530  unsigned _M_localized : 1;
531  unsigned _M_zero_fill : 1;
532  _WidthPrec _M_width_kind : 2;
533  _WidthPrec _M_prec_kind : 2;
534  _Pres_type _M_type : 4;
535  unsigned _M_reserved : 1;
536  unsigned _M_reserved2 : 16;
537  unsigned short _M_width;
538  unsigned short _M_prec;
539  char32_t _M_fill = ' ';
540 
541  using iterator = typename basic_string_view<_CharT>::iterator;
542 
543  static constexpr _Align
544  _S_align(_CharT __c) noexcept
545  {
546  switch (__c)
547  {
548  case '<': return _Align_left;
549  case '>': return _Align_right;
550  case '^': return _Align_centre;
551  default: return _Align_default;
552  }
553  }
554 
555  // pre: __first != __last
556  constexpr iterator
557  _M_parse_fill_and_align(iterator __first, iterator __last) noexcept
558  { return _M_parse_fill_and_align(__first, __last, "{"); }
559 
560  // pre: __first != __last
561  constexpr iterator
562  _M_parse_fill_and_align(iterator __first, iterator __last, string_view __not_fill) noexcept
563  {
564  for (char __c : __not_fill)
565  if (*__first == static_cast<_CharT>(__c))
566  return __first;
567 
568  using namespace __unicode;
569  if constexpr (__literal_encoding_is_unicode<_CharT>())
570  {
571  // Accept any UCS scalar value as fill character.
572  _Utf32_view<ranges::subrange<iterator>> __uv({__first, __last});
573  if (!__uv.empty())
574  {
575  auto __beg = __uv.begin();
576  char32_t __c = *__beg++;
577  if (__is_scalar_value(__c))
578  if (auto __next = __beg.base(); __next != __last)
579  if (_Align __align = _S_align(*__next))
580  {
581  _M_fill = __c;
582  _M_align = __align;
583  return ++__next;
584  }
585  }
586  }
587  else if (__last - __first >= 2)
588  if (_Align __align = _S_align(__first[1]))
589  {
590  _M_fill = *__first;
591  _M_align = __align;
592  return __first + 2;
593  }
594 
595  if (_Align __align = _S_align(__first[0]))
596  {
597  _M_fill = ' ';
598  _M_align = __align;
599  return __first + 1;
600  }
601  return __first;
602  }
603 
604  static constexpr _Sign
605  _S_sign(_CharT __c) noexcept
606  {
607  switch (__c)
608  {
609  case '+': return _Sign_plus;
610  case '-': return _Sign_minus;
611  case ' ': return _Sign_space;
612  default: return _Sign_default;
613  }
614  }
615 
616  // pre: __first != __last
617  constexpr iterator
618  _M_parse_sign(iterator __first, iterator) noexcept
619  {
620  if (_Sign __sign = _S_sign(*__first))
621  {
622  _M_sign = __sign;
623  return __first + 1;
624  }
625  return __first;
626  }
627 
628  // pre: *__first is valid
629  constexpr iterator
630  _M_parse_alternate_form(iterator __first, iterator) noexcept
631  {
632  if (*__first == '#')
633  {
634  _M_alt = true;
635  ++__first;
636  }
637  return __first;
638  }
639 
640  // pre: __first != __last
641  constexpr iterator
642  _M_parse_zero_fill(iterator __first, iterator /* __last */) noexcept
643  {
644  if (*__first == '0')
645  {
646  _M_zero_fill = true;
647  ++__first;
648  }
649  return __first;
650  }
651 
652  // pre: __first != __last
653  static constexpr iterator
654  _S_parse_width_or_precision(iterator __first, iterator __last,
655  unsigned short& __val, bool& __arg_id,
656  basic_format_parse_context<_CharT>& __pc)
657  {
658  if (__format::__is_digit(*__first))
659  {
660  auto [__v, __ptr] = __format::__parse_integer(__first, __last);
661  if (!__ptr)
662  __throw_format_error("format error: invalid width or precision "
663  "in format-spec");
664  __first = __ptr;
665  __val = __v;
666  }
667  else if (*__first == '{')
668  {
669  __arg_id = true;
670  ++__first;
671  if (__first == __last)
672  __format::__unmatched_left_brace_in_format_string();
673  if (*__first == '}')
674  __val = __pc.next_arg_id();
675  else
676  {
677  auto [__v, __ptr] = __format::__parse_arg_id(__first, __last);
678  if (__ptr == nullptr || __ptr == __last || *__ptr != '}')
679  __format::__invalid_arg_id_in_format_string();
680  __first = __ptr;
681  __pc.check_arg_id(__v);
682  __val = __v;
683  }
684 #if __cpp_lib_format >= 202305L
685  __pc.check_dynamic_spec_integral(__val);
686 #endif
687  ++__first; // past the '}'
688  }
689  return __first;
690  }
691 
692  // pre: __first != __last
693  constexpr iterator
694  _M_parse_width(iterator __first, iterator __last,
695  basic_format_parse_context<_CharT>& __pc)
696  {
697  bool __arg_id = false;
698  if (*__first == '0')
699  __throw_format_error("format error: width must be non-zero in "
700  "format string");
701  auto __next = _S_parse_width_or_precision(__first, __last, _M_width,
702  __arg_id, __pc);
703  if (__next != __first)
704  _M_width_kind = __arg_id ? _WP_from_arg : _WP_value;
705  return __next;
706  }
707 
708  // pre: __first != __last
709  constexpr iterator
710  _M_parse_precision(iterator __first, iterator __last,
711  basic_format_parse_context<_CharT>& __pc)
712  {
713  if (__first[0] != '.')
714  return __first;
715 
716  iterator __next = ++__first;
717  bool __arg_id = false;
718  if (__next != __last)
719  __next = _S_parse_width_or_precision(__first, __last, _M_prec,
720  __arg_id, __pc);
721  if (__next == __first)
722  __throw_format_error("format error: missing precision after '.' in "
723  "format string");
724  _M_prec_kind = __arg_id ? _WP_from_arg : _WP_value;
725  return __next;
726  }
727 
728  // pre: __first != __last
729  constexpr iterator
730  _M_parse_locale(iterator __first, iterator /* __last */) noexcept
731  {
732  if (*__first == 'L')
733  {
734  _M_localized = true;
735  ++__first;
736  }
737  return __first;
738  }
739 
740  template<typename _Context>
741  size_t
742  _M_get_width(_Context& __ctx) const
743  {
744  size_t __width = 0;
745  if (_M_width_kind == _WP_value)
746  __width = _M_width;
747  else if (_M_width_kind == _WP_from_arg)
748  __width = __format::__int_from_arg(__ctx.arg(_M_width));
749  return __width;
750  }
751 
752  template<typename _Context>
753  size_t
754  _M_get_precision(_Context& __ctx) const
755  {
756  size_t __prec = -1;
757  if (_M_prec_kind == _WP_value)
758  __prec = _M_prec;
759  else if (_M_prec_kind == _WP_from_arg)
760  __prec = __format::__int_from_arg(__ctx.arg(_M_prec));
761  return __prec;
762  }
763  };
764 
765  template<typename _Int>
766  inline char*
767  __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept
768  {
769  if (__i < 0)
770  *__dest = '-';
771  else if (__sign == _Sign_plus)
772  *__dest = '+';
773  else if (__sign == _Sign_space)
774  *__dest = ' ';
775  else
776  ++__dest;
777  return __dest;
778  }
779 
780  // Write STR to OUT (and do so efficiently if OUT is a _Sink_iter).
781  template<typename _Out, typename _CharT>
782  requires output_iterator<_Out, const _CharT&>
783  inline _Out
784  __write(_Out __out, basic_string_view<_CharT> __str)
785  {
786  if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
787  {
788  if (__str.size())
789  __out = __str;
790  }
791  else
792  for (_CharT __c : __str)
793  *__out++ = __c;
794  return __out;
795  }
796 
797  // Write STR to OUT with NFILL copies of FILL_CHAR specified by ALIGN.
798  // pre: __align != _Align_default
799  template<typename _Out, typename _CharT>
800  _Out
801  __write_padded(_Out __out, basic_string_view<_CharT> __str,
802  _Align __align, size_t __nfill, char32_t __fill_char)
803  {
804  const size_t __buflen = 0x20;
805  _CharT __padding_chars[__buflen];
806  __padding_chars[0] = _CharT();
807  basic_string_view<_CharT> __padding{__padding_chars, __buflen};
808 
809  auto __pad = [&__padding] (size_t __n, _Out& __o) {
810  if (__n == 0)
811  return;
812  while (__n > __padding.size())
813  {
814  __o = __format::__write(std::move(__o), __padding);
815  __n -= __padding.size();
816  }
817  if (__n != 0)
818  __o = __format::__write(std::move(__o), __padding.substr(0, __n));
819  };
820 
821  size_t __l, __r, __max;
822  if (__align == _Align_centre)
823  {
824  __l = __nfill / 2;
825  __r = __l + (__nfill & 1);
826  __max = __r;
827  }
828  else if (__align == _Align_right)
829  {
830  __l = __nfill;
831  __r = 0;
832  __max = __l;
833  }
834  else
835  {
836  __l = 0;
837  __r = __nfill;
838  __max = __r;
839  }
840 
841  using namespace __unicode;
842  if constexpr (__literal_encoding_is_unicode<_CharT>())
843  if (!__is_single_code_unit<_CharT>(__fill_char)) [[unlikely]]
844  {
845  // Encode fill char as multiple code units of type _CharT.
846  const char32_t __arr[1]{ __fill_char };
847  _Utf_view<_CharT, const char32_t(&)[1]> __v(__arr);
848  basic_string<_CharT> __padstr(__v.begin(), __v.end());
849  __padding = __padstr;
850  while (__l-- > 0)
851  __out = __format::__write(std::move(__out), __padding);
852  __out = __format::__write(std::move(__out), __str);
853  while (__r-- > 0)
854  __out = __format::__write(std::move(__out), __padding);
855  return __out;
856  }
857 
858  if (__max < __buflen)
859  __padding.remove_suffix(__buflen - __max);
860  else
861  __max = __buflen;
862 
863  char_traits<_CharT>::assign(__padding_chars, __max, __fill_char);
864  __pad(__l, __out);
865  __out = __format::__write(std::move(__out), __str);
866  __pad(__r, __out);
867 
868  return __out;
869  }
870 
871  // Write STR to OUT, with alignment and padding as determined by SPEC.
872  // pre: __spec._M_align != _Align_default || __align != _Align_default
873  template<typename _CharT, typename _Out>
874  _Out
875  __write_padded_as_spec(basic_string_view<type_identity_t<_CharT>> __str,
876  size_t __estimated_width,
877  basic_format_context<_Out, _CharT>& __fc,
878  const _Spec<_CharT>& __spec,
879  _Align __align = _Align_left)
880  {
881  size_t __width = __spec._M_get_width(__fc);
882 
883  if (__width <= __estimated_width)
884  return __format::__write(__fc.out(), __str);
885 
886  const size_t __nfill = __width - __estimated_width;
887 
888  if (__spec._M_align)
889  __align = __spec._M_align;
890 
891  return __format::__write_padded(__fc.out(), __str, __align, __nfill,
892  __spec._M_fill);
893  }
894 
895  // Values are indices into _Escapes::all.
896  enum class _Term_char : unsigned char {
897  _Tc_quote = 12,
898  _Tc_apos = 15
899  };
900 
901  template<typename _CharT>
902  struct _Escapes
903  {
904  using _Str_view = basic_string_view<_CharT>;
905 
906  static consteval
907  _Str_view _S_all()
908  { return _GLIBCXX_WIDEN("\t\\t\n\\n\r\\r\\\\\\\"\\\"'\\'\\u\\x"); }
909 
910  static constexpr
911  _CharT _S_term(_Term_char __term)
912  { return _S_all()[static_cast<unsigned char>(__term)]; }
913 
914  static consteval
915  _Str_view _S_tab()
916  { return _S_all().substr(0, 3); }
917 
918  static consteval
919  _Str_view _S_newline()
920  { return _S_all().substr(3, 3); }
921 
922  static consteval
923  _Str_view _S_return()
924  { return _S_all().substr(6, 3); }
925 
926  static consteval
927  _Str_view _S_bslash()
928  { return _S_all().substr(9, 3); }
929 
930  static consteval
931  _Str_view _S_quote()
932  { return _S_all().substr(12, 3); }
933 
934  static consteval
935  _Str_view _S_apos()
936  { return _S_all().substr(15, 3); }
937 
938  static consteval
939  _Str_view _S_u()
940  { return _S_all().substr(18, 2); }
941 
942  static consteval
943  _Str_view _S_x()
944  { return _S_all().substr(20, 2); }
945  };
946 
947  template<typename _CharT>
948  struct _Separators
949  {
950  using _Str_view = basic_string_view<_CharT>;
951 
952  static consteval
953  _Str_view _S_all()
954  { return _GLIBCXX_WIDEN("[]{}(), : "); }
955 
956  static consteval
957  _Str_view _S_squares()
958  { return _S_all().substr(0, 2); }
959 
960  static consteval
961  _Str_view _S_braces()
962  { return _S_all().substr(2, 2); }
963 
964  static consteval
965  _Str_view _S_parens()
966  { return _S_all().substr(4, 2); }
967 
968  static consteval
969  _Str_view _S_comma()
970  { return _S_all().substr(6, 2); }
971 
972  static consteval
973  _Str_view _S_colon()
974  { return _S_all().substr(8, 2); }
975  };
976 
977  template<typename _CharT>
978  constexpr bool __should_escape_ascii(_CharT __c, _Term_char __term)
979  {
980  using _Esc = _Escapes<_CharT>;
981  switch (__c)
982  {
983  case _Esc::_S_tab()[0]:
984  case _Esc::_S_newline()[0]:
985  case _Esc::_S_return()[0]:
986  case _Esc::_S_bslash()[0]:
987  return true;
988  case _Esc::_S_quote()[0]:
989  return __term == _Term_char::_Tc_quote;
990  case _Esc::_S_apos()[0]:
991  return __term == _Term_char::_Tc_apos;
992  default:
993  return (__c >= 0 && __c < 0x20) || __c == 0x7f;
994  };
995  }
996 
997  // @pre __c <= 0x10FFFF
998  constexpr bool __should_escape_unicode(char32_t __c, bool __prev_esc)
999  {
1000  if (__unicode::__should_escape_category(__c))
1001  return __c != U' ';
1002  if (!__prev_esc)
1003  return false;
1004  return __unicode::__grapheme_cluster_break_property(__c)
1005  == __unicode::_Gcb_property::_Gcb_Extend;
1006  }
1007 
1008  using uint_least32_t = __UINT_LEAST32_TYPE__;
1009  template<typename _Out, typename _CharT>
1010  _Out
1011  __write_escape_seq(_Out __out, uint_least32_t __val,
1012  basic_string_view<_CharT> __prefix)
1013  {
1014  using _Str_view = basic_string_view<_CharT>;
1015  constexpr size_t __max = 8;
1016  char __buf[__max];
1017  const string_view __narrow(
1018  __buf,
1019  std::__to_chars_i<uint_least32_t>(__buf, __buf + __max, __val, 16).ptr);
1020 
1021  __out = __format::__write(__out, __prefix);
1022  *__out = _Separators<_CharT>::_S_braces()[0];
1023  ++__out;
1024  if constexpr (is_same_v<char, _CharT>)
1025  __out = __format::__write(__out, __narrow);
1026 #ifdef _GLIBCXX_USE_WCHAR_T
1027  else
1028  {
1029  _CharT __wbuf[__max];
1030  const size_t __n = __narrow.size();
1031  std::__to_wstring_numeric(__narrow.data(), __n, __wbuf);
1032  __out = __format::__write(__out, _Str_view(__wbuf, __n));
1033  }
1034 #endif
1035  *__out = _Separators<_CharT>::_S_braces()[1];
1036  return ++__out;
1037  }
1038 
1039  template<typename _Out, typename _CharT>
1040  _Out
1041  __write_escaped_char(_Out __out, _CharT __c)
1042  {
1043  using _UChar = make_unsigned_t<_CharT>;
1044  using _Esc = _Escapes<_CharT>;
1045  switch (__c)
1046  {
1047  case _Esc::_S_tab()[0]:
1048  return __format::__write(__out, _Esc::_S_tab().substr(1, 2));
1049  case _Esc::_S_newline()[0]:
1050  return __format::__write(__out, _Esc::_S_newline().substr(1, 2));
1051  case _Esc::_S_return()[0]:
1052  return __format::__write(__out, _Esc::_S_return().substr(1, 2));
1053  case _Esc::_S_bslash()[0]:
1054  return __format::__write(__out, _Esc::_S_bslash().substr(1, 2));
1055  case _Esc::_S_quote()[0]:
1056  return __format::__write(__out, _Esc::_S_quote().substr(1, 2));
1057  case _Esc::_S_apos()[0]:
1058  return __format::__write(__out, _Esc::_S_apos().substr(1, 2));
1059  default:
1060  return __format::__write_escape_seq(__out,
1061  static_cast<_UChar>(__c),
1062  _Esc::_S_u());
1063  }
1064  }
1065 
1066  template<typename _CharT, typename _Out>
1067  _Out
1068  __write_escaped_ascii(_Out __out,
1069  basic_string_view<_CharT> __str,
1070  _Term_char __term)
1071  {
1072  using _Str_view = basic_string_view<_CharT>;
1073  auto __first = __str.begin();
1074  auto const __last = __str.end();
1075  while (__first != __last)
1076  {
1077  auto __print = __first;
1078  // assume anything outside ASCII is printable
1079  while (__print != __last
1080  && !__format::__should_escape_ascii(*__print, __term))
1081  ++__print;
1082 
1083  if (__print != __first)
1084  __out = __format::__write(__out, _Str_view(__first, __print));
1085 
1086  if (__print == __last)
1087  return __out;
1088 
1089  __first = __print;
1090  __out = __format::__write_escaped_char(__out, *__first);
1091  ++__first;
1092  }
1093  return __out;
1094  }
1095 
1096  template<typename _CharT, typename _Out>
1097  _Out
1098  __write_escaped_unicode(_Out __out,
1099  basic_string_view<_CharT> __str,
1100  _Term_char __term)
1101  {
1102  using _Str_view = basic_string_view<_CharT>;
1103  using _UChar = make_unsigned_t<_CharT>;
1104  using _Esc = _Escapes<_CharT>;
1105 
1106  static constexpr char32_t __replace = U'\uFFFD';
1107  static constexpr _Str_view __replace_rep = []
1108  {
1109  // N.B. "\uFFFD" is ill-formed if encoding is not unicode.
1110  if constexpr (is_same_v<char, _CharT>)
1111  return "\xEF\xBF\xBD";
1112  else
1113  return L"\xFFFD";
1114  }();
1115 
1116  __unicode::_Utf_view<char32_t, _Str_view> __v(std::move(__str));
1117  auto __first = __v.begin();
1118  auto const __last = __v.end();
1119 
1120  bool __prev_esc = true;
1121  while (__first != __last)
1122  {
1123  bool __esc_ascii = false;
1124  bool __esc_unicode = false;
1125  bool __esc_replace = false;
1126  auto __should_escape = [&](auto const& __it)
1127  {
1128  if (*__it <= 0x7f)
1129  return __esc_ascii
1130  = __format::__should_escape_ascii(*__it.base(), __term);
1131  if (__format::__should_escape_unicode(*__it, __prev_esc))
1132  return __esc_unicode = true;
1133  if (*__it == __replace)
1134  {
1135  _Str_view __units(__it.base(), __it._M_units());
1136  return __esc_replace = (__units != __replace_rep);
1137  }
1138  return false;
1139  };
1140 
1141  auto __print = __first;
1142  while (__print != __last && !__should_escape(__print))
1143  {
1144  __prev_esc = false;
1145  ++__print;
1146  }
1147 
1148  if (__print != __first)
1149  __out = __format::__write(__out, _Str_view(__first.base(), __print.base()));
1150 
1151  if (__print == __last)
1152  return __out;
1153 
1154  __first = __print;
1155  if (__esc_ascii)
1156  __out = __format::__write_escaped_char(__out, *__first.base());
1157  else if (__esc_unicode)
1158  __out = __format::__write_escape_seq(__out, *__first, _Esc::_S_u());
1159  else // __esc_replace
1160  for (_CharT __c : _Str_view(__first.base(), __first._M_units()))
1161  __out = __format::__write_escape_seq(__out,
1162  static_cast<_UChar>(__c),
1163  _Esc::_S_x());
1164  __prev_esc = true;
1165  ++__first;
1166 
1167  }
1168  return __out;
1169  }
1170 
1171  template<typename _CharT, typename _Out>
1172  _Out
1173  __write_escaped(_Out __out, basic_string_view<_CharT> __str, _Term_char __term)
1174  {
1175  *__out = _Escapes<_CharT>::_S_term(__term);
1176  ++__out;
1177 
1178  if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
1179  __out = __format::__write_escaped_unicode(__out, __str, __term);
1180  else if constexpr (is_same_v<char, _CharT>
1181  && __unicode::__literal_encoding_is_extended_ascii())
1182  __out = __format::__write_escaped_ascii(__out, __str, __term);
1183  else
1184  // TODO Handle non-ascii extended encoding
1185  __out = __format::__write_escaped_ascii(__out, __str, __term);
1186 
1187  *__out = _Escapes<_CharT>::_S_term(__term);
1188  return ++__out;
1189  }
1190 
1191  // A lightweight optional<locale>.
1192  struct _Optional_locale
1193  {
1194  [[__gnu__::__always_inline__]]
1195  _Optional_locale() : _M_dummy(), _M_hasval(false) { }
1196 
1197  _Optional_locale(const locale& __loc) noexcept
1198  : _M_loc(__loc), _M_hasval(true)
1199  { }
1200 
1201  _Optional_locale(const _Optional_locale& __l) noexcept
1202  : _M_dummy(), _M_hasval(__l._M_hasval)
1203  {
1204  if (_M_hasval)
1205  std::construct_at(&_M_loc, __l._M_loc);
1206  }
1207 
1208  _Optional_locale&
1209  operator=(const _Optional_locale& __l) noexcept
1210  {
1211  if (_M_hasval)
1212  {
1213  if (__l._M_hasval)
1214  _M_loc = __l._M_loc;
1215  else
1216  {
1217  _M_loc.~locale();
1218  _M_hasval = false;
1219  }
1220  }
1221  else if (__l._M_hasval)
1222  {
1223  std::construct_at(&_M_loc, __l._M_loc);
1224  _M_hasval = true;
1225  }
1226  return *this;
1227  }
1228 
1229  ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); }
1230 
1231  _Optional_locale&
1232  operator=(locale&& __loc) noexcept
1233  {
1234  if (_M_hasval)
1235  _M_loc = std::move(__loc);
1236  else
1237  {
1238  std::construct_at(&_M_loc, std::move(__loc));
1239  _M_hasval = true;
1240  }
1241  return *this;
1242  }
1243 
1244  const locale&
1245  value() noexcept
1246  {
1247  if (!_M_hasval)
1248  {
1249  std::construct_at(&_M_loc);
1250  _M_hasval = true;
1251  }
1252  return _M_loc;
1253  }
1254 
1255  bool has_value() const noexcept { return _M_hasval; }
1256 
1257  union {
1258  char _M_dummy = '\0';
1259  std::locale _M_loc;
1260  };
1261  bool _M_hasval = false;
1262  };
1263 
1264  template<__char _CharT>
1265  struct __formatter_str
1266  {
1267  __formatter_str() = default;
1268 
1269  constexpr
1270  __formatter_str(_Spec<_CharT> __spec) noexcept
1271  : _M_spec(__spec)
1272  { }
1273 
1274  constexpr typename basic_format_parse_context<_CharT>::iterator
1275  parse(basic_format_parse_context<_CharT>& __pc)
1276  {
1277  auto __first = __pc.begin();
1278  const auto __last = __pc.end();
1279  _Spec<_CharT> __spec{};
1280 
1281  auto __finalize = [this, &__spec] {
1282  _M_spec = __spec;
1283  };
1284 
1285  auto __finished = [&] {
1286  if (__first == __last || *__first == '}')
1287  {
1288  __finalize();
1289  return true;
1290  }
1291  return false;
1292  };
1293 
1294  if (__finished())
1295  return __first;
1296 
1297  __first = __spec._M_parse_fill_and_align(__first, __last);
1298  if (__finished())
1299  return __first;
1300 
1301  __first = __spec._M_parse_width(__first, __last, __pc);
1302  if (__finished())
1303  return __first;
1304 
1305  __first = __spec._M_parse_precision(__first, __last, __pc);
1306  if (__finished())
1307  return __first;
1308 
1309  if (*__first == 's')
1310  ++__first;
1311 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
1312  else if (*__first == '?')
1313  {
1314  __spec._M_type = _Pres_esc;
1315  ++__first;
1316  }
1317 #endif
1318 
1319  if (__finished())
1320  return __first;
1321 
1322  __format::__failed_to_parse_format_spec();
1323  }
1324 
1325  template<typename _Out>
1326  _Out
1327  format(basic_string_view<_CharT> __s,
1328  basic_format_context<_Out, _CharT>& __fc) const
1329  {
1330  constexpr auto __term = __format::_Term_char::_Tc_quote;
1331  const auto __write_direct = [&]
1332  {
1333  if (_M_spec._M_type == _Pres_esc)
1334  return __format::__write_escaped(__fc.out(), __s, __term);
1335  else
1336  return __format::__write(__fc.out(), __s);
1337  };
1338 
1339  if (_M_spec._M_width_kind == _WP_none
1340  && _M_spec._M_prec_kind == _WP_none)
1341  return __write_direct();
1342 
1343  const size_t __prec =
1344  _M_spec._M_prec_kind != _WP_none
1345  ? _M_spec._M_get_precision(__fc)
1346  : basic_string_view<_CharT>::npos;
1347 
1348  const size_t __estimated_width = _S_trunc(__s, __prec);
1349  // N.B. Escaping only increases width
1350  if (_M_spec._M_get_width(__fc) <= __estimated_width
1351  && _M_spec._M_prec_kind == _WP_none)
1352  return __write_direct();
1353 
1354  if (_M_spec._M_type != _Pres_esc)
1355  return __format::__write_padded_as_spec(__s, __estimated_width,
1356  __fc, _M_spec);
1357 
1358  __format::_Str_sink<_CharT> __sink;
1359  __format::__write_escaped(__sink.out(), __s, __term);
1360  basic_string_view<_CharT> __escaped(__sink.view().data(),
1361  __sink.view().size());
1362  const size_t __escaped_width = _S_trunc(__escaped, __prec);
1363  // N.B. [tab:format.type.string] defines '?' as
1364  // Copies the escaped string ([format.string.escaped]) to the output,
1365  // so precision seem to appy to escaped string.
1366  return __format::__write_padded_as_spec(__escaped, __escaped_width,
1367  __fc, _M_spec);
1368  }
1369 
1370 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
1371  template<ranges::input_range _Rg, typename _Out>
1372  requires same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _CharT>
1373  typename basic_format_context<_Out, _CharT>::iterator
1374  _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
1375  {
1376  using _String = basic_string<_CharT>;
1377  using _String_view = basic_string_view<_CharT>;
1378  if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
1379  {
1380  const size_t __n(ranges::distance(__rg));
1381  if constexpr (ranges::contiguous_range<_Rg>)
1382  return format(_String_view(ranges::data(__rg), __n), __fc);
1383  else if (__n <= __format::__stackbuf_size<_CharT>)
1384  {
1385  _CharT __buf[__format::__stackbuf_size<_CharT>];
1386  ranges::copy(__rg, __buf);
1387  return format(_String_view(__buf, __n), __fc);
1388  }
1389  else if constexpr (ranges::sized_range<_Rg>)
1390  return format(_String(from_range, __rg), __fc);
1391  else if constexpr (ranges::random_access_range<_Rg>)
1392  {
1393  ranges::iterator_t<_Rg> __first = ranges::begin(__rg);
1394  ranges::subrange __sub(__first, __first + __n);
1395  return format(_String(from_range, __sub), __fc);
1396  }
1397  else
1398  {
1399  // N.B. preserve the computed size
1400  ranges::subrange __sub(__rg, __n);
1401  return format(_String(from_range, __sub), __fc);
1402  }
1403  }
1404  else
1405  return format(_String(from_range, __rg), __fc);
1406  }
1407 
1408  constexpr void
1409  set_debug_format() noexcept
1410  { _M_spec._M_type = _Pres_esc; }
1411 #endif
1412 
1413  private:
1414  static size_t
1415  _S_trunc(basic_string_view<_CharT>& __s, size_t __prec)
1416  {
1417  if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
1418  {
1419  if (__prec != basic_string_view<_CharT>::npos)
1420  return __unicode::__truncate(__s, __prec);
1421  else
1422  return __unicode::__field_width(__s);
1423  }
1424  else
1425  {
1426  __s = __s.substr(0, __prec);
1427  return __s.size();
1428  }
1429  }
1430 
1431  _Spec<_CharT> _M_spec{};
1432  };
1433 
1434  template<__char _CharT>
1435  struct __formatter_int
1436  {
1437  // If no presentation type is specified, meaning of "none" depends
1438  // whether we are formatting an integer or a char or a bool.
1439  static constexpr _Pres_type _AsInteger = _Pres_d;
1440  static constexpr _Pres_type _AsBool = _Pres_s;
1441  static constexpr _Pres_type _AsChar = _Pres_c;
1442 
1443  constexpr typename basic_format_parse_context<_CharT>::iterator
1444  _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type)
1445  {
1446  _Spec<_CharT> __spec{};
1447  __spec._M_type = __type;
1448 
1449  const auto __last = __pc.end();
1450  auto __first = __pc.begin();
1451 
1452  auto __finalize = [this, &__spec] {
1453  _M_spec = __spec;
1454  };
1455 
1456  auto __finished = [&] {
1457  if (__first == __last || *__first == '}')
1458  {
1459  __finalize();
1460  return true;
1461  }
1462  return false;
1463  };
1464 
1465  if (__finished())
1466  return __first;
1467 
1468  __first = __spec._M_parse_fill_and_align(__first, __last);
1469  if (__finished())
1470  return __first;
1471 
1472  __first = __spec._M_parse_sign(__first, __last);
1473  if (__finished())
1474  return __first;
1475 
1476  __first = __spec._M_parse_alternate_form(__first, __last);
1477  if (__finished())
1478  return __first;
1479 
1480  __first = __spec._M_parse_zero_fill(__first, __last);
1481  if (__finished())
1482  return __first;
1483 
1484  __first = __spec._M_parse_width(__first, __last, __pc);
1485  if (__finished())
1486  return __first;
1487 
1488  __first = __spec._M_parse_locale(__first, __last);
1489  if (__finished())
1490  return __first;
1491 
1492  switch (*__first)
1493  {
1494  case 'b':
1495  __spec._M_type = _Pres_b;
1496  ++__first;
1497  break;
1498  case 'B':
1499  __spec._M_type = _Pres_B;
1500  ++__first;
1501  break;
1502  case 'c':
1503  // _GLIBCXX_RESOLVE_LIB_DEFECTS
1504  // 3586. format should not print bool with 'c'
1505  if (__type != _AsBool)
1506  {
1507  __spec._M_type = _Pres_c;
1508  ++__first;
1509  }
1510  break;
1511  case 'd':
1512  __spec._M_type = _Pres_d;
1513  ++__first;
1514  break;
1515  case 'o':
1516  __spec._M_type = _Pres_o;
1517  ++__first;
1518  break;
1519  case 'x':
1520  __spec._M_type = _Pres_x;
1521  ++__first;
1522  break;
1523  case 'X':
1524  __spec._M_type = _Pres_X;
1525  ++__first;
1526  break;
1527  case 's':
1528  if (__type == _AsBool)
1529  {
1530  __spec._M_type = _Pres_s; // same value (and meaning) as "none"
1531  ++__first;
1532  }
1533  break;
1534 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
1535  case '?':
1536  if (__type == _AsChar)
1537  {
1538  __spec._M_type = _Pres_esc;
1539  ++__first;
1540  }
1541 #endif
1542  break;
1543  }
1544 
1545  if (__finished())
1546  return __first;
1547 
1548  __format::__failed_to_parse_format_spec();
1549  }
1550 
1551  template<typename _Tp>
1552  constexpr typename basic_format_parse_context<_CharT>::iterator
1553  _M_parse(basic_format_parse_context<_CharT>& __pc)
1554  {
1555  if constexpr (is_same_v<_Tp, bool>)
1556  {
1557  auto __end = _M_do_parse(__pc, _AsBool);
1558  if (_M_spec._M_type == _Pres_s)
1559  if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill)
1560  __throw_format_error("format error: format-spec contains "
1561  "invalid formatting options for "
1562  "'bool'");
1563  return __end;
1564  }
1565  else if constexpr (__char<_Tp>)
1566  {
1567  auto __end = _M_do_parse(__pc, _AsChar);
1568  if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc)
1569  if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill
1570  /* XXX should be invalid? || _M_spec._M_localized */)
1571  __throw_format_error("format error: format-spec contains "
1572  "invalid formatting options for "
1573  "'charT'");
1574  return __end;
1575  }
1576  else
1577  return _M_do_parse(__pc, _AsInteger);
1578  }
1579 
1580  template<typename _Int, typename _Out>
1581  typename basic_format_context<_Out, _CharT>::iterator
1582  format(_Int __i, basic_format_context<_Out, _CharT>& __fc) const
1583  {
1584  if (_M_spec._M_type == _Pres_c)
1585  return _M_format_character(_S_to_character(__i), __fc);
1586 
1587  char __buf[sizeof(_Int) * __CHAR_BIT__ + 3];
1588  to_chars_result __res{};
1589 
1590  string_view __base_prefix;
1591  make_unsigned_t<_Int> __u;
1592  if (__i < 0)
1593  __u = -static_cast<make_unsigned_t<_Int>>(__i);
1594  else
1595  __u = __i;
1596 
1597  char* __start = __buf + 3;
1598  char* const __end = __buf + sizeof(__buf);
1599  char* const __start_digits = __start;
1600 
1601  switch (_M_spec._M_type)
1602  {
1603  case _Pres_b:
1604  case _Pres_B:
1605  __base_prefix = _M_spec._M_type == _Pres_b ? "0b" : "0B";
1606  __res = to_chars(__start, __end, __u, 2);
1607  break;
1608 #if 0
1609  case _Pres_c:
1610  return _M_format_character(_S_to_character(__i), __fc);
1611 #endif
1612  case _Pres_none:
1613  // Should not reach here with _Pres_none for bool or charT, so:
1614  [[fallthrough]];
1615  case _Pres_d:
1616  __res = to_chars(__start, __end, __u, 10);
1617  break;
1618  case _Pres_o:
1619  if (__i != 0)
1620  __base_prefix = "0";
1621  __res = to_chars(__start, __end, __u, 8);
1622  break;
1623  case _Pres_x:
1624  case _Pres_X:
1625  __base_prefix = _M_spec._M_type == _Pres_x ? "0x" : "0X";
1626  __res = to_chars(__start, __end, __u, 16);
1627  if (_M_spec._M_type == _Pres_X)
1628  for (auto __p = __start; __p != __res.ptr; ++__p)
1629 #if __has_builtin(__builtin_toupper)
1630  *__p = __builtin_toupper(*__p);
1631 #else
1632  *__p = std::toupper(*__p);
1633 #endif
1634  break;
1635  default:
1636  __builtin_unreachable();
1637  }
1638 
1639  if (_M_spec._M_alt && __base_prefix.size())
1640  {
1641  __start -= __base_prefix.size();
1642  __builtin_memcpy(__start, __base_prefix.data(),
1643  __base_prefix.size());
1644  }
1645  __start = __format::__put_sign(__i, _M_spec._M_sign, __start - 1);
1646 
1647  return _M_format_int(string_view(__start, __res.ptr - __start),
1648  __start_digits - __start, __fc);
1649  }
1650 
1651  template<typename _Out>
1652  typename basic_format_context<_Out, _CharT>::iterator
1653  format(bool __i, basic_format_context<_Out, _CharT>& __fc) const
1654  {
1655  if (_M_spec._M_type == _Pres_c)
1656  return _M_format_character(static_cast<unsigned char>(__i), __fc);
1657  if (_M_spec._M_type != _Pres_s)
1658  return format(static_cast<unsigned char>(__i), __fc);
1659 
1660  basic_string<_CharT> __s;
1661  size_t __est_width;
1662  if (_M_spec._M_localized) [[unlikely]]
1663  {
1664  auto& __np = std::use_facet<numpunct<_CharT>>(__fc.locale());
1665  __s = __i ? __np.truename() : __np.falsename();
1666  __est_width = __s.size(); // TODO Unicode-aware estimate
1667  }
1668  else
1669  {
1670  if constexpr (is_same_v<char, _CharT>)
1671  __s = __i ? "true" : "false";
1672  else
1673  __s = __i ? L"true" : L"false";
1674  __est_width = __s.size();
1675  }
1676 
1677  return __format::__write_padded_as_spec(__s, __est_width, __fc,
1678  _M_spec);
1679  }
1680 
1681  [[__gnu__::__always_inline__]]
1682  static size_t
1683  _S_character_width(_CharT __c)
1684  {
1685  // N.B. single byte cannot encode charcter of width greater than 1
1686  if constexpr (sizeof(_CharT) > 1u &&
1687  __unicode::__literal_encoding_is_unicode<_CharT>())
1688  return __unicode::__field_width(__c);
1689  else
1690  return 1u;
1691  }
1692 
1693  template<typename _Out>
1694  typename basic_format_context<_Out, _CharT>::iterator
1695  _M_format_character(_CharT __c,
1696  basic_format_context<_Out, _CharT>& __fc) const
1697  {
1698  return __format::__write_padded_as_spec({&__c, 1u},
1699  _S_character_width(__c),
1700  __fc, _M_spec);
1701  }
1702 
1703  template<typename _Out>
1704  typename basic_format_context<_Out, _CharT>::iterator
1705  _M_format_character_escaped(_CharT __c,
1706  basic_format_context<_Out, _CharT>& __fc) const
1707  {
1708  using _Esc = _Escapes<_CharT>;
1709  constexpr auto __term = __format::_Term_char::_Tc_apos;
1710  const basic_string_view<_CharT> __in(&__c, 1u);
1711  if (_M_spec._M_get_width(__fc) <= 3u)
1712  return __format::__write_escaped(__fc.out(), __in, __term);
1713 
1714  _CharT __buf[12];
1715  __format::_Fixedbuf_sink<_CharT> __sink(__buf);
1716  __format::__write_escaped(__sink.out(), __in, __term);
1717 
1718  const basic_string_view<_CharT> __escaped = __sink.view();
1719  size_t __estimated_width;
1720  if (__escaped[1] == _Esc::_S_bslash()[0]) // escape sequence
1721  __estimated_width = __escaped.size();
1722  else
1723  __estimated_width = 2 + _S_character_width(__c);
1724  return __format::__write_padded_as_spec(__escaped,
1725  __estimated_width,
1726  __fc, _M_spec);
1727  }
1728 
1729  template<typename _Int>
1730  static _CharT
1731  _S_to_character(_Int __i)
1732  {
1733  using _Traits = __gnu_cxx::__int_traits<_CharT>;
1734  if constexpr (is_signed_v<_Int> == is_signed_v<_CharT>)
1735  {
1736  if (_Traits::__min <= __i && __i <= _Traits::__max)
1737  return static_cast<_CharT>(__i);
1738  }
1739  else if constexpr (is_signed_v<_Int>)
1740  {
1741  if (__i >= 0 && make_unsigned_t<_Int>(__i) <= _Traits::__max)
1742  return static_cast<_CharT>(__i);
1743  }
1744  else if (__i <= make_unsigned_t<_CharT>(_Traits::__max))
1745  return static_cast<_CharT>(__i);
1746  __throw_format_error("format error: integer not representable as "
1747  "character");
1748  }
1749 
1750  template<typename _Out>
1751  typename basic_format_context<_Out, _CharT>::iterator
1752  _M_format_int(string_view __narrow_str, size_t __prefix_len,
1753  basic_format_context<_Out, _CharT>& __fc) const
1754  {
1755  size_t __width = _M_spec._M_get_width(__fc);
1756 
1757  basic_string_view<_CharT> __str;
1758  if constexpr (is_same_v<char, _CharT>)
1759  __str = __narrow_str;
1760 #ifdef _GLIBCXX_USE_WCHAR_T
1761  else
1762  {
1763  size_t __n = __narrow_str.size();
1764  auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
1765  std::__to_wstring_numeric(__narrow_str.data(), __n, __p);
1766  __str = {__p, __n};
1767  }
1768 #endif
1769 
1770  if (_M_spec._M_localized)
1771  {
1772  const auto& __l = __fc.locale();
1773  if (__l.name() != "C")
1774  {
1775  auto& __np = use_facet<numpunct<_CharT>>(__l);
1776  string __grp = __np.grouping();
1777  if (!__grp.empty())
1778  {
1779  size_t __n = __str.size() - __prefix_len;
1780  auto __p = (_CharT*)__builtin_alloca(2 * __n
1781  * sizeof(_CharT)
1782  + __prefix_len);
1783  auto __s = __str.data();
1784  char_traits<_CharT>::copy(__p, __s, __prefix_len);
1785  __s += __prefix_len;
1786  auto __end = std::__add_grouping(__p + __prefix_len,
1787  __np.thousands_sep(),
1788  __grp.data(),
1789  __grp.size(),
1790  __s, __s + __n);
1791  __str = {__p, size_t(__end - __p)};
1792  }
1793  }
1794  }
1795 
1796  if (__width <= __str.size())
1797  return __format::__write(__fc.out(), __str);
1798 
1799  char32_t __fill_char = _M_spec._M_fill;
1800  _Align __align = _M_spec._M_align;
1801 
1802  size_t __nfill = __width - __str.size();
1803  auto __out = __fc.out();
1804  if (__align == _Align_default)
1805  {
1806  __align = _Align_right;
1807  if (_M_spec._M_zero_fill)
1808  {
1809  __fill_char = _CharT('0');
1810  // Write sign and base prefix before zero filling.
1811  if (__prefix_len != 0)
1812  {
1813  __out = __format::__write(std::move(__out),
1814  __str.substr(0, __prefix_len));
1815  __str.remove_prefix(__prefix_len);
1816  }
1817  }
1818  else
1819  __fill_char = _CharT(' ');
1820  }
1821  return __format::__write_padded(std::move(__out), __str,
1822  __align, __nfill, __fill_char);
1823  }
1824 
1825 #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
1826  template<typename _Tp>
1827  using make_unsigned_t
1828  = typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)),
1829  std::make_unsigned<_Tp>,
1830  type_identity<unsigned __int128>>::type;
1831 
1832  // std::to_chars is not overloaded for int128 in strict mode.
1833  template<typename _Int>
1834  static to_chars_result
1835  to_chars(char* __first, char* __last, _Int __value, int __base)
1836  { return std::__to_chars_i<_Int>(__first, __last, __value, __base); }
1837 #endif
1838 
1839  _Spec<_CharT> _M_spec{};
1840  };
1841 
1842  // Decide how 128-bit floating-point types should be formatted (or not).
1843  // When supported, the typedef __format::__float128_t is the type that
1844  // format arguments should be converted to for storage in basic_format_arg.
1845  // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported.
1846  // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted
1847  // by converting them to long double (or __ieee128 for powerpc64le).
1848  // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit
1849  // support for _Float128, rather than formatting it as another type.
1850 #undef _GLIBCXX_FORMAT_F128
1851 
1852 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
1853 
1854  // Format 128-bit floating-point types using __ieee128.
1855  using __float128_t = __ieee128;
1856 # define _GLIBCXX_FORMAT_F128 1
1857 
1858 #ifdef __LONG_DOUBLE_IEEE128__
1859  // These overloads exist in the library, but are not declared.
1860  // Make them available as std::__format::to_chars.
1861  to_chars_result
1862  to_chars(char*, char*, __ibm128) noexcept
1863  __asm("_ZSt8to_charsPcS_e");
1864 
1865  to_chars_result
1866  to_chars(char*, char*, __ibm128, chars_format) noexcept
1867  __asm("_ZSt8to_charsPcS_eSt12chars_format");
1868 
1869  to_chars_result
1870  to_chars(char*, char*, __ibm128, chars_format, int) noexcept
1871  __asm("_ZSt8to_charsPcS_eSt12chars_formati");
1872 #elif __cplusplus == 202002L
1873  to_chars_result
1874  to_chars(char*, char*, __ieee128) noexcept
1875  __asm("_ZSt8to_charsPcS_u9__ieee128");
1876 
1877  to_chars_result
1878  to_chars(char*, char*, __ieee128, chars_format) noexcept
1879  __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_format");
1880 
1881  to_chars_result
1882  to_chars(char*, char*, __ieee128, chars_format, int) noexcept
1883  __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_formati");
1884 #endif
1885 
1886 #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
1887 
1888  // Format 128-bit floating-point types using long double.
1889  using __float128_t = long double;
1890 # define _GLIBCXX_FORMAT_F128 1
1891 
1892 #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
1893 
1894  // Format 128-bit floating-point types using _Float128.
1895  using __float128_t = _Float128;
1896 # define _GLIBCXX_FORMAT_F128 2
1897 
1898 # if __cplusplus == 202002L
1899  // These overloads exist in the library, but are not declared for C++20.
1900  // Make them available as std::__format::to_chars.
1901  to_chars_result
1902  to_chars(char*, char*, _Float128) noexcept
1903 # if _GLIBCXX_INLINE_VERSION
1904  __asm("_ZNSt3__88to_charsEPcS0_DF128_");
1905 # else
1906  __asm("_ZSt8to_charsPcS_DF128_");
1907 # endif
1908 
1909  to_chars_result
1910  to_chars(char*, char*, _Float128, chars_format) noexcept
1911 # if _GLIBCXX_INLINE_VERSION
1912  __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatE");
1913 # else
1914  __asm("_ZSt8to_charsPcS_DF128_St12chars_format");
1915 # endif
1916 
1917  to_chars_result
1918  to_chars(char*, char*, _Float128, chars_format, int) noexcept
1919 # if _GLIBCXX_INLINE_VERSION
1920  __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatEi");
1921 # else
1922  __asm("_ZSt8to_charsPcS_DF128_St12chars_formati");
1923 # endif
1924 # endif
1925 #endif
1926 
1927  using std::to_chars;
1928 
1929  // We can format a floating-point type iff it is usable with to_chars.
1930  template<typename _Tp>
1931  concept __formattable_float
1932  = is_same_v<remove_cv_t<_Tp>, _Tp> && requires (_Tp __t, char* __p)
1933  { __format::to_chars(__p, __p, __t, chars_format::scientific, 6); };
1934 
1935  template<__char _CharT>
1936  struct __formatter_fp
1937  {
1938  constexpr typename basic_format_parse_context<_CharT>::iterator
1939  parse(basic_format_parse_context<_CharT>& __pc)
1940  {
1941  _Spec<_CharT> __spec{};
1942  const auto __last = __pc.end();
1943  auto __first = __pc.begin();
1944 
1945  auto __finalize = [this, &__spec] {
1946  _M_spec = __spec;
1947  };
1948 
1949  auto __finished = [&] {
1950  if (__first == __last || *__first == '}')
1951  {
1952  __finalize();
1953  return true;
1954  }
1955  return false;
1956  };
1957 
1958  if (__finished())
1959  return __first;
1960 
1961  __first = __spec._M_parse_fill_and_align(__first, __last);
1962  if (__finished())
1963  return __first;
1964 
1965  __first = __spec._M_parse_sign(__first, __last);
1966  if (__finished())
1967  return __first;
1968 
1969  __first = __spec._M_parse_alternate_form(__first, __last);
1970  if (__finished())
1971  return __first;
1972 
1973  __first = __spec._M_parse_zero_fill(__first, __last);
1974  if (__finished())
1975  return __first;
1976 
1977  if (__first[0] != '.')
1978  {
1979  __first = __spec._M_parse_width(__first, __last, __pc);
1980  if (__finished())
1981  return __first;
1982  }
1983 
1984  __first = __spec._M_parse_precision(__first, __last, __pc);
1985  if (__finished())
1986  return __first;
1987 
1988  __first = __spec._M_parse_locale(__first, __last);
1989  if (__finished())
1990  return __first;
1991 
1992  switch (*__first)
1993  {
1994  case 'a':
1995  __spec._M_type = _Pres_a;
1996  ++__first;
1997  break;
1998  case 'A':
1999  __spec._M_type = _Pres_A;
2000  ++__first;
2001  break;
2002  case 'e':
2003  __spec._M_type = _Pres_e;
2004  ++__first;
2005  break;
2006  case 'E':
2007  __spec._M_type = _Pres_E;
2008  ++__first;
2009  break;
2010  case 'f':
2011  __spec._M_type = _Pres_f;
2012  ++__first;
2013  break;
2014  case 'F':
2015  __spec._M_type = _Pres_F;
2016  ++__first;
2017  break;
2018  case 'g':
2019  __spec._M_type = _Pres_g;
2020  ++__first;
2021  break;
2022  case 'G':
2023  __spec._M_type = _Pres_G;
2024  ++__first;
2025  break;
2026  }
2027 
2028  if (__finished())
2029  return __first;
2030 
2031  __format::__failed_to_parse_format_spec();
2032  }
2033 
2034  template<typename _Fp, typename _Out>
2035  typename basic_format_context<_Out, _CharT>::iterator
2036  format(_Fp __v, basic_format_context<_Out, _CharT>& __fc) const
2037  {
2038  std::string __dynbuf;
2039  char __buf[128];
2040  to_chars_result __res{};
2041 
2042  size_t __prec = 6;
2043  bool __use_prec = _M_spec._M_prec_kind != _WP_none;
2044  if (__use_prec)
2045  __prec = _M_spec._M_get_precision(__fc);
2046 
2047  char* __start = __buf + 1; // reserve space for sign
2048  char* __end = __buf + sizeof(__buf);
2049 
2050  chars_format __fmt{};
2051  bool __upper = false;
2052  bool __trailing_zeros = false;
2053  char __expc = 'e';
2054 
2055  switch (_M_spec._M_type)
2056  {
2057  case _Pres_A:
2058  __upper = true;
2059  __expc = 'P';
2060  [[fallthrough]];
2061  case _Pres_a:
2062  if (_M_spec._M_type != _Pres_A)
2063  __expc = 'p';
2064  __fmt = chars_format::hex;
2065  break;
2066  case _Pres_E:
2067  __upper = true;
2068  __expc = 'E';
2069  [[fallthrough]];
2070  case _Pres_e:
2071  __use_prec = true;
2072  __fmt = chars_format::scientific;
2073  break;
2074  case _Pres_F:
2075  __upper = true;
2076  [[fallthrough]];
2077  case _Pres_f:
2078  __use_prec = true;
2079  __fmt = chars_format::fixed;
2080  break;
2081  case _Pres_G:
2082  __upper = true;
2083  __expc = 'E';
2084  [[fallthrough]];
2085  case _Pres_g:
2086  __trailing_zeros = true;
2087  __use_prec = true;
2088  __fmt = chars_format::general;
2089  break;
2090  case _Pres_none:
2091  if (__use_prec)
2092  __fmt = chars_format::general;
2093  break;
2094  default:
2095  __builtin_unreachable();
2096  }
2097 
2098  // Write value into buffer using std::to_chars.
2099  auto __to_chars = [&](char* __b, char* __e) {
2100  if (__use_prec)
2101  return __format::to_chars(__b, __e, __v, __fmt, __prec);
2102  else if (__fmt != chars_format{})
2103  return __format::to_chars(__b, __e, __v, __fmt);
2104  else
2105  return __format::to_chars(__b, __e, __v);
2106  };
2107 
2108  // First try using stack buffer.
2109  __res = __to_chars(__start, __end);
2110 
2111  if (__builtin_expect(__res.ec == errc::value_too_large, 0))
2112  {
2113  // If the buffer is too small it's probably because of a large
2114  // precision, or a very large value in fixed format.
2115  size_t __guess = 8 + __prec;
2116  if (__fmt == chars_format::fixed) // +ddd.prec
2117  {
2118  if constexpr (is_same_v<_Fp, float> || is_same_v<_Fp, double>
2119  || is_same_v<_Fp, long double>)
2120  {
2121  // The number of digits to the left of the decimal point
2122  // is floor(log10(max(abs(__v),1)))+1
2123  int __exp{};
2124  if constexpr (is_same_v<_Fp, float>)
2125  __builtin_frexpf(__v, &__exp);
2126  else if constexpr (is_same_v<_Fp, double>)
2127  __builtin_frexp(__v, &__exp);
2128  else if constexpr (is_same_v<_Fp, long double>)
2129  __builtin_frexpl(__v, &__exp);
2130  if (__exp > 0)
2131  __guess += 1U + __exp * 4004U / 13301U; // log10(2) approx.
2132  }
2133  else
2134  __guess += numeric_limits<_Fp>::max_exponent10;
2135  }
2136  if (__guess <= sizeof(__buf)) [[unlikely]]
2137  __guess = sizeof(__buf) * 2;
2138  __dynbuf.reserve(__guess);
2139 
2140  do
2141  {
2142  // Mangling of this lambda, and thus resize_and_overwrite
2143  // instantiated with it, was fixed in ABI 18 (G++ 13). Since
2144  // <format> was new in G++ 13, and is experimental, that
2145  // isn't a problem.
2146  auto __overwrite = [&__to_chars, &__res] (char* __p, size_t __n)
2147  {
2148  __res = __to_chars(__p + 1, __p + __n - 1);
2149  return __res.ec == errc{} ? __res.ptr - __p : 0;
2150  };
2151 
2152  __dynbuf.__resize_and_overwrite(__dynbuf.capacity() * 2,
2153  __overwrite);
2154  __start = __dynbuf.data() + 1; // reserve space for sign
2155  __end = __dynbuf.data() + __dynbuf.size();
2156  }
2157  while (__builtin_expect(__res.ec == errc::value_too_large, 0));
2158  }
2159 
2160  // Use uppercase for 'A', 'E', and 'G' formats.
2161  if (__upper)
2162  {
2163  for (char* __p = __start; __p != __res.ptr; ++__p)
2164  *__p = std::toupper(*__p);
2165  }
2166 
2167  bool __have_sign = true;
2168  // Add sign for non-negative values.
2169  if (!__builtin_signbit(__v))
2170  {
2171  if (_M_spec._M_sign == _Sign_plus)
2172  *--__start = '+';
2173  else if (_M_spec._M_sign == _Sign_space)
2174  *--__start = ' ';
2175  else
2176  __have_sign = false;
2177  }
2178 
2179  string_view __narrow_str(__start, __res.ptr - __start);
2180 
2181  // Use alternate form. Ensure decimal point is always present,
2182  // and add trailing zeros (up to precision) for g and G forms.
2183  if (_M_spec._M_alt && __builtin_isfinite(__v))
2184  {
2185  string_view __s = __narrow_str;
2186  size_t __sigfigs; // Number of significant figures.
2187  size_t __z = 0; // Number of trailing zeros to add.
2188  size_t __p; // Position of the exponent character (if any).
2189  size_t __d = __s.find('.'); // Position of decimal point.
2190  if (__d != __s.npos) // Found decimal point.
2191  {
2192  __p = __s.find(__expc, __d + 1);
2193  if (__p == __s.npos)
2194  __p = __s.size();
2195 
2196  // If presentation type is g or G we might need to add zeros.
2197  if (__trailing_zeros)
2198  {
2199  // Find number of digits after first significant figure.
2200  if (__s[__have_sign] != '0')
2201  // A string like "D.D" or "-D.DDD"
2202  __sigfigs = __p - __have_sign - 1;
2203  else
2204  // A string like "0.D" or "-0.0DD".
2205  // Safe to assume there is a non-zero digit, because
2206  // otherwise there would be no decimal point.
2207  __sigfigs = __p - __s.find_first_not_of('0', __d + 1);
2208  }
2209  }
2210  else // No decimal point, we need to insert one.
2211  {
2212  __p = __s.find(__expc); // Find the exponent, if present.
2213  if (__p == __s.npos)
2214  __p = __s.size();
2215  __d = __p; // Position where '.' should be inserted.
2216  __sigfigs = __d - __have_sign;
2217  }
2218 
2219  if (__trailing_zeros && __prec != 0)
2220  {
2221  // For g and G presentation types std::to_chars produces
2222  // no more than prec significant figures. Insert this many
2223  // zeros so the result has exactly prec significant figures.
2224  __z = __prec - __sigfigs;
2225  }
2226 
2227  if (size_t __extras = int(__d == __p) + __z) // How many to add.
2228  {
2229  if (__dynbuf.empty() && __extras <= size_t(__end - __res.ptr))
2230  {
2231  // The stack buffer is large enough for the result.
2232  // Move exponent to make space for extra chars.
2233  __builtin_memmove(__start + __p + __extras,
2234  __start + __p,
2235  __s.size() - __p);
2236  if (__d == __p)
2237  __start[__p++] = '.';
2238  __builtin_memset(__start + __p, '0', __z);
2239  __narrow_str = {__s.data(), __s.size() + __extras};
2240  }
2241  else // Need to switch to the dynamic buffer.
2242  {
2243  __dynbuf.reserve(__s.size() + __extras);
2244  if (__dynbuf.empty())
2245  {
2246  __dynbuf = __s.substr(0, __p);
2247  if (__d == __p)
2248  __dynbuf += '.';
2249  if (__z)
2250  __dynbuf.append(__z, '0');
2251  __dynbuf.append(__s.substr(__p));
2252  }
2253  else
2254  {
2255  __dynbuf.insert(__p, __extras, '0');
2256  if (__d == __p)
2257  __dynbuf[__p] = '.';
2258  }
2259  __narrow_str = __dynbuf;
2260  }
2261  }
2262  }
2263 
2264  basic_string<_CharT> __wstr;
2265  basic_string_view<_CharT> __str;
2266  if constexpr (is_same_v<_CharT, char>)
2267  __str = __narrow_str;
2268 #ifdef _GLIBCXX_USE_WCHAR_T
2269  else
2270  {
2271  __wstr = std::__to_wstring_numeric(__narrow_str);
2272  __str = __wstr;
2273  }
2274 #endif
2275 
2276  if (_M_spec._M_localized && __builtin_isfinite(__v))
2277  {
2278  auto __s = _M_localize(__str, __expc, __fc.locale());
2279  if (!__s.empty())
2280  __str = __wstr = std::move(__s);
2281  }
2282 
2283  size_t __width = _M_spec._M_get_width(__fc);
2284 
2285  if (__width <= __str.size())
2286  return __format::__write(__fc.out(), __str);
2287 
2288  char32_t __fill_char = _M_spec._M_fill;
2289  _Align __align = _M_spec._M_align;
2290 
2291  size_t __nfill = __width - __str.size();
2292  auto __out = __fc.out();
2293  if (__align == _Align_default)
2294  {
2295  __align = _Align_right;
2296  if (_M_spec._M_zero_fill && __builtin_isfinite(__v))
2297  {
2298  __fill_char = _CharT('0');
2299  // Write sign before zero filling.
2300  if (!__format::__is_xdigit(__narrow_str[0]))
2301  {
2302  *__out++ = __str[0];
2303  __str.remove_prefix(1);
2304  }
2305  }
2306  else
2307  __fill_char = _CharT(' ');
2308  }
2309  return __format::__write_padded(std::move(__out), __str,
2310  __align, __nfill, __fill_char);
2311  }
2312 
2313  // Locale-specific format.
2314  basic_string<_CharT>
2315  _M_localize(basic_string_view<_CharT> __str, char __expc,
2316  const locale& __loc) const
2317  {
2318  basic_string<_CharT> __lstr;
2319 
2320  if (__loc == locale::classic())
2321  return __lstr; // Nothing to do.
2322 
2323  const auto& __np = use_facet<numpunct<_CharT>>(__loc);
2324  const _CharT __point = __np.decimal_point();
2325  const string __grp = __np.grouping();
2326 
2327  _CharT __dot, __exp;
2328  if constexpr (is_same_v<_CharT, char>)
2329  {
2330  __dot = '.';
2331  __exp = __expc;
2332  }
2333  else
2334  {
2335  __dot = L'.';
2336  switch (__expc)
2337  {
2338  case 'e':
2339  __exp = L'e';
2340  break;
2341  case 'E':
2342  __exp = L'E';
2343  break;
2344  case 'p':
2345  __exp = L'p';
2346  break;
2347  case 'P':
2348  __exp = L'P';
2349  break;
2350  default:
2351  __builtin_unreachable();
2352  }
2353  }
2354 
2355  if (__grp.empty() && __point == __dot)
2356  return __lstr; // Locale uses '.' and no grouping.
2357 
2358  size_t __d = __str.find(__dot); // Index of radix character (if any).
2359  size_t __e = min(__d, __str.find(__exp)); // First of radix or exponent
2360  if (__e == __str.npos)
2361  __e = __str.size();
2362  const size_t __r = __str.size() - __e; // Length of remainder.
2363  auto __overwrite = [&](_CharT* __p, size_t) {
2364  // Apply grouping to the digits before the radix or exponent.
2365  auto __end = std::__add_grouping(__p, __np.thousands_sep(),
2366  __grp.data(), __grp.size(),
2367  __str.data(), __str.data() + __e);
2368  if (__r) // If there's a fractional part or exponent
2369  {
2370  if (__d != __str.npos)
2371  {
2372  *__end = __point; // Add the locale's radix character.
2373  ++__end;
2374  ++__e;
2375  }
2376  const size_t __rlen = __str.size() - __e;
2377  // Append fractional digits and/or exponent:
2378  char_traits<_CharT>::copy(__end, __str.data() + __e, __rlen);
2379  __end += __rlen;
2380  }
2381  return (__end - __p);
2382  };
2383  __lstr.__resize_and_overwrite(__e * 2 + __r, __overwrite);
2384  return __lstr;
2385  }
2386 
2387  _Spec<_CharT> _M_spec{};
2388  };
2389 
2390 } // namespace __format
2391 /// @endcond
2392 
2393  /// Format a character.
2394  template<__format::__char _CharT>
2395  struct formatter<_CharT, _CharT>
2396  {
2397  formatter() = default;
2398 
2399  constexpr typename basic_format_parse_context<_CharT>::iterator
2400  parse(basic_format_parse_context<_CharT>& __pc)
2401  {
2402  return _M_f.template _M_parse<_CharT>(__pc);
2403  }
2404 
2405  template<typename _Out>
2406  typename basic_format_context<_Out, _CharT>::iterator
2407  format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const
2408  {
2409  if (_M_f._M_spec._M_type == __format::_Pres_none
2410  || _M_f._M_spec._M_type == __format::_Pres_c)
2411  return _M_f._M_format_character(__u, __fc);
2412  else if (_M_f._M_spec._M_type == __format::_Pres_esc)
2413  return _M_f._M_format_character_escaped(__u, __fc);
2414  else
2415  return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), __fc);
2416  }
2417 
2418 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2419  constexpr void
2420  set_debug_format() noexcept
2421  { _M_f._M_spec._M_type = __format::_Pres_esc; }
2422 #endif
2423 
2424  private:
2425  __format::__formatter_int<_CharT> _M_f;
2426  };
2427 
2428 #ifdef _GLIBCXX_USE_WCHAR_T
2429  /// Format a char value for wide character output.
2430  template<>
2431  struct formatter<char, wchar_t>
2432  {
2433  formatter() = default;
2434 
2435  constexpr typename basic_format_parse_context<wchar_t>::iterator
2436  parse(basic_format_parse_context<wchar_t>& __pc)
2437  {
2438  return _M_f._M_parse<char>(__pc);
2439  }
2440 
2441  template<typename _Out>
2442  typename basic_format_context<_Out, wchar_t>::iterator
2443  format(char __u, basic_format_context<_Out, wchar_t>& __fc) const
2444  {
2445  if (_M_f._M_spec._M_type == __format::_Pres_none
2446  || _M_f._M_spec._M_type == __format::_Pres_c)
2447  return _M_f._M_format_character(__u, __fc);
2448  else if (_M_f._M_spec._M_type == __format::_Pres_esc)
2449  return _M_f._M_format_character_escaped(__u, __fc);
2450  else
2451  return _M_f.format(static_cast<unsigned char>(__u), __fc);
2452  }
2453 
2454 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2455  constexpr void
2456  set_debug_format() noexcept
2457  { _M_f._M_spec._M_type = __format::_Pres_esc; }
2458 #endif
2459 
2460  private:
2461  __format::__formatter_int<wchar_t> _M_f;
2462  };
2463 #endif // USE_WCHAR_T
2464 
2465  /** Format a string.
2466  * @{
2467  */
2468  template<__format::__char _CharT>
2469  struct formatter<_CharT*, _CharT>
2470  {
2471  formatter() = default;
2472 
2473  [[__gnu__::__always_inline__]]
2474  constexpr typename basic_format_parse_context<_CharT>::iterator
2475  parse(basic_format_parse_context<_CharT>& __pc)
2476  { return _M_f.parse(__pc); }
2477 
2478  template<typename _Out>
2479  [[__gnu__::__nonnull__]]
2480  typename basic_format_context<_Out, _CharT>::iterator
2481  format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const
2482  { return _M_f.format(__u, __fc); }
2483 
2484 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2485  constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2486 #endif
2487 
2488  private:
2489  __format::__formatter_str<_CharT> _M_f;
2490  };
2491 
2492  template<__format::__char _CharT>
2493  struct formatter<const _CharT*, _CharT>
2494  {
2495  formatter() = default;
2496 
2497  [[__gnu__::__always_inline__]]
2498  constexpr typename basic_format_parse_context<_CharT>::iterator
2499  parse(basic_format_parse_context<_CharT>& __pc)
2500  { return _M_f.parse(__pc); }
2501 
2502  template<typename _Out>
2503  [[__gnu__::__nonnull__]]
2504  typename basic_format_context<_Out, _CharT>::iterator
2505  format(const _CharT* __u,
2506  basic_format_context<_Out, _CharT>& __fc) const
2507  { return _M_f.format(__u, __fc); }
2508 
2509 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2510  constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2511 #endif
2512 
2513  private:
2514  __format::__formatter_str<_CharT> _M_f;
2515  };
2516 
2517  template<__format::__char _CharT, size_t _Nm>
2518  struct formatter<_CharT[_Nm], _CharT>
2519  {
2520  formatter() = default;
2521 
2522  [[__gnu__::__always_inline__]]
2523  constexpr typename basic_format_parse_context<_CharT>::iterator
2524  parse(basic_format_parse_context<_CharT>& __pc)
2525  { return _M_f.parse(__pc); }
2526 
2527  template<typename _Out>
2528  typename basic_format_context<_Out, _CharT>::iterator
2529  format(const _CharT (&__u)[_Nm],
2530  basic_format_context<_Out, _CharT>& __fc) const
2531  { return _M_f.format({__u, _Nm}, __fc); }
2532 
2533 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2534  constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2535 #endif
2536 
2537  private:
2538  __format::__formatter_str<_CharT> _M_f;
2539  };
2540 
2541  template<typename _Traits, typename _Alloc>
2542  struct formatter<basic_string<char, _Traits, _Alloc>, char>
2543  {
2544  formatter() = default;
2545 
2546  [[__gnu__::__always_inline__]]
2547  constexpr typename basic_format_parse_context<char>::iterator
2548  parse(basic_format_parse_context<char>& __pc)
2549  { return _M_f.parse(__pc); }
2550 
2551  template<typename _Out>
2552  typename basic_format_context<_Out, char>::iterator
2553  format(const basic_string<char, _Traits, _Alloc>& __u,
2554  basic_format_context<_Out, char>& __fc) const
2555  { return _M_f.format(__u, __fc); }
2556 
2557 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2558  constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2559 #endif
2560 
2561  private:
2562  __format::__formatter_str<char> _M_f;
2563  };
2564 
2565 #ifdef _GLIBCXX_USE_WCHAR_T
2566  template<typename _Traits, typename _Alloc>
2567  struct formatter<basic_string<wchar_t, _Traits, _Alloc>, wchar_t>
2568  {
2569  formatter() = default;
2570 
2571  [[__gnu__::__always_inline__]]
2572  constexpr typename basic_format_parse_context<wchar_t>::iterator
2573  parse(basic_format_parse_context<wchar_t>& __pc)
2574  { return _M_f.parse(__pc); }
2575 
2576  template<typename _Out>
2577  typename basic_format_context<_Out, wchar_t>::iterator
2578  format(const basic_string<wchar_t, _Traits, _Alloc>& __u,
2579  basic_format_context<_Out, wchar_t>& __fc) const
2580  { return _M_f.format(__u, __fc); }
2581 
2582 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2583  constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2584 #endif
2585 
2586  private:
2587  __format::__formatter_str<wchar_t> _M_f;
2588  };
2589 #endif // USE_WCHAR_T
2590 
2591  template<typename _Traits>
2592  struct formatter<basic_string_view<char, _Traits>, char>
2593  {
2594  formatter() = default;
2595 
2596  [[__gnu__::__always_inline__]]
2597  constexpr typename basic_format_parse_context<char>::iterator
2598  parse(basic_format_parse_context<char>& __pc)
2599  { return _M_f.parse(__pc); }
2600 
2601  template<typename _Out>
2602  typename basic_format_context<_Out, char>::iterator
2603  format(basic_string_view<char, _Traits> __u,
2604  basic_format_context<_Out, char>& __fc) const
2605  { return _M_f.format(__u, __fc); }
2606 
2607 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2608  constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2609 #endif
2610 
2611  private:
2612  __format::__formatter_str<char> _M_f;
2613  };
2614 
2615 #ifdef _GLIBCXX_USE_WCHAR_T
2616  template<typename _Traits>
2617  struct formatter<basic_string_view<wchar_t, _Traits>, wchar_t>
2618  {
2619  formatter() = default;
2620 
2621  [[__gnu__::__always_inline__]]
2622  constexpr typename basic_format_parse_context<wchar_t>::iterator
2623  parse(basic_format_parse_context<wchar_t>& __pc)
2624  { return _M_f.parse(__pc); }
2625 
2626  template<typename _Out>
2627  typename basic_format_context<_Out, wchar_t>::iterator
2628  format(basic_string_view<wchar_t, _Traits> __u,
2629  basic_format_context<_Out, wchar_t>& __fc) const
2630  { return _M_f.format(__u, __fc); }
2631 
2632 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
2633  constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
2634 #endif
2635 
2636  private:
2637  __format::__formatter_str<wchar_t> _M_f;
2638  };
2639 #endif // USE_WCHAR_T
2640  /// @}
2641 
2642 /// @cond undocumented
2643 namespace __format
2644 {
2645  // each cv-unqualified arithmetic type ArithmeticT other than
2646  // char, wchar_t, char8_t, char16_t, or char32_t
2647  template<typename _Tp>
2648  constexpr bool __is_formattable_integer = __is_integer<_Tp>::__value;
2649 
2650 #if defined __SIZEOF_INT128__
2651  template<> inline constexpr bool __is_formattable_integer<__int128> = true;
2652  template<> inline constexpr bool __is_formattable_integer<unsigned __int128>
2653  = true;
2654 #endif
2655 
2656  template<> inline constexpr bool __is_formattable_integer<char> = false;
2657  template<> inline constexpr bool __is_formattable_integer<wchar_t> = false;
2658 #ifdef _GLIBCXX_USE_CHAR8_T
2659  template<> inline constexpr bool __is_formattable_integer<char8_t> = false;
2660 #endif
2661  template<> inline constexpr bool __is_formattable_integer<char16_t> = false;
2662  template<> inline constexpr bool __is_formattable_integer<char32_t> = false;
2663 }
2664 /// @endcond
2665 
2666  /// Format an integer.
2667  template<typename _Tp, __format::__char _CharT>
2668  requires __format::__is_formattable_integer<_Tp>
2669  struct formatter<_Tp, _CharT>
2670  {
2671  formatter() = default;
2672 
2673  [[__gnu__::__always_inline__]]
2674  constexpr typename basic_format_parse_context<_CharT>::iterator
2675  parse(basic_format_parse_context<_CharT>& __pc)
2676  {
2677  return _M_f.template _M_parse<_Tp>(__pc);
2678  }
2679 
2680  template<typename _Out>
2681  typename basic_format_context<_Out, _CharT>::iterator
2682  format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
2683  { return _M_f.format(__u, __fc); }
2684 
2685  private:
2686  __format::__formatter_int<_CharT> _M_f;
2687  };
2688 
2689 #if defined __glibcxx_to_chars
2690  /// Format a floating-point value.
2691  template<__format::__formattable_float _Tp, __format::__char _CharT>
2692  struct formatter<_Tp, _CharT>
2693  {
2694  formatter() = default;
2695 
2696  [[__gnu__::__always_inline__]]
2697  constexpr typename basic_format_parse_context<_CharT>::iterator
2698  parse(basic_format_parse_context<_CharT>& __pc)
2699  { return _M_f.parse(__pc); }
2700 
2701  template<typename _Out>
2702  typename basic_format_context<_Out, _CharT>::iterator
2703  format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
2704  { return _M_f.format(__u, __fc); }
2705 
2706  private:
2707  __format::__formatter_fp<_CharT> _M_f;
2708  };
2709 
2710 #if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__
2711  // Reuse __formatter_fp<C>::format<double, Out> for long double.
2712  template<__format::__char _CharT>
2713  struct formatter<long double, _CharT>
2714  {
2715  formatter() = default;
2716 
2717  [[__gnu__::__always_inline__]]
2718  constexpr typename basic_format_parse_context<_CharT>::iterator
2719  parse(basic_format_parse_context<_CharT>& __pc)
2720  { return _M_f.parse(__pc); }
2721 
2722  template<typename _Out>
2723  typename basic_format_context<_Out, _CharT>::iterator
2724  format(long double __u, basic_format_context<_Out, _CharT>& __fc) const
2725  { return _M_f.format((double)__u, __fc); }
2726 
2727  private:
2728  __format::__formatter_fp<_CharT> _M_f;
2729  };
2730 #endif
2731 
2732 #if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
2733  // Reuse __formatter_fp<C>::format<float, Out> for _Float16.
2734  template<__format::__char _CharT>
2735  struct formatter<_Float16, _CharT>
2736  {
2737  formatter() = default;
2738 
2739  [[__gnu__::__always_inline__]]
2740  constexpr typename basic_format_parse_context<_CharT>::iterator
2741  parse(basic_format_parse_context<_CharT>& __pc)
2742  { return _M_f.parse(__pc); }
2743 
2744  template<typename _Out>
2745  typename basic_format_context<_Out, _CharT>::iterator
2746  format(_Float16 __u, basic_format_context<_Out, _CharT>& __fc) const
2747  { return _M_f.format((float)__u, __fc); }
2748 
2749  private:
2750  __format::__formatter_fp<_CharT> _M_f;
2751  };
2752 #endif
2753 
2754 #if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
2755  // Reuse __formatter_fp<C>::format<float, Out> for _Float32.
2756  template<__format::__char _CharT>
2757  struct formatter<_Float32, _CharT>
2758  {
2759  formatter() = default;
2760 
2761  [[__gnu__::__always_inline__]]
2762  constexpr typename basic_format_parse_context<_CharT>::iterator
2763  parse(basic_format_parse_context<_CharT>& __pc)
2764  { return _M_f.parse(__pc); }
2765 
2766  template<typename _Out>
2767  typename basic_format_context<_Out, _CharT>::iterator
2768  format(_Float32 __u, basic_format_context<_Out, _CharT>& __fc) const
2769  { return _M_f.format((float)__u, __fc); }
2770 
2771  private:
2772  __format::__formatter_fp<_CharT> _M_f;
2773  };
2774 #endif
2775 
2776 #if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
2777  // Reuse __formatter_fp<C>::format<double, Out> for _Float64.
2778  template<__format::__char _CharT>
2779  struct formatter<_Float64, _CharT>
2780  {
2781  formatter() = default;
2782 
2783  [[__gnu__::__always_inline__]]
2784  constexpr typename basic_format_parse_context<_CharT>::iterator
2785  parse(basic_format_parse_context<_CharT>& __pc)
2786  { return _M_f.parse(__pc); }
2787 
2788  template<typename _Out>
2789  typename basic_format_context<_Out, _CharT>::iterator
2790  format(_Float64 __u, basic_format_context<_Out, _CharT>& __fc) const
2791  { return _M_f.format((double)__u, __fc); }
2792 
2793  private:
2794  __format::__formatter_fp<_CharT> _M_f;
2795  };
2796 #endif
2797 
2798 #if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1
2799  // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128.
2800  template<__format::__char _CharT>
2801  struct formatter<_Float128, _CharT>
2802  {
2803  formatter() = default;
2804 
2805  [[__gnu__::__always_inline__]]
2806  constexpr typename basic_format_parse_context<_CharT>::iterator
2807  parse(basic_format_parse_context<_CharT>& __pc)
2808  { return _M_f.parse(__pc); }
2809 
2810  template<typename _Out>
2811  typename basic_format_context<_Out, _CharT>::iterator
2812  format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const
2813  { return _M_f.format((__format::__float128_t)__u, __fc); }
2814 
2815  private:
2816  __format::__formatter_fp<_CharT> _M_f;
2817  };
2818 #endif
2819 
2820 #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
2821  // Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t.
2822  template<__format::__char _CharT>
2823  struct formatter<__gnu_cxx::__bfloat16_t, _CharT>
2824  {
2825  formatter() = default;
2826 
2827  [[__gnu__::__always_inline__]]
2828  constexpr typename basic_format_parse_context<_CharT>::iterator
2829  parse(basic_format_parse_context<_CharT>& __pc)
2830  { return _M_f.parse(__pc); }
2831 
2832  template<typename _Out>
2833  typename basic_format_context<_Out, _CharT>::iterator
2834  format(__gnu_cxx::__bfloat16_t __u,
2835  basic_format_context<_Out, _CharT>& __fc) const
2836  { return _M_f.format((float)__u, __fc); }
2837 
2838  private:
2839  __format::__formatter_fp<_CharT> _M_f;
2840  };
2841 #endif
2842 #endif // __cpp_lib_to_chars
2843 
2844  /** Format a pointer.
2845  * @{
2846  */
2847  template<__format::__char _CharT>
2848  struct formatter<const void*, _CharT>
2849  {
2850  formatter() = default;
2851 
2852  constexpr typename basic_format_parse_context<_CharT>::iterator
2853  parse(basic_format_parse_context<_CharT>& __pc)
2854  {
2855  __format::_Spec<_CharT> __spec{};
2856  const auto __last = __pc.end();
2857  auto __first = __pc.begin();
2858 
2859  auto __finalize = [this, &__spec] {
2860  _M_spec = __spec;
2861  };
2862 
2863  auto __finished = [&] {
2864  if (__first == __last || *__first == '}')
2865  {
2866  __finalize();
2867  return true;
2868  }
2869  return false;
2870  };
2871 
2872  if (__finished())
2873  return __first;
2874 
2875  __first = __spec._M_parse_fill_and_align(__first, __last);
2876  if (__finished())
2877  return __first;
2878 
2879 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2880 // P2510R3 Formatting pointers
2881 #if __glibcxx_format >= 202304L
2882  __first = __spec._M_parse_zero_fill(__first, __last);
2883  if (__finished())
2884  return __first;
2885 #endif
2886 
2887  __first = __spec._M_parse_width(__first, __last, __pc);
2888 
2889  if (__first != __last)
2890  {
2891  if (*__first == 'p')
2892  ++__first;
2893 #if __glibcxx_format >= 202304L
2894  else if (*__first == 'P')
2895  {
2896  __spec._M_type = __format::_Pres_P;
2897  ++__first;
2898  }
2899 #endif
2900  }
2901 
2902  if (__finished())
2903  return __first;
2904 
2905  __format::__failed_to_parse_format_spec();
2906  }
2907 
2908  template<typename _Out>
2909  typename basic_format_context<_Out, _CharT>::iterator
2910  format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
2911  {
2912  auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
2913  char __buf[2 + sizeof(__v) * 2];
2914  auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
2915  __u, 16);
2916  int __n = __ptr - __buf;
2917  __buf[0] = '0';
2918  __buf[1] = 'x';
2919 #if __glibcxx_format >= 202304L
2920  if (_M_spec._M_type == __format::_Pres_P)
2921  {
2922  __buf[1] = 'X';
2923  for (auto __p = __buf + 2; __p != __ptr; ++__p)
2924 #if __has_builtin(__builtin_toupper)
2925  *__p = __builtin_toupper(*__p);
2926 #else
2927  *__p = std::toupper(*__p);
2928 #endif
2929  }
2930 #endif
2931 
2932  basic_string_view<_CharT> __str;
2933  if constexpr (is_same_v<_CharT, char>)
2934  __str = string_view(__buf, __n);
2935 #ifdef _GLIBCXX_USE_WCHAR_T
2936  else
2937  {
2938  auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
2939  std::__to_wstring_numeric(__buf, __n, __p);
2940  __str = wstring_view(__p, __n);
2941  }
2942 #endif
2943 
2944 #if __glibcxx_format >= 202304L
2945  if (_M_spec._M_zero_fill)
2946  {
2947  size_t __width = _M_spec._M_get_width(__fc);
2948  if (__width <= __str.size())
2949  return __format::__write(__fc.out(), __str);
2950 
2951  auto __out = __fc.out();
2952  // Write "0x" or "0X" prefix before zero-filling.
2953  __out = __format::__write(std::move(__out), __str.substr(0, 2));
2954  __str.remove_prefix(2);
2955  size_t __nfill = __width - __n;
2956  return __format::__write_padded(std::move(__out), __str,
2957  __format::_Align_right,
2958  __nfill, _CharT('0'));
2959  }
2960 #endif
2961 
2962  return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
2963  __format::_Align_right);
2964  }
2965 
2966  private:
2967  __format::_Spec<_CharT> _M_spec{};
2968  };
2969 
2970  template<__format::__char _CharT>
2971  struct formatter<void*, _CharT>
2972  {
2973  formatter() = default;
2974 
2975  [[__gnu__::__always_inline__]]
2976  constexpr typename basic_format_parse_context<_CharT>::iterator
2977  parse(basic_format_parse_context<_CharT>& __pc)
2978  { return _M_f.parse(__pc); }
2979 
2980  template<typename _Out>
2981  typename basic_format_context<_Out, _CharT>::iterator
2982  format(void* __v, basic_format_context<_Out, _CharT>& __fc) const
2983  { return _M_f.format(__v, __fc); }
2984 
2985  private:
2986  formatter<const void*, _CharT> _M_f;
2987  };
2988 
2989  template<__format::__char _CharT>
2990  struct formatter<nullptr_t, _CharT>
2991  {
2992  formatter() = default;
2993 
2994  [[__gnu__::__always_inline__]]
2995  constexpr typename basic_format_parse_context<_CharT>::iterator
2996  parse(basic_format_parse_context<_CharT>& __pc)
2997  { return _M_f.parse(__pc); }
2998 
2999  template<typename _Out>
3000  typename basic_format_context<_Out, _CharT>::iterator
3001  format(nullptr_t, basic_format_context<_Out, _CharT>& __fc) const
3002  { return _M_f.format(nullptr, __fc); }
3003 
3004  private:
3005  formatter<const void*, _CharT> _M_f;
3006  };
3007  /// @}
3008 
3009 #if defined _GLIBCXX_USE_WCHAR_T && __glibcxx_format_ranges
3010  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3011  // 3944. Formatters converting sequences of char to sequences of wchar_t
3012 
3013  namespace __format { struct __disabled; }
3014 
3015  // std::formatter<__disabled, C> uses the primary template, which is disabled.
3016  template<>
3017  struct formatter<char*, wchar_t>
3018  : private formatter<__format::__disabled, wchar_t> { };
3019  template<>
3020  struct formatter<const char*, wchar_t>
3021  : private formatter<__format::__disabled, wchar_t> { };
3022  template<size_t _Nm>
3023  struct formatter<char[_Nm], wchar_t>
3024  : private formatter<__format::__disabled, wchar_t> { };
3025  template<class _Traits, class _Allocator>
3026  struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t>
3027  : private formatter<__format::__disabled, wchar_t> { };
3028  template<class _Traits>
3029  struct formatter<basic_string_view<char, _Traits>, wchar_t>
3030  : private formatter<__format::__disabled, wchar_t> { };
3031 #endif
3032 
3033  /// An iterator after the last character written, and the number of
3034  /// characters that would have been written.
3035  template<typename _Out>
3036  struct format_to_n_result
3037  {
3038  _Out out;
3039  iter_difference_t<_Out> size;
3040  };
3041 
3042 _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
3043 template<typename, typename> class vector;
3044 _GLIBCXX_END_NAMESPACE_CONTAINER
3045 
3046 /// @cond undocumented
3047 namespace __format
3048 {
3049  template<typename _CharT>
3050  class _Sink_iter
3051  {
3052  _Sink<_CharT>* _M_sink = nullptr;
3053 
3054  public:
3055  using iterator_category = output_iterator_tag;
3056  using value_type = void;
3057  using difference_type = ptrdiff_t;
3058  using pointer = void;
3059  using reference = void;
3060 
3061  _Sink_iter() = default;
3062  _Sink_iter(const _Sink_iter&) = default;
3063  _Sink_iter& operator=(const _Sink_iter&) = default;
3064 
3065  [[__gnu__::__always_inline__]]
3066  explicit constexpr
3067  _Sink_iter(_Sink<_CharT>& __sink) : _M_sink(std::addressof(__sink)) { }
3068 
3069  [[__gnu__::__always_inline__]]
3070  constexpr _Sink_iter&
3071  operator=(_CharT __c)
3072  {
3073  _M_sink->_M_write(__c);
3074  return *this;
3075  }
3076 
3077  [[__gnu__::__always_inline__]]
3078  constexpr _Sink_iter&
3079  operator=(basic_string_view<_CharT> __s)
3080  {
3081  _M_sink->_M_write(__s);
3082  return *this;
3083  }
3084 
3085  [[__gnu__::__always_inline__]]
3086  constexpr _Sink_iter&
3087  operator*() { return *this; }
3088 
3089  [[__gnu__::__always_inline__]]
3090  constexpr _Sink_iter&
3091  operator++() { return *this; }
3092 
3093  [[__gnu__::__always_inline__]]
3094  constexpr _Sink_iter
3095  operator++(int) { return *this; }
3096 
3097  auto
3098  _M_reserve(size_t __n) const
3099  { return _M_sink->_M_reserve(__n); }
3100  };
3101 
3102  // Abstract base class for type-erased character sinks.
3103  // All formatting and output is done via this type's iterator,
3104  // to reduce the number of different template instantiations.
3105  template<typename _CharT>
3106  class _Sink
3107  {
3108  friend class _Sink_iter<_CharT>;
3109 
3110  span<_CharT> _M_span;
3111  typename span<_CharT>::iterator _M_next;
3112 
3113  // Called when the span is full, to make more space available.
3114  // Precondition: _M_next != _M_span.begin()
3115  // Postcondition: _M_next != _M_span.end()
3116  // TODO: remove the precondition? could make overflow handle it.
3117  virtual void _M_overflow() = 0;
3118 
3119  protected:
3120  // Precondition: __span.size() != 0
3121  [[__gnu__::__always_inline__]]
3122  explicit constexpr
3123  _Sink(span<_CharT> __span) noexcept
3124  : _M_span(__span), _M_next(__span.begin())
3125  { }
3126 
3127  // The portion of the span that has been written to.
3128  [[__gnu__::__always_inline__]]
3129  span<_CharT>
3130  _M_used() const noexcept
3131  { return _M_span.first(_M_next - _M_span.begin()); }
3132 
3133  // The portion of the span that has not been written to.
3134  [[__gnu__::__always_inline__]]
3135  constexpr span<_CharT>
3136  _M_unused() const noexcept
3137  { return _M_span.subspan(_M_next - _M_span.begin()); }
3138 
3139  // Use the start of the span as the next write position.
3140  [[__gnu__::__always_inline__]]
3141  constexpr void
3142  _M_rewind() noexcept
3143  { _M_next = _M_span.begin(); }
3144 
3145  // Replace the current output range.
3146  void
3147  _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept
3148  {
3149  _M_span = __s;
3150  _M_next = __s.begin() + __pos;
3151  }
3152 
3153  // Called by the iterator for *it++ = c
3154  constexpr void
3155  _M_write(_CharT __c)
3156  {
3157  *_M_next++ = __c;
3158  if (_M_next - _M_span.begin() == std::ssize(_M_span)) [[unlikely]]
3159  _M_overflow();
3160  }
3161 
3162  constexpr void
3163  _M_write(basic_string_view<_CharT> __s)
3164  {
3165  span __to = _M_unused();
3166  while (__to.size() <= __s.size())
3167  {
3168  __s.copy(__to.data(), __to.size());
3169  _M_next += __to.size();
3170  __s.remove_prefix(__to.size());
3171  _M_overflow();
3172  __to = _M_unused();
3173  }
3174  if (__s.size())
3175  {
3176  __s.copy(__to.data(), __s.size());
3177  _M_next += __s.size();
3178  }
3179  }
3180 
3181  // A successful _Reservation can be used to directly write
3182  // up to N characters to the sink to avoid unwanted buffering.
3183  struct _Reservation
3184  {
3185  // True if the reservation was successful, false otherwise.
3186  explicit operator bool() const noexcept { return _M_sink; }
3187  // A pointer to write directly to the sink.
3188  _CharT* get() const noexcept { return _M_sink->_M_next.operator->(); }
3189  // Add n to the _M_next iterator for the sink.
3190  void _M_bump(size_t __n) { _M_sink->_M_bump(__n); }
3191  _Sink* _M_sink;
3192  };
3193 
3194  // Attempt to reserve space to write n characters to the sink.
3195  // If anything is written to the reservation then there must be a call
3196  // to _M_bump(N2) before any call to another member function of *this,
3197  // where N2 is the number of characters written.
3198  virtual _Reservation
3199  _M_reserve(size_t __n)
3200  {
3201  if (__n <= _M_unused().size())
3202  return { this };
3203 
3204  if (__n <= _M_span.size()) // Cannot meet the request.
3205  {
3206  _M_overflow(); // Make more space available.
3207  if (__n <= _M_unused().size())
3208  return { this };
3209  }
3210  return { nullptr };
3211  }
3212 
3213  // Update the next output position after writing directly to the sink.
3214  // pre: no calls to _M_write or _M_overflow since _M_reserve.
3215  virtual void
3216  _M_bump(size_t __n)
3217  { _M_next += __n; }
3218 
3219  public:
3220  _Sink(const _Sink&) = delete;
3221  _Sink& operator=(const _Sink&) = delete;
3222 
3223  [[__gnu__::__always_inline__]]
3224  constexpr _Sink_iter<_CharT>
3225  out() noexcept
3226  { return _Sink_iter<_CharT>(*this); }
3227  };
3228 
3229 
3230  template<typename _CharT>
3231  class _Fixedbuf_sink final : public _Sink<_CharT>
3232  {
3233  void
3234  _M_overflow() override
3235  {
3236  __glibcxx_assert(false);
3237  this->_M_rewind();
3238  }
3239 
3240  public:
3241  [[__gnu__::__always_inline__]]
3242  constexpr explicit
3243  _Fixedbuf_sink(span<_CharT> __buf)
3244  : _Sink<_CharT>(__buf)
3245  { }
3246 
3247  constexpr basic_string_view<_CharT>
3248  view() const
3249  {
3250  auto __s = this->_M_used();
3251  return basic_string_view<_CharT>(__s.data(), __s.size());
3252  }
3253  };
3254 
3255  // A sink with an internal buffer. This is used to implement concrete sinks.
3256  template<typename _CharT>
3257  class _Buf_sink : public _Sink<_CharT>
3258  {
3259  protected:
3260  _CharT _M_buf[__stackbuf_size<_CharT>];
3261 
3262  [[__gnu__::__always_inline__]]
3263  constexpr
3264  _Buf_sink() noexcept
3265  : _Sink<_CharT>(_M_buf)
3266  { }
3267  };
3268 
3269  using _GLIBCXX_STD_C::vector;
3270 
3271  // A sink that fills a sequence (e.g. std::string, std::vector, std::deque).
3272  // Writes to a buffer then appends that to the sequence when it fills up.
3273  template<typename _Seq>
3274  class _Seq_sink final : public _Buf_sink<typename _Seq::value_type>
3275  {
3276  using _CharT = typename _Seq::value_type;
3277 
3278  _Seq _M_seq;
3279 
3280  // Transfer buffer contents to the sequence, so buffer can be refilled.
3281  void
3282  _M_overflow() override
3283  {
3284  auto __s = this->_M_used();
3285  if (__s.empty()) [[unlikely]]
3286  return; // Nothing in the buffer to transfer to _M_seq.
3287 
3288  // If _M_reserve was called then _M_bump must have been called too.
3289  _GLIBCXX_DEBUG_ASSERT(__s.data() != _M_seq.data());
3290 
3291  if constexpr (__is_specialization_of<_Seq, basic_string>)
3292  _M_seq.append(__s.data(), __s.size());
3293  else
3294  _M_seq.insert(_M_seq.end(), __s.begin(), __s.end());
3295 
3296  // Make the whole of _M_buf available for the next write:
3297  this->_M_rewind();
3298  }
3299 
3300  typename _Sink<_CharT>::_Reservation
3301  _M_reserve(size_t __n) override
3302  {
3303  // We might already have n characters available in this->_M_unused(),
3304  // but the whole point of this function is to be an optimization for
3305  // the std::format("{}", x) case. We want to avoid writing to _M_buf
3306  // and then copying that into a basic_string if possible, so this
3307  // function prefers to create space directly in _M_seq rather than
3308  // using _M_buf.
3309 
3310  if constexpr (__is_specialization_of<_Seq, basic_string>
3311  || __is_specialization_of<_Seq, vector>)
3312  {
3313  // Flush the buffer to _M_seq first (should not be needed).
3314  if (this->_M_used().size()) [[unlikely]]
3315  _Seq_sink::_M_overflow();
3316 
3317  // Expand _M_seq to make __n new characters available:
3318  const auto __sz = _M_seq.size();
3319  if constexpr (is_same_v<string, _Seq> || is_same_v<wstring, _Seq>)
3320  _M_seq.__resize_and_overwrite(__sz + __n,
3321  [](auto, auto __n2) {
3322  return __n2;
3323  });
3324  else
3325  _M_seq.resize(__sz + __n);
3326 
3327  // Set _M_used() to be a span over the original part of _M_seq
3328  // and _M_unused() to be the extra capacity we just created:
3329  this->_M_reset(_M_seq, __sz);
3330  return { this };
3331  }
3332  else // Try to use the base class' buffer.
3333  return _Sink<_CharT>::_M_reserve(__n);
3334  }
3335 
3336  void
3337  _M_bump(size_t __n) override
3338  {
3339  if constexpr (__is_specialization_of<_Seq, basic_string>
3340  || __is_specialization_of<_Seq, vector>)
3341  {
3342  auto __s = this->_M_used();
3343  _GLIBCXX_DEBUG_ASSERT(__s.data() == _M_seq.data());
3344  // Truncate the sequence to the part that was actually written to:
3345  _M_seq.resize(__s.size() + __n);
3346  // Switch back to using buffer:
3347  this->_M_reset(this->_M_buf);
3348  }
3349  }
3350 
3351  public:
3352  // TODO: for SSO string, use SSO buffer as initial span, then switch
3353  // to _M_buf if it overflows? Or even do that for all unused capacity?
3354 
3355  [[__gnu__::__always_inline__]]
3356  _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>)
3357  { }
3358 
3359  _Seq_sink(_Seq&& __s) noexcept(is_nothrow_move_constructible_v<_Seq>)
3360  : _M_seq(std::move(__s))
3361  { }
3362 
3363  using _Sink<_CharT>::out;
3364 
3365  _Seq
3366  get() &&
3367  {
3368  if (this->_M_used().size() != 0)
3369  _Seq_sink::_M_overflow();
3370  return std::move(_M_seq);
3371  }
3372 
3373  // A writable span that views everything written to the sink.
3374  // Will be either a view over _M_seq or the used part of _M_buf.
3375  span<_CharT>
3376  view()
3377  {
3378  auto __s = this->_M_used();
3379  if (_M_seq.size())
3380  {
3381  if (__s.size() != 0)
3382  _Seq_sink::_M_overflow();
3383  return _M_seq;
3384  }
3385  return __s;
3386  }
3387  };
3388 
3389  // A sink that writes to an output iterator.
3390  // Writes to a fixed-size buffer and then flushes to the output iterator
3391  // when the buffer fills up.
3392  template<typename _CharT, typename _OutIter>
3393  class _Iter_sink : public _Buf_sink<_CharT>
3394  {
3395  _OutIter _M_out;
3396  iter_difference_t<_OutIter> _M_max;
3397 
3398  protected:
3399  size_t _M_count = 0;
3400 
3401  void
3402  _M_overflow() override
3403  {
3404  auto __s = this->_M_used();
3405  if (_M_max < 0) // No maximum.
3406  _M_out = ranges::copy(__s, std::move(_M_out)).out;
3407  else if (_M_count < static_cast<size_t>(_M_max))
3408  {
3409  auto __max = _M_max - _M_count;
3410  span<_CharT> __first;
3411  if (__max < __s.size())
3412  __first = __s.first(static_cast<size_t>(__max));
3413  else
3414  __first = __s;
3415  _M_out = ranges::copy(__first, std::move(_M_out)).out;
3416  }
3417  this->_M_rewind();
3418  _M_count += __s.size();
3419  }
3420 
3421  public:
3422  [[__gnu__::__always_inline__]]
3423  explicit
3424  _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max = -1)
3425  : _M_out(std::move(__out)), _M_max(__max)
3426  { }
3427 
3428  using _Sink<_CharT>::out;
3429 
3430  format_to_n_result<_OutIter>
3431  _M_finish() &&
3432  {
3433  if (this->_M_used().size() != 0)
3434  _Iter_sink::_M_overflow();
3435  iter_difference_t<_OutIter> __count(_M_count);
3436  return { std::move(_M_out), __count };
3437  }
3438  };
3439 
3440  // Partial specialization for contiguous iterators.
3441  // No buffer is used, characters are written straight to the iterator.
3442  // We do not know the size of the output range, so the span size just grows
3443  // as needed. The end of the span might be an invalid pointer outside the
3444  // valid range, but we never actually call _M_span.end(). This class does
3445  // not introduce any invalid pointer arithmetic or overflows that would not
3446  // have happened anyway.
3447  template<typename _CharT, contiguous_iterator _OutIter>
3448  requires same_as<iter_value_t<_OutIter>, _CharT>
3449  class _Iter_sink<_CharT, _OutIter> : public _Sink<_CharT>
3450  {
3451  _OutIter _M_first;
3452  iter_difference_t<_OutIter> _M_max = -1;
3453  protected:
3454  size_t _M_count = 0;
3455  private:
3456  _CharT _M_buf[64]; // Write here after outputting _M_max characters.
3457 
3458  protected:
3459  void
3460  _M_overflow() override
3461  {
3462  if (this->_M_unused().size() != 0)
3463  return; // No need to switch to internal buffer yet.
3464 
3465  auto __s = this->_M_used();
3466 
3467  if (_M_max >= 0)
3468  {
3469  _M_count += __s.size();
3470  // Span was already sized for the maximum character count,
3471  // if it overflows then any further output must go to the
3472  // internal buffer, to be discarded.
3473  this->_M_reset(this->_M_buf);
3474  }
3475  else
3476  {
3477  // No maximum character count. Just extend the span to allow
3478  // writing more characters to it.
3479  this->_M_reset({__s.data(), __s.size() + 1024}, __s.size());
3480  }
3481  }
3482 
3483  typename _Sink<_CharT>::_Reservation
3484  _M_reserve(size_t __n) final
3485  {
3486  auto __avail = this->_M_unused();
3487  if (__n > __avail.size())
3488  {
3489  if (_M_max >= 0)
3490  return {}; // cannot grow
3491 
3492  auto __s = this->_M_used();
3493  this->_M_reset({__s.data(), __s.size() + __n}, __s.size());
3494  }
3495  return { this };
3496  }
3497 
3498  private:
3499  static span<_CharT>
3500  _S_make_span(_CharT* __ptr, iter_difference_t<_OutIter> __n,
3501  span<_CharT> __buf) noexcept
3502  {
3503  if (__n == 0)
3504  return __buf; // Only write to the internal buffer.
3505 
3506  if (__n > 0)
3507  {
3508  if constexpr (!is_integral_v<iter_difference_t<_OutIter>>
3509  || sizeof(__n) > sizeof(size_t))
3510  {
3511  // __int128 or __detail::__max_diff_type
3512  auto __m = iter_difference_t<_OutIter>((size_t)-1);
3513  if (__n > __m)
3514  __n = __m;
3515  }
3516  return {__ptr, (size_t)__n};
3517  }
3518 
3519 #if __has_builtin(__builtin_dynamic_object_size)
3520  if (size_t __bytes = __builtin_dynamic_object_size(__ptr, 2))
3521  return {__ptr, __bytes / sizeof(_CharT)};
3522 #endif
3523  // Avoid forming a pointer to a different memory page.
3524  const auto __off = reinterpret_cast<__UINTPTR_TYPE__>(__ptr) % 1024;
3525  __n = (1024 - __off) / sizeof(_CharT);
3526  if (__n > 0) [[likely]]
3527  return {__ptr, static_cast<size_t>(__n)};
3528  else // Misaligned/packed buffer of wchar_t?
3529  return {__ptr, 1};
3530  }
3531 
3532  public:
3533  explicit
3534  _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __n = -1) noexcept
3535  : _Sink<_CharT>(_S_make_span(std::to_address(__out), __n, _M_buf)),
3536  _M_first(__out), _M_max(__n)
3537  { }
3538 
3539  format_to_n_result<_OutIter>
3540  _M_finish() &&
3541  {
3542  auto __s = this->_M_used();
3543  if (__s.data() == _M_buf)
3544  {
3545  // Switched to internal buffer, so must have written _M_max.
3546  iter_difference_t<_OutIter> __count(_M_count + __s.size());
3547  return { _M_first + _M_max, __count };
3548  }
3549  else // Not using internal buffer yet
3550  {
3551  iter_difference_t<_OutIter> __count(__s.size());
3552  return { _M_first + __count, __count };
3553  }
3554  }
3555  };
3556 
3557  enum _Arg_t : unsigned char {
3558  _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
3559  _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle,
3560  _Arg_i128, _Arg_u128,
3561  _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused.
3562 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3563  _Arg_next_value_,
3564  _Arg_f128 = _Arg_ldbl,
3565  _Arg_ibm128 = _Arg_next_value_,
3566 #else
3567  _Arg_f128,
3568 #endif
3569  _Arg_max_
3570  };
3571 
3572  template<typename _Context>
3573  struct _Arg_value
3574  {
3575  using _CharT = typename _Context::char_type;
3576 
3577  struct _HandleBase
3578  {
3579  const void* _M_ptr;
3580  void (*_M_func)();
3581  };
3582 
3583  union
3584  {
3585  monostate _M_none;
3586  bool _M_bool;
3587  _CharT _M_c;
3588  int _M_i;
3589  unsigned _M_u;
3590  long long _M_ll;
3591  unsigned long long _M_ull;
3592  float _M_flt;
3593  double _M_dbl;
3594 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous.
3595  long double _M_ldbl;
3596 #endif
3597  const _CharT* _M_str;
3598  basic_string_view<_CharT> _M_sv;
3599  const void* _M_ptr;
3600  _HandleBase _M_handle;
3601 #ifdef __SIZEOF_INT128__
3602  __int128 _M_i128;
3603  unsigned __int128 _M_u128;
3604 #endif
3605 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3606  __ieee128 _M_f128;
3607  __ibm128 _M_ibm128;
3608 #elif _GLIBCXX_FORMAT_F128 == 2
3609  __float128_t _M_f128;
3610 #endif
3611  };
3612 
3613  [[__gnu__::__always_inline__]]
3614  _Arg_value() : _M_none() { }
3615 
3616 #if 0
3617  template<typename _Tp>
3618  _Arg_value(in_place_type_t<_Tp>, _Tp __val)
3619  { _S_get<_Tp>() = __val; }
3620 #endif
3621 
3622  template<typename _Tp, typename _Self>
3623  [[__gnu__::__always_inline__]]
3624  static auto&
3625  _S_get(_Self& __u) noexcept
3626  {
3627  if constexpr (is_same_v<_Tp, bool>)
3628  return __u._M_bool;
3629  else if constexpr (is_same_v<_Tp, _CharT>)
3630  return __u._M_c;
3631  else if constexpr (is_same_v<_Tp, int>)
3632  return __u._M_i;
3633  else if constexpr (is_same_v<_Tp, unsigned>)
3634  return __u._M_u;
3635  else if constexpr (is_same_v<_Tp, long long>)
3636  return __u._M_ll;
3637  else if constexpr (is_same_v<_Tp, unsigned long long>)
3638  return __u._M_ull;
3639  else if constexpr (is_same_v<_Tp, float>)
3640  return __u._M_flt;
3641  else if constexpr (is_same_v<_Tp, double>)
3642  return __u._M_dbl;
3643 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3644  else if constexpr (is_same_v<_Tp, long double>)
3645  return __u._M_ldbl;
3646 #else
3647  else if constexpr (is_same_v<_Tp, __ieee128>)
3648  return __u._M_f128;
3649  else if constexpr (is_same_v<_Tp, __ibm128>)
3650  return __u._M_ibm128;
3651 #endif
3652  else if constexpr (is_same_v<_Tp, const _CharT*>)
3653  return __u._M_str;
3654  else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
3655  return __u._M_sv;
3656  else if constexpr (is_same_v<_Tp, const void*>)
3657  return __u._M_ptr;
3658 #ifdef __SIZEOF_INT128__
3659  else if constexpr (is_same_v<_Tp, __int128>)
3660  return __u._M_i128;
3661  else if constexpr (is_same_v<_Tp, unsigned __int128>)
3662  return __u._M_u128;
3663 #endif
3664 #if _GLIBCXX_FORMAT_F128 == 2
3665  else if constexpr (is_same_v<_Tp, __float128_t>)
3666  return __u._M_f128;
3667 #endif
3668  else if constexpr (derived_from<_Tp, _HandleBase>)
3669  return static_cast<_Tp&>(__u._M_handle);
3670  // Otherwise, ill-formed.
3671  }
3672 
3673  template<typename _Tp>
3674  [[__gnu__::__always_inline__]]
3675  auto&
3676  _M_get() noexcept
3677  { return _S_get<_Tp>(*this); }
3678 
3679  template<typename _Tp>
3680  [[__gnu__::__always_inline__]]
3681  const auto&
3682  _M_get() const noexcept
3683  { return _S_get<_Tp>(*this); }
3684 
3685  template<typename _Tp>
3686  [[__gnu__::__always_inline__]]
3687  void
3688  _M_set(_Tp __v) noexcept
3689  {
3690  if constexpr (derived_from<_Tp, _HandleBase>)
3691  std::construct_at(&_M_handle, __v);
3692  else
3693  _S_get<_Tp>(*this) = __v;
3694  }
3695  };
3696 
3697  // [format.arg.store], class template format-arg-store
3698  template<typename _Context, typename... _Args>
3699  class _Arg_store;
3700 
3701  template<typename _Visitor, typename _Ctx>
3702  decltype(auto) __visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
3703 
3704  template<typename _Ch, typename _Tp>
3705  consteval _Arg_t
3706  __to_arg_t_enum() noexcept;
3707 } // namespace __format
3708 /// @endcond
3709 
3710  template<typename _Context>
3711  class basic_format_arg
3712  {
3713  using _CharT = typename _Context::char_type;
3714 
3715  template<typename _Tp>
3716  static constexpr bool __formattable
3717  = __format::__formattable_with<_Tp, _Context>;
3718 
3719  public:
3720  class handle : public __format::_Arg_value<_Context>::_HandleBase
3721  {
3722  using _Base = typename __format::_Arg_value<_Context>::_HandleBase;
3723 
3724  // Format as const if possible, to reduce instantiations.
3725  template<typename _Tp>
3726  using __maybe_const_t
3727  = __conditional_t<__formattable<const _Tp>, const _Tp, _Tp>;
3728 
3729  template<typename _Tq>
3730  static void
3731  _S_format(basic_format_parse_context<_CharT>& __parse_ctx,
3732  _Context& __format_ctx, const void* __ptr)
3733  {
3734  using _Td = remove_const_t<_Tq>;
3735  typename _Context::template formatter_type<_Td> __f;
3736  __parse_ctx.advance_to(__f.parse(__parse_ctx));
3737  _Tq& __val = *const_cast<_Tq*>(static_cast<const _Td*>(__ptr));
3738  __format_ctx.advance_to(__f.format(__val, __format_ctx));
3739  }
3740 
3741  template<typename _Tp>
3742  explicit
3743  handle(_Tp& __val) noexcept
3744  {
3745  this->_M_ptr = __builtin_addressof(__val);
3746  auto __func = _S_format<__maybe_const_t<_Tp>>;
3747  this->_M_func = reinterpret_cast<void(*)()>(__func);
3748  }
3749 
3750  friend class basic_format_arg<_Context>;
3751 
3752  public:
3753  handle(const handle&) = default;
3754  handle& operator=(const handle&) = default;
3755 
3756  [[__gnu__::__always_inline__]]
3757  void
3758  format(basic_format_parse_context<_CharT>& __pc, _Context& __fc) const
3759  {
3760  using _Func = void(*)(basic_format_parse_context<_CharT>&,
3761  _Context&, const void*);
3762  auto __f = reinterpret_cast<_Func>(this->_M_func);
3763  __f(__pc, __fc, this->_M_ptr);
3764  }
3765  };
3766 
3767  [[__gnu__::__always_inline__]]
3768  basic_format_arg() noexcept : _M_type(__format::_Arg_none) { }
3769 
3770  [[nodiscard,__gnu__::__always_inline__]]
3771  explicit operator bool() const noexcept
3772  { return _M_type != __format::_Arg_none; }
3773 
3774 #if __cpp_lib_format >= 202306L // >= C++26
3775  template<typename _Visitor>
3776  decltype(auto)
3777  visit(this basic_format_arg __arg, _Visitor&& __vis)
3778  { return __arg._M_visit_user(std::forward<_Visitor>(__vis), __arg._M_type); }
3779 
3780  template<typename _Res, typename _Visitor>
3781  _Res
3782  visit(this basic_format_arg __arg, _Visitor&& __vis)
3783  { return __arg._M_visit_user(std::forward<_Visitor>(__vis), __arg._M_type); }
3784 #endif
3785 
3786  private:
3787  template<typename _Ctx>
3788  friend class basic_format_args;
3789 
3790  template<typename _Ctx, typename... _Args>
3791  friend class __format::_Arg_store;
3792 
3793  static_assert(is_trivially_copyable_v<__format::_Arg_value<_Context>>);
3794 
3795  __format::_Arg_value<_Context> _M_val;
3796  __format::_Arg_t _M_type;
3797 
3798  // Transform incoming argument type to the type stored in _Arg_value.
3799  // e.g. short -> int, std::string -> std::string_view,
3800  // char[3] -> const char*.
3801  template<typename _Tp>
3802  static consteval auto
3803  _S_to_arg_type()
3804  {
3805  using _Td = remove_const_t<_Tp>;
3806  if constexpr (is_same_v<_Td, bool>)
3807  return type_identity<bool>();
3808  else if constexpr (is_same_v<_Td, _CharT>)
3809  return type_identity<_CharT>();
3810  else if constexpr (is_same_v<_Td, char> && is_same_v<_CharT, wchar_t>)
3811  return type_identity<_CharT>();
3812 #ifdef __SIZEOF_INT128__ // Check before signed/unsigned integer
3813  else if constexpr (is_same_v<_Td, __int128>)
3814  return type_identity<__int128>();
3815  else if constexpr (is_same_v<_Td, unsigned __int128>)
3816  return type_identity<unsigned __int128>();
3817 #endif
3818  else if constexpr (__is_signed_integer<_Td>::value)
3819  {
3820  if constexpr (sizeof(_Td) <= sizeof(int))
3821  return type_identity<int>();
3822  else if constexpr (sizeof(_Td) <= sizeof(long long))
3823  return type_identity<long long>();
3824  }
3825  else if constexpr (__is_unsigned_integer<_Td>::value)
3826  {
3827  if constexpr (sizeof(_Td) <= sizeof(unsigned))
3828  return type_identity<unsigned>();
3829  else if constexpr (sizeof(_Td) <= sizeof(unsigned long long))
3830  return type_identity<unsigned long long>();
3831  }
3832  else if constexpr (is_same_v<_Td, float>)
3833  return type_identity<float>();
3834  else if constexpr (is_same_v<_Td, double>)
3835  return type_identity<double>();
3836 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3837  else if constexpr (is_same_v<_Td, long double>)
3838  return type_identity<long double>();
3839 #else
3840  else if constexpr (is_same_v<_Td, __ibm128>)
3841  return type_identity<__ibm128>();
3842  else if constexpr (is_same_v<_Td, __ieee128>)
3843  return type_identity<__ieee128>();
3844 #endif
3845 
3846 #if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
3847  else if constexpr (is_same_v<_Td, _Float16>)
3848  return type_identity<float>();
3849 #endif
3850 
3851 #if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
3852  else if constexpr (is_same_v<_Td, decltype(0.0bf16)>)
3853  return type_identity<float>();
3854 #endif
3855 
3856 #if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
3857  else if constexpr (is_same_v<_Td, _Float32>)
3858  return type_identity<float>();
3859 #endif
3860 
3861 #if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
3862  else if constexpr (is_same_v<_Td, _Float64>)
3863  return type_identity<double>();
3864 #endif
3865 
3866 #if _GLIBCXX_FORMAT_F128
3867 # if __FLT128_DIG__
3868  else if constexpr (is_same_v<_Td, _Float128>)
3869  return type_identity<__format::__float128_t>();
3870 # endif
3871 # if __SIZEOF_FLOAT128__
3872  else if constexpr (is_same_v<_Td, __float128>)
3873  return type_identity<__format::__float128_t>();
3874 # endif
3875 #endif
3876  else if constexpr (__is_specialization_of<_Td, basic_string_view>
3877  || __is_specialization_of<_Td, basic_string>)
3878  {
3879  if constexpr (is_same_v<typename _Td::value_type, _CharT>)
3880  return type_identity<basic_string_view<_CharT>>();
3881  else
3882  return type_identity<handle>();
3883  }
3884  else if constexpr (is_same_v<decay_t<_Td>, const _CharT*>)
3885  return type_identity<const _CharT*>();
3886  else if constexpr (is_same_v<decay_t<_Td>, _CharT*>)
3887  return type_identity<const _CharT*>();
3888  else if constexpr (is_void_v<remove_pointer_t<_Td>>)
3889  return type_identity<const void*>();
3890  else if constexpr (is_same_v<_Td, nullptr_t>)
3891  return type_identity<const void*>();
3892  else
3893  return type_identity<handle>();
3894  }
3895 
3896  // Transform a formattable type to the appropriate storage type.
3897  template<typename _Tp>
3898  using _Normalize = typename decltype(_S_to_arg_type<_Tp>())::type;
3899 
3900  // Get the _Arg_t value corresponding to a normalized type.
3901  template<typename _Tp>
3902  static consteval __format::_Arg_t
3903  _S_to_enum()
3904  {
3905  using namespace __format;
3906  if constexpr (is_same_v<_Tp, bool>)
3907  return _Arg_bool;
3908  else if constexpr (is_same_v<_Tp, _CharT>)
3909  return _Arg_c;
3910  else if constexpr (is_same_v<_Tp, int>)
3911  return _Arg_i;
3912  else if constexpr (is_same_v<_Tp, unsigned>)
3913  return _Arg_u;
3914  else if constexpr (is_same_v<_Tp, long long>)
3915  return _Arg_ll;
3916  else if constexpr (is_same_v<_Tp, unsigned long long>)
3917  return _Arg_ull;
3918  else if constexpr (is_same_v<_Tp, float>)
3919  return _Arg_flt;
3920  else if constexpr (is_same_v<_Tp, double>)
3921  return _Arg_dbl;
3922 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
3923  else if constexpr (is_same_v<_Tp, long double>)
3924  return _Arg_ldbl;
3925 #else
3926  // Don't use _Arg_ldbl for this target, it's ambiguous.
3927  else if constexpr (is_same_v<_Tp, __ibm128>)
3928  return _Arg_ibm128;
3929  else if constexpr (is_same_v<_Tp, __ieee128>)
3930  return _Arg_f128;
3931 #endif
3932  else if constexpr (is_same_v<_Tp, const _CharT*>)
3933  return _Arg_str;
3934  else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
3935  return _Arg_sv;
3936  else if constexpr (is_same_v<_Tp, const void*>)
3937  return _Arg_ptr;
3938 #ifdef __SIZEOF_INT128__
3939  else if constexpr (is_same_v<_Tp, __int128>)
3940  return _Arg_i128;
3941  else if constexpr (is_same_v<_Tp, unsigned __int128>)
3942  return _Arg_u128;
3943 #endif
3944 
3945 #if _GLIBCXX_FORMAT_F128 == 2
3946  else if constexpr (is_same_v<_Tp, __format::__float128_t>)
3947  return _Arg_f128;
3948 #endif
3949  else if constexpr (is_same_v<_Tp, handle>)
3950  return _Arg_handle;
3951  }
3952 
3953  template<typename _Tp>
3954  void
3955  _M_set(_Tp __v) noexcept
3956  {
3957  _M_type = _S_to_enum<_Tp>();
3958  _M_val._M_set(__v);
3959  }
3960 
3961  template<typename _Tp>
3962  requires __format::__formattable_with<_Tp, _Context>
3963  explicit
3964  basic_format_arg(_Tp& __v) noexcept
3965  {
3966  using _Td = _Normalize<_Tp>;
3967  if constexpr (is_same_v<_Td, basic_string_view<_CharT>>)
3968  _M_set(_Td{__v.data(), __v.size()});
3969  else if constexpr (is_same_v<remove_const_t<_Tp>, char>
3970  && is_same_v<_CharT, wchar_t>)
3971  _M_set(static_cast<_Td>(static_cast<unsigned char>(__v)));
3972  else
3973  _M_set(static_cast<_Td>(__v));
3974  }
3975 
3976  template<typename _Ctx, typename... _Argz>
3977  friend auto
3978  make_format_args(_Argz&...) noexcept;
3979 
3980  template<typename _Visitor, typename _Ctx>
3981  friend decltype(auto)
3982  visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>);
3983 
3984  template<typename _Visitor, typename _Ctx>
3985  friend decltype(auto)
3986  __format::__visit_format_arg(_Visitor&&, basic_format_arg<_Ctx>);
3987 
3988  template<typename _Ch, typename _Tp>
3989  friend consteval __format::_Arg_t
3990  __format::__to_arg_t_enum() noexcept;
3991 
3992  template<typename _Visitor>
3993  decltype(auto)
3994  _M_visit(_Visitor&& __vis, __format::_Arg_t __type)
3995  {
3996  using namespace __format;
3997  switch (__type)
3998  {
3999  case _Arg_none:
4000  return std::forward<_Visitor>(__vis)(_M_val._M_none);
4001  case _Arg_bool:
4002  return std::forward<_Visitor>(__vis)(_M_val._M_bool);
4003  case _Arg_c:
4004  return std::forward<_Visitor>(__vis)(_M_val._M_c);
4005  case _Arg_i:
4006  return std::forward<_Visitor>(__vis)(_M_val._M_i);
4007  case _Arg_u:
4008  return std::forward<_Visitor>(__vis)(_M_val._M_u);
4009  case _Arg_ll:
4010  return std::forward<_Visitor>(__vis)(_M_val._M_ll);
4011  case _Arg_ull:
4012  return std::forward<_Visitor>(__vis)(_M_val._M_ull);
4013 #if __glibcxx_to_chars // FIXME: need to be able to format these types!
4014  case _Arg_flt:
4015  return std::forward<_Visitor>(__vis)(_M_val._M_flt);
4016  case _Arg_dbl:
4017  return std::forward<_Visitor>(__vis)(_M_val._M_dbl);
4018 #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
4019  case _Arg_ldbl:
4020  return std::forward<_Visitor>(__vis)(_M_val._M_ldbl);
4021 #else
4022  case _Arg_f128:
4023  return std::forward<_Visitor>(__vis)(_M_val._M_f128);
4024  case _Arg_ibm128:
4025  return std::forward<_Visitor>(__vis)(_M_val._M_ibm128);
4026 #endif
4027 #endif
4028  case _Arg_str:
4029  return std::forward<_Visitor>(__vis)(_M_val._M_str);
4030  case _Arg_sv:
4031  return std::forward<_Visitor>(__vis)(_M_val._M_sv);
4032  case _Arg_ptr:
4033  return std::forward<_Visitor>(__vis)(_M_val._M_ptr);
4034  case _Arg_handle:
4035  {
4036  auto& __h = static_cast<handle&>(_M_val._M_handle);
4037  return std::forward<_Visitor>(__vis)(__h);
4038  }
4039 #ifdef __SIZEOF_INT128__
4040  case _Arg_i128:
4041  return std::forward<_Visitor>(__vis)(_M_val._M_i128);
4042  case _Arg_u128:
4043  return std::forward<_Visitor>(__vis)(_M_val._M_u128);
4044 #endif
4045 
4046 #if _GLIBCXX_FORMAT_F128 == 2
4047  case _Arg_f128:
4048  return std::forward<_Visitor>(__vis)(_M_val._M_f128);
4049 #endif
4050 
4051  default:
4052  // _Arg_f16 etc.
4053  __builtin_unreachable();
4054  }
4055  }
4056 
4057  template<typename _Visitor>
4058  decltype(auto)
4059  _M_visit_user(_Visitor&& __vis, __format::_Arg_t __type)
4060  {
4061  return _M_visit([&__vis]<typename _Tp>(_Tp& __val) -> decltype(auto)
4062  {
4063  constexpr bool __user_facing = __is_one_of<_Tp,
4064  monostate, bool, _CharT,
4065  int, unsigned int, long long int, unsigned long long int,
4066  float, double, long double,
4067  const _CharT*, basic_string_view<_CharT>,
4068  const void*, handle>::value;
4069  if constexpr (__user_facing)
4070  return std::forward<_Visitor>(__vis)(__val);
4071  else
4072  {
4073  handle __h(__val);
4074  return std::forward<_Visitor>(__vis)(__h);
4075  }
4076  }, __type);
4077  }
4078  };
4079 
4080  template<typename _Visitor, typename _Context>
4081  _GLIBCXX26_DEPRECATED_SUGGEST("std::basic_format_arg::visit")
4082  inline decltype(auto)
4083  visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg)
4084  {
4085  return __arg._M_visit_user(std::forward<_Visitor>(__vis), __arg._M_type);
4086  }
4087 
4088 /// @cond undocumented
4089 namespace __format
4090 {
4091  template<typename _Visitor, typename _Ctx>
4092  inline decltype(auto)
4093  __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg)
4094  {
4095  return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type);
4096  }
4097 
4098  struct _WidthPrecVisitor
4099  {
4100  template<typename _Tp>
4101  size_t
4102  operator()(_Tp& __arg) const
4103  {
4104  if constexpr (is_same_v<_Tp, monostate>)
4105  __format::__invalid_arg_id_in_format_string();
4106  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4107  // 3720. Restrict the valid types of arg-id for width and precision
4108  // 3721. Allow an arg-id with a value of zero for width
4109  else if constexpr (sizeof(_Tp) <= sizeof(long long))
4110  {
4111  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4112  // 3720. Restrict the valid types of arg-id for width and precision
4113  if constexpr (__is_unsigned_integer<_Tp>::value)
4114  return __arg;
4115  else if constexpr (__is_signed_integer<_Tp>::value)
4116  if (__arg >= 0)
4117  return __arg;
4118  }
4119  __throw_format_error("format error: argument used for width or "
4120  "precision must be a non-negative integer");
4121  }
4122  };
4123 
4124 #pragma GCC diagnostic push
4125 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
4126  template<typename _Context>
4127  inline size_t
4128  __int_from_arg(const basic_format_arg<_Context>& __arg)
4129  { return __format::__visit_format_arg(_WidthPrecVisitor(), __arg); }
4130 
4131  // Pack _Arg_t enum values into a single 60-bit integer.
4132  template<int _Bits, size_t _Nm>
4133  constexpr auto
4134  __pack_arg_types(const array<_Arg_t, _Nm>& __types)
4135  {
4136  __UINT64_TYPE__ __packed_types = 0;
4137  for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i)
4138  __packed_types = (__packed_types << _Bits) | *__i;
4139  return __packed_types;
4140  }
4141 } // namespace __format
4142 /// @endcond
4143 
4144  template<typename _Context>
4145  class basic_format_args
4146  {
4147  static constexpr int _S_packed_type_bits = 5; // _Arg_t values [0,20]
4148  static constexpr int _S_packed_type_mask = 0b11111;
4149  static constexpr int _S_max_packed_args = 12;
4150 
4151  static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) );
4152 
4153  template<typename... _Args>
4154  using _Store = __format::_Arg_store<_Context, _Args...>;
4155 
4156  template<typename _Ctx, typename... _Args>
4157  friend class __format::_Arg_store;
4158 
4159  using uint64_t = __UINT64_TYPE__;
4160  using _Format_arg = basic_format_arg<_Context>;
4161  using _Format_arg_val = __format::_Arg_value<_Context>;
4162 
4163  // If args are packed then the number of args is in _M_packed_size and
4164  // the packed types are in _M_unpacked_size, accessed via _M_type(i).
4165  // If args are not packed then the number of args is in _M_unpacked_size
4166  // and _M_packed_size is zero.
4167  uint64_t _M_packed_size : 4;
4168  uint64_t _M_unpacked_size : 60;
4169 
4170  union {
4171  const _Format_arg_val* _M_values; // Active when _M_packed_size != 0
4172  const _Format_arg* _M_args; // Active when _M_packed_size == 0
4173  };
4174 
4175  size_t
4176  _M_size() const noexcept
4177  { return _M_packed_size ? _M_packed_size : _M_unpacked_size; }
4178 
4179  typename __format::_Arg_t
4180  _M_type(size_t __i) const noexcept
4181  {
4182  uint64_t __t = _M_unpacked_size >> (__i * _S_packed_type_bits);
4183  return static_cast<__format::_Arg_t>(__t & _S_packed_type_mask);
4184  }
4185 
4186  template<typename _Ctx, typename... _Args>
4187  friend auto
4188  make_format_args(_Args&...) noexcept;
4189 
4190  // An array of _Arg_t enums corresponding to _Args...
4191  template<typename... _Args>
4192  static consteval array<__format::_Arg_t, sizeof...(_Args)>
4193  _S_types_to_pack()
4194  { return {_Format_arg::template _S_to_enum<_Args>()...}; }
4195 
4196  public:
4197  template<typename... _Args>
4198  basic_format_args(const _Store<_Args...>& __store) noexcept;
4199 
4200  [[nodiscard,__gnu__::__always_inline__]]
4201  basic_format_arg<_Context>
4202  get(size_t __i) const noexcept
4203  {
4204  basic_format_arg<_Context> __arg;
4205  if (__i < _M_packed_size)
4206  {
4207  __arg._M_type = _M_type(__i);
4208  __arg._M_val = _M_values[__i];
4209  }
4210  else if (_M_packed_size == 0 && __i < _M_unpacked_size)
4211  __arg = _M_args[__i];
4212  return __arg;
4213  }
4214  };
4215 
4216  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4217  // 3810. CTAD for std::basic_format_args
4218  template<typename _Context, typename... _Args>
4219  basic_format_args(__format::_Arg_store<_Context, _Args...>)
4220  -> basic_format_args<_Context>;
4221 
4222  template<typename _Context, typename... _Args>
4223  auto
4224  make_format_args(_Args&... __fmt_args) noexcept;
4225 
4226  // An array of type-erased formatting arguments.
4227  template<typename _Context, typename... _Args>
4228  class __format::_Arg_store
4229  {
4230  friend std::basic_format_args<_Context>;
4231 
4232  template<typename _Ctx, typename... _Argz>
4233  friend auto std::
4234 #if _GLIBCXX_INLINE_VERSION
4235  __8:: // Needed for PR c++/59256
4236 #endif
4237  make_format_args(_Argz&...) noexcept;
4238 
4239  // For a sufficiently small number of arguments we only store values.
4240  // basic_format_args can get the types from the _Args pack.
4241  static constexpr bool _S_values_only
4242  = sizeof...(_Args) <= basic_format_args<_Context>::_S_max_packed_args;
4243 
4244  using _Element_t
4245  = __conditional_t<_S_values_only,
4246  __format::_Arg_value<_Context>,
4247  basic_format_arg<_Context>>;
4248 
4249  _Element_t _M_args[sizeof...(_Args)];
4250 
4251  template<typename _Tp>
4252  static _Element_t
4253  _S_make_elt(_Tp& __v)
4254  {
4255  using _Tq = remove_const_t<_Tp>;
4256  using _CharT = typename _Context::char_type;
4257  static_assert(is_default_constructible_v<formatter<_Tq, _CharT>>,
4258  "std::formatter must be specialized for the type "
4259  "of each format arg");
4260  using __format::__formattable_with;
4261  if constexpr (is_const_v<_Tp>)
4262  if constexpr (!__formattable_with<_Tp, _Context>)
4263  if constexpr (__formattable_with<_Tq, _Context>)
4264  static_assert(__formattable_with<_Tp, _Context>,
4265  "format arg must be non-const because its "
4266  "std::formatter specialization has a "
4267  "non-const reference parameter");
4268  basic_format_arg<_Context> __arg(__v);
4269  if constexpr (_S_values_only)
4270  return __arg._M_val;
4271  else
4272  return __arg;
4273  }
4274 
4275  template<typename... _Tp>
4276  requires (sizeof...(_Tp) == sizeof...(_Args))
4277  [[__gnu__::__always_inline__]]
4278  _Arg_store(_Tp&... __a) noexcept
4279  : _M_args{_S_make_elt(__a)...}
4280  { }
4281  };
4282 
4283  template<typename _Context>
4284  class __format::_Arg_store<_Context>
4285  { };
4286 
4287  template<typename _Context>
4288  template<typename... _Args>
4289  inline
4290  basic_format_args<_Context>::
4291  basic_format_args(const _Store<_Args...>& __store) noexcept
4292  {
4293  if constexpr (sizeof...(_Args) == 0)
4294  {
4295  _M_packed_size = 0;
4296  _M_unpacked_size = 0;
4297  _M_args = nullptr;
4298  }
4299  else if constexpr (sizeof...(_Args) <= _S_max_packed_args)
4300  {
4301  // The number of packed arguments:
4302  _M_packed_size = sizeof...(_Args);
4303  // The packed type enums:
4304  _M_unpacked_size
4305  = __format::__pack_arg_types<_S_packed_type_bits>(_S_types_to_pack<_Args...>());
4306  // The _Arg_value objects.
4307  _M_values = __store._M_args;
4308  }
4309  else
4310  {
4311  // No packed arguments:
4312  _M_packed_size = 0;
4313  // The number of unpacked arguments:
4314  _M_unpacked_size = sizeof...(_Args);
4315  // The basic_format_arg objects:
4316  _M_args = __store._M_args;
4317  }
4318  }
4319 
4320  /// Capture formatting arguments for use by `std::vformat`.
4321  template<typename _Context = format_context, typename... _Args>
4322  [[nodiscard,__gnu__::__always_inline__]]
4323  inline auto
4324  make_format_args(_Args&... __fmt_args) noexcept
4325  {
4326  using _Fmt_arg = basic_format_arg<_Context>;
4327  using _Store = __format::_Arg_store<_Context, typename _Fmt_arg::template
4328  _Normalize<_Args>...>;
4329  return _Store(__fmt_args...);
4330  }
4331 
4332 #ifdef _GLIBCXX_USE_WCHAR_T
4333  /// Capture formatting arguments for use by `std::vformat` (for wide output).
4334  template<typename... _Args>
4335  [[nodiscard,__gnu__::__always_inline__]]
4336  inline auto
4337  make_wformat_args(_Args&... __args) noexcept
4338  { return std::make_format_args<wformat_context>(__args...); }
4339 #endif
4340 
4341 /// @cond undocumented
4342 namespace __format
4343 {
4344  template<typename _Out, typename _CharT, typename _Context>
4345  _Out
4346  __do_vformat_to(_Out, basic_string_view<_CharT>,
4347  const basic_format_args<_Context>&,
4348  const locale* = nullptr);
4349 
4350  template<typename _CharT> struct __formatter_chrono;
4351 
4352 } // namespace __format
4353 /// @endcond
4354 
4355  /** Context for std::format and similar functions.
4356  *
4357  * A formatting context contains an output iterator and locale to use
4358  * for the formatting operations. Most programs will never need to use
4359  * this class template explicitly. For typical uses of `std::format` the
4360  * library will use the specializations `std::format_context` (for `char`)
4361  * and `std::wformat_context` (for `wchar_t`).
4362  *
4363  * You are not allowed to define partial or explicit specializations of
4364  * this class template.
4365  *
4366  * @since C++20
4367  */
4368  template<typename _Out, typename _CharT>
4369  class basic_format_context
4370  {
4371  static_assert( output_iterator<_Out, const _CharT&> );
4372 
4373  basic_format_args<basic_format_context> _M_args;
4374  _Out _M_out;
4375  __format::_Optional_locale _M_loc;
4376 
4377  basic_format_context(basic_format_args<basic_format_context> __args,
4378  _Out __out)
4379  : _M_args(__args), _M_out(std::move(__out))
4380  { }
4381 
4382  basic_format_context(basic_format_args<basic_format_context> __args,
4383  _Out __out, const std::locale& __loc)
4384  : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc)
4385  { }
4386 
4387  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4388  // 4061. Should std::basic_format_context be
4389  // default-constructible/copyable/movable?
4390  basic_format_context(const basic_format_context&) = delete;
4391  basic_format_context& operator=(const basic_format_context&) = delete;
4392 
4393  template<typename _Out2, typename _CharT2, typename _Context2>
4394  friend _Out2
4395  __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>,
4396  const basic_format_args<_Context2>&,
4397  const locale*);
4398 
4399  friend __format::__formatter_chrono<_CharT>;
4400 
4401  public:
4402  ~basic_format_context() = default;
4403 
4404  using iterator = _Out;
4405  using char_type = _CharT;
4406  template<typename _Tp>
4407  using formatter_type = formatter<_Tp, _CharT>;
4408 
4409  [[nodiscard]]
4410  basic_format_arg<basic_format_context>
4411  arg(size_t __id) const noexcept
4412  { return _M_args.get(__id); }
4413 
4414  [[nodiscard]]
4415  std::locale locale() { return _M_loc.value(); }
4416 
4417  [[nodiscard]]
4418  iterator out() { return std::move(_M_out); }
4419 
4420  void advance_to(iterator __it) { _M_out = std::move(__it); }
4421  };
4422 
4423 
4424 /// @cond undocumented
4425 namespace __format
4426 {
4427  // Abstract base class defining an interface for scanning format strings.
4428  // Scan the characters in a format string, dividing it up into strings of
4429  // ordinary characters, escape sequences, and replacement fields.
4430  // Call virtual functions for derived classes to parse format-specifiers
4431  // or write formatted output.
4432  template<typename _CharT>
4433  struct _Scanner
4434  {
4435  using iterator = typename basic_format_parse_context<_CharT>::iterator;
4436 
4437  struct _Parse_context : basic_format_parse_context<_CharT>
4438  {
4439  using basic_format_parse_context<_CharT>::basic_format_parse_context;
4440  const _Arg_t* _M_types = nullptr;
4441  } _M_pc;
4442 
4443  constexpr explicit
4444  _Scanner(basic_string_view<_CharT> __str, size_t __nargs = (size_t)-1)
4445  : _M_pc(__str, __nargs)
4446  { }
4447 
4448  constexpr iterator begin() const noexcept { return _M_pc.begin(); }
4449  constexpr iterator end() const noexcept { return _M_pc.end(); }
4450 
4451  constexpr void
4452  _M_scan()
4453  {
4454  basic_string_view<_CharT> __fmt = _M_fmt_str();
4455 
4456  if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] == '}')
4457  {
4458  _M_pc.advance_to(begin() + 1);
4459  _M_format_arg(_M_pc.next_arg_id());
4460  return;
4461  }
4462 
4463  size_t __lbr = __fmt.find('{');
4464  size_t __rbr = __fmt.find('}');
4465 
4466  while (__fmt.size())
4467  {
4468  auto __cmp = __lbr <=> __rbr;
4469  if (__cmp == 0)
4470  {
4471  _M_on_chars(end());
4472  _M_pc.advance_to(end());
4473  return;
4474  }
4475  else if (__cmp < 0)
4476  {
4477  if (__lbr + 1 == __fmt.size()
4478  || (__rbr == __fmt.npos && __fmt[__lbr + 1] != '{'))
4479  __format::__unmatched_left_brace_in_format_string();
4480  const bool __is_escape = __fmt[__lbr + 1] == '{';
4481  iterator __last = begin() + __lbr + int(__is_escape);
4482  _M_on_chars(__last);
4483  _M_pc.advance_to(__last + 1);
4484  __fmt = _M_fmt_str();
4485  if (__is_escape)
4486  {
4487  if (__rbr != __fmt.npos)
4488  __rbr -= __lbr + 2;
4489  __lbr = __fmt.find('{');
4490  }
4491  else
4492  {
4493  _M_on_replacement_field();
4494  __fmt = _M_fmt_str();
4495  __lbr = __fmt.find('{');
4496  __rbr = __fmt.find('}');
4497  }
4498  }
4499  else
4500  {
4501  if (++__rbr == __fmt.size() || __fmt[__rbr] != '}')
4502  __format::__unmatched_right_brace_in_format_string();
4503  iterator __last = begin() + __rbr;
4504  _M_on_chars(__last);
4505  _M_pc.advance_to(__last + 1);
4506  __fmt = _M_fmt_str();
4507  if (__lbr != __fmt.npos)
4508  __lbr -= __rbr + 1;
4509  __rbr = __fmt.find('}');
4510  }
4511  }
4512  }
4513 
4514  constexpr basic_string_view<_CharT>
4515  _M_fmt_str() const noexcept
4516  { return {begin(), end()}; }
4517 
4518  constexpr virtual void _M_on_chars(iterator) { }
4519 
4520  constexpr void _M_on_replacement_field()
4521  {
4522  auto __next = begin();
4523 
4524  size_t __id;
4525  if (*__next == '}')
4526  __id = _M_pc.next_arg_id();
4527  else if (*__next == ':')
4528  {
4529  __id = _M_pc.next_arg_id();
4530  _M_pc.advance_to(++__next);
4531  }
4532  else
4533  {
4534  auto [__i, __ptr] = __format::__parse_arg_id(begin(), end());
4535  if (!__ptr || !(*__ptr == '}' || *__ptr == ':'))
4536  __format::__invalid_arg_id_in_format_string();
4537  _M_pc.check_arg_id(__id = __i);
4538  if (*__ptr == ':')
4539  {
4540  _M_pc.advance_to(++__ptr);
4541  }
4542  else
4543  _M_pc.advance_to(__ptr);
4544  }
4545  _M_format_arg(__id);
4546  if (begin() == end() || *begin() != '}')
4547  __format::__unmatched_left_brace_in_format_string();
4548  _M_pc.advance_to(begin() + 1); // Move past '}'
4549  }
4550 
4551  constexpr virtual void _M_format_arg(size_t __id) = 0;
4552  };
4553 
4554  // Process a format string and format the arguments in the context.
4555  template<typename _Out, typename _CharT>
4556  class _Formatting_scanner : public _Scanner<_CharT>
4557  {
4558  public:
4559  _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc,
4560  basic_string_view<_CharT> __str)
4561  : _Scanner<_CharT>(__str), _M_fc(__fc)
4562  { }
4563 
4564  private:
4565  basic_format_context<_Out, _CharT>& _M_fc;
4566 
4567  using iterator = typename _Scanner<_CharT>::iterator;
4568 
4569  constexpr void
4570  _M_on_chars(iterator __last) override
4571  {
4572  basic_string_view<_CharT> __str(this->begin(), __last);
4573  _M_fc.advance_to(__format::__write(_M_fc.out(), __str));
4574  }
4575 
4576  constexpr void
4577  _M_format_arg(size_t __id) override
4578  {
4579  using _Context = basic_format_context<_Out, _CharT>;
4580  using handle = typename basic_format_arg<_Context>::handle;
4581 
4582  __format::__visit_format_arg([this](auto& __arg) {
4583  using _Type = remove_reference_t<decltype(__arg)>;
4584  using _Formatter = typename _Context::template formatter_type<_Type>;
4585  if constexpr (is_same_v<_Type, monostate>)
4586  __format::__invalid_arg_id_in_format_string();
4587  else if constexpr (is_same_v<_Type, handle>)
4588  __arg.format(this->_M_pc, this->_M_fc);
4589  else if constexpr (is_default_constructible_v<_Formatter>)
4590  {
4591  _Formatter __f;
4592  this->_M_pc.advance_to(__f.parse(this->_M_pc));
4593  this->_M_fc.advance_to(__f.format(__arg, this->_M_fc));
4594  }
4595  else
4596  static_assert(__format::__formattable_with<_Type, _Context>);
4597  }, _M_fc.arg(__id));
4598  }
4599  };
4600 
4601  template<typename _CharT, typename _Tp>
4602  consteval _Arg_t
4603  __to_arg_t_enum() noexcept
4604  {
4605  using _Context = __format::__format_context<_CharT>;
4606  using _Fmt_arg = basic_format_arg<_Context>;
4607  using _NormalizedTp = typename _Fmt_arg::template _Normalize<_Tp>;
4608  return _Fmt_arg::template _S_to_enum<_NormalizedTp>();
4609  }
4610 
4611  // Validate a format string for Args.
4612  template<typename _CharT, typename... _Args>
4613  class _Checking_scanner : public _Scanner<_CharT>
4614  {
4615  static_assert(
4616  (is_default_constructible_v<formatter<_Args, _CharT>> && ...),
4617  "std::formatter must be specialized for each type being formatted");
4618 
4619  public:
4620  consteval
4621  _Checking_scanner(basic_string_view<_CharT> __str)
4622  : _Scanner<_CharT>(__str, sizeof...(_Args))
4623  {
4624 #if __cpp_lib_format >= 202305L
4625  this->_M_pc._M_types = _M_types.data();
4626 #endif
4627  }
4628 
4629  private:
4630  constexpr void
4631  _M_format_arg(size_t __id) override
4632  {
4633  if constexpr (sizeof...(_Args) != 0)
4634  {
4635  if (__id < sizeof...(_Args))
4636  {
4637  _M_parse_format_spec<_Args...>(__id);
4638  return;
4639  }
4640  }
4641  __builtin_unreachable();
4642  }
4643 
4644  template<typename _Tp, typename... _OtherArgs>
4645  constexpr void
4646  _M_parse_format_spec(size_t __id)
4647  {
4648  if (__id == 0)
4649  {
4650  formatter<_Tp, _CharT> __f;
4651  this->_M_pc.advance_to(__f.parse(this->_M_pc));
4652  }
4653  else if constexpr (sizeof...(_OtherArgs) != 0)
4654  _M_parse_format_spec<_OtherArgs...>(__id - 1);
4655  else
4656  __builtin_unreachable();
4657  }
4658 
4659 #if __cpp_lib_format >= 202305L
4660  array<_Arg_t, sizeof...(_Args)>
4661  _M_types{ { __format::__to_arg_t_enum<_CharT, _Args>()... } };
4662 #endif
4663  };
4664 
4665  template<typename _Out, typename _CharT, typename _Context>
4666  inline _Out
4667  __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
4668  const basic_format_args<_Context>& __args,
4669  const locale* __loc)
4670  {
4671  _Iter_sink<_CharT, _Out> __sink(std::move(__out));
4672  _Sink_iter<_CharT> __sink_out;
4673 
4674  if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
4675  __sink_out = __out; // Already a sink iterator, safe to use post-move.
4676  else
4677  __sink_out = __sink.out();
4678 
4679  if constexpr (is_same_v<_CharT, char>)
4680  // Fast path for "{}" format strings and simple format arg types.
4681  if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] == '}')
4682  {
4683  bool __done = false;
4684  __format::__visit_format_arg([&](auto& __arg) {
4685  using _Tp = remove_cvref_t<decltype(__arg)>;
4686  if constexpr (is_same_v<_Tp, bool>)
4687  {
4688  size_t __len = 4 + !__arg;
4689  const char* __chars[] = { "false", "true" };
4690  if (auto __res = __sink_out._M_reserve(__len))
4691  {
4692  __builtin_memcpy(__res.get(), __chars[__arg], __len);
4693  __res._M_bump(__len);
4694  __done = true;
4695  }
4696  }
4697  else if constexpr (is_same_v<_Tp, char>)
4698  {
4699  if (auto __res = __sink_out._M_reserve(1))
4700  {
4701  *__res.get() = __arg;
4702  __res._M_bump(1);
4703  __done = true;
4704  }
4705  }
4706  else if constexpr (is_integral_v<_Tp>)
4707  {
4708  make_unsigned_t<_Tp> __uval;
4709  const bool __neg = __arg < 0;
4710  if (__neg)
4711  __uval = make_unsigned_t<_Tp>(~__arg) + 1u;
4712  else
4713  __uval = __arg;
4714  const auto __n = __detail::__to_chars_len(__uval);
4715  if (auto __res = __sink_out._M_reserve(__n + __neg))
4716  {
4717  auto __ptr = __res.get();
4718  *__ptr = '-';
4719  __detail::__to_chars_10_impl(__ptr + (int)__neg, __n,
4720  __uval);
4721  __res._M_bump(__n + __neg);
4722  __done = true;
4723  }
4724  }
4725  else if constexpr (is_convertible_v<_Tp, string_view>)
4726  {
4727  string_view __sv = __arg;
4728  if (auto __res = __sink_out._M_reserve(__sv.size()))
4729  {
4730  __builtin_memcpy(__res.get(), __sv.data(), __sv.size());
4731  __res._M_bump(__sv.size());
4732  __done = true;
4733  }
4734  }
4735  }, __args.get(0));
4736 
4737  if (__done)
4738  {
4739  if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
4740  return __sink_out;
4741  else
4742  return std::move(__sink)._M_finish().out;
4743  }
4744  }
4745 
4746  auto __ctx = __loc == nullptr
4747  ? _Context(__args, __sink_out)
4748  : _Context(__args, __sink_out, *__loc);
4749  _Formatting_scanner<_Sink_iter<_CharT>, _CharT> __scanner(__ctx, __fmt);
4750  __scanner._M_scan();
4751 
4752  if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
4753  return __ctx.out();
4754  else
4755  return std::move(__sink)._M_finish().out;
4756  }
4757 #pragma GCC diagnostic pop
4758 
4759 } // namespace __format
4760 /// @endcond
4761 
4762 #if __cpp_lib_format >= 202305L // >= C++26
4763  /// @cond undocumented
4764  // Common implementation of check_dynamic_spec{,_string,_integral}
4765  template<typename _CharT>
4766  template<typename... _Ts>
4767  consteval void
4768  basic_format_parse_context<_CharT>::
4769  __check_dynamic_spec(size_t __id) noexcept
4770  {
4771  if (__id >= _M_num_args)
4772  __format::__invalid_arg_id_in_format_string();
4773  if constexpr (sizeof...(_Ts) != 0)
4774  {
4775  using _Parse_ctx = __format::_Scanner<_CharT>::_Parse_context;
4776  auto __arg = static_cast<_Parse_ctx*>(this)->_M_types[__id];
4777  __format::_Arg_t __types[] = {
4778  __format::__to_arg_t_enum<_CharT, _Ts>()...
4779  };
4780  for (auto __t : __types)
4781  if (__arg == __t)
4782  return;
4783  }
4784  __invalid_dynamic_spec("arg(id) type does not match");
4785  }
4786  /// @endcond
4787 #endif
4788 
4789  template<typename _CharT, typename... _Args>
4790  template<typename _Tp>
4791  requires convertible_to<const _Tp&, basic_string_view<_CharT>>
4792  consteval
4793  basic_format_string<_CharT, _Args...>::
4794  basic_format_string(const _Tp& __s)
4795  : _M_str(__s)
4796  {
4797  __format::_Checking_scanner<_CharT, remove_cvref_t<_Args>...>
4798  __scanner(_M_str);
4799  __scanner._M_scan();
4800  }
4801 
4802  // [format.functions], formatting functions
4803 
4804  template<typename _Out> requires output_iterator<_Out, const char&>
4805  [[__gnu__::__always_inline__]]
4806  inline _Out
4807  vformat_to(_Out __out, string_view __fmt, format_args __args)
4808  { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
4809 
4810 #ifdef _GLIBCXX_USE_WCHAR_T
4811  template<typename _Out> requires output_iterator<_Out, const wchar_t&>
4812  [[__gnu__::__always_inline__]]
4813  inline _Out
4814  vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
4815  { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
4816 #endif
4817 
4818  template<typename _Out> requires output_iterator<_Out, const char&>
4819  [[__gnu__::__always_inline__]]
4820  inline _Out
4821  vformat_to(_Out __out, const locale& __loc, string_view __fmt,
4822  format_args __args)
4823  {
4824  return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc);
4825  }
4826 
4827 #ifdef _GLIBCXX_USE_WCHAR_T
4828  template<typename _Out> requires output_iterator<_Out, const wchar_t&>
4829  [[__gnu__::__always_inline__]]
4830  inline _Out
4831  vformat_to(_Out __out, const locale& __loc, wstring_view __fmt,
4832  wformat_args __args)
4833  {
4834  return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc);
4835  }
4836 #endif
4837 
4838  [[nodiscard]]
4839  inline string
4840  vformat(string_view __fmt, format_args __args)
4841  {
4842  __format::_Str_sink<char> __buf;
4843  std::vformat_to(__buf.out(), __fmt, __args);
4844  return std::move(__buf).get();
4845  }
4846 
4847 #ifdef _GLIBCXX_USE_WCHAR_T
4848  [[nodiscard]]
4849  inline wstring
4850  vformat(wstring_view __fmt, wformat_args __args)
4851  {
4852  __format::_Str_sink<wchar_t> __buf;
4853  std::vformat_to(__buf.out(), __fmt, __args);
4854  return std::move(__buf).get();
4855  }
4856 #endif
4857 
4858  [[nodiscard]]
4859  inline string
4860  vformat(const locale& __loc, string_view __fmt, format_args __args)
4861  {
4862  __format::_Str_sink<char> __buf;
4863  std::vformat_to(__buf.out(), __loc, __fmt, __args);
4864  return std::move(__buf).get();
4865  }
4866 
4867 #ifdef _GLIBCXX_USE_WCHAR_T
4868  [[nodiscard]]
4869  inline wstring
4870  vformat(const locale& __loc, wstring_view __fmt, wformat_args __args)
4871  {
4872  __format::_Str_sink<wchar_t> __buf;
4873  std::vformat_to(__buf.out(), __loc, __fmt, __args);
4874  return std::move(__buf).get();
4875  }
4876 #endif
4877 
4878  template<typename... _Args>
4879  [[nodiscard]]
4880  inline string
4881  format(format_string<_Args...> __fmt, _Args&&... __args)
4882  { return std::vformat(__fmt.get(), std::make_format_args(__args...)); }
4883 
4884 #ifdef _GLIBCXX_USE_WCHAR_T
4885  template<typename... _Args>
4886  [[nodiscard]]
4887  inline wstring
4888  format(wformat_string<_Args...> __fmt, _Args&&... __args)
4889  { return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); }
4890 #endif
4891 
4892  template<typename... _Args>
4893  [[nodiscard]]
4894  inline string
4895  format(const locale& __loc, format_string<_Args...> __fmt,
4896  _Args&&... __args)
4897  {
4898  return std::vformat(__loc, __fmt.get(),
4899  std::make_format_args(__args...));
4900  }
4901 
4902 #ifdef _GLIBCXX_USE_WCHAR_T
4903  template<typename... _Args>
4904  [[nodiscard]]
4905  inline wstring
4906  format(const locale& __loc, wformat_string<_Args...> __fmt,
4907  _Args&&... __args)
4908  {
4909  return std::vformat(__loc, __fmt.get(),
4910  std::make_wformat_args(__args...));
4911  }
4912 #endif
4913 
4914  template<typename _Out, typename... _Args>
4915  requires output_iterator<_Out, const char&>
4916  inline _Out
4917  format_to(_Out __out, format_string<_Args...> __fmt, _Args&&... __args)
4918  {
4919  return std::vformat_to(std::move(__out), __fmt.get(),
4920  std::make_format_args(__args...));
4921  }
4922 
4923 #ifdef _GLIBCXX_USE_WCHAR_T
4924  template<typename _Out, typename... _Args>
4925  requires output_iterator<_Out, const wchar_t&>
4926  inline _Out
4927  format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&... __args)
4928  {
4929  return std::vformat_to(std::move(__out), __fmt.get(),
4930  std::make_wformat_args(__args...));
4931  }
4932 #endif
4933 
4934  template<typename _Out, typename... _Args>
4935  requires output_iterator<_Out, const char&>
4936  inline _Out
4937  format_to(_Out __out, const locale& __loc, format_string<_Args...> __fmt,
4938  _Args&&... __args)
4939  {
4940  return std::vformat_to(std::move(__out), __loc, __fmt.get(),
4941  std::make_format_args(__args...));
4942  }
4943 
4944 #ifdef _GLIBCXX_USE_WCHAR_T
4945  template<typename _Out, typename... _Args>
4946  requires output_iterator<_Out, const wchar_t&>
4947  inline _Out
4948  format_to(_Out __out, const locale& __loc, wformat_string<_Args...> __fmt,
4949  _Args&&... __args)
4950  {
4951  return std::vformat_to(std::move(__out), __loc, __fmt.get(),
4952  std::make_wformat_args(__args...));
4953  }
4954 #endif
4955 
4956  template<typename _Out, typename... _Args>
4957  requires output_iterator<_Out, const char&>
4958  inline format_to_n_result<_Out>
4959  format_to_n(_Out __out, iter_difference_t<_Out> __n,
4960  format_string<_Args...> __fmt, _Args&&... __args)
4961  {
4962  __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n);
4963  std::vformat_to(__sink.out(), __fmt.get(),
4964  std::make_format_args(__args...));
4965  return std::move(__sink)._M_finish();
4966  }
4967 
4968 #ifdef _GLIBCXX_USE_WCHAR_T
4969  template<typename _Out, typename... _Args>
4970  requires output_iterator<_Out, const wchar_t&>
4971  inline format_to_n_result<_Out>
4972  format_to_n(_Out __out, iter_difference_t<_Out> __n,
4973  wformat_string<_Args...> __fmt, _Args&&... __args)
4974  {
4975  __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n);
4976  std::vformat_to(__sink.out(), __fmt.get(),
4977  std::make_wformat_args(__args...));
4978  return std::move(__sink)._M_finish();
4979  }
4980 #endif
4981 
4982  template<typename _Out, typename... _Args>
4983  requires output_iterator<_Out, const char&>
4984  inline format_to_n_result<_Out>
4985  format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc,
4986  format_string<_Args...> __fmt, _Args&&... __args)
4987  {
4988  __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n);
4989  std::vformat_to(__sink.out(), __loc, __fmt.get(),
4990  std::make_format_args(__args...));
4991  return std::move(__sink)._M_finish();
4992  }
4993 
4994 #ifdef _GLIBCXX_USE_WCHAR_T
4995  template<typename _Out, typename... _Args>
4996  requires output_iterator<_Out, const wchar_t&>
4997  inline format_to_n_result<_Out>
4998  format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc,
4999  wformat_string<_Args...> __fmt, _Args&&... __args)
5000  {
5001  __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n);
5002  std::vformat_to(__sink.out(), __loc, __fmt.get(),
5003  std::make_wformat_args(__args...));
5004  return std::move(__sink)._M_finish();
5005  }
5006 #endif
5007 
5008 /// @cond undocumented
5009 namespace __format
5010 {
5011 #if 1
5012  template<typename _CharT>
5013  class _Counting_sink final : public _Iter_sink<_CharT, _CharT*>
5014  {
5015  public:
5016  _Counting_sink() : _Iter_sink<_CharT, _CharT*>(nullptr, 0) { }
5017 
5018  [[__gnu__::__always_inline__]]
5019  size_t
5020  count() const
5021  { return this->_M_count + this->_M_used().size(); }
5022  };
5023 #else
5024  template<typename _CharT>
5025  class _Counting_sink : public _Buf_sink<_CharT>
5026  {
5027  size_t _M_count = 0;
5028 
5029  void
5030  _M_overflow() override
5031  {
5032  if (!std::is_constant_evaluated())
5033  _M_count += this->_M_used().size();
5034  this->_M_rewind();
5035  }
5036 
5037  public:
5038  _Counting_sink() = default;
5039 
5040  [[__gnu__::__always_inline__]]
5041  size_t
5042  count() noexcept
5043  {
5044  _Counting_sink::_M_overflow();
5045  return _M_count;
5046  }
5047  };
5048 #endif
5049 } // namespace __format
5050 /// @endcond
5051 
5052  template<typename... _Args>
5053  [[nodiscard]]
5054  inline size_t
5055  formatted_size(format_string<_Args...> __fmt, _Args&&... __args)
5056  {
5057  __format::_Counting_sink<char> __buf;
5058  std::vformat_to(__buf.out(), __fmt.get(),
5059  std::make_format_args(__args...));
5060  return __buf.count();
5061  }
5062 
5063 #ifdef _GLIBCXX_USE_WCHAR_T
5064  template<typename... _Args>
5065  [[nodiscard]]
5066  inline size_t
5067  formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args)
5068  {
5069  __format::_Counting_sink<wchar_t> __buf;
5070  std::vformat_to(__buf.out(), __fmt.get(),
5071  std::make_wformat_args(__args...));
5072  return __buf.count();
5073  }
5074 #endif
5075 
5076  template<typename... _Args>
5077  [[nodiscard]]
5078  inline size_t
5079  formatted_size(const locale& __loc, format_string<_Args...> __fmt,
5080  _Args&&... __args)
5081  {
5082  __format::_Counting_sink<char> __buf;
5083  std::vformat_to(__buf.out(), __loc, __fmt.get(),
5084  std::make_format_args(__args...));
5085  return __buf.count();
5086  }
5087 
5088 #ifdef _GLIBCXX_USE_WCHAR_T
5089  template<typename... _Args>
5090  [[nodiscard]]
5091  inline size_t
5092  formatted_size(const locale& __loc, wformat_string<_Args...> __fmt,
5093  _Args&&... __args)
5094  {
5095  __format::_Counting_sink<wchar_t> __buf;
5096  std::vformat_to(__buf.out(), __loc, __fmt.get(),
5097  std::make_wformat_args(__args...));
5098  return __buf.count();
5099  }
5100 #endif
5101 
5102 #if __glibcxx_format_ranges // C++ >= 23 && HOSTED
5103  // [format.range], formatting of ranges
5104  // [format.range.fmtkind], variable template format_kind
5105  enum class range_format {
5106  disabled,
5107  map,
5108  set,
5109  sequence,
5110  string,
5111  debug_string
5112  };
5113 
5114  /** @brief A constant determining how a range should be formatted.
5115  *
5116  * The primary template of `std::format_kind` cannot be instantiated.
5117  * There is a partial specialization for input ranges and you can
5118  * specialize the variable template for your own cv-unqualified types
5119  * that satisfy the `ranges::input_range` concept.
5120  *
5121  * @since C++23
5122  */
5123  template<typename _Rg>
5124  constexpr auto format_kind = []{
5125  static_assert(false, "cannot use primary template of 'std::format_kind'");
5126  return type_identity<_Rg>{};
5127  }();
5128 
5129  /// @cond undocumented
5130  template<typename _Tp>
5131  consteval range_format
5132  __fmt_kind()
5133  {
5134  using _Ref = ranges::range_reference_t<_Tp>;
5135  if constexpr (is_same_v<remove_cvref_t<_Ref>, _Tp>)
5136  return range_format::disabled;
5137  else if constexpr (requires { typename _Tp::key_type; })
5138  {
5139  if constexpr (requires { typename _Tp::mapped_type; })
5140  {
5141  using _Up = remove_cvref_t<_Ref>;
5142  if constexpr (__is_pair<_Up>)
5143  return range_format::map;
5144  else if constexpr (__is_specialization_of<_Up, tuple>)
5145  if constexpr (tuple_size_v<_Up> == 2)
5146  return range_format::map;
5147  }
5148  return range_format::set;
5149  }
5150  else
5151  return range_format::sequence;
5152  }
5153  /// @endcond
5154 
5155  /// A constant determining how a range should be formatted.
5156  template<ranges::input_range _Rg> requires same_as<_Rg, remove_cvref_t<_Rg>>
5157  constexpr range_format format_kind<_Rg> = __fmt_kind<_Rg>();
5158 
5159 /// @cond undocumented
5160 namespace __format
5161 {
5162  template<typename _CharT, typename _Out, typename _Callback>
5163  typename basic_format_context<_Out, _CharT>::iterator
5164  __format_padded(basic_format_context<_Out, _CharT>& __fc,
5165  const _Spec<_CharT>& __spec,
5166  _Callback&& __call)
5167  {
5168  // This is required to implement formatting with padding,
5169  // as we need to format to temporary buffer, using the same iterator.
5170  static_assert(is_same_v<_Out, __format::_Sink_iter<_CharT>>);
5171 
5172  if (__spec._M_get_width(__fc) == 0)
5173  return __call(__fc);
5174 
5175  struct _Restore_out
5176  {
5177  _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc)
5178  : _M_ctx(std::addressof(__fc)), _M_out(__fc.out())
5179  { }
5180 
5181  void _M_trigger()
5182  {
5183  if (_M_ctx)
5184  _M_ctx->advance_to(_M_out);
5185  _M_ctx = nullptr;
5186  }
5187 
5188  ~_Restore_out()
5189  { _M_trigger(); }
5190 
5191  private:
5192  basic_format_context<_Sink_iter<_CharT>, _CharT>* _M_ctx;
5193  _Sink_iter<_CharT> _M_out;
5194  };
5195 
5196  _Restore_out __restore(__fc);
5197  // TODO Consider double sinking, first buffer of width
5198  // size and then original sink, if first buffer is overun
5199  // we do not need to align
5200  _Str_sink<_CharT> __buf;
5201  __fc.advance_to(__buf.out());
5202  __call(__fc);
5203  __restore._M_trigger();
5204 
5205  basic_string_view<_CharT> __str(__buf.view());
5206  size_t __width;
5207  if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
5208  __width = __unicode::__field_width(__str);
5209  else
5210  __width = __str.size();
5211 
5212  return __format::__write_padded_as_spec(__str, __width, __fc, __spec);
5213  }
5214 
5215  // _Rg& and const _Rg& are both formattable and use same formatter
5216  // specialization for their references.
5217  template<typename _Rg, typename _CharT>
5218  concept __simply_formattable_range
5219  = __const_formattable_range<_Rg, _CharT>
5220  && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>,
5221  remove_cvref_t<ranges::range_reference_t<const _Rg>>>;
5222 
5223  template<size_t _Pos, typename _Tp, typename _CharT>
5224  struct __indexed_formatter_storage
5225  {
5226  constexpr void
5227  _M_parse()
5228  {
5229  basic_format_parse_context<_CharT> __pc({});
5230  if (_M_formatter.parse(__pc) != __pc.end())
5231  __format::__failed_to_parse_format_spec();
5232  }
5233 
5234  template<typename _Out>
5235  void
5236  _M_format(__maybe_const<_Tp, _CharT>& __elem,
5237  basic_format_context<_Out, _CharT>& __fc,
5238  basic_string_view<_CharT> __sep) const
5239  {
5240  if constexpr (_Pos != 0)
5241  __fc.advance_to(__format::__write(__fc.out(), __sep));
5242  __fc.advance_to(_M_formatter.format(__elem, __fc));
5243  }
5244 
5245  [[__gnu__::__always_inline__]]
5246  constexpr void
5247  set_debug_format()
5248  {
5249  if constexpr (__has_debug_format<formatter<_Tp, _CharT>>)
5250  _M_formatter.set_debug_format();
5251  }
5252 
5253  private:
5254  formatter<_Tp, _CharT> _M_formatter;
5255  };
5256 
5257  template<typename _CharT, typename... _Tps>
5258  class __tuple_formatter
5259  {
5260  using _String_view = basic_string_view<_CharT>;
5261  using _Seps = __format::_Separators<_CharT>;
5262 
5263  public:
5264  constexpr void
5265  set_separator(basic_string_view<_CharT> __sep) noexcept
5266  { _M_sep = __sep; }
5267 
5268  constexpr void
5269  set_brackets(basic_string_view<_CharT> __open,
5270  basic_string_view<_CharT> __close) noexcept
5271  {
5272  _M_open = __open;
5273  _M_close = __close;
5274  }
5275 
5276  // We deviate from standard, that declares this as template accepting
5277  // unconstrained ParseContext type, which seems unimplementable.
5278  constexpr typename basic_format_parse_context<_CharT>::iterator
5279  parse(basic_format_parse_context<_CharT>& __pc)
5280  {
5281  auto __first = __pc.begin();
5282  const auto __last = __pc.end();
5283  __format::_Spec<_CharT> __spec{};
5284 
5285  auto __finished = [&]
5286  {
5287  if (__first != __last && *__first != '}')
5288  return false;
5289 
5290  _M_spec = __spec;
5291  _M_felems._M_parse();
5292  _M_felems.set_debug_format();
5293  return true;
5294  };
5295 
5296  if (__finished())
5297  return __first;
5298 
5299  __first = __spec._M_parse_fill_and_align(__first, __last, "{:");
5300  if (__finished())
5301  return __first;
5302 
5303  __first = __spec._M_parse_width(__first, __last, __pc);
5304  if (__finished())
5305  return __first;
5306 
5307  if (*__first == 'n')
5308  {
5309  ++__first;
5310  _M_open = _M_close = _String_view();
5311  }
5312  else if (*__first == 'm')
5313  {
5314  ++__first;
5315  if constexpr (sizeof...(_Tps) == 2)
5316  {
5317  _M_sep = _Seps::_S_colon();
5318  _M_open = _M_close = _String_view();
5319  }
5320  else
5321  __throw_format_error("format error: 'm' specifier requires range"
5322  " of pair or tuple of two elements");
5323  }
5324 
5325  if (__finished())
5326  return __first;
5327 
5328  __format::__failed_to_parse_format_spec();
5329  }
5330 
5331  protected:
5332  template<typename _Tuple, typename _Out, size_t... _Ids>
5333  typename basic_format_context<_Out, _CharT>::iterator
5334  _M_format(_Tuple& __tuple, index_sequence<_Ids...>,
5335  basic_format_context<_Out, _CharT>& __fc) const
5336  { return _M_format_elems(std::get<_Ids>(__tuple)..., __fc); }
5337 
5338  template<typename _Out>
5339  typename basic_format_context<_Out, _CharT>::iterator
5340  _M_format_elems(__maybe_const<_Tps, _CharT>&... __elems,
5341  basic_format_context<_Out, _CharT>& __fc) const
5342  {
5343  return __format::__format_padded(
5344  __fc, _M_spec,
5345  [this, &__elems...](basic_format_context<_Out, _CharT>& __nfc)
5346  {
5347  __nfc.advance_to(__format::__write(__nfc.out(), _M_open));
5348  _M_felems._M_format(__elems..., __nfc, _M_sep);
5349  return __format::__write(__nfc.out(), _M_close);
5350  });
5351  }
5352 
5353  private:
5354  template<size_t... _Ids>
5355  struct __formatters_storage
5356  : __indexed_formatter_storage<_Ids, _Tps, _CharT>...
5357  {
5358  template<size_t _Id, typename _Up>
5359  using _Base = __indexed_formatter_storage<_Id, _Up, _CharT>;
5360 
5361  constexpr void
5362  _M_parse()
5363  {
5364  (_Base<_Ids, _Tps>::_M_parse(), ...);
5365  }
5366 
5367  template<typename _Out>
5368  void
5369  _M_format(__maybe_const<_Tps, _CharT>&... __elems,
5370  basic_format_context<_Out, _CharT>& __fc,
5371  _String_view __sep) const
5372  {
5373  (_Base<_Ids, _Tps>::_M_format(__elems, __fc, __sep), ...);
5374  }
5375 
5376  constexpr void
5377  set_debug_format()
5378  {
5379  (_Base<_Ids, _Tps>::set_debug_format(), ...);
5380  }
5381  };
5382 
5383  template<size_t... _Ids>
5384  static auto
5385  _S_create_storage(index_sequence<_Ids...>)
5386  -> __formatters_storage<_Ids...>;
5387  using _Formatters
5388  = decltype(_S_create_storage(index_sequence_for<_Tps...>()));
5389 
5390  _Spec<_CharT> _M_spec{};
5391  _String_view _M_open = _Seps::_S_parens().substr(0, 1);
5392  _String_view _M_close = _Seps::_S_parens().substr(1, 1);
5393  _String_view _M_sep = _Seps::_S_comma();
5394  _Formatters _M_felems;
5395  };
5396 
5397  template<typename _Tp>
5398  concept __is_map_formattable
5399  = __is_pair<_Tp> || (__is_tuple_v<_Tp> && tuple_size_v<_Tp> == 2);
5400 
5401 } // namespace __format
5402 /// @endcond
5403 
5404  // [format.tuple] Tuple formatter
5405  template<__format::__char _CharT, formattable<_CharT> _Fp,
5406  formattable<_CharT> _Sp>
5407  struct formatter<pair<_Fp, _Sp>, _CharT>
5408  : __format::__tuple_formatter<_CharT, remove_cvref_t<_Fp>,
5409  remove_cvref_t<_Sp>>
5410  {
5411  private:
5412  using __maybe_const_pair
5413  = __conditional_t<formattable<const _Fp, _CharT>
5414  && formattable<const _Sp, _CharT>,
5415  const pair<_Fp, _Sp>, pair<_Fp, _Sp>>;
5416  public:
5417  // We deviate from standard, that declares this as template accepting
5418  // unconstrained FormatContext type, which seems unimplementable.
5419  template<typename _Out>
5420  typename basic_format_context<_Out, _CharT>::iterator
5421  format(__maybe_const_pair& __p,
5422  basic_format_context<_Out, _CharT>& __fc) const
5423  { return this->_M_format_elems(__p.first, __p.second, __fc); }
5424  };
5425 
5426  template<__format::__char _CharT, formattable<_CharT>... _Tps>
5427  struct formatter<tuple<_Tps...>, _CharT>
5428  : __format::__tuple_formatter<_CharT, remove_cvref_t<_Tps>...>
5429  {
5430  private:
5431  using __maybe_const_tuple
5432  = __conditional_t<(formattable<const _Tps, _CharT> && ...),
5433  const tuple<_Tps...>, tuple<_Tps...>>;
5434  public:
5435  // We deviate from standard, that declares this as template accepting
5436  // unconstrained FormatContext type, which seems unimplementable.
5437  template<typename _Out>
5438  typename basic_format_context<_Out, _CharT>::iterator
5439  format(__maybe_const_tuple& __t,
5440  basic_format_context<_Out, _CharT>& __fc) const
5441  { return this->_M_format(__t, index_sequence_for<_Tps...>(), __fc); }
5442  };
5443 
5444  // [format.range.formatter], class template range_formatter
5445  template<typename _Tp, __format::__char _CharT>
5446  requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
5447  class range_formatter
5448  {
5449  using _String_view = basic_string_view<_CharT>;
5450  using _Seps = __format::_Separators<_CharT>;
5451 
5452  public:
5453  constexpr void
5454  set_separator(basic_string_view<_CharT> __sep) noexcept
5455  { _M_sep = __sep; }
5456 
5457  constexpr void
5458  set_brackets(basic_string_view<_CharT> __open,
5459  basic_string_view<_CharT> __close) noexcept
5460  {
5461  _M_open = __open;
5462  _M_close = __close;
5463  }
5464 
5465  constexpr formatter<_Tp, _CharT>&
5466  underlying() noexcept
5467  { return _M_fval; }
5468 
5469  constexpr const formatter<_Tp, _CharT>&
5470  underlying() const noexcept
5471  { return _M_fval; }
5472 
5473  // We deviate from standard, that declares this as template accepting
5474  // unconstrained ParseContext type, which seems unimplementable.
5475  constexpr typename basic_format_parse_context<_CharT>::iterator
5476  parse(basic_format_parse_context<_CharT>& __pc)
5477  {
5478  auto __first = __pc.begin();
5479  const auto __last = __pc.end();
5480  __format::_Spec<_CharT> __spec{};
5481  bool __no_brace = false;
5482 
5483  auto __finished = [&]
5484  { return __first == __last || *__first == '}'; };
5485 
5486  auto __finalize = [&]
5487  {
5488  _M_spec = __spec;
5489  return __first;
5490  };
5491 
5492  auto __parse_val = [&](_String_view __nfs = _String_view())
5493  {
5494  basic_format_parse_context<_CharT> __npc(__nfs);
5495  if (_M_fval.parse(__npc) != __npc.end())
5496  __format::__failed_to_parse_format_spec();
5497  if constexpr (__format::__has_debug_format<formatter<_Tp, _CharT>>)
5498  _M_fval.set_debug_format();
5499  return __finalize();
5500  };
5501 
5502  if (__finished())
5503  return __parse_val();
5504 
5505  __first = __spec._M_parse_fill_and_align(__first, __last, "{:");
5506  if (__finished())
5507  return __parse_val();
5508 
5509  __first = __spec._M_parse_width(__first, __last, __pc);
5510  if (__finished())
5511  return __parse_val();
5512 
5513  if (*__first == '?')
5514  {
5515  ++__first;
5516  __spec._M_type = __format::_Pres_esc;
5517  if (__finished() || *__first != 's')
5518  __throw_format_error("format error: '?' is allowed only in"
5519  " combination with 's'");
5520  }
5521 
5522  if (*__first == 's')
5523  {
5524  ++__first;
5525  if constexpr (same_as<_Tp, _CharT>)
5526  {
5527  if (__spec._M_type != __format::_Pres_esc)
5528  __spec._M_type = __format::_Pres_str;
5529  if (__finished())
5530  return __finalize();
5531  __throw_format_error("format error: element format specifier"
5532  " cannot be provided when 's' specifier is used");
5533  }
5534  else
5535  __throw_format_error("format error: 's' specifier requires"
5536  " range of character types");
5537  }
5538 
5539  if (__finished())
5540  return __parse_val();
5541 
5542  if (*__first == 'n')
5543  {
5544  ++__first;
5545  _M_open = _M_close = _String_view();
5546  __no_brace = true;
5547  }
5548 
5549  if (__finished())
5550  return __parse_val();
5551 
5552  if (*__first == 'm')
5553  {
5554  _String_view __m(__first, 1);
5555  ++__first;
5556  if constexpr (__format::__is_map_formattable<_Tp>)
5557  {
5558  _M_sep = _Seps::_S_comma();
5559  if (!__no_brace)
5560  {
5561  _M_open = _Seps::_S_braces().substr(0, 1);
5562  _M_close = _Seps::_S_braces().substr(1, 1);
5563  }
5564  if (__finished())
5565  return __parse_val(__m);
5566  __throw_format_error("format error: element format specifier"
5567  " cannot be provided when 'm' specifier is used");
5568  }
5569  else
5570  __throw_format_error("format error: 'm' specifier requires"
5571  " range of pairs or tuples of two elements");
5572  }
5573 
5574  if (__finished())
5575  return __parse_val();
5576 
5577  if (*__first == ':')
5578  {
5579  __pc.advance_to(++__first);
5580  __first = _M_fval.parse(__pc);
5581  }
5582 
5583  if (__finished())
5584  return __finalize();
5585 
5586  __format::__failed_to_parse_format_spec();
5587  }
5588 
5589  // We deviate from standard, that declares this as template accepting
5590  // unconstrained FormatContext type, which seems unimplementable.
5591  template<ranges::input_range _Rg, typename _Out>
5592  requires formattable<ranges::range_reference_t<_Rg>, _CharT> &&
5593  same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _Tp>
5594  typename basic_format_context<_Out, _CharT>::iterator
5595  format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
5596  {
5597  using _Range = remove_reference_t<_Rg>;
5598  if constexpr (__format::__simply_formattable_range<_Range, _CharT>)
5599  return _M_format<const _Range>(__rg, __fc);
5600  else
5601  return _M_format(__rg, __fc);
5602  }
5603 
5604  private:
5605  template<ranges::input_range _Rg, typename _Out>
5606  typename basic_format_context<_Out, _CharT>::iterator
5607  _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const
5608  {
5609  if constexpr (same_as<_Tp, _CharT>)
5610  if (_M_spec._M_type == __format::_Pres_str
5611  || _M_spec._M_type == __format::_Pres_esc)
5612  {
5613  __format::__formatter_str __fstr(_M_spec);
5614  return __fstr._M_format_range(__rg, __fc);
5615  }
5616  return __format::__format_padded(
5617  __fc, _M_spec,
5618  [this, &__rg](basic_format_context<_Out, _CharT>& __nfc)
5619  { return _M_format_elems(__rg, __nfc); });
5620  }
5621 
5622 
5623  template<ranges::input_range _Rg, typename _Out>
5624  typename basic_format_context<_Out, _CharT>::iterator
5625  _M_format_elems(_Rg& __rg,
5626  basic_format_context<_Out, _CharT>& __fc) const
5627  {
5628  auto __out = __format::__write(__fc.out(), _M_open);
5629 
5630  auto __first = ranges::begin(__rg);
5631  auto const __last = ranges::end(__rg);
5632  if (__first == __last)
5633  return __format::__write(__out, _M_close);
5634 
5635  __fc.advance_to(__out);
5636  __out = _M_fval.format(*__first, __fc);
5637  for (++__first; __first != __last; ++__first)
5638  {
5639  __out = __format::__write(__out, _M_sep);
5640  __fc.advance_to(__out);
5641  __out = _M_fval.format(*__first, __fc);
5642  }
5643 
5644  return __format::__write(__out, _M_close);
5645  }
5646 
5647  __format::_Spec<_CharT> _M_spec{};
5648  _String_view _M_open = _Seps::_S_squares().substr(0, 1);
5649  _String_view _M_close = _Seps::_S_squares().substr(1, 1);
5650  _String_view _M_sep = _Seps::_S_comma();
5651  formatter<_Tp, _CharT> _M_fval;
5652  };
5653 
5654  // In standard this is shown as inheriting from specialization of
5655  // exposition only specialization for range-default-formatter for
5656  // each range_format. We opt for simpler implementation.
5657  // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr],
5658  // specializations for maps, sets, and strings
5659  template<ranges::input_range _Rg, __format::__char _CharT>
5660  requires (format_kind<_Rg> != range_format::disabled)
5661  && formattable<ranges::range_reference_t<_Rg>, _CharT>
5662  struct formatter<_Rg, _CharT>
5663  {
5664  private:
5665  static const bool _S_range_format_is_string =
5666  (format_kind<_Rg> == range_format::string)
5667  || (format_kind<_Rg> == range_format::debug_string);
5668  using _Vt = remove_cvref_t<
5669  ranges::range_reference_t<
5670  __format::__maybe_const_range<_Rg, _CharT>>>;
5671 
5672  static consteval bool _S_is_correct()
5673  {
5674  if constexpr (_S_range_format_is_string)
5675  static_assert(same_as<_Vt, _CharT>);
5676  return true;
5677  }
5678 
5679  static_assert(_S_is_correct());
5680 
5681  public:
5682  constexpr formatter() noexcept
5683  {
5684  using _Seps = __format::_Separators<_CharT>;
5685  if constexpr (format_kind<_Rg> == range_format::map)
5686  {
5687  static_assert(__format::__is_map_formattable<_Vt>);
5688  _M_under.set_brackets(_Seps::_S_braces().substr(0, 1),
5689  _Seps::_S_braces().substr(1, 1));
5690  _M_under.underlying().set_brackets({}, {});
5691  _M_under.underlying().set_separator(_Seps::_S_colon());
5692  }
5693  else if constexpr (format_kind<_Rg> == range_format::set)
5694  _M_under.set_brackets(_Seps::_S_braces().substr(0, 1),
5695  _Seps::_S_braces().substr(1, 1));
5696  }
5697 
5698  constexpr void
5699  set_separator(basic_string_view<_CharT> __sep) noexcept
5700  requires (!_S_range_format_is_string)
5701  { _M_under.set_separator(__sep); }
5702 
5703  constexpr void
5704  set_brackets(basic_string_view<_CharT> __open,
5705  basic_string_view<_CharT> __close) noexcept
5706  requires (!_S_range_format_is_string)
5707  { _M_under.set_brackets(__open, __close); }
5708 
5709  // We deviate from standard, that declares this as template accepting
5710  // unconstrained ParseContext type, which seems unimplementable.
5711  constexpr typename basic_format_parse_context<_CharT>::iterator
5712  parse(basic_format_parse_context<_CharT>& __pc)
5713  {
5714  auto __res = _M_under.parse(__pc);
5715  if constexpr (format_kind<_Rg> == range_format::debug_string)
5716  _M_under.set_debug_format();
5717  return __res;
5718  }
5719 
5720  // We deviate from standard, that declares this as template accepting
5721  // unconstrained FormatContext type, which seems unimplementable.
5722  template<typename _Out>
5723  typename basic_format_context<_Out, _CharT>::iterator
5724  format(__format::__maybe_const_range<_Rg, _CharT>& __rg,
5725  basic_format_context<_Out, _CharT>& __fc) const
5726  {
5727  if constexpr (_S_range_format_is_string)
5728  return _M_under._M_format_range(__rg, __fc);
5729  else
5730  return _M_under.format(__rg, __fc);
5731  }
5732 
5733  private:
5734  using _Formatter_under
5735  = __conditional_t<_S_range_format_is_string,
5736  __format::__formatter_str<_CharT>,
5737  range_formatter<_Vt, _CharT>>;
5738  _Formatter_under _M_under;
5739  };
5740 #endif // C++23 formatting ranges
5741 #undef _GLIBCXX_WIDEN
5742 
5743 _GLIBCXX_END_NAMESPACE_VERSION
5744 } // namespace std
5745 #endif // __cpp_lib_format
5746 #pragma GCC diagnostic pop
5747 #endif // _GLIBCXX_FORMAT