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 sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> |
13 | // friend constexpr range_difference_t<maybe-const<OtherConst, V>> |
14 | // operator-(const iterator<OtherConst>& x, const sentinel& y); |
15 | // |
16 | // template<bool OtherConst> |
17 | // requires sized_sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> |
18 | // friend constexpr range_difference_t<maybe-const<OtherConst, V>> |
19 | // operator-(const sentinel& x, const iterator<OtherConst>& y); |
20 | |
21 | #include <cassert> |
22 | #include <concepts> |
23 | #include <cstddef> |
24 | #include <functional> |
25 | #include <ranges> |
26 | #include <tuple> |
27 | |
28 | #include "../types.h" |
29 | |
30 | template <bool Const> |
31 | struct Iter { |
32 | std::tuple<int>* it_; |
33 | |
34 | using value_type = std::tuple<int>; |
35 | using difference_type = std::ptrdiff_t; |
36 | using iterator_concept = std::input_iterator_tag; |
37 | |
38 | constexpr decltype(auto) operator*() const { return *it_; } |
39 | constexpr Iter& operator++() { |
40 | ++it_; |
41 | return *this; |
42 | } |
43 | constexpr void operator++(int) { ++it_; } |
44 | }; |
45 | |
46 | template <bool Const> |
47 | struct Sent { |
48 | std::tuple<int>* end_; |
49 | |
50 | constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; } |
51 | }; |
52 | |
53 | template <bool Const> |
54 | struct SizedSent { |
55 | std::tuple<int>* end_; |
56 | |
57 | constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; } |
58 | |
59 | friend constexpr auto operator-(const SizedSent& st, const Iter<Const>& it) { return st.end_ - it.it_; } |
60 | |
61 | friend constexpr auto operator-(const Iter<Const>& it, const SizedSent& st) { return it.it_ - st.end_; } |
62 | }; |
63 | |
64 | template <bool Const> |
65 | struct CrossSizedSent { |
66 | std::tuple<int>* end_; |
67 | |
68 | template <bool C> |
69 | constexpr bool operator==(const Iter<C>& i) const { |
70 | return i.it_ == end_; |
71 | } |
72 | |
73 | template <bool C> |
74 | friend constexpr auto operator-(const CrossSizedSent& st, const Iter<C>& it) { |
75 | return st.end_ - it.it_; |
76 | } |
77 | |
78 | template <bool C> |
79 | friend constexpr auto operator-(const Iter<C>& it, const CrossSizedSent& st) { |
80 | return it.it_ - st.end_; |
81 | } |
82 | }; |
83 | |
84 | template <template <bool> class It, template <bool> class St> |
85 | struct Range : TupleBufferView { |
86 | using TupleBufferView::TupleBufferView; |
87 | |
88 | using iterator = It<false>; |
89 | using sentinel = St<false>; |
90 | using const_iterator = It<true>; |
91 | using const_sentinel = St<true>; |
92 | |
93 | constexpr iterator begin() { return {buffer_}; } |
94 | constexpr const_iterator begin() const { return {buffer_}; } |
95 | constexpr sentinel end() { return sentinel{buffer_ + size_}; } |
96 | constexpr const_sentinel end() const { return const_sentinel{buffer_ + size_}; } |
97 | }; |
98 | |
99 | template <class T, class U> |
100 | concept HasMinus = requires(const T t, const U u) { t - u; }; |
101 | |
102 | template <class BaseRange> |
103 | using ElementsView = std::ranges::elements_view<BaseRange, 0>; |
104 | |
105 | template <class BaseRange> |
106 | using ElemIter = std::ranges::iterator_t<ElementsView<BaseRange>>; |
107 | |
108 | template <class BaseRange> |
109 | using EleConstIter = std::ranges::iterator_t<const ElementsView<BaseRange>>; |
110 | |
111 | template <class BaseRange> |
112 | using EleSent = std::ranges::sentinel_t<ElementsView<BaseRange>>; |
113 | |
114 | template <class BaseRange> |
115 | using EleConstSent = std::ranges::sentinel_t<const ElementsView<BaseRange>>; |
116 | |
117 | constexpr void testConstraints() { |
118 | // base is not sized |
119 | { |
120 | using Base = Range<Iter, Sent>; |
121 | static_assert(!HasMinus<EleSent<Base>, ElemIter<Base>>); |
122 | static_assert(!HasMinus<ElemIter<Base>, EleSent<Base>>); |
123 | |
124 | static_assert(!HasMinus<EleSent<Base>, EleConstIter<Base>>); |
125 | static_assert(!HasMinus<EleConstIter<Base>, EleSent<Base>>); |
126 | |
127 | static_assert(!HasMinus<EleConstSent<Base>, EleConstIter<Base>>); |
128 | static_assert(!HasMinus<EleConstIter<Base>, EleConstSent<Base>>); |
129 | |
130 | static_assert(!HasMinus<EleConstSent<Base>, ElemIter<Base>>); |
131 | static_assert(!HasMinus<ElemIter<Base>, EleConstSent<Base>>); |
132 | } |
133 | |
134 | // base is sized but not cross const |
135 | { |
136 | using Base = Range<Iter, SizedSent>; |
137 | static_assert(HasMinus<EleSent<Base>, ElemIter<Base>>); |
138 | static_assert(HasMinus<ElemIter<Base>, EleSent<Base>>); |
139 | |
140 | static_assert(!HasMinus<EleSent<Base>, EleConstIter<Base>>); |
141 | static_assert(!HasMinus<EleConstIter<Base>, EleSent<Base>>); |
142 | |
143 | static_assert(HasMinus<EleConstSent<Base>, EleConstIter<Base>>); |
144 | static_assert(HasMinus<EleConstIter<Base>, EleConstSent<Base>>); |
145 | |
146 | static_assert(!HasMinus<EleConstSent<Base>, ElemIter<Base>>); |
147 | static_assert(!HasMinus<ElemIter<Base>, EleConstSent<Base>>); |
148 | } |
149 | |
150 | // base is cross const sized |
151 | { |
152 | using Base = Range<Iter, CrossSizedSent>; |
153 | static_assert(HasMinus<EleSent<Base>, ElemIter<Base>>); |
154 | static_assert(HasMinus<ElemIter<Base>, EleSent<Base>>); |
155 | |
156 | static_assert(HasMinus<EleSent<Base>, EleConstIter<Base>>); |
157 | static_assert(HasMinus<EleConstIter<Base>, EleSent<Base>>); |
158 | |
159 | static_assert(HasMinus<EleConstSent<Base>, EleConstIter<Base>>); |
160 | static_assert(HasMinus<EleConstIter<Base>, EleConstSent<Base>>); |
161 | |
162 | static_assert(HasMinus<EleConstSent<Base>, ElemIter<Base>>); |
163 | static_assert(HasMinus<ElemIter<Base>, EleConstSent<Base>>); |
164 | } |
165 | } |
166 | |
167 | constexpr bool test() { |
168 | std::tuple<int> buffer[] = {{1}, {2}, {3}, {4}, {5}}; |
169 | |
170 | // base is sized but not cross const |
171 | { |
172 | using Base = Range<Iter, SizedSent>; |
173 | Base base{buffer}; |
174 | auto ev = base | std::views::elements<0>; |
175 | auto iter = ev.begin(); |
176 | auto const_iter = std::as_const(ev).begin(); |
177 | auto sent = ev.end(); |
178 | auto const_sent = std::as_const(ev).end(); |
179 | |
180 | assert(iter - sent == -5); |
181 | assert(sent - iter == 5); |
182 | assert(const_iter - const_sent == -5); |
183 | assert(const_sent - const_iter == 5); |
184 | } |
185 | |
186 | // base is cross const sized |
187 | { |
188 | using Base = Range<Iter, CrossSizedSent>; |
189 | Base base{buffer}; |
190 | auto ev = base | std::views::elements<0>; |
191 | auto iter = ev.begin(); |
192 | auto const_iter = std::as_const(ev).begin(); |
193 | auto sent = ev.end(); |
194 | auto const_sent = std::as_const(ev).end(); |
195 | |
196 | assert(iter - sent == -5); |
197 | assert(sent - iter == 5); |
198 | assert(iter - const_sent == -5); |
199 | assert(const_sent - iter == 5); |
200 | assert(const_iter - sent == -5); |
201 | assert(sent - const_iter == 5); |
202 | assert(const_iter - const_sent == -5); |
203 | assert(const_sent - const_iter == 5); |
204 | } |
205 | |
206 | return true; |
207 | } |
208 | |
209 | int main(int, char**) { |
210 | test(); |
211 | static_assert(test()); |
212 | |
213 | return 0; |
214 | } |
215 | |