Skip to content

Commit b34b4ad

Browse files
Implement formattable, range_format, and format_kind (#4116)
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
1 parent b7c458a commit b34b4ad

7 files changed

Lines changed: 430 additions & 30 deletions

File tree

stl/inc/chrono

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5799,67 +5799,69 @@ private:
57995799
_CHRONO _Chrono_formatter<_CharT> _Impl;
58005800
};
58015801

5802-
template <class _Rep, class _Period, class _CharT>
5802+
// Per LWG-3997, the _CharT template parameter is constrained to supported character types.
5803+
5804+
template <class _Rep, class _Period, _Format_supported_charT _CharT>
58035805
struct formatter<_CHRONO duration<_Rep, _Period>, _CharT>
58045806
: _Fill_tm_formatter<_CHRONO duration<_Rep, _Period>, _CharT> {};
58055807

5806-
template <class _CharT>
5808+
template <_Format_supported_charT _CharT>
58075809
struct formatter<_CHRONO day, _CharT> : _Fill_tm_formatter<_CHRONO day, _CharT> {};
58085810

5809-
template <class _CharT>
5811+
template <_Format_supported_charT _CharT>
58105812
struct formatter<_CHRONO month, _CharT> : _Fill_tm_formatter<_CHRONO month, _CharT> {};
58115813

5812-
template <class _CharT>
5814+
template <_Format_supported_charT _CharT>
58135815
struct formatter<_CHRONO year, _CharT> : _Fill_tm_formatter<_CHRONO year, _CharT> {};
58145816

5815-
template <class _CharT>
5817+
template <_Format_supported_charT _CharT>
58165818
struct formatter<_CHRONO weekday, _CharT> : _Fill_tm_formatter<_CHRONO weekday, _CharT> {};
58175819

5818-
template <class _CharT>
5820+
template <_Format_supported_charT _CharT>
58195821
struct formatter<_CHRONO weekday_indexed, _CharT> : _Fill_tm_formatter<_CHRONO weekday_indexed, _CharT> {};
58205822

5821-
template <class _CharT>
5823+
template <_Format_supported_charT _CharT>
58225824
struct formatter<_CHRONO weekday_last, _CharT> : _Fill_tm_formatter<_CHRONO weekday_last, _CharT> {};
58235825

5824-
template <class _CharT>
5826+
template <_Format_supported_charT _CharT>
58255827
struct formatter<_CHRONO month_day, _CharT> : _Fill_tm_formatter<_CHRONO month_day, _CharT> {};
58265828

5827-
template <class _CharT>
5829+
template <_Format_supported_charT _CharT>
58285830
struct formatter<_CHRONO month_day_last, _CharT> : _Fill_tm_formatter<_CHRONO month_day_last, _CharT> {};
58295831

5830-
template <class _CharT>
5832+
template <_Format_supported_charT _CharT>
58315833
struct formatter<_CHRONO month_weekday, _CharT> : _Fill_tm_formatter<_CHRONO month_weekday, _CharT> {};
58325834

5833-
template <class _CharT>
5835+
template <_Format_supported_charT _CharT>
58345836
struct formatter<_CHRONO month_weekday_last, _CharT> : _Fill_tm_formatter<_CHRONO month_weekday_last, _CharT> {};
58355837

5836-
template <class _CharT>
5838+
template <_Format_supported_charT _CharT>
58375839
struct formatter<_CHRONO year_month, _CharT> : _Fill_tm_formatter<_CHRONO year_month, _CharT> {};
58385840

5839-
template <class _CharT>
5841+
template <_Format_supported_charT _CharT>
58405842
struct formatter<_CHRONO year_month_day, _CharT> : _Fill_tm_formatter<_CHRONO year_month_day, _CharT> {};
58415843

5842-
template <class _CharT>
5844+
template <_Format_supported_charT _CharT>
58435845
struct formatter<_CHRONO year_month_day_last, _CharT> : _Fill_tm_formatter<_CHRONO year_month_day_last, _CharT> {};
58445846

5845-
template <class _CharT>
5847+
template <_Format_supported_charT _CharT>
58465848
struct formatter<_CHRONO year_month_weekday, _CharT> : _Fill_tm_formatter<_CHRONO year_month_weekday, _CharT> {};
58475849

5848-
template <class _CharT>
5850+
template <_Format_supported_charT _CharT>
58495851
struct formatter<_CHRONO year_month_weekday_last, _CharT>
58505852
: _Fill_tm_formatter<_CHRONO year_month_weekday_last, _CharT> {};
58515853

