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>
test(std::array<int,N> value,std::array<int,N> expected)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>
test_iterators()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;
SwapCounterSwapCounter80   constexpr SwapCounter(int* counter_) : counter(counter_) {}
swap(SwapCounter & lhs,SwapCounter &)81   friend constexpr void swap(SwapCounter& lhs, SwapCounter&) { ++*lhs.counter; }
82 };
83 
test()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 
main(int,char **)140 int main(int, char**) {
141   test();
142   static_assert(test());
143 
144   return 0;
145 }
146