[libcxx-commits] [libcxx] 3b217f2 - [libc++] Implement `operator<=>` for `shared_ptr`

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Wed Aug 3 09:32:52 PDT 2022


Author: Adrian Vogelsgesang
Date: 2022-08-03T18:32:45+02:00
New Revision: 3b217f2f127ebf5da5b87485dd9bc33ae1a66427

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

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

Implements part of:

* P1614R2 The Mothership has Landed

Fixes LWG3427

Reviewed By: #libc, Mordante

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

Added: 
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp.pass.cpp

Modified: 
    libcxx/docs/Status/Cxx2bIssues.csv
    libcxx/docs/Status/SpaceshipProjects.csv
    libcxx/include/__memory/shared_ptr.h
    libcxx/include/memory
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp

Removed: 
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/eq.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/lt.pass.cpp


################################################################################
diff  --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv
index 361e76657b51a..73365dadc48db 100644
--- a/libcxx/docs/Status/Cxx2bIssues.csv
+++ b/libcxx/docs/Status/Cxx2bIssues.csv
@@ -28,7 +28,7 @@
 "`3421 <https://wg21.link/LWG3421>`__","Imperfect ADL emulation for boolean-testable","November 2020","|Nothing To Do|","","|ranges|"
 "`3425 <https://wg21.link/LWG3425>`__","``condition_variable_any`` fails to constrain its Lock parameters","November 2020","|Nothing To Do|",""
 "`3426 <https://wg21.link/LWG3426>`__","``operator<=>(const unique_ptr<T, D>&, nullptr_t)`` can't get no satisfaction","November 2020","","","|spaceship|"
-"`3427 <https://wg21.link/LWG3427>`__","``operator<=>(const shared_ptr<T>&, nullptr_t)`` definition ill-formed","November 2020","","","|spaceship|"
+"`3427 <https://wg21.link/LWG3427>`__","``operator<=>(const shared_ptr<T>&, nullptr_t)`` definition ill-formed","November 2020","|Complete|","16.0","|spaceship|"
 "`3428 <https://wg21.link/LWG3428>`__","``single_view``'s in place constructor should be explicit","November 2020","|Complete|","14.0","|ranges|"
 "`3434 <https://wg21.link/LWG3434>`__","``ios_base`` never reclaims memory for iarray and parray","November 2020","|Nothing To Do|",""
 "`3437 <https://wg21.link/LWG3437>`__","``__cpp_lib_polymorphic_allocator`` is in the wrong header","November 2020","|Complete|","14.0"

diff  --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index 8e002c054fb44..b7d1c561bba2f 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -26,7 +26,7 @@ Section,Description,Dependencies,Assignee,Complete
 | `[variant.monostate.relops] <https://wg21.link/variant.monostate.relops>`_","| monostate
 | variant",None,Kent Ross,|In Progress|
 | `[unique.ptr.special] <https://wg21.link/unique.ptr.special>`_,| `unique_ptr <https://reviews.llvm.org/D130838>`_,[comparisons.three.way],Adrian Vogelsgesang,|In Progress|
-| `[util.smartptr.shared.cmp] <https://wg21.link/util.smartptr.shared.cmp>`_,| `shared_ptr <https://reviews.llvm.org/D130852>`_,[comparisons.three.way],Adrian Vogelsgesang,|In Progress|
+| `[util.smartptr.shared.cmp] <https://wg21.link/util.smartptr.shared.cmp>`_,| `shared_ptr <https://reviews.llvm.org/D130852>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete|
 | `[type.index.members] <https://wg21.link/type.index.members>`_,| type_index,None,Unassigned,|Not Started|
 | `[charconv.syn] <https://wg21.link/charconv.syn>`_,| to_chars_result,None,Mark de Wever,|Complete|
 | `[charconv.syn] <https://wg21.link/charconv.syn>`_,| from_chars_result,None,Mark de Wever,|Complete|

diff  --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 41a7c7fa7575f..a450cba89318e 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -11,6 +11,8 @@
 #define _LIBCPP___MEMORY_SHARED_PTR_H
 
 #include <__availability>
+#include <__compare/compare_three_way.h>
+#include <__compare/ordering.h>
 #include <__config>
 #include <__functional/binary_function.h>
 #include <__functional/operations.h>
@@ -1184,6 +1186,8 @@ operator==(const shared_ptr<_Tp>& __x, const shared_ptr<_Up>& __y) _NOEXCEPT
     return __x.get() == __y.get();
 }
 
