1*134723edSLouis Dionne //===----------------------------------------------------------------------===//
2*134723edSLouis Dionne //
3*134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5*134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*134723edSLouis Dionne //
7*134723edSLouis Dionne //===----------------------------------------------------------------------===//
8*134723edSLouis Dionne 
9*134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_SHIFT_RIGHT_H
10*134723edSLouis Dionne #define _LIBCPP___ALGORITHM_SHIFT_RIGHT_H
11*134723edSLouis Dionne 
12*134723edSLouis Dionne #include <__config>
13*134723edSLouis Dionne #include <__algorithm/move.h>
14*134723edSLouis Dionne #include <__algorithm/move_backward.h>
15*134723edSLouis Dionne #include <__iterator/iterator_traits.h>
16*134723edSLouis Dionne #include <type_traits> // swap
17*134723edSLouis Dionne 
18*134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19*134723edSLouis Dionne #pragma GCC system_header
20*134723edSLouis Dionne #endif
21*134723edSLouis Dionne 
22*134723edSLouis Dionne _LIBCPP_PUSH_MACROS
23*134723edSLouis Dionne #include <__undef_macros>
24*134723edSLouis Dionne 
25*134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
26*134723edSLouis Dionne 
27*134723edSLouis Dionne #if _LIBCPP_STD_VER > 17
28*134723edSLouis Dionne 
29*134723edSLouis Dionne template <class _ForwardIterator>
30*134723edSLouis Dionne inline _LIBCPP_INLINE_VISIBILITY constexpr
31*134723edSLouis Dionne _ForwardIterator
32*134723edSLouis Dionne shift_right(_ForwardIterator __first, _ForwardIterator __last,
33*134723edSLouis Dionne             typename iterator_traits<_ForwardIterator>::difference_type __n)
34*134723edSLouis Dionne {
35*134723edSLouis Dionne     if (__n == 0) {
36*134723edSLouis Dionne         return __first;
37*134723edSLouis Dionne     }
38*134723edSLouis Dionne 
39*134723edSLouis Dionne     if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) {
40*134723edSLouis Dionne         decltype(__n) __d = __last - __first;
41*134723edSLouis Dionne         if (__n >= __d) {
42*134723edSLouis Dionne             return __last;
43*134723edSLouis Dionne         }
44*134723edSLouis Dionne         _ForwardIterator __m = __first + (__d - __n);
45*134723edSLouis Dionne         return _VSTD::move_backward(__first, __m, __last);
46*134723edSLouis Dionne     } else if constexpr (__is_cpp17_bidirectional_iterator<_ForwardIterator>::value) {
47*134723edSLouis Dionne         _ForwardIterator __m = __last;
48*134723edSLouis Dionne         for (; __n > 0; --__n) {
49*134723edSLouis Dionne             if (__m == __first) {
50*134723edSLouis Dionne                 return __last;
51*134723edSLouis Dionne             }
52*134723edSLouis Dionne             --__m;
53*134723edSLouis Dionne         }
54*134723edSLouis Dionne         return _VSTD::move_backward(__first, __m, __last);
55*134723edSLouis Dionne     } else {
56*134723edSLouis Dionne         _ForwardIterator __ret = __first;
57*134723edSLouis Dionne         for (; __n > 0; --__n) {
58*134723edSLouis Dionne             if (__ret == __last) {
59*134723edSLouis Dionne                 return __last;
60*134723edSLouis Dionne             }
61*134723edSLouis Dionne             ++__ret;
62*134723edSLouis Dionne         }
63*134723edSLouis Dionne 
64*134723edSLouis Dionne         // We have an __n-element scratch space from __first to __ret.
65*134723edSLouis Dionne         // Slide an __n-element window [__trail, __lead) from left to right.
66*134723edSLouis Dionne         // We're essentially doing swap_ranges(__first, __ret, __trail, __lead)
67*134723edSLouis Dionne         // over and over; but once __lead reaches __last we needn't bother
68*134723edSLouis Dionne         // to save the values of elements [__trail, __last).
69*134723edSLouis Dionne 
70*134723edSLouis Dionne         auto __trail = __first;
71*134723edSLouis Dionne         auto __lead = __ret;
72*134723edSLouis Dionne         while (__trail != __ret) {
73*134723edSLouis Dionne             if (__lead == __last) {
74*134723edSLouis Dionne                 _VSTD::move(__first, __trail, __ret);
75*134723edSLouis Dionne                 return __ret;
76*134723edSLouis Dionne             }
77*134723edSLouis Dionne             ++__trail;
78*134723edSLouis Dionne             ++__lead;
79*134723edSLouis Dionne         }
80*134723edSLouis Dionne 
81*134723edSLouis Dionne         _ForwardIterator __mid = __first;
82*134723edSLouis Dionne         while (true) {
83*134723edSLouis Dionne             if (__lead == __last) {
84*134723edSLouis Dionne                 __trail = _VSTD::move(__mid, __ret, __trail);
85*134723edSLouis Dionne                 _VSTD::move(__first, __mid, __trail);
86*134723edSLouis Dionne                 return __ret;
87*134723edSLouis Dionne             }
88*134723edSLouis Dionne             swap(*__mid, *__trail);
89*134723edSLouis Dionne             ++__mid;
90*134723edSLouis Dionne             ++__trail;
91*134723edSLouis Dionne             ++__lead;
92*134723edSLouis Dionne             if (__mid == __ret) {
93*134723edSLouis Dionne                 __mid = __first;
94*134723edSLouis Dionne             }
95*134723edSLouis Dionne         }
96*134723edSLouis Dionne     }
97*134723edSLouis Dionne }
98*134723edSLouis Dionne 
99*134723edSLouis Dionne #endif // _LIBCPP_STD_VER > 17
100*134723edSLouis Dionne 
101*134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
102*134723edSLouis Dionne 
103*134723edSLouis Dionne _LIBCPP_POP_MACROS
104*134723edSLouis Dionne 
105*134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_SHIFT_RIGHT_H
106