xref: /freebsd-src/contrib/llvm-project/libcxx/include/__algorithm/shift_right.h (revision b3edf4467982447620505a28fc82e38a414c07dc)
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