+#if _LIBCPP_STD_VER <= 17
+
 template<class _Tp, class _Up>
 inline _LIBCPP_INLINE_VISIBILITY
 bool
@@ -1230,6 +1234,17 @@ operator>=(const shared_ptr<_Tp>& __x, const shared_ptr<_Up>& __y) _NOEXCEPT
     return !(__x < __y);
 }
 
+#endif // _LIBCPP_STD_VER <= 17
+
+#if _LIBCPP_STD_VER > 17
+template<class _Tp, class _Up>
+_LIBCPP_HIDE_FROM_ABI strong_ordering
+operator<=>(shared_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) noexcept
+{
+    return compare_three_way()(__x.get(), __y.get());
+}
+#endif
+
 template<class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 bool
@@ -1238,6 +1253,8 @@ operator==(const shared_ptr<_Tp>& __x, nullptr_t) _NOEXCEPT
     return !__x;
 }
 
+#if _LIBCPP_STD_VER <= 17
+
 template<class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 bool
@@ -1326,6 +1343,17 @@ operator>=(nullptr_t, const shared_ptr<_Tp>& __x) _NOEXCEPT
     return !(nullptr < __x);
 }
 
+#endif // _LIBCPP_STD_VER <= 17
+
+#if _LIBCPP_STD_VER > 17
+template<class _Tp>
+_LIBCPP_HIDE_FROM_ABI strong_ordering
+operator<=>(shared_ptr<_Tp> const& __x, nullptr_t) noexcept
+{
+    return compare_three_way()(__x.get(), static_cast<typename shared_ptr<_Tp>::element_type*>(nullptr));
+}
+#endif
+
 template<class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 void

