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: c++03, c++11, c++14, c++17
10
11 // friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y);
12 //
13 // template<bool OtherConst = !Const>
14 // requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
15 // friend constexpr bool operator==(const iterator_t<maybe-const<OtherConst, V>>& x,
16 // const sentinel& y);
17
18 #include <array>
19 #include <cassert>
20 #include <ranges>
21
22 #include "../types.h"
23
24 template <bool Const>
25 struct Iter {
26 int* it_;
27
28 using value_type = int;
29 using difference_type = std::intptr_t;
30 using iterator_concept = std::input_iterator_tag;
31
operator *Iter32 constexpr decltype(auto) operator*() const { return *it_; }
operator ++Iter33 constexpr Iter& operator++() {
34 ++it_;
35 return *this;
36 }
operator ++Iter37 constexpr void operator++(int) { ++it_; }
38 };
39
40 template <bool Const>
41 struct Sent {
42 int* end_;
43
operator ==Sent44 constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
45 };
46
47 template <bool Const>
48 struct CrossComparableSent {
49 int* end_;
50
51 template <bool C>
operator ==CrossComparableSent52 constexpr bool operator==(const Iter<C>& i) const {
53 return i.it_ == end_;
54 }
55 };
56
57 template <template <bool> typename St>
58 struct Range : IntBufferViewBase {
59 using IntBufferViewBase::IntBufferViewBase;
beginRange60 constexpr Iter<false> begin() { return Iter<false>{buffer_}; }
beginRange61 constexpr Iter<true> begin() const { return Iter<true>{buffer_}; }
endRange62 constexpr St<false> end() { return St<false>{buffer_ + size_}; }
endRange63 constexpr St<true> end() const { return St<true>{buffer_ + size_}; }
64 };
65
66 using R = Range<Sent>;
67 using CrossComparableR = Range<CrossComparableSent>;
68
69 struct LessThan3 {
operator ()LessThan370 constexpr bool operator()(int i) const { return i < 3; }
71 };
72
73 using std::ranges::iterator_t;
74 using std::ranges::sentinel_t;
75 using std::ranges::take_while_view;
76
77 static_assert(weakly_equality_comparable_with<iterator_t<take_while_view<R, LessThan3>>, //
78 sentinel_t<take_while_view<R, LessThan3>>>);
79
80 static_assert(!weakly_equality_comparable_with<iterator_t<const take_while_view<R, LessThan3>>, //
81 sentinel_t<take_while_view<R, LessThan3>>>);
82
83 static_assert(!weakly_equality_comparable_with<iterator_t<take_while_view<R, LessThan3>>, //
84 sentinel_t<const take_while_view<R, LessThan3>>>);
85
86 static_assert(weakly_equality_comparable_with<iterator_t<const take_while_view<R, LessThan3>>, //
87 sentinel_t<const take_while_view<R, LessThan3>>>);
88
89 static_assert(weakly_equality_comparable_with<iterator_t<take_while_view<CrossComparableR, LessThan3>>, //
90 sentinel_t<take_while_view<CrossComparableR, LessThan3>>>);
91
92 static_assert(weakly_equality_comparable_with<iterator_t<const take_while_view<CrossComparableR, LessThan3>>, //
93 sentinel_t<take_while_view<CrossComparableR, LessThan3>>>);
94
95 static_assert(weakly_equality_comparable_with<iterator_t<take_while_view<CrossComparableR, LessThan3>>, //
96 sentinel_t<const take_while_view<CrossComparableR, LessThan3>>>);
97
98 static_assert(weakly_equality_comparable_with<iterator_t<const take_while_view<CrossComparableR, LessThan3>>, //
99 sentinel_t<const take_while_view<CrossComparableR, LessThan3>>>);
100
101 template <class R, bool ConstIter, bool ConstSent>
testOne()102 constexpr void testOne() {
103 auto getBegin = [](auto&& rng) {
104 if constexpr (ConstIter) {
105 return std::as_const(rng).begin();
106 } else {
107 return rng.begin();
108 }
109 };
110
111 auto getEnd = [](auto&& rng) {
112 if constexpr (ConstSent) {
113 return std::as_const(rng).end();
114 } else {
115 return rng.end();
116 }
117 };
118
119 // iter == sentinel.base
120 {
121 int buffer[] = {1};
122 R v{buffer};
123 std::ranges::take_while_view twv(v, LessThan3{});
124 auto iter = getBegin(twv);
125 auto st = getEnd(twv);
126 ++iter;
127 assert(iter == st);
128 }
129
130 // iter != sentinel.base && pred(*iter)
131 {
132 int buffer[] = {1, 3, 4};
133 R v{buffer};
134 std::ranges::take_while_view twv(v, LessThan3{});
135 auto iter = getBegin(twv);
136 auto st = getEnd(twv);
137 assert(iter != st);
138 ++iter;
139 assert(iter == st);
140 }
141
142 // iter != sentinel.base && !pred(*iter)
143 {
144 int buffer[] = {1, 2, 3, 4, 3, 2, 1};
145 R v{buffer};
146 std::ranges::take_while_view twv(v, LessThan3{});
147 auto iter = getBegin(twv);
148 auto sent = getEnd(twv);
149 assert(iter != sent);
150 }
151
152 // empty range
153 {
154 std::array<int, 0> arr;
155 R v{arr};
156 std::ranges::take_while_view twv(v, LessThan3{});
157 auto iter = getBegin(twv);
158 auto sent = getEnd(twv);
159 assert(iter == sent);
160 }
161 }
162
test()163 constexpr bool test() {
164 testOne<R, false, false>();
165 testOne<R, true, true>();
166 testOne<CrossComparableR, false, false>();
167 testOne<CrossComparableR, true, true>();
168
169 // LWG 3449 `take_view` and `take_while_view`'s `sentinel<false>` not comparable with their const iterator
170 testOne<CrossComparableR, true, false>();
171 testOne<CrossComparableR, false, true>();
172
173 // test std::invoke is used
174 {
175 struct Data {
176 bool b;
177 };
178
179 Data buffer[] = {{true}, {true}, {false}};
180 std::ranges::take_while_view twv(buffer, &Data::b);
181 auto it = twv.begin();
182 auto st = twv.end();
183 assert(it != st);
184
185 ++it;
186 assert(it != st);
187
188 ++it;
189 assert(it == st);
190 }
191
192 return true;
193 }
194
main(int,char **)195 int main(int, char**) {
196 test();
197 static_assert(test());
198
199 return 0;
200 }
201