//===----------------------------------------------------------------------===//
//
// 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<Const, Views...>;`,
// except `operator-(x, y)` which instead has the constraint
// `requires (sized_sentinel_for<iterator_t<maybe-const<Const, Views>>,
// iterator_t<maybe-const<Const, Views>>> && ...);`
#include <ranges>
#include <array>
#include <concepts>
#include <functional>
#include "../types.h"
template <class T, class U>
concept canPlusEqual = requires(T& t, U& u) { t += u; };
template <class T, class U>
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<decltype(a)>);
std::array b{4.1, 3.2, 4.3, 0.1, 0.2};
static_assert(std::ranges::contiguous_range<decltype(b)>);
{
// 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<Iter, std::intptr_t>);
}
{
// 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<Iter, std::intptr_t>);
}
{
// 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<View>);
static_assert(!std::ranges::random_access_range<View>);
auto it1 = v.begin();
auto it2 = v.end();
// it1 : <buffer1 + 0, buffer2 + 0>
// it2 : <buffer1 + 5, buffer2 + 9>
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<std::plus<>, Iter, std::intptr_t>);
static_assert(!std::invocable<std::plus<>, std::intptr_t, Iter>);
static_assert(!canPlusEqual<Iter, std::intptr_t>);
static_assert(!std::invocable<std::minus<>, Iter, std::intptr_t>);
static_assert(std::invocable<std::minus<>, Iter, Iter>);
static_assert(!canMinusEqual<Iter, std::intptr_t>);
}
{
// 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<std::minus<>, Iter, Iter>);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}