diff  --git a/libcxx/include/memory b/libcxx/include/memory
index a986d76c8b4ef..a5d2bfbdf330d 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -617,40 +617,44 @@ shared_ptr(unique_ptr<T, D>) -> shared_ptr<T>;
 template<class T, class U>
     bool operator==(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
 template<class T, class U>
-    bool operator!=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
+    bool operator!=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;               // removed in C++20
 template<class T, class U>
-    bool operator<(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
+    bool operator<(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;                // removed in C++20
 template<class T, class U>
-    bool operator>(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
+    bool operator>(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;                // removed in C++20
 template<class T, class U>
-    bool operator<=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
+    bool operator<=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;               // removed in C++20
 template<class T, class U>
-    bool operator>=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
+    bool operator>=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;               // removed in C++20
+template<class T, class U>
+    strong_ordering operator<=>(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;   // C++20
 
 template <class T>
     bool operator==(const shared_ptr<T>& x, nullptr_t) noexcept;
 template <class T>
-    bool operator==(nullptr_t, const shared_ptr<T>& y) noexcept;
+    bool operator==(nullptr_t, const shared_ptr<T>& y) noexcept;               // removed in C++20
 template <class T>
-    bool operator!=(const shared_ptr<T>& x, nullptr_t) noexcept;
+    bool operator!=(const shared_ptr<T>& x, nullptr_t) noexcept;               // removed in C++20
 template <class T>
-    bool operator!=(nullptr_t, const shared_ptr<T>& y) noexcept;
+    bool operator!=(nullptr_t, const shared_ptr<T>& y) noexcept;               // removed in C++20
 template <class T>
-    bool operator<(const shared_ptr<T>& x, nullptr_t) noexcept;
+    bool operator<(const shared_ptr<T>& x, nullptr_t) noexcept;                // removed in C++20
 template <class T>
-bool operator<(nullptr_t, const shared_ptr<T>& y) noexcept;
+    bool operator<(nullptr_t, const shared_ptr<T>& y) noexcept;                // removed in C++20
 template <class T>
-    bool operator<=(const shared_ptr<T>& x, nullptr_t) noexcept;
+    bool operator<=(const shared_ptr<T>& x, nullptr_t) noexcept;               // removed in C++20
 template <class T>
-    bool operator<=(nullptr_t, const shared_ptr<T>& y) noexcept;
+    bool operator<=(nullptr_t, const shared_ptr<T>& y) noexcept;               // removed in C++20
 template <class T>
-    bool operator>(const shared_ptr<T>& x, nullptr_t) noexcept;
+    bool operator>(const shared_ptr<T>& x, nullptr_t) noexcept;                // removed in C++20
 template <class T>
-    bool operator>(nullptr_t, const shared_ptr<T>& y) noexcept;
+    bool operator>(nullptr_t, const shared_ptr<T>& y) noexcept;                // removed in C++20
 template <class T>
-    bool operator>=(const shared_ptr<T>& x, nullptr_t) noexcept;
+    bool operator>=(const shared_ptr<T>& x, nullptr_t) noexcept;               // removed in C++20
 template <class T>
-    bool operator>=(nullptr_t, const shared_ptr<T>& y) noexcept;
+    bool operator>=(nullptr_t, const shared_ptr<T>& y) noexcept;               // removed in C++20
+template<class T>
+    strong_ordering operator<=>(shared_ptr<T> const& x, nullptr_t) noexcept;   // C++20
 
 // shared_ptr specialized algorithms:
 template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp.pass.cpp
new file mode 100644
index 0000000000000..00060ab546238
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <memory>
+
+// shared_ptr
+
+// template<class T, class U> bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b);
+// template<class T, class U> bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b);
+// template<class T, class U> bool operator< (const shared_ptr<T>& a, const shared_ptr<U>& b);
+// template<class T, class U> bool operator<=(const shared_ptr<T>& a, const shared_ptr<U>& b);
+// template<class T, class U> bool operator> (const shared_ptr<T>& a, const shared_ptr<U>& b);
+// template<class T, class U> bool operator>=(const shared_ptr<T>& a, const shared_ptr<U>& b);
+// template<class T1, class D1, class T2, class D2>
+//   requires three_way_comparable_with<typename unique_ptr<T1, D1>::pointer,
+//                                      typename unique_ptr<T2, D2>::pointer>
+//   compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer,
+//                              typename unique_ptr<T2, D2>::pointer>
+//     operator<=>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
+
+#include <memory>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_comparisons.h"
+
+void do_nothing(int*) {}
+
+int main(int, char**) {
+  AssertComparisonsAreNoexcept<std::shared_ptr<int> >();
+  AssertComparisonsReturnBool<std::shared_ptr<int> >();
+#if TEST_STD_VER > 17
+  AssertOrderAreNoexcept<std::shared_ptr<int>>();
+  AssertOrderReturn<std::strong_ordering, std::shared_ptr<int>>();
+#endif
+
+  int* ptr1(new int);
+  int* ptr2(new int);
+  const std::shared_ptr<int> p1(ptr1);
+  const std::shared_ptr<int> p2(ptr2);
+
+  assert(!(p1 == p2));
+  assert(p1 != p2);
+  assert((p1 < p2) == (ptr1 < ptr2));
+  assert((p1 <= p2) == (ptr1 <= ptr2));
+  assert((p1 > p2) == (ptr1 > ptr2));
+  assert((p1 >= p2) == (ptr1 >= ptr2));
+#if TEST_STD_VER > 17
+  assert((p1 <=> p2) != std::strong_ordering::equal);
+  assert((p1 <=> p2) == (ptr1 <=> ptr2));
+#endif
+
+  // The deleter does not influence the comparisons
+  // of the `shared_ptr`
+  const std::shared_ptr<int> p3(ptr2, do_nothing);
+  assert(p2 == p3);
+  assert(!(p1 == p3));
+  assert(!(p2 != p3));
+  assert(p1 != p3);
+  assert((p1 < p3) == (ptr1 < ptr2));
+  assert((p1 <= p3) == (ptr1 <= ptr2));
+  assert((p1 > p3) == (ptr1 > ptr2));
+  assert((p1 >= p3) == (ptr1 >= ptr2));
+#if TEST_STD_VER > 17
+  assert((p2 <=> p3) == std::strong_ordering::equal);
+  assert((p1 <=> p3) != std::strong_ordering::equal);
+  assert((p1 <=> p3) == (ptr1 <=> ptr2));
+#endif
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp
index bea3b4e94e27f..3bc8ef3799ab6 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/cmp_nullptr.pass.cpp
@@ -34,39 +34,58 @@
 //     bool operator>=(const shared_ptr<T>& x, nullptr_t) noexcept;
 // template <class T>
 //     bool operator>=(nullptr_t, const shared_ptr<T>& y) noexcept;
+// template<class T>
+//     strong_ordering operator<=>(shared_ptr<T> const& x, nullptr_t) noexcept;   // C++20
 
 #include <memory>
 #include <cassert>
 
 #include "test_macros.h"
+#include "test_comparisons.h"
 
 void do_nothing(int*) {}
 
 int main(int, char**)
 {
-    const std::shared_ptr<int> p1(new int(1));
-    assert(!(p1 == nullptr));
-    assert(!(nullptr == p1));
-    assert(!(p1 < nullptr));
-    assert( (nullptr < p1));
-    assert(!(p1 <= nullptr));
-    assert( (nullptr <= p1));
-    assert( (p1 > nullptr));
-    assert(!(nullptr > p1));
-    assert( (p1 >= nullptr));
-    assert(!(nullptr >= p1));
+  AssertComparisonsAreNoexcept<std::shared_ptr<int>, nullptr_t>();
+  AssertComparisonsAreNoexcept<nullptr_t, std::shared_ptr<int> >();
+  AssertComparisonsReturnBool<std::shared_ptr<int>, nullptr_t>();
+  AssertComparisonsReturnBool<nullptr_t, std::shared_ptr<int> >();
+#if TEST_STD_VER > 17
+  AssertOrderAreNoexcept<std::shared_ptr<int>>();
+  AssertOrderReturn<std::strong_ordering, std::shared_ptr<int>>();
+#endif
 
-    const std::shared_ptr<int> p2;
-    assert( (p2 == nullptr));
-    assert( (nullptr == p2));
-    assert(!(p2 < nullptr));
-    assert(!(nullptr < p2));
-    assert( (p2 <= nullptr));
-    assert( (nullptr <= p2));
-    assert(!(p2 > nullptr));
-    assert(!(nullptr > p2));
-    assert( (p2 >= nullptr));
-    assert( (nullptr >= p2));
+  const std::shared_ptr<int> p1(new int(1));
+  assert(!(p1 == nullptr));
+  assert(!(nullptr == p1));
+  assert(!(p1 < nullptr));
+  assert((nullptr < p1));
+  assert(!(p1 <= nullptr));
+  assert((nullptr <= p1));
+  assert((p1 > nullptr));
+  assert(!(nullptr > p1));
+  assert((p1 >= nullptr));
+  assert(!(nullptr >= p1));
+#if TEST_STD_VER > 17
+  assert((nullptr <=> p1) == std::strong_ordering::less);
+  assert((p1 <=> nullptr) == std::strong_ordering::greater);
+#endif
+
+  const std::shared_ptr<int> p2;
+  assert((p2 == nullptr));
+  assert((nullptr == p2));
+  assert(!(p2 < nullptr));
+  assert(!(nullptr < p2));
+  assert((p2 <= nullptr));
+  assert((nullptr <= p2));
+  assert(!(p2 > nullptr));
+  assert(!(nullptr > p2));
+  assert((p2 >= nullptr));
+  assert((nullptr >= p2));
+#if TEST_STD_VER > 17
+  assert((nullptr <=> p2) == std::strong_ordering::equivalent);
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/eq.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/eq.pass.cpp
deleted file mode 100644
index 2d1cee8ef895d..0000000000000
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/eq.pass.cpp
+++ /dev/null
@@ -1,34 +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
-//
-//===----------------------------------------------------------------------===//
-
-// <memory>
-
-// shared_ptr
-
-// template<class T, class U> bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b);
-// template<class T, class U> bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b);
-
-#include <memory>
-#include <cassert>
-
-#include "test_macros.h"
-
-void do_nothing(int*) {}
-
-int main(int, char**)
-{
-    int* ptr1(new int);
-    int* ptr2(new int);
-    const std::shared_ptr<int> p1(ptr1);
-    const std::shared_ptr<int> p2(ptr2);
-    const std::shared_ptr<int> p3(ptr2, do_nothing);
-    assert(p1 != p2);
-    assert(p2 == p3);
-
-  return 0;
-}

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/lt.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/lt.pass.cpp
deleted file mode 100644
index 478cb6c32e5c7..0000000000000
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cmp/lt.pass.cpp
+++ /dev/null
@@ -1,33 +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
-//
-//===----------------------------------------------------------------------===//
-
-// <memory>
-
-// shared_ptr
-
-// template<class T, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b);
-
-#include <memory>
-#include <cassert>
-
-#include "test_macros.h"
-
-void do_nothing(int*) {}
-
-int main(int, char**)
-{
-    int* ptr1(new int);
-    int* ptr2(new int);
-    const std::shared_ptr<int> p1(ptr1);
-    const std::shared_ptr<int> p2(ptr2);
-    const std::shared_ptr<int> p3(ptr2, do_nothing);
-    assert((p1 < p2) == (ptr1 < ptr2));
-    assert(!(p2 < p3) && !(p3 < p2));
-
-  return 0;
-}


        


More information about the libcxx-commits mailing list