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, */ > > 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 > > > > > >