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
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 test
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});
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 returned
97 {
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 ProxyIterator
117 {
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

source code of libcxx/test/std/algorithms/alg.modifying.operations/alg.reverse/ranges.reverse.pass.cpp