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 | |
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 | |
137 | int main(int, char**) { |
138 | test(); |
139 | static_assert(test()); |
140 | |
141 | return 0; |
142 | } |
143 | |