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