5852-
template <class _Rep, class _Period, class _CharT>
5854+
template <class _Rep, class _Period, _Format_supported_charT _CharT>
58535855
struct formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT>
58545856
: _Fill_tm_formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT> {};
58555857

5856-
template <class _CharT>
5858+
template <_Format_supported_charT _CharT>
58575859
struct formatter<_CHRONO sys_info, _CharT> : _Fill_tm_formatter<_CHRONO sys_info, _CharT> {};
58585860

5859-
template <class _CharT>
5861+
template <_Format_supported_charT _CharT>
58605862
struct formatter<_CHRONO local_info, _CharT> : _Fill_tm_formatter<_CHRONO local_info, _CharT> {};
58615863

5862-
template <class _Duration, class _CharT>
5864+
template <class _Duration, _Format_supported_charT _CharT>
58635865
struct formatter<_CHRONO sys_time<_Duration>, _CharT> {
58645866
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
58655867
return _Impl.template _Parse<_CHRONO sys_time<_Duration>>(_Parse_ctx);
@@ -5874,7 +5876,7 @@ private:
58745876
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")};
58755877
};
58765878

5877-
template <class _Duration, class _CharT>
5879+
template <class _Duration, _Format_supported_charT _CharT>
58785880
struct formatter<_CHRONO utc_time<_Duration>, _CharT> {
58795881
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
58805882
return _Impl.template _Parse<_CHRONO utc_time<_Duration>>(_Parse_ctx);
@@ -5890,7 +5892,7 @@ private:
58905892
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")};
58915893
};
58925894

5893-
template <class _Duration, class _CharT>
5895+
template <class _Duration, _Format_supported_charT _CharT>
58945896
struct formatter<_CHRONO tai_time<_Duration>, _CharT> {
58955897
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
58965898
return _Impl.template _Parse<_CHRONO tai_time<_Duration>>(_Parse_ctx);
@@ -5909,7 +5911,7 @@ private:
59095911
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "TAI")};
59105912
};
59115913

5912-
template <class _Duration, class _CharT>
5914+
template <class _Duration, _Format_supported_charT _CharT>
59135915
struct formatter<_CHRONO gps_time<_Duration>, _CharT> {
59145916
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
59155917
return _Impl.template _Parse<_CHRONO gps_time<_Duration>>(_Parse_ctx);
@@ -5928,7 +5930,7 @@ private:
59285930
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "GPS")};
59295931
};
59305932

5931-
template <class _Duration, class _CharT>
5933+
template <class _Duration, _Format_supported_charT _CharT>
59325934
struct formatter<_CHRONO file_time<_Duration>, _CharT> {
59335935
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
59345936
return _Impl.template _Parse<_CHRONO file_time<_Duration>>(_Parse_ctx);
@@ -5945,14 +5947,14 @@ private:
59455947
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")};
59465948
};
59475949

5948-
template <class _Duration, class _CharT>
5950+
template <class _Duration, _Format_supported_charT _CharT>
59495951
struct formatter<_CHRONO local_time<_Duration>, _CharT> : _Fill_tm_formatter<_CHRONO local_time<_Duration>, _CharT> {};
59505952

5951-
template <class _Duration, class _CharT>
5953+
template <class _Duration, _Format_supported_charT _CharT>
59525954
struct formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT>
59535955
: _Fill_tm_formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT> {};
59545956

5955-
template <class _Duration, class _TimeZonePtr, class _CharT>
5957+
template <class _Duration, class _TimeZonePtr, _Format_supported_charT _CharT>
59565958
struct formatter<_CHRONO zoned_time<_Duration, _TimeZonePtr>, _CharT>
59575959
: formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT> {
59585960

stl/inc/format

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,27 @@ public:
22292229
}
22302230
};
22312231

2232+
#if _HAS_CXX23
2233+
template <class _CharT>
2234+
struct _Phony_fmt_iter_for {
2235+
using iterator_category = output_iterator_tag;
2236+
using value_type = _CharT;
2237+
using difference_type = ptrdiff_t;
2238+
using pointer = _CharT*;
2239+
using reference = _CharT&;
2240+
2241+
reference operator*() const;
2242+
pointer operator->() const;
2243+
2244+
_Phony_fmt_iter_for& operator++();
2245+
_Phony_fmt_iter_for operator++(int);
2246+
};
2247+
2248+
_EXPORT_STD template <class _Ty, class _CharT>
2249+
concept formattable =
2250+
_Formattable_with<remove_reference_t<_Ty>, basic_format_context<_Phony_fmt_iter_for<_CharT>, _CharT>>;
2251+
#endif // _HAS_CXX23
2252+
22322253
template <class _Ty>
22332254
class _Fmt_buffer {
22342255
private:
@@ -2428,6 +2449,45 @@ using _Fmt_wit = back_insert_iterator<_Fmt_buffer<wchar_t>>;
24282449
_EXPORT_STD using format_context = basic_format_context<_Fmt_it, char>;
24292450
_EXPORT_STD using wformat_context = basic_format_context<_Fmt_wit, wchar_t>;
24302451

2452+
#if _HAS_CXX23
2453+
_EXPORT_STD enum class range_format { disabled, map, set, sequence, string, debug_string };
2454+
2455+
template <class _Ty>
2456+
struct _Invalid_format_kind {
2457+
static_assert(_Always_false<_Ty>, "A program that instantiates the primary template of format_kind is ill-formed. "
2458+
"(N4964 [format.range.fmtkind]/1)");
2459+
};
2460+
2461+
_EXPORT_STD template <class _Ty>
2462+
constexpr _Invalid_format_kind<_Ty> format_kind{};
2463+
2464+
template <class _Ty>
2465+
inline constexpr bool _Is_two_tuple = false;
2466+
2467+
template <class _Ty, class _Uty>
2468+
inline constexpr bool _Is_two_tuple<pair<_Ty, _Uty>> = true;
2469+
2470+
template <class _Ty, class _Uty>
2471+
inline constexpr bool _Is_two_tuple<tuple<_Ty, _Uty>> = true;
2472+
2473+
template <_RANGES input_range _Rng>
2474+
requires same_as<_Rng, remove_cvref_t<_Rng>>
2475+
constexpr range_format format_kind<_Rng> = []() consteval {
2476+
using _Ref_value_t = remove_cvref_t<_RANGES range_reference_t<_Rng>>;
2477+
if constexpr (same_as<_Ref_value_t, _Rng>) {
2478+
return range_format::disabled;
2479+
} else if constexpr (requires { typename _Rng::key_type; }) {
2480+
if constexpr (requires { typename _Rng::mapped_type; } && _Is_two_tuple<_Ref_value_t>) {
2481+
return range_format::map;
2482+
} else {
2483+
return range_format::set;
2484+
}
2485+
} else {
2486+
return range_format::sequence;
2487+
}
2488+
}();
2489+
#endif // _HAS_CXX23
2490+
24312491
_FMT_P2286_BEGIN
24322492
template <class _CharT, class _OutputIt>
24332493
_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate) {

stl/inc/thread

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ basic_ostream<_Ch, _Tr>& operator<<(basic_ostream<_Ch, _Tr>& _Str, thread::id _I
297297
}
298298

299299
#if _HAS_CXX23 && defined(__cpp_lib_concepts)
300-
template <class _CharT>
300+
// Per LWG-3997, the _CharT template parameter is constrained to supported character types.
301+
template <_Format_supported_charT _CharT>
301302
struct formatter<thread::id, _CharT> {
302303
private:
303304
using _Pc = basic_format_parse_context<_CharT>;

tests/libcxx/expected_results.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,6 @@ std/language.support/support.limits/support.limits.general/type_traits.version.c
351351

352352
# P2286R8 Formatting Ranges
353353
std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp FAIL
354-
std/utilities/format/format.range/format.range.fmtkind/format_kind.compile.pass.cpp FAIL
355-
std/utilities/format/format.range/format.range.fmtkind/range_format.compile.pass.cpp FAIL
356354
std/utilities/format/format.tuple/format.functions.format.pass.cpp FAIL
357355
std/utilities/format/format.tuple/format.functions.vformat.pass.cpp FAIL
358356
std/utilities/format/format.tuple/format.pass.cpp FAIL

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ tests\P2286R8_text_formatting_debug_enabled_specializations
600600
tests\P2286R8_text_formatting_escaping
601601
tests\P2286R8_text_formatting_escaping_legacy_text_encoding
602602
tests\P2286R8_text_formatting_escaping_utf8
603+
tests\P2286R8_text_formatting_formattable
603604
tests\P2302R4_ranges_alg_contains
604605
tests\P2302R4_ranges_alg_contains_subrange
605606
tests\P2321R2_proxy_reference
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\concepts_latest_matrix.lst

0 commit comments

Comments
 (0)