From 9680f9a8351631001d7002b690b8d94c43c30dbd Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 3 Nov 2021 16:03:12 -0700 Subject: [PATCH 01/11] add a few tests for new P2418R2 --- stl/inc/format | 57 +++++++++++-------- .../test.cpp | 22 +++++++ .../test.cpp | 11 ++++ 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index 9ed19e19558..1dd51b0e2a5 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -169,6 +169,16 @@ concept _CharT_or_bool = same_as<_Ty, _CharT> || same_as<_Ty, bool>; template concept _Format_supported_charT = _Is_any_of_v<_CharT, char, wchar_t>; +template +concept _Has_formatter = requires(_Ty& _Val, _Context& _Ctx) { + _STD declval>>().format(_Val, _Ctx); +}; + +template +concept _Has_const_formatter = requires(const _Ty& _Val, _Context& _Ctx) { + _STD declval>>().format(_Val, _Ctx); +}; + template struct formatter; @@ -259,12 +269,16 @@ public: public: template - explicit handle(const _Ty& _Val) noexcept + explicit handle(_Ty&& _Val) noexcept : _Ptr(_STD addressof(_Val)), _Format([](basic_format_parse_context<_CharType>& _Parse_ctx, _Context& _Format_ctx, const void* _Ptr) { - typename _Context::template formatter_type<_Ty> _Formatter; + using _Value_type = remove_cvref_t<_Ty>; + typename _Context::template formatter_type<_Value_type> _Formatter; + using _Qualified_type = + conditional_t<_Has_const_formatter<_Value_type, _Context>, const _Value_type, _Value_type>; _Parse_ctx.advance_to(_Formatter.parse(_Parse_ctx)); - _Format_ctx.advance_to(_Formatter.format(*static_cast(_Ptr), _Format_ctx)); + _Format_ctx.advance_to(_Formatter.format( + *const_cast<_Qualified_type*>(static_cast(_Ptr)), _Format_ctx)); }) {} void format(basic_format_parse_context<_CharType>& _Parse_ctx, _Context& _Format_ctx) const { @@ -1270,11 +1284,6 @@ public: } }; -template -concept _Has_formatter = requires(const _Ty& _Val, _Context& _Ctx) { - _STD declval>().format(_Val, _Ctx); -}; - template struct _Format_arg_traits { using _Char_type = typename _Context::char_type; @@ -1283,7 +1292,7 @@ struct _Format_arg_traits { // set of basic_format_arg (N4885 [format.arg]). They determine the mapping // from "raw" to "erased" argument type for _Format_arg_store. template <_Has_formatter<_Context> _Ty> - static auto _Phony_basic_format_arg_constructor(const _Ty&) { + static auto _Phony_basic_format_arg_constructor(_Ty&&) { // See N4885 [format.arg]/5 if constexpr (is_same_v<_Ty, bool>) { return bool{}; @@ -1327,7 +1336,7 @@ struct _Format_arg_traits { // clang-format on template - using _Storage_type = decltype(_Phony_basic_format_arg_constructor(_STD declval())); + using _Storage_type = decltype(_Phony_basic_format_arg_constructor(_STD declval<_Ty&&>())); template static constexpr size_t _Storage_size = sizeof(_Storage_type<_Ty>); @@ -2797,12 +2806,12 @@ using format_args = basic_format_args; using wformat_args = basic_format_args; template -_NODISCARD auto make_format_args(const _Args&... _Vals) { +_NODISCARD auto make_format_args(_Args&&... _Vals) { return _Format_arg_store<_Context, _Args...>{_Vals...}; } template -_NODISCARD auto make_wformat_args(const _Args&... _Vals) { +_NODISCARD auto make_wformat_args(_Args&&... _Vals) { return _Format_arg_store{_Vals...}; } @@ -2911,22 +2920,22 @@ _NODISCARD inline wstring vformat(const locale& _Loc, const wstring_view _Fmt, c } template -_NODISCARD string format(const string_view _Fmt, const _Types&... _Args) { +_NODISCARD string format(const string_view _Fmt, _Types&&... _Args) { return _STD vformat(_Fmt, _STD make_format_args(_Args...)); } template -_NODISCARD wstring format(const wstring_view _Fmt, const _Types&... _Args) { +_NODISCARD wstring format(const wstring_view _Fmt, _Types&&... _Args) { return _STD vformat(_Fmt, _STD make_wformat_args(_Args...)); } template -_NODISCARD string format(const locale& _Loc, const string_view _Fmt, const _Types&... _Args) { +_NODISCARD string format(const locale& _Loc, const string_view _Fmt, _Types&&... _Args) { return _STD vformat(_Loc, _Fmt, _STD make_format_args(_Args...)); } template -_NODISCARD wstring format(const locale& _Loc, const wstring_view _Fmt, const _Types&... _Args) { +_NODISCARD wstring format(const locale& _Loc, const wstring_view _Fmt, _Types&&... _Args) { return _STD vformat(_Loc, _Fmt, _STD make_wformat_args(_Args...)); } @@ -2938,7 +2947,7 @@ struct format_to_n_result { template _OutputIt, class... _Types> format_to_n_result<_OutputIt> format_to_n( - _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const string_view _Fmt, const _Types&... _Args) { + _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const string_view _Fmt, _Types&&... _Args) { _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); _STD vformat_to(_Fmt_it{_Buf}, _Fmt, _STD make_format_args(_Args...)); return {.out = _Buf._Out(), .size = _Buf._Count()}; @@ -2946,7 +2955,7 @@ format_to_n_result<_OutputIt> format_to_n( template _OutputIt, class... _Types> format_to_n_result<_OutputIt> format_to_n( - _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const wstring_view _Fmt, const _Types&... _Args) { + _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const wstring_view _Fmt, _Types&&... _Args) { _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); _STD vformat_to(_Fmt_wit{_Buf}, _Fmt, _STD make_wformat_args(_Args...)); return {.out = _Buf._Out(), .size = _Buf._Count()}; @@ -2954,7 +2963,7 @@ format_to_n_result<_OutputIt> format_to_n( template _OutputIt, class... _Types> format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const locale& _Loc, - const string_view _Fmt, const _Types&... _Args) { + const string_view _Fmt, _Types&&... _Args) { _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt, _STD make_format_args(_Args...)); return {.out = _Buf._Out(), .size = _Buf._Count()}; @@ -2962,35 +2971,35 @@ format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_ template _OutputIt, class... _Types> format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const locale& _Loc, - const wstring_view _Fmt, const _Types&... _Args) { + const wstring_view _Fmt, _Types&&... _Args) { _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt, _STD make_wformat_args(_Args...)); return {.out = _Buf._Out(), .size = _Buf._Count()}; } template -_NODISCARD size_t formatted_size(const string_view _Fmt, const _Types&... _Args) { +_NODISCARD size_t formatted_size(const string_view _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_it{_Buf}, _Fmt, _STD make_format_args(_Args...)); return _Buf._Count(); } template -_NODISCARD size_t formatted_size(const wstring_view _Fmt, const _Types&... _Args) { +_NODISCARD size_t formatted_size(const wstring_view _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_wit{_Buf}, _Fmt, _STD make_wformat_args(_Args...)); return _Buf._Count(); } template -_NODISCARD size_t formatted_size(const locale& _Loc, const string_view _Fmt, const _Types&... _Args) { +_NODISCARD size_t formatted_size(const locale& _Loc, const string_view _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt, _STD make_format_args(_Args...)); return _Buf._Count(); } template -_NODISCARD size_t formatted_size(const locale& _Loc, const wstring_view _Fmt, const _Types&... _Args) { +_NODISCARD size_t formatted_size(const locale& _Loc, const wstring_view _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt, _STD make_wformat_args(_Args...)); return _Buf._Count(); diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp index a087e83d50a..0ce59cc5589 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp @@ -35,6 +35,13 @@ struct basic_custom_formattable_type { string_view string_content; }; +struct move_only_custom_formattable_type { + string_view string_content; + move_only_custom_formattable_type(string_view val) : string_content(val) {} + move_only_custom_formattable_type(const move_only_custom_formattable_type&) = delete; + move_only_custom_formattable_type(move_only_custom_formattable_type&&) = default; +}; + template <> struct std::formatter { basic_format_parse_context::iterator parse(basic_format_parse_context& parse_ctx) { @@ -49,6 +56,20 @@ struct std::formatter { } }; +template <> +struct std::formatter { + basic_format_parse_context::iterator parse(basic_format_parse_context& parse_ctx) { + if (parse_ctx.begin() != parse_ctx.end()) { + throw format_error{"only empty specs please"}; + } + return parse_ctx.end(); + } + format_context::iterator format(move_only_custom_formattable_type& val, format_context& ctx) { + ctx.advance_to(copy(val.string_content.begin(), val.string_content.end(), ctx.out())); + return ctx.out(); + } +}; + template struct custom_formattable_type { T val; @@ -141,6 +162,7 @@ void test_mixed_custom_formattable_type() { int main() { assert(format("{}", basic_custom_formattable_type{"f"}) == "f"s); + assert(format("{}", move_only_custom_formattable_type{"f"}) == "f"s); test_custom_formattable_type(); test_custom_formattable_type(); test_mixed_custom_formattable_type(); diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index e6c4939de42..fee766cd60e 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1344,6 +1344,14 @@ void test_slow_append_path() { assert(str == hello_world); } + +template +void test_oddball_types_p2418r2() { + int i = 3; + int& i_ref = i; + assert(format(STR("{}"), i_ref) == STR("3")); +} + void test() { test_simple_formatting(); test_simple_formatting(); @@ -1413,6 +1421,9 @@ void test() { test_slow_append_path(); test_slow_append_path(); + + test_oddball_types_p2418r2(); + test_oddball_types_p2418r2(); } int main() { From 41de6fd55cafec98c3b4bf05ae0284eb14af756f Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 3 Nov 2021 18:36:06 -0700 Subject: [PATCH 02/11] forward from make_format_args --- stl/inc/format | 12 ++++++------ .../P0645R10_text_formatting_formatting/test.cpp | 11 ----------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index 1dd51b0e2a5..4db84da5290 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1400,8 +1400,8 @@ private: } template - void _Store(const size_t _Arg_index, const _Ty& _Val) noexcept { - using _Erased_type = typename _Traits::template _Storage_type<_Ty>; + void _Store(const size_t _Arg_index, _Ty&& _Val) noexcept { + using _Erased_type = typename _Traits::template _Storage_type>; _Basic_format_arg_type _Arg_type; if constexpr (is_same_v<_Erased_type, bool>) { @@ -1437,10 +1437,10 @@ private: } public: - _Format_arg_store(const _Args&... _Vals) noexcept { + _Format_arg_store(_Args&&... _Vals) noexcept { _Index_array[0] = {}; size_t _Arg_index = 0; - (_Store(_Arg_index++, _Vals), ...); + (_Store(_Arg_index++, static_cast<_Args&&>(_Vals)), ...); } }; @@ -2807,12 +2807,12 @@ using wformat_args = basic_format_args; template _NODISCARD auto make_format_args(_Args&&... _Vals) { - return _Format_arg_store<_Context, _Args...>{_Vals...}; + return _Format_arg_store<_Context, _Args...>{static_cast<_Args&&>(_Vals)...}; } template _NODISCARD auto make_wformat_args(_Args&&... _Vals) { - return _Format_arg_store{_Vals...}; + return _Format_arg_store{static_cast<_Args&&>(_Vals)...}; } template _OutputIt> diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index fee766cd60e..e6c4939de42 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1344,14 +1344,6 @@ void test_slow_append_path() { assert(str == hello_world); } - -template -void test_oddball_types_p2418r2() { - int i = 3; - int& i_ref = i; - assert(format(STR("{}"), i_ref) == STR("3")); -} - void test() { test_simple_formatting(); test_simple_formatting(); @@ -1421,9 +1413,6 @@ void test() { test_slow_append_path(); test_slow_append_path(); - - test_oddball_types_p2418r2(); - test_oddball_types_p2418r2(); } int main() { From b74bd0a4fe13a4dce5c7d6daa9cdcd3476367fc3 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 3 Nov 2021 18:46:51 -0700 Subject: [PATCH 03/11] correct storage size --- stl/inc/format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/format b/stl/inc/format index 4db84da5290..37ba7bbf23b 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1339,7 +1339,7 @@ struct _Format_arg_traits { using _Storage_type = decltype(_Phony_basic_format_arg_constructor(_STD declval<_Ty&&>())); template - static constexpr size_t _Storage_size = sizeof(_Storage_type<_Ty>); + static constexpr size_t _Storage_size = sizeof(_Storage_type>); }; struct _Format_arg_index { From 545296657a5e5a1d8289a4fcede7bb49fd5e3698 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Fri, 12 Nov 2021 20:55:48 -0800 Subject: [PATCH 04/11] address some review comments. --- stl/inc/format | 10 ++--- stl/inc/yvals_core.h | 1 + .../test.cpp | 39 ++++++++++++++++++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index 37ba7bbf23b..9fbd673883a 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1336,7 +1336,7 @@ struct _Format_arg_traits { // clang-format on template - using _Storage_type = decltype(_Phony_basic_format_arg_constructor(_STD declval<_Ty&&>())); + using _Storage_type = decltype(_Phony_basic_format_arg_constructor(_STD declval<_Ty>())); template static constexpr size_t _Storage_size = sizeof(_Storage_type>); @@ -2872,22 +2872,22 @@ _OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const wstring_view _Fmt } template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const string_view _Fmt, const _Types&... _Args) { +_OutputIt format_to(_OutputIt _Out, const string_view _Fmt, _Types&&... _Args) { return _STD vformat_to(_STD move(_Out), _Fmt, _STD make_format_args(_Args...)); } template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const wstring_view _Fmt, const _Types&... _Args) { +_OutputIt format_to(_OutputIt _Out, const wstring_view _Fmt, _Types&&... _Args) { return _STD vformat_to(_STD move(_Out), _Fmt, _STD make_wformat_args(_Args...)); } template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const string_view _Fmt, const _Types&... _Args) { +_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const string_view _Fmt, _Types&&... _Args) { return _STD vformat_to(_STD move(_Out), _Loc, _Fmt, _STD make_format_args(_Args...)); } template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const wstring_view _Fmt, const _Types&... _Args) { +_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const wstring_view _Fmt, _Types&&... _Args) { return _STD vformat_to(_STD move(_Out), _Loc, _Fmt, _STD make_wformat_args(_Args...)); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index fb4adb47f77..f76cba0c288 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -261,6 +261,7 @@ // P2328R1 join_view Should Join All views Of ranges // P2367R0 Remove Misuses Of List-Initialization From Clause 24 Ranges // P2432R1 Fix istream_view +// P2418R2 add support for std::generator-like types to std::format // P????R? directory_entry::clear_cache() // _HAS_CXX20 indirectly controls: diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp index 0ce59cc5589..ecc0f26be45 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,7 +39,7 @@ struct basic_custom_formattable_type { struct move_only_custom_formattable_type { string_view string_content; - move_only_custom_formattable_type(string_view val) : string_content(val) {} + explicit move_only_custom_formattable_type(string_view val) : string_content(val) {} move_only_custom_formattable_type(const move_only_custom_formattable_type&) = delete; move_only_custom_formattable_type(move_only_custom_formattable_type&&) = default; }; @@ -160,9 +162,44 @@ void test_mixed_custom_formattable_type() { test_numeric_mixed_args_custom_formattable_type(); } +template +void test_basic_custom_formatting() {} + int main() { + string str; + assert(format("{}", basic_custom_formattable_type{"f"}) == "f"s); + assert(format(locale{}, "{}", basic_custom_formattable_type{"f"}) == "f"s); + format_to(back_insert_iterator(str), "{}", basic_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + format_to(back_insert_iterator(str), locale{}, "{}", basic_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + format_to_n(back_insert_iterator(str), 5, "{}", basic_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + format_to_n(back_insert_iterator(str), 5, locale{}, "{}", basic_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + + assert(format("{}", move_only_custom_formattable_type{"f"}) == "f"s); + assert(format(locale{}, "{}", move_only_custom_formattable_type{"f"}) == "f"s); + format_to(back_insert_iterator(str), "{}", move_only_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + format_to(back_insert_iterator(str), locale{}, "{}", move_only_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + format_to_n(back_insert_iterator(str), 5, "{}", move_only_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + format_to_n(back_insert_iterator(str), 5, locale{}, "{}", move_only_custom_formattable_type{"f"}); + assert(str == "f"); + str.clear(); + + test_custom_formattable_type(); test_custom_formattable_type(); test_mixed_custom_formattable_type(); From d26cedbfecfa5dcb7e159d8c4a8399553ad4a871 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Tue, 7 Dec 2021 17:15:16 -0800 Subject: [PATCH 05/11] Apply a static assert for the case of trying to format a const something that it not const formattable. --- stl/inc/format | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stl/inc/format b/stl/inc/format index 9fbd673883a..50e07e1d640 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -279,7 +279,9 @@ public: _Parse_ctx.advance_to(_Formatter.parse(_Parse_ctx)); _Format_ctx.advance_to(_Formatter.format( *const_cast<_Qualified_type*>(static_cast(_Ptr)), _Format_ctx)); - }) {} + }) { + static_assert(_Has_const_formatter<_Ty, _Context> || !is_const_v>); + } void format(basic_format_parse_context<_CharType>& _Parse_ctx, _Context& _Format_ctx) const { _Format(_Parse_ctx, _Format_ctx, _Ptr); From 1c56f831a0b5517c1f4d7cab97071dc434ef80e1 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 12 Jan 2022 14:30:50 -0800 Subject: [PATCH 06/11] actually fix tests after the compile-time-checks changes. --- stl/inc/format | 4 ++-- .../P0645R10_text_formatting_formatting/test.cpp | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index c5e176d4516..9f2a8e766ab 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -3143,14 +3143,14 @@ format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_ } template -_NODISCARD size_t formatted_size(const _Fmt_string<_Types...> _Fmt, _Types&&... _Args) { +_NODISCARD size_t formatted_size(_Fmt_string<_Types...> _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_it{_Buf}, _Fmt._Str, _STD make_format_args(_Args...)); return _Buf._Count(); } template -_NODISCARD size_t formatted_size(const _Fmt_wstring<_Types...> _Fmt, _Types&&... _Args) { +_NODISCARD size_t formatted_size(_Fmt_wstring<_Types...> _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_wit{_Buf}, _Fmt._Str, _STD make_wformat_args(_Args...)); return _Buf._Count(); diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index 9f698c38fbe..058a0a85a85 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -992,16 +992,15 @@ void test_spec_replacement_field() { test_string_specs(); } template -void test_size_helper_impl( - const size_t expected_size, const _Basic_format_string fmt, const Args&... args) { - assert(formatted_size(fmt, args...) == expected_size); - assert(formatted_size(locale::classic(), fmt, args...) == expected_size); +void test_size_helper_impl(const size_t expected_size, const _Basic_format_string fmt, Args&&... args) { + assert(formatted_size(fmt, forward(args)...) == expected_size); + assert(formatted_size(locale::classic(), fmt, forward(args)...) == expected_size); const auto signed_size = static_cast(expected_size); basic_string str; { str.resize(expected_size); - const auto res = format_to_n(str.begin(), signed_size, fmt, args...); + const auto res = format_to_n(str.begin(), signed_size, fmt, forward(args)...); assert(res.size == signed_size); assert(res.out - str.begin() == signed_size); assert(res.out == str.end()); @@ -1009,7 +1008,7 @@ void test_size_helper_impl( basic_string locale_str; locale_str.resize(expected_size); - format_to_n(locale_str.begin(), signed_size, locale::classic(), fmt, args...); + format_to_n(locale_str.begin(), signed_size, locale::classic(), fmt, forward(args)...); assert(str == locale_str); assert(locale_str.size() == expected_size); } @@ -1017,7 +1016,7 @@ void test_size_helper_impl( { const auto half_size = expected_size / 2; half_str.resize(half_size); - const auto res = format_to_n(half_str.begin(), static_cast(half_size), fmt, args...); + const auto res = format_to_n(half_str.begin(), static_cast(half_size), fmt, forward(args)...); assert(res.size == signed_size); assert(static_cast(res.out - half_str.begin()) == half_size); assert(res.out == half_str.end()); From 02903a3a817d4479050fecbb5d61c311d0c097e1 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 12 Jan 2022 14:43:52 -0800 Subject: [PATCH 07/11] manually revert new clang-format changes. --- stl/inc/format | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index 9f2a8e766ab..22568907fd9 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -390,7 +390,7 @@ _NODISCARD constexpr const _CharT* _Parse_nonnegative_integer( const _CharT* _First, const _CharT* _Last, unsigned int& _Value) { _STL_INTERNAL_CHECK(_First != _Last && '0' <= *_First && *_First <= '9'); - constexpr auto _Max_int = static_cast((numeric_limits::max)()); + constexpr auto _Max_int = static_cast((numeric_limits::max) ()); constexpr auto _Big_int = _Max_int / 10u; _Value = 0; @@ -1150,7 +1150,7 @@ template _NODISCARD constexpr int _Get_dynamic_specs(const _FormatArg _Arg) { _STL_INTERNAL_STATIC_ASSERT(_Is_any_of_v<_Handler, _Width_checker, _Precision_checker>); const unsigned long long _Val = _STD visit_format_arg(_Handler{}, _Arg); - if (_Val > static_cast((numeric_limits::max)())) { + if (_Val > static_cast((numeric_limits::max) ())) { _THROW(format_error("Number is too big.")); } @@ -1224,7 +1224,7 @@ private: _ParseContext& _Parse_ctx; _NODISCARD static constexpr int _Verify_dynamic_arg_index_in_range(const size_t _Idx) { - if (_Idx > static_cast((numeric_limits::max)())) { + if (_Idx > static_cast((numeric_limits::max) ())) { _THROW(format_error("Dynamic width or precision index too large.")); } @@ -1298,7 +1298,7 @@ public: template constexpr void _On_type(_CharT _Type) { - if (_Type < 0 || _Type > (numeric_limits::max)()) { + if (_Type < 0 || _Type > (numeric_limits::max) ()) { _THROW(format_error("Invalid type specification.")); } const char _Narrow_type = static_cast(_Type); @@ -2320,7 +2320,7 @@ _NODISCARD _OutputIt _Write_integral( if (_Separators > 0) { return _Write_separated_integer(_Buffer_start, _End, _Groups, - _STD use_facet>(_Locale._Get()).thousands_sep(), _Separators, _STD move(_Out)); + _STD use_facet>(_Locale._Get()).thousands_sep(), _Separators, _STD move(_Out)); } return _RANGES _Copy_unchecked(_Buffer_start, _End, _STD move(_Out)).out; }; @@ -2472,7 +2472,7 @@ _NODISCARD _OutputIt _Fmt_write( auto _Buffer_start = _Buffer; auto _Width = static_cast(_Result.ptr - _Buffer_start); - const auto _Is_negative = (_STD signbit)(_Value); + const auto _Is_negative = (_STD signbit) (_Value); if (_Is_negative) { // Remove the '-', it will be dealt with directly @@ -2488,7 +2488,7 @@ _NODISCARD _OutputIt _Fmt_write( _Exponent = static_cast(_CSTD toupper(_Exponent)); } - const auto _Is_finite = (_STD isfinite)(_Value); + const auto _Is_finite = (_STD isfinite) (_Value); auto _Append_decimal = false; auto _Exponent_start = _Result.ptr; @@ -2507,7 +2507,7 @@ _NODISCARD _OutputIt _Fmt_write( _Exponent_start = _It; } } - _Integral_end = (_STD min)(_Radix_point, _Exponent_start); + _Integral_end = (_STD min) (_Radix_point, _Exponent_start); if (_Specs._Alt && _Radix_point == _Result.ptr) { // TRANSITION, decimal point may be wider @@ -2574,7 +2574,7 @@ _NODISCARD _OutputIt _Fmt_write( if (_Specs._Localized) { const auto& _Facet = _STD use_facet>(_Locale._Get()); _Out = _Write_separated_integer( - _Buffer_start, _Integral_end, _Groups, _Facet.thousands_sep(), _Separators, _STD move(_Out)); + _Buffer_start, _Integral_end, _Groups, _Facet.thousands_sep(), _Separators, _STD move(_Out)); if (_Radix_point != _Result.ptr || _Append_decimal) { *_Out++ = _Facet.decimal_point(); _Append_decimal = false; @@ -2644,7 +2644,7 @@ _NODISCARD const _CharT* _Measure_string_prefix(const basic_string_view<_CharT> const auto _Last = _Pos + _Value.size(); int _Estimated_width = 0; // the estimated width of [_Value.data(), _Pos) const _Fmt_codec<_CharT> _Codec; - constexpr auto _Max_int = (numeric_limits::max)(); + constexpr auto _Max_int = (numeric_limits::max) (); while (_Pos != _Last) { if (_Estimated_width == _Max_width && _Max_width >= 0) { From 15eb4cd66a4248471587ba6b04d4cd6d08f5e49b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 14 Jan 2022 18:29:36 -0800 Subject: [PATCH 08/11] Code review feedback. --- stl/inc/format | 10 +++++----- stl/inc/yvals_core.h | 4 ++-- .../test.cpp | 9 +++++---- .../test.compile.pass.cpp | 6 +++--- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index 22568907fd9..f901565c588 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1574,7 +1574,7 @@ public: _Format_arg_store(_Args&&... _Vals) noexcept { _Index_array[0] = {}; size_t _Arg_index = 0; - (_Store(_Arg_index++, static_cast<_Args&&>(_Vals)), ...); + (_Store(_Arg_index++, _STD forward<_Args>(_Vals)), ...); } }; @@ -2958,12 +2958,12 @@ using wformat_args = basic_format_args; template _NODISCARD auto make_format_args(_Args&&... _Vals) { - return _Format_arg_store<_Context, _Args...>{static_cast<_Args&&>(_Vals)...}; + return _Format_arg_store<_Context, _Args...>{_STD forward<_Args>(_Vals)...}; } template _NODISCARD auto make_wformat_args(_Args&&... _Vals) { - return _Format_arg_store{static_cast<_Args&&>(_Vals)...}; + return _Format_arg_store{_STD forward<_Args>(_Vals)...}; } template _OutputIt> @@ -3143,14 +3143,14 @@ format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_ } template -_NODISCARD size_t formatted_size(_Fmt_string<_Types...> _Fmt, _Types&&... _Args) { +_NODISCARD size_t formatted_size(const _Fmt_string<_Types...> _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_it{_Buf}, _Fmt._Str, _STD make_format_args(_Args...)); return _Buf._Count(); } template -_NODISCARD size_t formatted_size(_Fmt_wstring<_Types...> _Fmt, _Types&&... _Args) { +_NODISCARD size_t formatted_size(const _Fmt_wstring<_Types...> _Fmt, _Types&&... _Args) { _Fmt_counting_buffer _Buf; _STD vformat_to(_Fmt_wit{_Buf}, _Fmt._Str, _STD make_wformat_args(_Args...)); return _Buf._Count(); diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 74894b15b81..47c94be15eb 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -267,8 +267,8 @@ // P2367R0 Remove Misuses Of List-Initialization From Clause 24 Ranges // P2372R3 Fixing Locale Handling In chrono Formatters // P2415R2 What Is A view? +// P2418R2 Add Support For std::generator-like Types To std::format // P2432R1 Fix istream_view -// P2418R2 add support for std::generator-like types to std::format // P????R? directory_entry::clear_cache() // _HAS_CXX20 indirectly controls: @@ -1280,7 +1280,7 @@ #define __cpp_lib_erase_if 202002L #if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 and GH-1814 -#define __cpp_lib_format 202106L // P2216R3 std::format Improvements +#define __cpp_lib_format 202110L #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) #define __cpp_lib_generic_unordered_lookup 201811L diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp index e0f0f99f071..96745400c2d 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp @@ -4,9 +4,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -174,9 +174,6 @@ void test_mixed_custom_formattable_type() { test_numeric_mixed_args_custom_formattable_type(); } -template -void test_basic_custom_formatting() {} - int main() { string str; @@ -194,6 +191,8 @@ int main() { format_to_n(back_insert_iterator(str), 5, locale{}, "{}", basic_custom_formattable_type{"f"}); assert(str == "f"); str.clear(); + assert(formatted_size("{}", basic_custom_formattable_type{"f"}) == 1); + assert(formatted_size(locale{}, "{}", basic_custom_formattable_type{"f"}) == 1); assert(format("{}", move_only_custom_formattable_type{"f"}) == "f"s); @@ -210,6 +209,8 @@ int main() { format_to_n(back_insert_iterator(str), 5, locale{}, "{}", move_only_custom_formattable_type{"f"}); assert(str == "f"); str.clear(); + assert(formatted_size("{}", move_only_custom_formattable_type{"f"}) == 1); + assert(formatted_size(locale{}, "{}", move_only_custom_formattable_type{"f"}) == 1); test_custom_formattable_type(); diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 2379133b46e..481b0cb9572 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -739,10 +739,10 @@ STATIC_ASSERT(__cpp_lib_filesystem == 201703L); #if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support and GH-1814 #ifndef __cpp_lib_format #error __cpp_lib_format is not defined -#elif __cpp_lib_format != 202106L -#error __cpp_lib_format is not 202106L +#elif __cpp_lib_format != 202110L +#error __cpp_lib_format is not 202110L #else -STATIC_ASSERT(__cpp_lib_format == 202106L); +STATIC_ASSERT(__cpp_lib_format == 202110L); #endif #else #ifdef __cpp_lib_format From a4024515b0eab764a65958f092b2593feabcb433 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 14 Jan 2022 18:39:19 -0800 Subject: [PATCH 09/11] Avoid test code duplication. Also include for forward(). --- .../test.cpp | 63 ++++++++----------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp index 96745400c2d..bc6a02d3989 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using namespace std; // copied from the text_formatting_formatting test case @@ -146,6 +147,28 @@ void test_numeric_mixed_args_custom_formattable_type() { } } +template +void test_format_family_overloads() { + string str; + + assert(format("{}", CustomFormattableType{"f"}) == "f"s); + assert(format(locale{}, "{}", CustomFormattableType{"f"}) == "f"s); + format_to(back_insert_iterator(str), "{}", CustomFormattableType{"f"}); + assert(str == "f"); + str.clear(); + format_to(back_insert_iterator(str), locale{}, "{}", CustomFormattableType{"f"}); + assert(str == "f"); + str.clear(); + format_to_n(back_insert_iterator(str), 5, "{}", CustomFormattableType{"f"}); + assert(str == "f"); + str.clear(); + format_to_n(back_insert_iterator(str), 5, locale{}, "{}", CustomFormattableType{"f"}); + assert(str == "f"); + str.clear(); + assert(formatted_size("{}", CustomFormattableType{"f"}) == 1); + assert(formatted_size(locale{}, "{}", CustomFormattableType{"f"}) == 1); +} + template void test_custom_formattable_type() { test_numeric_custom_formattable_type(); @@ -175,44 +198,8 @@ void test_mixed_custom_formattable_type() { } int main() { - string str; - - assert(format("{}", basic_custom_formattable_type{"f"}) == "f"s); - assert(format(locale{}, "{}", basic_custom_formattable_type{"f"}) == "f"s); - format_to(back_insert_iterator(str), "{}", basic_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - format_to(back_insert_iterator(str), locale{}, "{}", basic_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - format_to_n(back_insert_iterator(str), 5, "{}", basic_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - format_to_n(back_insert_iterator(str), 5, locale{}, "{}", basic_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - assert(formatted_size("{}", basic_custom_formattable_type{"f"}) == 1); - assert(formatted_size(locale{}, "{}", basic_custom_formattable_type{"f"}) == 1); - - - assert(format("{}", move_only_custom_formattable_type{"f"}) == "f"s); - assert(format(locale{}, "{}", move_only_custom_formattable_type{"f"}) == "f"s); - format_to(back_insert_iterator(str), "{}", move_only_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - format_to(back_insert_iterator(str), locale{}, "{}", move_only_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - format_to_n(back_insert_iterator(str), 5, "{}", move_only_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - format_to_n(back_insert_iterator(str), 5, locale{}, "{}", move_only_custom_formattable_type{"f"}); - assert(str == "f"); - str.clear(); - assert(formatted_size("{}", move_only_custom_formattable_type{"f"}) == 1); - assert(formatted_size(locale{}, "{}", move_only_custom_formattable_type{"f"}) == 1); - - + test_format_family_overloads(); + test_format_family_overloads(); test_custom_formattable_type(); test_custom_formattable_type(); test_mixed_custom_formattable_type(); From 68be3557773077b507027d221f2ca17da790fa53 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 19 Jan 2022 22:01:40 -0800 Subject: [PATCH 10/11] apply review comments --- stl/inc/format | 28 +++++++++---------- .../test.cpp | 14 +++++----- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index f901565c588..0b4d4e0a0b8 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -175,9 +175,7 @@ concept _Has_formatter = requires(_Ty& _Val, _Context& _Ctx) { }; template -concept _Has_const_formatter = requires(const _Ty& _Val, _Context& _Ctx) { - _STD declval>>().format(_Val, _Ctx); -}; +concept _Has_const_formatter = _Has_formatter, _Context>; template struct formatter; @@ -1427,20 +1425,22 @@ struct _Format_arg_traits { // from "raw" to "erased" argument type for _Format_arg_store. template <_Has_formatter<_Context> _Ty> static auto _Phony_basic_format_arg_constructor(_Ty&&) { + // LWG-3631 + using _Td = remove_cvref_t<_Ty>; // See N4885 [format.arg]/5 - if constexpr (is_same_v<_Ty, bool>) { + if constexpr (is_same_v<_Td, bool>) { return bool{}; - } else if constexpr (is_same_v<_Ty, _Char_type>) { + } else if constexpr (is_same_v<_Td, _Char_type>) { return _Char_type{}; - } else if constexpr (is_same_v<_Ty, char> && is_same_v<_Char_type, wchar_t>) { + } else if constexpr (is_same_v<_Td, char> && is_same_v<_Char_type, wchar_t>) { return _Char_type{}; - } else if constexpr (signed_integral<_Ty> && sizeof(_Ty) <= sizeof(int)) { + } else if constexpr (signed_integral<_Td> && sizeof(_Td) <= sizeof(int)) { return int{}; - } else if constexpr (unsigned_integral<_Ty> && sizeof(_Ty) <= sizeof(unsigned int)) { + } else if constexpr (unsigned_integral<_Td> && sizeof(_Td) <= sizeof(unsigned int)) { return static_cast(42); - } else if constexpr (signed_integral<_Ty> && sizeof(_Ty) <= sizeof(long long)) { + } else if constexpr (signed_integral<_Td> && sizeof(_Td) <= sizeof(long long)) { return static_cast(42); - } else if constexpr (unsigned_integral<_Ty> && sizeof(_Ty) <= sizeof(unsigned long long)) { + } else if constexpr (unsigned_integral<_Td> && sizeof(_Td) <= sizeof(unsigned long long)) { return static_cast(42); } else { return typename basic_format_arg<_Context>::handle{42}; @@ -1571,10 +1571,10 @@ private: } public: - _Format_arg_store(_Args&&... _Vals) noexcept { + _Format_arg_store(_Args&... _Vals) noexcept { _Index_array[0] = {}; size_t _Arg_index = 0; - (_Store(_Arg_index++, _STD forward<_Args>(_Vals)), ...); + (_Store(_Arg_index++, _Vals), ...); } }; @@ -2958,12 +2958,12 @@ using wformat_args = basic_format_args; template _NODISCARD auto make_format_args(_Args&&... _Vals) { - return _Format_arg_store<_Context, _Args...>{_STD forward<_Args>(_Vals)...}; + return _Format_arg_store<_Context, _Args...>{_Vals...}; } template _NODISCARD auto make_wformat_args(_Args&&... _Vals) { - return _Format_arg_store{_STD forward<_Args>(_Vals)...}; + return _Format_arg_store{_Vals...}; } template _OutputIt> diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp index bc6a02d3989..76734fdfec8 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp @@ -48,11 +48,11 @@ struct basic_custom_formattable_type { string_view string_content; }; -struct move_only_custom_formattable_type { +struct not_const_formattable_type { string_view string_content; - explicit move_only_custom_formattable_type(string_view val) : string_content(val) {} - move_only_custom_formattable_type(const move_only_custom_formattable_type&) = delete; - move_only_custom_formattable_type(move_only_custom_formattable_type&&) = default; + explicit not_const_formattable_type(string_view val) : string_content(val) {} + not_const_formattable_type(const not_const_formattable_type&) = delete; + not_const_formattable_type(not_const_formattable_type&&) = delete; }; template <> @@ -70,14 +70,14 @@ struct std::formatter { }; template <> -struct std::formatter { +struct std::formatter { basic_format_parse_context::iterator parse(basic_format_parse_context& parse_ctx) { if (parse_ctx.begin() != parse_ctx.end()) { throw format_error{"only empty specs please"}; } return parse_ctx.end(); } - format_context::iterator format(move_only_custom_formattable_type& val, format_context& ctx) { + format_context::iterator format(not_const_formattable_type& val, format_context& ctx) { ctx.advance_to(copy(val.string_content.begin(), val.string_content.end(), ctx.out())); return ctx.out(); } @@ -199,7 +199,7 @@ void test_mixed_custom_formattable_type() { int main() { test_format_family_overloads(); - test_format_family_overloads(); + test_format_family_overloads(); test_custom_formattable_type(); test_custom_formattable_type(); test_mixed_custom_formattable_type(); From 4754c1ba0f1b9baf829171ec47fb692b23e04f7c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 21 Jan 2022 22:13:14 -0800 Subject: [PATCH 11/11] Add "per the proposed resolution of". --- stl/inc/format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/format b/stl/inc/format index bc7d9cecd1e..216afc83e9a 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1425,7 +1425,7 @@ struct _Format_arg_traits { // from "raw" to "erased" argument type for _Format_arg_store. template <_Has_formatter<_Context> _Ty> static auto _Phony_basic_format_arg_constructor(_Ty&&) { - // LWG-3631 + // per the proposed resolution of LWG-3631 using _Td = remove_cvref_t<_Ty>; // See N4885 [format.arg]/5 if constexpr (is_same_v<_Td, bool>) {