[libcxx-commits] [libcxx] [libc++] Implement `ranges::shift_right` (PR #177847)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Fri Feb 13 14:33:53 PST 2026


================
@@ -27,65 +33,77 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 20
 
-template <class _ForwardIterator>
-inline _LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator
-shift_right(_ForwardIterator __first,
-            _ForwardIterator __last,
-            typename iterator_traits<_ForwardIterator>::difference_type __n) {
+template <class _AlgPolicy, class _Iter, class _Sent>
+_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter>
+__shift_right(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) {
+  _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "Providing a negative shift amount to shift_right is UB");
   if (__n == 0) {
-    return __first;
+    _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
+    return pair<_Iter, _Iter>(std::move(__first), std::move(__end));
   }
 
-  if constexpr (__has_random_access_iterator_category<_ForwardIterator>::value) {
-    decltype(__n) __d = __last - __first;
-    if (__n >= __d) {
-      return __last;
+  using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iter>;
+
+  if constexpr (derived_from<_IterCategory, random_access_iterator_tag>) {
+    _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
+    auto __size = __end - __first;
+    if (__n >= __size) {
+      return pair<_Iter, _Iter>(__end, std::move(__end));
+    }
+    _Iter __m = __first;
+    _IterOps<_AlgPolicy>::advance(__m, (__size - __n));
+    auto __ret = std::__move_backward<_AlgPolicy>(std::move(__first), std::move(__m), __end);
+    return pair<_Iter, _Iter>(std::move(__ret.second), std::move(__end));
+  } else if constexpr (derived_from<_IterCategory, bidirectional_iterator_tag>) {
+    _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
----------------
ldionne wrote:

It's kinda sad that `next` doesn't return the number of positions it incremented by: otherwise we could skip the call to `distance` that follows, and we could do that check even for non-sized-sentinel.

https://github.com/llvm/llvm-project/pull/177847


More information about the libcxx-commits mailing list