diff --git a/stl/inc/chrono b/stl/inc/chrono index e3f887fa27e..c5e3638d21b 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -5136,46 +5136,85 @@ namespace chrono { return _Istr; } + template + struct _Time_parse_iomanip_c_str { + _Time_parse_iomanip_c_str(const _CharT* _Fmt_, _Parsable& _Tp_, + basic_string<_CharT, _Traits, _Alloc>* _Abbrev_ = nullptr, minutes* _Offset_ = nullptr) + : _Fmt{_Fmt_}, _Tp{_Tp_}, _Abbrev{_Abbrev_}, _Offset{_Offset_} {} + + _Time_parse_iomanip_c_str(_Time_parse_iomanip_c_str&&) = delete; + + const _CharT* _Fmt; + _Parsable& _Tp; + basic_string<_CharT, _Traits, _Alloc>* _Abbrev; + minutes* _Offset; + }; + template struct _Time_parse_iomanip { _Time_parse_iomanip(const basic_string<_CharT, _Traits, _Alloc>& _Fmt_, _Parsable& _Tp_, basic_string<_CharT, _Traits, _Alloc>* _Abbrev_ = nullptr, minutes* _Offset_ = nullptr) : _Fmt{_Fmt_}, _Tp{_Tp_}, _Abbrev{_Abbrev_}, _Offset{_Offset_} {} + _Time_parse_iomanip(_Time_parse_iomanip&&) = delete; + const basic_string<_CharT, _Traits, _Alloc>& _Fmt; _Parsable& _Tp; basic_string<_CharT, _Traits, _Alloc>* _Abbrev; minutes* _Offset; }; + template + using _Has_from_stream = + decltype(static_cast(from_stream(_STD declval&>(), + _STD declval(), _STD declval<_Parsable&>(), _STD declval<_Rest>()...)), + 0); // intentional ADL + + template , _Parsable> = 0> + _NODISCARD auto parse(const _CharT* _Fmt, _Parsable& _Tp) { + return _Time_parse_iomanip_c_str<_CharT, char_traits<_CharT>, allocator<_CharT>, _Parsable>{_Fmt, _Tp}; + } + template &>(), - _STD declval(), _STD declval<_Parsable&>()))>> + _Has_from_stream<_CharT, _Traits, _Parsable> = 0> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp) { return _Time_parse_iomanip{_Fmt, _Tp}; } template &>(), - _STD declval(), _STD declval<_Parsable&>(), - _STD declval*>()))>> + _Has_from_stream<_CharT, _Traits, _Parsable, basic_string<_CharT, _Traits, _Alloc>*> = 0> + _NODISCARD auto parse(const _CharT* _Fmt, _Parsable& _Tp, basic_string<_CharT, _Traits, _Alloc>& _Abbrev) { + return _Time_parse_iomanip_c_str{_Fmt, _Tp, _STD addressof(_Abbrev)}; + } + + template *> = 0> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp, basic_string<_CharT, _Traits, _Alloc>& _Abbrev) { return _Time_parse_iomanip{_Fmt, _Tp, _STD addressof(_Abbrev)}; } + template , _Parsable, basic_string<_CharT>*, minutes*> = 0> + _NODISCARD auto parse(const _CharT* _Fmt, _Parsable& _Tp, minutes& _Offset) { + return _Time_parse_iomanip_c_str{_Fmt, _Tp, static_cast*>(nullptr), &_Offset}; + } + template &>(), - _STD declval(), _STD declval<_Parsable&>(), - _STD declval*>(), _STD declval()))>> + _Has_from_stream<_CharT, _Traits, _Parsable, basic_string<_CharT, _Traits, _Alloc>*, minutes*> = 0> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp, minutes& _Offset) { return _Time_parse_iomanip{_Fmt, _Tp, static_cast*>(nullptr), &_Offset}; } template &>(), - _STD declval(), _STD declval<_Parsable&>(), - _STD declval*>(), _STD declval()))>> + _Has_from_stream<_CharT, _Traits, _Parsable, basic_string<_CharT, _Traits, _Alloc>*, minutes*> = 0> + _NODISCARD auto parse( + const _CharT* _Fmt, _Parsable& _Tp, basic_string<_CharT, _Traits, _Alloc>& _Abbrev, minutes& _Offset) { + return _Time_parse_iomanip_c_str{_Fmt, _Tp, _STD addressof(_Abbrev), &_Offset}; + } + + template *, minutes*> = 0> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp, basic_string<_CharT, _Traits, _Alloc>& _Abbrev, minutes& _Offset) { return _Time_parse_iomanip{_Fmt, _Tp, _STD addressof(_Abbrev), &_Offset}; @@ -5183,8 +5222,16 @@ namespace chrono { template basic_istream<_CharT, _Traits>& operator>>( - basic_istream<_CharT, _Traits>& _Is, const _Time_parse_iomanip<_CharT, _Traits, _Alloc, _Parsable>& _Tpi) { - return _CHRONO from_stream(_Is, _Tpi._Fmt.c_str(), _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); + basic_istream<_CharT, _Traits>& _Is, _Time_parse_iomanip_c_str<_CharT, _Traits, _Alloc, _Parsable>&& _Tpi) { + from_stream(_Is, _Tpi._Fmt, _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); // intentional ADL + return _Is; + } + + template + basic_istream<_CharT, _Traits>& operator>>( + basic_istream<_CharT, _Traits>& _Is, _Time_parse_iomanip<_CharT, _Traits, _Alloc, _Parsable>&& _Tpi) { + from_stream(_Is, _Tpi._Fmt.c_str(), _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); // intentional ADL + return _Is; } #endif // _HAS_CXX20 diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp index 373f7da3536..1a1c20b3c8b 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp @@ -29,7 +29,7 @@ bool test_duration_basic_out(const duration& d, const CharT* expect return ss.str() == expected; } -#define WIDEN(TYPE, STR) get(pair{STR, L##STR}); +#define WIDEN(TYPE, STR) get(pair{STR, L##STR}) template bool test_duration_locale_out() { @@ -64,8 +64,6 @@ bool test_duration_locale_out() { return ss.str() == expected; } -#undef WIDEN - void test_duration_output() { using LongRatio = ratio; assert(test_duration_basic_out(duration{1}, "1as")); @@ -128,9 +126,9 @@ void test_duration_output() { } -template -void test_parse(const CharT* str, const CharT* fmt, Parsable& p, type_identity_t*> abbrev = nullptr, - minutes* offset = nullptr) { +template +void test_parse(const CharT* str, const CStringOrStdString& fmt, Parsable& p, + type_identity_t*> abbrev = nullptr, minutes* offset = nullptr) { p = Parsable{}; if (abbrev) { if constexpr (is_same_v) { @@ -147,24 +145,24 @@ void test_parse(const CharT* str, const CharT* fmt, Parsable& p, type_identity_t basic_stringstream sstr{str}; if (abbrev) { if (offset) { - sstr >> parse(basic_string{fmt}, p, *abbrev, *offset); + sstr >> parse(fmt, p, *abbrev, *offset); } else { - sstr >> parse(basic_string{fmt}, p, *abbrev); + sstr >> parse(fmt, p, *abbrev); } } else { if (offset) { - sstr >> parse(basic_string{fmt}, p, *offset); + sstr >> parse(fmt, p, *offset); } else { - sstr >> parse(basic_string{fmt}, p); + sstr >> parse(fmt, p); } } assert(sstr); } -template -void fail_parse(const CharT* str, const CharT* fmt, Parsable& p, type_identity_t*> abbrev = nullptr, - minutes* offset = nullptr) { +template +void fail_parse(const CharT* str, const CStringOrStdString& fmt, Parsable& p, + type_identity_t*> abbrev = nullptr, minutes* offset = nullptr) { p = Parsable{}; if (abbrev) { if constexpr (is_same_v) { @@ -181,15 +179,15 @@ void fail_parse(const CharT* str, const CharT* fmt, Parsable& p, type_identity_t basic_stringstream sstr{str}; if (abbrev) { if (offset) { - sstr >> parse(basic_string{fmt}, p, *abbrev, *offset); + sstr >> parse(fmt, p, *abbrev, *offset); } else { - sstr >> parse(basic_string{fmt}, p, *abbrev); + sstr >> parse(fmt, p, *abbrev); } } else { if (offset) { - sstr >> parse(basic_string{fmt}, p, *offset); + sstr >> parse(fmt, p, *offset); } else { - sstr >> parse(basic_string{fmt}, p); + sstr >> parse(fmt, p); } } @@ -227,19 +225,19 @@ void test_lwg_3536() { { istringstream iss{"2:2:30"}; - iss >> parse(string{"%H:%M:%S"}, mm); + iss >> parse("%H:%M:%S", mm); assert(iss.fail() && mm == 20min); } { istringstream iss{"June"}; - iss >> parse(string{"%B"}, mm); + iss >> parse("%B", mm); assert(iss.fail() && mm == 20min); } { istringstream iss{""}; - iss >> parse(string{"%B"}, mm); + iss >> parse("%B", mm); assert(iss.fail() && mm == 20min); } } @@ -1172,36 +1170,37 @@ void parse_timepoints() { test_gh_1952(); } -void parse_wchar() { +template +void test_io_manipulator() { seconds time; - test_parse(L"12", L"%S", time); + test_parse(WIDEN(CharT, "12"), CStringOrStdString{WIDEN(CharT, "%S")}, time); assert(time == 12s); - test_parse(L"12", L"%M", time); + test_parse(WIDEN(CharT, "12"), CStringOrStdString{WIDEN(CharT, "%M")}, time); assert(time == 12min); - test_parse(L"30", L"%H", time); + test_parse(WIDEN(CharT, "30"), CStringOrStdString{WIDEN(CharT, "%H")}, time); assert(time == 30h); - test_parse(L" 1:23:42", L"%T", time); + test_parse(WIDEN(CharT, " 1:23:42"), CStringOrStdString{WIDEN(CharT, "%T")}, time); assert(time == 1h + 23min + 42s); - wstring tz_name; - test_parse(L"Etc/GMT+11", L"%Z", time, &tz_name); - assert(tz_name == L"Etc/GMT+11"); - fail_parse(L"Not_valid! 00", L"%Z %H", time, &tz_name); + basic_string tz_name; + test_parse(WIDEN(CharT, "Etc/GMT+11"), CStringOrStdString{WIDEN(CharT, "%Z")}, time, &tz_name); + assert(tz_name == WIDEN(CharT, "Etc/GMT+11")); + fail_parse(WIDEN(CharT, "Not_valid! 00"), CStringOrStdString{WIDEN(CharT, "%Z %H")}, time, &tz_name); weekday wd; - test_parse(L"wedNesday", L"%A", wd); + test_parse(WIDEN(CharT, "wedNesday"), CStringOrStdString{WIDEN(CharT, "%A")}, wd); assert(wd == Wednesday); month m; - test_parse(L"deCeMbeR", L"%b", m); + test_parse(WIDEN(CharT, "deCeMbeR"), CStringOrStdString{WIDEN(CharT, "%b")}, m); assert(m == December); sys_seconds st; - test_parse(L"oct 29 19:01:42 2020", L"%c", st); + test_parse(WIDEN(CharT, "oct 29 19:01:42 2020"), CStringOrStdString{WIDEN(CharT, "%c")}, st); assert(st == sys_days{2020y / October / 29d} + 19h + 1min + 42s); - fail_parse(L"ab", L"a%nb", time); - test_parse(L"a b", L"a%nb", time); - fail_parse(L"a b", L"a%nb", time); + fail_parse(WIDEN(CharT, "ab"), CStringOrStdString{WIDEN(CharT, "a%nb")}, time); + test_parse(WIDEN(CharT, "a b"), CStringOrStdString{WIDEN(CharT, "a%nb")}, time); + fail_parse(WIDEN(CharT, "a b"), CStringOrStdString{WIDEN(CharT, "a%nb")}, time); } void test_parse() { @@ -1216,7 +1215,10 @@ void test_parse() { parse_other_week_date(); parse_whitespace(); parse_timepoints(); - parse_wchar(); + test_io_manipulator(); + test_io_manipulator(); + test_io_manipulator(); + test_io_manipulator(); } void test() {