[libcxx-commits] [libcxx] d94a770 - [libc++][spaceship] Implement `operator<=>` for `time_point`

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Sat Apr 8 22:47:27 PDT 2023


Author: Hristo Hristov
Date: 2023-04-09T08:47:20+03:00
New Revision: d94a770f7b05161e0b8bc87975cfbc7f79d4b497

URL: https://github.com/llvm/llvm-project/commit/d94a770f7b05161e0b8bc87975cfbc7f79d4b497
DIFF: https://github.com/llvm/llvm-project/commit/d94a770f7b05161e0b8bc87975cfbc7f79d4b497.diff

LOG: [libc++][spaceship] Implement `operator<=>` for `time_point`

Depends on D145881

Implements parts of **P1614R2**: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1614r2.html
Implements `operator<=>` for `time_point`

Reviewed By: #libc, Mordante

Differential Revision: https://reviews.llvm.org/D146250

Added: 
    libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.compile.fail.cpp
    libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.pass.cpp

Modified: 
    libcxx/docs/Status/SpaceshipProjects.csv
    libcxx/include/__chrono/time_point.h
    libcxx/include/chrono

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index ab488ab847665..02eac2655d24c 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -53,7 +53,7 @@ Section,Description,Dependencies,Assignee,Complete
 | `[range.transform.iterator] <https://wg21.link/range.transform.iterator>`_,| `ranges::transform_view::iterator <https://reviews.llvm.org/D110774>`_,[concepts.cmp],Arthur O'Dwyer,|Complete|
 | `[range.elements.iterator] <https://wg21.link/range.elements.iterator>`_,| ranges::elements_view::iterator,[concepts.cmp],Hui Xie,|Complete|
 | `[time.duration.comparisons] <https://wg21.link/time.duration.comparisons>`_, `chrono::duration <https://reviews.llvm.org/D145881>`_, None, Hristo Hristov, |Complete|
-| `[time.point.comparisons] <https://wg21.link/time.point.comparisons>`_, `chrono::time_point <https://reviews.llvm.org/D146250>`_, None, Hristo Hristov, |In Progress|
+| `[time.point.comparisons] <https://wg21.link/time.point.comparisons>`_, `chrono::time_point <https://reviews.llvm.org/D146250>`_, None, Hristo Hristov, |Complete|
 "| `[time.cal.day.nonmembers] <https://wg21.link/time.cal.day.nonmembers>`_
 | `[time.cal.month.nonmembers] <https://wg21.link/time.cal.month.nonmembers>`_
 | `[time.cal.year.nonmembers] <https://wg21.link/time.cal.year.nonmembers>`_

diff  --git a/libcxx/include/__chrono/time_point.h b/libcxx/include/__chrono/time_point.h
index 8ac3158d54637..c14835401fa40 100644
--- 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 @@ operator==(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
     return __lhs.time_since_epoch() == __rhs.time_since_epoch();
 }
 
+#if _LIBCPP_STD_VER <= 17
+
 // time_point !=
 
 template <class _Clock, class _Duration1, class _Duration2>
@@ -160,6 +164,8 @@ operator!=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
     return !(__lhs == __rhs);
 }
 
+#endif // _LIBCPP_STD_VER <= 17
+
 // time_point <
 
 template <class _Clock, class _Duration1, class _Duration2>
@@ -200,6 +206,16 @@ operator>=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
     return !(__lhs < __rhs);
 }
 
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Clock, class _Duration1, three_way_comparable_with<_Duration1> _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 <class _Clock, class _Duration1, class _Rep2, class _Period2>

