On Tue, May 20, 2025 at 12:41 PM Tomasz Kaminski <tkami...@redhat.com> wrote:
> > > On Tue, May 20, 2025 at 11:41 AM Jonathan Wakely <jwak...@redhat.com> > wrote: > >> On 20/05/25 09:35 +0200, Tomasz Kamiński wrote: >> >These patch makes following changes to _Pres_type values: >> > * _Pres_esc is replaced with separate _M_debug flag. >> > * _Pres_s, _Pres_p do not overlap with _Pres_none. >> > * hexadecimal presentation use same values for pointer, integer >> > and floating point types. >> > >> >The members of _Spec<_CharT> are rearanged so the class contains 8 bits >> >> s/rearanged/rearranged/ >> >> >of reserved for future use (_M_reserved) and 8 bits of tail padding. >> >> s/of reserved/reserved/ >> >> >Derived classes (like _ChronoSpec<_CharT>) can reuse the storage for >> initial >> >members. We also add _SpecBase as the base class for _Spec<_CharT> to >> make >> >it non-C++98 POD, which allows tail padding to be reused on Itanium ABI. >> > >> >Finally, the format enumerators are defined as enum class with unsigned >> >char as underlying type, followed by using enum to bring names in scope. >> >_Term_char names are adjusted for consistency, and enumerator values are >> >changed so it can fit in smaller bitfields. >> > >> >The '?' is changed to separate _M_debug flag, to allow debug format to be >> >independent from the presentation type, and applied to multiple >> presentation >> >types. For example it could be used to trigger memberwise or reflection >> based >> >formatting. >> > >> >The _M_format_character and _M_format_character_escaped functions are >> merged >> >to single function that handle normal and debug presentation. In >> particular >> >this would allow future support for '?c' for printing integer types as >> escaped >> >character. _S_character_width is also folded in the merged function. >> > >> >Decoupling _Pres_s value from _Pres_none, allows it to be used for string >> >presentation for range formatting, and removes the need for separate >> _Pres_seq >> >and _Pres_str. This does not affect formatting of bool as >> __formatter_int::_M_parse >> >overrides default value of _M_type. And with separation of the _M_debug >> flag, >> >__formatter_str::format behavior is now agnostic to _M_type value. >> > >> >The values for integer presentation types, are arranged so textual >> presentations >> >(_Prec_s, _Pres_c) are grouped together. For consistency floating point >> >hexadecimal presentation uses the same values as integer ones. >> > >> >New _Pres_p and setting for _M_alt enables using some spec to configure >> formatting >> >of uintptr_t with __formatter_int, and const void* with __formatter_ptr. >> >Differentiating it from _Pres_none would allow future of formatter<T*, >> _CharT> >> >that would require explicit presentation type to be specified. This >> would allow >> >std::vector<T*> to be formatter directly with '{::p}' format spec. >> >> s/formatter/formatted/ >> >> >The constructors for __formatter_int and _formatter_ptr from >> _Spec<_CharT>, >> >> s/_formatter_ptr/__formatter_ptr/ >> >> >now also set default presentation modes, as format functions expects >> them. >> > >> >libstdc++-v3/ChangeLog: >> > >> > * include/bits/chrono_io.h >> (_ChronoSpec<_CharT>::_M_locale_specific): >> > Declare as bit filed in tail-padding.. >> >> s/filed/field/ >> >> > * include/bits/formatfwd.h (__format::_Align): Defined as enum >> class >> > and add using enum. >> > * include/std/format (__format::_Pres_type, __format::_Sign) >> > (__format::_WidthPrec, __format::_Arg_t): Defined as enum class >> and >> > add using enum. >> > (_Pres_type::_Pres_esc): Replace with _Pres_max. >> > (_Pres_type::_Pres_seq, _Pres_type::_Pres_str): Remove. >> > (__format::_Pres_type): Updated values of enumerators as >> described above. >> >> This line is more than 80 columns, please add a line break. >> >> Please adjust the rest of the ChangeLog to keep to around 74 chars >> where possible. >> >> > (_Spec<_CharT>): Rearranged members to have 8 bits of >> tail-padding. >> > (_Spec<_CharT>::_M_debug): Defined. >> > (_Spec<_CharT>::_M_reserved): Extended to 8 bits and moved at the >> end. >> > (_Spec<_CharT>::_M_reserved2): Removed. >> > (_Spec<_CharT>::_M_parse_fill_and_align, >> _Spec<_CharT>::_M_parse_sign) >> > (__format::__write_padded_as_spec): Adjusted default value checks. >> > (__format::_Term_char): Add using enum and adjust enumertors. >> > (__Escapes::_S_term): Adjusted for _Term_char values. >> > (__format::__should_escape_ascii): Adjusted _Term_char uses. >> > (__foramt::__write_escaped): Adjusted for _Term_char. >> > (__formatter_str<_CharT>::parse): Set _Pres_s if specifed and >> _M_debug >> > instead of _Pres_esc. >> > (__formatter_str<_CharT>::set_debug_format): Set _M_debug instead >> of >> > _Pres_esc. >> > (__formatter_str<_CharT>::format, >> __formatter_str<_CharT>::_M_format_range): >> > Check _M_debug instead of _Prec_esc. >> > (__formatter_str<_CharT>::_M_format_escaped): Adjusted _Term_char >> uses. >> > (__formatter_int<_CharT>::__formatter_int(_Spec<_CharT>)): Set >> _Pres_d if >> > default presentation type is not set. >> > (__formatter_int<_CharT>::_M_parse): Adjusted default value >> checks. >> > (__formatter_int<_CharT>::_M_do_parse): Set _M_debug instead of >> _Pres_esc. >> > (__formatter_int<_CharT>::_M_format_character): Handle escaped >> presentation. >> > (__formatter_int<_CharT>::_M_format_character_escaped) >> > (__formatter_int<_CharT>::_S_character_width): Merged into >> _M_format_character. >> > (__formatter_ptr<_CharT>::__formatter_ptr(_Spec<_CharT>)): Set >> _Pres_p if default >> > presentation type is not set. >> > (__formatter_ptr<_CharT>::parse): Add default __type parameter, >> store _Pres_p, >> > and handle _M_alt to be consistent with meaning for integers. >> > (__foramtter_ptr<_CharT>::_M_set_default): Define. >> > (__format::__pack_arg_types, std::basic_format_args): Add >> necessary casts. >> > (formatter<_CharT, _CharT>::set_debug_format) >> > (formatter<char, wchar_t>::set_debug_format): Set _M_debug >> instead of _Pres_esc. >> > (formatter<_CharT, _CharT>::format, formatter<char, >> wchar_t>::format): >> > Simplify calls to _M_format_character. >> > (range_formatter<_Rg, _CharT>::parse): Replace _Pres_str with >> _Pres_s >> > and set _M_debug instead of _Pres_esc. >> > (range_formatter<_Rg, _CharT>::format): Replace _Pres_str with >> _Pres_s. >> >--- >> >Adjusted values for the _Term_char so they can now fit in 2 bits >> bitfield. >> >Handle _Term_non. >> >I think the commit message is now longer than the diff. >> >> :-) >> >> >OK for trunk? >> >> OK, thanks. >> >> (There are two more spelling typos noted below ...) >> >> >> > libstdc++-v3/include/bits/chrono_io.h | 18 +- >> > libstdc++-v3/include/bits/formatfwd.h | 3 +- >> > libstdc++-v3/include/std/format | 257 ++++++++++++++------------ >> > 3 files changed, 145 insertions(+), 133 deletions(-) >> > >> >diff --git a/libstdc++-v3/include/bits/chrono_io.h >> b/libstdc++-v3/include/bits/chrono_io.h >> >index ace8b9f2629..991142fd83f 100644 >> >--- a/libstdc++-v3/include/bits/chrono_io.h >> >+++ b/libstdc++-v3/include/bits/chrono_io.h >> >@@ -207,21 +207,15 @@ namespace __format >> > template<typename _CharT> >> > struct _ChronoSpec : _Spec<_CharT> >> > { >> >- basic_string_view<_CharT> _M_chrono_specs; >> >- >> >- // Use one of the reserved bits in __format::_Spec<C>. >> >+ // Placed in tail-padding of __format::_Spec<C>. >> > // This indicates that a locale-dependent conversion specifier >> such as >> > // %a is used in the chrono-specs. This is not the same as the >> > // _Spec<C>::_M_localized member which indicates that "L" was >> present >> > // in the format-spec, e.g. "{:L%a}" is localized and >> locale-specific, >> > // but "{:L}" is only localized and "{:%a}" is only >> locale-specific. >> >- constexpr bool >> >- _M_locale_specific() const noexcept >> >- { return this->_M_reserved; } >> >+ unsigned _M_locale_specific : 1; >> > >> >- constexpr void >> >- _M_locale_specific(bool __b) noexcept >> >- { this->_M_reserved = __b; } >> >+ basic_string_view<_CharT> _M_chrono_specs; >> > }; >> > >> > // Represents the information provided by a chrono type. >> >@@ -488,7 +482,7 @@ namespace __format >> > _M_spec = __spec; >> > _M_spec._M_chrono_specs >> > = __string_view(__chrono_specs, __first - >> __chrono_specs); >> >- _M_spec._M_locale_specific(__locale_specific); >> >+ _M_spec._M_locale_specific = __locale_specific; >> > >> > return __first; >> > } >> >@@ -512,7 +506,7 @@ namespace __format >> > // of chrono types is underspecified >> > if constexpr (is_same_v<_CharT, char>) >> > if constexpr (__unicode::__literal_encoding_is_utf8()) >> >- if (_M_spec._M_localized && _M_spec._M_locale_specific()) >> >+ if (_M_spec._M_localized && _M_spec._M_locale_specific) >> > { >> > extern locale __with_encoding_conversion(const locale&); >> > >> >@@ -806,7 +800,7 @@ namespace __format >> > // of chrono types is underspecified >> > if constexpr (is_same_v<_CharT, char>) >> > if constexpr (__unicode::__literal_encoding_is_utf8()) >> >- if (_M_spec._M_localized && _M_spec._M_locale_specific() >> >+ if (_M_spec._M_localized && _M_spec._M_locale_specific >> > && __loc != locale::classic()) >> > { >> > extern string_view >> >diff --git a/libstdc++-v3/include/bits/formatfwd.h >> b/libstdc++-v3/include/bits/formatfwd.h >> >index 3fa01ad1eab..777e6290f74 100644 >> >--- a/libstdc++-v3/include/bits/formatfwd.h >> >+++ b/libstdc++-v3/include/bits/formatfwd.h >> >@@ -71,12 +71,13 @@ namespace __format >> > concept __char = same_as<_CharT, char>; >> > #endif >> > >> >- enum _Align { >> >+ enum class _Align : unsigned char { >> > _Align_default, >> > _Align_left, >> > _Align_right, >> > _Align_centre, >> > }; >> >+ using enum _Align; >> > >> > template<typename _CharT> struct _Spec; >> > >> >diff --git a/libstdc++-v3/include/std/format >> b/libstdc++-v3/include/std/format >> >index b1823db83bc..c0a10a38152 100644 >> >--- a/libstdc++-v3/include/std/format >> >+++ b/libstdc++-v3/include/std/format >> >@@ -472,30 +472,33 @@ namespace __format >> > return {0, nullptr}; >> > } >> > >> >- enum _Pres_type { >> >+ enum class _Pres_type : unsigned char { >> > _Pres_none = 0, // Default type (not valid for integer presentation >> types). >> >+ _Pres_s = 1, // For strings, bool, ranges >> > // Presentation types for integral types (including bool and charT). >> >- _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c, >> >- // Presentation types for floating-point types. >> >- _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, >> _Pres_G, >> >- _Pres_p = 0, _Pres_P, // For pointers. >> >- _Pres_s = 0, // For strings, bool >> >- _Pres_seq = 0, _Pres_str, // For ranges >> >- _Pres_esc = 0xf, // For strings, charT and ranges >> > Changing it to /* _Pres_s, */ > Finally removed it, as adding this comment will put integer presentation types over 80 column limit, and I think there is more value in having them in one line. > >> This /* s */ confused me more than it helped me, but maybe I'm just >> being slow this morning. >> >> >+ /* s */ _Pres_c = 2, _Pres_x, _Pres_X, _Pres_d, _Pres_o, _Pres_b, >> _Pres_B, >> >+ // Presentation types for floating-point types >> >+ _Pres_g = 1, _Pres_G, _Pres_a, _Pres_A, _Pres_e, _Pres_E, _Pres_f, >> _Pres_F, >> >+ // For pointers, the value are same as hexadecimal presentations >> for integers >> >+ _Pres_p = _Pres_x, _Pres_P = _Pres_X, >> >+ _Pres_max = 0xf, >> > }; >> >+ using enum _Pres_type; >> > >> >- enum _Sign { >> >+ enum class _Sign : unsigned char { >> > _Sign_default, >> > _Sign_plus, >> > _Sign_minus, // XXX does this need to be distinct from >> _Sign_default? >> > _Sign_space, >> > }; >> >+ using enum _Sign; >> > >> >- enum _WidthPrec { >> >+ enum _WidthPrec : unsigned char { >> > _WP_none, // No width/prec specified. >> > _WP_value, // Fixed width/prec specified. >> > _WP_from_arg // Use a formatting argument for width/prec. >> > }; >> >+ using enum _WidthPrec; >> > >> > template<typename _Context> >> > size_t >> >@@ -507,9 +510,17 @@ namespace __format >> > constexpr bool __is_xdigit(char __c) >> > { return std::__detail::__from_chars_alnum_to_val(__c) < 16; } >> > >> >+ // Used to make _Spec a non-C++98 POD, so the tail-padding is used. >> >+ // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod >> >+ struct _SpecBase >> >+ { }; >> >+ >> > template<typename _CharT> >> >- struct _Spec >> >+ struct _Spec : _SpecBase >> > { >> >+ unsigned short _M_width; >> >+ unsigned short _M_prec; >> >+ char32_t _M_fill = ' '; >> > _Align _M_align : 2; >> > _Sign _M_sign : 2; >> > unsigned _M_alt : 1; >> >@@ -517,12 +528,11 @@ namespace __format >> > unsigned _M_zero_fill : 1; >> > _WidthPrec _M_width_kind : 2; >> > _WidthPrec _M_prec_kind : 2; >> >+ unsigned _M_debug : 1; >> > _Pres_type _M_type : 4; >> >- unsigned _M_reserved : 1; >> >- unsigned _M_reserved2 : 16; >> >- unsigned short _M_width; >> >- unsigned short _M_prec; >> >- char32_t _M_fill = ' '; >> >+ unsigned _M_reserved : 8; >> >+ // This class has 8bits of tail padding, that can be used by >> >+ // derived classes. >> > >> > using iterator = typename basic_string_view<_CharT>::iterator; >> > >> >@@ -562,7 +572,7 @@ namespace __format >> > char32_t __c = *__beg++; >> > if (__is_scalar_value(__c)) >> > if (auto __next = __beg.base(); __next != __last) >> >- if (_Align __align = _S_align(*__next)) >> >+ if (_Align __align = _S_align(*__next); __align != >> _Align_default) >> > { >> > _M_fill = __c; >> > _M_align = __align; >> >@@ -571,14 +581,14 @@ namespace __format >> > } >> > } >> > else if (__last - __first >= 2) >> >- if (_Align __align = _S_align(__first[1])) >> >+ if (_Align __align = _S_align(__first[1]); __align != >> _Align_default) >> > { >> > _M_fill = *__first; >> > _M_align = __align; >> > return __first + 2; >> > } >> > >> >- if (_Align __align = _S_align(__first[0])) >> >+ if (_Align __align = _S_align(__first[0]); __align != >> _Align_default) >> > { >> > _M_fill = ' '; >> > _M_align = __align; >> >@@ -603,7 +613,7 @@ namespace __format >> > constexpr iterator >> > _M_parse_sign(iterator __first, iterator) noexcept >> > { >> >- if (_Sign __sign = _S_sign(*__first)) >> >+ if (_Sign __sign = _S_sign(*__first); __sign != _Sign_default) >> > { >> > _M_sign = __sign; >> > return __first + 1; >> >@@ -871,7 +881,7 @@ namespace __format >> > >> > const size_t __nfill = __width - __estimated_width; >> > >> >- if (__spec._M_align) >> >+ if (__spec._M_align != _Align_default) >> > __align = __spec._M_align; >> > >> > return __format::__write_padded(__fc.out(), __str, __align, >> __nfill, >> >@@ -896,12 +906,12 @@ namespace __format >> > } >> > } >> > >> >- >> >- // Values are indices into _Escapes::all. >> > enum class _Term_char : unsigned char { >> >- _Tc_quote = 12, >> >- _Tc_apos = 15 >> >+ _Term_none, >> >+ _Term_quote, >> >+ _Term_apos, >> > }; >> >+ using enum _Term_char; >> > >> > template<typename _CharT> >> > struct _Escapes >> >@@ -912,10 +922,6 @@ namespace __format >> > _Str_view _S_all() >> > { return _GLIBCXX_WIDEN("\t\\t\n\\n\r\\r\\\\\\\"\\\"'\\'\\u\\x"); >> } >> > >> >- static constexpr >> >- _CharT _S_term(_Term_char __term) >> >- { return _S_all()[static_cast<unsigned char>(__term)]; } >> >- >> > static consteval >> > _Str_view _S_tab() >> > { return _S_all().substr(0, 3); } >> >@@ -947,6 +953,21 @@ namespace __format >> > static consteval >> > _Str_view _S_x() >> > { return _S_all().substr(20, 2); } >> >+ >> >+ static constexpr >> >+ _Str_view _S_term(_Term_char __term) >> >+ { >> >+ switch (__term) >> >+ { >> >+ case _Term_none: >> >+ return _Str_view(); >> >+ case _Term_quote: >> >+ return _S_quote().substr(0, 1); >> >+ case _Term_apos: >> >+ return _S_apos().substr(0, 1); >> >+ } >> >+ __builtin_unreachable(); >> >+ } >> > }; >> > >> > template<typename _CharT> >> >@@ -991,9 +1012,9 @@ namespace __format >> > case _Esc::_S_bslash()[0]: >> > return true; >> > case _Esc::_S_quote()[0]: >> >- return __term == _Term_char::_Tc_quote; >> >+ return __term == _Term_quote; >> > case _Esc::_S_apos()[0]: >> >- return __term == _Term_char::_Tc_apos; >> >+ return __term == _Term_apos; >> > default: >> > return (__c >= 0 && __c < 0x20) || __c == 0x7f; >> > }; >> >@@ -1062,9 +1083,8 @@ namespace __format >> > case _Esc::_S_apos()[0]: >> > return __format::__write(__out, _Esc::_S_apos().substr(1, 2)); >> > default: >> >- return __format::__write_escape_seq(__out, >> >- static_cast<_UChar>(__c), >> >- _Esc::_S_u()); >> >+ return __format::__write_escape_seq( >> >+ __out, static_cast<_UChar>(__c), _Esc::_S_u()); >> > } >> > } >> > >> >@@ -1177,8 +1197,7 @@ namespace __format >> > _Out >> > __write_escaped(_Out __out, basic_string_view<_CharT> __str, >> _Term_char __term) >> > { >> >- *__out = _Escapes<_CharT>::_S_term(__term); >> >- ++__out; >> >+ __out = __format::__write(__out, >> _Escapes<_CharT>::_S_term(__term)); >> > >> > if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) >> > __out = __format::__write_escaped_unicode(__out, __str, __term); >> >@@ -1189,8 +1208,7 @@ namespace __format >> > // TODO Handle non-ascii extended encoding >> > __out = __format::__write_escaped_ascii(__out, __str, __term); >> > >> >- *__out = _Escapes<_CharT>::_S_term(__term); >> >- return ++__out; >> >+ return __format::__write(__out, >> _Escapes<_CharT>::_S_term(__term)); >> > } >> > >> > // A lightweight optional<locale>. >> >@@ -1312,11 +1330,14 @@ namespace __format >> > return __first; >> > >> > if (*__first == 's') >> >- ++__first; >> >+ { >> >+ __spec._M_type = _Pres_s; >> >+ ++__first; >> >+ } >> > #if __glibcxx_format_ranges // C++ >= 23 && HOSTED >> > else if (*__first == '?') >> > { >> >- __spec._M_type = _Pres_esc; >> >+ __spec._M_debug = true; >> > ++__first; >> > } >> > #endif >> >@@ -1332,7 +1353,7 @@ namespace __format >> > format(basic_string_view<_CharT> __s, >> > basic_format_context<_Out, _CharT>& __fc) const >> > { >> >- if (_M_spec._M_type == _Pres_esc) >> >+ if (_M_spec._M_debug) >> > return _M_format_escaped(__s, __fc); >> > >> > if (_M_spec._M_width_kind == _WP_none >> >@@ -1349,22 +1370,21 @@ namespace __format >> > _M_format_escaped(basic_string_view<_CharT> __s, >> > basic_format_context<_Out, _CharT>& __fc) const >> > { >> >- constexpr auto __term = __format::_Term_char::_Tc_quote; >> > const size_t __padwidth = _M_spec._M_get_width(__fc); >> > if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none) >> >- return __format::__write_escaped(__fc.out(), __s, __term); >> >+ return __format::__write_escaped(__fc.out(), __s, >> _Term_quote); >> > >> > const size_t __maxwidth = _M_spec._M_get_precision(__fc); >> > const size_t __width = __truncate(__s, __maxwidth); >> > // N.B. Escaping only increases width >> > if (__padwidth <= __width && _M_spec._M_prec_kind == _WP_none) >> >- return __format::__write_escaped(__fc.out(), __s, __term); >> >+ return __format::__write_escaped(__fc.out(), __s, >> _Term_quote); >> > >> > // N.B. [tab:format.type.string] defines '?' as >> > // Copies the escaped string ([format.string.escaped]) to the >> output, >> > // so precision seem to appy to escaped string. >> > _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, >> __maxwidth); >> >- __format::__write_escaped(__sink.out(), __s, __term); >> >+ __format::__write_escaped(__sink.out(), __s, _Term_quote); >> > return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); >> > } >> > >> >@@ -1388,7 +1408,7 @@ namespace __format >> > size_t(ranges::distance(__rg))); >> > return format(__str, __fc); >> > } >> >- else if (_M_spec._M_type != _Pres_esc) >> >+ else if (!_M_spec._M_debug) >> > { >> > const size_t __padwidth = _M_spec._M_get_width(__fc); >> > if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none) >> >@@ -1441,7 +1461,7 @@ namespace __format >> > >> > constexpr void >> > set_debug_format() noexcept >> >- { _M_spec._M_type = _Pres_esc; } >> >+ { _M_spec._M_debug = true; } >> > #endif >> > >> > private: >> >@@ -1462,7 +1482,10 @@ namespace __format >> > constexpr >> > __formatter_int(_Spec<_CharT> __spec) noexcept >> > : _M_spec(__spec) >> >- { } >> >+ { >> >+ if (_M_spec._M_type == _Pres_none) >> >+ _M_spec._M_type = _Pres_d; >> >+ } >> > >> > constexpr typename basic_format_parse_context<_CharT>::iterator >> > _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type >> __type) >> >@@ -1551,7 +1574,7 @@ namespace __format >> > case 's': >> > if (__type == _AsBool) >> > { >> >- __spec._M_type = _Pres_s; // same value (and meaning) as >> "none" >> >+ __spec._M_type = _Pres_s; // same meaning as "none" for >> bool >> > ++__first; >> > } >> > break; >> >@@ -1559,7 +1582,7 @@ namespace __format >> > case '?': >> > if (__type == _AsChar) >> > { >> >- __spec._M_type = _Pres_esc; >> >+ __spec._M_debug = true; >> > ++__first; >> > } >> > #endif >> >@@ -1580,7 +1603,8 @@ namespace __format >> > { >> > auto __end = _M_do_parse(__pc, _AsBool); >> > if (_M_spec._M_type == _Pres_s) >> >- if (_M_spec._M_sign || _M_spec._M_alt || >> _M_spec._M_zero_fill) >> >+ if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt >> >+ || _M_spec._M_zero_fill) >> > __throw_format_error("format error: format-spec >> contains " >> > "invalid formatting options for " >> > "'bool'"); >> >@@ -1589,8 +1613,9 @@ namespace __format >> > else if constexpr (__char<_Tp>) >> > { >> > auto __end = _M_do_parse(__pc, _AsChar); >> >- if (_M_spec._M_type == _Pres_c || _M_spec._M_type == >> _Pres_esc) >> >- if (_M_spec._M_sign || _M_spec._M_alt || >> _M_spec._M_zero_fill >> >+ if (_M_spec._M_type == _Pres_c) >> >+ if (_M_spec._M_sign != _Sign_default || _M_spec._M_alt >> >+ || _M_spec._M_zero_fill >> > /* XXX should be invalid? || _M_spec._M_localized >> */) >> > __throw_format_error("format error: format-spec >> contains " >> > "invalid formatting options for " >> >@@ -1702,51 +1727,34 @@ namespace __format >> > _M_spec); >> > } >> > >> >- [[__gnu__::__always_inline__]] >> >- static size_t >> >- _S_character_width(_CharT __c) >> >- { >> >- // N.B. single byte cannot encode charcter of width greater than 1 >> >> s/charcter/character/ >> >> >- if constexpr (sizeof(_CharT) > 1u && >> >- >> __unicode::__literal_encoding_is_unicode<_CharT>()) >> >- return __unicode::__field_width(__c); >> >- else >> >- return 1u; >> >- } >> >- >> > template<typename _Out> >> > typename basic_format_context<_Out, _CharT>::iterator >> > _M_format_character(_CharT __c, >> >- basic_format_context<_Out, _CharT>& __fc) const >> >+ basic_format_context<_Out, _CharT>& __fc) >> const >> > { >> >- return __format::__write_padded_as_spec({&__c, 1u}, >> >- _S_character_width(__c), >> >- __fc, _M_spec); >> >- } >> >+ basic_string_view<_CharT> __in(&__c, 1u); >> >+ size_t __width = 1u; >> >+ // N.B. single byte cannot encode charcter of width greater >> than 1 >> >> s/charcter/character/ >> >> >+ if constexpr (sizeof(_CharT) > 1u && >> >+ >> __unicode::__literal_encoding_is_unicode<_CharT>()) >> >+ __width = __unicode::__field_width(__c); >> > >> >- template<typename _Out> >> >- typename basic_format_context<_Out, _CharT>::iterator >> >- _M_format_character_escaped(_CharT __c, >> >- basic_format_context<_Out, _CharT>& >> __fc) const >> >- { >> >- using _Esc = _Escapes<_CharT>; >> >- constexpr auto __term = __format::_Term_char::_Tc_apos; >> >- const basic_string_view<_CharT> __in(&__c, 1u); >> >- if (_M_spec._M_get_width(__fc) <= 3u) >> >- return __format::__write_escaped(__fc.out(), __in, __term); >> >+ if (!_M_spec._M_debug) >> >+ return __format::__write_padded_as_spec(__in, __width, >> >+ __fc, _M_spec); >> >+ >> >+ __width += 2; >> >+ if (_M_spec._M_get_width(__fc) <= __width) >> >+ return __format::__write_escaped(__fc.out(), __in, >> _Term_apos); >> > >> > _CharT __buf[12]; >> >- __format::_Fixedbuf_sink<_CharT> __sink(__buf); >> >- __format::__write_escaped(__sink.out(), __in, __term); >> >+ _Fixedbuf_sink<_CharT> __sink(__buf); >> >+ __format::__write_escaped(__sink.out(), __in, _Term_apos); >> > >> >- const basic_string_view<_CharT> __escaped = __sink.view(); >> >- size_t __estimated_width; >> >- if (__escaped[1] == _Esc::_S_bslash()[0]) // escape sequence >> >- __estimated_width = __escaped.size(); >> >- else >> >- __estimated_width = 2 + _S_character_width(__c); >> >- return __format::__write_padded_as_spec(__escaped, >> >- __estimated_width, >> >+ __in = __sink.view(); >> >+ if (__in[1] == _Escapes<_CharT>::_S_bslash()[0]) // escape >> sequence >> >+ __width = __in.size(); >> >+ return __format::__write_padded_as_spec(__in, __width, >> > __fc, _M_spec); >> > } >> > >> >@@ -2423,17 +2431,18 @@ namespace __format >> > constexpr >> > __formatter_ptr(_Spec<_CharT> __spec) noexcept >> > : _M_spec(__spec) >> >- { } >> >+ { _M_set_default(_Pres_p); } >> > >> > constexpr typename basic_format_parse_context<_CharT>::iterator >> >- parse(basic_format_parse_context<_CharT>& __pc) >> >+ parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type >> = _Pres_p) >> > { >> > __format::_Spec<_CharT> __spec{}; >> > const auto __last = __pc.end(); >> > auto __first = __pc.begin(); >> > >> >- auto __finalize = [this, &__spec] { >> >+ auto __finalize = [this, &__spec, __type] { >> > _M_spec = __spec; >> >+ _M_set_default(__type); >> > }; >> > >> > auto __finished = [&] { >> >@@ -2461,19 +2470,23 @@ namespace __format >> > #endif >> > >> > __first = __spec._M_parse_width(__first, __last, __pc); >> >+ if (__finished()) >> >+ return __first; >> > >> >- if (__first != __last) >> >+ if (*__first == 'p') >> > { >> >- if (*__first == 'p') >> >- ++__first; >> >+ __spec._M_type = _Pres_p; >> >+ _M_spec._M_alt = !_M_spec._M_alt; >> >+ ++__first; >> >+ } >> > #if __glibcxx_format >= 202304L >> >- else if (*__first == 'P') >> >- { >> >- __spec._M_type = __format::_Pres_P; >> >- ++__first; >> >- } >> >-#endif >> >+ else if (*__first == 'P') >> >+ { >> >+ __spec._M_type = _Pres_P; >> >+ _M_spec._M_alt = !_M_spec._M_alt; >> >+ ++__first; >> > } >> >+#endif >> > >> > if (__finished()) >> > return __first; >> >@@ -2540,6 +2553,17 @@ namespace __format >> > } >> > >> > private: >> >+ [[__gnu__::__always_inline__]] >> >+ constexpr void >> >+ _M_set_default(_Pres_type __type) >> >+ { >> >+ if (_M_spec._M_type == _Pres_none && __type != _Pres_none) >> >+ { >> >+ _M_spec._M_type = __type; >> >+ _M_spec._M_alt = !_M_spec._M_alt; >> >+ } >> >+ } >> >+ >> > __format::_Spec<_CharT> _M_spec{}; >> > }; >> > >> >@@ -2562,11 +2586,8 @@ namespace __format >> > typename basic_format_context<_Out, _CharT>::iterator >> > format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const >> > { >> >- if (_M_f._M_spec._M_type == __format::_Pres_none >> >- || _M_f._M_spec._M_type == __format::_Pres_c) >> >+ if (_M_f._M_spec._M_type == __format::_Pres_c) >> > return _M_f._M_format_character(__u, __fc); >> >- else if (_M_f._M_spec._M_type == __format::_Pres_esc) >> >- return _M_f._M_format_character_escaped(__u, __fc); >> > else >> > return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), >> __fc); >> > } >> >@@ -2574,7 +2595,7 @@ namespace __format >> > #if __glibcxx_format_ranges // C++ >= 23 && HOSTED >> > constexpr void >> > set_debug_format() noexcept >> >- { _M_f._M_spec._M_type = __format::_Pres_esc; } >> >+ { _M_f._M_spec._M_debug = true; } >> > #endif >> > >> > private: >> >@@ -2598,11 +2619,8 @@ namespace __format >> > typename basic_format_context<_Out, wchar_t>::iterator >> > format(char __u, basic_format_context<_Out, wchar_t>& __fc) const >> > { >> >- if (_M_f._M_spec._M_type == __format::_Pres_none >> >- || _M_f._M_spec._M_type == __format::_Pres_c) >> >+ if (_M_f._M_spec._M_type == __format::_Pres_c) >> > return _M_f._M_format_character(__u, __fc); >> >- else if (_M_f._M_spec._M_type == __format::_Pres_esc) >> >- return _M_f._M_format_character_escaped(__u, __fc); >> > else >> > return _M_f.format(static_cast<unsigned char>(__u), __fc); >> > } >> >@@ -2610,7 +2628,7 @@ namespace __format >> > #if __glibcxx_format_ranges // C++ >= 23 && HOSTED >> > constexpr void >> > set_debug_format() noexcept >> >- { _M_f._M_spec._M_type = __format::_Pres_esc; } >> >+ { _M_f._M_spec._M_debug = true; } >> > #endif >> > >> > private: >> >@@ -3864,7 +3882,7 @@ namespace __format >> > } >> > }; >> > >> >- enum _Arg_t : unsigned char { >> >+ enum class _Arg_t : unsigned char { >> > _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull, >> > _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, >> _Arg_handle, >> > _Arg_i128, _Arg_u128, _Arg_float128, >> >@@ -3876,6 +3894,7 @@ namespace __format >> > _Arg_ieee128 = _Arg_float128, >> > #endif >> > }; >> >+ using enum _Arg_t; >> > >> > template<typename _Context> >> > struct _Arg_value >> >@@ -4488,7 +4507,7 @@ namespace __format >> > { >> > __UINT64_TYPE__ __packed_types = 0; >> > for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i) >> >- __packed_types = (__packed_types << _Bits) | *__i; >> >+ __packed_types = (__packed_types << _Bits) | (unsigned)*__i; >> > return __packed_types; >> > } >> > } // namespace __format >> >@@ -4501,7 +4520,7 @@ namespace __format >> > static constexpr int _S_packed_type_mask = 0b11111; >> > static constexpr int _S_max_packed_args = 12; >> > >> >- static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) >> ); >> >+ static_assert( (unsigned)__format::_Arg_max_ <= (1u << >> _S_packed_type_bits) ); >> > >> > template<typename... _Args> >> > using _Store = __format::_Arg_store<_Context, _Args...>; >> >@@ -5849,7 +5868,7 @@ namespace __format >> > if (*__first == '?') >> > { >> > ++__first; >> >- __spec._M_type = __format::_Pres_esc; >> >+ __spec._M_debug = true; >> > if (__finished() || *__first != 's') >> > __throw_format_error("format error: '?' is allowed only in" >> > " combination with 's'"); >> >@@ -5860,8 +5879,7 @@ namespace __format >> > ++__first; >> > if constexpr (same_as<_Tp, _CharT>) >> > { >> >- if (__spec._M_type != __format::_Pres_esc) >> >- __spec._M_type = __format::_Pres_str; >> >+ __spec._M_type = __format::_Pres_s; >> > if (__finished()) >> > return __finalize(); >> > __throw_format_error("format error: element format >> specifier" >> >@@ -5943,8 +5961,7 @@ namespace __format >> > _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) >> const >> > { >> > if constexpr (same_as<_Tp, _CharT>) >> >- if (_M_spec._M_type == __format::_Pres_str >> >- || _M_spec._M_type == __format::_Pres_esc) >> >+ if (_M_spec._M_type == __format::_Pres_s) >> > { >> > __format::__formatter_str __fstr(_M_spec); >> > return __fstr._M_format_range(__rg, __fc); >> >-- >> >2.49.0 >> > >> > >> >>