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