145 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// <algorithm>12 13// template<bidirectional_iterator I, sentinel_for<I> S>14// requires permutable<I>15// constexpr I ranges::reverse(I first, S last);16// template<bidirectional_range R>17// requires permutable<iterator_t<R>>18// constexpr borrowed_iterator_t<R> ranges::reverse(R&& r);19 20#include <algorithm>21#include <array>22#include <concepts>23#include <ranges>24 25#include "almost_satisfies_types.h"26#include "MoveOnly.h"27#include "test_iterators.h"28 29template <class Iter, class Sent = sentinel_wrapper<Iter>>30concept HasReverseIt = requires (Iter first, Sent last) { std::ranges::reverse(first, last); };31 32static_assert(HasReverseIt<int*>);33static_assert(!HasReverseIt<BidirectionalIteratorNotDerivedFrom>);34static_assert(!HasReverseIt<BidirectionalIteratorNotDecrementable>);35static_assert(!HasReverseIt<PermutableNotForwardIterator>);36static_assert(!HasReverseIt<PermutableNotSwappable>);37 38 39template <class Range>40concept HasReverseR = requires (Range range) { std::ranges::reverse(range); };41 42static_assert(HasReverseR<UncheckedRange<int*>>);43static_assert(!HasReverseR<BidirectionalRangeNotDerivedFrom>);44static_assert(!HasReverseR<BidirectionalRangeNotDecrementable>);45static_assert(!HasReverseR<PermutableRangeNotForwardIterator>);46static_assert(!HasReverseR<PermutableRangeNotSwappable>);47 48template <class Iter, class Sent, std::size_t N>49constexpr void test(std::array<int, N> value, std::array<int, N> expected) {50 {51 auto val = value;52 std::same_as<Iter> decltype(auto) ret = std::ranges::reverse(Iter(val.data()), Sent(Iter(val.data() + val.size())));53 assert(val == expected);54 assert(base(ret) == val.data() + val.size());55 }56 {57 auto val = value;58 auto range = std::ranges::subrange(Iter(val.data()), Sent(Iter(val.data() + val.size())));59 std::same_as<Iter> decltype(auto) ret = std::ranges::reverse(range);60 assert(val == expected);61 assert(base(ret) == val.data() + val.size());62 }63}64 65template <class Iter, class Sent = Iter>66constexpr void test_iterators() {67 // simple test68 test<Iter, Sent, 4>({1, 2, 3, 4}, {4, 3, 2, 1});69 // check that an odd number of elements works70 test<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, {7, 6, 5, 4, 3, 2, 1});71 // check that an empty range works72 test<Iter, Sent, 0>({}, {});73 // check that a single element works74 test<Iter, Sent, 1>({5}, {5});75}76 77struct SwapCounter {78 int* counter;79 constexpr SwapCounter(int* counter_) : counter(counter_) {}80 friend constexpr void swap(SwapCounter& lhs, SwapCounter&) { ++*lhs.counter; }81};82 83constexpr bool test() {84 test_iterators<bidirectional_iterator<int*>>();85 test_iterators<bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>();86 test_iterators<random_access_iterator<int*>>();87 test_iterators<random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>>>();88 test_iterators<contiguous_iterator<int*>>();89 test_iterators<contiguous_iterator<int*>, sentinel_wrapper<contiguous_iterator<int*>>>();90 test_iterators<int*>();91 92 test_iterators<ProxyIterator<bidirectional_iterator<int*>>>();93 test_iterators<ProxyIterator<random_access_iterator<int*>>>();94 test_iterators<ProxyIterator<contiguous_iterator<int*>>>();95 96 // check that std::ranges::dangling is returned97 {98 [[maybe_unused]] std::same_as<std::ranges::dangling> auto ret = std::ranges::reverse(std::array {1, 2, 3, 4});99 }100 101 {102 {103 int counter = 0;104 SwapCounter a[] = {&counter, &counter, &counter, &counter};105 std::ranges::reverse(a);106 assert(counter == 2);107 }108 {109 int counter = 0;110 SwapCounter a[] = {&counter, &counter, &counter, &counter};111 std::ranges::reverse(a, a + 4);112 assert(counter == 2);113 }114 }115 116 // Move only types work for ProxyIterator117 {118 {119 MoveOnly a[] = {1, 2, 3};120 ProxyRange proxyA{a};121 std::ranges::reverse(proxyA.begin(), proxyA.end());122 assert(a[0].get() == 3);123 assert(a[1].get() == 2);124 assert(a[2].get() == 1);125 }126 {127 MoveOnly a[] = {1, 2, 3};128 ProxyRange proxyA{a};129 std::ranges::reverse(proxyA);130 assert(a[0].get() == 3);131 assert(a[1].get() == 2);132 assert(a[2].get() == 1);133 }134 }135 136 return true;137}138 139int main(int, char**) {140 test();141 static_assert(test());142 143 return 0;144}145