1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<permutable I, sentinel_for<I> S>
14 // constexpr subrange<I> rotate(I first, I middle, S last); // since C++20
16 // template<forward_range R>
17 // requires permutable<iterator_t<R>>
18 // constexpr borrowed_subrange_t<R> rotate(R&& r, iterator_t<R> middle); // Since C++20
25 #include "almost_satisfies_types.h"
26 #include "test_iterators.h"
28 // Test constraints of the (iterator, sentinel) overload.
29 // ======================================================
31 template <class Iter
= int*, class Sent
= int*>
32 concept HasRotateIter
=
33 requires(Iter
&& iter
, Sent
&& sent
) {
34 std::ranges::rotate(std::forward
<Iter
>(iter
), std::forward
<Iter
>(iter
), std::forward
<Sent
>(sent
));
37 static_assert(HasRotateIter
<int*, int*>);
40 static_assert(!HasRotateIter
<PermutableNotForwardIterator
>);
41 static_assert(!HasRotateIter
<PermutableNotSwappable
>);
43 // !sentinel_for<S, I>
44 static_assert(!HasRotateIter
<int*, SentinelForNotSemiregular
>);
45 static_assert(!HasRotateIter
<int*, SentinelForNotWeaklyEqualityComparableWith
>);
47 // Test constraints of the (range) overload.
48 // =========================================
50 template <class Range
>
51 concept HasRotateRange
=
52 requires(Range
&& range
, std::ranges::iterator_t
<Range
> iter
) {
53 std::ranges::rotate(std::forward
<Range
>(range
), iter
);
57 using R
= UncheckedRange
<T
>;
59 static_assert(HasRotateRange
<R
<int*>>);
62 static_assert(!HasRotateRange
<ForwardRangeNotDerivedFrom
>);
63 static_assert(!HasRotateRange
<ForwardRangeNotIncrementable
>);
64 static_assert(!HasRotateRange
<ForwardRangeNotSentinelSemiregular
>);
65 static_assert(!HasRotateRange
<ForwardRangeNotSentinelEqualityComparableWith
>);
67 // !permutable<iterator_t<R>>
68 static_assert(!HasRotateRange
<PermutableRangeNotForwardIterator
>);
69 static_assert(!HasRotateRange
<PermutableRangeNotSwappable
>);
71 template <class Iter
, class Sent
, std::size_t N
>
72 constexpr void test_one(const std::array
<int, N
> input
, std::size_t mid_index
, std::array
<int, N
> expected
) {
73 assert(mid_index
<= N
);
75 { // (iterator, sentinel) overload.
77 auto begin
= Iter(in
.data());
78 auto mid
= Iter(in
.data() + mid_index
);
79 auto end
= Sent(Iter(in
.data() + in
.size()));
81 std::same_as
<std::ranges::subrange
<Iter
>> decltype(auto) result
= std::ranges::rotate(begin
, mid
, end
);
82 assert(base(result
.begin()) == in
.data() + in
.size() - mid_index
);
83 assert(base(result
.end()) == in
.data() + in
.size());
84 assert(in
== expected
);
87 { // (range) overload.
89 auto begin
= Iter(in
.data());
90 auto mid
= Iter(in
.data() + mid_index
);
91 auto end
= Sent(Iter(in
.data() + in
.size()));
92 auto range
= std::ranges::subrange(std::move(begin
), std::move(end
));
94 std::same_as
<std::ranges::subrange
<Iter
>> decltype(auto) result
= std::ranges::rotate(range
, mid
);
95 assert(base(result
.begin()) == in
.data() + in
.size() - mid_index
);
96 assert(base(result
.end()) == in
.data() + in
.size());
97 assert(in
== expected
);
101 template <class Iter
, class Sent
>
102 constexpr void test_iter_sent() {
104 test_one
<Iter
, Sent
, 0>({}, 0, {});
106 // 1-element sequence.
107 test_one
<Iter
, Sent
, 1>({1}, 0, {1});
109 // 2-element sequence.
110 test_one
<Iter
, Sent
, 2>({1, 2}, 1, {2, 1});
112 // 3-element sequence.
113 test_one
<Iter
, Sent
, 3>({1, 2, 3}, 1, {2, 3, 1});
114 test_one
<Iter
, Sent
, 3>({1, 2, 3}, 2, {3, 1, 2});
117 test_one
<Iter
, Sent
, 7>({1, 2, 3, 4, 5, 6, 7}, 2, {3, 4, 5, 6, 7, 1, 2});
119 // Rotate around the middle.
120 test_one
<Iter
, Sent
, 7>({1, 2, 3, 4, 5, 6, 7}, 3, {4, 5, 6, 7, 1, 2, 3});
122 // Rotate around the 1st element (no-op).
123 test_one
<Iter
, Sent
, 7>({1, 2, 3, 4, 5, 6, 7}, 0, {1, 2, 3, 4, 5, 6, 7});
125 // Rotate around the 2nd element.
126 test_one
<Iter
, Sent
, 7>({1, 2, 3, 4, 5, 6, 7}, 1, {2, 3, 4, 5, 6, 7, 1});
128 // Rotate around the last element.
129 test_one
<Iter
, Sent
, 7>({1, 2, 3, 4, 5, 6, 7}, 6, {7, 1, 2, 3, 4, 5, 6});
131 // Pass `end()` as `mid` (no-op).
132 test_one
<Iter
, Sent
, 7>({1, 2, 3, 4, 5, 6, 7}, 7, {1, 2, 3, 4, 5, 6, 7});
135 template <class Iter
>
136 constexpr void test_iter() {
137 test_iter_sent
<Iter
, Iter
>();
138 test_iter_sent
<Iter
, sentinel_wrapper
<Iter
>>();
141 constexpr void test_iterators() {
142 test_iter
<forward_iterator
<int*>>();
143 test_iter
<bidirectional_iterator
<int*>>();
144 test_iter
<random_access_iterator
<int*>>();
145 test_iter
<contiguous_iterator
<int*>>();
149 constexpr bool test() {
152 { // Complexity: at most `last - first` swaps.
153 const std::array input
= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
154 auto expected
= static_cast<int>(input
.size());
159 auto begin
= adl::Iterator::TrackSwaps(in
.data(), swaps
);
160 auto end
= adl::Iterator::TrackSwaps(in
.data() + in
.size(), swaps
);
162 for (std::size_t mid
= 0; mid
!= input
.size(); ++mid
) {
163 std::ranges::rotate(begin
, begin
+ mid
, end
);
164 assert(swaps
<= expected
);
171 auto begin
= adl::Iterator::TrackSwaps(in
.data(), swaps
);
172 auto end
= adl::Iterator::TrackSwaps(in
.data() + in
.size(), swaps
);
173 auto range
= std::ranges::subrange(begin
, end
);
175 for (std::size_t mid
= 0; mid
!= input
.size(); ++mid
) {
176 std::ranges::rotate(range
, begin
+ mid
);
177 assert(swaps
<= expected
);
185 int main(int, char**) {
187 static_assert(test());