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