[libcxx-commits] [libcxx] [libc++] LWG4490: Allow calling `std::ranges::size` in ranges algorithms (PR #217460)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Aug 19 13:55:04 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: eiytoq (eiytoq)

<details>
<summary>Changes</summary>

LWG4490 allows implementations to use `ranges::size()` to optimize algorithms.

This patch applies this to the following range algorithms:

sorting algorithms
heap algorithms
`ranges::next_permutation`
`ranges::prev_permutation`
`ranges::copy_backward`
`ranges::move_backward`
`ranges::fold_right`
`ranges::fold_right_last`
`ranges::inplace_merge`
`ranges::reverse`
`ranges::reverse_copy`
`ranges::rotate`
`ranges::shuffle`
`ranges::stable_partition`

Fixes #<!-- -->204452


---

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


24 Files Affected:

- (modified) libcxx/docs/Status/Cxx29Issues.csv (+1-1) 
- (modified) libcxx/include/__algorithm/iterator_operations.h (+13) 
- (modified) libcxx/include/__algorithm/ranges_copy_backward.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_fold.h (+9-2) 
- (modified) libcxx/include/__algorithm/ranges_inplace_merge.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_is_heap.h (+5-1) 
- (modified) libcxx/include/__algorithm/ranges_is_heap_until.h (+5-1) 
- (modified) libcxx/include/__algorithm/ranges_make_heap.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_move_backward.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_next_permutation.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_nth_element.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_partial_sort.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_pop_heap.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_prev_permutation.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_push_heap.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_reverse.h (+5-1) 
- (modified) libcxx/include/__algorithm/ranges_reverse_copy.h (+7-2) 
- (modified) libcxx/include/__algorithm/ranges_rotate.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_shuffle.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_sort.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_sort_heap.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_stable_partition.h (+4-1) 
- (modified) libcxx/include/__algorithm/ranges_stable_sort.h (+4-1) 
- (added) libcxx/test/libcxx/algorithms/iterator_operations.pass.cpp (+60) 


``````````diff
diff --git a/libcxx/docs/Status/Cxx29Issues.csv b/libcxx/docs/Status/Cxx29Issues.csv
index 13056a97782df..c6a7d58168e42 100644
--- a/libcxx/docs/Status/Cxx29Issues.csv
+++ b/libcxx/docs/Status/Cxx29Issues.csv
@@ -11,7 +11,7 @@
 "`LWG4385 <https://wg21.link/LWG4385>`__","Including ``<simd>`` doesn't provide ``std::begin``/``end``","2026-06 (Brno)","","","`#204449 <https://github.com/llvm/llvm-project/issues/204449>`__",""
 "`LWG4471 <https://wg21.link/LWG4471>`__","Remove test for ``get_env`` ``noexcept``-ness from ``inline_scheduler``","2026-06 (Brno)","","","`#204450 <https://github.com/llvm/llvm-project/issues/204450>`__",""
 "`LWG4487 <https://wg21.link/LWG4487>`__","Is member ``is_steady`` of a *Cpp17Clock* type required to be usable in constant expressions?","2026-06 (Brno)","","","`#204451 <https://github.com/llvm/llvm-project/issues/204451>`__",""
-"`LWG4490 <https://wg21.link/LWG4490>`__","Allow calling ``std::ranges::size`` in ranges algorithms","2026-06 (Brno)","","","`#204452 <https://github.com/llvm/llvm-project/issues/204452>`__",""
+"`LWG4490 <https://wg21.link/LWG4490>`__","Allow calling ``std::ranges::size`` in ranges algorithms","2026-06 (Brno)","|Complete|","24","`#204452 <https://github.com/llvm/llvm-project/issues/204452>`__",""
 "`LWG4521 <https://wg21.link/LWG4521>`__","Improve [atomics.order] p10 to have a consistent way with [intro.races]","2026-06 (Brno)","","","`#204453 <https://github.com/llvm/llvm-project/issues/204453>`__",""
 "`LWG4531 <https://wg21.link/LWG4531>`__","Should there be a feature-test macro update for ``constexpr`` ``std::to_(w)string``?","2026-06 (Brno)","","","`#204454 <https://github.com/llvm/llvm-project/issues/204454>`__",""
 "`LWG4567 <https://wg21.link/LWG4567>`__","Feature test macro value for ``apply_result``, ``is_applicable``","2026-06 (Brno)","","","`#204455 <https://github.com/llvm/llvm-project/issues/204455>`__",""
diff --git a/libcxx/include/__algorithm/iterator_operations.h b/libcxx/include/__algorithm/iterator_operations.h
index 1aa2f8d1604f1..273f3298f780f 100644
--- a/libcxx/include/__algorithm/iterator_operations.h
+++ b/libcxx/include/__algorithm/iterator_operations.h
@@ -22,6 +22,8 @@
 #include <__iterator/next.h>
 #include <__iterator/prev.h>
 #include <__iterator/readable_traits.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_reference.h>
 #include <__type_traits/is_same.h>
@@ -63,6 +65,17 @@ struct _IterOps<_RangeAlgPolicy> {
   static constexpr auto next         = ranges::next;
   static constexpr auto prev         = ranges::prev;
   static constexpr auto __advance_to = ranges::advance;
+
+  template <ranges::forward_range _Range>
+  _LIBCPP_HIDE_FROM_ABI static constexpr auto __end(_Range&& __range) {
+    if constexpr (ranges::common_range<_Range>) {
+      return ranges::end(__range);
+    } else if constexpr (ranges::random_access_range<_Range> && ranges::sized_range<_Range>) {
+      return ranges::next(ranges::begin(__range), ranges::distance(__range));
+    } else {
+      return ranges::end(__range);
+    }
+  }
 };
 
 #endif
diff --git a/libcxx/include/__algorithm/ranges_copy_backward.h b/libcxx/include/__algorithm/ranges_copy_backward.h
index ff4e7c241e1e8..c8f9195a1ff46 100644
--- a/libcxx/include/__algorithm/ranges_copy_backward.h
+++ b/libcxx/include/__algorithm/ranges_copy_backward.h
@@ -47,7 +47,10 @@ struct __copy_backward {
     requires indirectly_copyable<iterator_t<_Range>, _Iter>
   _LIBCPP_HIDE_FROM_ABI constexpr copy_backward_result<borrowed_iterator_t<_Range>, _Iter>
   operator()(_Range&& __r, _Iter __result) const {
-    return std::__copy_backward<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), std::move(__result));
+    auto __first = ranges::begin(__r);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+    return std::__copy_backward<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_fold.h b/libcxx/include/__algorithm/ranges_fold.h
index a82d9acfcea8c..1c0ac56e1dee8 100644
--- a/libcxx/include/__algorithm/ranges_fold.h
+++ b/libcxx/include/__algorithm/ranges_fold.h
@@ -11,6 +11,7 @@
 #define _LIBCPP___ALGORITHM_RANGES_FOLD_H
 
 #include <__algorithm/for_each.h>
+#include <__algorithm/iterator_operations.h>
 #include <__concepts/assignable.h>
 #include <__concepts/constructible.h>
 #include <__concepts/convertible_to.h>
@@ -231,7 +232,10 @@ struct __fold_right {
 
   template <bidirectional_range _Range, class _Tp, __indirectly_binary_right_foldable<_Tp, iterator_t<_Range>> _Func>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range, _Tp __init, _Func __func) {
-    return operator()(ranges::begin(__range), ranges::end(__range), std::move(__init), std::ref(__func));
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return operator()(std::move(__first), std::move(__last), std::move(__init), std::ref(__func));
   }
 };
 
