Skip to content

[libc++] Implement ranges::shift_right#177847

Merged
huixie90 merged 6 commits intollvm:mainfrom
huixie90:hxie/ranges_shift_right
Feb 14, 2026
Merged

[libc++] Implement ranges::shift_right#177847
huixie90 merged 6 commits intollvm:mainfrom
huixie90:hxie/ranges_shift_right

Conversation

@huixie90
Copy link
Member

@huixie90 huixie90 commented Jan 25, 2026

Implement the ranges::shift_right algorithm from P2440R1.

Fixes #134062
Fixes #105184

@huixie90 huixie90 requested a review from a team as a code owner January 25, 2026 10:30
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jan 25, 2026
@huixie90 huixie90 self-assigned this Jan 25, 2026
@llvmbot
Copy link
Member

llvmbot commented Jan 25, 2026

@llvm/pr-subscribers-libcxx

Author: Hui (huixie90)

Changes

Patch is 33.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/177847.diff

18 Files Affected:

  • (modified) libcxx/docs/FeatureTestMacroTable.rst (+2)
  • (modified) libcxx/docs/ReleaseNotes/23.rst (+2)
  • (modified) libcxx/docs/Status/Cxx23Papers.csv (+1-1)
  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (added) libcxx/include/__algorithm/ranges_shift_right.h (+77)
  • (modified) libcxx/include/__algorithm/shift_right.h (+49-30)
  • (modified) libcxx/include/algorithm (+8)
  • (modified) libcxx/include/module.modulemap.in (+3)
  • (modified) libcxx/include/version (+4-1)
  • (modified) libcxx/modules/std/algorithm.inc (+3-1)
  • (added) libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp (+28)
  • (added) libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp (+307)
  • (modified) libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp (+1)
  • (modified) libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp (+4)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.compile.pass.cpp (+4-4)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+4-4)
  • (modified) libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp (+3)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+1-1)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index d2b76cb96e866..0f65770a4fa14 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -394,6 +394,8 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_reference_from_temporary``                     *unimplemented*
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_shift``                                        ``202202L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_spanstream``                                   *unimplemented*
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_stacktrace``                                   *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index 73f5984768592..ffc586d9630a3 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -38,6 +38,8 @@ What's New in Libc++ 23.0.0?
 Implemented Papers
 ------------------
 
+- P2440R1: ``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right`` (`Github <https://llvm.org/PR105184>`__)
+
 Improvements and New Features
 -----------------------------
 
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 2a5c64a53d79e..fd99ff635aa00 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -46,7 +46,7 @@
 "`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","`#105180 <https://github.com/llvm/llvm-project/issues/105180>`__","Implemented the type traits only."
 "`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","`#105182 <https://github.com/llvm/llvm-project/issues/105182>`__",""
 "`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","`#105183 <https://github.com/llvm/llvm-project/issues/105183>`__",""
-"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__","Only ``ranges::iota`` is implemented."
+"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Complete|","23","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__",""
 "`P2441R2 <https://wg21.link/P2441R2>`__","``views::join_with``","2022-02 (Virtual)","|Complete|","21","`#105185 <https://github.com/llvm/llvm-project/issues/105185>`__",""
 "`P2442R1 <https://wg21.link/P2442R1>`__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","`#105187 <https://github.com/llvm/llvm-project/issues/105187>`__",""
 "`P2443R1 <https://wg21.link/P2443R1>`__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","`#105188 <https://github.com/llvm/llvm-project/issues/105188>`__",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index a4ad3bedd2460..5be7474278c7f 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -157,6 +157,7 @@ set(files
   __algorithm/ranges_set_intersection.h
   __algorithm/ranges_set_symmetric_difference.h
   __algorithm/ranges_set_union.h
+  __algorithm/ranges_shift_right.h
   __algorithm/ranges_shuffle.h
   __algorithm/ranges_sort.h
   __algorithm/ranges_sort_heap.h
diff --git a/libcxx/include/__algorithm/ranges_shift_right.h b/libcxx/include/__algorithm/ranges_shift_right.h
new file mode 100644
index 0000000000000..9b3f27ea2bb0a
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_shift_right.h
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_RANGES_SHIFT_RIGHT_H
+#define _LIBCPP___ALGORITHM_RANGES_SHIFT_RIGHT_H
+
+#include <__algorithm/iterator_operations.h>
+#include <__algorithm/shift_right.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/permutable.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/subrange.h>
+#include <__utility/move.h>
+#include <iterator>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+namespace __shift_right {
+
+struct __fn {
+  template <permutable _Iter, sentinel_for<_Iter> _Sent>
+  _LIBCPP_HIDE_FROM_ABI static constexpr subrange<_Iter>
+  operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) {
+    auto __ret = std::__shift_right<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__n));
+    return {std::move(__ret.first), std::move(__ret.second)};
+  }
+
+  template <forward_range _Range>
+    requires permutable<iterator_t<_Range>>
+  _LIBCPP_HIDE_FROM_ABI static constexpr borrowed_subrange_t<_Range>
+  operator()(_Range&& __range, range_difference_t<_Range> __n) {
+    if constexpr (sized_range<_Range>) {
+      if (__n >= ranges::distance(__range)) {
+        auto __iter = ranges::begin(__range);
+        auto __end  = ranges::end(__range);
+        ranges::advance(__iter, __end);
+        return {__iter, std::move(__iter)};
+      }
+    }
+
+    auto __ret = std::__shift_right<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), std::move(__n));
+    return {std::move(__ret.first), std::move(__ret.second)};
+  }
+};
+} // namespace __shift_right
+
+inline namespace __cpo {
+inline constexpr auto shift_right = __shift_right::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ALGORITHM_RANGES_SHIFT_RIGHT_H
diff --git a/libcxx/include/__algorithm/shift_right.h b/libcxx/include/__algorithm/shift_right.h
index 01853057fc478..338a1401dad72 100644
--- a/libcxx/include/__algorithm/shift_right.h
+++ b/libcxx/include/__algorithm/shift_right.h
@@ -9,12 +9,18 @@
 #ifndef _LIBCPP___ALGORITHM_SHIFT_RIGHT_H
 #define _LIBCPP___ALGORITHM_SHIFT_RIGHT_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/move.h>
 #include <__algorithm/move_backward.h>
 #include <__algorithm/swap_ranges.h>
+#include <__assert>
 #include <__config>
+#include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
 #include <__utility/swap.h>
+#include <concepts>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -27,36 +33,41 @@ _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, "n must be greater than or equal to 0");
+  _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
   if (__n == 0) {
-    return __first;
+    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>) {
+    auto __size = __end - __first;
+    if (__n >= __size) {
+      return pair<_Iter, _Iter>(__end, std::move(__end));
     }
-    _ForwardIterator __m = __first + (__d - __n);
-    return std::move_backward(__first, __m, __last);
-  } else if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) {
-    _ForwardIterator __m = __last;
+    _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 __m = __end;
     for (; __n > 0; --__n) {
       if (__m == __first) {
-        return __last;
+        return pair<_Iter, _Iter>(__end, std::move(__end));
       }
       --__m;
     }
-    return std::move_backward(__first, __m, __last);
+    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 {
-    _ForwardIterator __ret = __first;
+    _Iter __ret = __first;
     for (; __n > 0; --__n) {
-      if (__ret == __last) {
-        return __last;
+      if (__ret == __end) {
+        return pair<_Iter, _Iter>(__end, std::move(__end));
       }
       ++__ret;
     }
@@ -64,28 +75,28 @@ shift_right(_ForwardIterator __first,
     // 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).
+    // over and over; but once __lead reaches __end we needn't bother
+    // to save the values of elements [__trail, __end).
 
     auto __trail = __first;
     auto __lead  = __ret;
     while (__trail != __ret) {
-      if (__lead == __last) {
-        std::move(__first, __trail, __ret);
-        return __ret;
+      if (__lead == __end) {
+        std::__move<_AlgPolicy>(std::move(__first), std::move(__trail), __ret);
+        return pair<_Iter, _Iter>(__ret, std::move(__end));
       }
       ++__trail;
       ++__lead;
     }
 
-    _ForwardIterator __mid = __first;
+    _Iter __mid = __first;
     while (true) {
-      if (__lead == __last) {
-        __trail = std::move(__mid, __ret, __trail);
-        std::move(__first, __mid, __trail);
-        return __ret;
+      if (__lead == __end) {
+        __trail = std::__move<_AlgPolicy>(__mid, __ret, __trail).second;
+        std::__move<_AlgPolicy>(std::move(__first), std::move(__mid), std::move(__trail));
+        return pair<_Iter, _Iter>(__ret, std::move(__end));
       }
-      swap(*__mid, *__trail);
+      _IterOps<_AlgPolicy>::iter_swap(__mid, __trail);
       ++__mid;
       ++__trail;
       ++__lead;
@@ -96,6 +107,14 @@ shift_right(_ForwardIterator __first,
   }
 }
 
+template <class _ForwardIterator>
+_LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator
+shift_right(_ForwardIterator __first,
+            _ForwardIterator __last,
+            typename iterator_traits<_ForwardIterator>::difference_type __n) {
+  return std::__shift_right<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __n).first;
+}
+
 #endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 64e9fa6306145..1cdbe76287dea 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1489,6 +1489,13 @@ template<class ForwardIterator>
     shift_right(ForwardIterator first, ForwardIterator last,
                 typename iterator_traits<ForwardIterator>::difference_type n); // C++20
 
+  template<permutable I, sentinel_for<I> S>
+    constexpr subrange<I> ranges::shift_right(I first, S last, iter_difference_t<I> n);              // since C++23
+
+  template<forward_range R>
+    requires permutable<iterator_t<R>>
+    constexpr borrowed_subrange_t<R> ranges::shift_right(R&& r, range_difference_t<R> n)             // since C++23
+
 template <class InputIterator, class Predicate>
     constexpr bool  // constexpr since C++20
     is_partitioned(InputIterator first, InputIterator last, Predicate pred);
@@ -2035,6 +2042,7 @@ template <class BidirectionalIterator, class Compare>
 #    include <__algorithm/ranges_ends_with.h>
 #    include <__algorithm/ranges_find_last.h>
 #    include <__algorithm/ranges_fold.h>
+#    include <__algorithm/ranges_shift_right.h>
 #    include <__algorithm/ranges_starts_with.h>
 #  endif // _LIBCPP_STD_VER >= 23
 
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 62f928667bbd6..307c562a9a5d2 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -760,6 +760,9 @@ module std [system] {
       export std.functional.ranges_operations
       export std.algorithm.in_in_out_result
     }
+    module ranges_shift_right {
+      header "__algorithm/ranges_shift_right.h"
+    }
     module ranges_shuffle {
       header "__algorithm/ranges_shuffle.h"
     }
diff --git a/libcxx/include/version b/libcxx/include/version
index 7d77677a012ce..562538c5393cc 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -236,7 +236,8 @@ __cpp_lib_shared_ptr_arrays                             201707L <memory>
                                                         201611L // C++17
 __cpp_lib_shared_ptr_weak_type                          201606L <memory>
 __cpp_lib_shared_timed_mutex                            201402L <shared_mutex>
-__cpp_lib_shift                                         201806L <algorithm>
+__cpp_lib_shift                                         202202L <algorithm>
+                                                        201806L // C++20
 __cpp_lib_smart_ptr_for_overwrite                       202002L <memory>
 __cpp_lib_smart_ptr_owner_equality                      202306L <memory>
 __cpp_lib_source_location                               201907L <source_location>
@@ -533,6 +534,8 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_ranges_to_container                  202202L
 # define __cpp_lib_ranges_zip                           202110L
 // # define __cpp_lib_reference_from_temporary             202202L
+# undef  __cpp_lib_shift
+# define __cpp_lib_shift                                202202L
 // # define __cpp_lib_spanstream                           202106L
 // # define __cpp_lib_stacktrace                           202011L
 # define __cpp_lib_stdatomic_h                          202011L
diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc
index 95c05f01e5562..768de4bc1dba2 100644
--- a/libcxx/modules/std/algorithm.inc
+++ b/libcxx/modules/std/algorithm.inc
@@ -362,9 +362,11 @@ export namespace std {
 
   using std::shift_right;
 
+  #if _LIBCPP_STD_VER >= 23
   namespace ranges {
-    // using std::ranges::shift_right;
+    using std::ranges::shift_right;
   }
+  #endif // _LIBCPP_STD_VER >= 23
 
   // [alg.sorting], sorting and related operations
   // [alg.sort], sorting
diff --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
new file mode 100644
index 0000000000000..0a49a82276c48
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/alg.shift/assert.shift_right.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: libcpp-hardening-mode=none
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+#include <algorithm>
+#include <array>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+  std::array<int, 5> arr = {1, 2, 3, 4, 5};
+  TEST_LIBCPP_ASSERT_FAILURE(std::ranges::shift_right(arr, -2), "n must be greater than or equal to 0");
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::ranges::shift_right(arr.begin(), arr.end(), -2), "n must be greater than or equal to 0");
+
+  return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp
new file mode 100644
index 0000000000000..48bb35f4b4589
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges_shift_right.pass.cpp
@@ -0,0 +1,307 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=9000000
+
+// <algorithm>
+
+// template<permutable I, sentinel_for<I> S>
+//   constexpr subrange<I> ranges::shift_right(I first, S last, iter_difference_t<I> n);
+
+// template<forward_range R>
+//   requires permutable<iterator_t<R>>
+//   constexpr borrowed_subrange_t<R> ranges::shift_right(R&& r, range_difference_t<R> n)
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <vector>
+
+#include "almost_satisfies_types.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "MoveOnly.h"
+
+struct InvalidDifferenceT {};
+
+template <class Iter, class Sent = Iter, class N = std::iter_difference_t<Iter>>
+concept HasShiftRightIt = requires(Iter iter, Sent sent, N n) { std::ranges::shift_right(iter, sent, n); };
+
+static_assert(HasShiftRightIt<int*>);
+static_assert(HasShiftRightIt<int*, sentinel_wrapper<int*>>);
+static_assert(HasShiftRightIt<int*, sized_sentinel<int*>>);
+static_assert(!HasShiftRightIt<int*, int*, InvalidDifferenceT>);
+static_assert(!HasShiftRightIt<int*, int, int>);
+
+static_assert(!HasShiftRightIt<ForwardIteratorNotDerivedFrom>);
+static_assert(!HasShiftRightIt<PermutableNotForwardIterator>);
+static_assert(!HasShiftRightIt<PermutableNotSwappable>);
+
+template <class Range, class N = std::ranges::range_difference_t<Range>>
+concept HasShiftRightR = requires(Range range, N n) { std::ranges::shift_right(range, n); };
+
+static_assert(HasShiftRightR<UncheckedRange<int*>>);
+static_assert(!HasShiftRightR<UncheckedRange<int*>, InvalidDifferenceT>);
+
+static_assert(!HasShiftRightR<ForwardRangeNotDerivedFrom>);
+static_assert(!HasShiftRightR<PermutableRangeNotForwardIterator>);
+static_assert(!HasShiftRightR<PermutableRangeNotSwappable>);
+
+struct TrackCopyMove {
+  mutable int copy_count = 0;
+  int move_count         = 0;
+
+  constexpr TrackCopyMove() = default;
+  constexpr TrackCopyMove(const TrackCopyMove& other) : copy_count(other.copy_count), move_count(other.move_count) {
+    ++copy_count;
+    ++other.copy_count;
+  }
+
+  constexpr TrackCopyMove(TrackCopyMove&& other) noexcept : copy_count(other.copy_count), move_count(other.move_count) {
+    ++move_count;
+    ++other.move_count;
+  }
+  constexpr TrackCopyMove& operator=(const TrackCopyMove& other) {
+    ++copy_count;
+    ++other.copy_count;
+    return *this;
+  }
+  constexpr TrackCopyMove& operator=(TrackCopyMove&& other) noexcept {
+    ++move_count;
+    ++other.move_count;
+    return *this;...
[truncated]

@github-actions
Copy link

github-actions bot commented Jan 25, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

@huixie90 huixie90 force-pushed the hxie/ranges_shift_right branch from 91e088f to eb6ff07 Compare January 25, 2026 10:39
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it depends on whether iterator and sentinel are the same type. If they are the same, next simply return the __last without doing any increments

@huixie90 huixie90 merged commit d7a24d3 into llvm:main Feb 14, 2026
82 checks passed
manasij7479 pushed a commit to manasij7479/llvm-project that referenced this pull request Feb 18, 2026
Implement the `ranges::shift_right` algorithm from
[P2440R1](https://wg21.link/P2440R1).

Fixes llvm#134062
Fixes llvm#105184
HendrikHuebner pushed a commit to HendrikHuebner/llvm-project that referenced this pull request Mar 10, 2026
Implement the `ranges::shift_right` algorithm from
[P2440R1](https://wg21.link/P2440R1).

Fixes llvm#134062
Fixes llvm#105184
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P2440R1: ranges::shift_right P2440R1: ranges::iota, ranges::shift_left and ranges::shift_right

3 participants