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