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