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
>>
>>

Reply via email to