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 // template<bool OtherConst>
12 // requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
13 // friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
14
15 #include <array>
16 #include <cassert>
17 #include <ranges>
18
19 #include "../types.h"
20 #include "test_range.h"
21
22 template <bool Const>
23 struct Iter {
24 std::tuple<int>* it_;
25
26 using value_type = std::tuple<int>;
27 using difference_type = std::intptr_t;
28 using iterator_concept = std::input_iterator_tag;
29
operator *Iter30 constexpr decltype(auto) operator*() const { return *it_; }
operator ++Iter31 constexpr Iter& operator++() {
32 ++it_;
33 return *this;
34 }
operator ++Iter35 constexpr void operator++(int) { ++it_; }
36 };
37
38 template <bool Const>
39 struct Sent {
40 std::tuple<int>* end_;
41
operator ==Sent42 constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
43 };
44
45 template <bool Const>
46 struct CrossComparableSent {
47 std::tuple<int>* end_;
48
49 template <bool C>
operator ==CrossComparableSent50 constexpr bool operator==(const Iter<C>& i) const {
51 return i.it_ == end_;
52 }
53 };
54
55 template <template <bool> typename St>
56 struct Range : TupleBufferView {
57 using TupleBufferView::TupleBufferView;
beginRange58 constexpr Iter<false> begin() { return Iter<false>{buffer_}; }
beginRange59 constexpr Iter<true> begin() const { return Iter<true>{buffer_}; }
endRange60 constexpr St<false> end() { return St<false>{buffer_ + size_}; }
endRange61 constexpr St<true> end() const { return St<true>{buffer_ + size_}; }
62 };
63
64 using R = Range<Sent>;
65 using CrossComparableR = Range<CrossComparableSent>;
66
67 using std::ranges::elements_view;
68 using std::ranges::iterator_t;
69 using std::ranges::sentinel_t;
70
71 static_assert(weakly_equality_comparable_with<iterator_t<elements_view<R, 0>>, //
72 sentinel_t<elements_view<R, 0>>>);
73
74 static_assert(!weakly_equality_comparable_with<iterator_t<const elements_view<R, 0>>, //
75 sentinel_t<elements_view<R, 0>>>);
76
77 static_assert(!weakly_equality_comparable_with<iterator_t<elements_view<R, 0>>, //
78 sentinel_t<const elements_view<R, 0>>>);
79
80 static_assert(weakly_equality_comparable_with<iterator_t<const elements_view<R, 0>>, //
81 sentinel_t<const elements_view<R, 0>>>);
82
83 static_assert(weakly_equality_comparable_with<iterator_t<elements_view<CrossComparableR, 0>>, //
84 sentinel_t<elements_view<CrossComparableR, 0>>>);
85
86 static_assert(weakly_equality_comparable_with<iterator_t<const elements_view<CrossComparableR, 0>>, //
87 sentinel_t<elements_view<CrossComparableR, 0>>>);
88
89 static_assert(weakly_equality_comparable_with<iterator_t<elements_view<CrossComparableR, 0>>, //
90 sentinel_t<const elements_view<CrossComparableR, 0>>>);
91
92 static_assert(weakly_equality_comparable_with<iterator_t<const elements_view<CrossComparableR, 0>>, //
93 sentinel_t<const elements_view<CrossComparableR, 0>>>);
94
95 template <class R, bool ConstIter, bool ConstSent>
testOne()96 constexpr void testOne() {
97 auto getBegin = [](auto&& rng) {
98 if constexpr (ConstIter) {
99 return std::as_const(rng).begin();
100 } else {
101 return rng.begin();
102 }
103 };
104
105 auto getEnd = [](auto&& rng) {
106 if constexpr (ConstSent) {
107 return std::as_const(rng).end();
108 } else {
109 return rng.end();
110 }
111 };
112
113 // iter == sentinel.base
114 {
115 std::tuple<int> buffer[] = {{1}};
116 R v{buffer};
117 std::ranges::elements_view<R, 0> ev(v);
118 auto iter = getBegin(ev);
119 auto st = getEnd(ev);
120 ++iter;
121 assert(iter == st);
122 }
123
124 // iter != sentinel.base
125 {
126 std::tuple<int> buffer[] = {{1}};
127 R v{buffer};
128 std::ranges::elements_view<R, 0> ev(v);
129 auto iter = getBegin(ev);
130 auto st = getEnd(ev);
131 assert(iter != st);
132 }
133
134 // empty range
135 {
136 std::array<std::tuple<int>, 0> arr;
137 R v{arr};
138 std::ranges::elements_view<R, 0> ev(v);
139 auto iter = getBegin(ev);
140 auto sent = getEnd(ev);
141 assert(iter == sent);
142 }
143 }
144
test()145 constexpr bool test() {
146 testOne<R, false, false>();
147 testOne<R, true, true>();
148 testOne<CrossComparableR, false, false>();
149 testOne<CrossComparableR, true, true>();
150 testOne<CrossComparableR, true, false>();
151 testOne<CrossComparableR, false, true>();
152
153 return true;
154 }
155
main(int,char **)156 int main(int, char**) {
157 test();
158 static_assert(test());
159
160 return 0;
161 }
162