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