@@ -255,7 +259,10 @@ struct __fold_right_last {
   template <bidirectional_range _Range,
             __indirectly_binary_right_foldable<range_value_t<_Range>, iterator_t<_Range>> _Func>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range, _Func __func) {
-    return operator()(ranges::begin(__range), ranges::end(__range), std::ref(__func));
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return operator()(std::move(__first), std::move(__last), std::ref(__func));
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_inplace_merge.h b/libcxx/include/__algorithm/ranges_inplace_merge.h
index 54581aff396ea..7abb1a7f4b55b 100644
--- a/libcxx/include/__algorithm/ranges_inplace_merge.h
+++ b/libcxx/include/__algorithm/ranges_inplace_merge.h
@@ -61,8 +61,11 @@ struct __inplace_merge {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 borrowed_iterator_t<_Range>
   operator()(_Range&& __range, iterator_t<_Range> __middle, _Comp __comp = {}, _Proj __proj = {}) const {
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
     return __inplace_merge_impl(
-        ranges::begin(__range), std::move(__middle), ranges::end(__range), std::move(__comp), std::move(__proj));
+        std::move(__first), std::move(__middle), std::move(__last), std::move(__comp), std::move(__proj));
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_is_heap.h b/libcxx/include/__algorithm/ranges_is_heap.h
index b4724abfb62a5..db750e6d52fe1 100644
--- a/libcxx/include/__algorithm/ranges_is_heap.h
+++ b/libcxx/include/__algorithm/ranges_is_heap.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ALGORITHM_RANGES_IS_HEAP_H
 
 #include <__algorithm/is_heap_until.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -59,7 +60,10 @@ struct __is_heap {
             indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool
   operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __is_heap_fn_impl(ranges::begin(__range), ranges::end(__range), __comp, __proj);
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return __is_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_is_heap_until.h b/libcxx/include/__algorithm/ranges_is_heap_until.h
index 25f3b484faa66..92e1cb3887195 100644
--- a/libcxx/include/__algorithm/ranges_is_heap_until.h
+++ b/libcxx/include/__algorithm/ranges_is_heap_until.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ALGORITHM_RANGES_IS_HEAP_UNTIL_H
 
 #include <__algorithm/is_heap_until.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -59,7 +60,10 @@ struct __is_heap_until {
             indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range>
   operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __is_heap_until_fn_impl(ranges::begin(__range), ranges::end(__range), __comp, __proj);
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return __is_heap_until_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_make_heap.h b/libcxx/include/__algorithm/ranges_make_heap.h
index 97148f77b4181..8a65497c058fb 100644
--- a/libcxx/include/__algorithm/ranges_make_heap.h
+++ b/libcxx/include/__algorithm/ranges_make_heap.h
@@ -63,7 +63,10 @@ struct __make_heap {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range>
   operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __make_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+    auto __first = ranges::begin(__r);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+    return __make_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_move_backward.h b/libcxx/include/__algorithm/ranges_move_backward.h
index a4b51d09a68b0..d64f7d18a434c 100644
--- a/libcxx/include/__algorithm/ranges_move_backward.h
+++ b/libcxx/include/__algorithm/ranges_move_backward.h
@@ -49,7 +49,10 @@ struct __move_backward {
     requires indirectly_movable<iterator_t<_Range>, _Iter>
   _LIBCPP_HIDE_FROM_ABI constexpr move_backward_result<borrowed_iterator_t<_Range>, _Iter>
   operator()(_Range&& __range, _Iter __result) const {
-    return std::__move_backward<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), std::move(__result));
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return std::__move_backward<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_next_permutation.h b/libcxx/include/__algorithm/ranges_next_permutation.h
index 1b485423e892f..333c33e6fc5c3 100644
--- a/libcxx/include/__algorithm/ranges_next_permutation.h
+++ b/libcxx/include/__algorithm/ranges_next_permutation.h
@@ -54,8 +54,11 @@ struct __next_permutation {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr next_permutation_result<borrowed_iterator_t<_Range>>
   operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
     auto __result = std::__next_permutation<_RangeAlgPolicy>(
-        ranges::begin(__range), ranges::end(__range), std::__make_projected(__comp, __proj));
+        std::move(__first), std::move(__last), std::__make_projected(__comp, __proj));
     return {std::move(__result.first), std::move(__result.second)};
   }
 };
diff --git a/libcxx/include/__algorithm/ranges_nth_element.h b/libcxx/include/__algorithm/ranges_nth_element.h
index e92c51e713cb4..771543f28121d 100644
--- a/libcxx/include/__algorithm/ranges_nth_element.h
+++ b/libcxx/include/__algorithm/ranges_nth_element.h
@@ -62,7 +62,10 @@ struct __nth_element {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range>
   operator()(_Range&& __r, iterator_t<_Range> __nth, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __nth_element_fn_impl(ranges::begin(__r), std::move(__nth), ranges::end(__r), __comp, __proj);
+    auto __first = ranges::begin(__r);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+    return __nth_element_fn_impl(std::move(__first), std::move(__nth), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_partial_sort.h b/libcxx/include/__algorithm/ranges_partial_sort.h
index fc8a1f7d93065..51dda25cfba12 100644
--- a/libcxx/include/__algorithm/ranges_partial_sort.h
+++ b/libcxx/include/__algorithm/ranges_partial_sort.h
@@ -60,7 +60,10 @@ struct __partial_sort {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range>
   operator()(_Range&& __r, iterator_t<_Range> __middle, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __partial_sort_fn_impl(ranges::begin(__r), std::move(__middle), ranges::end(__r), __comp, __proj);
+    auto __first = ranges::begin(__r);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+    return __partial_sort_fn_impl(std::move(__first), std::move(__middle), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_pop_heap.h b/libcxx/include/__algorithm/ranges_pop_heap.h
index eccf54c094e3d..6584d749f893a 100644
--- a/libcxx/include/__algorithm/ranges_pop_heap.h
+++ b/libcxx/include/__algorithm/ranges_pop_heap.h
@@ -64,7 +64,10 @@ struct __pop_heap {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range>
   operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __pop_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+    auto __first = ranges::begin(__r);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+    return __pop_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_prev_permutation.h b/libcxx/include/__algorithm/ranges_prev_permutation.h
index f2294b1cb00ba..6707ff52f5368 100644
--- a/libcxx/include/__algorithm/ranges_prev_permutation.h
+++ b/libcxx/include/__algorithm/ranges_prev_permutation.h
@@ -54,8 +54,11 @@ struct __prev_permutation {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr prev_permutation_result<borrowed_iterator_t<_Range>>
   operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
     auto __result = std::__prev_permutation<_RangeAlgPolicy>(
-        ranges::begin(__range), ranges::end(__range), std::__make_projected(__comp, __proj));
+        std::move(__first), std::move(__last), std::__make_projected(__comp, __proj));
     return {std::move(__result.first), std::move(__result.second)};
   }
 };
diff --git a/libcxx/include/__algorithm/ranges_push_heap.h b/libcxx/include/__algorithm/ranges_push_heap.h
index c5e0465bdcfe1..c5c5ceb4ac865 100644
--- a/libcxx/include/__algorithm/ranges_push_heap.h
+++ b/libcxx/include/__algorithm/ranges_push_heap.h
@@ -63,7 +63,10 @@ struct __push_heap {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range>
   operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __push_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+    auto __first = ranges::begin(__r);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+    return __push_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_reverse.h b/libcxx/include/__algorithm/ranges_reverse.h
index 4e82118719772..5b549150f6218 100644
--- a/libcxx/include/__algorithm/ranges_reverse.h
+++ b/libcxx/include/__algorithm/ranges_reverse.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_REVERSE_H
 #define _LIBCPP___ALGORITHM_RANGES_REVERSE_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__iterator/iter_swap.h>
@@ -61,7 +62,10 @@ struct __reverse {
   template <bidirectional_range _Range>
     requires permutable<iterator_t<_Range>>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> operator()(_Range&& __range) const {
-    return (*this)(ranges::begin(__range), ranges::end(__range));
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return (*this)(std::move(__first), std::move(__last));
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_reverse_copy.h b/libcxx/include/__algorithm/ranges_reverse_copy.h
index 9fedab5bd4362..1f1de11f8dca3 100644
--- a/libcxx/include/__algorithm/ranges_reverse_copy.h
+++ b/libcxx/include/__algorithm/ranges_reverse_copy.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ALGORITHM_RANGES_REVERSE_COPY_H
 
 #include <__algorithm/in_out_result.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/ranges_copy.h>
 #include <__config>
 #include <__iterator/concepts.h>
@@ -50,8 +51,12 @@ struct __reverse_copy {
     requires indirectly_copyable<iterator_t<_Range>, _OutIter>
   _LIBCPP_HIDE_FROM_ABI constexpr reverse_copy_result<borrowed_iterator_t<_Range>, _OutIter>
   operator()(_Range&& __range, _OutIter __result) const {
-    auto __ret = ranges::copy(__range | views::reverse, std::move(__result));
-    return {ranges::next(ranges::begin(__range), ranges::end(__range)), std::move(__ret.out)};
+    auto __first = ranges::begin(__range);
+    auto __last  = ranges::next(__first, _IterOps<_RangeAlgPolicy>::__end(__range));
+
+    auto __ret =
+        ranges::copy(std::make_reverse_iterator(__last), std::make_reverse_iterator(__first), std::move(__result));
+    return {std::move(__last), std::move(__ret.out)};
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_rotate.h b/libcxx/include/__algorithm/ranges_rotate.h
index c1affc684ae4f..6878fed268de4 100644
--- a/libcxx/include/__algorithm/ranges_rotate.h
+++ b/libcxx/include/__algorithm/ranges_rotate.h
@@ -49,7 +49,10 @@ struct __rotate {
     requires permutable<iterator_t<_Range>>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range>
   operator()(_Range&& __range, iterator_t<_Range> __middle) const {
-    return __rotate_fn_impl(ranges::begin(__range), std::move(__middle), ranges::end(__range));
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return __rotate_fn_impl(std::move(__first), std::move(__middle), std::move(__last));
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_shuffle.h b/libcxx/include/__algorithm/ranges_shuffle.h
index 87cb3685bb95f..c22780c722a0e 100644
--- a/libcxx/include/__algorithm/ranges_shuffle.h
+++ b/libcxx/include/__algorithm/ranges_shuffle.h
@@ -50,7 +50,10 @@ struct __shuffle {
   template <random_access_range _Range, class _Gen>
     requires permutable<iterator_t<_Range>> && uniform_random_bit_generator<remove_reference_t<_Gen>>
   _LIBCPP_HIDE_FROM_ABI borrowed_iterator_t<_Range> operator()(_Range&& __range, _Gen&& __gen) const {
-    return (*this)(ranges::begin(__range), ranges::end(__range), std::forward<_Gen>(__gen));
+    auto __first = ranges::begin(__range);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+    return (*this)(std::move(__first), std::move(__last), std::forward<_Gen>(__gen));
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_sort.h b/libcxx/include/__algorithm/ranges_sort.h
index 2afad4c41301e..8e3adab29bda2 100644
--- a/libcxx/include/__algorithm/ranges_sort.h
+++ b/libcxx/include/__algorithm/ranges_sort.h
@@ -62,7 +62,10 @@ struct __sort {
     requires sortable<iterator_t<_Range>, _Comp, _Proj>
   _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range>
   operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
-    return __sort_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+    auto __first = ranges::begin(__r);
+    auto __last  = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+    return __sort_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
   }
 };
 
diff --git a/libcxx/include/__algorithm/ranges_sort_heap.h b/libcxx/include/__algorithm/ranges_sort_heap.h
index d3e20874fac50..f14f37c96a7da 100644
--- a/libcxx/include/__algorithm/ranges_sort_heap.h
+++ b/lib...
[truncated]

``````````

</details>


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


More information about the libcxx-commits mailing list