aboutsummaryrefslogtreecommitdiff
path: root/libcxx/include/__algorithm/shift.h
blob: fa96566b47d555e6eb9f9ab11cf3ecce32289ea3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___ALGORITHM_SHIFT_H
#define _LIBCPP___ALGORITHM_SHIFT_H

#include <__config>
#include <__algorithm/move.h>
#include <__iterator/iterator_traits.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

// shift_left, shift_right

#if _LIBCPP_STD_VER > 17

template <class _ForwardIterator>
inline _LIBCPP_INLINE_VISIBILITY constexpr
_ForwardIterator
shift_left(_ForwardIterator __first, _ForwardIterator __last,
           typename iterator_traits<_ForwardIterator>::difference_type __n)
{
    if (__n == 0) {
        return __last;
    }

    _ForwardIterator __m = __first;
    if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) {
        if (__n >= __last - __first) {
            return __first;
        }
        __m += __n;
    } else {
        for (; __n > 0; --__n) {
            if (__m == __last) {
                return __first;
            }
            ++__m;
        }
    }
    return _VSTD::move(__m, __last, __first);
}

template <class _ForwardIterator>
inline _LIBCPP_INLINE_VISIBILITY constexpr
_ForwardIterator
shift_right(_ForwardIterator __first, _ForwardIterator __last,
            typename iterator_traits<_ForwardIterator>::difference_type __n)
{
    if (__n == 0) {
        return __first;
    }

    if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) {
        decltype(__n) __d = __last - __first;
        if (__n >= __d) {
            return __last;
        }
        _ForwardIterator __m = __first + (__d - __n);
        return _VSTD::move_backward(__first, __m, __last);
    } else if constexpr (__is_cpp17_bidirectional_iterator<_ForwardIterator>::value) {
        _ForwardIterator __m = __last;
        for (; __n > 0; --__n) {
            if (__m == __first) {
                return __last;
            }
            --__m;
        }
        return _VSTD::move_backward(__first, __m, __last);
    } else {
        _ForwardIterator __ret = __first;
        for (; __n > 0; --__n) {
            if (__ret == __last) {
                return __last;
            }
            ++__ret;
        }

        // We have an __n-element scratch space from __first to __ret.
        // Slide an __n-element window [__trail, __lead) from left to right.
        // We're essentially doing swap_ranges(__first, __ret, __trail, __lead)
        // over and over; but once __lead reaches __last we needn't bother
        // to save the values of elements [__trail, __last).

        auto __trail = __first;
        auto __lead = __ret;
        while (__trail != __ret) {
            if (__lead == __last) {
                _VSTD::move(__first, __trail, __ret);
                return __ret;
            }
            ++__trail;
            ++__lead;
        }

        _ForwardIterator __mid = __first;
        while (true) {
            if (__lead == __last) {
                __trail = _VSTD::move(__mid, __ret, __trail);
                _VSTD::move(__first, __mid, __trail);
                return __ret;
            }
            swap(*__mid, *__trail);
            ++__mid;
            ++__trail;
            ++__lead;
            if (__mid == __ret) {
                __mid = __first;
            }
        }
    }
}

#endif // _LIBCPP_STD_VER > 17

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___ALGORITHM_SHIFT_H