//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // x += n; // x + n; // n + x; // x -= n; // x - n; // x - y; // All the arithmetic operators have the constraint `requires all-random-access;`, // except `operator-(x, y)` which instead has the constraint // `requires (sized_sentinel_for>, // iterator_t>> && ...);` #include #include #include #include #include "../types.h" template concept canPlusEqual = requires(T& t, U& u) { t += u; }; template concept canMinusEqual = requires(T& t, U& u) { t -= u; }; constexpr bool test() { int buffer1[5] = {1, 2, 3, 4, 5}; int buffer2[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; SizedRandomAccessView a{buffer1}; static_assert(std::ranges::random_access_range); std::array b{4.1, 3.2, 4.3, 0.1, 0.2}; static_assert(std::ranges::contiguous_range); { // operator+(x, n) and operator+= std::ranges::zip_view v(a, b); auto it1 = v.begin(); auto it2 = it1 + 3; auto [x2, y2] = *it2; assert(&x2 == &(a[3])); assert(&y2 == &(b[3])); auto it3 = 3 + it1; auto [x3, y3] = *it3; assert(&x3 == &(a[3])); assert(&y3 == &(b[3])); it1 += 3; assert(it1 == it2); auto [x1, y1] = *it2; assert(&x1 == &(a[3])); assert(&y1 == &(b[3])); using Iter = decltype(it1); static_assert(canPlusEqual); } { // operator-(x, n) and operator-= std::ranges::zip_view v(a, b); auto it1 = v.end(); auto it2 = it1 - 3; auto [x2, y2] = *it2; assert(&x2 == &(a[2])); assert(&y2 == &(b[2])); it1 -= 3; assert(it1 == it2); auto [x1, y1] = *it2; assert(&x1 == &(a[2])); assert(&y1 == &(b[2])); using Iter = decltype(it1); static_assert(canMinusEqual); } { // operator-(x, y) std::ranges::zip_view v(a, b); assert((v.end() - v.begin()) == 5); auto it1 = v.begin() + 2; auto it2 = v.end() - 1; assert((it1 - it2) == -2); } { // in this case sentinel is computed by getting each of the underlying sentinels, so the distance // between begin and end for each of the underlying iterators can be different std::ranges::zip_view v{ForwardSizedView(buffer1), ForwardSizedView(buffer2)}; using View = decltype(v); static_assert(std::ranges::common_range); static_assert(!std::ranges::random_access_range); auto it1 = v.begin(); auto it2 = v.end(); // it1 : // it2 : assert((it1 - it2) == -5); assert((it2 - it1) == 5); } { // One of the ranges is not random access std::ranges::zip_view v(a, b, ForwardSizedView{buffer1}); using Iter = decltype(v.begin()); static_assert(!std::invocable, Iter, std::intptr_t>); static_assert(!std::invocable, std::intptr_t, Iter>); static_assert(!canPlusEqual); static_assert(!std::invocable, Iter, std::intptr_t>); static_assert(std::invocable, Iter, Iter>); static_assert(!canMinusEqual); } { // One of the ranges does not have sized sentinel std::ranges::zip_view v(a, b, InputCommonView{buffer1}); using Iter = decltype(v.begin()); static_assert(!std::invocable, Iter, Iter>); } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }