Skip to content

Commit 456668e

Browse files
committed
[libc++][spaceship] Implements X::iterator container requirements. (#99343)
This implements the requirements for the container iterator requirements for array, deque, vector, and `vector<bool>`. Implements: - LWG3352 strong_equality isn't a thing Implements parts of: - P1614R2 The Mothership has Landed Fixes: #62486
1 parent 7af27be commit 456668e

File tree

14 files changed

+413
-7
lines changed

14 files changed

+413
-7
lines changed

libcxx/docs/Status/Cxx20Issues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@
264264
"`3349 <https://wg21.link/LWG3349>`__","Missing ``__cpp_lib_constexpr_complex``\ for P0415R1","Prague","|Complete|","16.0"
265265
"`3350 <https://wg21.link/LWG3350>`__","Simplify return type of ``lexicographical_compare_three_way``\ ","Prague","|Complete|","17.0","|spaceship|"
266266
"`3351 <https://wg21.link/LWG3351>`__","``ranges::enable_safe_range``\ should not be constrained","Prague","|Complete|","15.0","|ranges|"
267-
"`3352 <https://wg21.link/LWG3352>`__","``strong_equality``\ isn't a thing","Prague","|Nothing To Do|","","|spaceship|"
267+
"`3352 <https://wg21.link/LWG3352>`__","``strong_equality``\ isn't a thing","Prague","|Complete|","19.0","|spaceship|"
268268
"`3354 <https://wg21.link/LWG3354>`__","``has_strong_structural_equality``\ has a meaningless definition","Prague","|Nothing To Do|","","|spaceship|"
269269
"`3355 <https://wg21.link/LWG3355>`__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|"
270270
"`3356 <https://wg21.link/LWG3356>`__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0"

libcxx/docs/Status/SpaceshipProjects.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Section,Description,Dependencies,Assignee,Complete
8383
"| `[string.view.synop] <https://wg21.link/string.view.synop>`_
8484
| `[string.view.comparison] <https://wg21.link/string.view.comparison>`_",| `basic_string_view <https://reviews.llvm.org/D130295>`_,None,Mark de Wever,|Complete|
8585
- `5.7 Clause 22: Containers library <https://wg21.link/p1614r2#clause-22-containers-library>`_,,,,
86-
| `[container.requirements.general] <https://wg21.link/container.requirements.general>`_,|,None,Unassigned,|Not Started|
86+
| `[container.requirements.general] <https://wg21.link/container.requirements.general>`_,|,None,Mark de Wever,|Complete|
8787
| `[array.syn] <https://wg21.link/array.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `array <https://reviews.llvm.org/D132265>`_,[expos.only.func],"| Adrian Vogelsgesang
8888
| Hristo Hristov",|Complete|
8989
| `[deque.syn] <https://wg21.link/deque.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `deque <https://reviews.llvm.org/D144821>`_,[expos.only.func],Hristo Hristov,|Complete|

libcxx/include/__bit_reference

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <__bit/countr.h>
1717
#include <__bit/invert_if.h>
1818
#include <__bit/popcount.h>
19+
#include <__compare/ordering.h>
1920
#include <__config>
2021
#include <__fwd/bit_reference.h>
2122
#include <__iterator/iterator_traits.h>
@@ -913,6 +914,7 @@ public:
913914
return __x.__seg_ == __y.__seg_ && __x.__ctz_ == __y.__ctz_;
914915
}
915916

917+
#if _LIBCPP_STD_VER <= 17
916918
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool
917919
operator!=(const __bit_iterator& __x, const __bit_iterator& __y) {
918920
return !(__x == __y);
@@ -937,6 +939,18 @@ public:
937939
operator>=(const __bit_iterator& __x, const __bit_iterator& __y) {
938940
return !(__x < __y);
939941
}
942+
#else // _LIBCPP_STD_VER <= 17
943+
_LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering
944+
operator<=>(const __bit_iterator& __x, const __bit_iterator& __y) {
945+
if (__x.__seg_ < __y.__seg_)
946+
return strong_ordering::less;
947+
948+
if (__x.__seg_ == __y.__seg_)
949+
return __x.__ctz_ <=> __y.__ctz_;
950+
951+
return strong_ordering::greater;
952+
}
953+
#endif // _LIBCPP_STD_VER <= 17
940954

941955
private:
942956
_LIBCPP_HIDE_FROM_ABI

libcxx/include/__iterator/bounded_iter.h

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

1313
#include <__assert>
14+
#include <__compare/ordering.h>
15+
#include <__compare/three_way_comparable.h>
1416
#include <__config>
1517
#include <__iterator/iterator_traits.h>
1618
#include <__memory/pointer_traits.h>
@@ -201,10 +203,15 @@ struct __bounded_iter {
201203
operator==(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
202204
return __x.__current_ == __y.__current_;
203205
}
206+
207+
#if _LIBCPP_STD_VER <= 17
204208
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
205209
operator!=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
206210
return __x.__current_ != __y.__current_;
207211
}
212+
#endif
213+
214+
// TODO(mordante) disable these overloads in the LLVM 20 release.
208215
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
209216
operator<(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
210217
return __x.__current_ < __y.__current_;
@@ -222,6 +229,23 @@ struct __bounded_iter {
222229
return __x.__current_ >= __y.__current_;
223230
}
224231

232+
#if _LIBCPP_STD_VER >= 20
233+
_LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering
234+
operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept {
235+
if constexpr (three_way_comparable<_Iterator, strong_ordering>) {
236+
return __x.__current_ <=> __y.__current_;
237+
} else {
238+
if (__x.__current_ < __y.__current_)
239+
return strong_ordering::less;
240+
241+
if (__x.__current_ == __y.__current_)
242+
return strong_ordering::equal;
243+
244+
return strong_ordering::greater;
245+
}
246+
}
247+
#endif // _LIBCPP_STD_VER >= 20
248+
225249
private:
226250
template <class>
227251
friend struct pointer_traits;

libcxx/include/__iterator/wrap_iter.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#ifndef _LIBCPP___ITERATOR_WRAP_ITER_H
1111
#define _LIBCPP___ITERATOR_WRAP_ITER_H
1212

13+
#include <__compare/ordering.h>
14+
#include <__compare/three_way_comparable.h>
1315
#include <__config>
1416
#include <__iterator/iterator_traits.h>
1517
#include <__memory/addressof.h>
@@ -131,6 +133,7 @@ operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC
131133
return __x.base() < __y.base();
132134
}
133135

136+
#if _LIBCPP_STD_VER <= 17
134137
template <class _Iter1>
135138
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
136139
operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
@@ -142,7 +145,9 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
142145
operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
143146
return !(__x == __y);
144147
}
148+
#endif
145149

150+
// TODO(mordante) disable these overloads in the LLVM 20 release.
146151
template <class _Iter1>
147152
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
148153
operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
@@ -179,6 +184,24 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX
179184
return !(__y < __x);
180185
}
181186

187+
#if _LIBCPP_STD_VER >= 20
188+
template <class _Iter1, class _Iter2>
189+
_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering
190+
operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept {
191+
if constexpr (three_way_comparable_with<_Iter1, _Iter2, strong_ordering>) {
192+
return __x.base() <=> __y.base();
193+
} else {
194+
if (__x.base() < __y.base())
195+
return strong_ordering::less;
196+
197+
if (__x.base() == __y.base())
198+
return strong_ordering::equal;
199+
200+
return strong_ordering::greater;
201+
}
202+
}
203+
#endif // _LIBCPP_STD_VER >= 20
204+
182205
template <class _Iter1, class _Iter2>
183206
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
184207
#ifndef _LIBCPP_CXX03_LANG

libcxx/include/deque

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,10 +376,13 @@ public:
376376
return __x.__ptr_ == __y.__ptr_;
377377
}
378378

379+
#if _LIBCPP_STD_VER <= 17
379380
_LIBCPP_HIDE_FROM_ABI friend bool operator!=(const __deque_iterator& __x, const __deque_iterator& __y) {
380381
return !(__x == __y);
381382
}
383+
#endif
382384

385+
// TODO(mordante) disable these overloads in the LLVM 20 release.
383386
_LIBCPP_HIDE_FROM_ABI friend bool operator<(const __deque_iterator& __x, const __deque_iterator& __y) {
384387
return __x.__m_iter_ < __y.__m_iter_ || (__x.__m_iter_ == __y.__m_iter_ && __x.__ptr_ < __y.__ptr_);
385388
}
@@ -396,6 +399,29 @@ public:
396399
return !(__x < __y);
397400
}
398401

