diff --git a/stl/inc/chrono b/stl/inc/chrono index d53e2873cb6..7927b883277 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -15,6 +15,10 @@ #include #include +#if _HAS_CXX20 +#include +#endif // _HAS_CXX20 + #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -50,6 +54,23 @@ namespace chrono { } }; +#if _HAS_CXX20 + template + concept _Is_clock = requires { + typename _Clock::rep; + typename _Clock::period; + typename _Clock::duration; + typename _Clock::time_point; + _Clock::is_steady; + _Clock::now(); + }; + + template + struct is_clock : bool_constant<_Is_clock<_Clock>> {}; + template + inline constexpr bool is_clock_v = _Is_clock<_Clock>; +#endif // _HAS_CXX20 + // CLASS TEMPLATE duration template > class duration; @@ -89,7 +110,7 @@ namespace chrono { int> = 0> constexpr duration(const duration<_Rep2, _Period2>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v<_Rep2>) // strengthened - : _MyRep(chrono::duration_cast(_Dur).count()) {} + : _MyRep(_CHRONO duration_cast(_Dur).count()) {} _NODISCARD constexpr _Rep count() const noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { return _MyRep; @@ -196,6 +217,23 @@ namespace chrono { return _MyDur; } +#if _HAS_CXX20 + constexpr time_point& operator++() noexcept(is_arithmetic_v) /* strengthened */ { + ++_MyDur; + return *this; + } + constexpr time_point operator++(int) noexcept(is_arithmetic_v) /* strengthened */ { + return time_point{_MyDur++}; + } + constexpr time_point& operator--() noexcept(is_arithmetic_v) /* strengthened */ { + --_MyDur; + return *this; + } + constexpr time_point operator--(int) noexcept(is_arithmetic_v) /* strengthened */ { + return time_point{_MyDur--}; + } +#endif // _HAS_CXX20 + _CONSTEXPR17 time_point& operator+=(const _Duration& _Dur) noexcept(is_arithmetic_v) /* strengthened */ { _MyDur += _Dur; return *this; @@ -225,16 +263,16 @@ struct _Lcm : integral_constant::value) * _Bx> { // STRUCT TEMPLATE common_type SPECIALIZATIONS template -struct common_type, - chrono::duration<_Rep2, _Period2>> { // common type of two durations - using type = chrono::duration, +struct common_type<_CHRONO duration<_Rep1, _Period1>, + _CHRONO duration<_Rep2, _Period2>> { // common type of two durations + using type = _CHRONO duration, ratio<_Gcd<_Period1::num, _Period2::num>::value, _Lcm<_Period1::den, _Period2::den>::value>>; }; template -struct common_type, - chrono::time_point<_Clock, _Duration2>> { // common type of two time points - using type = chrono::time_point<_Clock, common_type_t<_Duration1, _Duration2>>; +struct common_type<_CHRONO time_point<_Clock, _Duration1>, + _CHRONO time_point<_Clock, _Duration2>> { // common type of two time points + using type = _CHRONO time_point<_Clock, common_type_t<_Duration1, _Duration2>>; }; namespace chrono { @@ -405,7 +443,7 @@ namespace chrono { is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration; round towards negative infinity // i.e. the greatest integral result such that the result <= _Dur - const _To _Casted{chrono::duration_cast<_To>(_Dur)}; + const _To _Casted{_CHRONO duration_cast<_To>(_Dur)}; if (_Casted > _Dur) { return _To{_Casted.count() - static_cast(1)}; } @@ -419,7 +457,7 @@ namespace chrono { is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration; round towards positive infinity // i.e. the least integral result such that _Dur <= the result - const _To _Casted{chrono::duration_cast<_To>(_Dur)}; + const _To _Casted{_CHRONO duration_cast<_To>(_Dur)}; if (_Casted < _Dur) { return _To{_Casted.count() + static_cast(1)}; } @@ -439,7 +477,7 @@ namespace chrono { _NODISCARD constexpr _To round(const duration<_Rep, _Period>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration, round to nearest, ties to even - const _To _Floored{chrono::floor<_To>(_Dur)}; + const _To _Floored{_CHRONO floor<_To>(_Dur)}; const _To _Ceiled{_Floored + _To{1}}; const auto _Floor_adjustment = _Dur - _Floored; const auto _Ceil_adjustment = _Ceiled - _Dur; @@ -466,6 +504,12 @@ namespace chrono { using seconds = duration; using minutes = duration>; using hours = duration>; +#if _HAS_CXX20 + using days = duration, hours::period>>; + using weeks = duration, days::period>>; + using years = duration, days::period>>; + using months = duration>>; +#endif // _HAS_CXX20 // time_point ARITHMETIC template @@ -546,7 +590,7 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> time_point_cast(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; truncate - return time_point<_Clock, _To>(chrono::duration_cast<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO duration_cast<_To>(_Time.time_since_epoch())); } // FUNCTION TEMPLATE floor (for time_point instances) @@ -554,7 +598,7 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> floor(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round towards negative infinity - return time_point<_Clock, _To>(chrono::floor<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO floor<_To>(_Time.time_since_epoch())); } // FUNCTION TEMPLATE ceil (for time_point instances) @@ -562,7 +606,7 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> ceil(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round towards positive infinity - return time_point<_Clock, _To>(chrono::ceil<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO ceil<_To>(_Time.time_since_epoch())); } // FUNCTION TEMPLATE round (for time_point instances) @@ -571,15 +615,15 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> round(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round to nearest, ties to even - return time_point<_Clock, _To>(chrono::round<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO round<_To>(_Time.time_since_epoch())); } // CLOCKS struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime using rep = long long; using period = ratio<1, 10'000'000>; // 100 nanoseconds - using duration = chrono::duration; - using time_point = chrono::time_point; + using duration = _CHRONO duration; + using time_point = _CHRONO time_point; static constexpr bool is_steady = false; _NODISCARD static time_point now() noexcept { // get current time @@ -595,11 +639,19 @@ namespace chrono { } }; +#if _HAS_CXX20 + // sys_time ALIASES + template + using sys_time = time_point; + using sys_seconds = sys_time; + using sys_days = sys_time; +#endif // _HAS_CXX20 + struct steady_clock { // wraps QueryPerformanceCounter using rep = long long; using period = nano; using duration = nanoseconds; - using time_point = chrono::time_point; + using time_point = _CHRONO time_point; static constexpr bool is_steady = true; _NODISCARD static time_point now() noexcept { // get current time @@ -699,28 +751,1338 @@ namespace chrono { return _Os << _Sstr.str(); } + + struct local_t {}; + + template + using local_time = time_point; + using local_seconds = local_time; + using local_days = local_time; + + struct last_spec { + explicit last_spec() = default; + }; + inline constexpr last_spec last{}; + + class day { + public: + day() = default; + constexpr explicit day(unsigned int _Val) noexcept : _Day{static_cast(_Val)} {} + + constexpr day& operator++() noexcept { + ++_Day; + return *this; + } + constexpr day operator++(int) noexcept { + return day{_Day++}; + } + constexpr day& operator--() noexcept { + --_Day; + return *this; + } + constexpr day operator--(int) noexcept { + return day{_Day--}; + } + + constexpr day& operator+=(const days& _Days) noexcept { + _Day += static_cast(_Days.count()); + return *this; + } + constexpr day& operator-=(const days& _Days) noexcept { + _Day -= static_cast(_Days.count()); + return *this; + } + + _NODISCARD constexpr explicit operator unsigned int() const noexcept { + return _Day; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Day >= 1 && _Day <= 31; + } + + private: + unsigned char _Day; + }; + + _NODISCARD constexpr bool operator==(const day& _Left, const day& _Right) noexcept { + return static_cast(_Left) == static_cast(_Right); + } + _NODISCARD constexpr strong_ordering operator<=>(const day& _Left, const day& _Right) noexcept { + return static_cast(_Left) <=> static_cast(_Right); + } + + _NODISCARD constexpr day operator+(const day& _Left, const days& _Right) noexcept { + return day{static_cast(_Left) + _Right.count()}; + } + _NODISCARD constexpr day operator+(const days& _Left, const day& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr day operator-(const day& _Left, const days& _Right) noexcept { + return day{static_cast(_Left) - _Right.count()}; + } + _NODISCARD constexpr days operator-(const day& _Left, const day& _Right) noexcept { + return days{ + static_cast(static_cast(_Left)) - static_cast(static_cast(_Right))}; + } + + class month { + public: + month() = default; + constexpr explicit month(unsigned int _Val) noexcept : _Month{static_cast(_Val)} {} + + constexpr month& operator++() noexcept { + *this += months{1}; + return *this; + } + constexpr month operator++(int) noexcept { + month _Temp{*this}; + ++*this; + return _Temp; + } + constexpr month& operator--() noexcept { + *this -= months{1}; + return *this; + } + constexpr month operator--(int) noexcept { + month _Temp{*this}; + --*this; + return _Temp; + } + + constexpr month& operator+=(const months& _Months) noexcept; + constexpr month& operator-=(const months& _Months) noexcept; + + _NODISCARD constexpr explicit operator unsigned int() const noexcept { + return _Month; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Month >= 1 && _Month <= 12; + } + + private: + unsigned char _Month; + }; + + _NODISCARD constexpr bool operator==(const month& _Left, const month& _Right) noexcept { + return static_cast(_Left) == static_cast(_Right); + } + _NODISCARD constexpr strong_ordering operator<=>(const month& _Left, const month& _Right) noexcept { + return static_cast(_Left) <=> static_cast(_Right); + } + + _NODISCARD constexpr month operator+(const month& _Left, const months& _Right) noexcept { + const auto _Mo = static_cast(static_cast(_Left)) + (_Right.count() - 1); + const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12; + return month{static_cast(_Mo - _Div * 12 + 1)}; + } + _NODISCARD constexpr month operator+(const months& _Left, const month& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr month operator-(const month& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + _NODISCARD constexpr months operator-(const month& _Left, const month& _Right) noexcept { + const auto _Mo = static_cast(_Left) - static_cast(_Right); + return months{_Mo <= 11 ? _Mo : _Mo + 12}; + } + + constexpr month& month::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + constexpr month& month::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + + class year { + public: + year() = default; + constexpr explicit year(int _Val) noexcept : _Year{static_cast(_Val)} {} + + constexpr year& operator++() noexcept { + ++_Year; + return *this; + } + constexpr year operator++(int) noexcept { + return year{_Year++}; + } + constexpr year& operator--() noexcept { + --_Year; + return *this; + } + constexpr year operator--(int) noexcept { + return year{_Year--}; + } + + constexpr year& operator+=(const years& _Years) noexcept { +#ifdef __EDG__ // TRANSITION, VSO-1271098 + _Year = static_cast(_Year + _Years.count()); +#else // ^^^ workaround / no workaround vvv + _Year += static_cast(_Years.count()); +#endif // ^^^ no workaround ^^^ + return *this; + } + constexpr year& operator-=(const years& _Years) noexcept { +#ifdef __EDG__ // TRANSITION, VSO-1271098 + _Year = static_cast(_Year - _Years.count()); +#else // ^^^ workaround / no workaround vvv + _Year -= static_cast(_Years.count()); +#endif // ^^^ no workaround ^^^ + return *this; + } + + _NODISCARD constexpr year operator+() const noexcept { + return *this; + } + _NODISCARD constexpr year operator-() const noexcept { + return year{-_Year}; + } + + _NODISCARD constexpr bool is_leap() const noexcept { + return _Year % 4 == 0 && (_Year % 100 != 0 || _Year % 400 == 0); + } + + _NODISCARD constexpr explicit operator int() const noexcept { + return _Year; + } + + _NODISCARD constexpr bool ok() const noexcept { + return _Year_min <= _Year && _Year <= _Year_max; + } + + _NODISCARD static constexpr year(min)() noexcept { + return year{_Year_min}; + } + _NODISCARD static constexpr year(max)() noexcept { + return year{_Year_max}; + } + + private: + short _Year; + static constexpr int _Year_min = -32767; + static constexpr int _Year_max = 32767; + }; + + _NODISCARD constexpr bool operator==(const year& _Left, const year& _Right) noexcept { + return static_cast(_Left) == static_cast(_Right); + } + _NODISCARD constexpr strong_ordering operator<=>(const year& _Left, const year& _Right) noexcept { + return static_cast(_Left) <=> static_cast(_Right); + } + + _NODISCARD constexpr year operator+(const year& _Left, const years& _Right) noexcept { + return year{static_cast(_Left) + _Right.count()}; + } + _NODISCARD constexpr year operator+(const years& _Left, const year& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr year operator-(const year& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + _NODISCARD constexpr years operator-(const year& _Left, const year& _Right) noexcept { + return years{static_cast(_Left) - static_cast(_Right)}; + } + + class weekday_indexed; + class weekday_last; + + class weekday { + public: + weekday() = default; + constexpr explicit weekday(unsigned int _Val) noexcept + : _Weekday{static_cast(_Val == 7 ? 0 : _Val)} {} + constexpr weekday(const sys_days& _Sys_day) noexcept + : _Weekday{static_cast(_Weekday_from_days(_Sys_day.time_since_epoch().count()))} {} + constexpr explicit weekday(const local_days& _Local_day) noexcept + : _Weekday{static_cast(_Weekday_from_days(_Local_day.time_since_epoch().count()))} {} + + constexpr weekday& operator++() noexcept { + return *this += days{1}; + } + constexpr weekday operator++(int) noexcept { + weekday _Temp{*this}; + ++*this; + return _Temp; + } + constexpr weekday& operator--() noexcept { + return *this -= days{1}; + } + constexpr weekday operator--(int) noexcept { + weekday _Temp{*this}; + --*this; + return _Temp; + } + + constexpr weekday& operator+=(const days& _Days) noexcept; + constexpr weekday& operator-=(const days& _Days) noexcept; + + _NODISCARD constexpr unsigned int c_encoding() const noexcept { + return _Weekday; + } + _NODISCARD constexpr unsigned int iso_encoding() const noexcept { + return _Weekday == 0u ? 7u : _Weekday; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Weekday <= 6; + } + + _NODISCARD constexpr weekday_indexed operator[](unsigned int _Index) const noexcept; + _NODISCARD constexpr weekday_last operator[](last_spec) const noexcept; + + private: + unsigned char _Weekday; + + // courtesy of Howard Hinnant + // https://howardhinnant.github.io/date_algorithms.html#weekday_from_days + _NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept { + return static_cast(_Tp >= -4 ? (_Tp + 4) % 7 : (_Tp + 5) % 7 + 6); + } + }; + + _NODISCARD constexpr bool operator==(const weekday& _Left, const weekday& _Right) noexcept { + return _Left.c_encoding() == _Right.c_encoding(); + } + + _NODISCARD constexpr weekday operator+(const weekday& _Left, const days& _Right) noexcept { + const auto _Wd = static_cast(_Left.c_encoding()) + _Right.count(); + const auto _Div = (_Wd >= 0 ? _Wd : _Wd - 6) / 7; + return weekday{static_cast(_Wd - _Div * 7)}; + } + _NODISCARD constexpr weekday operator+(const days& _Left, const weekday& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr weekday operator-(const weekday& _Left, const days& _Right) noexcept { + return _Left + -_Right; + } + _NODISCARD constexpr days operator-(const weekday& _Left, const weekday& _Right) noexcept { + const auto _Wd = _Left.c_encoding() - _Right.c_encoding(); + const auto _Wk = _Wd <= 6 ? _Wd : _Wd + 7; + return days{_Wk}; + } + + constexpr weekday& weekday::operator+=(const days& _Days) noexcept { + *this = *this + _Days; + return *this; + } + constexpr weekday& weekday::operator-=(const days& _Days) noexcept { + *this = *this - _Days; + return *this; + } + + class weekday_indexed { + public: + weekday_indexed() = default; + constexpr weekday_indexed(const weekday& _Wd, unsigned int _Idx) noexcept + : _Weekday{_Wd}, _Index{static_cast(_Idx)} {} + + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday; + } + _NODISCARD constexpr unsigned int index() const noexcept { + return _Index; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Weekday.ok() && _Index >= 1 && _Index <= 5; + } + + private: + _CHRONO weekday _Weekday; + unsigned char _Index; + }; + + _NODISCARD constexpr bool operator==(const weekday_indexed& _Left, const weekday_indexed& _Right) noexcept { + return _Left.weekday() == _Right.weekday() && _Left.index() == _Right.index(); + } + + class weekday_last { + public: + constexpr explicit weekday_last(const weekday& _Wd) noexcept : _Weekday{_Wd} {} + + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Weekday.ok(); + } + + private: + _CHRONO weekday _Weekday; + }; + + _NODISCARD constexpr bool operator==(const weekday_last& _Left, const weekday_last& _Right) noexcept { + return _Left.weekday() == _Right.weekday(); + } + + _NODISCARD constexpr weekday_indexed weekday::operator[](unsigned int _Index) const noexcept { + return {*this, _Index}; + } + _NODISCARD constexpr weekday_last weekday::operator[](last_spec) const noexcept { + return weekday_last{*this}; + } + + class month_day { + public: + month_day() = default; + constexpr month_day(const month& _Month_, const day& _Day_) noexcept : _Month{_Month_}, _Day{_Day_} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr day day() const noexcept { + return _Day; + } + _NODISCARD constexpr bool ok() const noexcept { + if (!_Month.ok() || !_Day.ok()) { + return false; + } + + const auto _Da = static_cast(_Day); + const auto _Mo = static_cast(_Month); + if (_Mo == 2) { + return _Da <= 29; + } + + if (_Mo == 4 || _Mo == 6 || _Mo == 9 || _Mo == 11) { + return _Da <= 30; + } + return true; + } + + private: + _CHRONO month _Month; + _CHRONO day _Day; + }; + + _NODISCARD constexpr bool operator==(const month_day& _Left, const month_day& _Right) noexcept { + return _Left.month() == _Right.month() && _Left.day() == _Right.day(); + } + _NODISCARD constexpr strong_ordering operator<=>(const month_day& _Left, const month_day& _Right) noexcept { + const auto _Comp = _Left.month() <=> _Right.month(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.day() <=> _Right.day(); + } + + class month_day_last { + public: + constexpr explicit month_day_last(const month& _Month_) noexcept : _Month{_Month_} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Month.ok(); + } + + private: + _CHRONO month _Month; + }; + + _NODISCARD constexpr bool operator==(const month_day_last& _Left, const month_day_last& _Right) noexcept { + return _Left.month() == _Right.month(); + } + _NODISCARD constexpr strong_ordering operator<=>( + const month_day_last& _Left, const month_day_last& _Right) noexcept { + return _Left.month() <=> _Right.month(); + } + + class month_weekday { + public: + constexpr month_weekday(const month& _Month_, const weekday_indexed& _Wdi) noexcept + : _Month{_Month_}, _Weekday_index{_Wdi} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday_indexed weekday_indexed() const noexcept { + return _Weekday_index; + } + + _NODISCARD constexpr bool ok() const noexcept { + return _Month.ok() && _Weekday_index.ok(); + } + + private: + _CHRONO month _Month; + _CHRONO weekday_indexed _Weekday_index; + }; + + _NODISCARD constexpr bool operator==(const month_weekday& _Left, const month_weekday& _Right) noexcept { + return _Left.month() == _Right.month() && _Left.weekday_indexed() == _Right.weekday_indexed(); + } + + class month_weekday_last { + public: + constexpr month_weekday_last(const month& _Month_, const weekday_last& _Wdl) noexcept + : _Month{_Month_}, _Weekday_last{_Wdl} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday_last weekday_last() const noexcept { + return _Weekday_last; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Month.ok() && _Weekday_last.ok(); + } + + private: + _CHRONO month _Month; + _CHRONO weekday_last _Weekday_last; + }; + + _NODISCARD constexpr bool operator==(const month_weekday_last& _Left, const month_weekday_last& _Right) noexcept { + return _Left.month() == _Right.month() && _Left.weekday_last() == _Right.weekday_last(); + } + + class year_month { + public: + year_month() = default; + constexpr year_month(const year& _Year_, const month& _Month_) noexcept : _Year{_Year_}, _Month{_Month_} {} + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + + template + constexpr year_month& operator+=(const months& _Months) noexcept; + template + constexpr year_month& operator-=(const months& _Months) noexcept; + constexpr year_month& operator+=(const years& _Years) noexcept; + constexpr year_month& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr bool ok() const noexcept { + return _Year.ok() && _Month.ok(); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + }; + + _NODISCARD constexpr bool operator==(const year_month& _Left, const year_month& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month(); + } + _NODISCARD constexpr strong_ordering operator<=>(const year_month& _Left, const year_month& _Right) noexcept { + const auto _Comp = _Left.year() <=> _Right.year(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.month() <=> _Right.month(); + } + + template + _NODISCARD constexpr year_month operator+(const year_month& _Left, const months& _Right) noexcept { + const auto _Mo = static_cast(static_cast(_Left.month())) + (_Right.count() - 1); + const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12; + return year_month{_Left.year() + years{_Div}, month{static_cast(_Mo - _Div * 12 + 1)}}; + } + template + _NODISCARD constexpr year_month operator+(const months& _Left, const year_month& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month operator-(const year_month& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr months operator-(const year_month& _Left, const year_month& _Right) noexcept { + return _Left.year() - _Right.year() + + months{static_cast(static_cast(_Left.month())) + - static_cast(static_cast(_Right.month()))}; + } + + _NODISCARD constexpr year_month operator+(const year_month& _Left, const years& _Right) noexcept { + return {year{_Left.year() + _Right}, _Left.month()}; + } + + _NODISCARD constexpr year_month operator+(const years& _Left, const year_month& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month operator-(const year_month& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month& year_month::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month& year_month::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month& year_month::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month& year_month::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + inline constexpr day _Last_day_table[] = { + day{31}, day{28}, day{31}, day{30}, day{31}, day{30}, day{31}, day{31}, day{30}, day{31}, day{30}, day{31}}; + + _NODISCARD constexpr day _Last_day(const year& _Year, const month& _Month) { + if (_Month == month{2} && _Year.is_leap()) { + return day{29}; + } + + return _Last_day_table[static_cast(_Month) - 1]; + } + + class year_month_day_last; + + class year_month_day { + public: + year_month_day() = default; + constexpr year_month_day(const year& _Year_, const month& _Month_, const day& _Day_) noexcept + : _Year{_Year_}, _Month{_Month_}, _Day{_Day_} {} + constexpr year_month_day(const year_month_day_last& _Ymdl) noexcept; + constexpr year_month_day(const sys_days& _Sys_days) noexcept + : year_month_day{_Civil_from_days(_Sys_days.time_since_epoch().count())} {} + constexpr explicit year_month_day(const local_days& _Local_days) noexcept + : year_month_day{_Civil_from_days(_Local_days.time_since_epoch().count())} {} + + template + constexpr year_month_day& operator+=(const months& _Months) noexcept; + template + constexpr year_month_day& operator-=(const months& _Months) noexcept; + constexpr year_month_day& operator+=(const years& _Years) noexcept; + constexpr year_month_day& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr day day() const noexcept { + return _Day; + } + + _NODISCARD constexpr operator sys_days() const noexcept { + return sys_days{_Days_from_civil()}; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + if (!_Year.ok() || !_Month.ok()) { + return false; + } + + return _Day >= _CHRONO day{1} && _Day <= _Last_day(_Year, _Month); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + _CHRONO day _Day; + + // courtesy of Howard Hinnant + // https://howardhinnant.github.io/date_algorithms.html#civil_from_days + _NODISCARD static constexpr year_month_day _Civil_from_days(int _Tp) noexcept { + static_assert(numeric_limits::digits >= 18); + static_assert(numeric_limits::digits >= 20); + const int _Zx = _Tp + 719468; // Shift epoch to 0000-03-01 + const int _Era = (_Zx >= 0 ? _Zx : _Zx - 146096) / 146097; + const unsigned int _Day_of_era = static_cast(_Zx - _Era * 146097); // [0, 146096] + const unsigned int _Year_of_era = + (_Day_of_era - _Day_of_era / 1460 + _Day_of_era / 36524 - _Day_of_era / 146096) / 365; // [0, 399] + const int _Year = static_cast(_Year_of_era) + _Era * 400; // Where March is the first month + const unsigned int _Day_of_year = + _Day_of_era - (365 * _Year_of_era + _Year_of_era / 4 - _Year_of_era / 100); // [0, 365] + const unsigned int _Mp = (5 * _Day_of_year + 2) / 153; // [0, 11] + const unsigned int _Day = _Day_of_year - (153 * _Mp + 2) / 5 + 1; // [1, 31] + const unsigned int _Month = _Mp + (_Mp < 10 ? 3 : static_cast(-9)); // [1, 12] + return year_month_day{_CHRONO year{_Year + (_Month <= 2)}, _CHRONO month{_Month}, _CHRONO day{_Day}}; + } + // courtesy of Howard Hinnant + // https://howardhinnant.github.io/date_algorithms.html#days_from_civil + _NODISCARD constexpr days _Days_from_civil() const noexcept { + static_assert(numeric_limits::digits >= 18); + static_assert(numeric_limits::digits >= 20); + const int _Ye = static_cast(_Year) - (_Month <= _CHRONO month{2}); + const unsigned int _Mo = static_cast(_Month); + const int _Era = (_Ye >= 0 ? _Ye : _Ye - 399) / 400; + const unsigned int _Year_of_era = static_cast(_Ye - _Era * 400); // [0, 399] + const unsigned int _Day_of_year = (153 * (_Mo + (_Mo > 2 ? static_cast(-3) : 9)) + 2) / 5 + + static_cast(_Day) - 1; // [0, 365] + const unsigned int _Day_of_era = + _Year_of_era * 365 + _Year_of_era / 4 - _Year_of_era / 100 + _Day_of_year; // [0, 146096] + return days{_Era * 146097 + static_cast(_Day_of_era) - 719468}; + } + }; + + _NODISCARD constexpr bool operator==(const year_month_day& _Left, const year_month_day& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month() && _Left.day() == _Right.day(); + } + _NODISCARD constexpr strong_ordering operator<=>( + const year_month_day& _Left, const year_month_day& _Right) noexcept { + auto _Comp = _Left.year() <=> _Right.year(); + if (_Comp != 0) { + return _Comp; + } + + _Comp = _Left.month() <=> _Right.month(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.day() <=> _Right.day(); + } + + template + _NODISCARD constexpr year_month_day operator+(const year_month_day& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), _Ym.month(), _Left.day()}; + } + + template + _NODISCARD constexpr year_month_day operator+(const months& _Left, const year_month_day& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_day operator-(const year_month_day& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_day operator+(const year_month_day& _Left, const years& _Right) noexcept { + return {_Left.year() + _Right, _Left.month(), _Left.day()}; + } + + _NODISCARD constexpr year_month_day operator+(const years& _Left, const year_month_day& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month_day operator-(const year_month_day& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_day& year_month_day::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_day& year_month_day::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_day& year_month_day::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_day& year_month_day::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + class year_month_day_last { + public: + constexpr year_month_day_last(const year& _Year_, const month_day_last& _Mdl) noexcept + : _Year{_Year_}, _Month_day_last{_Mdl} {} + + template + constexpr year_month_day_last& operator+=(const months& _Months) noexcept; + template + constexpr year_month_day_last& operator-=(const months& _Months) noexcept; + constexpr year_month_day_last& operator+=(const years& _Years) noexcept; + constexpr year_month_day_last& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month_day_last.month(); + } + _NODISCARD constexpr month_day_last month_day_last() const noexcept { + return _Month_day_last; + } + _NODISCARD constexpr day day() const noexcept { + return _Last_day(year(), month()); + } + + _NODISCARD constexpr operator sys_days() const noexcept { + return sys_days{year_month_day{year(), month(), day()}}; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Year.ok() && _Month_day_last.ok(); + } + + private: + _CHRONO year _Year; + _CHRONO month_day_last _Month_day_last; + }; + + _NODISCARD constexpr bool operator==(const year_month_day_last& _Left, const year_month_day_last& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month_day_last() == _Right.month_day_last(); + } + _NODISCARD constexpr strong_ordering operator<=>( + const year_month_day_last& _Left, const year_month_day_last& _Right) noexcept { + const auto _Comp = _Left.year() <=> _Right.year(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.month_day_last() <=> _Right.month_day_last(); + } + + template + _NODISCARD constexpr year_month_day_last operator+( + const year_month_day_last& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), month_day_last{_Ym.month()}}; + } + template + _NODISCARD constexpr year_month_day_last operator+( + const months& _Left, const year_month_day_last& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_day_last operator-( + const year_month_day_last& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_day_last operator+(const year_month_day_last& _Left, const years& _Right) noexcept { + return {_Left.year() + _Right, _Left.month_day_last()}; + } + _NODISCARD constexpr year_month_day_last operator+(const years& _Left, const year_month_day_last& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr year_month_day_last operator-(const year_month_day_last& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_day_last& year_month_day_last::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_day_last& year_month_day_last::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_day_last& year_month_day_last::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_day_last& year_month_day_last::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + constexpr year_month_day::year_month_day(const year_month_day_last& _Ymdl) noexcept + : _Year{_Ymdl.year()}, _Month{_Ymdl.month()}, _Day{_Ymdl.day()} {} + + class year_month_weekday { + public: + year_month_weekday() = default; + constexpr year_month_weekday(const year& _Year_, const month& _Month_, const weekday_indexed& _Wdi) noexcept + : _Year{_Year_}, _Month{_Month_}, _Weekday_index{_Wdi} {} + constexpr year_month_weekday(const sys_days& _Sys_days) noexcept + : year_month_weekday{_Ymwd_from_days(_Sys_days.time_since_epoch())} {} + constexpr explicit year_month_weekday(const local_days& _Local_days) noexcept + : year_month_weekday{_Ymwd_from_days(_Local_days.time_since_epoch())} {} + + template + constexpr year_month_weekday& operator+=(const months& _Months) noexcept; + template + constexpr year_month_weekday& operator-=(const months& _Months) noexcept; + constexpr year_month_weekday& operator+=(const years& _Years) noexcept; + constexpr year_month_weekday& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday_index.weekday(); + } + _NODISCARD constexpr unsigned int index() const noexcept { + return _Weekday_index.index(); + } + _NODISCARD constexpr weekday_indexed weekday_indexed() const noexcept { + return _Weekday_index; + } + + _NODISCARD constexpr operator sys_days() const noexcept { + const sys_days _First = year_month_day{_Year, _Month, day{1}}; + const days _Diff = weekday() - _CHRONO weekday{_First}; + const days _Days = _Diff + days{(static_cast(index()) - 1) * 7}; + return _First + _Days; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + if (!_Year.ok() || !_Month.ok() || !_Weekday_index.ok()) { + return false; + } + + if (_Weekday_index.index() <= 4) { + return true; + } + + // As index() == 5 is not always valid + // Determine the date of the first weekday and check if + days{28} is <= last day of the month + const sys_days _First_of_month = year_month_day{_Year, _Month, day{1}}; + const days _First_weekday = weekday() - _CHRONO weekday{_First_of_month} + days{1}; + const days _Last = _First_weekday + days{28}; + return static_cast(_Last.count()) <= static_cast(_Last_day(_Year, _Month)); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + _CHRONO weekday_indexed _Weekday_index; + + _NODISCARD static constexpr year_month_weekday _Ymwd_from_days(days _Dp) noexcept { + const _CHRONO year_month_day _Ymd = sys_days{_Dp}; + const _CHRONO weekday _Wd = sys_days{_Dp}; + const auto _Idx = ((static_cast(_Ymd.day()) - 1) / 7) + 1; + return {_Ymd.year(), _Ymd.month(), _Wd[_Idx]}; + } + }; + + _NODISCARD constexpr bool operator==(const year_month_weekday& _Left, const year_month_weekday& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month() + && _Left.weekday_indexed() == _Right.weekday_indexed(); + } + + template + _NODISCARD constexpr year_month_weekday operator+(const year_month_weekday& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), _Ym.month(), _Left.weekday_indexed()}; + } + template + _NODISCARD constexpr year_month_weekday operator+(const months& _Left, const year_month_weekday& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_weekday operator-(const year_month_weekday& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_weekday operator+(const year_month_weekday& _Left, const years& _Right) noexcept { + return year_month_weekday{_Left.year() + _Right, _Left.month(), _Left.weekday_indexed()}; + } + _NODISCARD constexpr year_month_weekday operator+(const years& _Left, const year_month_weekday& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month_weekday operator-(const year_month_weekday& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_weekday& year_month_weekday::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_weekday& year_month_weekday::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_weekday& year_month_weekday::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_weekday& year_month_weekday::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + class year_month_weekday_last { + public: + constexpr year_month_weekday_last(const year& _Year_, const month& _Month_, const weekday_last& _Wdl) noexcept + : _Year{_Year_}, _Month{_Month_}, _Weekday_last{_Wdl} {} + + template + constexpr year_month_weekday_last& operator+=(const months& _Months) noexcept; + template + constexpr year_month_weekday_last& operator-=(const months& _Months) noexcept; + constexpr year_month_weekday_last& operator+=(const years& _Years) noexcept; + constexpr year_month_weekday_last& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday_last.weekday(); + } + + _NODISCARD constexpr weekday_last weekday_last() const noexcept { + return _Weekday_last; + } + + _NODISCARD constexpr operator sys_days() const noexcept { + const sys_days _Last = year_month_day_last{_Year, month_day_last{_Month}}; + const auto _Diff = _CHRONO weekday{_Last} - weekday(); + return _Last - _Diff; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Year.ok() && _Month.ok() && _Weekday_last.ok(); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + _CHRONO weekday_last _Weekday_last; + }; + + _NODISCARD constexpr bool operator==( + const year_month_weekday_last& _Left, const year_month_weekday_last& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month() + && _Left.weekday_last() == _Right.weekday_last(); + } + + template + _NODISCARD constexpr year_month_weekday_last operator+( + const year_month_weekday_last& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), _Ym.month(), _Left.weekday_last()}; + } + template + _NODISCARD constexpr year_month_weekday_last operator+( + const months& _Left, const year_month_weekday_last& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_weekday_last operator-( + const year_month_weekday_last& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_weekday_last operator+( + const year_month_weekday_last& _Left, const years& _Right) noexcept { + return {_Left.year() + _Right, _Left.month(), _Left.weekday_last()}; + } + _NODISCARD constexpr year_month_weekday_last operator+( + const years& _Left, const year_month_weekday_last& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month_weekday_last operator-( + const year_month_weekday_last& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_weekday_last& year_month_weekday_last::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_weekday_last& year_month_weekday_last::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_weekday_last& year_month_weekday_last::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_weekday_last& year_month_weekday_last::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + // Civil calendar conventional syntax operators + _NODISCARD constexpr year_month operator/(const year& _Year, const month& _Month) noexcept { + return {_Year, _Month}; + } + _NODISCARD constexpr year_month operator/(const year& _Year, int _Month) noexcept { + return _Year / month{static_cast(_Month)}; + } + _NODISCARD constexpr month_day operator/(const month& _Month, const day& _Day) noexcept { + return {_Month, _Day}; + } + _NODISCARD constexpr month_day operator/(const month& _Month, int _Day) noexcept { + return _Month / day{static_cast(_Day)}; + } + _NODISCARD constexpr month_day operator/(int _Month, const day& _Day) noexcept { + return month{static_cast(_Month)} / _Day; + } + _NODISCARD constexpr month_day operator/(const day& _Day, const month& _Month) noexcept { + return _Month / _Day; + } + _NODISCARD constexpr month_day operator/(const day& _Day, int _Month) noexcept { + return month{static_cast(_Month)} / _Day; + } + _NODISCARD constexpr month_day_last operator/(const month& _Month, last_spec) noexcept { + return month_day_last{_Month}; + } + _NODISCARD constexpr month_day_last operator/(int _Month, last_spec) noexcept { + return month{static_cast(_Month)} / last; + } + _NODISCARD constexpr month_day_last operator/(last_spec, const month& _Month) noexcept { + return _Month / last; + } + _NODISCARD constexpr month_day_last operator/(last_spec, int _Month) noexcept { + return month{static_cast(_Month)} / last; + } + _NODISCARD constexpr month_weekday operator/(const month& _Month, const weekday_indexed& _Wdi) noexcept { + return {_Month, _Wdi}; + } + _NODISCARD constexpr month_weekday operator/(int _Month, const weekday_indexed& _Wdi) noexcept { + return month{static_cast(_Month)} / _Wdi; + } + _NODISCARD constexpr month_weekday operator/(const weekday_indexed& _Wdi, const month& _Month) noexcept { + return _Month / _Wdi; + } + _NODISCARD constexpr month_weekday operator/(const weekday_indexed& _Wdi, int _Month) noexcept { + return month{static_cast(_Month)} / _Wdi; + } + _NODISCARD constexpr month_weekday_last operator/(const month& _Month, const weekday_last& _Wdl) noexcept { + return {_Month, _Wdl}; + } + _NODISCARD constexpr month_weekday_last operator/(int _Month, const weekday_last& _Wdl) noexcept { + return month{static_cast(_Month)} / _Wdl; + } + _NODISCARD constexpr month_weekday_last operator/(const weekday_last& _Wdl, const month& _Month) noexcept { + return _Month / _Wdl; + } + _NODISCARD constexpr month_weekday_last operator/(const weekday_last& _Wdl, int _Month) noexcept { + return month{static_cast(_Month)} / _Wdl; + } + _NODISCARD constexpr year_month_day operator/(const year_month& _Ym, const day& _Day) noexcept { + return {_Ym.year(), _Ym.month(), _Day}; + } + _NODISCARD constexpr year_month_day operator/(const year_month& _Ym, int _Day) noexcept { + return _Ym / day{static_cast(_Day)}; + } + _NODISCARD constexpr year_month_day operator/(const year& _Year, const month_day& _Md) noexcept { + return _Year / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day operator/(int _Year, const month_day& _Md) noexcept { + return year{_Year} / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day operator/(const month_day& _Md, const year& _Year) noexcept { + return _Year / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day operator/(const month_day& _Md, int _Year) noexcept { + return year{_Year} / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day_last operator/(const year_month& _Ym, last_spec) noexcept { + return {_Ym.year(), month_day_last{_Ym.month()}}; + } + _NODISCARD constexpr year_month_day_last operator/(const year& _Year, const month_day_last& _Mdl) noexcept { + return {_Year, _Mdl}; + } + _NODISCARD constexpr year_month_day_last operator/(int _Year, const month_day_last& _Mdl) noexcept { + return year{_Year} / _Mdl; + } + _NODISCARD constexpr year_month_day_last operator/(const month_day_last& _Mdl, const year& _Year) noexcept { + return _Year / _Mdl; + } + _NODISCARD constexpr year_month_day_last operator/(const month_day_last& _Mdl, int _Year) noexcept { + return year{_Year} / _Mdl; + } + _NODISCARD constexpr year_month_weekday operator/(const year_month& _Ym, const weekday_indexed& _Wdi) noexcept { + return year_month_weekday{_Ym.year(), _Ym.month(), _Wdi}; + } + _NODISCARD constexpr year_month_weekday operator/(const year& _Year, const month_weekday& _Mwd) noexcept { + return year_month_weekday{_Year, _Mwd.month(), _Mwd.weekday_indexed()}; + } + _NODISCARD constexpr year_month_weekday operator/(int _Year, const month_weekday& _Mwd) noexcept { + return year{_Year} / _Mwd; + } + _NODISCARD constexpr year_month_weekday operator/(const month_weekday& _Mwd, const year& _Year) noexcept { + return _Year / _Mwd; + } + _NODISCARD constexpr year_month_weekday operator/(const month_weekday& _Mwd, int _Year) noexcept { + return year{_Year} / _Mwd; + } + _NODISCARD constexpr year_month_weekday_last operator/(const year_month& _Ym, const weekday_last& _Wdl) noexcept { + return {_Ym.year(), _Ym.month(), _Wdl}; + } + _NODISCARD constexpr year_month_weekday_last operator/( + const year& _Year, const month_weekday_last& _Mwdl) noexcept { + return {_Year, _Mwdl.month(), _Mwdl.weekday_last()}; + } + _NODISCARD constexpr year_month_weekday_last operator/(int _Year, const month_weekday_last& _Mwdl) noexcept { + return year{_Year} / _Mwdl; + } + _NODISCARD constexpr year_month_weekday_last operator/( + const month_weekday_last& _Mwdl, const year& _Year) noexcept { + return _Year / _Mwdl; + } + _NODISCARD constexpr year_month_weekday_last operator/(const month_weekday_last& _Mwdl, int _Year) noexcept { + return year{_Year} / _Mwdl; + } + + // Calendrical constants + inline constexpr weekday Sunday{0}; + inline constexpr weekday Monday{1}; + inline constexpr weekday Tuesday{2}; + inline constexpr weekday Wednesday{3}; + inline constexpr weekday Thursday{4}; + inline constexpr weekday Friday{5}; + inline constexpr weekday Saturday{6}; + + inline constexpr month January{1}; + inline constexpr month February{2}; + inline constexpr month March{3}; + inline constexpr month April{4}; + inline constexpr month May{5}; + inline constexpr month June{6}; + inline constexpr month July{7}; + inline constexpr month August{8}; + inline constexpr month September{9}; + inline constexpr month October{10}; + inline constexpr month November{11}; + inline constexpr month December{12}; + + _NODISCARD constexpr intmax_t _Pow10(const unsigned int _Exp) { + intmax_t _Result = 1; + for (unsigned int _Ix = 0; _Ix < _Exp; ++_Ix) { + _Result *= 10; + } + return _Result; + } + + template + requires _Is_duration_v<_Duration> class hh_mm_ss { + public: + static constexpr unsigned int fractional_width = [] { + auto _Num = _Duration::period::num; + constexpr auto _Den = _Duration::period::den; + // Returns the number of fractional digits of _Num / _Den in the range [0, 18]. + // If it can't be represented, 6 is returned. + // Example: _Fractional_width(1, 8) would return 3 for 0.125. + _STL_ASSERT(_Num > 0 && _Den > 0, "Numerator and denominator can't be less than 1."); + unsigned int _Result = 0; + for (; _Num % _Den != 0 && _Result < 19; _Num = _Num % _Den * 10, ++_Result) { + } + return _Result == 19 ? 6 : _Result; + }(); + using precision = + duration, ratio<1, _Pow10(fractional_width)>>; + + constexpr hh_mm_ss() noexcept : hh_mm_ss{_Duration::zero()} {} + // clang-format off + constexpr explicit hh_mm_ss(_Duration _Dur) + : _Is_neg{_Dur < _Duration::zero()}, + _Hours{_CHRONO duration_cast<_CHRONO hours>(_CHRONO abs(_Dur))}, + _Mins{_CHRONO duration_cast<_CHRONO minutes>(_CHRONO abs(_Dur) - hours())}, + _Secs{_CHRONO duration_cast<_CHRONO seconds>(_CHRONO abs(_Dur) - hours() - minutes())} { + // clang-format on + if constexpr (treat_as_floating_point_v) { + _Sub_secs = _CHRONO abs(_Dur) - hours() - minutes() - seconds(); + } else { + _Sub_secs = _CHRONO duration_cast(_CHRONO abs(_Dur) - hours() - minutes() - seconds()); + } + } + + _NODISCARD constexpr bool is_negative() const noexcept { + return _Is_neg; + } + _NODISCARD constexpr hours hours() const noexcept { + return _Hours; + } + _NODISCARD constexpr minutes minutes() const noexcept { + return _Mins; + } + _NODISCARD constexpr seconds seconds() const noexcept { + return _Secs; + } + _NODISCARD constexpr precision subseconds() const noexcept { + return _Sub_secs; + } + + _NODISCARD constexpr explicit operator precision() const noexcept { + return to_duration(); + } + _NODISCARD constexpr precision to_duration() const noexcept { + const auto _Dur = _Hours + _Mins + _Secs + _Sub_secs; + return _Is_neg ? -_Dur : _Dur; + } + + private: + bool _Is_neg; + _CHRONO hours _Hours; + _CHRONO minutes _Mins; + _CHRONO seconds _Secs; + precision _Sub_secs; + }; + + _NODISCARD constexpr bool is_am(const hours& _Hours) noexcept { + return _Hours >= hours{0} && _Hours <= hours{11}; + } + _NODISCARD constexpr bool is_pm(const hours& _Hours) noexcept { + return _Hours >= hours{12} && _Hours <= hours{23}; + } + + _NODISCARD constexpr hours make12(const hours& _Hours) noexcept { + const auto _H_count{_Hours.count()}; + auto _Ret{_H_count == 0 ? 12 : _H_count}; + if (_Ret > 12) { + _Ret -= 12; + } + + return hours{_Ret}; + } + _NODISCARD constexpr hours make24(const hours& _Hours, bool _Is_pm) noexcept { + const auto _H_count{_Hours.count()}; + auto _Ret{_H_count == 12 ? 0 : _H_count}; + if (_Is_pm) { + _Ret += 12; + } + + return hours{_Ret}; + } #endif // _HAS_CXX20 } // namespace chrono // HELPERS template -_NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const chrono::duration<_Rep, _Period>& _Rel_time) noexcept( +_NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept( is_arithmetic_v<_Rep>) { // Convert duration to xtime, maximum 10 days from now, returns whether clamping occurred. // If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where // the other side of the DLL boundary overflows int32_t milliseconds. // Every function calling this one is TRANSITION, ABI - constexpr chrono::nanoseconds _Ten_days{chrono::hours{24} * 10}; - constexpr chrono::duration _Ten_days_d{_Ten_days}; - chrono::nanoseconds _Tx0 = chrono::system_clock::now().time_since_epoch(); + constexpr _CHRONO nanoseconds _Ten_days{_CHRONO hours{24} * 10}; + constexpr _CHRONO duration _Ten_days_d{_Ten_days}; + _CHRONO nanoseconds _Tx0 = _CHRONO system_clock::now().time_since_epoch(); const bool _Clamped = _Ten_days_d < _Rel_time; if (_Clamped) { _Tx0 += _Ten_days; } else { - _Tx0 += chrono::duration_cast(_Rel_time); + _Tx0 += _CHRONO duration_cast<_CHRONO nanoseconds>(_Rel_time); } - const auto _Whole_seconds = chrono::duration_cast(_Tx0); + const auto _Whole_seconds = _CHRONO duration_cast<_CHRONO seconds>(_Tx0); _Xt.sec = _Whole_seconds.count(); _Tx0 -= _Whole_seconds; _Xt.nsec = static_cast(_Tx0.count()); @@ -730,58 +2092,66 @@ _NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const chrono::duratio // duration LITERALS inline namespace literals { inline namespace chrono_literals { - _NODISCARD constexpr chrono::hours operator"" h(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::hours(_Val); + _NODISCARD constexpr _CHRONO hours operator"" h(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO hours(_Val); } - _NODISCARD constexpr chrono::duration> operator"" h(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration> operator"" h(long double _Val) noexcept /* strengthened */ { - return chrono::duration>(_Val); + return _CHRONO duration>(_Val); } - _NODISCARD constexpr chrono::minutes(operator"" min)(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::minutes(_Val); + _NODISCARD constexpr _CHRONO minutes(operator"" min)(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO minutes(_Val); } - _NODISCARD constexpr chrono::duration>(operator"" min)(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration>(operator"" min)(long double _Val) noexcept /* strengthened */ { - return chrono::duration>(_Val); + return _CHRONO duration>(_Val); } - _NODISCARD constexpr chrono::seconds operator"" s(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::seconds(_Val); + _NODISCARD constexpr _CHRONO seconds operator"" s(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO seconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" s(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + _NODISCARD constexpr _CHRONO duration operator"" s(long double _Val) noexcept /* strengthened */ { + return _CHRONO duration(_Val); } - _NODISCARD constexpr chrono::milliseconds operator"" ms(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::milliseconds(_Val); + _NODISCARD constexpr _CHRONO milliseconds operator"" ms(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO milliseconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" ms(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration operator"" ms(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + return _CHRONO duration(_Val); } - _NODISCARD constexpr chrono::microseconds operator"" us(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::microseconds(_Val); + _NODISCARD constexpr _CHRONO microseconds operator"" us(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO microseconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" us(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration operator"" us(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + return _CHRONO duration(_Val); } - _NODISCARD constexpr chrono::nanoseconds operator"" ns(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::nanoseconds(_Val); + _NODISCARD constexpr _CHRONO nanoseconds operator"" ns(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO nanoseconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" ns(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration operator"" ns(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + return _CHRONO duration(_Val); } +#if _HAS_CXX20 + _NODISCARD constexpr _CHRONO day operator"" d(unsigned long long _Day) noexcept { + return _CHRONO day{static_cast(_Day)}; + } + _NODISCARD constexpr _CHRONO year operator"" y(unsigned long long _Year) noexcept { + return _CHRONO year{static_cast(_Year)}; + } +#endif // _HAS_CXX20 } // namespace chrono_literals } // namespace literals diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index e37d8daf036..cb6379b7566 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -138,6 +138,8 @@ // P0318R1 unwrap_reference, unwrap_ref_decay // P0325R4 to_array() // P0339R6 polymorphic_allocator<> +// P0355R7 Calendars And Time Zones +// (partially implemented) // P0356R5 bind_front() // P0357R3 Supporting Incomplete Types In reference_wrapper // P0408R7 Efficient Access To basic_stringbuf's Buffer @@ -1278,6 +1280,7 @@ compiler option, or define _ALLOW_RTCc_IN_STL to acknowledge that you have recei #define _STD_BEGIN namespace std { #define _STD_END } #define _STD ::std:: +#define _CHRONO ::std::chrono:: #define _RANGES ::std::ranges:: // We use the stdext (standard extension) namespace to contain extensions that are not part of the current standard diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 8961a1cc341..f87033a4b49 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -286,205 +286,25 @@ std/strings/string.view/string.view.io/stream_insert_decl_present.compile.pass.c # *** MISSING STL FEATURES *** # C++20 P0355R7 " Calendars And Time Zones" -std/utilities/time/days.pass.cpp FAIL -std/utilities/time/months.pass.cpp FAIL -std/utilities/time/weeks.pass.cpp FAIL -std/utilities/time/years.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.last/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.md/time.cal.md.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/ok.pass.cpp FAIL std/utilities/time/time.cal/time.cal.mdlast/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/weekday_indexed.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/weekday_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_weekday_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_weekday_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/index.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/c_encoding.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/iso_encoding.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/operator[].pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/is_leap.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/plus_minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.year_month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/index.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/weekday_indexed.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/streaming.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/consistency.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/file_time.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/now.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/rep_signed.pass.cpp FAIL -std/utilities/time/time.clock/time.clock.system/local_time.types.pass.cpp FAIL -std/utilities/time/time.clock/time.clock.system/sys.time.types.pass.cpp FAIL -std/utilities/time/time.duration/time.duration.literals/literals1.pass.cpp FAIL -std/utilities/time/time.hms/time.12/is_am.pass.cpp FAIL -std/utilities/time/time.hms/time.12/is_pm.pass.cpp FAIL -std/utilities/time/time.hms/time.12/make12.pass.cpp FAIL -std/utilities/time/time.hms/time.12/make24.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/hours.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/is_negative.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/minutes.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/precision.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/precision_type.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/seconds.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/subseconds.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/to_duration.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/width.pass.cpp FAIL # C++20 P0608R3 "Improving variant's Converting Constructor/Assignment" std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp FAIL @@ -809,6 +629,30 @@ std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/eval.pass.cpp F # They shouldn't behave differently. Both of them should probably return NaN. std/numerics/c.math/c.math.lerp/c.math.lerp.pass.cpp FAIL +# --month{14} should be 1, not 13 as the test expects +std/utilities/time/time.cal/time.cal.month/time.cal.month.members/decrement.pass.cpp FAIL + +# test is broken due to month_weekday not being default constructible +std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/month.pass.cpp FAIL + +# conversion from '__int64' to 'long', possible loss of data +std/utilities/time/time.hms/time.hms.members/seconds.pass.cpp:0 FAIL +std/utilities/time/time.hms/time.hms.members/subseconds.pass.cpp:0 FAIL + +# Code: `for (int i = 1000; i < 20; ++i)` +# warning C6294: Ill-defined for-loop: initial condition does not satisfy test. Loop body not executed. +std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/comparisons.pass.cpp:0 FAIL + +# Tests are manually declaring printf, which appears to be unused. +# warning C28301: No annotations for first declaration of 'printf'. +std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/minus.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/minus.pass.cpp:0 FAIL + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Assertions and other runtime failures. diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 61b46acc242..a087a941415 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -286,205 +286,25 @@ strings\string.view\string.view.io\stream_insert_decl_present.compile.pass.cpp # *** MISSING STL FEATURES *** # C++20 P0355R7 " Calendars And Time Zones" -utilities\time\days.pass.cpp -utilities\time\months.pass.cpp -utilities\time\weeks.pass.cpp -utilities\time\years.pass.cpp -utilities\time\time.cal\time.cal.day\types.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\increment.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\ok.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.last\types.pass.cpp -utilities\time\time.cal\time.cal.md\types.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\day.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\month.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\ok.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.md\time.cal.md.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.mdlast\comparisons.pass.cpp -utilities\time\time.cal\time.cal.mdlast\ctor.pass.cpp -utilities\time\time.cal\time.cal.mdlast\month.pass.cpp -utilities\time\time.cal\time.cal.mdlast\ok.pass.cpp utilities\time\time.cal\time.cal.mdlast\streaming.pass.cpp -utilities\time\time.cal\time.cal.mdlast\types.pass.cpp -utilities\time\time.cal\time.cal.month\types.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\increment.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\ok.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.mwd\types.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\month.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\ok.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\weekday_indexed.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.mwd\time.cal.mwd.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\types.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\month.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\weekday_last.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.operators\month_day.pass.cpp -utilities\time\time.cal\time.cal.operators\month_day_last.pass.cpp -utilities\time\time.cal\time.cal.operators\month_weekday.pass.cpp -utilities\time\time.cal\time.cal.operators\month_weekday_last.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_day.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_day_last.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_weekday.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_weekday_last.pass.cpp -utilities\time\time.cal\time.cal.wdidx\types.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\index.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\ok.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.wdlast\types.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.weekday\types.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\c_encoding.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ctor.local_days.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ctor.sys_days.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\increment.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\iso_encoding.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ok.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\operator[].pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.year\types.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\increment.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\is_leap.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\ok.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\plus_minus.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ym\types.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\month.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\year.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymd\types.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.year_month_day_last.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\day.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\op.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\op.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\day.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\month_day_last.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\op_local_days.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\op_sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymwd\types.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ctor.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ctor.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\index.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\op.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\op.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\weekday_indexed.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\types.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\op_local_days.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\op_sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\streaming.pass.cpp utilities\time\time.clock\time.clock.file\consistency.pass.cpp utilities\time\time.clock\time.clock.file\file_time.pass.cpp utilities\time\time.clock\time.clock.file\now.pass.cpp utilities\time\time.clock\time.clock.file\rep_signed.pass.cpp -utilities\time\time.clock\time.clock.system\local_time.types.pass.cpp -utilities\time\time.clock\time.clock.system\sys.time.types.pass.cpp -utilities\time\time.duration\time.duration.literals\literals1.pass.cpp -utilities\time\time.hms\time.12\is_am.pass.cpp -utilities\time\time.hms\time.12\is_pm.pass.cpp -utilities\time\time.hms\time.12\make12.pass.cpp -utilities\time\time.hms\time.12\make24.pass.cpp -utilities\time\time.hms\time.hms.members\hours.pass.cpp -utilities\time\time.hms\time.hms.members\is_negative.pass.cpp -utilities\time\time.hms\time.hms.members\minutes.pass.cpp -utilities\time\time.hms\time.hms.members\precision.pass.cpp -utilities\time\time.hms\time.hms.members\precision_type.pass.cpp -utilities\time\time.hms\time.hms.members\seconds.pass.cpp -utilities\time\time.hms\time.hms.members\subseconds.pass.cpp -utilities\time\time.hms\time.hms.members\to_duration.pass.cpp -utilities\time\time.hms\time.hms.members\width.pass.cpp # C++20 P0608R3 "Improving variant's Converting Constructor/Assignment" utilities\variant\variant.variant\variant.assign\conv.pass.cpp @@ -809,6 +629,30 @@ numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\eval.pass.cpp # They shouldn't behave differently. Both of them should probably return NaN. numerics\c.math\c.math.lerp\c.math.lerp.pass.cpp +# --month{14} should be 1, not 13 as the test expects +utilities\time\time.cal\time.cal.month\time.cal.month.members\decrement.pass.cpp + +# test is broken due to month_weekday not being default constructible +utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\month.pass.cpp + +# conversion from '__int64' to 'long', possible loss of data +utilities\time\time.hms\time.hms.members\seconds.pass.cpp +utilities\time\time.hms\time.hms.members\subseconds.pass.cpp + +# Code: `for (int i = 1000; i < 20; ++i)` +# warning C6294: Ill-defined for-loop: initial condition does not satisfy test. Loop body not executed. +utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\comparisons.pass.cpp + +# Tests are manually declaring printf, which appears to be unused. +# warning C28301: No annotations for first declaration of 'printf'. +utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\minus.pass.cpp +utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\minus.pass.cpp + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Assertions and other runtime failures. diff --git a/tests/std/test.lst b/tests/std/test.lst index 014d2c798d4..8560d477f8d 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -226,7 +226,12 @@ tests\P0220R1_searchers tests\P0220R1_string_view tests\P0325R4_to_array tests\P0339R6_polymorphic_allocator +tests\P0355R7_calendars_and_time_zones_clocks +tests\P0355R7_calendars_and_time_zones_dates +tests\P0355R7_calendars_and_time_zones_dates_literals +tests\P0355R7_calendars_and_time_zones_hms tests\P0355R7_calendars_and_time_zones_io +tests\P0355R7_calendars_and_time_zones_time_point_and_durations tests\P0356R5_bind_front tests\P0357R3_supporting_incomplete_types_in_reference_wrapper tests\P0408R7_efficient_access_to_stringbuf_buffer diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.compile.pass.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.compile.pass.cpp new file mode 100644 index 00000000000..26ac91006b0 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.compile.pass.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +using namespace std::chrono; + +struct not_a_clock { + bool rep(); + static char period; + int duration(); + static float time_point; + using is_steady = long; + static int now; +}; + +struct real_fake_clock { + using rep = bool; + using period = char; + using duration = float; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_rep { + using period = char; + using duration = float; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_period { + using rep = bool; + using duration = float; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_duration { + using rep = bool; + using period = char; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_time_point { + using rep = bool; + using period = char; + using duration = float; + static long is_steady; + static short now(); +}; + +struct no_steady { + using rep = bool; + using period = char; + using duration = float; + using time_point = int; + static short now(); +}; + +struct no_now { + using rep = bool; + using period = char; + using duration = float; + using time_point = int; + static long is_steady; +}; + +static_assert(is_clock::value, "steady_clock is not a clock"); +static_assert(is_clock_v, "steady_clock is not a clock"); +static_assert(is_clock_v, "real_fake_clock is not a clock"); +static_assert(!is_clock_v, "not_a_clock is a clock"); + +static_assert(!is_clock_v, "no_rep is a clock"); +static_assert(!is_clock_v, "no_period is a clock"); +static_assert(!is_clock_v, "no_duration is a clock"); +static_assert(!is_clock_v, "no_time_point is a clock"); +static_assert(!is_clock_v, "no_steady is a clock"); +static_assert(!is_clock_v, "no_now is a clock"); + +int main() {} // COMPILE-ONLY diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp new file mode 100644 index 00000000000..90d6d7ad946 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp @@ -0,0 +1,988 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +constexpr int y_min = -32767; +constexpr int y_max = 32767; + +// For testing LWG-3260 "year_month* arithmetic rejects durations convertible to years" +using Decades = duration, years::period>>; + +constexpr void day_test() { + day d{0u}; + + static_assert(noexcept(day{})); + static_assert(noexcept(day{0u})); + + static_assert(noexcept(++d)); + static_assert(noexcept(d++)); + static_assert(noexcept(--d)); + static_assert(noexcept(d--)); + static_assert(noexcept(d += days{})); + static_assert(noexcept(d -= days{})); + + static_assert(noexcept(static_cast(d))); + static_assert(noexcept(d.ok())); + + static_assert(noexcept(d == d)); + static_assert(noexcept(d <=> d)); + + static_assert(noexcept(d + days{})); + static_assert(noexcept(days{} + d)); + + static_assert(noexcept(d - days{})); + static_assert(noexcept(d - d)); + + static_assert(noexcept(0d)); + + assert(static_cast(d) == 0u); + assert(d == 0d); + assert(++d == 1d); + assert(d++ == 1d); + assert(d == 2d); + + assert(--d == 1d); + assert(d-- == 1d); + assert(d == 0d); + + d += days{2}; + assert(d == 2d); + d -= days{2}; + assert(d == 0d); + + assert(d < 2d); + assert(2d > d); + + for (unsigned int i = 0; i <= 255; ++i) { + if (i > 0 && i <= 31) { + assert(day{i}.ok()); + } else { + assert(!day{i}.ok()); + } + } + + assert(5d + days{5} == 10d); + assert(days{5} + 5d == 10d); + assert(10d - days{5} == 5d); + assert(10d - 2d == days{8}); +} + +constexpr void month_test() { + month m{1u}; + + static_assert(noexcept(month{})); + static_assert(noexcept(month{0u})); + + static_assert(noexcept(++m)); + static_assert(noexcept(m++)); + static_assert(noexcept(--m)); + static_assert(noexcept(m--)); + static_assert(noexcept(m += months{})); + static_assert(noexcept(m -= months{})); + + static_assert(noexcept(static_cast(m))); + static_assert(noexcept(m.ok())); + + static_assert(noexcept(m == m)); + static_assert(noexcept(m <=> m)); + + static_assert(noexcept(m + months{})); + static_assert(noexcept(months{0} + m)); + + static_assert(noexcept(m - months{})); + static_assert(noexcept(m - m)); + + assert(static_cast(m) == 1u); + assert(m == January); + assert(++m == February); + assert(m++ == February); + assert(m == March); + + assert(--m == February); + assert(m-- == February); + assert(m == January); + + m += months{2}; + assert(m == March); + m -= months{2}; + assert(m == January); + + for (unsigned int i = 0; i <= 255; ++i) { + if (i >= 1 && i <= 12) { + assert(month{i}.ok()); + } else { + assert(!month{i}.ok()); + } + } + + assert(February > m); + assert(m < February); + + assert(February + months{11} == January); + assert(months{11} + February == January); + assert(month{0} + months{1} == January); + assert(month{13} + months{1} == February); + assert(month{23} + months{1} == December); + assert(February - months{2} == December); + assert(January - February == months{11}); +} + +constexpr void year_test() { + year y{1}; + + static_assert(noexcept(year{})); + static_assert(noexcept(year{0})); + + static_assert(noexcept(++y)); + static_assert(noexcept(y++)); + static_assert(noexcept(--y)); + static_assert(noexcept(y--)); + static_assert(noexcept(y += years{})); + static_assert(noexcept(y -= years{})); + static_assert(noexcept(+y)); + static_assert(noexcept(-y)); + + static_assert(noexcept(y.is_leap())); + static_assert(noexcept(static_cast(y))); + static_assert(noexcept(y.ok())); + static_assert(noexcept(year::min())); + static_assert(noexcept(year::max())); + + static_assert(noexcept(y == y)); + static_assert(noexcept(y <=> y)); + + static_assert(noexcept(y + years{})); + static_assert(noexcept(years{} + y)); + + static_assert(noexcept(y - years{})); + static_assert(noexcept(y - y)); + + static_assert(noexcept(0y)); + + assert(static_cast(y) == 1); + assert(y == 1y); + assert(++y == 2y); + assert(y++ == 2y); + assert(y == 3y); + + assert(--y == 2y); + assert(y-- == 2y); + assert(y == 1y); + + y += years{2}; + assert(y == 3y); + y -= years{2}; + assert(y == 1y); + + year extreme{-30'000}; + extreme += years{60'000}; + assert(extreme == 30'000y); + extreme -= years{60'000}; + assert(extreme == -30'000y); + + assert(+y == 1y); + assert(-y == year{-1}); + auto y2 = -y; + assert(-y2 == y); + assert(+y2 == -y); + + assert(year::min() == year{y_min}); + assert(year::max() == year{y_max}); + + assert(!year{y_min - 1}.ok()); + assert(!year{y_max + 1}.ok()); + + for (int i = y_min; i <= y_max; ++i) { + assert(year{i}.ok()); + if (i % 4 == 0 && (i % 100 != 0 || i % 400 == 0)) { + assert(year{i}.is_leap()); + } else { + assert(!year{i}.is_leap()); + } + } + + assert(y < 2y); + assert(2y > y); + + assert(y + years{4} == 5y); + assert(years{4} + y == 5y); + + assert(y - years{4} == -3y); + assert(year{10} - year{5} == years{5}); + assert(year{-5} - year{-10} == years{5}); +} + +constexpr void weekday_test() { + weekday wd{0u}; + + static_assert(noexcept(weekday{})); + static_assert(noexcept(weekday{0u})); + static_assert(noexcept(weekday{sys_days{}})); + static_assert(noexcept(weekday{local_days{}})); + + static_assert(noexcept(++wd)); + static_assert(noexcept(wd++)); + static_assert(noexcept(--wd)); + static_assert(noexcept(wd--)); + static_assert(noexcept(wd += days{})); + static_assert(noexcept(wd -= days{})); + + static_assert(noexcept(wd.c_encoding())); + static_assert(noexcept(wd.iso_encoding())); + static_assert(noexcept(wd.ok())); + static_assert(noexcept(wd[0u])); + static_assert(noexcept(wd[last])); + + static_assert(noexcept(wd == wd)); + + static_assert(noexcept(wd + days{})); + static_assert(noexcept(days{} + wd)); + + static_assert(noexcept(wd - days{})); + static_assert(noexcept(wd - wd)); + + assert(weekday{7} == Sunday); + assert(weekday{sys_days{}} == Thursday); + assert(weekday{local_days{}} == sys_days{local_days{}.time_since_epoch()}); + + assert(wd == Sunday); + assert(++wd == Monday); + assert(wd++ == Monday); + assert(wd == Tuesday); + + assert(--wd == Monday); + assert(wd-- == Monday); + assert(wd == Sunday); + + wd += days{2}; + assert(wd == Tuesday); + wd -= days{3}; + assert(wd == Saturday); + + assert(Sunday.c_encoding() == 0u); + assert(Sunday.iso_encoding() == 7u); + + for (unsigned int i = 0; i <= 255; ++i) { + if (i <= 7) { + assert(weekday{i}.ok()); + } else { + assert(!weekday{i}.ok()); + } + } + assert(Monday + days{6} == Sunday); + assert(Monday + days{8} == Tuesday); + assert(Wednesday + days{14} == Wednesday); + assert(Sunday - Monday == days{6}); + assert(Sunday - Tuesday == days{5}); + assert(Wednesday - Thursday == days{6}); +} + +constexpr void weekday_indexed_test() { + const weekday_indexed wdi1{Monday, 2}; + + static_assert(noexcept(weekday_indexed{})); + static_assert(noexcept(weekday_indexed{weekday{}, 0u})); + + static_assert(noexcept(wdi1.weekday())); + static_assert(noexcept(wdi1.index())); + static_assert(noexcept(wdi1.ok())); + + static_assert(noexcept(wdi1 == wdi1)); + + assert(wdi1.weekday() == Monday); + assert(wdi1.index() == 2); + + weekday_indexed wdi2 = Monday[2]; + assert(wdi2.weekday() == Monday); + assert(wdi2.index() == 2); + + assert(wdi1 == wdi2); + + assert((!weekday_indexed{Sunday, 0}.ok())); + for (unsigned int i = 1; i <= 5; ++i) { + assert((weekday_indexed{Sunday, i}.ok())); + assert((weekday_indexed{Monday, i}.ok())); + assert((weekday_indexed{Tuesday, i}.ok())); + assert((weekday_indexed{Wednesday, i}.ok())); + assert((weekday_indexed{Thursday, i}.ok())); + assert((weekday_indexed{Friday, i}.ok())); + assert((weekday_indexed{Saturday, i}.ok())); + } + assert((!weekday_indexed{Sunday, 6}.ok())); + assert((!weekday_indexed{Sunday, 7}.ok())); +} + +constexpr void weekday_last_test() { + const weekday_last wdl{Monday}; + + static_assert(noexcept(weekday_last{weekday{}})); + + static_assert(noexcept(wdl.weekday())); + static_assert(noexcept(wdl.ok())); + + static_assert(noexcept(wdl == wdl)); + + assert(wdl.ok()); + assert(Monday[last].ok()); + assert(Monday[last].weekday() == Monday); + assert(wdl.weekday() == Monday); + assert(wdl == weekday_last{Monday}); +} + +constexpr void month_day_test() { + const month_day md{January, 1d}; + + static_assert(noexcept(month_day{})); + static_assert(noexcept(month_day{month{}, day{}})); + + static_assert(noexcept(md.month())); + static_assert(noexcept(md.day())); + static_assert(noexcept(md.ok())); + + static_assert(noexcept(md == md)); + static_assert(noexcept(md <=> md)); + + assert(md.month() == January); + assert(md.day() == 1d); + + assert((md < month_day{January, 2d})); + assert((month_day{January, 2d} > md)); + assert((md < month_day{December, 25d})); + assert((month_day{December, 25d} > md)); + assert((md == month_day{January, 1d})); + + if (is_constant_evaluated()) { + static_assert((January / 31).ok()); + static_assert((February / 29).ok()); + static_assert((April / 30).ok()); + static_assert(!(January / 32).ok()); + static_assert(!(February / 30).ok()); + static_assert(!(April / 31).ok()); + } else { + for (unsigned int i = 0; i <= 255; ++i) { + month m{i}; + for (unsigned int d = 0; d <= 255; ++d) { + if (d < 1 || d > 31 || i < 1 || i > 12) { + assert((!month_day{m, day{d}}.ok())); + } else if (d == 30 && m == February) { + assert((!month_day{m, day{d}}.ok())); + } else if (d == 31 && (m == February || m == April || m == June || m == September || m == November)) { + assert((!month_day{m, day{d}}.ok())); + } else { + assert((month_day{m, day{d}}.ok())); + } + } + } + } +} + +constexpr void month_day_last_test() { + const month_day_last mdl{January}; + + static_assert(noexcept(month_day_last{month{}})); + static_assert(noexcept(mdl.month())); + static_assert(noexcept(mdl.ok())); + + static_assert(noexcept(mdl == mdl)); + static_assert(noexcept(mdl <=> mdl)); + + assert((February / last).month() == February); + + assert(!(month{0} / last).ok()); + for (unsigned int i = 1; i <= 12; ++i) { + assert((month{i} / last).ok()); + } + assert(!(month{13} / last).ok()); + + assert(January / last == January / last); + assert(January / last < February / last); + assert(December / last > February / last); +} + +constexpr void month_weekday_test() { + const auto mwd1 = January / Monday[2]; + + static_assert(noexcept(month_weekday{month{}, weekday_indexed{Sunday, 0u}})); + + static_assert(noexcept(mwd1.month())); + static_assert(noexcept(mwd1.weekday_indexed())); + static_assert(noexcept(mwd1.ok())); + + static_assert(noexcept(mwd1 == mwd1)); + + assert(mwd1.month() == January); + assert(mwd1.weekday_indexed().weekday() == Monday); + assert(mwd1.weekday_indexed().index() == 2); + + assert(January / Monday[2] == January / Monday[2]); + + if (is_constant_evaluated()) { + static_assert((January / Monday[1]).ok()); + static_assert((January / Monday[5]).ok()); + static_assert(!(January / Monday[6]).ok()); + static_assert(!(January / Monday[0]).ok()); + static_assert(!(month{0} / Monday[1]).ok()); + } else { + for (auto m = 0u; m <= 255u; ++m) { + for (auto wd = 0u; wd <= 255u; ++wd) { + for (auto wdi = 0u; wdi <= 6u; ++wdi) { + const auto mwd = month{m} / weekday{wd}[wdi]; + if (m >= 1 && m <= 12 && wd <= 7 && wdi >= 1 && wdi <= 5) { + assert(mwd.ok()); + } else { + assert(!mwd.ok()); + } + } + } + } + } +} + +constexpr void month_weekday_last_test() { + const auto mwdl = January / Monday[last]; + + static_assert(noexcept(month_weekday_last{month{}, weekday_last{Sunday}})); + static_assert(noexcept(mwdl.month())); + static_assert(noexcept(mwdl.weekday_last())); + static_assert(noexcept(mwdl.ok())); + + static_assert(noexcept(mwdl == mwdl)); + + assert(mwdl.month() == January); + assert(mwdl.weekday_last().weekday() == Monday); + assert(mwdl == January / Monday[last]); +} + +constexpr void year_month_test() { + auto ym = 2020y / January; + + static_assert(noexcept(year_month{})); + static_assert(noexcept(year_month{year{}, month{}})); + + static_assert(noexcept(ym.year())); + static_assert(noexcept(ym.month())); + + static_assert(noexcept(ym += months{})); + static_assert(noexcept(ym -= months{})); + static_assert(noexcept(ym += years{})); + static_assert(noexcept(ym -= years{})); + + static_assert(noexcept(ym.ok())); + + static_assert(noexcept(ym == ym)); + static_assert(noexcept(ym <=> ym)); + + static_assert(noexcept(ym + months{})); + static_assert(noexcept(months{} + ym)); + static_assert(noexcept(ym - months{})); + + static_assert(noexcept(ym - ym)); + static_assert(noexcept(ym + years{})); + static_assert(noexcept(years{} + ym)); + static_assert(noexcept(ym - years{})); + + assert(ym.year() == 2020y); + assert(ym.month() == January); + + ym += months{2}; + assert(ym.year() == 2020y); + assert(ym.month() == March); + ym -= months{2}; + assert(ym.year() == 2020y); + assert(ym.month() == January); + + ym += years{2}; + assert(ym.year() == 2022y); + assert(ym.month() == January); + ym -= years{2}; + assert(ym.year() == 2020y); + assert(ym.month() == January); + + ym += Decades{2}; + assert(ym.year() == 2040y); + assert(ym.month() == January); + ym -= Decades{2}; + assert(ym.year() == 2020y); + assert(ym.month() == January); + + assert(2020y / April == 2020y / April); + assert(2019y / April < 2020y / April); + assert(2020y / March < 2020y / April); + assert(2020y / April > 2019y / April); + assert(2020y / April > 2020y / March); + + assert(ym + months{2} == 2020y / March); + assert(months{2} + ym == 2020y / March); + + assert(ym - months{2} == 2019y / November); + assert(ym - 2019y / January == months{12}); + + assert(ym + years{2} == 2022y / January); + assert(years{2} + ym == 2022y / January); + + assert(ym - years{2} == 2018y / January); + + assert(ym + Decades{2} == 2040y / January); + assert(Decades{2} + ym == 2040y / January); + + assert(ym - Decades{2} == 2000y / January); + + if (is_constant_evaluated()) { + static_assert((2020y / 1).ok()); + static_assert(!(2020y / 13).ok()); + static_assert(!(32768y / 1).ok()); + } else { + for (int y = y_min - 1; y <= y_max + 1; ++y) { + for (auto m = 0u; m <= 255u; ++m) { + const auto ym2 = year{y} / month{m}; + if (y == y_min - 1 || y == y_max + 1) { + assert(!ym2.ok()); + } else if (m >= 1 && m <= 12) { + assert(ym2.ok()); + } else { + assert(!ym2.ok()); + } + } + } + } +} + +constexpr void year_month_day_test() { + year_month_day ymd1{2020y / January / 1d}; + + static_assert(noexcept(year_month_day{})); + static_assert(noexcept(year_month_day{year{}, month{}, day{}})); + static_assert(noexcept(year_month_day{year_month_day_last{year{}, month_day_last{January}}})); + static_assert(noexcept(year_month_day{sys_days{}})); + static_assert(noexcept(year_month_day{local_days{}})); + + static_assert(noexcept(ymd1 += months{})); + static_assert(noexcept(ymd1 -= months{})); + static_assert(noexcept(ymd1 += years{})); + static_assert(noexcept(ymd1 -= years{})); + + static_assert(noexcept(ymd1.year())); + static_assert(noexcept(ymd1.month())); + static_assert(noexcept(ymd1.day())); + + static_assert(noexcept(static_cast(ymd1))); + static_assert(noexcept(static_cast(ymd1))); + static_assert(noexcept(ymd1.ok())); + + static_assert(noexcept(ymd1 == ymd1)); + static_assert(noexcept(ymd1 <=> ymd1)); + + static_assert(noexcept(ymd1 + months{})); + static_assert(noexcept(months{} + ymd1)); + static_assert(noexcept(ymd1 - months{})); + + static_assert(noexcept(ymd1 + years{})); + static_assert(noexcept(years{} + ymd1)); + static_assert(noexcept(ymd1 - years{})); + + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + year_month_day ymd2{2020y / January / last}; + assert(ymd2.year() == 2020y); + assert(ymd2.month() == January); + assert(ymd2.day() == 31d); + + year_month_day epoch{sys_days{}}; + assert(epoch == year_month_day{sys_days{epoch}}); + assert(epoch.year() == 1970y); + assert(epoch.month() == January); + assert(epoch.day() == 1d); + + local_days ldp; + sys_days sys{ldp.time_since_epoch()}; + year_month_day ymld{ldp}; + assert(ymld == year_month_day{sys}); + + ymd1 += months{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == March); + assert(ymd1.day() == 1d); + + ymd1 -= months{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 += years{2}; + assert(ymd1.year() == 2022y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 -= years{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 += Decades{2}; + assert(ymd1.year() == 2040y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 -= Decades{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + assert(2020y / April / 6d == sys_days{days{18'358}}); + assert(sys_days{2017y / January / 0} == 2016y / December / 31); + assert(sys_days{2017y / January / 31} == 2017y / January / 31); + assert(sys_days{2017y / January / 32} == 2017y / February / 1); + + assert(static_cast(ymld) == local_days{}); + + assert(2020y / January / 1d == 2020y / January / 1d); + assert(2019y / January / 1d < 2020y / January / 1d); + assert(2020y / January / 1d < 2020y / February / 1d); + assert(2020y / January / 1d < 2020y / January / 2d); + assert(2020y / January / 1d > 2019y / January / 1d); + assert(2020y / February / 1d > 2020y / January / 1d); + assert(2020y / January / 2d > 2020y / January / 1d); + + const auto ymd3 = 2019y / December / 31d + months{2}; + assert(ymd3 == 2020y / February / 31d); + assert(!ymd3.ok()); + assert(months{2} + 2019y / December / 31d == ymd3); + + + assert(2020y / January / 1d - months{2} == 2019y / November / 1d); + + assert(2020y / January / 1d + years{2} == 2022y / January / 1d); + assert(years{2} + 2020y / January / 1d == 2022y / January / 1d); + + assert(2020y / January / 1d - years{2} == 2018y / January / 1d); + + assert(2020y / January / 1d + Decades{2} == 2040y / January / 1d); + assert(Decades{2} + 2020y / January / 1d == 2040y / January / 1d); + + assert(2020y / January / 1d - Decades{2} == 2000y / January / 1d); + + if (is_constant_evaluated()) { + static_assert(!(-32768y / 1 / 1).ok()); + static_assert(!(32768y / 1 / 1).ok()); + static_assert((2020y / 1 / 1).ok()); + + static_assert(!(2020y / 0 / 1).ok()); + static_assert(!(2020y / 13 / 1).ok()); + static_assert((2020y / 5 / 1).ok()); + + static_assert(!(2020y / 2 / 30).ok()); + static_assert(!(2019y / 2 / 29).ok()); + static_assert(!(2020y / 1 / 0).ok()); + static_assert(!(2020y / 1 / 32).ok()); + static_assert((2020y / 2 / 29).ok()); + static_assert((2020y / 7 / 31).ok()); + } else { + for (int iy = -3000; iy <= 3000; ++iy) { // instead of [y_min, y_max], to limit the number of iterations + for (auto um = 0u; um <= 13u; ++um) { // instead of [0, 255], to limit the number of iterations + for (auto ud = 0u; ud <= 32u; ++ud) { + const year y{iy}; + const month m{um}; + const day d{ud}; + if (y.ok() && m.ok() && d >= 1d && d <= (y / m / last).day()) { + assert((y / m / d).ok()); + } else { + assert(!(y / m / d).ok()); + } + } + } + } + } +} + +constexpr void year_month_day_last_test() { + auto ymdl = 2020y / February / last; + + static_assert(noexcept(year_month_day_last{year{}, month_day_last{January}})); + + static_assert(noexcept(ymdl += months{})); + static_assert(noexcept(ymdl -= months{})); + static_assert(noexcept(ymdl += years{})); + static_assert(noexcept(ymdl -= years{})); + + static_assert(noexcept(ymdl.year())); + static_assert(noexcept(ymdl.month())); + static_assert(noexcept(ymdl.month_day_last())); + static_assert(noexcept(ymdl.day())); + + static_assert(noexcept(static_cast(ymdl))); + static_assert(noexcept(static_cast(ymdl))); + static_assert(noexcept(ymdl.ok())); + + static_assert(noexcept(ymdl == ymdl)); + static_assert(noexcept(ymdl <=> ymdl)); + + static_assert(noexcept(ymdl + months{})); + static_assert(noexcept(months{} + ymdl)); + static_assert(noexcept(ymdl - months{})); + + static_assert(noexcept(ymdl + years{})); + static_assert(noexcept(years{} + ymdl)); + static_assert(noexcept(ymdl - years{})); + + assert(ymdl == 2020y / February / last); + assert(ymdl == 2020y / February / 29d); + assert(ymdl.year() == 2020y); + assert(ymdl.month() == February); + assert(ymdl.month_day_last() == February / last); + assert(ymdl.day() == 29d); + + ymdl += months{2}; + assert(ymdl == 2020y / April / 30d); + + ymdl -= months{2}; + assert(ymdl == 2020y / February / 29d); + + ymdl += years{2}; + assert(ymdl == 2022y / February / 28d); + + ymdl -= years{2}; + assert(ymdl == 2020y / February / 29d); + + ymdl += Decades{2}; + assert(ymdl == 2040y / February / 29d); + + ymdl -= Decades{2}; + assert(ymdl == 2020y / February / 29d); + + assert(2020y / April / last == sys_days{days{18'382}}); + assert(static_cast(ymdl) == local_days{ymdl}); + + assert(ymdl < 2021y / February / last); + assert(ymdl < 2020y / March / last); + assert(2021y / February / last > ymdl); + assert(2020y / March / last > ymdl); + + assert(ymdl + months{2} == 2020y / April / last); + assert(months{2} + ymdl == 2020y / April / last); + + assert(ymdl - months{2} == 2019y / December / last); + + assert(ymdl + years{2} == 2022y / February / last); + assert(years{2} + ymdl == 2022y / February / last); + + assert(ymdl - years{2} == 2018y / February / last); + + assert(ymdl + Decades{2} == 2040y / February / last); + assert(Decades{2} + ymdl == 2040y / February / last); + + assert(ymdl - Decades{2} == 2000y / February / last); + + if (is_constant_evaluated()) { + static_assert((2020y / 1 / last).ok()); + static_assert(!(2020y / 13 / last).ok()); + } else { + for (int iy = y_min; iy <= y_max; ++iy) { + for (auto m = 0u; m <= 255u; ++m) { + const year y{iy}; + const auto mdl = month{m} / last; + if (y.ok() && mdl.ok()) { + assert((y / mdl).ok()); + } else { + assert(!(y / mdl).ok()); + } + } + } + } +} + +constexpr void year_month_weekday_test() { + auto ymwd = 2020y / April / Tuesday[2]; + + static_assert(noexcept(year_month_weekday{})); + static_assert(noexcept(year_month_weekday{year{}, month{}, weekday_indexed{}})); + static_assert(noexcept(year_month_weekday{sys_days{}})); + static_assert(noexcept(year_month_weekday{local_days{}})); + + static_assert(noexcept(ymwd += months{})); + static_assert(noexcept(ymwd -= months{})); + static_assert(noexcept(ymwd += years{})); + static_assert(noexcept(ymwd -= years{})); + + static_assert(noexcept(ymwd.year())); + static_assert(noexcept(ymwd.month())); + static_assert(noexcept(ymwd.weekday())); + static_assert(noexcept(ymwd.index())); + static_assert(noexcept(ymwd.weekday_indexed())); + + static_assert(noexcept(static_cast(ymwd))); + static_assert(noexcept(static_cast(ymwd))); + static_assert(noexcept(ymwd.ok())); + + static_assert(noexcept(ymwd == ymwd)); + + static_assert(noexcept(ymwd + months{})); + static_assert(noexcept(months{} + ymwd)); + static_assert(noexcept(ymwd - months{})); + + static_assert(noexcept(ymwd + years{})); + static_assert(noexcept(years{} + ymwd)); + static_assert(noexcept(ymwd - years{})); + + assert(ymwd == 2020y / April / Tuesday[2]); + assert(ymwd.year() == 2020y); + assert(ymwd.month() == April); + assert(ymwd.weekday() == Tuesday); + assert(ymwd.index() == 2u); + assert(ymwd.weekday_indexed() == Tuesday[2]); + + const year_month_weekday epoch{sys_days{}}; + assert(epoch == year_month_weekday{sys_days{epoch}}); + assert(epoch == 1970y / January / Thursday[1]); + + local_days ldp; + sys_days sys{ldp.time_since_epoch()}; + year_month_weekday ymlwd{ldp}; + assert(ymlwd == year_month_weekday{sys}); + + ymwd += months{2}; + assert(ymwd == 2020y / June / Tuesday[2]); + ymwd -= months{2}; + assert(ymwd == 2020y / April / Tuesday[2]); + + ymwd += years{2}; + assert(ymwd == 2022y / April / Tuesday[2]); + ymwd -= years{2}; + assert(ymwd == 2020y / April / Tuesday[2]); + + ymwd += Decades{2}; + assert(ymwd == 2040y / April / Tuesday[2]); + ymwd -= Decades{2}; + assert(ymwd == 2020y / April / Tuesday[2]); + + assert(static_cast(epoch) == sys_days{}); + const auto previous = 1970y / January / Thursday[0]; + assert(static_cast(previous) == (sys_days{} - days{7})); + assert(static_cast(ymwd) == local_days{ymwd}); + + + assert((2020y / April / Wednesday[5]).ok()); + assert(!(-32768y / April / Wednesday[1]).ok()); + assert(!(2020y / month{0} / Wednesday[1]).ok()); + assert(!(2020y / April / Tuesday[5]).ok()); + + assert(ymwd + months{2} == 2020y / June / Tuesday[2]); + assert(months{2} + ymwd == 2020y / June / Tuesday[2]); + + assert(ymwd - months{2} == 2020y / February / Tuesday[2]); + + assert(ymwd + years{2} == 2022y / April / Tuesday[2]); + assert(years{2} + ymwd == 2022y / April / Tuesday[2]); + + assert(ymwd - years{2} == 2018y / April / Tuesday[2]); + + assert(ymwd + Decades{2} == 2040y / April / Tuesday[2]); + assert(Decades{2} + ymwd == 2040y / April / Tuesday[2]); + + assert(ymwd - Decades{2} == 2000y / April / Tuesday[2]); +} + +constexpr void year_month_weekday_last_test() { + auto ymwdl = 2020y / January / Monday[last]; + + static_assert(noexcept(year_month_weekday_last{year{}, month{}, weekday_last{Sunday}})); + + static_assert(noexcept(ymwdl += months{})); + static_assert(noexcept(ymwdl -= months{})); + static_assert(noexcept(ymwdl += years{})); + static_assert(noexcept(ymwdl -= years{})); + + static_assert(noexcept(ymwdl.year())); + static_assert(noexcept(ymwdl.month())); + static_assert(noexcept(ymwdl.weekday())); + static_assert(noexcept(ymwdl.weekday_last())); + + static_assert(noexcept(static_cast(ymwdl))); + static_assert(noexcept(static_cast(ymwdl))); + static_assert(noexcept(ymwdl.ok())); + + static_assert(noexcept(ymwdl == ymwdl)); + + static_assert(noexcept(ymwdl + months{})); + static_assert(noexcept(months{} + ymwdl)); + static_assert(noexcept(ymwdl - months{})); + + static_assert(noexcept(ymwdl + years{})); + static_assert(noexcept(years{} + ymwdl)); + static_assert(noexcept(ymwdl - years{})); + + assert(ymwdl == 2020y / January / Monday[last]); + assert(ymwdl.year() == 2020y); + assert(ymwdl.month() == January); + assert(ymwdl.weekday() == Monday); + assert(ymwdl.weekday_last() == Monday[last]); + + ymwdl += months{2}; + assert(ymwdl == 2020y / March / Monday[last]); + ymwdl -= months{2}; + assert(ymwdl == 2020y / January / Monday[last]); + + ymwdl += years{2}; + assert(ymwdl == 2022y / January / Monday[last]); + ymwdl -= years{2}; + assert(ymwdl == 2020y / January / Monday[last]); + + ymwdl += Decades{2}; + assert(ymwdl == 2040y / January / Monday[last]); + ymwdl -= Decades{2}; + assert(ymwdl == 2020y / January / Monday[last]); + + assert(static_cast(ymwdl) == sys_days{days{18'288}}); + assert(static_cast(ymwdl) == local_days{ymwdl}); + + assert((2020y / April / Wednesday[last]).ok()); + assert(!(-32768y / April / Wednesday[last]).ok()); + assert(!(2020y / month{0} / Wednesday[last]).ok()); + assert(!(2020y / April / weekday{8}[last]).ok()); + + assert(ymwdl + months{2} == 2020y / March / Monday[last]); + assert(months{2} + ymwdl == 2020y / March / Monday[last]); + + assert(ymwdl - months{2} == 2019y / November / Monday[last]); + + assert(ymwdl + years{2} == 2022y / January / Monday[last]); + assert(years{2} + ymwdl == 2022y / January / Monday[last]); + + assert(ymwdl - years{2} == 2018y / January / Monday[last]); + + assert(ymwdl + Decades{2} == 2040y / January / Monday[last]); + assert(Decades{2} + ymwdl == 2040y / January / Monday[last]); + + assert(ymwdl - Decades{2} == 2000y / January / Monday[last]); +} + +constexpr bool test() { + day_test(); + month_test(); + year_test(); + weekday_test(); + weekday_indexed_test(); + weekday_last_test(); + month_day_test(); + month_day_last_test(); + month_weekday_test(); + month_weekday_last_test(); + year_month_test(); + year_month_day_test(); + year_month_day_last_test(); + year_month_weekday_test(); + year_month_weekday_last_test(); + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/test.compile.pass.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/test.compile.pass.cpp new file mode 100644 index 00000000000..f0512320f08 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/test.compile.pass.cpp @@ -0,0 +1,186 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +using namespace std; +using namespace std::chrono; + +int main() {} // COMPILE-ONLY + +static_assert(noexcept(year{} / month{})); +static_assert(noexcept(year{} / 0)); +static_assert(noexcept(month{} / day{})); +static_assert(noexcept(month{} / 0)); +static_assert(noexcept(0 / day{})); +static_assert(noexcept(day{} / month{})); +static_assert(noexcept(day{} / 0)); +static_assert(noexcept(month{} / last)); +static_assert(noexcept(0 / last)); +static_assert(noexcept(last / month{})); +static_assert(noexcept(last / 0)); +static_assert(noexcept(month{} / Sunday[1])); +static_assert(noexcept(0 / Sunday[1])); +static_assert(noexcept(Sunday[1] / month{})); +static_assert(noexcept(Sunday[1] / 0)); +static_assert(noexcept(month{} / Sunday[last])); +static_assert(noexcept(0 / Sunday[last])); +static_assert(noexcept(Sunday[last] / month{})); +static_assert(noexcept(Sunday[last] / 0)); +static_assert(noexcept(year_month{} / day{})); +static_assert(noexcept(year_month{} / 0)); +static_assert(noexcept(year{} / month_day{})); +static_assert(noexcept(0 / month_day{})); +static_assert(noexcept(month_day{} / year{})); +static_assert(noexcept(month_day{} / 0)); +static_assert(noexcept(year_month{} / last)); +static_assert(noexcept(year{} / month_day_last{January})); +static_assert(noexcept(0 / month_day_last{January})); +static_assert(noexcept(month_day_last{January} / year{})); +static_assert(noexcept(month_day_last{January} / 0)); +static_assert(noexcept(year_month{} / Sunday[1])); +static_assert(noexcept(year{} / month_weekday{January, Sunday[1]})); +static_assert(noexcept(0 / month_weekday{January, Sunday[1]})); +static_assert(noexcept(month_weekday{January, Sunday[1]} / year{})); +static_assert(noexcept(month_weekday{January, Sunday[1]} / 0)); +static_assert(noexcept(year_month{} / Sunday[last])); +static_assert(noexcept(year{} / month_weekday_last{January, Sunday[last]})); +static_assert(noexcept(0 / month_weekday_last{January, Sunday[last]})); +static_assert(noexcept(month_weekday_last{January, Sunday[last]} / year{})); +static_assert(noexcept(month_weekday_last{January, Sunday[last]} / 0)); + +#define TRIVIAL_COPY_STANDARD_LAYOUT(TYPE) \ + static_assert(is_trivially_copyable_v, "chrono::" #TYPE " is not trivially copyable"); \ + static_assert(is_standard_layout_v, "chrono::" #TYPE " is not standard-layout"); + +TRIVIAL_COPY_STANDARD_LAYOUT(day) +TRIVIAL_COPY_STANDARD_LAYOUT(month) +TRIVIAL_COPY_STANDARD_LAYOUT(year) +TRIVIAL_COPY_STANDARD_LAYOUT(weekday) +TRIVIAL_COPY_STANDARD_LAYOUT(weekday_indexed) +TRIVIAL_COPY_STANDARD_LAYOUT(weekday_last) +TRIVIAL_COPY_STANDARD_LAYOUT(month_day) +TRIVIAL_COPY_STANDARD_LAYOUT(month_day_last) +TRIVIAL_COPY_STANDARD_LAYOUT(month_weekday) +TRIVIAL_COPY_STANDARD_LAYOUT(month_weekday_last) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_day) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_day_last) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_weekday) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_weekday_last) + +#define TYPE_ASSERT(TYPE, EXPR) \ + static_assert(is_same_v>, #EXPR " is not chrono::" #TYPE); + +TYPE_ASSERT(day, 0d) +TYPE_ASSERT(year, 0y) +TYPE_ASSERT(month, January) +TYPE_ASSERT(month, February) +TYPE_ASSERT(month, March) +TYPE_ASSERT(month, April) +TYPE_ASSERT(month, May) +TYPE_ASSERT(month, June) +TYPE_ASSERT(month, July) +TYPE_ASSERT(month, August) +TYPE_ASSERT(month, September) +TYPE_ASSERT(month, October) +TYPE_ASSERT(month, November) +TYPE_ASSERT(month, December) +TYPE_ASSERT(weekday, Sunday) +TYPE_ASSERT(weekday, Monday) +TYPE_ASSERT(weekday, Tuesday) +TYPE_ASSERT(weekday, Wednesday) +TYPE_ASSERT(weekday, Thursday) +TYPE_ASSERT(weekday, Friday) +TYPE_ASSERT(weekday, Saturday) +TYPE_ASSERT(last_spec, last) +TYPE_ASSERT(weekday_indexed, declval()[1]) +TYPE_ASSERT(weekday_last, declval()[last]) + +TYPE_ASSERT(year_month, 2020y / January) +TYPE_ASSERT(year_month, 2020y / 1) + +TYPE_ASSERT(month_day, January / 1d) +TYPE_ASSERT(month_day, January / 1) +TYPE_ASSERT(month_day, 1 / 1d) +TYPE_ASSERT(month_day, 1d / January) +TYPE_ASSERT(month_day, 1d / 1) + +TYPE_ASSERT(month_day_last, January / last) +TYPE_ASSERT(month_day_last, 1 / last) +TYPE_ASSERT(month_day_last, last / January) +TYPE_ASSERT(month_day_last, last / 1) + +TYPE_ASSERT(month_weekday, January / Monday[1]) +TYPE_ASSERT(month_weekday, 1 / Monday[1]) +TYPE_ASSERT(month_weekday, Monday[1] / January) +TYPE_ASSERT(month_weekday, Monday[1] / 1) + +TYPE_ASSERT(month_weekday_last, January / Monday[last]) +TYPE_ASSERT(month_weekday_last, 1 / Monday[last]) +TYPE_ASSERT(month_weekday_last, Monday[last] / January) +TYPE_ASSERT(month_weekday_last, Monday[last] / 1) + +TYPE_ASSERT(year_month_day, 2020y / January / 1d) +TYPE_ASSERT(year_month_day, 2020y / January / 1) +constexpr auto md = January / 1; +TYPE_ASSERT(year_month_day, 2020y / md) +TYPE_ASSERT(year_month_day, 2020 / md) +TYPE_ASSERT(year_month_day, January / 1 / 2020y) +TYPE_ASSERT(year_month_day, January / 1 / 2020) +TYPE_ASSERT(year_month_day, 1d / January / 2020y) +TYPE_ASSERT(year_month_day, 1d / January / 2020) +TYPE_ASSERT(year_month_day, 1d / 1 / 2020) +TYPE_ASSERT(year_month_day, 1d / 1 / 2020y) + +TYPE_ASSERT(year_month_day_last, 2020y / January / last) +constexpr auto mdl = January / last; +TYPE_ASSERT(year_month_day_last, 2020y / mdl) +TYPE_ASSERT(year_month_day_last, 2020 / mdl) +TYPE_ASSERT(year_month_day_last, last / January / 2020y) +TYPE_ASSERT(year_month_day_last, January / last / 2020) + +TYPE_ASSERT(year_month_weekday, 2020y / January / Monday[1]) +constexpr auto mwd = January / Monday[1]; +TYPE_ASSERT(year_month_weekday, 2020y / mwd) +TYPE_ASSERT(year_month_weekday, 2020 / mwd) +TYPE_ASSERT(year_month_weekday, January / Monday[1] / 2020y) +TYPE_ASSERT(year_month_weekday, January / Monday[1] / 2020) +TYPE_ASSERT(year_month_weekday, Monday[1] / January / 2020y) +TYPE_ASSERT(year_month_weekday, Monday[1] / January / 2020) + +TYPE_ASSERT(year_month_weekday_last, 2020y / January / Monday[last]) +constexpr auto mwdl = January / Monday[last]; +TYPE_ASSERT(year_month_weekday_last, 2020y / mwdl) +TYPE_ASSERT(year_month_weekday_last, 2020 / mwdl) +TYPE_ASSERT(year_month_weekday_last, January / Monday[last] / 2020y) +TYPE_ASSERT(year_month_weekday_last, January / Monday[last] / 2020) +TYPE_ASSERT(year_month_weekday_last, 1 / Monday[last] / 2020) +TYPE_ASSERT(year_month_weekday_last, 1 / Monday[last] / 2020y) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / 1 / 2020y) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / 1 / 2020) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / January / 2020) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / January / 2020y) + +#define VALUE_ASSERT(VALUE, EXPECTED) static_assert(VALUE == EXPECTED, "chrono::" #VALUE " is not " #EXPECTED); +VALUE_ASSERT(month{1}, January) +VALUE_ASSERT(month{2}, February) +VALUE_ASSERT(month{3}, March) +VALUE_ASSERT(month{4}, April) +VALUE_ASSERT(month{5}, May) +VALUE_ASSERT(month{6}, June) +VALUE_ASSERT(month{7}, July) +VALUE_ASSERT(month{8}, August) +VALUE_ASSERT(month{9}, September) +VALUE_ASSERT(month{10}, October) +VALUE_ASSERT(month{11}, November) +VALUE_ASSERT(month{12}, December) + +VALUE_ASSERT(weekday{0}, Sunday) +VALUE_ASSERT(weekday{1}, Monday) +VALUE_ASSERT(weekday{2}, Tuesday) +VALUE_ASSERT(weekday{3}, Wednesday) +VALUE_ASSERT(weekday{4}, Thursday) +VALUE_ASSERT(weekday{5}, Friday) +VALUE_ASSERT(weekday{6}, Saturday) diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_hms/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_hms/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/test.cpp new file mode 100644 index 00000000000..05d0320e311 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/test.cpp @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +using hms_hours = hh_mm_ss; +using f_hours = duration>; +using f_hms_hours = hh_mm_ss; + +constexpr void am_pm() { + static_assert(noexcept(is_am(hours{}))); + static_assert(noexcept(is_pm(hours{}))); + + for (hours i = 0h; i < 12h; ++i) { + assert(is_am(i)); + assert(!is_pm(i)); + } + for (hours i = 12h; i < 24h; ++i) { + assert(!is_am(i)); + assert(is_pm(i)); + } +} + +constexpr void make12_24() { + static_assert(noexcept(make12(hours{}))); + static_assert(noexcept(make24(hours{}, true))); + + assert(make12(1h) == 1h); + assert(make12(13h) == 1h); + assert(make12(0h) == 12h); + assert(make12(12h) == 12h); + + assert(make24(12h, true) == 12h); + assert(make24(12h, false) == 0h); + assert(make24(5h, true) == 17h); + assert(make24(5h, false) == 5h); +} + +template +constexpr auto width() { + return hh_mm_ss::fractional_width; +} +template +constexpr auto width() { + return hh_mm_ss>>::fractional_width; +} + +constexpr void fractional_width() { + static_assert(width() == 0); + static_assert(width() == 0); + static_assert(width() == 0); + static_assert(width() == 0); + static_assert(width() == 3); + static_assert(width() == 6); + static_assert(width() == 9); + + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 2); + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 6); + static_assert(width() == 3); + static_assert(width() == 6); + static_assert(width() == 1); + static_assert(width() == 4); + static_assert(width() == 3); + static_assert(width() == 6); + // static_assert(width() == 6); overflows + + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 2); + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 6); + static_assert(width() == 3); + static_assert(width() == 6); + static_assert(width() == 1); + static_assert(width() == 4); + static_assert(width() == 3); + static_assert(width() == 6); + // static_assert(width() == 6); overflows +} + +constexpr void constructor() { + static_assert(noexcept(hms_hours{})); + static_assert(noexcept(f_hms_hours{})); + + assert(hms_hours{}.hours() == hms_hours{hours::zero()}.hours()); + assert(hms_hours{}.minutes() == hms_hours{hours::zero()}.minutes()); + assert(hms_hours{}.seconds() == hms_hours{hours::zero()}.seconds()); + assert(hms_hours{}.subseconds() == hms_hours{hours::zero()}.subseconds()); + + assert(f_hms_hours{}.hours() == f_hms_hours{hours::zero()}.hours()); + assert(f_hms_hours{}.minutes() == f_hms_hours{hours::zero()}.minutes()); + assert(f_hms_hours{}.seconds() == f_hms_hours{hours::zero()}.seconds()); + assert(f_hms_hours{}.subseconds() == f_hms_hours{hours::zero()}.subseconds()); +} + +constexpr void is_negative() { + static_assert(noexcept(hms_hours{}.is_negative())); + static_assert(noexcept(f_hms_hours{}.is_negative())); + + assert(hh_mm_ss(days{-1}).is_negative()); + assert(!hh_mm_ss(days{1}).is_negative()); + + assert(hh_mm_ss{-1h}.is_negative()); + assert(!hh_mm_ss{1h}.is_negative()); + + assert(hh_mm_ss{-1min}.is_negative()); + assert(!hh_mm_ss{1min}.is_negative()); + + assert(hh_mm_ss{-1s}.is_negative()); + assert(!hh_mm_ss{1s}.is_negative()); + + assert(hh_mm_ss{-1ms}.is_negative()); + assert(!hh_mm_ss{1ms}.is_negative()); + + assert(hh_mm_ss{-1us}.is_negative()); + assert(!hh_mm_ss{1us}.is_negative()); + + assert(hh_mm_ss{-1ns}.is_negative()); + assert(!hh_mm_ss{1ns}.is_negative()); + + assert(f_hms_hours{f_hours{-1.f}}.is_negative()); + assert(!f_hms_hours{f_hours{1.f}}.is_negative()); +} + +constexpr auto ones = 1h + 1min + 1s + 1ms; + +constexpr void hour() { + static_assert(noexcept(hms_hours{}.hours())); + static_assert(noexcept(f_hms_hours{}.hours())); + + assert(hh_mm_ss(days{1}).hours() == 24h); + assert(hh_mm_ss(ones).hours() == 1h); + assert(hh_mm_ss(-ones).hours() == 1h); + assert(hh_mm_ss(59min).hours() == 0h); + assert(f_hms_hours{f_hours{1.f}}.hours() == 1h); +} + +constexpr void mins() { + static_assert(noexcept(hms_hours{}.minutes())); + static_assert(noexcept(f_hms_hours{}.minutes())); + + assert(hh_mm_ss(ones).minutes() == 1min); + assert(hh_mm_ss(-ones).minutes() == 1min); + assert(hh_mm_ss(59s).minutes() == 0min); + assert(f_hms_hours{f_hours{0.0166667f}}.minutes() == 1min); +} + +constexpr void secs() { + static_assert(noexcept(hms_hours{}.seconds())); + static_assert(noexcept(f_hms_hours{}.seconds())); + + assert(hh_mm_ss(ones).seconds() == 1s); + assert(hh_mm_ss(-ones).seconds() == 1s); + assert(hh_mm_ss(999ms).seconds() == 0s); + assert(f_hms_hours{f_hours{0.000277778f}}.seconds() == 1s); +} + +constexpr void subsecs() { + static_assert(noexcept(hms_hours{}.subseconds())); + static_assert(noexcept(f_hms_hours{}.subseconds())); + + assert(hh_mm_ss(ones).subseconds() == 1ms); + assert(hh_mm_ss(-ones).subseconds() == 1ms); + assert(hh_mm_ss(999us).subseconds() == 999us); + assert(hh_mm_ss(duration_cast(999us)).subseconds() == 0ms); + using f_hms_milli = hh_mm_ss>; + assert(f_hms_milli{1ms}.subseconds() == 1ms); +} + +constexpr void to_duration() { + using precision = hms_hours::precision; + using f_precision = f_hms_hours::precision; + + static_assert(noexcept(hms_hours{}.to_duration())); + static_assert(noexcept(static_cast(hms_hours{}))); + static_assert(noexcept(f_hms_hours{}.to_duration())); + static_assert(noexcept(static_cast(f_hms_hours{}))); + + assert(hh_mm_ss(ones).to_duration() == ones); + assert(hh_mm_ss(-ones).to_duration() == -ones); + assert(f_hms_hours{f_hours{1.f}}.to_duration() == 1h); + assert(f_hms_hours{f_hours{-1.f}}.to_duration() == -1h); + + hh_mm_ss hms(50ms); + milliseconds milli_val = static_cast(hms); + static_assert(is_same_v); + assert(hms.to_duration() == milli_val); + + f_hms_hours fhms{f_hours{1}}; + auto fhours_val = static_cast(fhms); + static_assert(is_same_v); + static_assert(is_same_v, f_precision>); + assert(fhms.to_duration() == fhours_val); +} + +constexpr bool test() { + am_pm(); + make12_24(); + fractional_width(); + constructor(); + is_negative(); + hour(); + mins(); + secs(); + subsecs(); + to_duration(); + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/test.cpp new file mode 100644 index 00000000000..66bec4ea7da --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/test.cpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +#define DURATION_TEST(TYPE, BITS, ...) \ + static_assert( \ + is_integral_v && is_signed_v, "chrono::" #TYPE "::rep is not a signed integral type."); \ + static_assert( \ + numeric_limits::digits >= BITS, "chrono::" #TYPE "::rep is not at least " #BITS " bits."); \ + static_assert(is_same_v, "chrono::" #TYPE "::period is not " #__VA_ARGS__ "."); + +DURATION_TEST(days, 25, ratio_multiply, hours::period>) +DURATION_TEST(weeks, 22, ratio_multiply, days::period>) +DURATION_TEST(months, 20, ratio_divide>) +DURATION_TEST(years, 17, ratio_multiply, days::period>) + +// clang-format off +static_assert(is_same_v>, + "sys_seconds is not time_point."); +static_assert(is_same_v>, + "sys_days is not time_point."); + +static_assert(is_same_v>, + "local_seconds is not time_point."); +static_assert(is_same_v>, + "local_days is not time_point."); +// clang-format on + +constexpr bool test() { + steady_clock::time_point tp1; + + static_assert(noexcept(++tp1)); // strengthened + static_assert(noexcept(tp1++)); // strengthened + static_assert(noexcept(--tp1)); // strengthened + static_assert(noexcept(tp1--)); // strengthened + + auto tp2 = tp1++; + assert(tp1.time_since_epoch().count() == 1); + assert(tp2.time_since_epoch().count() == 0); + tp2 = ++tp1; + assert(tp1.time_since_epoch().count() == 2); + assert(tp2.time_since_epoch().count() == 2); + + tp2 = tp1--; + assert(tp1.time_since_epoch().count() == 1); + assert(tp2.time_since_epoch().count() == 2); + tp2 = --tp1; + assert(tp1.time_since_epoch().count() == 0); + assert(tp2.time_since_epoch().count() == 0); + + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp index d660f96e77b..1fa579ad294 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp +++ b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp @@ -324,9 +324,13 @@ int main() { puts("Testing ."); promise p{}; future f{p.get_future()}; +#if 0 // TRANSITION, VSO-1271718 (Standard Library Header Units ICE with C++20 chrono) assert(f.wait_for(chrono::seconds{0}) == future_status::timeout); +#endif // ^^^ no workaround ^^^ p.set_value(1729); +#if 0 // TRANSITION, VSO-1271718 (Standard Library Header Units ICE with C++20 chrono) assert(f.wait_for(chrono::seconds{0}) == future_status::ready); +#endif // ^^^ no workaround ^^^ assert(f.get() == 1729); } @@ -756,7 +760,9 @@ int main() { } l.count_down(); // tell main() that we're done while (!token.stop_requested()) { +#if 0 // TRANSITION, VSO-1271718 (Standard Library Header Units ICE with C++20 chrono) this_thread::sleep_for(10ms); // not a timing assumption; avoids spinning furiously +#endif // ^^^ no workaround ^^^ } vec.push_back(-1000); // indicate that token.stop_requested() returned true }};