1134723edSLouis Dionne //===----------------------------------------------------------------------===//
2134723edSLouis Dionne //
3134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6134723edSLouis Dionne //
7134723edSLouis Dionne //===----------------------------------------------------------------------===//
8134723edSLouis Dionne
9134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_ROTATE_H
10134723edSLouis Dionne #define _LIBCPP___ALGORITHM_ROTATE_H
11134723edSLouis Dionne
128ed702b8SKonstantin Varlamov #include <__algorithm/iterator_operations.h>
13134723edSLouis Dionne #include <__algorithm/move.h>
14134723edSLouis Dionne #include <__algorithm/move_backward.h>
156adbc83eSChristopher Di Bella #include <__algorithm/swap_ranges.h>
16134723edSLouis Dionne #include <__config>
17134723edSLouis Dionne #include <__iterator/iterator_traits.h>
18*580f6048SNikolas Klauser #include <__type_traits/is_trivially_assignable.h>
1952915d78SNikolas Klauser #include <__utility/move.h>
2036c746caSKonstantin Varlamov #include <__utility/pair.h>
21134723edSLouis Dionne
22134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23134723edSLouis Dionne # pragma GCC system_header
24134723edSLouis Dionne #endif
25134723edSLouis Dionne
267b462251SLouis Dionne _LIBCPP_PUSH_MACROS
277b462251SLouis Dionne #include <__undef_macros>
287b462251SLouis Dionne
29134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
30134723edSLouis Dionne
318ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _ForwardIterator>
325146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
__rotate_left(_ForwardIterator __first,_ForwardIterator __last)339783f28cSLouis Dionne __rotate_left(_ForwardIterator __first, _ForwardIterator __last) {
34134723edSLouis Dionne typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
3536c746caSKonstantin Varlamov using _Ops = _IterOps<_AlgPolicy>;
3636c746caSKonstantin Varlamov
3736c746caSKonstantin Varlamov value_type __tmp = _Ops::__iter_move(__first);
389783f28cSLouis Dionne _ForwardIterator __lm1 = std::__move<_AlgPolicy>(_Ops::next(__first), __last, __first).second;
3977a00c0dSLouis Dionne *__lm1 = std::move(__tmp);
40134723edSLouis Dionne return __lm1;
41134723edSLouis Dionne }
42134723edSLouis Dionne
438ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _BidirectionalIterator>
445146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator
__rotate_right(_BidirectionalIterator __first,_BidirectionalIterator __last)459783f28cSLouis Dionne __rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last) {
46134723edSLouis Dionne typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
4736c746caSKonstantin Varlamov using _Ops = _IterOps<_AlgPolicy>;
4836c746caSKonstantin Varlamov
4936c746caSKonstantin Varlamov _BidirectionalIterator __lm1 = _Ops::prev(__last);
5036c746caSKonstantin Varlamov value_type __tmp = _Ops::__iter_move(__lm1);
515629d492Svarconst _BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last)).second;
5277a00c0dSLouis Dionne *__first = std::move(__tmp);
53134723edSLouis Dionne return __fp1;
54134723edSLouis Dionne }
55134723edSLouis Dionne
568ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _ForwardIterator>
575146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _ForwardIterator
__rotate_forward(_ForwardIterator __first,_ForwardIterator __middle,_ForwardIterator __last)589783f28cSLouis Dionne __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) {
59134723edSLouis Dionne _ForwardIterator __i = __middle;
609783f28cSLouis Dionne while (true) {
618ed702b8SKonstantin Varlamov _IterOps<_AlgPolicy>::iter_swap(__first, __i);
62134723edSLouis Dionne ++__first;
63134723edSLouis Dionne if (++__i == __last)
64134723edSLouis Dionne break;
65134723edSLouis Dionne if (__first == __middle)
66134723edSLouis Dionne __middle = __i;
67134723edSLouis Dionne }
68134723edSLouis Dionne _ForwardIterator __r = __first;
699783f28cSLouis Dionne if (__first != __middle) {
70134723edSLouis Dionne __i = __middle;
719783f28cSLouis Dionne while (true) {
728ed702b8SKonstantin Varlamov _IterOps<_AlgPolicy>::iter_swap(__first, __i);
73134723edSLouis Dionne ++__first;
749783f28cSLouis Dionne if (++__i == __last) {
75134723edSLouis Dionne if (__first == __middle)
76134723edSLouis Dionne break;
77134723edSLouis Dionne __i = __middle;
789783f28cSLouis Dionne } else if (__first == __middle)
79134723edSLouis Dionne __middle = __i;
80134723edSLouis Dionne }
81134723edSLouis Dionne }
82134723edSLouis Dionne return __r;
83134723edSLouis Dionne }
84134723edSLouis Dionne
85134723edSLouis Dionne template <typename _Integral>
__algo_gcd(_Integral __x,_Integral __y)869783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Integral __algo_gcd(_Integral __x, _Integral __y) {
879783f28cSLouis Dionne do {
88134723edSLouis Dionne _Integral __t = __x % __y;
89134723edSLouis Dionne __x = __y;
90134723edSLouis Dionne __y = __t;
91134723edSLouis Dionne } while (__y);
92134723edSLouis Dionne return __x;
93134723edSLouis Dionne }
94134723edSLouis Dionne
958ed702b8SKonstantin Varlamov template <class _AlgPolicy, typename _RandomAccessIterator>
965146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _RandomAccessIterator
__rotate_gcd(_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last)979783f28cSLouis Dionne __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) {
98134723edSLouis Dionne typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
99134723edSLouis Dionne typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
10036c746caSKonstantin Varlamov using _Ops = _IterOps<_AlgPolicy>;
101134723edSLouis Dionne
102134723edSLouis Dionne const difference_type __m1 = __middle - __first;
10336c746caSKonstantin Varlamov const difference_type __m2 = _Ops::distance(__middle, __last);
1049783f28cSLouis Dionne if (__m1 == __m2) {
10536c746caSKonstantin Varlamov std::__swap_ranges<_AlgPolicy>(__first, __middle, __middle, __last);
106134723edSLouis Dionne return __middle;
107134723edSLouis Dionne }
10877a00c0dSLouis Dionne const difference_type __g = std::__algo_gcd(__m1, __m2);
1099783f28cSLouis Dionne for (_RandomAccessIterator __p = __first + __g; __p != __first;) {
11036c746caSKonstantin Varlamov value_type __t(_Ops::__iter_move(--__p));
111134723edSLouis Dionne _RandomAccessIterator __p1 = __p;
112134723edSLouis Dionne _RandomAccessIterator __p2 = __p1 + __m1;
1139783f28cSLouis Dionne do {
11436c746caSKonstantin Varlamov *__p1 = _Ops::__iter_move(__p2);
115134723edSLouis Dionne __p1 = __p2;
11636c746caSKonstantin Varlamov const difference_type __d = _Ops::distance(__p2, __last);
117134723edSLouis Dionne if (__m1 < __d)
118134723edSLouis Dionne __p2 += __m1;
119134723edSLouis Dionne else
120134723edSLouis Dionne __p2 = __first + (__m1 - __d);
121134723edSLouis Dionne } while (__p2 != __p);
12277a00c0dSLouis Dionne *__p1 = std::move(__t);
123134723edSLouis Dionne }
124134723edSLouis Dionne return __first + __m2;
125134723edSLouis Dionne }
126134723edSLouis Dionne
1278ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _ForwardIterator>
1289783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
__rotate_impl(_ForwardIterator __first,_ForwardIterator __middle,_ForwardIterator __last,std::forward_iterator_tag)1299783f28cSLouis Dionne __rotate_impl(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, std::forward_iterator_tag) {
130134723edSLouis Dionne typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
1319783f28cSLouis Dionne if (is_trivially_move_assignable<value_type>::value) {
1328ed702b8SKonstantin Varlamov if (_IterOps<_AlgPolicy>::next(__first) == __middle)
1338ed702b8SKonstantin Varlamov return std::__rotate_left<_AlgPolicy>(__first, __last);
134134723edSLouis Dionne }
1358ed702b8SKonstantin Varlamov return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
136134723edSLouis Dionne }
137134723edSLouis Dionne
1388ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _BidirectionalIterator>
__rotate_impl(_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last,bidirectional_iterator_tag)1399783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator __rotate_impl(
1409783f28cSLouis Dionne _BidirectionalIterator __first,
1419783f28cSLouis Dionne _BidirectionalIterator __middle,
1429783f28cSLouis Dionne _BidirectionalIterator __last,
1439783f28cSLouis Dionne bidirectional_iterator_tag) {
144134723edSLouis Dionne typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
1459783f28cSLouis Dionne if (is_trivially_move_assignable<value_type>::value) {
1468ed702b8SKonstantin Varlamov if (_IterOps<_AlgPolicy>::next(__first) == __middle)
1478ed702b8SKonstantin Varlamov return std::__rotate_left<_AlgPolicy>(__first, __last);
1488ed702b8SKonstantin Varlamov if (_IterOps<_AlgPolicy>::next(__middle) == __last)
1498ed702b8SKonstantin Varlamov return std::__rotate_right<_AlgPolicy>(__first, __last);
150134723edSLouis Dionne }
1518ed702b8SKonstantin Varlamov return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
152134723edSLouis Dionne }
153134723edSLouis Dionne
1548ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _RandomAccessIterator>
__rotate_impl(_RandomAccessIterator __first,_RandomAccessIterator __middle,_RandomAccessIterator __last,random_access_iterator_tag)1559783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __rotate_impl(
1569783f28cSLouis Dionne _RandomAccessIterator __first,
1579783f28cSLouis Dionne _RandomAccessIterator __middle,
1589783f28cSLouis Dionne _RandomAccessIterator __last,
1599783f28cSLouis Dionne random_access_iterator_tag) {
160134723edSLouis Dionne typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
1619783f28cSLouis Dionne if (is_trivially_move_assignable<value_type>::value) {
1628ed702b8SKonstantin Varlamov if (_IterOps<_AlgPolicy>::next(__first) == __middle)
1638ed702b8SKonstantin Varlamov return std::__rotate_left<_AlgPolicy>(__first, __last);
1648ed702b8SKonstantin Varlamov if (_IterOps<_AlgPolicy>::next(__middle) == __last)
1658ed702b8SKonstantin Varlamov return std::__rotate_right<_AlgPolicy>(__first, __last);
1668ed702b8SKonstantin Varlamov return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last);
167134723edSLouis Dionne }
1688ed702b8SKonstantin Varlamov return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
1698ed702b8SKonstantin Varlamov }
1708ed702b8SKonstantin Varlamov
17136c746caSKonstantin Varlamov template <class _AlgPolicy, class _Iterator, class _Sentinel>
1729783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iterator, _Iterator>
__rotate(_Iterator __first,_Iterator __middle,_Sentinel __last)17336c746caSKonstantin Varlamov __rotate(_Iterator __first, _Iterator __middle, _Sentinel __last) {
17436c746caSKonstantin Varlamov using _Ret = pair<_Iterator, _Iterator>;
17536c746caSKonstantin Varlamov _Iterator __last_iter = _IterOps<_AlgPolicy>::next(__middle, __last);
1768ed702b8SKonstantin Varlamov
17736c746caSKonstantin Varlamov if (__first == __middle)
17836c746caSKonstantin Varlamov return _Ret(__last_iter, __last_iter);
17936c746caSKonstantin Varlamov if (__middle == __last)
18036c746caSKonstantin Varlamov return _Ret(std::move(__first), std::move(__last_iter));
18136c746caSKonstantin Varlamov
18236c746caSKonstantin Varlamov using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iterator>;
1839783f28cSLouis Dionne auto __result = std::__rotate_impl<_AlgPolicy>(std::move(__first), std::move(__middle), __last_iter, _IterCategory());
18436c746caSKonstantin Varlamov
18536c746caSKonstantin Varlamov return _Ret(std::move(__result), std::move(__last_iter));
186134723edSLouis Dionne }
187134723edSLouis Dionne
188134723edSLouis Dionne template <class _ForwardIterator>
1899783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
rotate(_ForwardIterator __first,_ForwardIterator __middle,_ForwardIterator __last)1909783f28cSLouis Dionne rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) {
1919783f28cSLouis Dionne return std::__rotate<_ClassicAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last)).first;
192134723edSLouis Dionne }
193134723edSLouis Dionne
194134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
195134723edSLouis Dionne
1967b462251SLouis Dionne _LIBCPP_POP_MACROS
1977b462251SLouis Dionne
198134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_ROTATE_H
199