rotate.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. //===----------------------------------------------------------------------===//
  2. //
  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
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef _LIBCPP___ALGORITHM_ROTATE_H
  9. #define _LIBCPP___ALGORITHM_ROTATE_H
  10. #include <__algorithm/iterator_operations.h>
  11. #include <__algorithm/move.h>
  12. #include <__algorithm/move_backward.h>
  13. #include <__algorithm/swap_ranges.h>
  14. #include <__config>
  15. #include <__iterator/iterator_traits.h>
  16. #include <__type_traits/is_trivially_move_assignable.h>
  17. #include <__utility/move.h>
  18. #include <__utility/pair.h>
  19. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  20. # pragma GCC system_header
  21. #endif
  22. _LIBCPP_BEGIN_NAMESPACE_STD
  23. template <class _AlgPolicy, class _ForwardIterator>
  24. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
  25. __rotate_left(_ForwardIterator __first, _ForwardIterator __last)
  26. {
  27. typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
  28. using _Ops = _IterOps<_AlgPolicy>;
  29. value_type __tmp = _Ops::__iter_move(__first);
  30. _ForwardIterator __lm1 = std::__move<_AlgPolicy>(
  31. _Ops::next(__first), __last, __first).second;
  32. *__lm1 = _VSTD::move(__tmp);
  33. return __lm1;
  34. }
  35. template <class _AlgPolicy, class _BidirectionalIterator>
  36. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator
  37. __rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last)
  38. {
  39. typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
  40. using _Ops = _IterOps<_AlgPolicy>;
  41. _BidirectionalIterator __lm1 = _Ops::prev(__last);
  42. value_type __tmp = _Ops::__iter_move(__lm1);
  43. _BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last)).second;
  44. *__first = _VSTD::move(__tmp);
  45. return __fp1;
  46. }
  47. template <class _AlgPolicy, class _ForwardIterator>
  48. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _ForwardIterator
  49. __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
  50. {
  51. _ForwardIterator __i = __middle;
  52. while (true)
  53. {
  54. _IterOps<_AlgPolicy>::iter_swap(__first, __i);
  55. ++__first;
  56. if (++__i == __last)
  57. break;
  58. if (__first == __middle)
  59. __middle = __i;
  60. }
  61. _ForwardIterator __r = __first;
  62. if (__first != __middle)
  63. {
  64. __i = __middle;
  65. while (true)
  66. {
  67. _IterOps<_AlgPolicy>::iter_swap(__first, __i);
  68. ++__first;
  69. if (++__i == __last)
  70. {
  71. if (__first == __middle)
  72. break;
  73. __i = __middle;
  74. }
  75. else if (__first == __middle)
  76. __middle = __i;
  77. }
  78. }
  79. return __r;
  80. }
  81. template<typename _Integral>
  82. inline _LIBCPP_INLINE_VISIBILITY
  83. _LIBCPP_CONSTEXPR_SINCE_CXX17 _Integral
  84. __algo_gcd(_Integral __x, _Integral __y)
  85. {
  86. do
  87. {
  88. _Integral __t = __x % __y;
  89. __x = __y;
  90. __y = __t;
  91. } while (__y);
  92. return __x;
  93. }
  94. template <class _AlgPolicy, typename _RandomAccessIterator>
  95. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _RandomAccessIterator
  96. __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last)
  97. {
  98. typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
  99. typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
  100. using _Ops = _IterOps<_AlgPolicy>;
  101. const difference_type __m1 = __middle - __first;
  102. const difference_type __m2 = _Ops::distance(__middle, __last);
  103. if (__m1 == __m2)
  104. {
  105. std::__swap_ranges<_AlgPolicy>(__first, __middle, __middle, __last);
  106. return __middle;
  107. }
  108. const difference_type __g = _VSTD::__algo_gcd(__m1, __m2);
  109. for (_RandomAccessIterator __p = __first + __g; __p != __first;)
  110. {
  111. value_type __t(_Ops::__iter_move(--__p));
  112. _RandomAccessIterator __p1 = __p;
  113. _RandomAccessIterator __p2 = __p1 + __m1;
  114. do
  115. {
  116. *__p1 = _Ops::__iter_move(__p2);
  117. __p1 = __p2;
  118. const difference_type __d = _Ops::distance(__p2, __last);
  119. if (__m1 < __d)
  120. __p2 += __m1;
  121. else
  122. __p2 = __first + (__m1 - __d);
  123. } while (__p2 != __p);
  124. *__p1 = _VSTD::move(__t);
  125. }
  126. return __first + __m2;
  127. }
  128. template <class _AlgPolicy, class _ForwardIterator>
  129. inline _LIBCPP_INLINE_VISIBILITY
  130. _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
  131. __rotate_impl(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
  132. _VSTD::forward_iterator_tag)
  133. {
  134. typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
  135. if (is_trivially_move_assignable<value_type>::value)
  136. {
  137. if (_IterOps<_AlgPolicy>::next(__first) == __middle)
  138. return std::__rotate_left<_AlgPolicy>(__first, __last);
  139. }
  140. return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
  141. }
  142. template <class _AlgPolicy, class _BidirectionalIterator>
  143. inline _LIBCPP_INLINE_VISIBILITY
  144. _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator
  145. __rotate_impl(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
  146. bidirectional_iterator_tag)
  147. {
  148. typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
  149. if (is_trivially_move_assignable<value_type>::value)
  150. {
  151. if (_IterOps<_AlgPolicy>::next(__first) == __middle)
  152. return std::__rotate_left<_AlgPolicy>(__first, __last);
  153. if (_IterOps<_AlgPolicy>::next(__middle) == __last)
  154. return std::__rotate_right<_AlgPolicy>(__first, __last);
  155. }
  156. return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
  157. }
  158. template <class _AlgPolicy, class _RandomAccessIterator>
  159. inline _LIBCPP_INLINE_VISIBILITY
  160. _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator
  161. __rotate_impl(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
  162. random_access_iterator_tag)
  163. {
  164. typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
  165. if (is_trivially_move_assignable<value_type>::value)
  166. {
  167. if (_IterOps<_AlgPolicy>::next(__first) == __middle)
  168. return std::__rotate_left<_AlgPolicy>(__first, __last);
  169. if (_IterOps<_AlgPolicy>::next(__middle) == __last)
  170. return std::__rotate_right<_AlgPolicy>(__first, __last);
  171. return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last);
  172. }
  173. return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
  174. }
  175. template <class _AlgPolicy, class _Iterator, class _Sentinel>
  176. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
  177. pair<_Iterator, _Iterator>
  178. __rotate(_Iterator __first, _Iterator __middle, _Sentinel __last) {
  179. using _Ret = pair<_Iterator, _Iterator>;
  180. _Iterator __last_iter = _IterOps<_AlgPolicy>::next(__middle, __last);
  181. if (__first == __middle)
  182. return _Ret(__last_iter, __last_iter);
  183. if (__middle == __last)
  184. return _Ret(std::move(__first), std::move(__last_iter));
  185. using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iterator>;
  186. auto __result = std::__rotate_impl<_AlgPolicy>(
  187. std::move(__first), std::move(__middle), __last_iter, _IterCategory());
  188. return _Ret(std::move(__result), std::move(__last_iter));
  189. }
  190. template <class _ForwardIterator>
  191. inline _LIBCPP_INLINE_VISIBILITY
  192. _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
  193. rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
  194. {
  195. return std::__rotate<_ClassicAlgPolicy>(
  196. std::move(__first), std::move(__middle), std::move(__last)).first;
  197. }
  198. _LIBCPP_END_NAMESPACE_STD
  199. #endif // _LIBCPP___ALGORITHM_ROTATE_H