xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/minus.pass.cpp (revision 3fe3f9c51cbac91af741e53e96c89f633bd2a6ad)
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 
operator *Iter38   constexpr decltype(auto) operator*() const { return *it_; }
operator ++Iter39   constexpr Iter& operator++() {
40     ++it_;
41     return *this;
42   }
operator ++Iter43   constexpr void operator++(int) { ++it_; }
44 };
45 
46 template <bool Const>
47 struct Sent {
48   std::tuple<int>* end_;
49 
operator ==Sent50   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 
operator ==SizedSent57   constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
58 
operator -(const SizedSent & st,const Iter<Const> & it)59   friend constexpr auto operator-(const SizedSent& st, const Iter<Const>& it) { return st.end_ - it.it_; }
60 
operator -(const Iter<Const> & it,const SizedSent & st)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>
operator ==CrossSizedSent69   constexpr bool operator==(const Iter<C>& i) const {
70     return i.it_ == end_;
71   }
72 
73   template <bool C>
operator -(const CrossSizedSent & st,const Iter<C> & it)74   friend constexpr auto operator-(const CrossSizedSent& st, const Iter<C>& it) {
75     return st.end_ - it.it_;
76   }
77 
78   template <bool C>
operator -(const Iter<C> & it,const CrossSizedSent & st)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 
beginRange93   constexpr iterator begin() { return {buffer_}; }
beginRange94   constexpr const_iterator begin() const { return {buffer_}; }
endRange95   constexpr sentinel end() { return sentinel{buffer_ + size_}; }
endRange96   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 
testConstraints()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 
test()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 
main(int,char **)209 int main(int, char**) {
210   test();
211   static_assert(test());
212 
213   return 0;
214 }
215