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