[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:54:19 PDT 2026
https://github.com/eiytoq created https://github.com/llvm/llvm-project/pull/217460
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
>From 60d583cb93634ecc84c06c18a94678ec11523cb2 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Thu, 20 Aug 2026 03:49:21 +0800
Subject: [PATCH] fix
---
libcxx/docs/Status/Cxx29Issues.csv | 2 +-
.../include/__algorithm/iterator_operations.h | 13 ++++
.../__algorithm/ranges_copy_backward.h | 5 +-
libcxx/include/__algorithm/ranges_fold.h | 11 +++-
.../__algorithm/ranges_inplace_merge.h | 5 +-
libcxx/include/__algorithm/ranges_is_heap.h | 6 +-
.../__algorithm/ranges_is_heap_until.h | 6 +-
libcxx/include/__algorithm/ranges_make_heap.h | 5 +-
.../__algorithm/ranges_move_backward.h | 5 +-
.../__algorithm/ranges_next_permutation.h | 5 +-
.../include/__algorithm/ranges_nth_element.h | 5 +-
.../include/__algorithm/ranges_partial_sort.h | 5 +-
libcxx/include/__algorithm/ranges_pop_heap.h | 5 +-
.../__algorithm/ranges_prev_permutation.h | 5 +-
libcxx/include/__algorithm/ranges_push_heap.h | 5 +-
libcxx/include/__algorithm/ranges_reverse.h | 6 +-
.../include/__algorithm/ranges_reverse_copy.h | 9 ++-
libcxx/include/__algorithm/ranges_rotate.h | 5 +-
libcxx/include/__algorithm/ranges_shuffle.h | 5 +-
libcxx/include/__algorithm/ranges_sort.h | 5 +-
libcxx/include/__algorithm/ranges_sort_heap.h | 5 +-
.../__algorithm/ranges_stable_partition.h | 5 +-
.../include/__algorithm/ranges_stable_sort.h | 5 +-
.../algorithms/iterator_operations.pass.cpp | 60 +++++++++++++++++++
24 files changed, 169 insertions(+), 24 deletions(-)
create mode 100644 libcxx/test/libcxx/algorithms/iterator_operations.pass.cpp
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/libcxx/include/__algorithm/ranges_sort_heap.h
@@ -63,7 +63,10 @@ struct __sort_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 __sort_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+ auto __first = ranges::begin(__r);
+ auto __last = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+ return __sort_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_stable_partition.h b/libcxx/include/__algorithm/ranges_stable_partition.h
index d8cfc8d941450..5c6302a9f77d0 100644
--- a/libcxx/include/__algorithm/ranges_stable_partition.h
+++ b/libcxx/include/__algorithm/ranges_stable_partition.h
@@ -71,7 +71,10 @@ struct __stable_partition {
requires permutable<iterator_t<_Range>>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 borrowed_subrange_t<_Range>
operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
- return __stable_partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
+ auto __first = ranges::begin(__range);
+ auto __last = _IterOps<_RangeAlgPolicy>::__end(__range);
+
+ return __stable_partition_fn_impl(std::move(__first), std::move(__last), __pred, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_stable_sort.h b/libcxx/include/__algorithm/ranges_stable_sort.h
index 6e17d0d0c7ec4..97c401bfba891 100644
--- a/libcxx/include/__algorithm/ranges_stable_sort.h
+++ b/libcxx/include/__algorithm/ranges_stable_sort.h
@@ -62,7 +62,10 @@ struct __stable_sort {
requires sortable<iterator_t<_Range>, _Comp, _Proj>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 borrowed_iterator_t<_Range>
operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
- return __stable_sort_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+ auto __first = ranges::begin(__r);
+ auto __last = _IterOps<_RangeAlgPolicy>::__end(__r);
+
+ return __stable_sort_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
}
};
diff --git a/libcxx/test/libcxx/algorithms/iterator_operations.pass.cpp b/libcxx/test/libcxx/algorithms/iterator_operations.pass.cpp
new file mode 100644
index 0000000000000..ca78cde18cf4b
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/iterator_operations.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+#include <__algorithm/iterator_operations.h>
+#include <cassert>
+#include <cstddef>
+
+#include "test_macros.h"
+#include "test_range.h"
+
+template <class I, class S, bool Sized = false>
+struct test_subrange {
+ I first;
+ S last;
+ std::size_t n = 0;
+
+ bool flag = false;
+
+ I begin() { return first; }
+ S end() { return last; }
+
+ std::size_t size()
+ requires Sized
+ {
+ flag = true;
+ return n;
+ }
+};
+
+template <class I, class S>
+test_subrange(I, S) -> test_subrange<I, S>;
+
+template <class I, class S>
+test_subrange(I, S, std::size_t) -> test_subrange<I, S, true>;
+
+constexpr int data[] = {1, 2, 3};
+
+using Iter = random_access_iterator<const int*>;
+using Sent = sentinel_wrapper<Iter>;
+
+int main(int, char**) {
+ test_subrange r0{Iter(data), Iter(data + 3), 3};
+ std::_IterOps<std::_RangeAlgPolicy>::__end(r0);
+ assert(r0.flag == false);
+
+ test_subrange r1{Iter(data), Sent(Iter(data + 3)), 3};
+ std::_IterOps<std::_RangeAlgPolicy>::__end(r1);
+ assert(r1.flag == true);
+
+ test_subrange r2{Iter(data), Sent(Iter(data + 3))};
+ std::_IterOps<std::_RangeAlgPolicy>::__end(r2);
+ assert(r2.flag == false);
+}
More information about the libcxx-commits
mailing list