402+
#if _LIBCPP_STD_VER >= 20
403+
_LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) {
404+
if (__x.__m_iter_ < __y.__m_iter_)
405+
return strong_ordering::less;
406+
407+
if (__x.__m_iter_ == __y.__m_iter_) {
408+
if constexpr (three_way_comparable<pointer, strong_ordering>) {
409+
return __x.__ptr_ <=> __y.__ptr_;
410+
} else {
411+
if (__x.__ptr_ < __y.__ptr_)
412+
return strong_ordering::less;
413+
414+
if (__x.__ptr_ == __y.__ptr_)
415+
return strong_ordering::equal;
416+
417+
return strong_ordering::greater;
418+
}
419+
}
420+
421+
return strong_ordering::greater;
422+
}
423+
#endif // _LIBCPP_STD_VER >= 20
424+
399425
private:
400426
_LIBCPP_HIDE_FROM_ABI explicit __deque_iterator(__map_iterator __m, pointer __p) _NOEXCEPT
401427
: __m_iter_(__m),
@@ -2530,8 +2556,7 @@ inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const deque<_Tp, _Allocator>& __x,
25302556
template <class _Tp, class _Allocator>
25312557
_LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Tp>
25322558
operator<=>(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y) {
2533-
return std::lexicographical_compare_three_way(
2534-
__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
2559+
return std::lexicographical_compare_three_way(__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
25352560
}
25362561

25372562
#endif // _LIBCPP_STD_VER <= 17

libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//
1212
// Comparison operators
1313

14+
#include <concepts>
1415
#include <__iterator/bounded_iter.h>
1516

1617
#include "test_iterators.h"
@@ -59,6 +60,12 @@ TEST_CONSTEXPR_CXX14 bool tests() {
5960
assert(iter1 >= iter1);
6061
}
6162

63+
#if TEST_STD_VER >= 20
64+
// P1614
65+
std::same_as<std::strong_ordering> decltype(auto) r1 = iter1 <=> iter2;
66+
assert(r1 == std::strong_ordering::less);
67+
#endif
68+
6269
return true;
6370
}
6471

@@ -69,8 +76,11 @@ int main(int, char**) {
6976
#endif
7077

7178
#if TEST_STD_VER > 17
72-
tests<contiguous_iterator<int*> >();
73-
static_assert(tests<contiguous_iterator<int*> >(), "");
79+
tests<contiguous_iterator<int*>>();
80+
static_assert(tests<contiguous_iterator<int*>>());
81+
82+
tests<three_way_contiguous_iterator<int*>>();
83+
static_assert(tests<three_way_contiguous_iterator<int*>>());
7484
#endif
7585

7686
return 0;

libcxx/test/std/containers/sequences/array/iterators.pass.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,15 @@ TEST_CONSTEXPR_CXX17 bool tests()
148148
assert(std::rbegin(c) != std::rend(c));
149149
assert(std::cbegin(c) != std::cend(c));
150150
assert(std::crbegin(c) != std::crend(c));
151+
152+
# if TEST_STD_VER >= 20
153+
// P1614 + LWG3352
154+
std::same_as<std::strong_ordering> decltype(auto) r1 = ii1 <=> ii2;
155+
assert(r1 == std::strong_ordering::equal);
156+
157+
std::same_as<std::strong_ordering> decltype(auto) r2 = cii <=> ii2;
158+
assert(r2 == std::strong_ordering::equal);
159+
# endif
151160
}
152161
{
153162
typedef std::array<int, 0> C;
@@ -189,6 +198,15 @@ TEST_CONSTEXPR_CXX17 bool tests()
189198
assert(std::rbegin(c) == std::rend(c));
190199
assert(std::cbegin(c) == std::cend(c));
191200
assert(std::crbegin(c) == std::crend(c));
201+
202+
# if TEST_STD_VER >= 20
203+
// P1614 + LWG3352
204+
std::same_as<std::strong_ordering> decltype(auto) r1 = ii1 <=> ii2;
205+
assert(r1 == std::strong_ordering::equal);
206+
207+
std::same_as<std::strong_ordering> decltype(auto) r2 = cii <=> ii2;
208+
assert(r2 == std::strong_ordering::equal);
209+
# endif
192210
}
193211
}
194212
#endif

