Skip to content

Commit 0ddc58a

Browse files
Quuxplusonememfrob
authored andcommitted
[libc++] NFCI: Restore code duplication in wrap_iter, with test.
It turns out that D105040 broke `std::rel_ops`; we actually do need both a one-template-parameter and a two-template-parameter version of all the comparison operators, because if we have only the heterogeneous two-parameter version, then `x > x` is ambiguous: template<class T, class U> int f(S<T>, S<U>) { return 1; } template<class T> int f(T, T) { return 2; } // rel_ops S<int> s; f(s,s); // ambiguous between #1 and #2 Adding the one-template-parameter version fixes the ambiguity: template<class T, class U> int f(S<T>, S<U>) { return 1; } template<class T> int f(T, T) { return 2; } // rel_ops template<class T> int f(S<T>, S<T>) { return 3; } S<int> s; f(s,s); // #3 beats both #1 and #2 We have the same problem with `reverse_iterator` as with `__wrap_iter`. But so do libstdc++ and Microsoft, so we're not going to worry about it. Differential Revision: https://reviews.llvm.org/D105894
1 parent f352994 commit 0ddc58a

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

libcxx/include/__iterator/wrap_iter.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,31 @@ class __wrap_iter
164164
template <class _Tp, size_t> friend class _LIBCPP_TEMPLATE_VIS span;
165165
};
166166

167+
template <class _Iter1>
168+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
169+
bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
170+
{
171+
return __x.base() == __y.base();
172+
}
173+
167174
template <class _Iter1, class _Iter2>
168175
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
169176
bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
170177
{
171178
return __x.base() == __y.base();
172179
}
173180

181+
template <class _Iter1>
182+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
183+
bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
184+
{
185+
#if _LIBCPP_DEBUG_LEVEL == 2
186+
_LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y),
187+
"Attempted to compare incomparable iterators");
188+
#endif
189+
return __x.base() < __y.base();
190+
}
191+
174192
template <class _Iter1, class _Iter2>
175193
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
176194
bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
@@ -182,27 +200,55 @@ bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _
182200
return __x.base() < __y.base();
183201
}
184202

203+
template <class _Iter1>
204+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
205+
bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
206+
{
207+
return !(__x == __y);
208+
}
209+
185210
template <class _Iter1, class _Iter2>
186211
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
187212
bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
188213
{
189214
return !(__x == __y);
190215
}
191216

217+
template <class _Iter1>
218+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
219+
bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
220+
{
221+
return __y < __x;
222+
}
223+
192224
template <class _Iter1, class _Iter2>
193225
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
194226
bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
195227
{
196228
return __y < __x;
197229
}
198230

231+
template <class _Iter1>
232+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
233+
bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
234+
{
235+
return !(__x < __y);
236+
}
237+
199238
template <class _Iter1, class _Iter2>
200239
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
201240
bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
202241
{
203242
return !(__x < __y);
204243
}
205244

245+
template <class _Iter1>
246+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
247+
bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
248+
{
249+
return !(__y < __x);
250+
}
251+
206252
template <class _Iter1, class _Iter2>
207253
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
208254
bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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+
// UNSUPPORTED: libcpp-has-no-filesystem-library
10+
11+
// Make sure the various containers' iterators are not broken by the use of `std::rel_ops`.
12+
13+
#include <utility> // for std::rel_ops
14+
15+
#include <array>
16+
#include <deque>
17+
#include <forward_list>
18+
#include <list>
19+
#include <map>
20+
#include <set>
21+
#include <string>
22+
#include <unordered_map>
23+
#include <unordered_set>
24+
#include <vector>
25+
26+
#include "test_macros.h"
27+
28+
#if TEST_STD_VER >= 11
29+
#include "filesystem_include.h"
30+
#endif
31+
32+
#if TEST_STD_VER >= 17
33+
#include <string_view>
34+
#endif
35+
36+
#if TEST_STD_VER >= 20
37+
#include <span>
38+
#endif
39+
40+
using namespace std::rel_ops;
41+
42+
template<class It, class ConstIt>
43+
void test_eq(It it, ConstIt cit) {
44+
(void)(it == it);
45+
(void)(it != it);
46+
(void)(it == cit);
47+
(void)(it != cit);
48+
(void)(cit == it);
49+
(void)(cit != it);
50+
(void)(cit == cit);
51+
(void)(cit != cit);
52+
}
53+
54+
template<class It, class ConstIt>
55+
void test_lt(It it, ConstIt cit) {
56+
(void)(it < it);
57+
(void)(it <= it);
58+
(void)(it > it);
59+
(void)(it >= it);
60+
(void)(it < cit);
61+
(void)(it <= cit);
62+
(void)(it > cit);
63+
(void)(it >= cit);
64+
(void)(cit < it);
65+
(void)(cit <= it);
66+
(void)(cit > it);
67+
(void)(cit >= it);
68+
(void)(cit < cit);
69+
(void)(cit <= cit);
70+
(void)(cit > cit);
71+
(void)(cit >= cit);
72+
73+
// Test subtraction too, even though std::rel_ops shouldn't affect it.
74+
75+
(void)(it - it);
76+
(void)(it - cit);
77+
(void)(cit - it);
78+
(void)(cit - cit);
79+
}
80+
81+
template<class Container>
82+
void test_forward() {
83+
// There is no need to distinguish "forward" from "bidirectional."
84+
// libc++ already can't handle `c.rbegin() >= c.rbegin()` in the
85+
// presence of std::rel_ops, and neither can Microsoft nor libstdc++.
86+
87+
Container c;
88+
typename Container::iterator it = c.begin();
89+
typename Container::const_iterator cit = c.begin();
90+
test_eq(it, cit);
91+
}
92+
93+
template<class Container>
94+
void test_random_access() {
95+
Container c;
96+
typename Container::iterator it = c.begin();
97+
typename Container::const_iterator cit = c.begin();
98+
test_eq(it, cit);
99+
test_lt(it, cit);
100+
}
101+
102+
template void test_random_access<std::array<int, 10> >();
103+
template void test_random_access<std::deque<int> >();
104+
template void test_forward<std::forward_list<int> >();
105+
template void test_forward<std::list<int> >();
106+
template void test_forward<std::map<int, int> >();
107+
template void test_forward<std::multimap<int, int> >();
108+
template void test_forward<std::multiset<int> >();
109+
template void test_forward<std::set<int> >();
110+
template void test_random_access<std::string>();
111+
template void test_forward<std::unordered_map<int, int> >();
112+
template void test_forward<std::unordered_multimap<int, int> >();
113+
template void test_forward<std::unordered_multiset<int> >();
114+
template void test_forward<std::unordered_set<int> >();
115+
template void test_random_access<std::vector<int> >();
116+
117+
#if TEST_STD_VER >= 11
118+
void test_directory_iterators() {
119+
fs::directory_iterator it;
120+
test_eq(it, it);
121+
122+
fs::recursive_directory_iterator rdit;
123+
test_eq(rdit, rdit);
124+
}
125+
126+
template void test_forward<fs::path>();
127+
#endif
128+
129+
#if TEST_STD_VER >= 17
130+
template void test_random_access<std::string_view>();
131+
#endif
132+
133+
#if TEST_STD_VER >= 20
134+
void test_span() {
135+
std::span<int> c;
136+
std::span<int>::iterator it = c.begin(); // span has no const_iterator
137+
test_eq(it, it);
138+
test_lt(it, it);
139+
}
140+
#endif

0 commit comments

Comments
 (0)