[libcxx-commits] [libcxx] a7c3379 - [libc++][ranges] Make range algorithms support proxy iterators
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jul 17 18:12:14 PDT 2022
Author: Konstantin Varlamov
Date: 2022-07-17T18:12:06-07:00
New Revision: a7c3379cf9a4efc9381f832639827a39f0396f65
URL: https://github.com/llvm/llvm-project/commit/a7c3379cf9a4efc9381f832639827a39f0396f65
DIFF: https://github.com/llvm/llvm-project/commit/a7c3379cf9a4efc9381f832639827a39f0396f65.diff
LOG: [libc++][ranges] Make range algorithms support proxy iterators
Also test all the range algorithms to verify the support.
Differential Revision: https://reviews.llvm.org/D129823
Added:
libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
Modified:
libcxx/include/__algorithm/inplace_merge.h
libcxx/include/__algorithm/iterator_operations.h
libcxx/include/__algorithm/make_heap.h
libcxx/include/__algorithm/min_element.h
libcxx/include/__algorithm/nth_element.h
libcxx/include/__algorithm/partial_sort.h
libcxx/include/__algorithm/partial_sort_copy.h
libcxx/include/__algorithm/pop_heap.h
libcxx/include/__algorithm/push_heap.h
libcxx/include/__algorithm/ranges_fill.h
libcxx/include/__algorithm/ranges_make_heap.h
libcxx/include/__algorithm/ranges_min_element.h
libcxx/include/__algorithm/ranges_nth_element.h
libcxx/include/__algorithm/ranges_pop_heap.h
libcxx/include/__algorithm/ranges_push_heap.h
libcxx/include/__algorithm/ranges_sort.h
libcxx/include/__algorithm/ranges_sort_heap.h
libcxx/include/__algorithm/ranges_stable_sort.h
libcxx/include/__algorithm/shuffle.h
libcxx/include/__algorithm/sift_down.h
libcxx/include/__algorithm/sort.h
libcxx/include/__algorithm/sort_heap.h
libcxx/include/__algorithm/stable_sort.h
libcxx/include/__debug_utils/randomize_range.h
libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
libcxx/test/support/test.support/test_proxy.pass.cpp
libcxx/test/support/test_iterators.h
Removed:
################################################################################
diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index 58919ddbae76..7369786eeb06 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/lower_bound.h>
#include <__algorithm/min.h>
#include <__algorithm/move.h>
@@ -21,7 +22,6 @@
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
-#include <__utility/swap.h>
#include <memory>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -53,7 +53,7 @@ class __invert // invert the sense of a comparison
bool operator()(const _T1& __x, const _T2& __y) {return __p_(__y, __x);}
};
-template <class _Compare, class _InputIterator1, class _InputIterator2,
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2,
class _OutputIterator>
void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
@@ -63,25 +63,26 @@ void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
{
if (__first2 == __last2)
{
+ // TODO(alg-policy): pass `_AlgPolicy` once it's supported by `move`.
_VSTD::move(__first1, __last1, __result);
return;
}
if (__comp(*__first2, *__first1))
{
- *__result = _VSTD::move(*__first2);
+ *__result = _IterOps<_AlgPolicy>::__iter_move(__first2);
++__first2;
}
else
{
- *__result = _VSTD::move(*__first1);
+ *__result = _IterOps<_AlgPolicy>::__iter_move(__first1);
++__first1;
}
}
// __first2 through __last2 are already in the right spot.
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void
__buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
_Compare __comp, typename iterator_traits<_BidirectionalIterator>::
diff erence_type __len1,
@@ -95,30 +96,32 @@ __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator
{
value_type* __p = __buff;
for (_BidirectionalIterator __i = __first; __i != __middle; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
- ::new ((void*)__p) value_type(_VSTD::move(*__i));
- _VSTD::__half_inplace_merge<_Compare>(__buff, __p, __middle, __last, __first, __comp);
+ ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
+ std::__half_inplace_merge<_AlgPolicy, _Compare>(__buff, __p, __middle, __last, __first, __comp);
}
else
{
value_type* __p = __buff;
for (_BidirectionalIterator __i = __middle; __i != __last; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
- ::new ((void*)__p) value_type(_VSTD::move(*__i));
+ ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
typedef reverse_iterator<_BidirectionalIterator> _RBi;
typedef reverse_iterator<value_type*> _Rv;
typedef __invert<_Compare> _Inverted;
- _VSTD::__half_inplace_merge<_Inverted>(_Rv(__p), _Rv(__buff),
+ std::__half_inplace_merge<_AlgPolicy, _Inverted>(_Rv(__p), _Rv(__buff),
_RBi(__middle), _RBi(__first),
_RBi(__last), _Inverted(__comp));
}
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void
__inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
_Compare __comp, typename iterator_traits<_BidirectionalIterator>::
diff erence_type __len1,
typename iterator_traits<_BidirectionalIterator>::
diff erence_type __len2,
typename iterator_traits<_BidirectionalIterator>::value_type* __buff, ptr
diff _t __buff_size)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_BidirectionalIterator>::
diff erence_type
diff erence_type;
while (true)
{
@@ -126,7 +129,7 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
if (__len2 == 0)
return;
if (__len1 <= __buff_size || __len2 <= __buff_size)
- return _VSTD::__buffered_inplace_merge<_Compare>
+ return std::__buffered_inplace_merge<_AlgPolicy, _Compare>
(__first, __middle, __last, __comp, __len1, __len2, __buff);
// shrink [__first, __middle) as much as possible (with no moves), returning if it shrinks to 0
for (; true; ++__first, (void) --__len1)
@@ -153,35 +156,37 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
{ // __len >= 1, __len2 >= 2
__len21 = __len2 / 2;
__m2 = __middle;
- _VSTD::advance(__m2, __len21);
+ _Ops::advance(__m2, __len21);
__m1 = _VSTD::__upper_bound<_Compare>(__first, __middle, *__m2, __comp);
- __len11 = _VSTD::distance(__first, __m1);
+ __len11 = _Ops::distance(__first, __m1);
}
else
{
if (__len1 == 1)
{ // __len1 >= __len2 && __len2 > 0, therefore __len2 == 1
// It is known *__first > *__middle
- swap(*__first, *__middle);
+ _Ops::iter_swap(__first, __middle);
return;
}
// __len1 >= 2, __len2 >= 1
__len11 = __len1 / 2;
__m1 = __first;
- _VSTD::advance(__m1, __len11);
+ _Ops::advance(__m1, __len11);
__m2 = std::lower_bound(__middle, __last, *__m1, __comp);
- __len21 = _VSTD::distance(__middle, __m2);
+ __len21 = _Ops::distance(__middle, __m2);
}
diff erence_type __len12 = __len1 - __len11; // distance(__m1, __middle)
diff erence_type __len22 = __len2 - __len21; // distance(__m2, __last)
// [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last)
// swap middle two partitions
+ // TODO(alg-policy): pass `_AlgPolicy` once it's supported by `rotate`.
__middle = _VSTD::rotate(__m1, __middle, __m2);
// __len12 and __len21 now have swapped meanings
// merge smaller range with recursive call and larger with tail recursion elimination
if (__len11 + __len21 < __len12 + __len22)
{
- _VSTD::__inplace_merge<_Compare>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
+ std::__inplace_merge<_AlgPolicy, _Compare>(
+ __first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
// _VSTD::__inplace_merge<_Compare>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
__first = __middle;
__middle = __m2;
@@ -190,7 +195,8 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
}
else
{
- _VSTD::__inplace_merge<_Compare>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
+ std::__inplace_merge<_AlgPolicy, _Compare>(
+ __middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
// _VSTD::__inplace_merge<_Compare>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
__last = __middle;
__middle = __m1;
@@ -217,7 +223,7 @@ _LIBCPP_SUPPRESS_DEPRECATED_PUSH
_LIBCPP_SUPPRESS_DEPRECATED_POP
unique_ptr<value_type, __return_temporary_buffer> __h(__buf.first);
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__inplace_merge<_Comp_ref>(__first, __middle, __last, __comp, __len1, __len2,
+ return _VSTD::__inplace_merge<_ClassicAlgPolicy, _Comp_ref>(__first, __middle, __last, __comp, __len1, __len2,
__buf.first, __buf.second);
}
diff --git a/libcxx/include/__algorithm/iterator_operations.h b/libcxx/include/__algorithm/iterator_operations.h
index eb627e1ace7a..de9c8a130ecb 100644
--- a/libcxx/include/__algorithm/iterator_operations.h
+++ b/libcxx/include/__algorithm/iterator_operations.h
@@ -41,6 +41,7 @@ struct _IterOps<_RangeAlgPolicy> {
static constexpr auto next = ranges::next;
static constexpr auto __advance_to = ranges::advance;
};
+
#endif
struct _ClassicAlgPolicy {};
@@ -85,7 +86,8 @@ struct _IterOps<_ClassicAlgPolicy> {
}
template <class _Iter>
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11 void __advance_to(_Iter& __first, _Iter __last) {
+ _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
+ void __advance_to(_Iter& __first, _Iter __last) {
__first = __last;
}
};
diff --git a/libcxx/include/__algorithm/make_heap.h b/libcxx/include/__algorithm/make_heap.h
index bc39d82bf916..bf9dd96756af 100644
--- a/libcxx/include/__algorithm/make_heap.h
+++ b/libcxx/include/__algorithm/make_heap.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/sift_down.h>
#include <__config>
#include <__iterator/iterator_traits.h>
@@ -22,7 +23,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using _CompRef = typename __comp_ref_type<_Compare>::type;
@@ -33,7 +34,7 @@ void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
if (__n > 1) {
// start from the first parent, there is no need to consider children
for (
diff erence_type __start = (__n - 2) / 2; __start >= 0; --__start) {
- std::__sift_down<_CompRef>(__first, __comp_ref, __n, __first + __start);
+ std::__sift_down<_AlgPolicy, _CompRef>(__first, __comp_ref, __n, __first + __start);
}
}
}
@@ -41,7 +42,7 @@ void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__make_heap(std::move(__first), std::move(__last), __comp);
+ std::__make_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/min_element.h b/libcxx/include/__algorithm/min_element.h
index 129833d42bda..17b242c341e6 100644
--- a/libcxx/include/__algorithm/min_element.h
+++ b/libcxx/include/__algorithm/min_element.h
@@ -12,7 +12,11 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
#include <__iterator/iterator_traits.h>
+#include <__type_traits/is_callable.h>
+#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -20,28 +24,38 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _ForwardIterator>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
-__min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp)
-{
- static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value,
- "std::min_element requires a ForwardIterator");
- if (__first != __last)
- {
- _ForwardIterator __i = __first;
- while (++__i != __last)
- if (__comp(*__i, *__first))
- __first = __i;
- }
+template <class _Comp, class _Iter, class _Sent, class _Proj>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+_Iter __min_element(_Iter __first, _Sent __last, _Comp __comp, _Proj& __proj) {
+ if (__first == __last)
return __first;
+
+ _Iter __i = __first;
+ while (++__i != __last)
+ if (std::__invoke(__comp, std::__invoke(__proj, *__i), std::__invoke(__proj, *__first)))
+ __first = __i;
+
+ return __first;
+}
+
+template <class _Comp, class _Iter, class _Sent>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+_Iter __min_element(_Iter __first, _Sent __last, _Comp __comp) {
+ auto __proj = __identity();
+ return std::__min_element<_Comp>(std::move(__first), std::move(__last), __comp, __proj);
}
template <class _ForwardIterator, class _Compare>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp)
{
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__min_element<_Comp_ref>(__first, __last, __comp);
+ static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value,
+ "std::min_element requires a ForwardIterator");
+ static_assert(__is_callable<_Compare, decltype(*__first), decltype(*__first)>::value,
+ "The comparator has to be callable");
+
+ typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
+ return std::__min_element<_Comp_ref>(std::move(__first), std::move(__last), __comp);
}
template <class _ForwardIterator>
diff --git a/libcxx/include/__algorithm/nth_element.h b/libcxx/include/__algorithm/nth_element.h
index c7cdef5be817..688398dee814 100644
--- a/libcxx/include/__algorithm/nth_element.h
+++ b/libcxx/include/__algorithm/nth_element.h
@@ -11,13 +11,13 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/sort.h>
#include <__config>
#include <__debug>
#include <__debug_utils/randomize_range.h>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
-#include <__utility/swap.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -41,10 +41,12 @@ __nth_element_find_guard(_RandomAccessIterator& __i, _RandomAccessIterator& __j,
}
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 void
__nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
// _Compare is known to be a reference type
typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type
diff erence_type;
const
diff erence_type __limit = 7;
@@ -60,24 +62,24 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
return;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _Ops::iter_swap(__first, __last);
return;
case 3:
{
_RandomAccessIterator __m = __first;
- _VSTD::__sort3<_Compare>(__first, ++__m, --__last, __comp);
+ std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp);
return;
}
}
if (__len <= __limit)
{
- _VSTD::__selection_sort<_Compare>(__first, __last, __comp);
+ std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
return;
}
// __len > __limit >= 3
_RandomAccessIterator __m = __first + __len/2;
_RandomAccessIterator __lm1 = __last;
- unsigned __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, --__lm1, __comp);
+ unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp);
// *__m is median
// partition [__first, __m) < *__m and *__m <= [__m, __last)
// (this inhibits tossing elements equivalent to __m around unnecessarily)
@@ -90,7 +92,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
{
// *__first == *__m, *__first doesn't go in first part
if (_VSTD::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
} else {
// *__first == *__m, *__m <= all other elements
@@ -102,7 +104,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
if (__i == __j) {
return; // [__first, __last) all equivalent elements
} else if (__comp(*__first, *__i)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
break;
@@ -121,7 +123,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
;
if (__i >= __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
}
@@ -152,7 +154,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
;
if (__i >= __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
// It is known that __m != __j
// If __m just moved, follow it
@@ -164,7 +166,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
// [__first, __i) < *__m and *__m <= [__i, __last)
if (__i != __m && __comp(*__m, *__i))
{
- swap(*__i, *__m);
+ _Ops::iter_swap(__i, __m);
++__n_swaps;
}
// [__first, __i) < *__i and *__i <= [__i+1, __last)
@@ -220,21 +222,21 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
}
}
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void __nth_element_impl(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last,
_Compare& __comp) {
if (__nth == __last)
return;
- std::__debug_randomize_range(__first, __last);
+ std::__debug_randomize_range<_AlgPolicy>(__first, __last);
using _Comp_ref = typename __comp_ref_type<_Compare>::type;
- std::__nth_element<_Comp_ref>(__first, __nth, __last, __comp);
+ std::__nth_element<_AlgPolicy, _Comp_ref>(__first, __nth, __last, __comp);
- std::__debug_randomize_range(__first, __nth);
+ std::__debug_randomize_range<_AlgPolicy>(__first, __nth);
if (__nth != __last) {
- std::__debug_randomize_range(++__nth, __last);
+ std::__debug_randomize_range<_AlgPolicy>(++__nth, __last);
}
}
@@ -242,7 +244,7 @@ template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last,
_Compare __comp) {
- std::__nth_element_impl(std::move(__first), std::move(__nth), std::move(__last), __comp);
+ std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/partial_sort.h b/libcxx/include/__algorithm/partial_sort.h
index e008c0c99679..2c2468fc09ac 100644
--- a/libcxx/include/__algorithm/partial_sort.h
+++ b/libcxx/include/__algorithm/partial_sort.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_heap.h>
#include <__algorithm/sift_down.h>
#include <__algorithm/sort_heap.h>
@@ -18,7 +19,6 @@
#include <__debug>
#include <__debug_utils/randomize_range.h>
#include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -26,24 +26,24 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
__partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
_Compare __comp)
{
if (__first == __middle)
return;
- _VSTD::__make_heap<_Compare>(__first, __middle, __comp);
+ std::__make_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __middle - __first;
for (_RandomAccessIterator __i = __middle; __i != __last; ++__i)
{
if (__comp(*__i, *__first))
{
- swap(*__i, *__first);
- _VSTD::__sift_down<_Compare>(__first, __comp, __len, __first);
+ _IterOps<_AlgPolicy>::iter_swap(__i, __first);
+ std::__sift_down<_AlgPolicy, _Compare>(__first, __comp, __len, __first);
}
}
- _VSTD::__sort_heap<_Compare>(__first, __middle, __comp);
+ std::__sort_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
}
template <class _RandomAccessIterator, class _Compare>
@@ -52,10 +52,10 @@ void
partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
_Compare __comp)
{
- std::__debug_randomize_range(__first, __last);
+ std::__debug_randomize_range<_ClassicAlgPolicy>(__first, __last);
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- _VSTD::__partial_sort<_Comp_ref>(__first, __middle, __last, __comp);
- std::__debug_randomize_range(__middle, __last);
+ std::__partial_sort<_ClassicAlgPolicy, _Comp_ref>(__first, __middle, __last, __comp);
+ std::__debug_randomize_range<_ClassicAlgPolicy>(__middle, __last);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/partial_sort_copy.h b/libcxx/include/__algorithm/partial_sort_copy.h
index 7ed1e538e9b8..3556764e652d 100644
--- a/libcxx/include/__algorithm/partial_sort_copy.h
+++ b/libcxx/include/__algorithm/partial_sort_copy.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_heap.h>
#include <__algorithm/sift_down.h>
#include <__algorithm/sort_heap.h>
@@ -23,7 +24,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _InputIterator, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _InputIterator, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 _RandomAccessIterator
__partial_sort_copy(_InputIterator __first, _InputIterator __last,
_RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp)
@@ -33,15 +34,15 @@ __partial_sort_copy(_InputIterator __first, _InputIterator __last,
{
for (; __first != __last && __r != __result_last; ++__first, (void) ++__r)
*__r = *__first;
- _VSTD::__make_heap<_Compare>(__result_first, __r, __comp);
+ std::__make_heap<_AlgPolicy, _Compare>(__result_first, __r, __comp);
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __r - __result_first;
for (; __first != __last; ++__first)
if (__comp(*__first, *__result_first))
{
*__result_first = *__first;
- _VSTD::__sift_down<_Compare>(__result_first, __comp, __len, __result_first);
+ std::__sift_down<_AlgPolicy, _Compare>(__result_first, __comp, __len, __result_first);
}
- _VSTD::__sort_heap<_Compare>(__result_first, __r, __comp);
+ std::__sort_heap<_AlgPolicy, _Compare>(__result_first, __r, __comp);
}
return __r;
}
@@ -53,7 +54,8 @@ partial_sort_copy(_InputIterator __first, _InputIterator __last,
_RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp)
{
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__partial_sort_copy<_Comp_ref>(__first, __last, __result_first, __result_last, __comp);
+ return std::__partial_sort_copy<_ClassicAlgPolicy, _Comp_ref>(
+ __first, __last, __result_first, __result_last, __comp);
}
template <class _InputIterator, class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/pop_heap.h b/libcxx/include/__algorithm/pop_heap.h
index cadda81f6c88..e9852ddcc3f2 100644
--- a/libcxx/include/__algorithm/pop_heap.h
+++ b/libcxx/include/__algorithm/pop_heap.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/push_heap.h>
#include <__algorithm/sift_down.h>
#include <__assert>
@@ -24,7 +25,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len) {
@@ -35,17 +36,17 @@ void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Co
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
if (__len > 1) {
- value_type __top = std::move(*__first); // create a hole at __first
- _RandomAccessIterator __hole = std::__floyd_sift_down<_CompRef>(__first, __comp_ref, __len);
+ value_type __top = _IterOps<_AlgPolicy>::__iter_move(__first); // create a hole at __first
+ _RandomAccessIterator __hole = std::__floyd_sift_down<_AlgPolicy, _CompRef>(__first, __comp_ref, __len);
--__last;
if (__hole == __last) {
*__hole = std::move(__top);
} else {
- *__hole = std::move(*__last);
+ *__hole = _IterOps<_AlgPolicy>::__iter_move(__last);
++__hole;
*__last = std::move(__top);
- std::__sift_up<_CompRef>(__first, __hole, __comp_ref, __hole - __first);
+ std::__sift_up<_AlgPolicy, _CompRef>(__first, __hole, __comp_ref, __hole - __first);
}
}
}
@@ -54,7 +55,7 @@ template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __last - __first;
- std::__pop_heap(std::move(__first), std::move(__last), __comp, __len);
+ std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp, __len);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/push_heap.h b/libcxx/include/__algorithm/push_heap.h
index 1e3eec373d4f..a9aabb1dc24b 100644
--- a/libcxx/include/__algorithm/push_heap.h
+++ b/libcxx/include/__algorithm/push_heap.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
@@ -21,7 +22,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len) {
@@ -32,9 +33,9 @@ void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Com
_RandomAccessIterator __ptr = __first + __len;
if (__comp(*__ptr, *--__last)) {
- value_type __t(std::move(*__last));
+ value_type __t(_IterOps<_AlgPolicy>::__iter_move(__last));
do {
- *__last = std::move(*__ptr);
+ *__last = _IterOps<_AlgPolicy>::__iter_move(__ptr);
__last = __ptr;
if (__len == 0)
break;
@@ -47,18 +48,18 @@ void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Com
}
}
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using _CompRef = typename __comp_ref_type<_Compare>::type;
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __last - __first;
- std::__sift_up<_CompRef>(std::move(__first), std::move(__last), __comp, __len);
+ std::__sift_up<_AlgPolicy, _CompRef>(std::move(__first), std::move(__last), __comp, __len);
}
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__push_heap(std::move(__first), std::move(__last), __comp);
+ std::__push_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/ranges_fill.h b/libcxx/include/__algorithm/ranges_fill.h
index 846e31885141..7ce4a76ba9e9 100644
--- a/libcxx/include/__algorithm/ranges_fill.h
+++ b/libcxx/include/__algorithm/ranges_fill.h
@@ -30,7 +30,7 @@ struct __fn {
template <class _Type, output_iterator<const _Type&> _Iter, sentinel_for<_Iter> _Sent>
_LIBCPP_HIDE_FROM_ABI constexpr
_Iter operator()(_Iter __first, _Sent __last, const _Type& __value) const {
- if constexpr(random_access_iterator<_Iter>) {
+ if constexpr(random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>) {
return ranges::fill_n(__first, __last - __first, __value);
} else {
for (; __first != __last; ++__first)
diff --git a/libcxx/include/__algorithm/ranges_make_heap.h b/libcxx/include/__algorithm/ranges_make_heap.h
index fd488dc11a4b..8eabdd12cd2f 100644
--- a/libcxx/include/__algorithm/ranges_make_heap.h
+++ b/libcxx/include/__algorithm/ranges_make_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_heap.h>
#include <__algorithm/make_projected.h>
#include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__make_heap(std::move(__first), __last_iter, __projected_comp);
+ std::__make_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_min_element.h b/libcxx/include/__algorithm/ranges_min_element.h
index ae82dceb9ad8..26f95fe3a6d2 100644
--- a/libcxx/include/__algorithm/ranges_min_element.h
+++ b/libcxx/include/__algorithm/ranges_min_element.h
@@ -30,6 +30,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
+// TODO(ranges): `ranges::min_element` can now simply delegate to `std::__min_element`.
template <class _Ip, class _Sp, class _Proj, class _Comp>
_LIBCPP_HIDE_FROM_ABI static constexpr
_Ip __min_element_impl(_Ip __first, _Sp __last, _Comp& __comp, _Proj& __proj) {
diff --git a/libcxx/include/__algorithm/ranges_nth_element.h b/libcxx/include/__algorithm/ranges_nth_element.h
index 2a929eacb89d..b15eb816b918 100644
--- a/libcxx/include/__algorithm/ranges_nth_element.h
+++ b/libcxx/include/__algorithm/ranges_nth_element.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H
#define _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/nth_element.h>
#include <__config>
@@ -44,7 +45,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__nth_element_impl(std::move(__first), std::move(__nth), __last_iter, __projected_comp);
+ std::__nth_element_impl<_RangeAlgPolicy>(std::move(__first), std::move(__nth), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_pop_heap.h b/libcxx/include/__algorithm/ranges_pop_heap.h
index d0b8314e5b0a..92df6119d34a 100644
--- a/libcxx/include/__algorithm/ranges_pop_heap.h
+++ b/libcxx/include/__algorithm/ranges_pop_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/pop_heap.h>
#include <__concepts/same_as.h>
@@ -46,7 +47,7 @@ struct __fn {
auto __len = __last_iter - __first;
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__pop_heap(std::move(__first), __last_iter, __projected_comp, __len);
+ std::__pop_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp, __len);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_push_heap.h b/libcxx/include/__algorithm/ranges_push_heap.h
index e46ad19cfed7..4c41b00128de 100644
--- a/libcxx/include/__algorithm/ranges_push_heap.h
+++ b/libcxx/include/__algorithm/ranges_push_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/push_heap.h>
#include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__push_heap(std::move(__first), __last_iter, __projected_comp);
+ std::__push_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_sort.h b/libcxx/include/__algorithm/ranges_sort.h
index 8297940df237..ef14db64295d 100644
--- a/libcxx/include/__algorithm/ranges_sort.h
+++ b/libcxx/include/__algorithm/ranges_sort.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_SORT_H
#define _LIBCPP___ALGORITHM_RANGES_SORT_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/sort.h>
#include <__config>
@@ -44,7 +45,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__sort_impl(std::move(__first), __last_iter, __projected_comp);
+ std::__sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_sort_heap.h b/libcxx/include/__algorithm/ranges_sort_heap.h
index c753e20c44a6..eb6a30dcd3d0 100644
--- a/libcxx/include/__algorithm/ranges_sort_heap.h
+++ b/libcxx/include/__algorithm/ranges_sort_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/sort_heap.h>
#include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__sort_heap(std::move(__first), __last_iter, __projected_comp);
+ std::__sort_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_stable_sort.h b/libcxx/include/__algorithm/ranges_stable_sort.h
index 20e840426434..de48416a41be 100644
--- a/libcxx/include/__algorithm/ranges_stable_sort.h
+++ b/libcxx/include/__algorithm/ranges_stable_sort.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H
#define _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/stable_sort.h>
#include <__config>
@@ -44,7 +45,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__stable_sort_impl(std::move(__first), __last_iter, __projected_comp);
+ std::__stable_sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/shuffle.h b/libcxx/include/__algorithm/shuffle.h
index 6c6ff5675dad..077881562192 100644
--- a/libcxx/include/__algorithm/shuffle.h
+++ b/libcxx/include/__algorithm/shuffle.h
@@ -9,11 +9,13 @@
#ifndef _LIBCPP___ALGORITHM_SHUFFLE_H
#define _LIBCPP___ALGORITHM_SHUFFLE_H
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__debug>
#include <__iterator/iterator_traits.h>
#include <__random/uniform_int_distribution.h>
-#include <__utility/swap.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
#include <cstddef>
#include <cstdint>
@@ -134,10 +136,8 @@ random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
}
#endif
-template<class _RandomAccessIterator, class _UniformRandomNumberGenerator>
- void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
- _UniformRandomNumberGenerator&& __g)
-{
+template <class _AlgPolicy, class _RandomAccessIterator, class _UniformRandomNumberGenerator>
+void __shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, _UniformRandomNumberGenerator&& __g) {
typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type
diff erence_type;
typedef uniform_int_distribution<ptr
diff _t> _Dp;
typedef typename _Dp::param_type _Pp;
@@ -149,11 +149,18 @@ template<class _RandomAccessIterator, class _UniformRandomNumberGenerator>
{
diff erence_type __i = __uid(__g, _Pp(0, __d));
if (__i !=
diff erence_type(0))
- swap(*__first, *(__first + __i));
+ _IterOps<_AlgPolicy>::iter_swap(__first, __first + __i);
}
}
}
+template <class _RandomAccessIterator, class _UniformRandomNumberGenerator>
+void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ _UniformRandomNumberGenerator&& __g) {
+ std::__shuffle<_ClassicAlgPolicy>(
+ std::move(__first), std::move(__last), std::forward<_UniformRandomNumberGenerator>(__g));
+}
+
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
diff --git a/libcxx/include/__algorithm/sift_down.h b/libcxx/include/__algorithm/sift_down.h
index 0351a1c578b0..be2eb29dd53a 100644
--- a/libcxx/include/__algorithm/sift_down.h
+++ b/libcxx/include/__algorithm/sift_down.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_SIFT_DOWN_H
#define _LIBCPP___ALGORITHM_SIFT_DOWN_H
+#include <__algorithm/iterator_operations.h>
#include <__assert>
#include <__config>
#include <__iterator/iterator_traits.h>
@@ -20,12 +21,14 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 void
__sift_down(_RandomAccessIterator __first, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
_RandomAccessIterator __start)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type
diff erence_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
// left-child of __start is at 2 * __start + 1
@@ -49,11 +52,11 @@ __sift_down(_RandomAccessIterator __first, _Compare __comp,
// we are, __start is larger than its largest child
return;
- value_type __top(_VSTD::move(*__start));
+ value_type __top(_Ops::__iter_move(__start));
do
{
// we are not in heap-order, swap the parent with its largest child
- *__start = _VSTD::move(*__child_i);
+ *__start = _Ops::__iter_move(__child_i);
__start = __child_i;
if ((__len - 2) / 2 < __child)
@@ -74,7 +77,7 @@ __sift_down(_RandomAccessIterator __first, _Compare __comp,
*__start = _VSTD::move(__top);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator
__floyd_sift_down(_RandomAccessIterator __first, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len)
@@ -97,7 +100,7 @@ __floyd_sift_down(_RandomAccessIterator __first, _Compare __comp,
}
// swap __hole with its largest child
- *__hole = std::move(*__child_i);
+ *__hole = _IterOps<_AlgPolicy>::__iter_move(__child_i);
__hole = __child_i;
// if __hole is now a leaf, we're done
diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 76a18215731b..db658515b71b 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/min_element.h>
#include <__algorithm/partial_sort.h>
#include <__algorithm/unwrap_iter.h>
@@ -21,7 +22,6 @@
#include <__functional/operations.h>
#include <__functional/ranges_operations.h>
#include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
#include <climits>
#include <memory>
@@ -31,37 +31,85 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+// Wraps an algorithm policy tag and a comparator in a single struct, used to pass the policy tag around without
+// changing the number of template arguments (to keep the ABI stable). This is only used for the "range" policy tag.
+//
+// To create an object of this type, use `_WrapAlgPolicy<T, C>::type` -- see the specialization below for the rationale.
+template <class _PolicyT, class _CompT, class = void>
+struct _WrapAlgPolicy {
+ using type = _WrapAlgPolicy;
+
+ using _AlgPolicy = _PolicyT;
+ using _Comp = _CompT;
+ _Comp& __comp;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+ _WrapAlgPolicy(_Comp& __c) : __comp(__c) {}
+};
+
+// Specialization for the "classic" policy tag that avoids creating a struct and simply defines an alias for the
+// comparator. When unwrapping, a pristine comparator is always considered to have the "classic" tag attached. Passing
+// the pristine comparator where possible allows using template instantiations from the dylib.
+template <class _PolicyT, class _CompT>
+struct _WrapAlgPolicy<_PolicyT, _CompT, __enable_if_t<std::is_same<_PolicyT, _ClassicAlgPolicy>::value> > {
+ using type = _CompT;
+};
+
+// Unwraps a pristine functor (e.g. `std::less`) as if it were wrapped using `_WrapAlgPolicy`. The policy tag is always
+// set to "classic".
+template <class _CompT>
+struct _UnwrapAlgPolicy {
+ using _AlgPolicy = _ClassicAlgPolicy;
+ using _Comp = _CompT;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
+ _Comp __get_comp(_Comp __comp) { return __comp; }
+};
+
+// Unwraps a `_WrapAlgPolicy` struct.
+template <class... _Ts>
+struct _UnwrapAlgPolicy<_WrapAlgPolicy<_Ts...> > {
+ using _Wrapped = _WrapAlgPolicy<_Ts...>;
+ using _AlgPolicy = typename _Wrapped::_AlgPolicy;
+ using _Comp = typename _Wrapped::_Comp;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
+ _Comp __get_comp(_Wrapped& __w) { return __w.__comp; }
+};
+
// stable, 2-3 compares, 0-2 swaps
-template <class _Compare, class _ForwardIterator>
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 unsigned __sort3(_ForwardIterator __x, _ForwardIterator __y, _ForwardIterator __z,
_Compare __c) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
unsigned __r = 0;
if (!__c(*__y, *__x)) // if x <= y
{
if (!__c(*__z, *__y)) // if y <= z
return __r; // x <= y && y <= z
// x <= y && y > z
- swap(*__y, *__z); // x <= z && y < z
+ _Ops::iter_swap(__y, __z); // x <= z && y < z
__r = 1;
if (__c(*__y, *__x)) // if x > y
{
- swap(*__x, *__y); // x < y && y <= z
+ _Ops::iter_swap(__x, __y); // x < y && y <= z
__r = 2;
}
return __r; // x <= y && y < z
}
if (__c(*__z, *__y)) // x > y, if y > z
{
- swap(*__x, *__z); // x < y && y < z
+ _Ops::iter_swap(__x, __z); // x < y && y < z
__r = 1;
return __r;
}
- swap(*__x, *__y); // x > y && y <= z
+ _Ops::iter_swap(__x, __y); // x > y && y <= z
__r = 1; // x < y && x <= z
if (__c(*__z, *__y)) // if y > z
{
- swap(*__y, *__z); // x <= y && y < z
+ _Ops::iter_swap(__y, __z); // x <= y && y < z
__r = 2;
}
return __r;
@@ -69,18 +117,20 @@ _LIBCPP_CONSTEXPR_AFTER_CXX11 unsigned __sort3(_ForwardIterator __x, _ForwardIte
// stable, 3-6 compares, 0-5 swaps
-template <class _Compare, class _ForwardIterator>
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4,
_Compare __c) {
- unsigned __r = _VSTD::__sort3<_Compare>(__x1, __x2, __x3, __c);
+ using _Ops = _IterOps<_AlgPolicy>;
+
+ unsigned __r = std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c);
if (__c(*__x4, *__x3)) {
- swap(*__x3, *__x4);
+ _Ops::iter_swap(__x3, __x4);
++__r;
if (__c(*__x3, *__x2)) {
- swap(*__x2, *__x3);
+ _Ops::iter_swap(__x2, __x3);
++__r;
if (__c(*__x2, *__x1)) {
- swap(*__x1, *__x2);
+ _Ops::iter_swap(__x1, __x2);
++__r;
}
}
@@ -90,21 +140,28 @@ unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator
// stable, 4-10 compares, 0-9 swaps
-template <class _Compare, class _ForwardIterator>
+template <class _WrappedComp, class _ForwardIterator>
_LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3,
- _ForwardIterator __x4, _ForwardIterator __x5, _Compare __c) {
- unsigned __r = _VSTD::__sort4<_Compare>(__x1, __x2, __x3, __x4, __c);
+ _ForwardIterator __x4, _ForwardIterator __x5, _WrappedComp __wrapped_comp) {
+ using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+ using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+ using _Ops = _IterOps<_AlgPolicy>;
+
+ using _Compare = typename _Unwrap::_Comp;
+ _Compare __c = _Unwrap::__get_comp(__wrapped_comp);
+
+ unsigned __r = std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
if (__c(*__x5, *__x4)) {
- swap(*__x4, *__x5);
+ _Ops::iter_swap(__x4, __x5);
++__r;
if (__c(*__x4, *__x3)) {
- swap(*__x3, *__x4);
+ _Ops::iter_swap(__x3, __x4);
++__r;
if (__c(*__x3, *__x2)) {
- swap(*__x2, *__x3);
+ _Ops::iter_swap(__x2, __x3);
++__r;
if (__c(*__x2, *__x1)) {
- swap(*__x1, *__x2);
+ _Ops::iter_swap(__x1, __x2);
++__r;
}
}
@@ -113,6 +170,16 @@ _LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _F
return __r;
}
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
+_LIBCPP_HIDDEN unsigned __sort5_wrap_policy(
+ _ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4, _ForwardIterator __x5,
+ _Compare __c) {
+ using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
+ _WrappedComp __wrapped_comp(__c);
+ return std::__sort5<_WrappedComp>(
+ std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __wrapped_comp);
+}
+
// The comparator being simple is a prerequisite for using the branchless optimization.
template <class _Tp>
struct __is_simple_comparator : false_type {};
@@ -137,6 +204,7 @@ using __use_branchless_sort =
// Ensures that __c(*__x, *__y) is true by swapping *__x and *__y if necessary.
template <class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI void __cond_swap(_RandomAccessIterator __x, _RandomAccessIterator __y, _Compare __c) {
+ // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`).
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
bool __r = __c(*__x, *__y);
value_type __tmp = __r ? *__x : *__y;
@@ -149,6 +217,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __cond_swap(_RandomAccessIterator __x, _Random
template <class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI void __partially_sorted_swap(_RandomAccessIterator __x, _RandomAccessIterator __y,
_RandomAccessIterator __z, _Compare __c) {
+ // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`).
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
bool __r = __c(*__z, *__x);
value_type __tmp = __r ? *__z : *__x;
@@ -158,7 +227,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __partially_sorted_swap(_RandomAccessIterator
*__y = __r ? *__y : __tmp;
}
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_Compare __c) {
@@ -166,14 +235,14 @@ __sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
_VSTD::__partially_sorted_swap<_Compare>(__x1, __x2, __x3, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_Compare __c) {
- _VSTD::__sort3<_Compare>(__x1, __x2, __x3, __c);
+ std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _Compare __c) {
@@ -184,14 +253,14 @@ __sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
_VSTD::__cond_swap<_Compare>(__x2, __x3, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _Compare __c) {
- _VSTD::__sort4<_Compare>(__x1, __x2, __x3, __x4, __c);
+ std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
@@ -203,53 +272,57 @@ __sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
_VSTD::__partially_sorted_swap<_Compare>(__x2, __x3, __x4, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
- _VSTD::__sort5<_Compare>(__x1, __x2, __x3, __x4, __x5, __c);
+ std::__sort5_wrap_policy<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __x5, __c);
}
// Assumes size > 0
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 void __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
_Compare __comp) {
_BidirectionalIterator __lm1 = __last;
for (--__lm1; __first != __lm1; ++__first) {
- _BidirectionalIterator __i = _VSTD::min_element(__first, __last, __comp);
+ _BidirectionalIterator __i = std::__min_element<_Compare>(__first, __last, __comp);
if (__i != __first)
- swap(*__first, *__i);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __i);
}
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
if (__first != __last) {
_BidirectionalIterator __i = __first;
for (++__i; __i != __last; ++__i) {
_BidirectionalIterator __j = __i;
- value_type __t(_VSTD::move(*__j));
+ value_type __t(_Ops::__iter_move(__j));
for (_BidirectionalIterator __k = __i; __k != __first && __comp(__t, *--__k); --__j)
- *__j = _VSTD::move(*__k);
+ *__j = _Ops::__iter_move(__k);
*__j = _VSTD::move(__t);
}
}
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void __insertion_sort_3(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type
diff erence_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
_RandomAccessIterator __j = __first +
diff erence_type(2);
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), __j, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first +
diff erence_type(1), __j, __comp);
for (_RandomAccessIterator __i = __j +
diff erence_type(1); __i != __last; ++__i) {
if (__comp(*__i, *__j)) {
- value_type __t(_VSTD::move(*__i));
+ value_type __t(_Ops::__iter_move(__i));
_RandomAccessIterator __k = __j;
__j = __i;
do {
- *__j = _VSTD::move(*__k);
+ *__j = _Ops::__iter_move(__k);
__j = __k;
} while (__j != __first && __comp(__t, *--__k));
*__j = _VSTD::move(__t);
@@ -258,8 +331,16 @@ void __insertion_sort_3(_RandomAccessIterator __first, _RandomAccessIterator __l
}
}
-template <class _Compare, class _RandomAccessIterator>
-bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+template <class _WrappedComp, class _RandomAccessIterator>
+bool __insertion_sort_incomplete(
+ _RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
+ using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+ using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+ using _Ops = _IterOps<_AlgPolicy>;
+
+ using _Compare = typename _Unwrap::_Comp;
+ _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
+
typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type
diff erence_type;
switch (__last - __first) {
case 0:
@@ -267,32 +348,33 @@ bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIte
return true;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __last);
return true;
case 3:
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), --__last, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first +
diff erence_type(1), --__last, __comp);
return true;
case 4:
- _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), __first +
diff erence_type(2),
- --__last, __comp);
+ std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first +
diff erence_type(1), __first +
diff erence_type(2), --__last, __comp);
return true;
case 5:
- _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), __first +
diff erence_type(2),
- __first +
diff erence_type(3), --__last, __comp);
+ std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first +
diff erence_type(1), __first +
diff erence_type(2), __first +
diff erence_type(3),
+ --__last, __comp);
return true;
}
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
_RandomAccessIterator __j = __first +
diff erence_type(2);
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), __j, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first +
diff erence_type(1), __j, __comp);
const unsigned __limit = 8;
unsigned __count = 0;
for (_RandomAccessIterator __i = __j +
diff erence_type(1); __i != __last; ++__i) {
if (__comp(*__i, *__j)) {
- value_type __t(_VSTD::move(*__i));
+ value_type __t(_Ops::__iter_move(__i));
_RandomAccessIterator __k = __j;
__j = __i;
do {
- *__j = _VSTD::move(*__k);
+ *__j = _Ops::__iter_move(__k);
__j = __k;
} while (__j != __first && __comp(__t, *--__k));
*__j = _VSTD::move(__t);
@@ -304,27 +386,29 @@ bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIte
return true;
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void __insertion_sort_move(_BidirectionalIterator __first1, _BidirectionalIterator __last1,
typename iterator_traits<_BidirectionalIterator>::value_type* __first2, _Compare __comp) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
if (__first1 != __last1) {
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
value_type* __last2 = __first2;
- ::new ((void*)__last2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__last2) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
for (++__last2; ++__first1 != __last1; ++__last2) {
value_type* __j2 = __last2;
value_type* __i2 = __j2;
if (__comp(*__first1, *--__i2)) {
- ::new ((void*)__j2) value_type(_VSTD::move(*__i2));
+ ::new ((void*)__j2) value_type(std::move(*__i2));
__d.template __incr<value_type>();
for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
- *__j2 = _VSTD::move(*__i2);
- *__j2 = _VSTD::move(*__first1);
+ *__j2 = std::move(*__i2);
+ *__j2 = _Ops::__iter_move(__first1);
} else {
- ::new ((void*)__j2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__j2) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
}
}
@@ -332,9 +416,11 @@ void __insertion_sort_move(_BidirectionalIterator __first1, _BidirectionalIterat
}
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __depth) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type
diff erence_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
const
diff erence_type __limit =
@@ -348,28 +434,29 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
return;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __last);
return;
case 3:
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), --__last, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first +
diff erence_type(1), --__last, __comp);
return;
case 4:
- _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), __first +
diff erence_type(2),
- --__last, __comp);
+ std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first +
diff erence_type(1), __first +
diff erence_type(2), --__last, __comp);
return;
case 5:
- _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first +
diff erence_type(1), __first +
diff erence_type(2),
- __first +
diff erence_type(3), --__last, __comp);
+ std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first +
diff erence_type(1), __first +
diff erence_type(2), __first +
diff erence_type(3),
+ --__last, __comp);
return;
}
if (__len <= __limit) {
- _VSTD::__insertion_sort_3<_Compare>(__first, __last, __comp);
+ std::__insertion_sort_3<_AlgPolicy, _Compare>(__first, __last, __comp);
return;
}
// __len > 5
if (__depth == 0) {
// Fallback to heap sort as Introsort suggests.
- _VSTD::__partial_sort<_Compare>(__first, __last, __last, __comp);
+ std::__partial_sort<_AlgPolicy, _Compare>(__first, __last, __last, __comp);
return;
}
--__depth;
@@ -383,11 +470,12 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
__delta = __len / 2;
__m += __delta;
__delta /= 2;
- __n_swaps = _VSTD::__sort5<_Compare>(__first, __first + __delta, __m, __m + __delta, __lm1, __comp);
+ __n_swaps = std::__sort5_wrap_policy<_AlgPolicy, _Compare>(
+ __first, __first + __delta, __m, __m + __delta, __lm1, __comp);
} else {
__delta = __len / 2;
__m += __delta;
- __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, __lm1, __comp);
+ __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, __lm1, __comp);
}
}
// *__m is median
@@ -414,7 +502,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
if (__i == __j)
return; // [__first, __last) all equivalent elements
if (__comp(*__first, *__i)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
break;
@@ -432,7 +520,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
;
if (__i >= __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
}
@@ -443,7 +531,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
goto __restart;
}
if (__comp(*__j, *__m)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
break; // found guard for downward moving __j, now use unguarded partition
}
@@ -465,7 +553,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
;
if (__i > __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
// It is known that __m != __j
// If __m just moved, follow it
@@ -476,14 +564,16 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
}
// [__first, __i) < *__m and *__m <= [__i, __last)
if (__i != __m && __comp(*__m, *__i)) {
- swap(*__i, *__m);
+ _Ops::iter_swap(__i, __m);
++__n_swaps;
}
// [__first, __i) < *__i and *__i <= [__i+1, __last)
// If we were given a perfect partition, see if insertion sort is quick...
if (__n_swaps == 0) {
- bool __fs = _VSTD::__insertion_sort_incomplete<_Compare>(__first, __i, __comp);
- if (_VSTD::__insertion_sort_incomplete<_Compare>(__i +
diff erence_type(1), __last, __comp)) {
+ using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
+ _WrappedComp __wrapped_comp(__comp);
+ bool __fs = std::__insertion_sort_incomplete<_WrappedComp>(__first, __i, __wrapped_comp);
+ if (std::__insertion_sort_incomplete<_WrappedComp>(__i +
diff erence_type(1), __last, __wrapped_comp)) {
if (__fs)
return;
__last = __i;
@@ -497,10 +587,10 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
}
// sort smaller range with recursive call and larger with tail recursion elimination
if (__i - __first < __last - __i) {
- _VSTD::__introsort<_Compare>(__first, __i, __comp, __depth);
+ std::__introsort<_AlgPolicy, _Compare>(__first, __i, __comp, __depth);
__first = ++__i;
} else {
- _VSTD::__introsort<_Compare>(__i +
diff erence_type(1), __last, __comp, __depth);
+ std::__introsort<_AlgPolicy, _Compare>(__i +
diff erence_type(1), __last, __comp, __depth);
__last = __i;
}
}
@@ -525,17 +615,22 @@ inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) {
return __log2;
}
-template <class _Compare, class _RandomAccessIterator>
-void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+template <class _WrappedComp, class _RandomAccessIterator>
+void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type
diff erence_type;
diff erence_type __depth_limit = 2 * __log2i(__last - __first);
- _VSTD::__introsort<_Compare>(__first, __last, __comp, __depth_limit);
+
+ using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+ using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+ using _Compare = typename _Unwrap::_Comp;
+ _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
+ std::__introsort<_AlgPolicy, _Compare>(__first, __last, __comp, __depth_limit);
}
template <class _Compare, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY void __sort(_Tp** __first, _Tp** __last, __less<_Tp*>&) {
__less<uintptr_t> __comp;
- _VSTD::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
+ std::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
}
extern template _LIBCPP_FUNC_VIS void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
@@ -576,22 +671,27 @@ extern template _LIBCPP_FUNC_VIS bool __insertion_sort_incomplete<__less<long do
extern template _LIBCPP_FUNC_VIS unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&);
-template <class _RandomAccessIterator, class _Comp>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void __sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
- std::__debug_randomize_range(__first, __last);
+ std::__debug_randomize_range<_AlgPolicy>(__first, __last);
+
using _Comp_ref = typename __comp_ref_type<_Comp>::type;
if (__libcpp_is_constant_evaluated()) {
- std::__partial_sort<_Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
+ std::__partial_sort<_AlgPolicy, _Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
+
} else {
- std::__sort<_Comp_ref>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), _Comp_ref(__comp));
+ using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Comp_ref>::type;
+ _Comp_ref __comp_ref(__comp);
+ _WrappedComp __wrapped_comp(__comp_ref);
+ std::__sort<_WrappedComp>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __wrapped_comp);
}
}
template <class _RandomAccessIterator, class _Comp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
- std::__sort_impl(std::move(__first), std::move(__last), __comp);
+ std::__sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/sort_heap.h b/libcxx/include/__algorithm/sort_heap.h
index 261adedd0eaf..d0620eadf437 100644
--- a/libcxx/include/__algorithm/sort_heap.h
+++ b/libcxx/include/__algorithm/sort_heap.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/pop_heap.h>
#include <__config>
#include <__iterator/iterator_traits.h>
@@ -23,7 +24,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using _CompRef = typename __comp_ref_type<_Compare>::type;
@@ -31,13 +32,13 @@ void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
using
diff erence_type = typename iterator_traits<_RandomAccessIterator>::
diff erence_type;
for (
diff erence_type __n = __last - __first; __n > 1; --__last, (void) --__n)
- std::__pop_heap<_CompRef>(__first, __last, __comp_ref, __n);
+ std::__pop_heap<_AlgPolicy, _CompRef>(__first, __last, __comp_ref, __n);
}
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__sort_heap(std::move(__first), std::move(__last), __comp);
+ std::__sort_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index e3479aad62e6..6122758bdefe 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -12,11 +12,11 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__algorithm/inplace_merge.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/sort.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
-#include <__utility/swap.h>
#include <memory>
#include <type_traits>
@@ -26,12 +26,14 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _InputIterator1, class _InputIterator2>
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2>
void
__merge_move_construct(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
typename iterator_traits<_InputIterator1>::value_type* __result, _Compare __comp)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_InputIterator1>::value_type value_type;
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h(__result, __d);
@@ -40,111 +42,115 @@ __merge_move_construct(_InputIterator1 __first1, _InputIterator1 __last1,
if (__first1 == __last1)
{
for (; __first2 != __last2; ++__first2, (void) ++__result, __d.template __incr<value_type>())
- ::new ((void*)__result) value_type(_VSTD::move(*__first2));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
__h.release();
return;
}
if (__first2 == __last2)
{
for (; __first1 != __last1; ++__first1, (void) ++__result, __d.template __incr<value_type>())
- ::new ((void*)__result) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
__h.release();
return;
}
if (__comp(*__first2, *__first1))
{
- ::new ((void*)__result) value_type(_VSTD::move(*__first2));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
__d.template __incr<value_type>();
++__first2;
}
else
{
- ::new ((void*)__result) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
++__first1;
}
}
}
-template <class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
void
__merge_move_assign(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
_OutputIterator __result, _Compare __comp)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
for (; __first1 != __last1; ++__result)
{
if (__first2 == __last2)
{
for (; __first1 != __last1; ++__first1, (void) ++__result)
- *__result = _VSTD::move(*__first1);
+ *__result = _Ops::__iter_move(__first1);
return;
}
if (__comp(*__first2, *__first1))
{
- *__result = _VSTD::move(*__first2);
+ *__result = _Ops::__iter_move(__first2);
++__first2;
}
else
{
- *__result = _VSTD::move(*__first1);
+ *__result = _Ops::__iter_move(__first1);
++__first1;
}
}
for (; __first2 != __last2; ++__first2, (void) ++__result)
- *__result = _VSTD::move(*__first2);
+ *__result = _Ops::__iter_move(__first2);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __buff, ptr
diff _t __buff_size);
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void
__stable_sort_move(_RandomAccessIterator __first1, _RandomAccessIterator __last1, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __first2)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
switch (__len)
{
case 0:
return;
case 1:
- ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
return;
case 2:
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
if (__comp(*--__last1, *__first1))
{
- ::new ((void*)__first2) value_type(_VSTD::move(*__last1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
__d.template __incr<value_type>();
++__first2;
- ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
}
else
{
- ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
++__first2;
- ::new ((void*)__first2) value_type(_VSTD::move(*__last1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
}
__h2.release();
return;
}
if (__len <= 8)
{
- _VSTD::__insertion_sort_move<_Compare>(__first1, __last1, __first2, __comp);
+ std::__insertion_sort_move<_AlgPolicy, _Compare>(__first1, __last1, __first2, __comp);
return;
}
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __l2 = __len / 2;
_RandomAccessIterator __m = __first1 + __l2;
- _VSTD::__stable_sort<_Compare>(__first1, __m, __comp, __l2, __first2, __l2);
- _VSTD::__stable_sort<_Compare>(__m, __last1, __comp, __len - __l2, __first2 + __l2, __len - __l2);
- _VSTD::__merge_move_construct<_Compare>(__first1, __m, __m, __last1, __first2, __comp);
+ std::__stable_sort<_AlgPolicy, _Compare>(__first1, __m, __comp, __l2, __first2, __l2);
+ std::__stable_sort<_AlgPolicy, _Compare>(__m, __last1, __comp, __len - __l2, __first2 + __l2, __len - __l2);
+ std::__merge_move_construct<_AlgPolicy, _Compare>(__first1, __m, __m, __last1, __first2, __comp);
}
template <class _Tp>
@@ -153,7 +159,7 @@ struct __stable_sort_switch
static const unsigned value = 128*is_trivially_copy_assignable<_Tp>::value;
};
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
@@ -168,12 +174,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
return;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __last);
return;
}
if (__len <= static_cast<
diff erence_type>(__stable_sort_switch<value_type>::value))
{
- _VSTD::__insertion_sort<_Compare>(__first, __last, __comp);
+ std::__insertion_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
return;
}
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __l2 = __len / 2;
@@ -182,11 +188,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
{
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h2(__buff, __d);
- _VSTD::__stable_sort_move<_Compare>(__first, __m, __comp, __l2, __buff);
+ std::__stable_sort_move<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff);
__d.__set(__l2, (value_type*)nullptr);
- _VSTD::__stable_sort_move<_Compare>(__m, __last, __comp, __len - __l2, __buff + __l2);
+ std::__stable_sort_move<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff + __l2);
__d.__set(__len, (value_type*)nullptr);
- _VSTD::__merge_move_assign<_Compare>(__buff, __buff + __l2, __buff + __l2, __buff + __len, __first, __comp);
+ std::__merge_move_assign<_AlgPolicy, _Compare>(
+ __buff, __buff + __l2, __buff + __l2, __buff + __len, __first, __comp);
// _VSTD::__merge<_Compare>(move_iterator<value_type*>(__buff),
// move_iterator<value_type*>(__buff + __l2),
// move_iterator<_RandomAccessIterator>(__buff + __l2),
@@ -194,12 +201,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
// __first, __comp);
return;
}
- _VSTD::__stable_sort<_Compare>(__first, __m, __comp, __l2, __buff, __buff_size);
- _VSTD::__stable_sort<_Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size);
- _VSTD::__inplace_merge<_Compare>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
+ std::__stable_sort<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff, __buff_size);
+ std::__stable_sort<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size);
+ std::__inplace_merge<_AlgPolicy, _Compare>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
}
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI
void __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
@@ -217,13 +224,13 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
}
using _Comp_ref = typename __comp_ref_type<_Compare>::type;
- std::__stable_sort<_Comp_ref>(__first, __last, __comp, __len, __buf.first, __buf.second);
+ std::__stable_sort<_AlgPolicy, _Comp_ref>(__first, __last, __comp, __len, __buf.first, __buf.second);
}
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI
void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__stable_sort_impl(std::move(__first), std::move(__last), __comp);
+ std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__debug_utils/randomize_range.h b/libcxx/include/__debug_utils/randomize_range.h
index fd5b9e588493..9ed22556c416 100644
--- a/libcxx/include/__debug_utils/randomize_range.h
+++ b/libcxx/include/__debug_utils/randomize_range.h
@@ -22,7 +22,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Iterator>
+template <class _AlgPolicy, class _Iterator>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __debug_randomize_range(_Iterator __first, _Iterator __last) {
#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY
# ifdef _LIBCPP_CXX03_LANG
@@ -30,7 +30,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __debug_randomize_range
# endif
if (!__libcpp_is_constant_evaluated())
- std::shuffle(__first, __last, __libcpp_debug_randomizer());
+ std::__shuffle<_AlgPolicy>(__first, __last, __libcpp_debug_randomizer());
#else
(void)__first;
(void)__last;
diff --git a/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp b/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
index 4913a7085bf6..7124e54c2285 100644
--- a/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
@@ -34,7 +34,7 @@ std::vector<MyType> deterministic() {
for (int i = 0; i < kSize; ++i) {
v[i].value = (i % 2 ? i : kSize / 2 + i);
}
- std::__nth_element(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
+ std::__nth_element<std::_ClassicAlgPolicy>(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
return v;
}
diff --git a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
index 8aa91bd551c1..99e0b0e127e9 100644
--- a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
@@ -34,7 +34,7 @@ std::vector<MyType> deterministic() {
for (int i = 0; i < kSize; ++i) {
v[i].value = (i % 2 ? 1 : kSize / 2 + i);
}
- std::__partial_sort(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
+ std::__partial_sort<std::_ClassicAlgPolicy>(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
return v;
}
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
new file mode 100644
index 000000000000..f6eaf15862e3
--- /dev/null
+++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
@@ -0,0 +1,170 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// <algorithm>
+//
+// Range algorithms should work with proxy iterators. For example, the implementations should use `iter_swap` (which is
+// a customization point) rather than plain `swap` (which might not work with certain valid iterators).
+
+#include <algorithm>
+
+#include <array>
+#include <concepts>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <random>
+#include <ranges>
+
+#include "test_iterators.h"
+
+template <class Func, std::ranges::range Input, class ...Args>
+constexpr void test(Func&& func, Input& in, Args&& ...args) {
+ func(in.begin(), in.end(), std::forward<Args>(args)...);
+ func(in, std::forward<Args>(args)...);
+}
+
+template <class Func, std::ranges::range Range1, std::ranges::range Range2, class ...Args>
+constexpr void test(Func&& func, Range1& r1, Range2& r2, Args&& ...args) {
+ func(r1.begin(), r1.end(), r2.begin(), r2.end(), std::forward<Args>(args)...);
+ func(r1, r2, std::forward<Args>(args)...);
+}
+
+template <class Func, std::ranges::range Input, class ...Args>
+constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t<Input> mid, Args&& ...args) {
+ func(in.begin(), mid, in.end(), std::forward<Args>(args)...);
+ func(in, mid, std::forward<Args>(args)...);
+}
+
+constexpr bool test_all() {
+ std::array input = {1, 2, 3};
+ ProxyRange in{input};
+ std::array input2 = {4, 5, 6};
+ ProxyRange in2{input2};
+
+ auto mid = in.begin() + 1;
+
+ std::array output = {4, 5, 6, 7, 8, 9};
+ ProxyIterator out{output.begin()};
+ //auto out2 = output.begin() + 1;
+
+ int num = 2;
+ Proxy<int&> x{num};
+ int count = 1;
+
+ auto unary_pred = [](const Proxy<int>& val) { return val.getData() > 0; };
+ //auto binary_pred = [](const Proxy<int>& lhs, const Proxy<int>& rhs) { return lhs.getData() == rhs.getData(); };
+ auto binary_func = [](const Proxy<int>& lhs, const Proxy<int>&) -> Proxy<int> { return lhs.getData(); };
+ //auto gen = [] { return Proxy<int>(42); };
+ //std::mt19937 rand_gen;
+
+ test(std::ranges::any_of, in, unary_pred);
+ test(std::ranges::all_of, in, unary_pred);
+ test(std::ranges::none_of, in, unary_pred);
+ test(std::ranges::find, in, x);
+ test(std::ranges::find_if, in, unary_pred);
+ test(std::ranges::find_if_not, in, unary_pred);
+ test(std::ranges::find_first_of, in, in2);
+ test(std::ranges::adjacent_find, in);
+ test(std::ranges::mismatch, in, in2);
+ test(std::ranges::equal, in, in2);
+ test(std::ranges::lexicographical_compare, in, in2);
+ //test(std::ranges::partition_point, unary_pred);
+ test(std::ranges::lower_bound, in, x);
+ test(std::ranges::upper_bound, in, x);
+ //test(std::ranges::equal_range, in, x);
+ test(std::ranges::binary_search, in, x);
+
+ test(std::ranges::min_element, in);
+ test(std::ranges::max_element, in);
+ test(std::ranges::minmax_element, in);
+ test(std::ranges::count, in, x);
+ test(std::ranges::count_if, in, unary_pred);
+ test(std::ranges::search, in, in2);
+ test(std::ranges::search_n, in, count, x);
+ test(std::ranges::find_end, in, in2);
+ test(std::ranges::is_partitioned, in, unary_pred);
+ test(std::ranges::is_sorted, in);
+ test(std::ranges::is_sorted_until, in);
+ //test(std::ranges::includes, in, in2);
+ //test(std::ranges::is_heap, in);
+ //test(std::ranges::is_heap_until, in);
+ //test(std::ranges::is_permutation, in, in2);
+ test(std::ranges::for_each, in, std::identity{});
+ std::ranges::for_each_n(in.begin(), count, std::identity{});
+ test(std::ranges::copy, in, out);
+ std::ranges::copy_n(in.begin(), count, out);
+ test(std::ranges::copy_if, in, out, unary_pred);
+ // TODO: uncomment `copy_backward` once https://reviews.llvm.org/D128864 lands.
+ //test(std::ranges::copy_backward, in, out);
+ test(std::ranges::move, in, out);
+ // TODO: uncomment `move_backward` once https://reviews.llvm.org/D128864 lands.
+ // test(std::ranges::move_backward, in, out);
+ test(std::ranges::fill, in, x);
+ std::ranges::fill_n(in.begin(), count, x);
+ test(std::ranges::transform, in, out, std::identity{});
+ test(std::ranges::transform, in, in2, out, binary_func);
+ //test(std::ranges::generate, in, gen);
+ //std::ranges::generate_n(in.begin(), count, gen);
+ //test(std::ranges::remove_copy, in, out, x);
+ //test(std::ranges::remove_copy_if, in, out, unary_pred);
+ test(std::ranges::replace, in, x, x);
+ test(std::ranges::replace_if, in, unary_pred, x);
+ //test(std::ranges::replace_copy, in, out, x, x);
+ //test(std::ranges::replace_copy_if, in, out, unary_pred, x);
+ //test(std::ranges::swap_ranges, in, in2);
+ test(std::ranges::reverse_copy, in, out);
+ test_mid(std::ranges::rotate_copy, in, mid, out);
+ //test(std::ranges::sample, in, out, count, rand_gen);
+ //test(std::ranges::unique_copy, in, out);
+ //test(std::ranges::partition_copy, in, out, out2, unary_pred);
+ //test_mid(std::ranges::partial_sort_copy, in, in2);
+ test(std::ranges::merge, in, in2, out);
+ test(std::ranges::set_
diff erence, in, in2, out);
+ test(std::ranges::set_intersection, in, in2, out);
+ test(std::ranges::set_symmetric_
diff erence, in, in2, out);
+ test(std::ranges::set_union, in, in2, out);
+ test(std::ranges::remove, in, x);
+ test(std::ranges::remove_if, in, unary_pred);
+ test(std::ranges::reverse, in);
+ //test_mid(std::ranges::rotate, in, mid);
+ //test(std::ranges::shuffle, in, rand_gen);
+ //test(std::ranges::unique, in);
+ //test(std::ranges::partition, in, binary_pred);
+ //if (!std::is_constant_evaluated())
+ // test(std::ranges::stable_partition, in, binary_pred);
+ test(std::ranges::sort, in);
+ // TODO: `stable_sort` requires `ranges::rotate` to be implemented.
+ //if (!std::is_constant_evaluated())
+ // test(std::ranges::stable_sort, in);
+ //test_mid(std::ranges::partial_sort, in, mid);
+ test_mid(std::ranges::nth_element, in, mid);
+ //if (!std::is_constant_evaluated())
+ // test_mid(std::ranges::inplace_merge, in, mid);
+ test(std::ranges::make_heap, in);
+ test(std::ranges::push_heap, in);
+ test(std::ranges::pop_heap, in);
+ test(std::ranges::sort_heap, in);
+ //test(std::ranges::prev_permutation, in);
+ //test(std::ranges::next_permutation, in);
+
+ // The algorithms that work on uninitialized memory have constraints that prevent proxy iterators from being used with
+ // them.
+
+ return true;
+}
+
+int main(int, char**) {
+ test_all();
+ static_assert(test_all());
+
+ return 0;
+}
diff --git a/libcxx/test/support/test.support/test_proxy.pass.cpp b/libcxx/test/support/test.support/test_proxy.pass.cpp
index 515423a3d269..29583865deae 100644
--- a/libcxx/test/support/test.support/test_proxy.pass.cpp
+++ b/libcxx/test/support/test.support/test_proxy.pass.cpp
@@ -58,10 +58,20 @@ constexpr void testProxy() {
p4 = std::move(p3);
assert(p4.data.get() == 8);
- int i = 5, j = 6;
+ // `T` is a reference type.
+ int i = 5, j = 6, k = 7, x = 8;
Proxy<int&> p5{i};
+ // `Other` is a prvalue.
p5 = Proxy<int&>{j};
assert(p5.data == 6);
+ // `Other` is a const lvalue.
+ const Proxy<int&> p_ref{k};
+ p5 = p_ref;
+ assert(p5.data == 7);
+ // `Other` is an xvalue.
+ Proxy<int&> px{x};
+ p5 = std::move(px);
+ assert(p5.data == 8);
}
// const assignment
@@ -87,6 +97,18 @@ constexpr void testProxy() {
Proxy<int> p2{6};
assert(p1 != p2);
assert(p1 < p2);
+
+ // Comparing `T` and `T&`.
+ int i = 5, j = 6;
+ Proxy<int&> p_ref{i};
+ Proxy<const int&> p_cref{j};
+ assert(p1 == p_ref);
+ assert(p2 == p_cref);
+ assert(p_ref == p1);
+ assert(p_cref == p2);
+ assert(p_ref == p_ref);
+ assert(p_cref == p_cref);
+ assert(p_ref != p_cref);
}
}
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index c222c93c524d..2f20e50e54c2 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -827,12 +827,12 @@ class Iterator {
// ======================================================================
// Proxy that can wrap a value or a reference. It simulates C++23's tuple
// but simplified to just hold one argument.
-// Note that unlike tuple, this class deliberately doesn't have special handling
-// of swap to cause a compilation error if it's used in an algorithm that relies
+// Note that unlike tuple, this class deliberately doesn't have special handling
+// of swap to cause a compilation error if it's used in an algorithm that relies
// on plain swap instead of ranges::iter_swap.
// This class is useful for testing that if algorithms support proxy iterator
// properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of
-// plain swap and std::move
+// plain swap and std::move
template <class T>
struct Proxy;
@@ -878,17 +878,40 @@ struct Proxy {
return *this;
}
+ // If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence
+ // over the templated `operator=` above because it's a better match).
+ constexpr Proxy& operator=(const Proxy& rhs) {
+ data = rhs.data;
+ return *this;
+ }
+
// no specialised swap function that takes const Proxy& and no specialised const member swap
// Calling swap(Proxy<T>{}, Proxy<T>{}) would fail (pass prvalues)
// Compare operators are defined for the convenience of the tests
friend constexpr bool operator==(const Proxy&, const Proxy&)
- requires std::equality_comparable<T>
+ requires (std::equality_comparable<T> && !std::is_reference_v<T>)
= default;
+ // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default equality comparison operator is deleted
+ // when `T` is a reference type.
+ template <class U>
+ friend constexpr bool operator==(const Proxy& lhs, const Proxy<U>& rhs)
+ requires std::equality_comparable_with<std::decay_t<T>, std::decay_t<U>> {
+ return lhs.data == rhs.data;
+ }
+
friend constexpr auto operator<=>(const Proxy&, const Proxy&)
- requires std::three_way_comparable<T>
+ requires (std::three_way_comparable<T> && !std::is_reference_v<T>)
= default;
+
+ // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default 3-way comparison operator is deleted when
+ // `T` is a reference type.
+ template <class U>
+ friend constexpr auto operator<=>(const Proxy& lhs, const Proxy<U>& rhs)
+ requires std::three_way_comparable_with<std::decay_t<T>, std::decay_t<U>> {
+ return lhs.data <=> rhs.data;
+ }
};
// This is to make ProxyIterator model `std::indirectly_readable`
@@ -920,7 +943,7 @@ struct ProxyIteratorBase {};
template <class Base>
requires std::derived_from<
typename std::iterator_traits<Base>::iterator_category,
- std::input_iterator_tag>
+ std::input_iterator_tag>
struct ProxyIteratorBase<Base> {
using iterator_category = std::input_iterator_tag;
};
@@ -951,8 +974,8 @@ struct ProxyIterator : ProxyIteratorBase<Base> {
= default;
constexpr ProxyIterator(Base base) : base_{std::move(base)} {}
-
- template <class T>
+
+ template <class T>
requires std::constructible_from<Base, T&&>
constexpr ProxyIterator(T&& t) : base_{std::forward<T>(t)} {}
@@ -1076,6 +1099,7 @@ struct ProxyIterator : ProxyIteratorBase<Base> {
static_assert(std::indirectly_readable<ProxyIterator<int*>>);
static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int>>);
+static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int&>>);
template <class BaseSent>
struct ProxySentinel {
More information about the libcxx-commits
mailing list