Skip to content

Commit 3b217f2

Browse files
vogelsgesangmordante
authored andcommitted
[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
1 parent 144cea2 commit 3b217f2

File tree

8 files changed

+167
-107
lines changed

8 files changed

+167
-107
lines changed

libcxx/docs/Status/Cxx2bIssues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"`3421 <https://wg21.link/LWG3421>`__","Imperfect ADL emulation for boolean-testable","November 2020","|Nothing To Do|","","|ranges|"
2929
"`3425 <https://wg21.link/LWG3425>`__","``condition_variable_any`` fails to constrain its Lock parameters","November 2020","|Nothing To Do|",""
3030
"`3426 <https://wg21.link/LWG3426>`__","``operator<=>(const unique_ptr<T, D>&, nullptr_t)`` can't get no satisfaction","November 2020","","","|spaceship|"
31-
"`3427 <https://wg21.link/LWG3427>`__","``operator<=>(const shared_ptr<T>&, nullptr_t)`` definition ill-formed","November 2020","","","|spaceship|"
31+
"`3427 <https://wg21.link/LWG3427>`__","``operator<=>(const shared_ptr<T>&, nullptr_t)`` definition ill-formed","November 2020","|Complete|","16.0","|spaceship|"
3232
"`3428 <https://wg21.link/LWG3428>`__","``single_view``'s in place constructor should be explicit","November 2020","|Complete|","14.0","|ranges|"
3333
"`3434 <https://wg21.link/LWG3434>`__","``ios_base`` never reclaims memory for iarray and parray","November 2020","|Nothing To Do|",""
3434
"`3437 <https://wg21.link/LWG3437>`__","``__cpp_lib_polymorphic_allocator`` is in the wrong header","November 2020","|Complete|","14.0"

libcxx/docs/Status/SpaceshipProjects.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Section,Description,Dependencies,Assignee,Complete
2626
| `[variant.monostate.relops] <https://wg21.link/variant.monostate.relops>`_","| monostate
2727
| variant",None,Kent Ross,|In Progress|
2828
| `[unique.ptr.special] <https://wg21.link/unique.ptr.special>`_,| `unique_ptr <https://reviews.llvm.org/D130838>`_,[comparisons.three.way],Adrian Vogelsgesang,|In Progress|
29-
| `[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|
29+
| `[util.smartptr.shared.cmp] <https://wg21.link/util.smartptr.shared.cmp>`_,| `shared_ptr <https://reviews.llvm.org/D130852>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete|
3030
| `[type.index.members] <https://wg21.link/type.index.members>`_,| type_index,None,Unassigned,|Not Started|
3131
| `[charconv.syn] <https://wg21.link/charconv.syn>`_,| to_chars_result,None,Mark de Wever,|Complete|
3232
| `[charconv.syn] <https://wg21.link/charconv.syn>`_,| from_chars_result,None,Mark de Wever,|Complete|

libcxx/include/__memory/shared_ptr.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#define _LIBCPP___MEMORY_SHARED_PTR_H
1212

1313
#include <__availability>
14+
#include <__compare/compare_three_way.h>
15+
#include <__compare/ordering.h>
1416
#include <__config>
1517
#include <__functional/binary_function.h>
1618
#include <__functional/operations.h>
@@ -1184,6 +1186,8 @@ operator==(const shared_ptr<_Tp>& __x, const shared_ptr<_Up>& __y) _NOEXCEPT
11841186
return __x.get() == __y.get();
11851187
}
11861188

1189+
#if _LIBCPP_STD_VER <= 17
1190+
11871191
template<class _Tp, class _Up>
11881192
inline _LIBCPP_INLINE_VISIBILITY
11891193
bool
@@ -1230,6 +1234,17 @@ operator>=(const shared_ptr<_Tp>& __x, const shared_ptr<_Up>& __y) _NOEXCEPT
12301234
return !(__x < __y);
12311235
}
12321236

