File indexing completed on 2025-12-16 10:27:55
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef RANGES_V3_ALGORITHM_ROTATE_HPP
0022 #define RANGES_V3_ALGORITHM_ROTATE_HPP
0023
0024 #include <type_traits>
0025 #include <utility>
0026
0027 #include <range/v3/range_fwd.hpp>
0028
0029 #include <range/v3/algorithm/move.hpp>
0030 #include <range/v3/algorithm/move_backward.hpp>
0031 #include <range/v3/algorithm/swap_ranges.hpp>
0032 #include <range/v3/iterator/operations.hpp>
0033 #include <range/v3/iterator/traits.hpp>
0034 #include <range/v3/range/access.hpp>
0035 #include <range/v3/range/concepts.hpp>
0036 #include <range/v3/range/traits.hpp>
0037 #include <range/v3/utility/move.hpp>
0038 #include <range/v3/utility/static_const.hpp>
0039 #include <range/v3/utility/swap.hpp>
0040 #include <range/v3/view/subrange.hpp>
0041
0042 #include <range/v3/detail/prologue.hpp>
0043
0044 namespace ranges
0045 {
0046
0047
0048
0049 namespace detail
0050 {
0051 template<typename I>
0052 constexpr subrange<I> rotate_left(I first, I last)
0053 {
0054 iter_value_t<I> tmp = iter_move(first);
0055 I lm1 = ranges::move(next(first), last, first).out;
0056 *lm1 = std::move(tmp);
0057 return {lm1, last};
0058 }
0059
0060 template<typename I>
0061 constexpr subrange<I> rotate_right(I first, I last)
0062 {
0063 I lm1 = prev(last);
0064 iter_value_t<I> tmp = iter_move(lm1);
0065 I fp1 = move_backward(first, lm1, last).out;
0066 *first = std::move(tmp);
0067 return {fp1, last};
0068 }
0069
0070 template<typename I, typename S>
0071 constexpr subrange<I> rotate_forward(I first, I middle, S last)
0072 {
0073 I i = middle;
0074 while(true)
0075 {
0076 ranges::iter_swap(first, i);
0077 ++first;
0078 if(++i == last)
0079 break;
0080 if(first == middle)
0081 middle = i;
0082 }
0083 I r = first;
0084 if(first != middle)
0085 {
0086 I j = middle;
0087 while(true)
0088 {
0089 ranges::iter_swap(first, j);
0090 ++first;
0091 if(++j == last)
0092 {
0093 if(first == middle)
0094 break;
0095 j = middle;
0096 }
0097 else if(first == middle)
0098 middle = j;
0099 }
0100 }
0101 return {r, i};
0102 }
0103
0104 template<typename D>
0105 constexpr D gcd(D x, D y)
0106 {
0107 do
0108 {
0109 D t = x % y;
0110 x = y;
0111 y = t;
0112 } while(y);
0113 return x;
0114 }
0115
0116 template<typename I>
0117 constexpr subrange<I> rotate_gcd(I first, I middle, I last)
0118 {
0119 auto const m1 = middle - first;
0120 auto const m2 = last - middle;
0121 if(m1 == m2)
0122 {
0123 swap_ranges(first, middle, middle);
0124 return {middle, last};
0125 }
0126 auto const g = detail::gcd(m1, m2);
0127 for(I p = first + g; p != first;)
0128 {
0129 iter_value_t<I> t = iter_move(--p);
0130 I p1 = p;
0131 I p2 = p1 + m1;
0132 do
0133 {
0134 *p1 = iter_move(p2);
0135 p1 = p2;
0136 auto const d = last - p2;
0137 if(m1 < d)
0138 p2 += m1;
0139 else
0140 p2 = first + (m1 - d);
0141 } while(p2 != p);
0142 *p1 = std::move(t);
0143 }
0144 return {first + m2, last};
0145 }
0146
0147 template<typename I, typename S>
0148 constexpr subrange<I> rotate_(I first, I middle, S last, std::forward_iterator_tag)
0149 {
0150 return detail::rotate_forward(first, middle, last);
0151 }
0152
0153 template<typename I>
0154 constexpr subrange<I> rotate_(I first, I middle, I last, std::forward_iterator_tag)
0155 {
0156 using value_type = iter_value_t<I>;
0157 if(detail::is_trivially_move_assignable_v<value_type>)
0158 {
0159 if(next(first) == middle)
0160 return detail::rotate_left(first, last);
0161 }
0162 return detail::rotate_forward(first, middle, last);
0163 }
0164
0165 template<typename I>
0166 constexpr subrange<I> rotate_(I first, I middle, I last, std::bidirectional_iterator_tag)
0167 {
0168 using value_type = iter_value_t<I>;
0169 if(detail::is_trivially_move_assignable_v<value_type>)
0170 {
0171 if(next(first) == middle)
0172 return detail::rotate_left(first, last);
0173 if(next(middle) == last)
0174 return detail::rotate_right(first, last);
0175 }
0176 return detail::rotate_forward(first, middle, last);
0177 }
0178
0179 template<typename I>
0180 constexpr subrange<I> rotate_(I first, I middle, I last, std::random_access_iterator_tag)
0181 {
0182 using value_type = iter_value_t<I>;
0183 if(detail::is_trivially_move_assignable_v<value_type>)
0184 {
0185 if(next(first) == middle)
0186 return detail::rotate_left(first, last);
0187 if(next(middle) == last)
0188 return detail::rotate_right(first, last);
0189 return detail::rotate_gcd(first, middle, last);
0190 }
0191 return detail::rotate_forward(first, middle, last);
0192 }
0193 }
0194
0195
0196 RANGES_FUNC_BEGIN(rotate)
0197
0198
0199 template(typename I, typename S)(
0200 requires permutable<I> AND sentinel_for<S, I>)
0201 constexpr subrange<I> RANGES_FUNC(rotate)(I first, I middle, S last)
0202 {
0203 if(first == middle)
0204 {
0205 first = ranges::next(std::move(first), last);
0206 return {first, first};
0207 }
0208 if(middle == last)
0209 {
0210 return {first, middle};
0211 }
0212 return detail::rotate_(first, middle, last, iterator_tag_of<I>{});
0213 }
0214
0215
0216 template(typename Rng, typename I = iterator_t<Rng>)(
0217 requires range<Rng> AND permutable<I>)
0218 constexpr borrowed_subrange_t<Rng> RANGES_FUNC(rotate)(Rng && rng, I middle)
0219 {
0220 return (*this)(begin(rng), std::move(middle), end(rng));
0221 }
0222
0223 RANGES_FUNC_END(rotate)
0224
0225 namespace cpp20
0226 {
0227 using ranges::rotate;
0228 }
0229
0230 }
0231
0232 #include <range/v3/detail/epilogue.hpp>
0233
0234 #endif