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 // x += n;
13 // x + n;
14 // n + x;
15 // x -= n;
16 // x - n;
17 // x - y;
18 // All the arithmetic operators have the constraint `requires all-random-access<Const, Views...>;`,
19 // except `operator-(x, y)` which instead has the constraint
20 //    `requires (sized_­sentinel_­for<iterator_t<maybe-const<Const, Views>>,
21 //                                  iterator_t<maybe-const<Const, Views>>> && ...);`
22 
23 #include <ranges>
24 
25 #include <array>
26 #include <concepts>
27 #include <functional>
28 
29 #include "../types.h"
30 
31 template <class T, class U>
32 concept canPlusEqual = requires(T& t, U& u) { t += u; };
33 
34 template <class T, class U>
35 concept canMinusEqual = requires(T& t, U& u) { t -= u; };
36 
test()37 constexpr bool test() {
38   int buffer1[5] = {1, 2, 3, 4, 5};
39   int buffer2[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
40 
41   SizedRandomAccessView a{buffer1};
42   static_assert(std::ranges::random_access_range<decltype(a)>);
43   std::array b{4.1, 3.2, 4.3, 0.1, 0.2};
44   static_assert(std::ranges::contiguous_range<decltype(b)>);
45   {
46     // operator+(x, n) and operator+=
47     std::ranges::zip_view v(a, b);
48     auto it1 = v.begin();
49 
50     auto it2 = it1 + 3;
51     auto [x2, y2] = *it2;
52     assert(&x2 == &(a[3]));
53     assert(&y2 == &(b[3]));
54 
55     auto it3 = 3 + it1;
56     auto [x3, y3] = *it3;
57     assert(&x3 == &(a[3]));
58     assert(&y3 == &(b[3]));
59 
60     it1 += 3;
61     assert(it1 == it2);
62     auto [x1, y1] = *it2;
63     assert(&x1 == &(a[3]));
64     assert(&y1 == &(b[3]));
65 
66     using Iter = decltype(it1);
67     static_assert(canPlusEqual<Iter, intptr_t>);
68   }
69 
70   {
71     // operator-(x, n) and operator-=
72     std::ranges::zip_view v(a, b);
73     auto it1 = v.end();
74 
75     auto it2 = it1 - 3;
76     auto [x2, y2] = *it2;
77     assert(&x2 == &(a[2]));
78     assert(&y2 == &(b[2]));
79 
80     it1 -= 3;
81     assert(it1 == it2);
82     auto [x1, y1] = *it2;
83     assert(&x1 == &(a[2]));
84     assert(&y1 == &(b[2]));
85 
86     using Iter = decltype(it1);
87     static_assert(canMinusEqual<Iter, intptr_t>);
88   }
89 
90   {
91     // operator-(x, y)
92     std::ranges::zip_view v(a, b);
93     assert((v.end() - v.begin()) == 5);
94 
95     auto it1 = v.begin() + 2;
96     auto it2 = v.end() - 1;
97     assert((it1 - it2) == -2);
98   }
99 
100   {
101     // in this case sentinel is computed by getting each of the underlying sentinels, so the distance
102     // between begin and end for each of the underlying iterators can be different
103     std::ranges::zip_view v{ForwardSizedView(buffer1), ForwardSizedView(buffer2)};
104     using View = decltype(v);
105     static_assert(std::ranges::common_range<View>);
106     static_assert(!std::ranges::random_access_range<View>);
107 
108     auto it1 = v.begin();
109     auto it2 = v.end();
110     // it1 : <buffer1 + 0, buffer2 + 0>
111     // it2 : <buffer1 + 5, buffer2 + 9>
112     assert((it1 - it2) == -5);
113     assert((it2 - it1) == 5);
114   }
115 
116   {
117     // One of the ranges is not random access
118     std::ranges::zip_view v(a, b, ForwardSizedView{buffer1});
119     using Iter = decltype(v.begin());
120     static_assert(!std::invocable<std::plus<>, Iter, intptr_t>);
121     static_assert(!std::invocable<std::plus<>, intptr_t, Iter>);
122     static_assert(!canPlusEqual<Iter, intptr_t>);
123     static_assert(!std::invocable<std::minus<>, Iter, intptr_t>);
124     static_assert(std::invocable<std::minus<>, Iter, Iter>);
125     static_assert(!canMinusEqual<Iter, intptr_t>);
126   }
127 
128   {
129     // One of the ranges does not have sized sentinel
130     std::ranges::zip_view v(a, b, InputCommonView{buffer1});
131     using Iter = decltype(v.begin());
132     static_assert(!std::invocable<std::minus<>, Iter, Iter>);
133   }
134 
135   return true;
136 }
137 
main(int,char **)138 int main(int, char**) {
139   test();
140   static_assert(test());
141 
142   return 0;
143 }
144