//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // // template S> // requires permutable // constexpr I ranges::reverse(I first, S last); // template // requires permutable> // constexpr borrowed_iterator_t ranges::reverse(R&& r); #include #include #include #include #include "almost_satisfies_types.h" #include "MoveOnly.h" #include "test_iterators.h" template > concept HasReverseIt = requires (Iter first, Sent last) { std::ranges::reverse(first, last); }; static_assert(HasReverseIt); static_assert(!HasReverseIt); static_assert(!HasReverseIt); static_assert(!HasReverseIt); static_assert(!HasReverseIt); template concept HasReverseR = requires (Range range) { std::ranges::reverse(range); }; static_assert(HasReverseR>); static_assert(!HasReverseR); static_assert(!HasReverseR); static_assert(!HasReverseR); static_assert(!HasReverseR); template constexpr void test(std::array value, std::array expected) { { auto val = value; std::same_as decltype(auto) ret = std::ranges::reverse(Iter(val.data()), Sent(Iter(val.data() + val.size()))); assert(val == expected); assert(base(ret) == val.data() + val.size()); } { auto val = value; auto range = std::ranges::subrange(Iter(val.data()), Sent(Iter(val.data() + val.size()))); std::same_as decltype(auto) ret = std::ranges::reverse(range); assert(val == expected); assert(base(ret) == val.data() + val.size()); } } template constexpr void test_iterators() { // simple test test({1, 2, 3, 4}, {4, 3, 2, 1}); // check that an odd number of elements works test({1, 2, 3, 4, 5, 6, 7}, {7, 6, 5, 4, 3, 2, 1}); // check that an empty range works test({}, {}); // check that a single element works test({5}, {5}); } struct SwapCounter { int* counter; constexpr SwapCounter(int* counter_) : counter(counter_) {} friend constexpr void swap(SwapCounter& lhs, SwapCounter&) { ++*lhs.counter; } }; constexpr bool test() { test_iterators>(); test_iterators, sentinel_wrapper>>(); test_iterators>(); test_iterators, sentinel_wrapper>>(); test_iterators>(); test_iterators, sentinel_wrapper>>(); test_iterators(); test_iterators>>(); test_iterators>>(); test_iterators>>(); // check that std::ranges::dangling is returned { [[maybe_unused]] std::same_as auto ret = std::ranges::reverse(std::array {1, 2, 3, 4}); } { { int counter = 0; SwapCounter a[] = {&counter, &counter, &counter, &counter}; std::ranges::reverse(a); assert(counter == 2); } { int counter = 0; SwapCounter a[] = {&counter, &counter, &counter, &counter}; std::ranges::reverse(a, a + 4); assert(counter == 2); } } // Move only types work for ProxyIterator { { MoveOnly a[] = {1, 2, 3}; ProxyRange proxyA{a}; std::ranges::reverse(proxyA.begin(), proxyA.end()); assert(a[0].get() == 3); assert(a[1].get() == 2); assert(a[2].get() == 1); } { MoveOnly a[] = {1, 2, 3}; ProxyRange proxyA{a}; std::ranges::reverse(proxyA); assert(a[0].get() == 3); assert(a[1].get() == 2); assert(a[2].get() == 1); } } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }