rotate.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. //===----------------------------------------------------------------------===//
  14. //
  15. // The LLVM Compiler Infrastructure
  16. //
  17. // This file is dual licensed under the MIT and the University of Illinois Open
  18. // Source Licenses. See LICENSE.TXT for details.
  19. //
  20. //===----------------------------------------------------------------------===//
  21. #ifndef RANGES_V3_ALGORITHM_ROTATE_HPP
  22. #define RANGES_V3_ALGORITHM_ROTATE_HPP
  23. #include <type_traits>
  24. #include <utility>
  25. #include <range/v3/range_fwd.hpp>
  26. #include <range/v3/algorithm/move.hpp>
  27. #include <range/v3/algorithm/move_backward.hpp>
  28. #include <range/v3/algorithm/swap_ranges.hpp>
  29. #include <range/v3/iterator/operations.hpp>
  30. #include <range/v3/iterator/traits.hpp>
  31. #include <range/v3/range/access.hpp>
  32. #include <range/v3/range/concepts.hpp>
  33. #include <range/v3/range/traits.hpp>
  34. #include <range/v3/utility/move.hpp>
  35. #include <range/v3/utility/static_const.hpp>
  36. #include <range/v3/utility/swap.hpp>
  37. #include <range/v3/view/subrange.hpp>
  38. #include <range/v3/detail/prologue.hpp>
  39. namespace ranges
  40. {
  41. /// \addtogroup group-algorithms
  42. /// @{
  43. /// \cond
  44. namespace detail
  45. {
  46. template<typename I> // Forward
  47. constexpr subrange<I> rotate_left(I first, I last)
  48. {
  49. iter_value_t<I> tmp = iter_move(first);
  50. I lm1 = ranges::move(next(first), last, first).out;
  51. *lm1 = std::move(tmp);
  52. return {lm1, last};
  53. }
  54. template<typename I> // Bidirectional
  55. constexpr subrange<I> rotate_right(I first, I last)
  56. {
  57. I lm1 = prev(last);
  58. iter_value_t<I> tmp = iter_move(lm1);
  59. I fp1 = move_backward(first, lm1, last).out;
  60. *first = std::move(tmp);
  61. return {fp1, last};
  62. }
  63. template<typename I, typename S> // Forward
  64. constexpr subrange<I> rotate_forward(I first, I middle, S last)
  65. {
  66. I i = middle;
  67. while(true)
  68. {
  69. ranges::iter_swap(first, i);
  70. ++first;
  71. if(++i == last)
  72. break;
  73. if(first == middle)
  74. middle = i;
  75. }
  76. I r = first;
  77. if(first != middle)
  78. {
  79. I j = middle;
  80. while(true)
  81. {
  82. ranges::iter_swap(first, j);
  83. ++first;
  84. if(++j == last)
  85. {
  86. if(first == middle)
  87. break;
  88. j = middle;
  89. }
  90. else if(first == middle)
  91. middle = j;
  92. }
  93. }
  94. return {r, i};
  95. }
  96. template<typename D>
  97. constexpr D gcd(D x, D y)
  98. {
  99. do
  100. {
  101. D t = x % y;
  102. x = y;
  103. y = t;
  104. } while(y);
  105. return x;
  106. }
  107. template<typename I> // Random
  108. constexpr subrange<I> rotate_gcd(I first, I middle, I last)
  109. {
  110. auto const m1 = middle - first;
  111. auto const m2 = last - middle;
  112. if(m1 == m2)
  113. {
  114. swap_ranges(first, middle, middle);
  115. return {middle, last};
  116. }
  117. auto const g = detail::gcd(m1, m2);
  118. for(I p = first + g; p != first;)
  119. {
  120. iter_value_t<I> t = iter_move(--p);
  121. I p1 = p;
  122. I p2 = p1 + m1;
  123. do
  124. {
  125. *p1 = iter_move(p2);
  126. p1 = p2;
  127. auto const d = last - p2;
  128. if(m1 < d)
  129. p2 += m1;
  130. else
  131. p2 = first + (m1 - d);
  132. } while(p2 != p);
  133. *p1 = std::move(t);
  134. }
  135. return {first + m2, last};
  136. }
  137. template<typename I, typename S>
  138. constexpr subrange<I> rotate_(I first, I middle, S last, std::forward_iterator_tag)
  139. {
  140. return detail::rotate_forward(first, middle, last);
  141. }
  142. template<typename I>
  143. constexpr subrange<I> rotate_(I first, I middle, I last, std::forward_iterator_tag)
  144. {
  145. using value_type = iter_value_t<I>;
  146. if(detail::is_trivially_move_assignable_v<value_type>)
  147. {
  148. if(next(first) == middle)
  149. return detail::rotate_left(first, last);
  150. }
  151. return detail::rotate_forward(first, middle, last);
  152. }
  153. template<typename I>
  154. constexpr subrange<I> rotate_(I first, I middle, I last, std::bidirectional_iterator_tag)
  155. {
  156. using value_type = iter_value_t<I>;
  157. if(detail::is_trivially_move_assignable_v<value_type>)
  158. {
  159. if(next(first) == middle)
  160. return detail::rotate_left(first, last);
  161. if(next(middle) == last)
  162. return detail::rotate_right(first, last);
  163. }
  164. return detail::rotate_forward(first, middle, last);
  165. }
  166. template<typename I>
  167. constexpr subrange<I> rotate_(I first, I middle, I last, std::random_access_iterator_tag)
  168. {
  169. using value_type = iter_value_t<I>;
  170. if(detail::is_trivially_move_assignable_v<value_type>)
  171. {
  172. if(next(first) == middle)
  173. return detail::rotate_left(first, last);
  174. if(next(middle) == last)
  175. return detail::rotate_right(first, last);
  176. return detail::rotate_gcd(first, middle, last);
  177. }
  178. return detail::rotate_forward(first, middle, last);
  179. }
  180. } // namespace detail
  181. /// \endcond
  182. RANGES_FUNC_BEGIN(rotate)
  183. /// \brief function template \c rotate
  184. template(typename I, typename S)(
  185. requires permutable<I> AND sentinel_for<S, I>)
  186. constexpr subrange<I> RANGES_FUNC(rotate)(I first, I middle, S last) //
  187. {
  188. if(first == middle)
  189. {
  190. first = ranges::next(std::move(first), last);
  191. return {first, first};
  192. }
  193. if(middle == last)
  194. {
  195. return {first, middle};
  196. }
  197. return detail::rotate_(first, middle, last, iterator_tag_of<I>{});
  198. }
  199. /// \overload
  200. template(typename Rng, typename I = iterator_t<Rng>)(
  201. requires range<Rng> AND permutable<I>)
  202. constexpr borrowed_subrange_t<Rng> RANGES_FUNC(rotate)(Rng && rng, I middle) //
  203. {
  204. return (*this)(begin(rng), std::move(middle), end(rng));
  205. }
  206. RANGES_FUNC_END(rotate)
  207. namespace cpp20
  208. {
  209. using ranges::rotate;
  210. }
  211. /// @}
  212. } // namespace ranges
  213. #include <range/v3/detail/epilogue.hpp>
  214. #endif