You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rotate.hpp 7.2KB

5 vuotta sitten
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. namespace ranges
  39. {
  40. /// \addtogroup group-algorithms
  41. /// @{
  42. /// \cond
  43. namespace detail
  44. {
  45. template<typename I> // Forward
  46. subrange<I> rotate_left(I first, I last)
  47. {
  48. iter_value_t<I> tmp = iter_move(first);
  49. I lm1 = ranges::move(next(first), last, first).out;
  50. *lm1 = std::move(tmp);
  51. return {lm1, last};
  52. }
  53. template<typename I> // Bidirectional
  54. subrange<I> rotate_right(I first, I last)
  55. {
  56. I lm1 = prev(last);
  57. iter_value_t<I> tmp = iter_move(lm1);
  58. I fp1 = move_backward(first, lm1, last).out;
  59. *first = std::move(tmp);
  60. return {fp1, last};
  61. }
  62. template<typename I, typename S> // Forward
  63. subrange<I> rotate_forward(I first, I middle, S last)
  64. {
  65. I i = middle;
  66. while(true)
  67. {
  68. ranges::iter_swap(first, i);
  69. ++first;
  70. if(++i == last)
  71. break;
  72. if(first == middle)
  73. middle = i;
  74. }
  75. I r = first;
  76. if(first != middle)
  77. {
  78. I j = middle;
  79. while(true)
  80. {
  81. ranges::iter_swap(first, j);
  82. ++first;
  83. if(++j == last)
  84. {
  85. if(first == middle)
  86. break;
  87. j = middle;
  88. }
  89. else if(first == middle)
  90. middle = j;
  91. }
  92. }
  93. return {r, i};
  94. }
  95. template<typename D>
  96. D gcd(D x, D y)
  97. {
  98. do
  99. {
  100. D t = x % y;
  101. x = y;
  102. y = t;
  103. } while(y);
  104. return x;
  105. }
  106. template<typename I> // Random
  107. subrange<I> rotate_gcd(I first, I middle, I last)
  108. {
  109. auto const m1 = middle - first;
  110. auto const m2 = last - middle;
  111. if(m1 == m2)
  112. {
  113. swap_ranges(first, middle, middle);
  114. return {middle, last};
  115. }
  116. auto const g = detail::gcd(m1, m2);
  117. for(I p = first + g; p != first;)
  118. {
  119. iter_value_t<I> t = iter_move(--p);
  120. I p1 = p;
  121. I p2 = p1 + m1;
  122. do
  123. {
  124. *p1 = iter_move(p2);
  125. p1 = p2;
  126. auto const d = last - p2;
  127. if(m1 < d)
  128. p2 += m1;
  129. else
  130. p2 = first + (m1 - d);
  131. } while(p2 != p);
  132. *p1 = std::move(t);
  133. }
  134. return {first + m2, last};
  135. }
  136. template<typename I, typename S>
  137. subrange<I> rotate_(I first, I middle, S last, detail::forward_iterator_tag_)
  138. {
  139. return detail::rotate_forward(first, middle, last);
  140. }
  141. template<typename I>
  142. subrange<I> rotate_(I first, I middle, I last, detail::forward_iterator_tag_)
  143. {
  144. using value_type = iter_value_t<I>;
  145. if(detail::is_trivially_move_assignable<value_type>::value)
  146. {
  147. if(next(first) == middle)
  148. return detail::rotate_left(first, last);
  149. }
  150. return detail::rotate_forward(first, middle, last);
  151. }
  152. template<typename I>
  153. subrange<I> rotate_(I first, I middle, I last,
  154. detail::bidirectional_iterator_tag_)
  155. {
  156. using value_type = iter_value_t<I>;
  157. if(detail::is_trivially_move_assignable<value_type>::value)
  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. subrange<I> rotate_(I first, I middle, I last,
  168. detail::random_access_iterator_tag_)
  169. {
  170. using value_type = iter_value_t<I>;
  171. if(detail::is_trivially_move_assignable<value_type>::value)
  172. {
  173. if(next(first) == middle)
  174. return detail::rotate_left(first, last);
  175. if(next(middle) == last)
  176. return detail::rotate_right(first, last);
  177. return detail::rotate_gcd(first, middle, last);
  178. }
  179. return detail::rotate_forward(first, middle, last);
  180. }
  181. } // namespace detail
  182. /// \endcond
  183. RANGES_BEGIN_NIEBLOID(rotate)
  184. /// \brief function template \c rotate
  185. template<typename I, typename S>
  186. auto RANGES_FUN_NIEBLOID(rotate)(I first, I middle, S last) //
  187. ->CPP_ret(subrange<I>)( //
  188. requires permutable<I> && sentinel_for<S, I>)
  189. {
  190. if(first == middle)
  191. {
  192. first = ranges::next(std::move(first), last);
  193. return {first, first};
  194. }
  195. if(middle == last)
  196. {
  197. return {first, middle};
  198. }
  199. return detail::rotate_(first, middle, last, iterator_tag_of<I>{});
  200. }
  201. /// \overload
  202. template<typename Rng, typename I = iterator_t<Rng>>
  203. auto RANGES_FUN_NIEBLOID(rotate)(Rng && rng, I middle) //
  204. ->CPP_ret(safe_subrange_t<Rng>)( //
  205. requires range<Rng> && permutable<I>)
  206. {
  207. return (*this)(begin(rng), std::move(middle), end(rng));
  208. }
  209. RANGES_END_NIEBLOID(rotate)
  210. namespace cpp20
  211. {
  212. using ranges::rotate;
  213. }
  214. /// @}
  215. } // namespace ranges
  216. #endif // include guard