[libcxx-commits] [libcxx] 41e7665 - [libc++] Implement `operator<=>` for `thread::id`

Adrian Vogelsgesang via libcxx-commits libcxx-commits at lists.llvm.org
Sat Aug 13 17:31:12 PDT 2022


Author: Adrian Vogelsgesang
Date: 2022-08-13T17:30:55-07:00
New Revision: 41e7665c4b8ed47d1802b1dc8a41be3eacf805ad

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

LOG: [libc++] Implement `operator<=>` for `thread::id`

The new operator<=> is mapped onto the existing functions
__libcpp_thread_id_equal and __libcpp_thread_id_less. Introducing a
new __libcpp_thread_id_compare_three_way might lead to more efficient
code. Given that we can still introduce __libcpp_thread_id_compare_three_way
later, for this commit I opted to not break ABI. If requested, I will
add __libcpp_thread_id_compare_three_way in a follow-up commit.

Implements part of P1614R2 "The Mothership has Landed"

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

Added: 
    libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp

Modified: 
    libcxx/docs/Status/SpaceshipProjects.csv
    libcxx/include/__threading_support
    libcxx/include/thread

Removed: 
    libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp
    libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp


################################################################################
diff  --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index 203ebac1b2818..5a8efbd9e21c8 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -78,4 +78,4 @@ Section,Description,Dependencies,Assignee,Complete
 | `[fs.path.nonmember] <https://wg21.link/fs.path.nonmember>`_,| `filesystem::path <https://reviews.llvm.org/D130859>`_,None,Adrian Vogelsgesang,|In Progress|
 | `[fs.dir.entry.obs] <https://wg21.link/fs.dir.entry.obs>`_,| `filesystem::directory_entry <https://reviews.llvm.org/D130860>`_,None,Adrian Vogelsgesang,|In Progress|
 | `[re.submatch.op] <https://wg21.link/re.submatch.op>`_,| sub_match,None,Mark de Wever,|In Progress|
-| `[thread.thread.id] <https://wg21.link/thread.thread.id>`_,| `thread::id <https://reviews.llvm.org/D131362>`_,None,Adrian Vogelsgesang,|In Progress|
+| `[thread.thread.id] <https://wg21.link/thread.thread.id>`_,| `thread::id <https://reviews.llvm.org/D131362>`_,None,Adrian Vogelsgesang,|Complete|

diff  --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support
index c9119f3b2dffc..55f5af2f3f584 100644
--- a/libcxx/include/__threading_support
+++ b/libcxx/include/__threading_support
@@ -13,6 +13,7 @@
 #include <__availability>
 #include <__chrono/convert_to_timespec.h>
 #include <__chrono/duration.h>
+#include <__compare/ordering.h>
 #include <__config>
 #include <__thread/poll_with_backoff.h>
 #include <errno.h>
@@ -609,6 +610,14 @@ class _LIBCPP_TEMPLATE_VIS __thread_id
     // on other platforms.  We assume 0 works everywhere for now.
     __libcpp_thread_id __id_;
 
+    static _LIBCPP_HIDE_FROM_ABI
+        bool __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT
+        { // id==0 is always less than any other thread_id
+        if (__x.__id_ == 0) return __y.__id_ != 0;
+        if (__y.__id_ == 0) return false;
+        return  __libcpp_thread_id_less(__x.__id_, __y.__id_);
+        }
+
 public:
     _LIBCPP_INLINE_VISIBILITY
     __thread_id() _NOEXCEPT : __id_(0) {}
@@ -617,7 +626,11 @@ public:
     void __reset() { __id_ = 0; }
 
     friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
-    friend _LIBCPP_HIDE_FROM_ABI bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT;
+#if _LIBCPP_STD_VER <= 17
+    friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT;
+#else // _LIBCPP_STD_VER <= 17
+    friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept;
+#endif // _LIBCPP_STD_VER <= 17
 
     template<class _CharT, class _Traits>
     friend
@@ -644,25 +657,35 @@ bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
   return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
 }
 
+#if _LIBCPP_STD_VER <= 17
+
 inline _LIBCPP_HIDE_FROM_ABI
 bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT {
-    return !(__x == __y);
+  return !(__x == __y);
 }
 
 inline _LIBCPP_HIDE_FROM_ABI
 bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT {
-  // id==0 is always less than any other thread_id
-  if (__x.__id_ == 0)
-    return __y.__id_ != 0;
-  if (__y.__id_ == 0)
-    return false;
-  return __libcpp_thread_id_less(__x.__id_, __y.__id_);
+  return __thread_id::__lt_impl(__x.__id_, __y.__id_);
 }
 
 inline _LIBCPP_HIDE_FROM_ABI bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__y < __x); }
 inline _LIBCPP_HIDE_FROM_ABI bool operator>(__thread_id __x, __thread_id __y) _NOEXCEPT { return __y < __x; }
 inline _LIBCPP_HIDE_FROM_ABI bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__x < __y); }
 
+#else // _LIBCPP_STD_VER <= 17
+
+inline _LIBCPP_HIDE_FROM_ABI
+strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept {
+  if (__x == __y)
+    return strong_ordering::equal;
+  if (__thread_id::__lt_impl(__x, __y))
+    return strong_ordering::less;
+  return strong_ordering::greater;
+}
+
+#endif // _LIBCPP_STD_VER <= 17
+
 namespace this_thread
 {
 

diff  --git a/libcxx/include/thread b/libcxx/include/thread
index cde165039b3a2..8b8699271eeec 100644
--- a/libcxx/include/thread
+++ b/libcxx/include/thread
@@ -53,11 +53,12 @@ public:
 };
 
 bool operator==(thread::id x, thread::id y) noexcept;
