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
30template <class T, class U>
31concept canPlusEqual = requires(T& t, U& u) { t += u; };
32
33template <class T, class U>
34concept canMinusEqual = requires(T& t, U& u) { t -= u; };
35
36constexpr 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
137int main(int, char**) {
138 test();
139 static_assert(test());
140
141 return 0;
142}
143

source code of libcxx/test/std/ranges/range.adaptors/range.zip/iterator/arithmetic.pass.cpp