1237+
#endif // _LIBCPP_STD_VER <= 17
1238+
1239+
#if _LIBCPP_STD_VER > 17
1240+
template<class _Tp, class _Up>
1241+
_LIBCPP_HIDE_FROM_ABI strong_ordering
1242+
operator<=>(shared_ptr<_Tp> const& __x, shared_ptr<_Up> const& __y) noexcept
1243+
{
1244+
return compare_three_way()(__x.get(), __y.get());
1245+
}
1246+
#endif
1247+
12331248
template<class _Tp>
12341249
inline _LIBCPP_INLINE_VISIBILITY
12351250
bool
@@ -1238,6 +1253,8 @@ operator==(const shared_ptr<_Tp>& __x, nullptr_t) _NOEXCEPT
12381253
return !__x;
12391254
}
12401255

1256+
#if _LIBCPP_STD_VER <= 17
1257+
12411258
template<class _Tp>
12421259
inline _LIBCPP_INLINE_VISIBILITY
12431260
bool
@@ -1326,6 +1343,17 @@ operator>=(nullptr_t, const shared_ptr<_Tp>& __x) _NOEXCEPT
13261343
return !(nullptr < __x);
13271344
}
13281345

1346+
#endif // _LIBCPP_STD_VER <= 17
1347+
1348+
#if _LIBCPP_STD_VER > 17
1349+
template<class _Tp>
1350+
_LIBCPP_HIDE_FROM_ABI strong_ordering
1351+
operator<=>(shared_ptr<_Tp> const& __x, nullptr_t) noexcept
1352+
{
1353+
return compare_three_way()(__x.get(), static_cast<typename shared_ptr<_Tp>::element_type*>(nullptr));
1354+
}
1355+
#endif
1356+
13291357
template<class _Tp>
13301358
inline _LIBCPP_INLINE_VISIBILITY
13311359
void

