diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -53,7 +53,7 @@ | `[range.transform.iterator] `_,| `ranges::transform_view::iterator `_,[concepts.cmp],Arthur O'Dwyer,|Complete| | `[range.elements.iterator] `_,| ranges::elements_view::iterator,[concepts.cmp],Hui Xie,|Complete| | `[time.duration.comparisons] `_, `chrono::duration `_, None, Hristo Hristov, |Complete| -| `[time.point.comparisons] `_, "chrono::time_point", None, Mark de Wever, |Not Started| +| `[time.point.comparisons] `_, `chrono::time_point `_, None, Hristo Hristov, |Complete| "| `[time.cal.day.nonmembers] `_ | `[time.cal.month.nonmembers] `_ | `[time.cal.year.nonmembers] `_ diff --git a/libcxx/include/__chrono/time_point.h b/libcxx/include/__chrono/time_point.h --- a/libcxx/include/__chrono/time_point.h +++ b/libcxx/include/__chrono/time_point.h @@ -11,6 +11,8 @@ #define _LIBCPP___CHRONO_TIME_POINT_H #include <__chrono/duration.h> +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__type_traits/common_type.h> #include <__type_traits/enable_if.h> @@ -150,6 +152,8 @@ return __lhs.time_since_epoch() == __rhs.time_since_epoch(); } +#if _LIBCPP_STD_VER <= 17 + // time_point != template @@ -160,6 +164,8 @@ return !(__lhs == __rhs); } +#endif // _LIBCPP_STD_VER <= 17 + // time_point < template @@ -200,6 +206,16 @@ return !(__lhs < __rhs); } +#if _LIBCPP_STD_VER >= 20 + +template _Duration2> +_LIBCPP_HIDE_FROM_ABI constexpr auto +operator<=>(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return __lhs.time_since_epoch() <=> __rhs.time_since_epoch(); +} + +#endif // _LIBCPP_STD_VER >= 20 + // time_point operator+(time_point x, duration y); template diff --git a/libcxx/include/chrono b/libcxx/include/chrono --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -235,7 +235,7 @@ template bool operator==(const time_point& lhs, const time_point& rhs); template - bool operator!=(const time_point& lhs, const time_point& rhs); + bool operator!=(const time_point& lhs, const time_point& rhs); // removed in C++20 template bool operator< (const time_point& lhs, const time_point& rhs); template @@ -244,6 +244,10 @@ bool operator> (const time_point& lhs, const time_point& rhs); template bool operator>=(const time_point& lhs, const time_point& rhs); +template Duration2> + constexpr auto operator<=>(const time_point& lhs, + const time_point& rhs); // since C++20 // time_point_cast (constexpr in C++14) diff --git a/libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.pass.cpp b/libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.pass.cpp @@ -0,0 +1,112 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// time_point + +// template Duration2> +// constexpr auto operator<=>(const time_point& lhs, +// const time_point& rhs); + +#include +#include +#include + +#include "test_comparisons.h" + +constexpr bool test() { + using Clock = std::chrono::system_clock; + + using Duration1 = std::chrono::milliseconds; + using Duration2 = std::chrono::microseconds; + using T1 = std::chrono::time_point; + using T2 = std::chrono::time_point; + + { + T1 t1(Duration1(3)); + T1 t2(Duration1(3)); + assert((t1 <=> t2) == std::strong_ordering::equal); + assert(testOrder(t1, t2, std::strong_ordering::equal)); + } + { + T1 t1(Duration1(3)); + T1 t2(Duration1(4)); + assert((t1 <=> t2) == std::strong_ordering::less); + assert(testOrder(t1, t2, std::strong_ordering::less)); + } + { + T1 t1(Duration1(3)); + T2 t2(Duration2(3000)); + assert((t1 <=> t2) == std::strong_ordering::equal); + assert(testOrder(t1, t2, std::strong_ordering::equal)); + } + { + T1 t1(Duration1(3)); + T2 t2(Duration2(3001)); + assert((t1 <=> t2) == std::strong_ordering::less); + assert(testOrder(t1, t2, std::strong_ordering::less)); + assert((t2 <=> t1) == std::strong_ordering::greater); + assert(testOrder(t2, t1, std::strong_ordering::greater)); + } + + using DInt30Hz = std::chrono::duration>; + using DInt60Hz = std::chrono::duration>; + + using TIntR1 = std::chrono::time_point; + using TIntR2 = std::chrono::time_point; + + { + TIntR1 t1(DInt30Hz(10)); + TIntR2 t2(DInt60Hz(20)); + assert((t1 <=> t2) == std::strong_ordering::equal); + assert(testOrder(t1, t2, std::strong_ordering::equal)); + } + { + TIntR1 t1(DInt30Hz(10)); + TIntR2 t2(DInt60Hz(21)); + assert((t1 <=> t2) == std::strong_ordering::less); + assert(testOrder(t1, t2, std::strong_ordering::less)); + } + { + TIntR1 t1(DInt30Hz(11)); + TIntR2 t2(DInt60Hz(20)); + assert((t1 <=> t2) == std::strong_ordering::greater); + assert(testOrder(t1, t2, std::strong_ordering::greater)); + } + + using DF30Hz = std::chrono::duration>; + using DF60Hz = std::chrono::duration>; + using F1 = std::chrono::time_point; + using F2 = std::chrono::time_point; + + // Skipped equality comparison test for floating point values. + { + F1 t1(DF30Hz(3.5)); + F2 t2(DF60Hz(7.1)); + assert((t1 <=> t2) == std::weak_ordering::less); + assert(testOrder(t1, t2, std::weak_ordering::less)); + } + { + F1 t1(DF30Hz(3.6)); + F2 t2(DF60Hz(7.0)); + assert((t1 <=> t2) == std::weak_ordering::greater); + assert(testOrder(t1, t2, std::weak_ordering::greater)); + } + + return true; +} + +int main(int, char**) { + assert(test()); + static_assert(test()); + return 0; +}