On Tue, Apr 29, 2025 at 12:58 PM Tomasz Kaminski <tkami...@redhat.com> wrote:
> > > On Tue, Apr 29, 2025 at 9:28 AM Tomasz Kamiński <tkami...@redhat.com> > 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. >> >> Instead of `_M_reserved` and `_M_reserved2` bitfields, the members of >> _Spec<_CharT> are rearranged so the class contains 16bit of tail padding. >> 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 was adjusted for consistency. >> >> 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. >> >> The constructors for __formatter_int and _formatter_ptr from >> _Spec<_CharT>, >> 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.. >> * 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. >> (_Spec<_CharT>): Rearranged members to have 16bits of >> tail-padding. >> (_Spec<_CharT>::_M_debug): Defined. >> (_Spec<_CharT>::_M_reserved, _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 rename enumertors. >> (__format::__should_escape_ascii): Adjusted _Term_char uses. >> (__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. >> --- >> I think using tail-padding is the better option, so following on here. >> Performed a few additional cleanups: >> * _Term_char now is consitient with remaining enumerators >> * __formatter_ptr/_formatter_int constructor from _Spec, now set >> defaults for >> _Pres_none, as format expects them. This makes using them like in >> formatter<thread::id, _CharT> easier. >> Testing on x86_64-linux. OK for turnk if test passes? >> > All test passed. OK for trunk? > This is implemented on top of one-liner fix from "libstdc++: Fix _Padding_sink in case when predicted is between padwidth and maxwidth [PR109162]", so needs to be merged after. > >> libstdc++-v3/include/bits/chrono_io.h | 18 +-- >> libstdc++-v3/include/bits/formatfwd.h | 3 +- >> libstdc++-v3/include/std/format | 221 ++++++++++++++------------ >> 3 files changed, 123 insertions(+), 119 deletions(-) >> >> diff --git a/libstdc++-v3/include/bits/chrono_io.h >> b/libstdc++-v3/include/bits/chrono_io.h >> index b7f6f5f49e5..2b77eb2acc5 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; >> } >> @@ -514,7 +508,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&); >> >> @@ -816,7 +810,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 b3794b64b59..0be214b8713 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 >> + /* 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,10 @@ 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 = ' '; >> + // This class has 16bit of tail padding, that can be used by >> + // derived classes. >> >> using iterator = typename basic_string_view<_CharT>::iterator; >> >> @@ -562,7 +571,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 +580,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 +612,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 +880,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, >> @@ -899,9 +908,10 @@ namespace __format >> >> // Values are indices into _Escapes::all. >> enum class _Term_char : unsigned char { >> - _Tc_quote = 12, >> - _Tc_apos = 15 >> + _Term_quote = 12, >> + _Term_apos = 15 >> }; >> + using enum _Term_char; >> >> template<typename _CharT> >> struct _Escapes >> @@ -991,9 +1001,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; >> }; >> @@ -1312,11 +1322,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 +1345,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 +1362,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 +1400,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 +1453,7 @@ namespace __format >> >> constexpr void >> set_debug_format() noexcept >> - { _M_spec._M_type = _Pres_esc; } >> + { _M_spec._M_debug = true; } >> #endif >> >> private: >> @@ -1462,7 +1474,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 +1566,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 +1574,7 @@ namespace __format >> case '?': >> if (__type == _AsChar) >> { >> - __spec._M_type = _Pres_esc; >> + __spec._M_debug = true; >> ++__first; >> } >> #endif >> @@ -1580,7 +1595,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 +1605,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 +1719,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 >> - 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 >> + 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); >> + __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); >> } >> >> @@ -2419,17 +2419,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 = [&] { >> @@ -2457,19 +2458,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; >> @@ -2536,6 +2541,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{}; >> }; >> >> @@ -2558,11 +2574,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); >> } >> @@ -2570,7 +2583,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: >> @@ -2594,11 +2607,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); >> } >> @@ -2606,7 +2616,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: >> @@ -3792,7 +3802,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, >> @@ -3806,6 +3816,7 @@ namespace __format >> #endif >> _Arg_max_ >> }; >> + using enum _Arg_t; >> >> template<typename _Context> >> struct _Arg_value >> @@ -4373,7 +4384,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 >> @@ -4386,7 +4397,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...>; >> @@ -5725,7 +5736,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'"); >> @@ -5736,8 +5747,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" >> @@ -5819,8 +5829,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 >> >>