[PATCH v2] libstdc++: Implement formatters for pair and tuple [PR109162]

Jonathan Wakely jwakely@redhat.com
Wed Apr 16 10:09:29 GMT 2025


On 16/04/25 11:45 +0200, Tomasz Kamiński wrote:
>This patch implements formatter specializations for pair and tuple form
>P2286R8. In addition using 'm` and range_format::map (from P2585R1) for
>ranges are now supported.
>
>The formatters for pairs and tuples whose corresponding elements are the same
>(after applying remove_cvref_t) derive from the same __tuple_formatter class.
>This reduce the code duplication, as most of the parsing and formatting is the
>same in such cases. We use a custom reduced implementation of the tuple
>(__formatters_storage) to store the elements formatters.
>
>Handling of the padding (width and fill) options, is extracted to
>__format::__format_padded function, that is used both by __tuple_formatter and
>range_formatter. To reduce number of instantations range_formatter::format
>triggers, we cast incoming range to __format::__maybe_const_range<_Rg, _CharT>&,
>before formatting it.
>
>As in the case of previous commits, the signatures of the user-facing parse
>and format methods of the provided formatters deviate from the standard by
>constraining types of parameters:
>* _CharT is constrained __formatter::__char
>* basic_format_parse_context<_CharT> for parse argument
>* basic_format_context<_Out, _CharT> for format second argument
>The standard specifies last three of above as unconstrained types.
>
>Finally, test for tuple-like std::array and std::ranges::subrange,
>that illustrate that they remain formatted as ranges.
>
>	PR libstdc++/PR109162
>
>libstdc++-v3/ChangeLog:
>
>	* include/std/format (__formatter_int::_M_format_character_escaped)
>	(__formatter_str::format): Use __sink.out() to produce _Sink_iter.
>	(__format::__const_formattable_range): Moved closer to range_formatter.
>	(__format::__maybe_const_range): Use `__conditional_t` and moved closer
>	to range_formatter.
>	(__format::__format_padded, __format::maybe_const)
>	(__format::__indexed_formatter_storage, __format::__tuple_formatter)
>	(std::formatter<pair<_Fp, _Sp>, _CharT>>)
>	(std::formatter<tuple<_Tps...>, _CharT): Define.
>	(std::formatter<_Rg, _CharT>::format): Cast incoming range to
>	__format::__maybe_const_range<_Rg, _CharT>&.
>	(std::formatter<_Rg, _CharT>::_M_format): Extracted from format,
>	and use __format_padded.
>	(std::formatter<_Rg, _CharT>::_M_format_no_padding): Rename...
>	(std::formatter<_Rg, _CharT>::_M_format_elems): ...to this.
>	(std::formatter<_Rg, _CharT>::_M_format_with_padding): Extracted as
>	__format_padded.
>	* testsuite/util/testsuite_iterators.h (test_input_range_nocopy):
>	Define.
>	* testsuite/std/format/ranges/formatter.cc: Tests for `m` specifier.
>	* testsuite/std/format/ranges/sequence.cc: Tests for array and subrange.
>	* testsuite/std/format/ranges/map.cc: New test.
>	* testsuite/std/format/tuple.cc: New test.
>---
>I doged the which is safe, static_cast or const_cast discussion by
>calling:
>+         using __maybe_const_range
>+           = __format::__maybe_const_range<_Rg, _CharT>;
>+         return _M_format<__maybe_const_range>(__rg, __fc);

OK.

>I have also applied the `__conditional_t` to __maybe_const_range,
>and moved this two helpers closer to range_formatter.

Thanks.

And addressof is qualified, and trigger is renamed to _M_trigger.

>OK for trunk?

OK, thanks.




More information about the Libstdc++ mailing list