11d1a191eSNikolas Klauser //===----------------------------------------------------------------------===//
21d1a191eSNikolas Klauser //
31d1a191eSNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41d1a191eSNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
51d1a191eSNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61d1a191eSNikolas Klauser //
71d1a191eSNikolas Klauser //===----------------------------------------------------------------------===//
81d1a191eSNikolas Klauser 
91d1a191eSNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17
101d1a191eSNikolas Klauser 
111d1a191eSNikolas Klauser // <algorithm>
121d1a191eSNikolas Klauser 
131d1a191eSNikolas Klauser // template<bidirectional_iterator I, sentinel_for<I> S>
141d1a191eSNikolas Klauser //   requires permutable<I>
151d1a191eSNikolas Klauser //   constexpr I ranges::reverse(I first, S last);
161d1a191eSNikolas Klauser // template<bidirectional_range R>
171d1a191eSNikolas Klauser //   requires permutable<iterator_t<R>>
181d1a191eSNikolas Klauser //   constexpr borrowed_iterator_t<R> ranges::reverse(R&& r);
191d1a191eSNikolas Klauser 
201d1a191eSNikolas Klauser #include <algorithm>
211d1a191eSNikolas Klauser #include <array>
221d1a191eSNikolas Klauser #include <concepts>
231d1a191eSNikolas Klauser #include <ranges>
241d1a191eSNikolas Klauser 
251d1a191eSNikolas Klauser #include "almost_satisfies_types.h"
26a81cc1fcSHui Xie #include "MoveOnly.h"
271d1a191eSNikolas Klauser #include "test_iterators.h"
281d1a191eSNikolas Klauser 
291d1a191eSNikolas Klauser template <class Iter, class Sent = sentinel_wrapper<Iter>>
301d1a191eSNikolas Klauser concept HasReverseIt = requires (Iter first, Sent last) { std::ranges::reverse(first, last); };
311d1a191eSNikolas Klauser 
321d1a191eSNikolas Klauser static_assert(HasReverseIt<int*>);
331d1a191eSNikolas Klauser static_assert(!HasReverseIt<BidirectionalIteratorNotDerivedFrom>);
341d1a191eSNikolas Klauser static_assert(!HasReverseIt<BidirectionalIteratorNotDecrementable>);
351d1a191eSNikolas Klauser static_assert(!HasReverseIt<PermutableNotForwardIterator>);
361d1a191eSNikolas Klauser static_assert(!HasReverseIt<PermutableNotSwappable>);
371d1a191eSNikolas Klauser 
381d1a191eSNikolas Klauser 
391d1a191eSNikolas Klauser template <class Range>
401d1a191eSNikolas Klauser concept HasReverseR = requires (Range range) { std::ranges::reverse(range); };
411d1a191eSNikolas Klauser 
421d1a191eSNikolas Klauser static_assert(HasReverseR<UncheckedRange<int*>>);
431d1a191eSNikolas Klauser static_assert(!HasReverseR<BidirectionalRangeNotDerivedFrom>);
441d1a191eSNikolas Klauser static_assert(!HasReverseR<BidirectionalRangeNotDecrementable>);
451d1a191eSNikolas Klauser static_assert(!HasReverseR<PermutableRangeNotForwardIterator>);
461d1a191eSNikolas Klauser static_assert(!HasReverseR<PermutableRangeNotSwappable>);
471d1a191eSNikolas Klauser 
48*fb855eb9SMark de Wever template <class Iter, class Sent, std::size_t N>
test(std::array<int,N> value,std::array<int,N> expected)491d1a191eSNikolas Klauser constexpr void test(std::array<int, N> value, std::array<int, N> expected) {
501d1a191eSNikolas Klauser   {
511d1a191eSNikolas Klauser     auto val = value;
521d1a191eSNikolas Klauser     std::same_as<Iter> decltype(auto) ret = std::ranges::reverse(Iter(val.data()), Sent(Iter(val.data() + val.size())));
531d1a191eSNikolas Klauser     assert(val == expected);
541d1a191eSNikolas Klauser     assert(base(ret) == val.data() + val.size());
551d1a191eSNikolas Klauser   }
561d1a191eSNikolas Klauser   {
571d1a191eSNikolas Klauser     auto val = value;
581d1a191eSNikolas Klauser     auto range = std::ranges::subrange(Iter(val.data()), Sent(Iter(val.data() + val.size())));
591d1a191eSNikolas Klauser     std::same_as<Iter> decltype(auto) ret = std::ranges::reverse(range);
601d1a191eSNikolas Klauser     assert(val == expected);
611d1a191eSNikolas Klauser     assert(base(ret) == val.data() + val.size());
621d1a191eSNikolas Klauser   }
631d1a191eSNikolas Klauser }
641d1a191eSNikolas Klauser 
651d1a191eSNikolas Klauser template <class Iter, class Sent = Iter>
test_iterators()661d1a191eSNikolas Klauser constexpr void test_iterators() {
671d1a191eSNikolas Klauser   // simple test
681d1a191eSNikolas Klauser   test<Iter, Sent, 4>({1, 2, 3, 4}, {4, 3, 2, 1});
691d1a191eSNikolas Klauser   // check that an odd number of elements works
701d1a191eSNikolas Klauser   test<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, {7, 6, 5, 4, 3, 2, 1});
711d1a191eSNikolas Klauser   // check that an empty range works
721d1a191eSNikolas Klauser   test<Iter, Sent, 0>({}, {});
731d1a191eSNikolas Klauser   // check that a single element works
741d1a191eSNikolas Klauser   test<Iter, Sent, 1>({5}, {5});
751d1a191eSNikolas Klauser }
761d1a191eSNikolas Klauser 
771d1a191eSNikolas Klauser struct SwapCounter {
781d1a191eSNikolas Klauser   int* counter;
SwapCounterSwapCounter791d1a191eSNikolas Klauser   constexpr SwapCounter(int* counter_) : counter(counter_) {}
swap(SwapCounter & lhs,SwapCounter &)801d1a191eSNikolas Klauser   friend constexpr void swap(SwapCounter& lhs, SwapCounter&) { ++*lhs.counter; }
811d1a191eSNikolas Klauser };
821d1a191eSNikolas Klauser 
test()831d1a191eSNikolas Klauser constexpr bool test() {
841d1a191eSNikolas Klauser   test_iterators<bidirectional_iterator<int*>>();
851d1a191eSNikolas Klauser   test_iterators<bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>();
861d1a191eSNikolas Klauser   test_iterators<random_access_iterator<int*>>();
871d1a191eSNikolas Klauser   test_iterators<random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>>>();
881d1a191eSNikolas Klauser   test_iterators<contiguous_iterator<int*>>();
891d1a191eSNikolas Klauser   test_iterators<contiguous_iterator<int*>, sentinel_wrapper<contiguous_iterator<int*>>>();
901d1a191eSNikolas Klauser   test_iterators<int*>();
911d1a191eSNikolas Klauser 
92a81cc1fcSHui Xie   test_iterators<ProxyIterator<bidirectional_iterator<int*>>>();
93a81cc1fcSHui Xie   test_iterators<ProxyIterator<random_access_iterator<int*>>>();
94a81cc1fcSHui Xie   test_iterators<ProxyIterator<contiguous_iterator<int*>>>();
95a81cc1fcSHui Xie 
961d1a191eSNikolas Klauser   // check that std::ranges::dangling is returned
971d1a191eSNikolas Klauser   {
981d1a191eSNikolas Klauser     [[maybe_unused]] std::same_as<std::ranges::dangling> auto ret = std::ranges::reverse(std::array {1, 2, 3, 4});
991d1a191eSNikolas Klauser   }
1001d1a191eSNikolas Klauser 
1011d1a191eSNikolas Klauser   {
1021d1a191eSNikolas Klauser     {
1031d1a191eSNikolas Klauser       int counter = 0;
1041d1a191eSNikolas Klauser       SwapCounter a[] = {&counter, &counter, &counter, &counter};
1051d1a191eSNikolas Klauser       std::ranges::reverse(a);
1061d1a191eSNikolas Klauser       assert(counter == 2);
1071d1a191eSNikolas Klauser     }
1081d1a191eSNikolas Klauser     {
1091d1a191eSNikolas Klauser       int counter = 0;
1101d1a191eSNikolas Klauser       SwapCounter a[] = {&counter, &counter, &counter, &counter};
1111d1a191eSNikolas Klauser       std::ranges::reverse(a, a + 4);
1121d1a191eSNikolas Klauser       assert(counter == 2);
1131d1a191eSNikolas Klauser     }
1141d1a191eSNikolas Klauser   }
1151d1a191eSNikolas Klauser 
116a81cc1fcSHui Xie   // Move only types work for ProxyIterator
117a81cc1fcSHui Xie   {
118a81cc1fcSHui Xie     {
119a81cc1fcSHui Xie       MoveOnly a[] = {1, 2, 3};
120a81cc1fcSHui Xie       ProxyRange proxyA{a};
121a81cc1fcSHui Xie       std::ranges::reverse(proxyA.begin(), proxyA.end());
122a81cc1fcSHui Xie       assert(a[0].get() == 3);
123a81cc1fcSHui Xie       assert(a[1].get() == 2);
124a81cc1fcSHui Xie       assert(a[2].get() == 1);
125a81cc1fcSHui Xie     }
126a81cc1fcSHui Xie     {
127a81cc1fcSHui Xie       MoveOnly a[] = {1, 2, 3};
128a81cc1fcSHui Xie       ProxyRange proxyA{a};
129a81cc1fcSHui Xie       std::ranges::reverse(proxyA);
130a81cc1fcSHui Xie       assert(a[0].get() == 3);
131a81cc1fcSHui Xie       assert(a[1].get() == 2);
132a81cc1fcSHui Xie       assert(a[2].get() == 1);
133a81cc1fcSHui Xie     }
134a81cc1fcSHui Xie   }
135a81cc1fcSHui Xie 
1361d1a191eSNikolas Klauser   return true;
1371d1a191eSNikolas Klauser }
1381d1a191eSNikolas Klauser 
main(int,char **)1391d1a191eSNikolas Klauser int main(int, char**) {
1401d1a191eSNikolas Klauser   test();
1411d1a191eSNikolas Klauser   static_assert(test());
1421d1a191eSNikolas Klauser 
1431d1a191eSNikolas Klauser   return 0;
1441d1a191eSNikolas Klauser }
145