//===----------------------------------------------------------------------===// // // 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> // constexpr subrange rotate(I first, I middle, S last); // since C++20 // // template // requires permutable> // constexpr borrowed_subrange_t rotate(R&& r, iterator_t middle); // Since C++20 #include #include #include #include #include #include "almost_satisfies_types.h" #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" // Test constraints of the (iterator, sentinel) overload. // ====================================================== template concept HasRotateIter = requires(Iter&& iter, Sent&& sent) { std::ranges::rotate(std::forward(iter), std::forward(iter), std::forward(sent)); }; static_assert(HasRotateIter); // !permutable static_assert(!HasRotateIter); static_assert(!HasRotateIter); // !sentinel_for static_assert(!HasRotateIter); static_assert(!HasRotateIter); // Test constraints of the (range) overload. // ========================================= template concept HasRotateRange = requires(Range&& range, std::ranges::iterator_t iter) { std::ranges::rotate(std::forward(range), iter); }; template using R = UncheckedRange; static_assert(HasRotateRange>); // !forward_range static_assert(!HasRotateRange); static_assert(!HasRotateRange); static_assert(!HasRotateRange); static_assert(!HasRotateRange); // !permutable> static_assert(!HasRotateRange); static_assert(!HasRotateRange); template constexpr void test_one(const std::array input, std::size_t mid_index, std::array expected) { assert(mid_index <= N); { // (iterator, sentinel) overload. auto in = input; auto begin = Iter(in.data()); auto mid = Iter(in.data() + mid_index); auto end = Sent(Iter(in.data() + in.size())); std::same_as> decltype(auto) result = std::ranges::rotate(begin, mid, end); assert(base(result.begin()) == in.data() + in.size() - mid_index); assert(base(result.end()) == in.data() + in.size()); assert(in == expected); } { // (range) overload. auto in = input; auto begin = Iter(in.data()); auto mid = Iter(in.data() + mid_index); auto end = Sent(Iter(in.data() + in.size())); auto range = std::ranges::subrange(std::move(begin), std::move(end)); std::same_as> decltype(auto) result = std::ranges::rotate(range, mid); assert(base(result.begin()) == in.data() + in.size() - mid_index); assert(base(result.end()) == in.data() + in.size()); assert(in == expected); } } template constexpr void test_iter_sent() { // Empty sequence. test_one({}, 0, {}); // 1-element sequence. test_one({1}, 0, {1}); // 2-element sequence. test_one({1, 2}, 1, {2, 1}); // 3-element sequence. test_one({1, 2, 3}, 1, {2, 3, 1}); test_one({1, 2, 3}, 2, {3, 1, 2}); // Longer sequence. test_one({1, 2, 3, 4, 5, 6, 7}, 2, {3, 4, 5, 6, 7, 1, 2}); // Rotate around the middle. test_one({1, 2, 3, 4, 5, 6, 7}, 3, {4, 5, 6, 7, 1, 2, 3}); // Rotate around the 1st element (no-op). test_one({1, 2, 3, 4, 5, 6, 7}, 0, {1, 2, 3, 4, 5, 6, 7}); // Rotate around the 2nd element. test_one({1, 2, 3, 4, 5, 6, 7}, 1, {2, 3, 4, 5, 6, 7, 1}); // Rotate around the last element. test_one({1, 2, 3, 4, 5, 6, 7}, 6, {7, 1, 2, 3, 4, 5, 6}); // Pass `end()` as `mid` (no-op). test_one({1, 2, 3, 4, 5, 6, 7}, 7, {1, 2, 3, 4, 5, 6, 7}); } #if TEST_STD_VER >= 23 template TEST_CONSTEXPR_CXX20 bool test_vector_bool() { for (int offset = -4; offset <= 4; ++offset) { std::vector a(N, false); std::size_t mid = N / 2 + offset; for (std::size_t i = mid; i < N; ++i) a[i] = true; // (iterator, sentinel)-overload std::ranges::rotate(std::ranges::begin(a), std::ranges::begin(a) + mid, std::ranges::end(a)); for (std::size_t i = 0; i < N; ++i) assert(a[i] == (i < N - mid)); // range-overload std::ranges::rotate(a, std::ranges::begin(a) + (N - mid)); for (std::size_t i = 0; i < N; ++i) assert(a[i] == (i >= mid)); } return true; }; #endif constexpr bool test() { types::for_each(types::forward_iterator_list(), []() { test_iter_sent(); test_iter_sent>(); }); { // Complexity: at most `last - first` swaps. const std::array input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto expected = static_cast(input.size()); { auto in = input; int swaps = 0; auto begin = adl::Iterator::TrackSwaps(in.data(), swaps); auto end = adl::Iterator::TrackSwaps(in.data() + in.size(), swaps); for (std::size_t mid = 0; mid != input.size(); ++mid) { std::ranges::rotate(begin, begin + mid, end); assert(swaps <= expected); } } { auto in = input; int swaps = 0; auto begin = adl::Iterator::TrackSwaps(in.data(), swaps); auto end = adl::Iterator::TrackSwaps(in.data() + in.size(), swaps); auto range = std::ranges::subrange(begin, end); for (std::size_t mid = 0; mid != input.size(); ++mid) { std::ranges::rotate(range, begin + mid); assert(swaps <= expected); } } } #if TEST_STD_VER >= 23 test_vector_bool<8>(); test_vector_bool<19>(); test_vector_bool<32>(); test_vector_bool<49>(); test_vector_bool<64>(); test_vector_bool<199>(); test_vector_bool<256>(); #endif return true; } int main(int, char**) { test(); static_assert(test()); return 0; }