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
30template <bool Const>
31struct 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
46template <bool Const>
47struct Sent {
48 std::tuple<int>* end_;
49
50 constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
51};
52
53template <bool Const>
54struct 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
64template <bool Const>
65struct 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
84template <template <bool> class It, template <bool> class St>
85struct 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
99template <class T, class U>
100concept HasMinus = requires(const T t, const U u) { t - u; };
101
102template <class BaseRange>
103using ElementsView = std::ranges::elements_view<BaseRange, 0>;
104
105template <class BaseRange>
106using ElemIter = std::ranges::iterator_t<ElementsView<BaseRange>>;
107
108template <class BaseRange>
109using EleConstIter = std::ranges::iterator_t<const ElementsView<BaseRange>>;
110
111template <class BaseRange>
112using EleSent = std::ranges::sentinel_t<ElementsView<BaseRange>>;
113
114template <class BaseRange>
115using EleConstSent = std::ranges::sentinel_t<const ElementsView<BaseRange>>;
116
117constexpr 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
167constexpr 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
209int main(int, char**) {
210 test();
211 static_assert(test());
212
213 return 0;
214}
215

source code of libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/minus.pass.cpp