libcxx/test/std/containers/sequences/deque/iterators.pass.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,27 @@ int main(int, char**)
4141
i = c.begin();
4242
C::const_iterator j;
4343
j = c.cbegin();
44+
4445
assert(i == j);
46+
assert(!(i != j));
47+
48+
assert(!(i < j));
49+
assert((i <= j));
50+
51+
assert(!(i > j));
52+
assert((i >= j));
53+
54+
# if TEST_STD_VER >= 20
55+
// P1614 + LWG3352
56+
// When the allocator does not have operator<=> then the iterator uses a
57+
// fallback to provide operator<=>.
58+
// Make sure to test with an allocator that does not have operator<=>.
59+
static_assert(!std::three_way_comparable<min_allocator<int>, std::strong_ordering>);
60+
static_assert(std::three_way_comparable<typename C::iterator, std::strong_ordering>);
61+
62+
std::same_as<std::strong_ordering> decltype(auto) r1 = i <=> j;
63+
assert(r1 == std::strong_ordering::equal);
64+
# endif
4565
}
4666
#endif
4767
#if TEST_STD_VER > 11
@@ -74,6 +94,15 @@ int main(int, char**)
7494
// assert ( cii != c.begin());
7595
// assert ( cii != c.cend());
7696
// assert ( ii1 != c.end());
97+
98+
# if TEST_STD_VER >= 20
99+
// P1614 + LWG3352
100+
std::same_as<std::strong_ordering> decltype(auto) r1 = ii1 <=> ii2;
101+
assert(r1 == std::strong_ordering::equal);
102+
103+
std::same_as<std::strong_ordering> decltype(auto) r2 = cii <=> ii2;
104+
assert(r2 == std::strong_ordering::equal);
105+
# endif // TEST_STD_VER > 20
77106
}
78107
#endif
79108

libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,21 @@ TEST_CONSTEXPR_CXX20 bool tests()
7777
C::iterator i = c.begin();
7878
C::iterator j = c.end();
7979
assert(std::distance(i, j) == 0);
80+
8081
assert(i == j);
82+
assert(!(i != j));
83+
84+
assert(!(i < j));
85+
assert((i <= j));
86+
87+
assert(!(i > j));
88+
assert((i >= j));
89+
90+
# if TEST_STD_VER >= 20
91+
// P1614 + LWG3352
92+
std::same_as<std::strong_ordering> decltype(auto) r = i <=> j;
93+
assert(r == std::strong_ordering::equal);
94+
# endif
8195
}
8296
{
8397
typedef bool T;
@@ -86,7 +100,21 @@ TEST_CONSTEXPR_CXX20 bool tests()
86100
C::const_iterator i = c.begin();
87101
C::const_iterator j = c.end();
88102
assert(std::distance(i, j) == 0);
103+
89104
assert(i == j);
105+
assert(!(i != j));
106+
107+
assert(!(i < j));
108+
assert((i <= j));
109+
110+
assert(!(i > j));
111+
assert((i >= j));
112+
113+
# if TEST_STD_VER >= 20
114+
// P1614 + LWG3352
115+
std::same_as<std::strong_ordering> decltype(auto) r = i <=> j;
116+
assert(r == std::strong_ordering::equal);
117+
# endif
90118
}
91119
{
92120
typedef bool T;
@@ -131,6 +159,15 @@ TEST_CONSTEXPR_CXX20 bool tests()
131159
assert ( (cii >= ii1 ));
132160
assert (cii - ii1 == 0);
133161
assert (ii1 - cii == 0);
162+
163+
# if TEST_STD_VER >= 20
164+
// P1614 + LWG3352
165+
std::same_as<std::strong_ordering> decltype(auto) r1 = ii1 <=> ii2;
166+
assert(r1 == std::strong_ordering::equal);
167+
168+
std::same_as<std::strong_ordering> decltype(auto) r2 = cii <=> ii2;
169+
assert(r2 == std::strong_ordering::equal);
170+
# endif // TEST_STD_VER > 20
134171
}
135172
#endif
136173

0 commit comments

Comments
 (0)