rotate.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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_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_PUSH_MACROS
  23. #include <__undef_macros>
  24. _LIBCPP_BEGIN_NAMESPACE_STD
  25. template <class _AlgPolicy, class _ForwardIterator>
  26. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
  27. __rotate_left(_ForwardIterator __first, _ForwardIterator __last) {
  28. typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
  29. using _Ops = _IterOps<_AlgPolicy>;
  30. value_type __tmp = _Ops::__iter_move(__first);
  31. _ForwardIterator __lm1 = std::__move<_AlgPolicy>(_Ops::next(__first), __last, __first).second;
  32. *__lm1 = std::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. typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
  39. using _Ops = _IterOps<_AlgPolicy>;
  40. _BidirectionalIterator __lm1 = _Ops::prev(__last);
  41. value_type __tmp = _Ops::__iter_move(__lm1);
  42. _BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last)).second;
  43. *__first = std::move(__tmp);
  44. return __fp1;
  45. }
  46. template <class _AlgPolicy, class _ForwardIterator>
  47. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _ForwardIterator
  48. __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) {
  49. _ForwardIterator __i = __middle;
  50. while (true) {
  51. _IterOps<_AlgPolicy>::iter_swap(__first, __i);
  52. ++__first;
  53. if (++__i == __last)
  54. break;
  55. if (__first == __middle)
  56. __middle = __i;
  57. }
  58. _ForwardIterator __r = __first;
  59. if (__first != __middle) {
  60. __i = __middle;
  61. while (true) {
  62. _IterOps<_AlgPolicy>::iter_swap(__first, __i);
  63. ++__first;
  64. if (++__i == __last) {
  65. if (__first == __middle)
  66. break;
  67. __i = __middle;
  68. } else if (__first == __middle)
  69. __middle = __i;
  70. }
  71. }
  72. return __r;
  73. }
  74. template <typename _Integral>
  75. inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Integral __algo_gcd(_Integral __x, _Integral __y) {
  76. do {
  77. _Integral __t = __x % __y;
  78. __x = __y;
  79. __y = __t;
  80. } while (__y);
  81. return __x;
  82. }
  83. template <class _AlgPolicy, typename _RandomAccessIterator>
  84. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _RandomAccessIterator
  85. __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) {
  86. typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
  87. typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
  88. using _Ops = _IterOps<_AlgPolicy>;
  89. const difference_type __m1 = __middle - __first;
  90. const difference_type __m2 = _Ops::distance(__middle, __last);
  91. if (__m1 == __m2) {
  92. std::__swap_ranges<_AlgPolicy>(__first, __middle, __middle, __last);
  93. return __middle;
  94. }
  95. const difference_type __g = std::__algo_gcd(__m1, __m2);
  96. for (_RandomAccessIterator __p = __first + __g; __p != __first;) {
  97. value_type __t(_Ops::__iter_move(--__p));
  98. _RandomAccessIterator __p1 = __p;
  99. _RandomAccessIterator __p2 = __p1 + __m1;
  100. do {
  101. *__p1 = _Ops::__iter_move(__p2);
  102. __p1 = __p2;
  103. const difference_type __d = _Ops::distance(__p2, __last);
  104. if (__m1 < __d)
  105. __p2 += __m1;
  106. else
  107. __p2 = __first + (__m1 - __d);
  108. } while (__p2 != __p);
  109. *__p1 = std::move(__t);
  110. }
  111. return __first + __m2;
  112. }
  113. template <class _AlgPolicy, class _ForwardIterator>
  114. inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
  115. __rotate_impl(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, std::forward_iterator_tag) {
  116. typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
  117. if (is_trivially_move_assignable<value_type>::value) {
  118. if (_IterOps<_AlgPolicy>::next(__first) == __middle)
  119. return std::__rotate_left<_AlgPolicy>(__first, __last);
  120. }
  121. return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
  122. }
  123. template <class _AlgPolicy, class _BidirectionalIterator>
  124. inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator __rotate_impl(
  125. _BidirectionalIterator __first,
  126. _BidirectionalIterator __middle,
  127. _BidirectionalIterator __last,
  128. bidirectional_iterator_tag) {
  129. typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
  130. if (is_trivially_move_assignable<value_type>::value) {
  131. if (_IterOps<_AlgPolicy>::next(__first) == __middle)
  132. return std::__rotate_left<_AlgPolicy>(__first, __last);
  133. if (_IterOps<_AlgPolicy>::next(__middle) == __last)
  134. return std::__rotate_right<_AlgPolicy>(__first, __last);
  135. }
  136. return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
  137. }
  138. template <class _AlgPolicy, class _RandomAccessIterator>
  139. inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __rotate_impl(
  140. _RandomAccessIterator __first,
  141. _RandomAccessIterator __middle,
  142. _RandomAccessIterator __last,
  143. random_access_iterator_tag) {
  144. typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
  145. if (is_trivially_move_assignable<value_type>::value) {
  146. if (_IterOps<_AlgPolicy>::next(__first) == __middle)
  147. return std::__rotate_left<_AlgPolicy>(__first, __last);
  148. if (_IterOps<_AlgPolicy>::next(__middle) == __last)
  149. return std::__rotate_right<_AlgPolicy>(__first, __last);
  150. return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last);
  151. }
  152. return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
  153. }
  154. template <class _AlgPolicy, class _Iterator, class _Sentinel>
  155. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iterator, _Iterator>
  156. __rotate(_Iterator __first, _Iterator __middle, _Sentinel __last) {
  157. using _Ret = pair<_Iterator, _Iterator>;
  158. _Iterator __last_iter = _IterOps<_AlgPolicy>::next(__middle, __last);
  159. if (__first == __middle)
  160. return _Ret(__last_iter, __last_iter);
  161. if (__middle == __last)
  162. return _Ret(std::move(__first), std::move(__last_iter));
  163. using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iterator>;
  164. auto __result = std::__rotate_impl<_AlgPolicy>(std::move(__first), std::move(__middle), __last_iter, _IterCategory());
  165. return _Ret(std::move(__result), std::move(__last_iter));
  166. }
  167. template <class _ForwardIterator>
  168. inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
  169. rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) {
  170. return std::__rotate<_ClassicAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last)).first;
  171. }
  172. _LIBCPP_END_NAMESPACE_STD
  173. _LIBCPP_POP_MACROS
  174. #endif // _LIBCPP___ALGORITHM_ROTATE_H