//===----------------------------------------------------------------------===//
//
// 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
// <algorithm>
// template<bidirectional_iterator I, sentinel_for<I> S>
// requires permutable<I>
// constexpr I ranges::reverse(I first, S last);
// template<bidirectional_range R>
// requires permutable<iterator_t<R>>
// constexpr borrowed_iterator_t<R> ranges::reverse(R&& r);
#include <algorithm>
#include <array>
#include <concepts>
#include <ranges>
#include "almost_satisfies_types.h"
#include "MoveOnly.h"
#include "test_iterators.h"
template <class Iter, class Sent = sentinel_wrapper<Iter>>
concept HasReverseIt = requires (Iter first, Sent last) { std::ranges::reverse(first, last); };
static_assert(HasReverseIt<int*>);
static_assert(!HasReverseIt<BidirectionalIteratorNotDerivedFrom>);
static_assert(!HasReverseIt<BidirectionalIteratorNotDecrementable>);
static_assert(!HasReverseIt<PermutableNotForwardIterator>);
static_assert(!HasReverseIt<PermutableNotSwappable>);
template <class Range>
concept HasReverseR = requires (Range range) { std::ranges::reverse(range); };
static_assert(HasReverseR<UncheckedRange<int*>>);
static_assert(!HasReverseR<BidirectionalRangeNotDerivedFrom>);
static_assert(!HasReverseR<BidirectionalRangeNotDecrementable>);
static_assert(!HasReverseR<PermutableRangeNotForwardIterator>);
static_assert(!HasReverseR<PermutableRangeNotSwappable>);
template <class Iter, class Sent, std::size_t N>
constexpr void test(std::array<int, N> value, std::array<int, N> expected) {
{
auto val = value;
std::same_as<Iter> decltype(auto) ret = std::ranges::reverse(Iter(val.data()), Sent(Iter(val.data() + val.size())));
assert(val == expected);
assert(base(ret) == val.data() + val.size());
}
{
auto val = value;
auto range = std::ranges::subrange(Iter(val.data()), Sent(Iter(val.data() + val.size())));
std::same_as<Iter> decltype(auto) ret = std::ranges::reverse(range);
assert(val == expected);
assert(base(ret) == val.data() + val.size());
}
}
template <class Iter, class Sent = Iter>
constexpr void test_iterators() {
// simple test
test<Iter, Sent, 4>({1, 2, 3, 4}, {4, 3, 2, 1});
// check that an odd number of elements works
test<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, {7, 6, 5, 4, 3, 2, 1});
// check that an empty range works
test<Iter, Sent, 0>({}, {});
// check that a single element works
test<Iter, Sent, 1>({5}, {5});
}
struct SwapCounter {
int* counter;
constexpr SwapCounter(int* counter_) : counter(counter_) {}
friend constexpr void swap(SwapCounter& lhs, SwapCounter&) { ++*lhs.counter; }
};
constexpr bool test() {
test_iterators<bidirectional_iterator<int*>>();
test_iterators<bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>();
test_iterators<random_access_iterator<int*>>();
test_iterators<random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>>>();
test_iterators<contiguous_iterator<int*>>();
test_iterators<contiguous_iterator<int*>, sentinel_wrapper<contiguous_iterator<int*>>>();
test_iterators<int*>();
test_iterators<ProxyIterator<bidirectional_iterator<int*>>>();
test_iterators<ProxyIterator<random_access_iterator<int*>>>();
test_iterators<ProxyIterator<contiguous_iterator<int*>>>();
// check that std::ranges::dangling is returned
{
[[maybe_unused]] std::same_as<std::ranges::dangling> auto ret = std::ranges::reverse(std::array {1, 2, 3, 4});
}
{
{
int counter = 0;
SwapCounter a[] = {&counter, &counter, &counter, &counter};
std::ranges::reverse(a);
assert(counter == 2);
}
{
int counter = 0;
SwapCounter a[] = {&counter, &counter, &counter, &counter};
std::ranges::reverse(a, a + 4);
assert(counter == 2);
}
}
// Move only types work for ProxyIterator
{
{
MoveOnly a[] = {1, 2, 3};
ProxyRange proxyA{a};
std::ranges::reverse(proxyA.begin(), proxyA.end());
assert(a[0].get() == 3);
assert(a[1].get() == 2);
assert(a[2].get() == 1);
}
{
MoveOnly a[] = {1, 2, 3};
ProxyRange proxyA{a};
std::ranges::reverse(proxyA);
assert(a[0].get() == 3);
assert(a[1].get() == 2);
assert(a[2].get() == 1);
}
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}