//===----------------------------------------------------------------------===// // // 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 "almost_satisfies_types.h" #include "test_iterators.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}); } template constexpr void test_iter() { test_iter_sent(); test_iter_sent>(); } constexpr void test_iterators() { test_iter>(); test_iter>(); test_iter>(); test_iter>(); test_iter(); } constexpr bool test() { test_iterators(); { // 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); } } } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }