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