libcxx/include/memory

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -617,40 +617,44 @@ shared_ptr(unique_ptr<T, D>) -> shared_ptr<T>;
617617
template<class T, class U>
618618
bool operator==(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
619619
template<class T, class U>
620-
bool operator!=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
620+
bool operator!=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; // removed in C++20
621621
template<class T, class U>
622-
bool operator<(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
622+
bool operator<(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; // removed in C++20
623623
template<class T, class U>
624-
bool operator>(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
624+
bool operator>(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; // removed in C++20
625625
template<class T, class U>
626-
bool operator<=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
626+
bool operator<=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; // removed in C++20
627627
template<class T, class U>
628-
bool operator>=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
628+
bool operator>=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; // removed in C++20
629+
template<class T, class U>
630+
strong_ordering operator<=>(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; // C++20
629631
630632
template <class T>
631633
bool operator==(const shared_ptr<T>& x, nullptr_t) noexcept;
632634
template <class T>
633-
bool operator==(nullptr_t, const shared_ptr<T>& y) noexcept;
635+
bool operator==(nullptr_t, const shared_ptr<T>& y) noexcept; // removed in C++20
634636
template <class T>
635-
bool operator!=(const shared_ptr<T>& x, nullptr_t) noexcept;
637+
bool operator!=(const shared_ptr<T>& x, nullptr_t) noexcept; // removed in C++20
636638
template <class T>
637-
bool operator!=(nullptr_t, const shared_ptr<T>& y) noexcept;
639+
bool operator!=(nullptr_t, const shared_ptr<T>& y) noexcept; // removed in C++20
638640
template <class T>
639-
bool operator<(const shared_ptr<T>& x, nullptr_t) noexcept;
641+
bool operator<(const shared_ptr<T>& x, nullptr_t) noexcept; // removed in C++20
640642
template <class T>
641-
bool operator<(nullptr_t, const shared_ptr<T>& y) noexcept;
643+
bool operator<(nullptr_t, const shared_ptr<T>& y) noexcept; // removed in C++20
642644
template <class T>
643-
bool operator<=(const shared_ptr<T>& x, nullptr_t) noexcept;
645+
bool operator<=(const shared_ptr<T>& x, nullptr_t) noexcept; // removed in C++20
644646
template <class T>
645-
bool operator<=(nullptr_t, const shared_ptr<T>& y) noexcept;
647+
bool operator<=(nullptr_t, const shared_ptr<T>& y) noexcept; // removed in C++20
646648
template <class T>
647-
bool operator>(const shared_ptr<T>& x, nullptr_t) noexcept;
649+
bool operator>(const shared_ptr<T>& x, nullptr_t) noexcept; // removed in C++20
648650
template <class T>
649-
bool operator>(nullptr_t, const shared_ptr<T>& y) noexcept;
651+
bool operator>(nullptr_t, const shared_ptr<T>& y) noexcept; // removed in C++20
650652
template <class T>
651-
bool operator>=(const shared_ptr<T>& x, nullptr_t) noexcept;
653+
bool operator>=(const shared_ptr<T>& x, nullptr_t) noexcept; // removed in C++20
652654
template <class T>
653-
bool operator>=(nullptr_t, const shared_ptr<T>& y) noexcept;
655+
bool operator>=(nullptr_t, const shared_ptr<T>& y) noexcept; // removed in C++20
656+
template<class T>
657+
strong_ordering operator<=>(shared_ptr<T> const& x, nullptr_t) noexcept; // C++20
654658
655659
// shared_ptr specialized algorithms:
656660
template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <memory>
10+
11+
// shared_ptr
12+
13+
// template<class T, class U> bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b);
14+
// template<class T, class U> bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b);
15+
// template<class T, class U> bool operator< (const shared_ptr<T>& a, const shared_ptr<U>& b);
16+
// template<class T, class U> bool operator<=(const shared_ptr<T>& a, const shared_ptr<U>& b);
17+
// template<class T, class U> bool operator> (const shared_ptr<T>& a, const shared_ptr<U>& b);
18+
// template<class T, class U> bool operator>=(const shared_ptr<T>& a, const shared_ptr<U>& b);
19+
// template<class T1, class D1, class T2, class D2>
20+
// requires three_way_comparable_with<typename unique_ptr<T1, D1>::pointer,
21+
// typename unique_ptr<T2, D2>::pointer>
22+
// compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer,
23+
// typename unique_ptr<T2, D2>::pointer>
24+
// operator<=>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
25+
26+
#include <memory>
27+
#include <cassert>
28+
29+
#include "test_macros.h"
30+
#include "test_comparisons.h"
31+
32+
void do_nothing(int*) {}
33+
34+
int main(int, char**) {
35+
AssertComparisonsAreNoexcept<std::shared_ptr<int> >();
36+
AssertComparisonsReturnBool<std::shared_ptr<int> >();
37+
#if TEST_STD_VER > 17
38+
AssertOrderAreNoexcept<std::shared_ptr<int>>();
39+
AssertOrderReturn<std::strong_ordering, std::shared_ptr<int>>();
40+
#endif
41+
42+
int* ptr1(new int);
43+
int* ptr2(new int);
44+
const std::shared_ptr<int> p1(ptr1);
45+
const std::shared_ptr<int> p2(ptr2);
46+
47+
assert(!(p1 == p2));
48+
assert(p1 != p2);
49+
assert((p1 < p2) == (ptr1 < ptr2));
50+
assert((p1 <= p2) == (ptr1 <= ptr2));
51+
assert((p1 > p2) == (ptr1 > ptr2));
52+
assert((p1 >= p2) == (ptr1 >= ptr2));
53+
#if TEST_STD_VER > 17
54+
assert((p1 <=> p2) != std::strong_ordering::equal);
55+
assert((p1 <=> p2) == (ptr1 <=> ptr2));
56+
#endif
57+
58+
// The deleter does not influence the comparisons
59+
// of the `shared_ptr`
60+
const std::shared_ptr<int> p3(ptr2, do_nothing);
61+
assert(p2 == p3);
62+
assert(!(p1 == p3));
63+
assert(!(p2 != p3));
64+
assert(p1 != p3);
65+
assert((p1 < p3) == (ptr1 < ptr2));
66+
assert((p1 <= p3) == (ptr1 <= ptr2));
67+
assert((p1 > p3) == (ptr1 > ptr2));
68+
assert((p1 >= p3) == (ptr1 >= ptr2));
69+
#if TEST_STD_VER > 17
70+
assert((p2 <=> p3) == std::strong_ordering::equal);
71+
assert((p1 <=> p3) != std::strong_ordering::equal);
72+
assert((p1 <=> p3) == (ptr1 <=> ptr2));
73+
#endif
74+
75+
return 0;
76+
}

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

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,39 +34,58 @@
3434
// bool operator>=(const shared_ptr<T>& x, nullptr_t) noexcept;
3535
// template <class T>
3636
// bool operator>=(nullptr_t, const shared_ptr<T>& y) noexcept;
37+
// template<class T>
38+
// strong_ordering operator<=>(shared_ptr<T> const& x, nullptr_t) noexcept; // C++20
3739

3840
#include <memory>
3941
#include <cassert>
4042

4143
#include "test_macros.h"
44+
#include "test_comparisons.h"
4245

4346
void do_nothing(int*) {}
4447

4548
int main(int, char**)
4649
{
47-
const std::shared_ptr<int> p1(new int(1));
48-
assert(!(p1 == nullptr));
49-
assert(!(nullptr == p1));
50-
assert(!(p1 < nullptr));
51-
assert( (nullptr < p1));
52-
assert(!(p1 <= nullptr));
53-
assert( (nullptr <= p1));
54-
assert( (p1 > nullptr));
55-
assert(!(nullptr > p1));
56-
assert( (p1 >= nullptr));
57-
assert(!(nullptr >= p1));
50+
AssertComparisonsAreNoexcept<std::shared_ptr<int>, nullptr_t>();
51+
AssertComparisonsAreNoexcept<nullptr_t, std::shared_ptr<int> >();
52+
AssertComparisonsReturnBool<std::shared_ptr<int>, nullptr_t>();
53+
AssertComparisonsReturnBool<nullptr_t, std::shared_ptr<int> >();
54+
#if TEST_STD_VER > 17
55+
AssertOrderAreNoexcept<std::shared_ptr<int>>();
56+
AssertOrderReturn<std::strong_ordering, std::shared_ptr<int>>();
57+
#endif
5858

59-
const std::shared_ptr<int> p2;
60-
assert( (p2 == nullptr));
61-
assert( (nullptr == p2));
62-
assert(!(p2 < nullptr));
63-
assert(!(nullptr < p2));
64-
assert( (p2 <= nullptr));
65-
assert( (nullptr <= p2));
66-
assert(!(p2 > nullptr));
67-
assert(!(nullptr > p2));
68-
assert( (p2 >= nullptr));
69-
assert( (nullptr >= p2));
59+
const std::shared_ptr<int> p1(new int(1));
60+
assert(!(p1 == nullptr));
61+
assert(!(nullptr == p1));
62+
assert(!(p1 < nullptr));
63+
assert((nullptr < p1));
64+
assert(!(p1 <= nullptr));
65+
assert((nullptr <= p1));
66+
assert((p1 > nullptr));
67+
assert(!(nullptr > p1));
68+
assert((p1 >= nullptr));
69+
assert(!(nullptr >= p1));
70+
#if TEST_STD_VER > 17
71+
assert((nullptr <=> p1) == std::strong_ordering::less);
72+
assert((p1 <=> nullptr) == std::strong_ordering::greater);
73+
#endif
74+
75+
const std::shared_ptr<int> p2;
76+
assert((p2 == nullptr));
77+
assert((nullptr == p2));
78+
assert(!(p2 < nullptr));
79+
assert(!(nullptr < p2));
80+
assert((p2 <= nullptr));
81+
assert((nullptr <= p2));
82+
assert(!(p2 > nullptr));
83+
assert(!(nullptr > p2));
84+
assert((p2 >= nullptr));
85+
assert((nullptr >= p2));
86+
#if TEST_STD_VER > 17
87+
assert((nullptr <=> p2) == std::strong_ordering::equivalent);
88+
#endif
7089

7190
return 0;
7291
}

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

Lines changed: 0 additions & 34 deletions
This file was deleted.

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

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)