diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -41,6 +41,8 @@ Improvements and New Features ----------------------------- +* Implemented ``operator<=>`` for ``std::unique_ptr`` + Deprecations and Removals ------------------------- 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 @@ -25,7 +25,7 @@ "| `[variant.relops] `_ | `[variant.monostate.relops] `_","| monostate | variant",None,Kent Ross,|In Progress| -| `[unique.ptr.special] `_,| unique_ptr,[comparisons.three.way],Unassigned,|Not Started| +| `[unique.ptr.special] `_,| unique_ptr,[comparisons.three.way],Adrian Vogelsgesang,|Complete| | `[util.smartptr.shared.cmp] `_,| shared_ptr,[comparisons.three.way],Unassigned,|Not Started| | `[type.index.members] `_,| type_index,None,Unassigned,|Not Started| | `[charconv.syn] `_,| to_chars_result,None,Mark de Wever,|Complete| diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -10,6 +10,9 @@ #ifndef _LIBCPP___MEMORY_UNIQUE_PTR_H #define _LIBCPP___MEMORY_UNIQUE_PTR_H +#include <__compare/compare_three_way.h> +#include <__compare/compare_three_way_result.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__functional/hash.h> #include <__functional/operations.h> @@ -557,10 +560,12 @@ bool operator==(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return __x.get() == __y.get();} +#if _LIBCPP_STD_VER <= 17 template inline _LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x == __y);} +#endif template inline _LIBCPP_INLINE_VISIBILITY @@ -588,6 +593,18 @@ bool operator>=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x < __y);} + +#if _LIBCPP_STD_VER > 17 +template +requires three_way_comparable_with::pointer, + typename unique_ptr<_T2, _D2>::pointer> +compare_three_way_result_t::pointer, + typename unique_ptr<_T2, _D2>::pointer> +operator<=>(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) { + return compare_three_way()(__x.get(), __y.get()); +} +#endif + template inline _LIBCPP_INLINE_VISIBILITY bool @@ -596,6 +613,7 @@ return !__x; } +#if _LIBCPP_STD_VER <= 17 template inline _LIBCPP_INLINE_VISIBILITY bool @@ -619,6 +637,7 @@ { return static_cast(__x); } +#endif // _LIBCPP_STD_VER <= 17 template inline _LIBCPP_INLINE_VISIBILITY @@ -686,6 +705,15 @@ return !(nullptr < __x); } +#if _LIBCPP_STD_VER > 17 +template +requires three_way_comparable::pointer> +compare_three_way_result_t::pointer> +operator<=>(const unique_ptr<_T1, _D1>& __x, nullptr_t) { + return compare_three_way()(__x.get(), static_cast::pointer>(nullptr)); +} +#endif + #if _LIBCPP_STD_VER > 11 template diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -505,7 +505,7 @@ template bool operator==(const unique_ptr& x, const unique_ptr& y); template - bool operator!=(const unique_ptr& x, const unique_ptr& y); + bool operator!=(const unique_ptr& x, const unique_ptr& y); // removed in C++20 template bool operator<(const unique_ptr& x, const unique_ptr& y); template @@ -514,15 +514,21 @@ bool operator>(const unique_ptr& x, const unique_ptr& y); template bool operator>=(const unique_ptr& x, const unique_ptr& y); +template + requires three_way_comparable_with::pointer, + typename unique_ptr::pointer> + compare_three_way_result_t::pointer, + typename unique_ptr::pointer> + operator<=>(const unique_ptr& x, const unique_ptr& y); // C++20 template bool operator==(const unique_ptr& x, nullptr_t) noexcept; template - bool operator==(nullptr_t, const unique_ptr& y) noexcept; + bool operator==(nullptr_t, const unique_ptr& y) noexcept; // removed in C++20 template - bool operator!=(const unique_ptr& x, nullptr_t) noexcept; + bool operator!=(const unique_ptr& x, nullptr_t) noexcept; // removed in C++20 template - bool operator!=(nullptr_t, const unique_ptr& y) noexcept; + bool operator!=(nullptr_t, const unique_ptr& y) noexcept; // removed in C++20 template bool operator<(const unique_ptr& x, nullptr_t); @@ -540,6 +546,10 @@ bool operator>=(const unique_ptr& x, nullptr_t); template bool operator>=(nullptr_t, const unique_ptr& y); +template + requires three_way_comparable::pointer> + compare_three_way_result_t::pointer> + operator<=>(const unique_ptr& x, nullptr_t); // C++20 class bad_weak_ptr : public std::exception diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/cmp_nullptr.pass.cpp @@ -34,6 +34,10 @@ // bool operator>=(const unique_ptr& x, nullptr_t) noexcept; // template // bool operator>=(nullptr_t, const unique_ptr& y) noexcept; +// template +// requires three_­way_­comparable::pointer> +// constexpr compare_three_way_result_t::pointer> +// operator<=>(const unique_ptr& x, nullptr_t); // C++20 #include #include @@ -55,6 +59,10 @@ 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::unique_ptr p2; assert( (p2 == nullptr)); @@ -67,6 +75,9 @@ assert(!(nullptr > p2)); assert( (p2 >= nullptr)); assert( (nullptr >= p2)); +#if TEST_STD_VER > 17 + assert((nullptr <=> p2) == std::strong_ordering::equivalent); +#endif - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/rel.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/rel.pass.cpp --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/rel.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.special/rel.pass.cpp @@ -26,6 +26,13 @@ // bool // operator>=(const unique_ptr& x, const unique_ptr& y); +// template +// requires three_way_comparable_with::pointer, +// typename unique_ptr::pointer> +// compare_three_way_result_t::pointer, +// typename unique_ptr::pointer> +// operator<=>(const unique_ptr& x, const unique_ptr& y); + #include #include @@ -53,6 +60,8 @@ int B::count = 0; +static std::strong_ordering reverse(std::strong_ordering v) { return 0 <=> v; } + int main(int, char**) { { @@ -61,6 +70,10 @@ assert((p1 < p2) == !(p1 > p2)); assert((p1 < p2) == (p1 <= p2)); assert((p1 < p2) == !(p1 >= p2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p1) == std::strong_ordering::equivalent); + assert((p1 <=> p2) == reverse(p2 <=> p1)); +#endif } { const std::unique_ptr > p1(new A); @@ -68,6 +81,9 @@ assert((p1 < p2) == !(p1 > p2)); assert((p1 < p2) == (p1 <= p2)); assert((p1 < p2) == !(p1 >= p2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) == reverse(p2 <=> p1)); +#endif } { const std::unique_ptr > p1(new A[3]); @@ -75,6 +91,9 @@ assert((p1 < p2) == !(p1 > p2)); assert((p1 < p2) == (p1 <= p2)); assert((p1 < p2) == !(p1 >= p2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) == reverse(p2 <=> p1)); +#endif } { const std::unique_ptr > p1(new A[3]); @@ -82,6 +101,9 @@ assert((p1 < p2) == !(p1 > p2)); assert((p1 < p2) == (p1 <= p2)); assert((p1 < p2) == !(p1 >= p2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) == reverse(p2 <=> p1)); +#endif } { const std::unique_ptr > p1; @@ -89,6 +111,9 @@ assert((p1 < p2) == (p1 > p2)); assert((p1 < p2) == !(p1 <= p2)); assert((p1 < p2) == !(p1 >= p2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) == reverse(p2 <=> p1)); +#endif } { const std::unique_ptr > p1; @@ -96,6 +121,9 @@ assert((p1 < p2) == (p1 > p2)); assert((p1 < p2) == !(p1 <= p2)); assert((p1 < p2) == !(p1 >= p2)); +#if TEST_STD_VER > 17 + assert((p1 <=> p2) == reverse(p2 <=> p1)); +#endif } return 0;