diff  --git a/libcxx/include/chrono b/libcxx/include/chrono
index a6b4565811f7b..b5d3b0318742a 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -235,7 +235,7 @@ template <class Clock, class Duration1, class Duration2>
 template <class Clock, class Duration1, class Duration2>
    bool operator==(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
 template <class Clock, class Duration1, class Duration2>
-   bool operator!=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
+   bool operator!=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs); // removed in C++20
 template <class Clock, class Duration1, class Duration2>
    bool operator< (const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
 template <class Clock, class Duration1, class Duration2>
@@ -244,6 +244,10 @@ template <class Clock, class Duration1, class Duration2>
    bool operator> (const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
 template <class Clock, class Duration1, class Duration2>
    bool operator>=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
+template<class Clock, class Duration1,
+         three_way_comparable_with<Duration1> Duration2>
+  constexpr auto operator<=>(const time_point<Clock, Duration1>& lhs,
+                             const time_point<Clock, Duration2>& 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.compile.fail.cpp b/libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.compile.fail.cpp
new file mode 100644
index 0000000000000..9d4ab04c77e04
--- /dev/null
+++ b/libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.compile.fail.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <chrono>
+
+// time_point
+
+// template<class Clock, class Duration1,
+//          three_way_comparable_with<Duration1> Duration2>
+//   constexpr auto operator<=>(const time_point<Clock, Duration1>& lhs,
+//                              const time_point<Clock, Duration2>& rhs);
+
+// time_points with 
diff erent clocks should not compare
+
+#include <chrono>
+
+#include "../../clock.h"
+
+int main(int, char**) {
+  using namespace std::chrono_literals;
+  std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> t1{3ms};
+  std::chrono::time_point<Clock, std::chrono::milliseconds> t2{3ms};
+
+  t1 <=> t2;
+
+  return 0;
+}

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
index 0000000000000..aed80138303e9
--- /dev/null
+++ b/libcxx/test/std/time/time.point/time.point.comparisons/compare.three_way.pass.cpp
@@ -0,0 +1,127 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <chrono>
+
+// time_point
+
+// template<class Clock, class Duration1,
+//          three_way_comparable_with<Duration1> Duration2>
+//   constexpr auto operator<=>(const time_point<Clock, Duration1>& lhs,
+//                              const time_point<Clock, Duration2>& rhs);
+
+#include <cassert>
+#include <chrono>
+#include <ratio>
+
+#include "test_comparisons.h"
+
+constexpr void test_with_integral_ticks_value() {
+  using Clock = std::chrono::system_clock;
+
+  using Duration1 = std::chrono::milliseconds;
+  using Duration2 = std::chrono::microseconds;
+  using T1        = std::chrono::time_point<Clock, Duration1>;
+  using T2        = std::chrono::time_point<Clock, Duration2>;
+
+  {
+    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));
+  }
+}
+
+constexpr void test_with_integral_ticks_value_and_custom_period_value() {
+  using Clock = std::chrono::system_clock;
+
+  using DInt30Hz = std::chrono::duration<int, std::ratio<1, 30>>;
+  using DInt60Hz = std::chrono::duration<int, std::ratio<1, 60>>;
+
+  using TIntR1 = std::chrono::time_point<Clock, DInt30Hz>;
+  using TIntR2 = std::chrono::time_point<Clock, DInt60Hz>;
+
+  {
+    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));
+  }
+}
+
+constexpr void test_with_floating_point_ticks_value() {
+  using Clock = std::chrono::system_clock;
+
+  using DF30Hz = std::chrono::duration<double, std::ratio<1, 30>>;
+  using DF60Hz = std::chrono::duration<double, std::ratio<1, 60>>;
+  using F1     = std::chrono::time_point<Clock, DF30Hz>;
+  using F2     = std::chrono::time_point<Clock, DF60Hz>;
+
+  // No 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));
+  }
+}
+
+constexpr bool test() {
+  test_with_integral_ticks_value();
+  test_with_integral_ticks_value_and_custom_period_value();
+  test_with_floating_point_ticks_value();
+
+  return true;
+}
+
+int main(int, char**) {
+  assert(test());
+  static_assert(test());
+  return 0;
+}


        


More information about the libcxx-commits mailing list