From 1043b11ecbb82ad559013cee255ac56256d9d330 Mon Sep 17 00:00:00 2001 From: statementreply Date: Fri, 19 Feb 2021 09:47:24 +0800 Subject: [PATCH] P1614R2 Spaceship: Clause 27: Time (partial, pre-C++20 types) (#1602) Co-authored-by: Stephan T. Lavavej --- stl/inc/chrono | 29 +++ tests/std/test.lst | 1 + tests/std/tests/P1614R2_spaceship/env.lst | 7 + tests/std/tests/P1614R2_spaceship/test.cpp | 262 +++++++++++++++++++++ 4 files changed, 299 insertions(+) create mode 100644 tests/std/tests/P1614R2_spaceship/env.lst create mode 100644 tests/std/tests/P1614R2_spaceship/test.cpp diff --git a/stl/inc/chrono b/stl/inc/chrono index 25d3b2ac19..c664419e17 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -17,6 +17,9 @@ #if _HAS_CXX20 #include +#ifdef __cpp_lib_concepts +#include +#endif // defined(__cpp_lib_concepts) #endif // _HAS_CXX20 #pragma pack(push, _CRT_PACKING) @@ -370,12 +373,14 @@ namespace chrono { return _CT(_Left).count() == _CT(_Right).count(); } +#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { return !(_Left == _Right); } +#endif // !_HAS_CXX20 template _NODISCARD constexpr bool @@ -406,6 +411,19 @@ namespace chrono { return !(_Left < _Right); } +#ifdef __cpp_lib_concepts + // clang-format off + template + requires three_way_comparable, duration<_Rep2, _Period2>>::rep> + _NODISCARD constexpr auto + operator<=>(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( + is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { + // clang-format on + using _CT = common_type_t, duration<_Rep2, _Period2>>; + return _CT(_Left).count() <=> _CT(_Right).count(); + } +#endif // defined(__cpp_lib_concepts) + // FUNCTION TEMPLATE duration_cast template , int> _Enabled> _NODISCARD constexpr _To duration_cast(const duration<_Rep, _Period>& _Dur) noexcept( @@ -550,12 +568,14 @@ namespace chrono { return _Left.time_since_epoch() == _Right.time_since_epoch(); } +#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return !(_Left == _Right); } +#endif // !_HAS_CXX20 template _NODISCARD constexpr bool @@ -585,6 +605,15 @@ namespace chrono { return !(_Left < _Right); } +#ifdef __cpp_lib_concepts + template _Duration2> + _NODISCARD constexpr auto + operator<=>(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( + is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { + return _Left.time_since_epoch() <=> _Right.time_since_epoch(); + } +#endif // defined(__cpp_lib_concepts) + // FUNCTION TEMPLATE time_point_cast template , int> = 0> _NODISCARD constexpr time_point<_Clock, _To> time_point_cast(const time_point<_Clock, _Duration>& _Time) noexcept( diff --git a/tests/std/test.lst b/tests/std/test.lst index a403bb4532..f1088e709a 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -398,6 +398,7 @@ tests\P1135R6_semaphore tests\P1165R1_consistently_propagating_stateful_allocators tests\P1423R3_char8_t_remediation tests\P1502R1_standard_library_header_units +tests\P1614R2_spaceship tests\P1645R1_constexpr_numeric tests\VSO_0000000_allocator_propagation tests\VSO_0000000_any_calling_conventions diff --git a/tests/std/tests/P1614R2_spaceship/env.lst b/tests/std/tests/P1614R2_spaceship/env.lst new file mode 100644 index 0000000000..20ea5fe342 --- /dev/null +++ b/tests/std/tests/P1614R2_spaceship/env.lst @@ -0,0 +1,7 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst +RUNALL_CROSSLIST +PM_CL="/D_STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS=0" +PM_CL="/D_STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS=1" diff --git a/tests/std/tests/P1614R2_spaceship/test.cpp b/tests/std/tests/P1614R2_spaceship/test.cpp new file mode 100644 index 0000000000..37fb868db7 --- /dev/null +++ b/tests/std/tests/P1614R2_spaceship/test.cpp @@ -0,0 +1,262 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Covers: +// * spaceship for containers + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +using SpaceshipType = decltype(std::declval() <=> std::declval()); + +template +concept HasSpaceshipWith = requires { + std::declval() <=> std::declval(); +}; + +using PartiallyOrdered = double; + +struct WeaklyOrdered { + [[nodiscard]] constexpr bool operator==(const WeaklyOrdered&) const { + return true; + } + + [[nodiscard]] constexpr std::weak_ordering operator<=>(const WeaklyOrdered&) const { + return std::weak_ordering::equivalent; + } +}; + +using StronglyOrdered = int; + +// Activates synth-three-way in N4861 16.4.2.1 [expos.only.func]/2. +struct SynthOrdered { + int val; + + constexpr SynthOrdered(const int x) : val{x} {} + + [[nodiscard]] constexpr bool operator==(const SynthOrdered& other) const { + return val == other.val; + } + + [[nodiscard]] constexpr bool operator<(const SynthOrdered& other) const { + return val < other.val; + } +}; + +struct OrderedChar { + OrderedChar() = default; + OrderedChar(const char other) : c(other) {} + + OrderedChar& operator=(const char& other) { + c = other; + return *this; + } + + auto operator<=>(const OrderedChar&) const = default; + + operator char() const { + return c; + } + + char c; +}; + +struct WeaklyOrderedChar : OrderedChar {}; +struct WeaklyOrderedByOmissionChar : OrderedChar {}; +struct PartiallyOrderedChar : OrderedChar {}; + +namespace std { + template <> + struct char_traits : char_traits { + using char_type = OrderedChar; + + static int compare(const char_type* first1, const char_type* first2, size_t count) { + for (; 0 < count; --count, ++first1, ++first2) { + if (*first1 != *first2) { + return *first1 < *first2 ? -1 : +1; + } + } + + return 0; + } + + static bool eq(const char_type l, const char_type r) { + return l.c == r.c; + } + }; + + template <> + struct char_traits : char_traits { + using char_type = WeaklyOrderedChar; + using comparison_category = weak_ordering; + }; + + template <> + struct char_traits : char_traits { + using char_type = WeaklyOrderedByOmissionChar; + + private: + using comparison_category = strong_ordering; + }; + + template <> + struct char_traits : char_traits { + using char_type = PartiallyOrderedChar; + using comparison_category = partial_ordering; + }; +} // namespace std + +struct dummy_diagnostic : std::error_category { + const char* name() const noexcept override { + return "dummy"; + } + std::string message(int) const override { + return ""; + } +}; + +template +void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) { + assert(smaller == smaller_equal); + assert(smaller_equal == smaller); + assert(smaller != larger); + assert(larger != smaller); + assert(smaller < larger); + assert(!(larger < smaller)); + assert(larger > smaller); + assert(!(smaller > larger)); + assert(smaller <= larger); + assert(!(larger <= smaller)); + assert(larger >= smaller); + assert(!(smaller >= larger)); + assert((smaller <=> larger) < 0); + assert((larger <=> smaller) > 0); + assert((smaller <=> smaller_equal) == 0); + + static_assert(std::is_same_v larger), ReturnType>); +} + +template +inline constexpr bool is_pair = false; +template +inline constexpr bool is_pair> = true; // TRANSITION, std::pair spaceship not yet implemented + +template +void ordered_containers_test(const Container& smaller, const Container& smaller_equal, const Container& larger) { + using Elem = typename Container::value_type; + if constexpr (is_pair // TRANSITION, std::pair spaceship not yet implemented + || std::is_same_v) { + spaceship_test(smaller, smaller_equal, larger); + } else { + spaceship_test(smaller, smaller_equal, larger); + } +} + +template +void unordered_containers_test( + const Container& something, const Container& something_equal, const Container& different) { + assert(something == something_equal); + assert(something != different); +} + +template +void diagnostics_test() { + dummy_diagnostic c_mem[2]; + { + ErrorType e_smaller(0, c_mem[0]); + ErrorType e_equal(0, c_mem[0]); + ErrorType e_larger(1, c_mem[1]); + + spaceship_test(e_smaller, e_equal, e_larger); + } + { + ErrorType e_smaller(0, c_mem[0]); + ErrorType e_larger(0, c_mem[1]); + + assert(e_smaller < e_larger); + assert(!(e_larger < e_smaller)); + assert((e_smaller <=> e_larger) < 0); + assert((e_larger <=> e_smaller) > 0); + } + { + ErrorType e_smaller(0, c_mem[0]); + ErrorType e_larger(1, c_mem[0]); + + assert(e_smaller < e_larger); + assert(!(e_larger < e_smaller)); + assert((e_smaller <=> e_larger) < 0); + assert((e_larger <=> e_smaller) > 0); + } +} + +void ordering_test_cases() { + { // chrono::duration + using std::chrono::hours; + using std::chrono::minutes; + using std::chrono::seconds; + + spaceship_test(seconds{1}, seconds{1}, seconds{2}); + spaceship_test(seconds{3600}, hours{1}, minutes{61}); + + using double_seconds = std::chrono::duration; + using float_milliseconds = std::chrono::duration; + using ntsc_fields = std::chrono::duration>; + + spaceship_test(double_seconds{1}, float_milliseconds{1000}, ntsc_fields{60}); + + constexpr double_seconds nan_s{std::numeric_limits::quiet_NaN()}; +#ifdef __clang__ // TRANSITION, DevCom-445462 + static_assert(nan_s <=> nan_s == std::partial_ordering::unordered); +#endif // defined(__clang__) + assert(nan_s <=> nan_s == std::partial_ordering::unordered); + } + { // chrono::time_point + using std::chrono::milliseconds; + using double_seconds = std::chrono::duration; + using sys_tp = std::chrono::system_clock::time_point; + using sys_ms = std::chrono::time_point; + using sys_double_s = std::chrono::time_point; + + spaceship_test(sys_tp{}, sys_ms{}, sys_ms{milliseconds{1}}); + spaceship_test(sys_tp{}, sys_double_s{}, sys_double_s{double_seconds{1}}); + + constexpr sys_double_s nan_tp{double_seconds{std::numeric_limits::quiet_NaN()}}; +#ifdef __clang__ // TRANSITION, DevCom-445462 + static_assert(nan_tp <=> nan_tp == std::partial_ordering::unordered); +#endif // defined(__clang__) + assert(nan_tp <=> nan_tp == std::partial_ordering::unordered); + + using steady_tp = std::chrono::steady_clock::time_point; + static_assert(!HasSpaceshipWith); + } +} + +int main() { + ordering_test_cases(); +}