Skip to content

Commit 73c8388

Browse files
[libc++][test] Test flat_meow with proper underlying iterators
Flat container adaptors require the iterators of underlying containers to be random access, and it is required that random access container iterators must support three-way comparison ([container.reqmts]/39 - /41). As a result, we should at least avoid testing "containers" with random access but not three-way comparable iterators for flat container adaptors. This patch adds a new class template `three_way_random_access_iterator` to `test_iterators.h` and fixes some usages of `MinSequenceContainer` with the new iterators.
1 parent 1878259 commit 73c8388

File tree

5 files changed

+210
-88
lines changed

5 files changed

+210
-88
lines changed

libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/iterator_comparison.pass.cpp

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ void test() {
2828
using Key = typename KeyContainer::value_type;
2929
using Value = typename ValueContainer::value_type;
3030
using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
31-
using KI = typename KeyContainer::iterator;
3231
using I = M::iterator;
3332
using CI = M::const_iterator;
3433
using RI = M::reverse_iterator;
@@ -115,34 +114,32 @@ void test() {
115114
assert(cri2 >= cri2);
116115
assert(!(cri1 >= cri2));
117116

118-
if constexpr (std::three_way_comparable<KI>) {
119-
static_assert(std::three_way_comparable<I>); // ...of course the wrapped iterators still support <=>.
120-
static_assert(std::three_way_comparable<CI>);
121-
static_assert(std::three_way_comparable<RI>);
122-
static_assert(std::three_way_comparable<CRI>);
123-
static_assert(std::same_as<decltype(I() <=> I()), std::strong_ordering>);
124-
static_assert(std::same_as<decltype(I() <=> CI()), std::strong_ordering>);
125-
static_assert(std::same_as<decltype(CI() <=> CI()), std::strong_ordering>);
126-
static_assert(std::same_as<decltype(RI() <=> RI()), std::strong_ordering>);
127-
static_assert(std::same_as<decltype(RI() <=> CRI()), std::strong_ordering>);
128-
static_assert(std::same_as<decltype(CRI() <=> CRI()), std::strong_ordering>);
129-
130-
assert(i1 <=> i1 == std::strong_ordering::equivalent);
131-
assert(i1 <=> i2 == std::strong_ordering::less);
132-
assert(i2 <=> i1 == std::strong_ordering::greater);
133-
134-
assert(ci1 <=> ci1 == std::strong_ordering::equivalent);
135-
assert(ci1 <=> ci2 == std::strong_ordering::less);
136-
assert(ci2 <=> ci1 == std::strong_ordering::greater);
137-
138-
assert(ri1 <=> ri1 == std::strong_ordering::equivalent);
139-
assert(ri1 <=> ri2 == std::strong_ordering::less);
140-
assert(ri2 <=> ri1 == std::strong_ordering::greater);
141-
142-
assert(cri1 <=> cri1 == std::strong_ordering::equivalent);
143-
assert(cri1 <=> cri2 == std::strong_ordering::less);
144-
assert(cri2 <=> cri1 == std::strong_ordering::greater);
145-
}
117+
static_assert(std::three_way_comparable<I>); // ...of course the wrapped iterators still support <=>.
118+
static_assert(std::three_way_comparable<CI>);
119+
static_assert(std::three_way_comparable<RI>);
120+
static_assert(std::three_way_comparable<CRI>);
121+
static_assert(std::same_as<decltype(I() <=> I()), std::strong_ordering>);
122+
static_assert(std::same_as<decltype(I() <=> CI()), std::strong_ordering>);
123+
static_assert(std::same_as<decltype(CI() <=> CI()), std::strong_ordering>);
124+
static_assert(std::same_as<decltype(RI() <=> RI()), std::strong_ordering>);
125+
static_assert(std::same_as<decltype(RI() <=> CRI()), std::strong_ordering>);
126+
static_assert(std::same_as<decltype(CRI() <=> CRI()), std::strong_ordering>);
127+
128+
assert(i1 <=> i1 == std::strong_ordering::equivalent);
129+
assert(i1 <=> i2 == std::strong_ordering::less);
130+
assert(i2 <=> i1 == std::strong_ordering::greater);
131+
132+
assert(ci1 <=> ci1 == std::strong_ordering::equivalent);
133+
assert(ci1 <=> ci2 == std::strong_ordering::less);
134+
assert(ci2 <=> ci1 == std::strong_ordering::greater);
135+
136+
assert(ri1 <=> ri1 == std::strong_ordering::equivalent);
137+
assert(ri1 <=> ri2 == std::strong_ordering::less);
138+
assert(ri2 <=> ri1 == std::strong_ordering::greater);
139+
140+
assert(cri1 <=> cri1 == std::strong_ordering::equivalent);
141+
assert(cri1 <=> cri2 == std::strong_ordering::less);
142+
assert(cri2 <=> cri1 == std::strong_ordering::greater);
146143
}
147144

148145
int main(int, char**) {

libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.iterators/iterator_comparison.pass.cpp

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ void test() {
2828
using Key = typename KeyContainer::value_type;
2929
using Value = typename ValueContainer::value_type;
3030
using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
31-
using KI = typename KeyContainer::iterator;
3231
using I = M::iterator;
3332
using CI = M::const_iterator;
3433
using RI = M::reverse_iterator;
@@ -115,34 +114,32 @@ void test() {
115114
assert(cri2 >= cri2);
116115
assert(!(cri1 >= cri2));
117116

118-
if constexpr (std::three_way_comparable<KI>) {
119-
static_assert(std::three_way_comparable<I>); // ...of course the wrapped iterators still support <=>.
120-
static_assert(std::three_way_comparable<CI>);
121-
static_assert(std::three_way_comparable<RI>);
122-
static_assert(std::three_way_comparable<CRI>);
123-
static_assert(std::same_as<decltype(I() <=> I()), std::strong_ordering>);
124-
static_assert(std::same_as<decltype(I() <=> CI()), std::strong_ordering>);
125-
static_assert(std::same_as<decltype(CI() <=> CI()), std::strong_ordering>);
126-
static_assert(std::same_as<decltype(RI() <=> RI()), std::strong_ordering>);
127-
static_assert(std::same_as<decltype(RI() <=> CRI()), std::strong_ordering>);
128-
static_assert(std::same_as<decltype(CRI() <=> CRI()), std::strong_ordering>);
129-
130-
assert(i1 <=> i1 == std::strong_ordering::equivalent);
131-
assert(i1 <=> i2 == std::strong_ordering::less);
132-
assert(i2 <=> i1 == std::strong_ordering::greater);
133-
134-
assert(ci1 <=> ci1 == std::strong_ordering::equivalent);
135-
assert(ci1 <=> ci2 == std::strong_ordering::less);
136-
assert(ci2 <=> ci1 == std::strong_ordering::greater);
137-
138-
assert(ri1 <=> ri1 == std::strong_ordering::equivalent);
139-
assert(ri1 <=> ri2 == std::strong_ordering::less);
140-
assert(ri2 <=> ri1 == std::strong_ordering::greater);
141-
142-
assert(cri1 <=> cri1 == std::strong_ordering::equivalent);
143-
assert(cri1 <=> cri2 == std::strong_ordering::less);
144-
assert(cri2 <=> cri1 == std::strong_ordering::greater);
145-
}
117+
static_assert(std::three_way_comparable<I>); // ...of course the wrapped iterators still support <=>.
118+
static_assert(std::three_way_comparable<CI>);
119+
static_assert(std::three_way_comparable<RI>);
120+
static_assert(std::three_way_comparable<CRI>);
121+
static_assert(std::same_as<decltype(I() <=> I()), std::strong_ordering>);
122+
static_assert(std::same_as<decltype(I() <=> CI()), std::strong_ordering>);
123+
static_assert(std::same_as<decltype(CI() <=> CI()), std::strong_ordering>);
124+
static_assert(std::same_as<decltype(RI() <=> RI()), std::strong_ordering>);
125+
static_assert(std::same_as<decltype(RI() <=> CRI()), std::strong_ordering>);
126+
static_assert(std::same_as<decltype(CRI() <=> CRI()), std::strong_ordering>);
127+
128+
assert(i1 <=> i1 == std::strong_ordering::equivalent);
129+
assert(i1 <=> i2 == std::strong_ordering::less);
130+
assert(i2 <=> i1 == std::strong_ordering::greater);
131+
132+
assert(ci1 <=> ci1 == std::strong_ordering::equivalent);
133+
assert(ci1 <=> ci2 == std::strong_ordering::less);
134+
assert(ci2 <=> ci1 == std::strong_ordering::greater);
135+
136+
assert(ri1 <=> ri1 == std::strong_ordering::equivalent);
137+
assert(ri1 <=> ri2 == std::strong_ordering::less);
138+
assert(ri2 <=> ri1 == std::strong_ordering::greater);
139+
140+
assert(cri1 <=> cri1 == std::strong_ordering::equivalent);
141+
assert(cri1 <=> cri2 == std::strong_ordering::less);
142+
assert(cri2 <=> cri1 == std::strong_ordering::greater);
146143
}
147144

148145
int main(int, char**) {

libcxx/test/std/containers/container.adaptors/flat.set/flat.set.iterators/iterator_comparison.pass.cpp

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ template <class KeyContainer>
2727
void test_one() {
2828
using Key = typename KeyContainer::value_type;
2929
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
30-
using KI = typename KeyContainer::iterator;
3130
using I = M::iterator;
3231
using CI = M::const_iterator;
3332
using RI = M::reverse_iterator;
@@ -114,34 +113,32 @@ void test_one() {
114113
assert(cri2 >= cri2);
115114
assert(!(cri1 >= cri2));
116115

117-
if constexpr (std::three_way_comparable<KI>) {
118-
static_assert(std::three_way_comparable<I>); // ...of course the wrapped iterators still support <=>.
119-
static_assert(std::three_way_comparable<CI>);
120-
static_assert(std::three_way_comparable<RI>);
121-
static_assert(std::three_way_comparable<CRI>);
122-
static_assert(std::same_as<decltype(I() <=> I()), std::strong_ordering>);
123-
static_assert(std::same_as<decltype(I() <=> CI()), std::strong_ordering>);
124-
static_assert(std::same_as<decltype(CI() <=> CI()), std::strong_ordering>);
125-
static_assert(std::same_as<decltype(RI() <=> RI()), std::strong_ordering>);
126-
static_assert(std::same_as<decltype(RI() <=> CRI()), std::strong_ordering>);
127-
static_assert(std::same_as<decltype(CRI() <=> CRI()), std::strong_ordering>);
128-
129-
assert(i1 <=> i1 == std::strong_ordering::equivalent);
130-
assert(i1 <=> i2 == std::strong_ordering::less);
131-
assert(i2 <=> i1 == std::strong_ordering::greater);
132-
133-
assert(ci1 <=> ci1 == std::strong_ordering::equivalent);
134-
assert(ci1 <=> ci2 == std::strong_ordering::less);
135-
assert(ci2 <=> ci1 == std::strong_ordering::greater);
136-
137-
assert(ri1 <=> ri1 == std::strong_ordering::equivalent);
138-
assert(ri1 <=> ri2 == std::strong_ordering::less);
139-
assert(ri2 <=> ri1 == std::strong_ordering::greater);
140-
141-
assert(cri1 <=> cri1 == std::strong_ordering::equivalent);
142-
assert(cri1 <=> cri2 == std::strong_ordering::less);
143-
assert(cri2 <=> cri1 == std::strong_ordering::greater);
144-
}
116+
static_assert(std::three_way_comparable<I>); // ...of course the wrapped iterators still support <=>.
117+
static_assert(std::three_way_comparable<CI>);
118+
static_assert(std::three_way_comparable<RI>);
119+
static_assert(std::three_way_comparable<CRI>);
120+
static_assert(std::same_as<decltype(I() <=> I()), std::strong_ordering>);
121+
static_assert(std::same_as<decltype(I() <=> CI()), std::strong_ordering>);
122+
static_assert(std::same_as<decltype(CI() <=> CI()), std::strong_ordering>);
123+
static_assert(std::same_as<decltype(RI() <=> RI()), std::strong_ordering>);
124+
static_assert(std::same_as<decltype(RI() <=> CRI()), std::strong_ordering>);
125+
static_assert(std::same_as<decltype(CRI() <=> CRI()), std::strong_ordering>);
126+
127+
assert(i1 <=> i1 == std::strong_ordering::equivalent);
128+
assert(i1 <=> i2 == std::strong_ordering::less);
129+
assert(i2 <=> i1 == std::strong_ordering::greater);
130+
131+
assert(ci1 <=> ci1 == std::strong_ordering::equivalent);
132+
assert(ci1 <=> ci2 == std::strong_ordering::less);
133+
assert(ci2 <=> ci1 == std::strong_ordering::greater);
134+
135+
assert(ri1 <=> ri1 == std::strong_ordering::equivalent);
136+
assert(ri1 <=> ri2 == std::strong_ordering::less);
137+
assert(ri2 <=> ri1 == std::strong_ordering::greater);
138+
139+
assert(cri1 <=> cri1 == std::strong_ordering::equivalent);
140+
assert(cri1 <=> cri2 == std::strong_ordering::less);
141+
assert(cri2 <=> cri1 == std::strong_ordering::greater);
145142
}
146143

147144
void test() {

libcxx/test/support/MinSequenceContainer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
#include "test_iterators.h"
1616

17-
template <class T, class Iterator = random_access_iterator<T*>, class ConstIterator = random_access_iterator<const T*>>
17+
template <class T,
18+
class Iterator = three_way_random_access_iterator<T*>,
19+
class ConstIterator = three_way_random_access_iterator<const T*>>
1820
struct MinSequenceContainer {
1921
using value_type = T;
2022
using difference_type = int;

libcxx/test/support/test_iterators.h

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,135 @@ template <class It>
267267
random_access_iterator(It) -> random_access_iterator<It>;
268268
#endif
269269

270+
// Since C++20, a container iterator type that is random access is also required to support three-way comparison.
271+
// See C++20 [tab:container.req], C++23 [container.reqmts]/39 - /41.
272+
template <class It>
273+
class three_way_random_access_iterator {
274+
It it_;
275+
support::double_move_tracker tracker_;
276+
277+
template <class U>
278+
friend class three_way_random_access_iterator;
279+
280+
public:
281+
typedef std::random_access_iterator_tag iterator_category;
282+
typedef typename std::iterator_traits<It>::value_type value_type;
283+
typedef typename std::iterator_traits<It>::difference_type difference_type;
284+
typedef It pointer;
285+
typedef typename std::iterator_traits<It>::reference reference;
286+
287+
TEST_CONSTEXPR three_way_random_access_iterator() : it_() {}
288+
TEST_CONSTEXPR explicit three_way_random_access_iterator(It it) : it_(it) {}
289+
290+
template <class U>
291+
TEST_CONSTEXPR three_way_random_access_iterator(const three_way_random_access_iterator<U>& u)
292+
: it_(u.it_), tracker_(u.tracker_) {}
293+
294+
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
295+
TEST_CONSTEXPR_CXX14 three_way_random_access_iterator(three_way_random_access_iterator<U>&& u)
296+
: it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) {
297+
u.it_ = U();
298+
}
299+
300+
TEST_CONSTEXPR_CXX14 reference operator*() const { return *it_; }
301+
TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const { return it_[n]; }
302+
303+
TEST_CONSTEXPR_CXX14 three_way_random_access_iterator& operator++() {
304+
++it_;
305+
return *this;
306+
}
307+
TEST_CONSTEXPR_CXX14 three_way_random_access_iterator& operator--() {
308+
--it_;
309+
return *this;
310+
}
311+
TEST_CONSTEXPR_CXX14 three_way_random_access_iterator operator++(int) {
312+
return three_way_random_access_iterator(it_++);
313+
}
314+
TEST_CONSTEXPR_CXX14 three_way_random_access_iterator operator--(int) {
315+
return three_way_random_access_iterator(it_--);
316+
}
317+
318+
TEST_CONSTEXPR_CXX14 three_way_random_access_iterator& operator+=(difference_type n) {
319+
it_ += n;
320+
return *this;
321+
}
322+
TEST_CONSTEXPR_CXX14 three_way_random_access_iterator& operator-=(difference_type n) {
323+
it_ -= n;
324+
return *this;
325+
}
326+
friend TEST_CONSTEXPR_CXX14 three_way_random_access_iterator
327+
operator+(three_way_random_access_iterator x, difference_type n) {
328+
x += n;
329+
return x;
330+
}
331+
friend TEST_CONSTEXPR_CXX14 three_way_random_access_iterator
332+
operator+(difference_type n, three_way_random_access_iterator x) {
333+
x += n;
334+
return x;
335+
}
336+
friend TEST_CONSTEXPR_CXX14 three_way_random_access_iterator
337+
operator-(three_way_random_access_iterator x, difference_type n) {
338+
x -= n;
339+
return x;
340+
}
341+
friend TEST_CONSTEXPR difference_type
342+
operator-(three_way_random_access_iterator x, three_way_random_access_iterator y) {
343+
return x.it_ - y.it_;
344+
}
345+
346+
friend TEST_CONSTEXPR bool
347+
operator==(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) {
348+
return x.it_ == y.it_;
349+
}
350+
#if TEST_STD_VER < 20
351+
friend TEST_CONSTEXPR bool
352+
operator!=(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) {
353+
return x.it_ != y.it_;
354+
}
355+
#endif
356+
friend TEST_CONSTEXPR bool
357+
operator<(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) {
358+
return x.it_ < y.it_;
359+
}
360+
friend TEST_CONSTEXPR bool
361+
operator<=(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) {
362+
return x.it_ <= y.it_;
363+
}
364+
friend TEST_CONSTEXPR bool
365+
operator>(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) {
366+
return x.it_ > y.it_;
367+
}
368+
friend TEST_CONSTEXPR bool
369+
operator>=(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) {
370+
return x.it_ >= y.it_;
371+
}
372+
#if TEST_STD_VER >= 20
373+
friend constexpr std::strong_ordering
374+
operator<=>(const three_way_random_access_iterator& x, const three_way_random_access_iterator& y) {
375+
if constexpr (std::three_way_comparable<It>) {
376+
return x.it_ <=> y.it_;
377+
} else {
378+
if (x.it_ < y.it_) {
379+
return std::strong_ordering::less;
380+
} else if (y.it_ < x.it_) {
381+
return std::strong_ordering::greater;
382+
} else {
383+
return std::strong_ordering::equal;
384+
}
385+
}
386+
}
387+
#endif
388+
389+
friend TEST_CONSTEXPR It base(const three_way_random_access_iterator& i) { return i.it_; }
390+
391+
template <class T>
392+
void operator,(T const&) = delete;
393+
};
394+
#if TEST_STD_VER > 14
395+
template <class It>
396+
three_way_random_access_iterator(It) -> three_way_random_access_iterator<It>;
397+
#endif
398+
270399
#if TEST_STD_VER > 17
271400

272401
template <std::random_access_iterator It>

0 commit comments

Comments
 (0)