1fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9fe6060f1SDimitry Andric #ifndef _LIBCPP___ALGORITHM_ROTATE_H 10fe6060f1SDimitry Andric #define _LIBCPP___ALGORITHM_ROTATE_H 11fe6060f1SDimitry Andric 12fcaf7f86SDimitry Andric #include <__algorithm/iterator_operations.h> 13fe6060f1SDimitry Andric #include <__algorithm/move.h> 14fe6060f1SDimitry Andric #include <__algorithm/move_backward.h> 15fe6060f1SDimitry Andric #include <__algorithm/swap_ranges.h> 16fe6060f1SDimitry Andric #include <__config> 17fe6060f1SDimitry Andric #include <__iterator/iterator_traits.h> 18*0fca6ea1SDimitry Andric #include <__type_traits/is_trivially_assignable.h> 1981ad6265SDimitry Andric #include <__utility/move.h> 2061cfbce3SDimitry Andric #include <__utility/pair.h> 21fe6060f1SDimitry Andric 22fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 23fe6060f1SDimitry Andric # pragma GCC system_header 24fe6060f1SDimitry Andric #endif 25fe6060f1SDimitry Andric 26b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS 27b3edf446SDimitry Andric #include <__undef_macros> 28b3edf446SDimitry Andric 29fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 30fe6060f1SDimitry Andric 31fcaf7f86SDimitry Andric template <class _AlgPolicy, class _ForwardIterator> 32bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator 33cb14a3feSDimitry Andric __rotate_left(_ForwardIterator __first, _ForwardIterator __last) { 34fe6060f1SDimitry Andric typedef typename iterator_traits<_ForwardIterator>::value_type value_type; 3561cfbce3SDimitry Andric using _Ops = _IterOps<_AlgPolicy>; 3661cfbce3SDimitry Andric 3761cfbce3SDimitry Andric value_type __tmp = _Ops::__iter_move(__first); 38cb14a3feSDimitry Andric _ForwardIterator __lm1 = std::__move<_AlgPolicy>(_Ops::next(__first), __last, __first).second; 395f757f3fSDimitry Andric *__lm1 = std::move(__tmp); 40fe6060f1SDimitry Andric return __lm1; 41fe6060f1SDimitry Andric } 42fe6060f1SDimitry Andric 43fcaf7f86SDimitry Andric template <class _AlgPolicy, class _BidirectionalIterator> 44bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator 45cb14a3feSDimitry Andric __rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last) { 46fe6060f1SDimitry Andric typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; 4761cfbce3SDimitry Andric using _Ops = _IterOps<_AlgPolicy>; 4861cfbce3SDimitry Andric 4961cfbce3SDimitry Andric _BidirectionalIterator __lm1 = _Ops::prev(__last); 5061cfbce3SDimitry Andric value_type __tmp = _Ops::__iter_move(__lm1); 51bdd1243dSDimitry Andric _BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last)).second; 525f757f3fSDimitry Andric *__first = std::move(__tmp); 53fe6060f1SDimitry Andric return __fp1; 54fe6060f1SDimitry Andric } 55fe6060f1SDimitry Andric 56fcaf7f86SDimitry Andric template <class _AlgPolicy, class _ForwardIterator> 57bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _ForwardIterator 58cb14a3feSDimitry Andric __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { 59fe6060f1SDimitry Andric _ForwardIterator __i = __middle; 60cb14a3feSDimitry Andric while (true) { 61fcaf7f86SDimitry Andric _IterOps<_AlgPolicy>::iter_swap(__first, __i); 62fe6060f1SDimitry Andric ++__first; 63fe6060f1SDimitry Andric if (++__i == __last) 64fe6060f1SDimitry Andric break; 65fe6060f1SDimitry Andric if (__first == __middle) 66fe6060f1SDimitry Andric __middle = __i; 67fe6060f1SDimitry Andric } 68fe6060f1SDimitry Andric _ForwardIterator __r = __first; 69cb14a3feSDimitry Andric if (__first != __middle) { 70fe6060f1SDimitry Andric __i = __middle; 71cb14a3feSDimitry Andric while (true) { 72fcaf7f86SDimitry Andric _IterOps<_AlgPolicy>::iter_swap(__first, __i); 73fe6060f1SDimitry Andric ++__first; 74cb14a3feSDimitry Andric if (++__i == __last) { 75fe6060f1SDimitry Andric if (__first == __middle) 76fe6060f1SDimitry Andric break; 77fe6060f1SDimitry Andric __i = __middle; 78cb14a3feSDimitry Andric } else if (__first == __middle) 79fe6060f1SDimitry Andric __middle = __i; 80fe6060f1SDimitry Andric } 81fe6060f1SDimitry Andric } 82fe6060f1SDimitry Andric return __r; 83fe6060f1SDimitry Andric } 84fe6060f1SDimitry Andric 85fe6060f1SDimitry Andric template <typename _Integral> 86cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Integral __algo_gcd(_Integral __x, _Integral __y) { 87cb14a3feSDimitry Andric do { 88fe6060f1SDimitry Andric _Integral __t = __x % __y; 89fe6060f1SDimitry Andric __x = __y; 90fe6060f1SDimitry Andric __y = __t; 91fe6060f1SDimitry Andric } while (__y); 92fe6060f1SDimitry Andric return __x; 93fe6060f1SDimitry Andric } 94fe6060f1SDimitry Andric 95fcaf7f86SDimitry Andric template <class _AlgPolicy, typename _RandomAccessIterator> 96bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _RandomAccessIterator 97cb14a3feSDimitry Andric __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) { 98fe6060f1SDimitry Andric typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; 99fe6060f1SDimitry Andric typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; 10061cfbce3SDimitry Andric using _Ops = _IterOps<_AlgPolicy>; 101fe6060f1SDimitry Andric 102fe6060f1SDimitry Andric const difference_type __m1 = __middle - __first; 10361cfbce3SDimitry Andric const difference_type __m2 = _Ops::distance(__middle, __last); 104cb14a3feSDimitry Andric if (__m1 == __m2) { 10561cfbce3SDimitry Andric std::__swap_ranges<_AlgPolicy>(__first, __middle, __middle, __last); 106fe6060f1SDimitry Andric return __middle; 107fe6060f1SDimitry Andric } 1085f757f3fSDimitry Andric const difference_type __g = std::__algo_gcd(__m1, __m2); 109cb14a3feSDimitry Andric for (_RandomAccessIterator __p = __first + __g; __p != __first;) { 11061cfbce3SDimitry Andric value_type __t(_Ops::__iter_move(--__p)); 111fe6060f1SDimitry Andric _RandomAccessIterator __p1 = __p; 112fe6060f1SDimitry Andric _RandomAccessIterator __p2 = __p1 + __m1; 113cb14a3feSDimitry Andric do { 11461cfbce3SDimitry Andric *__p1 = _Ops::__iter_move(__p2); 115fe6060f1SDimitry Andric __p1 = __p2; 11661cfbce3SDimitry Andric const difference_type __d = _Ops::distance(__p2, __last); 117fe6060f1SDimitry Andric if (__m1 < __d) 118fe6060f1SDimitry Andric __p2 += __m1; 119fe6060f1SDimitry Andric else 120fe6060f1SDimitry Andric __p2 = __first + (__m1 - __d); 121fe6060f1SDimitry Andric } while (__p2 != __p); 1225f757f3fSDimitry Andric *__p1 = std::move(__t); 123fe6060f1SDimitry Andric } 124fe6060f1SDimitry Andric return __first + __m2; 125fe6060f1SDimitry Andric } 126fe6060f1SDimitry Andric 127fcaf7f86SDimitry Andric template <class _AlgPolicy, class _ForwardIterator> 128cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator 129cb14a3feSDimitry Andric __rotate_impl(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, std::forward_iterator_tag) { 130fe6060f1SDimitry Andric typedef typename iterator_traits<_ForwardIterator>::value_type value_type; 131cb14a3feSDimitry Andric if (is_trivially_move_assignable<value_type>::value) { 132fcaf7f86SDimitry Andric if (_IterOps<_AlgPolicy>::next(__first) == __middle) 133fcaf7f86SDimitry Andric return std::__rotate_left<_AlgPolicy>(__first, __last); 134fe6060f1SDimitry Andric } 135fcaf7f86SDimitry Andric return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last); 136fe6060f1SDimitry Andric } 137fe6060f1SDimitry Andric 138fcaf7f86SDimitry Andric template <class _AlgPolicy, class _BidirectionalIterator> 139cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator __rotate_impl( 140cb14a3feSDimitry Andric _BidirectionalIterator __first, 141cb14a3feSDimitry Andric _BidirectionalIterator __middle, 142cb14a3feSDimitry Andric _BidirectionalIterator __last, 143cb14a3feSDimitry Andric bidirectional_iterator_tag) { 144fe6060f1SDimitry Andric typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; 145cb14a3feSDimitry Andric if (is_trivially_move_assignable<value_type>::value) { 146fcaf7f86SDimitry Andric if (_IterOps<_AlgPolicy>::next(__first) == __middle) 147fcaf7f86SDimitry Andric return std::__rotate_left<_AlgPolicy>(__first, __last); 148fcaf7f86SDimitry Andric if (_IterOps<_AlgPolicy>::next(__middle) == __last) 149fcaf7f86SDimitry Andric return std::__rotate_right<_AlgPolicy>(__first, __last); 150fe6060f1SDimitry Andric } 151fcaf7f86SDimitry Andric return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last); 152fe6060f1SDimitry Andric } 153fe6060f1SDimitry Andric 154fcaf7f86SDimitry Andric template <class _AlgPolicy, class _RandomAccessIterator> 155cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __rotate_impl( 156cb14a3feSDimitry Andric _RandomAccessIterator __first, 157cb14a3feSDimitry Andric _RandomAccessIterator __middle, 158cb14a3feSDimitry Andric _RandomAccessIterator __last, 159cb14a3feSDimitry Andric random_access_iterator_tag) { 160fe6060f1SDimitry Andric typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; 161cb14a3feSDimitry Andric if (is_trivially_move_assignable<value_type>::value) { 162fcaf7f86SDimitry Andric if (_IterOps<_AlgPolicy>::next(__first) == __middle) 163fcaf7f86SDimitry Andric return std::__rotate_left<_AlgPolicy>(__first, __last); 164fcaf7f86SDimitry Andric if (_IterOps<_AlgPolicy>::next(__middle) == __last) 165fcaf7f86SDimitry Andric return std::__rotate_right<_AlgPolicy>(__first, __last); 166fcaf7f86SDimitry Andric return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last); 167fe6060f1SDimitry Andric } 168fcaf7f86SDimitry Andric return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last); 169fcaf7f86SDimitry Andric } 170fcaf7f86SDimitry Andric 17161cfbce3SDimitry Andric template <class _AlgPolicy, class _Iterator, class _Sentinel> 172cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iterator, _Iterator> 17361cfbce3SDimitry Andric __rotate(_Iterator __first, _Iterator __middle, _Sentinel __last) { 17461cfbce3SDimitry Andric using _Ret = pair<_Iterator, _Iterator>; 17561cfbce3SDimitry Andric _Iterator __last_iter = _IterOps<_AlgPolicy>::next(__middle, __last); 176fcaf7f86SDimitry Andric 17761cfbce3SDimitry Andric if (__first == __middle) 17861cfbce3SDimitry Andric return _Ret(__last_iter, __last_iter); 17961cfbce3SDimitry Andric if (__middle == __last) 18061cfbce3SDimitry Andric return _Ret(std::move(__first), std::move(__last_iter)); 18161cfbce3SDimitry Andric 18261cfbce3SDimitry Andric using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iterator>; 183cb14a3feSDimitry Andric auto __result = std::__rotate_impl<_AlgPolicy>(std::move(__first), std::move(__middle), __last_iter, _IterCategory()); 18461cfbce3SDimitry Andric 18561cfbce3SDimitry Andric return _Ret(std::move(__result), std::move(__last_iter)); 186fe6060f1SDimitry Andric } 187fe6060f1SDimitry Andric 188fe6060f1SDimitry Andric template <class _ForwardIterator> 189cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator 190cb14a3feSDimitry Andric rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { 191cb14a3feSDimitry Andric return std::__rotate<_ClassicAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last)).first; 192fe6060f1SDimitry Andric } 193fe6060f1SDimitry Andric 194fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 195fe6060f1SDimitry Andric 196b3edf446SDimitry Andric _LIBCPP_POP_MACROS 197b3edf446SDimitry Andric 198fe6060f1SDimitry Andric #endif // _LIBCPP___ALGORITHM_ROTATE_H 199