-bool operator!=(thread::id x, thread::id y) noexcept;
-bool operator< (thread::id x, thread::id y) noexcept;
-bool operator<=(thread::id x, thread::id y) noexcept;
-bool operator> (thread::id x, thread::id y) noexcept;
-bool operator>=(thread::id x, thread::id y) noexcept;
+bool operator!=(thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator< (thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator<=(thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator> (thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator>=(thread::id x, thread::id y) noexcept;             // removed in C++20
+strong_ordering operator<=>(thread::id x, thread::id y) noexcept; // C++20
 
 template<class charT, class traits>
 basic_ostream<charT, traits>&

diff  --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp
new file mode 100644
index 0000000000000..7be937aa948c5
--- /dev/null
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-threads
+
+// <thread>
+
+// class thread::id
+
+// bool operator==(thread::id x, thread::id y) noexcept;
+// bool operator!=(thread::id x, thread::id y) noexcept;
+// bool operator< (thread::id x, thread::id y) noexcept;
+// bool operator<=(thread::id x, thread::id y) noexcept;
+// bool operator> (thread::id x, thread::id y) noexcept;
+// bool operator>=(thread::id x, thread::id y) noexcept;
+// strong_ordering operator<=>(thread::id x, thread::id y) noexcept;
+
+#include <thread>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_comparisons.h"
+
+int main(int, char**) {
+  AssertComparisonsAreNoexcept<std::thread::id>();
+  AssertComparisonsReturnBool<std::thread::id>();
+#if TEST_STD_VER > 17
+  AssertOrderAreNoexcept<std::thread::id>();
+  AssertOrderReturn<std::strong_ordering, std::thread::id>();
+#endif
+
+  std::thread::id id1;
+  std::thread::id id2;
+  std::thread::id id3 = std::this_thread::get_id();
+
+  // `id1` and `id2` should compare equal
+  assert(testComparisons(id1, id2, /*isEqual*/ true, /*isLess*/ false));
+#if TEST_STD_VER > 17
+  assert(testOrder(id1, id2, std::strong_ordering::equal));
+#endif
+
+  // Test `t1` and `t3` which are not equal
+  bool isLess = id1 < id3;
+  assert(testComparisons(id1, id3, /*isEqual*/ false, isLess));
+#if TEST_STD_VER > 17
+  assert(testOrder(id1, id3, isLess ? std::strong_ordering::less : std::strong_ordering::greater));
+#endif
+
+  // Regression tests for https://github.com/llvm/llvm-project/issues/56187
+  // libc++ previously declared the comparison operators as hidden friends
+  // which was non-conforming.
+  assert(std::operator==(id1, id2));
+#if TEST_STD_VER <= 17
+  assert(!std::operator!=(id1, id2));
+  assert(!std::operator<(id1, id2));
+  assert(std::operator<=(id1, id2));
+  assert(!std::operator>(id1, id2));
+  assert(std::operator>=(id1, id2));
+#else
+  assert(std::operator<=>(id1, id2) == std::strong_ordering::equal);
+#endif
+
+  return 0;
+}

diff  --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp
deleted file mode 100644
index 01d505c325cc7..0000000000000
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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: no-threads
-
-// <thread>
-
-// class thread::id
-
-// bool operator==(thread::id x, thread::id y);
-// bool operator!=(thread::id x, thread::id y);
-
-#include <thread>
-#include <cassert>
-
-#include "test_macros.h"
-
-int main(int, char**)
-{
-    std::thread::id id0;
-    std::thread::id id1;
-    id1 = id0;
-    assert( (id1 == id0));
-    assert(!(id1 != id0));
-    id1 = std::this_thread::get_id();
-    assert(!(id1 == id0));
-    assert( (id1 != id0));
-
-    // Regression tests for https://github.com/llvm/llvm-project/issues/56187
-    // libc++ previously declared the comparison operators as hidden friends
-    // which was non-conforming.
-    assert(!std::operator==(id1, id0));
-    assert(std::operator!=(id1, id0));
-
-    return 0;
-}

diff  --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp
deleted file mode 100644
index 7519f04ebb353..0000000000000
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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: no-threads
-
-// <thread>
-
-// class thread::id
-
-// bool operator< (thread::id x, thread::id y);
-// bool operator<=(thread::id x, thread::id y);
-// bool operator> (thread::id x, thread::id y);
-// bool operator>=(thread::id x, thread::id y);
-
-#include <thread>
-#include <cassert>
-
-#include "test_macros.h"
-
-int main(int, char**)
-{
-    std::thread::id id0;
-    std::thread::id id1;
-    std::thread::id id2 = std::this_thread::get_id();
-    assert(!(id0 <  id1));
-    assert( (id0 <= id1));
-    assert(!(id0 >  id1));
-    assert( (id0 >= id1));
-    assert(!(id0 == id2));
-    if (id0 < id2) {
-      assert( (id0 <= id2));
-      assert(!(id0 >  id2));
-      assert(!(id0 >= id2));
-    } else {
-      assert(!(id0 <= id2));
-      assert( (id0 >  id2));
-      assert( (id0 >= id2));
-    }
-
-    // Regression tests for https://github.com/llvm/llvm-project/issues/56187
-    // libc++ previously declared the comparison operators as hidden friends
-    // which was non-conforming.
-    assert(!std::operator<(id0, id1));
-    assert(std::operator<=(id0, id1));
-    assert(!std::operator>(id0, id1));
-    assert(std::operator>=(id0, id1));
-
-    return 0;
-}


        


More information about the libcxx-commits mailing list