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