rotate.h 6.5 KB

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