xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.zip/sentinel/minus.pass.cpp (revision e07a2f49e3d3c13b6e9b89e0f6118652f2b2d3ac)
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, c++20
10 
11 // template <bool OtherConst>
12 // requires(sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>,
13 //                             iterator_t<maybe-const<OtherConst, Views>>>&&...)
14 // friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...>
15 //   operator-(const iterator<OtherConst>&, const sentinel&)
16 //
17 // template <bool OtherConst>
18 // requires(sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>,
19 //                             iterator_t<maybe-const<OtherConst, Views>>>&&...)
20 // friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...>
21 //   operator-(const sentinel&, const iterator<OtherConst>&)
22 
23 #include <cassert>
24 #include <concepts>
25 #include <functional>
26 #include <ranges>
27 #include <tuple>
28 
29 #include "../types.h"
30 
31 template <class Base = int*>
32 struct convertible_forward_sized_iterator {
33   Base it_ = nullptr;
34 
35   using iterator_category = std::forward_iterator_tag;
36   using value_type = int;
37   using difference_type = std::intptr_t;
38 
39   convertible_forward_sized_iterator() = default;
convertible_forward_sized_iteratorconvertible_forward_sized_iterator40   constexpr convertible_forward_sized_iterator(Base it) : it_(it) {}
41 
42   template <std::convertible_to<Base> U>
convertible_forward_sized_iteratorconvertible_forward_sized_iterator43   constexpr convertible_forward_sized_iterator(const convertible_forward_sized_iterator<U>& it) : it_(it.it_) {}
44 
operator *convertible_forward_sized_iterator45   constexpr decltype(*Base{}) operator*() const { return *it_; }
46 
operator ++convertible_forward_sized_iterator47   constexpr convertible_forward_sized_iterator& operator++() {
48     ++it_;
49     return *this;
50   }
operator ++convertible_forward_sized_iterator51   constexpr convertible_forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); }
52 
53   friend constexpr bool operator==(const convertible_forward_sized_iterator&,
54                                    const convertible_forward_sized_iterator&) = default;
55 
operator -(const convertible_forward_sized_iterator & x,const convertible_forward_sized_iterator & y)56   friend constexpr difference_type operator-(const convertible_forward_sized_iterator& x,
57                                              const convertible_forward_sized_iterator& y) {
58     return x.it_ - y.it_;
59   }
60 };
61 static_assert(std::forward_iterator<convertible_forward_sized_iterator<>>);
62 
63 template <class Base>
64 struct convertible_sized_sentinel {
65   Base base_;
66   explicit convertible_sized_sentinel() = default;
convertible_sized_sentinelconvertible_sized_sentinel67   constexpr convertible_sized_sentinel(const Base& it) : base_(it) {}
68 
69   template <std::convertible_to<Base> U>
convertible_sized_sentinelconvertible_sized_sentinel70   constexpr convertible_sized_sentinel(const convertible_sized_sentinel<U>& other) : base_(other.base_) {}
71 
72   template <class U>
73     requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)
operator ==(const convertible_sized_sentinel & s,const U & base)74   friend constexpr bool operator==(const convertible_sized_sentinel& s, const U& base) {
75     return s.base_ == base;
76   }
77   template <class U>
78     requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)
operator -(const convertible_sized_sentinel & s,const U & i)79   friend constexpr auto operator-(const convertible_sized_sentinel& s, const U& i) {
80     return s.base_ - i;
81   }
82 
83   template <class U>
84     requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)
operator -(const U & i,const convertible_sized_sentinel & s)85   friend constexpr auto operator-(const U& i, const convertible_sized_sentinel& s) {
86     return i - s.base_;
87   }
88 };
89 static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<>>,
90                                       convertible_forward_sized_iterator<>>);
91 static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<const int*>>,
92                                       convertible_forward_sized_iterator<int*>>);
93 static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<int*>>,
94                                       convertible_forward_sized_iterator<const int*>>);
95 
96 struct ConstCompatibleForwardSized : IntBufferView {
97   using IntBufferView::IntBufferView;
98 
99   using iterator = convertible_forward_sized_iterator<int*>;
100   using const_iterator = convertible_forward_sized_iterator<const int*>;
101 
beginConstCompatibleForwardSized102   constexpr iterator begin() { return {buffer_}; }
beginConstCompatibleForwardSized103   constexpr const_iterator begin() const { return {buffer_}; }
endConstCompatibleForwardSized104   constexpr convertible_sized_sentinel<iterator> end() { return iterator{buffer_ + size_}; }
endConstCompatibleForwardSized105   constexpr convertible_sized_sentinel<const_iterator> end() const { return const_iterator{buffer_ + size_}; }
106 };
107 
108 // clang-format off
109 template <class T, class U>
110 concept HasMinus = std::invocable<std::minus<>,const T&, const U&>;
111 
112 template <class T>
113 concept SentinelHasMinus = HasMinus<std::ranges::sentinel_t<T>, std::ranges::iterator_t<T>>;
114 // clang-format on
115 
test()116 constexpr bool test() {
117   int buffer1[5] = {1, 2, 3, 4, 5};
118 
119   {
120     // simple-view
121     std::ranges::zip_view v{ForwardSizedNonCommon(buffer1)};
122     static_assert(!std::ranges::common_range<decltype(v)>);
123     static_assert(simple_view<decltype(v)>);
124 
125     auto it = v.begin();
126     auto st = v.end();
127     assert(st - it == 5);
128     assert(st - std::ranges::next(it, 1) == 4);
129 
130     assert(it - st == -5);
131     assert(std::ranges::next(it, 1) - st == -4);
132     static_assert(SentinelHasMinus<decltype(v)>);
133   }
134 
135   {
136     // shortest range
137     std::ranges::zip_view v(std::views::iota(0, 3), ForwardSizedNonCommon(buffer1));
138     static_assert(!std::ranges::common_range<decltype(v)>);
139     auto it = v.begin();
140     auto st = v.end();
141     assert(st - it == 3);
142     assert(st - std::ranges::next(it, 1) == 2);
143 
144     assert(it - st == -3);
145     assert(std::ranges::next(it, 1) - st == -2);
146     static_assert(SentinelHasMinus<decltype(v)>);
147   }
148 
149   {
150     // underlying sentinel does not model sized_sentinel_for
151     std::ranges::zip_view v(std::views::iota(0), SizedRandomAccessView(buffer1));
152     static_assert(!std::ranges::common_range<decltype(v)>);
153     static_assert(!SentinelHasMinus<decltype(v)>);
154   }
155 
156   {
157     // const incompatible:
158     // underlying const sentinels cannot subtract underlying iterators
159     // underlying sentinels cannot subtract underlying const iterators
160     std::ranges::zip_view v(NonSimpleForwardSizedNonCommon{buffer1});
161     static_assert(!std::ranges::common_range<decltype(v)>);
162     static_assert(!simple_view<decltype(v)>);
163 
164     using Iter = std::ranges::iterator_t<decltype(v)>;
165     using ConstIter = std::ranges::iterator_t<const decltype(v)>;
166     static_assert(!std::is_same_v<Iter, ConstIter>);
167     using Sentinel = std::ranges::sentinel_t<decltype(v)>;
168     using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
169     static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
170 
171     static_assert(HasMinus<Iter, Sentinel>);
172     static_assert(HasMinus<Sentinel, Iter>);
173     static_assert(HasMinus<ConstIter, ConstSentinel>);
174     static_assert(HasMinus<ConstSentinel, ConstIter>);
175     auto it = v.begin();
176     auto const_it = std::as_const(v).begin();
177     auto st = v.end();
178     auto const_st = std::as_const(v).end();
179     assert(it - st == -5);
180     assert(st - it == 5);
181     assert(const_it - const_st == -5);
182     assert(const_st - const_it == 5);
183 
184     static_assert(!HasMinus<Iter, ConstSentinel>);
185     static_assert(!HasMinus<ConstSentinel, Iter>);
186     static_assert(!HasMinus<ConstIter, Sentinel>);
187     static_assert(!HasMinus<Sentinel, ConstIter>);
188   }
189 
190   {
191     // const compatible allow non-const to const conversion
192     std::ranges::zip_view v(ConstCompatibleForwardSized{buffer1});
193     static_assert(!std::ranges::common_range<decltype(v)>);
194     static_assert(!simple_view<decltype(v)>);
195 
196     using Iter = std::ranges::iterator_t<decltype(v)>;
197     using ConstIter = std::ranges::iterator_t<const decltype(v)>;
198     static_assert(!std::is_same_v<Iter, ConstIter>);
199     using Sentinel = std::ranges::sentinel_t<decltype(v)>;
200     using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
201     static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
202 
203     static_assert(HasMinus<Iter, Sentinel>);
204     static_assert(HasMinus<Sentinel, Iter>);
205     static_assert(HasMinus<ConstIter, ConstSentinel>);
206     static_assert(HasMinus<ConstSentinel, ConstIter>);
207     static_assert(HasMinus<Iter, ConstSentinel>);
208     static_assert(HasMinus<ConstSentinel, Iter>);
209     static_assert(HasMinus<ConstIter, Sentinel>);
210     static_assert(HasMinus<Sentinel, ConstIter>);
211 
212     auto it = v.begin();
213     auto const_it = std::as_const(v).begin();
214     auto st = v.end();
215     auto const_st = std::as_const(v).end();
216 
217     assert(it - st == -5);
218     assert(st - it == 5);
219     assert(const_it - const_st == -5);
220     assert(const_st - const_it == 5);
221     assert(it - const_st == -5);
222     assert(const_st - it == 5);
223     assert(const_it - st == -5);
224     assert(st - const_it == 5);
225   }
226   return true;
227 }
228 
main(int,char **)229 int main(int, char**) {
230   test();
231   static_assert(test());
232 
233   return 0;
234 }
235