1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
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);
25 #include "almost_satisfies_types.h"
27 #include "test_iterators.h"
29 template <class Iter
, class Sent
= sentinel_wrapper
<Iter
>>
30 concept HasReverseIt
= requires (Iter first
, Sent last
) { std::ranges::reverse(first
, last
); };
32 static_assert(HasReverseIt
<int*>);
33 static_assert(!HasReverseIt
<BidirectionalIteratorNotDerivedFrom
>);
34 static_assert(!HasReverseIt
<BidirectionalIteratorNotDecrementable
>);
35 static_assert(!HasReverseIt
<PermutableNotForwardIterator
>);
36 static_assert(!HasReverseIt
<PermutableNotSwappable
>);
39 template <class Range
>
40 concept HasReverseR
= requires (Range range
) { std::ranges::reverse(range
); };
42 static_assert(HasReverseR
<UncheckedRange
<int*>>);
43 static_assert(!HasReverseR
<BidirectionalRangeNotDerivedFrom
>);
44 static_assert(!HasReverseR
<BidirectionalRangeNotDecrementable
>);
45 static_assert(!HasReverseR
<PermutableRangeNotForwardIterator
>);
46 static_assert(!HasReverseR
<PermutableRangeNotSwappable
>);
48 template <class Iter
, class Sent
, std::size_t N
>
49 constexpr void test(std::array
<int, N
> value
, std::array
<int, N
> expected
) {
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());
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());
65 template <class Iter
, class Sent
= Iter
>
66 constexpr void test_iterators() {
68 test
<Iter
, Sent
, 4>({1, 2, 3, 4}, {4, 3, 2, 1});
69 // check that an odd number of elements works
70 test
<Iter
, Sent
, 7>({1, 2, 3, 4, 5, 6, 7}, {7, 6, 5, 4, 3, 2, 1});
71 // check that an empty range works
72 test
<Iter
, Sent
, 0>({}, {});
73 // check that a single element works
74 test
<Iter
, Sent
, 1>({5}, {5});
79 constexpr SwapCounter(int* counter_
) : counter(counter_
) {}
80 friend constexpr void swap(SwapCounter
& lhs
, SwapCounter
&) { ++*lhs
.counter
; }
83 constexpr 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*>();
92 test_iterators
<ProxyIterator
<bidirectional_iterator
<int*>>>();
93 test_iterators
<ProxyIterator
<random_access_iterator
<int*>>>();
94 test_iterators
<ProxyIterator
<contiguous_iterator
<int*>>>();
96 // check that std::ranges::dangling is returned
98 [[maybe_unused
]] std::same_as
<std::ranges::dangling
> auto ret
= std::ranges::reverse(std::array
{1, 2, 3, 4});
104 SwapCounter a
[] = {&counter
, &counter
, &counter
, &counter
};
105 std::ranges::reverse(a
);
106 assert(counter
== 2);
110 SwapCounter a
[] = {&counter
, &counter
, &counter
, &counter
};
111 std::ranges::reverse(a
, a
+ 4);
112 assert(counter
== 2);
116 // Move only types work for ProxyIterator
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);
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);
139 int main(int, char**) {
141 static_assert(test());