diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h --- 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 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -53,7 +53,7 @@ bool operator()(const _T1& __x, const _T2& __y) {return __p_(__y, __x);} }; -template void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, @@ -63,25 +63,26 @@ { 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 +template void __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp, typename iterator_traits<_BidirectionalIterator>::difference_type __len1, @@ -95,30 +96,32 @@ { value_type* __p = __buff; for (_BidirectionalIterator __i = __first; __i != __middle; __d.template __incr(), (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(), (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 _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 +template void __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp, typename iterator_traits<_BidirectionalIterator>::difference_type __len1, typename iterator_traits<_BidirectionalIterator>::difference_type __len2, typename iterator_traits<_BidirectionalIterator>::value_type* __buff, ptrdiff_t __buff_size) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type; while (true) { @@ -126,7 +129,7 @@ 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 @@ { // __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); } difference_type __len12 = __len1 - __len11; // distance(__m1, __middle) difference_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 @@ } 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_POP unique_ptr __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 --- a/libcxx/include/__algorithm/iterator_operations.h +++ b/libcxx/include/__algorithm/iterator_operations.h @@ -41,6 +41,7 @@ static constexpr auto next = ranges::next; static constexpr auto __advance_to = ranges::advance; }; + #endif struct _ClassicAlgPolicy {}; @@ -85,7 +86,8 @@ } template - _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 --- 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 +template 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 @@ if (__n > 1) { // start from the first parent, there is no need to consider children for (difference_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 @@ template 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 diff --git a/libcxx/include/__algorithm/min_element.h b/libcxx/include/__algorithm/min_element.h --- 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 -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 +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 +_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 _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 diff --git a/libcxx/include/__algorithm/nth_element.h b/libcxx/include/__algorithm/nth_element.h --- 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 @@ } } -template +template _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>::difference_type difference_type; const difference_type __limit = 7; @@ -60,24 +62,24 @@ 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 @@ { // *__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 @@ 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 @@ ; if (__i >= __j) break; - swap(*__i, *__j); + _Ops::iter_swap(__i, __j); ++__n_swaps; ++__i; } @@ -152,7 +154,7 @@ ; 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 @@ // [__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 @@ } } -template +template 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 @@ 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 diff --git a/libcxx/include/__algorithm/partial_sort.h b/libcxx/include/__algorithm/partial_sort.h --- 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 +template _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>::difference_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 @@ -52,10 +52,10 @@ 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 diff --git a/libcxx/include/__algorithm/partial_sort_copy.h b/libcxx/include/__algorithm/partial_sort_copy.h --- 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 +template _LIBCPP_CONSTEXPR_AFTER_CXX17 _RandomAccessIterator __partial_sort_copy(_InputIterator __first, _InputIterator __last, _RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp) @@ -33,15 +34,15 @@ { 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>::difference_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 @@ _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 diff --git a/libcxx/include/__algorithm/pop_heap.h b/libcxx/include/__algorithm/pop_heap.h --- 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 +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len) { @@ -35,17 +36,17 @@ 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 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { typename iterator_traits<_RandomAccessIterator>::difference_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 diff --git a/libcxx/include/__algorithm/push_heap.h b/libcxx/include/__algorithm/push_heap.h --- 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 +template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len) { @@ -32,9 +33,9 @@ _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 @@ } } -template +template 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>::difference_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 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 diff --git a/libcxx/include/__algorithm/ranges_fill.h b/libcxx/include/__algorithm/ranges_fill.h --- a/libcxx/include/__algorithm/ranges_fill.h +++ b/libcxx/include/__algorithm/ranges_fill.h @@ -30,7 +30,7 @@ template _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 --- 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 @@ 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 --- a/libcxx/include/__algorithm/ranges_min_element.h +++ b/libcxx/include/__algorithm/ranges_min_element.h @@ -30,6 +30,7 @@ namespace ranges { +// TODO(ranges): `ranges::min_element` can now simply delegate to `std::__min_element`. template _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 --- 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 --- 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 #include @@ -134,10 +136,8 @@ } #endif -template - void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, - _UniformRandomNumberGenerator&& __g) -{ +template +void __shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, _UniformRandomNumberGenerator&& __g) { typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef uniform_int_distribution _Dp; typedef typename _Dp::param_type _Pp; @@ -149,11 +149,18 @@ { difference_type __i = __uid(__g, _Pp(0, __d)); if (__i != difference_type(0)) - swap(*__first, *(__first + __i)); + _IterOps<_AlgPolicy>::iter_swap(__first, __first + __i); } } } +template +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 --- 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 +template _LIBCPP_CONSTEXPR_AFTER_CXX11 void __sift_down(_RandomAccessIterator __first, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len, _RandomAccessIterator __start) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; // left-child of __start is at 2 * __start + 1 @@ -49,11 +52,11 @@ // 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 @@ *__start = _VSTD::move(__top); } -template +template _LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator __floyd_sift_down(_RandomAccessIterator __first, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len) @@ -97,7 +100,7 @@ } // 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 --- 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 #include @@ -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::type` -- see the specialization below for the rationale. +template +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 +struct _WrapAlgPolicy<_PolicyT, _CompT, __enable_if_t::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 +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 +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 +template _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 @@ // stable, 3-6 compares, 0-5 swaps -template +template 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 @@ // stable, 4-10 compares, 0-9 swaps -template +template _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 @@ return __r; } +template +_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 struct __is_simple_comparator : false_type {}; @@ -137,6 +204,7 @@ // Ensures that __c(*__x, *__y) is true by swapping *__x and *__y if necessary. template 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 @@ template 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 @@ *__y = __r ? *__y : __tmp; } -template +template 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 @@ _VSTD::__partially_sorted_swap<_Compare>(__x1, __x2, __x3, __c); } -template +template inline _LIBCPP_HIDE_FROM_ABI __enable_if_t::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 +template 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 @@ _VSTD::__cond_swap<_Compare>(__x2, __x3, __c); } -template +template inline _LIBCPP_HIDE_FROM_ABI __enable_if_t::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 +template 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 @@ _VSTD::__partially_sorted_swap<_Compare>(__x2, __x3, __x4, __c); } -template +template inline _LIBCPP_HIDE_FROM_ABI __enable_if_t::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 +template _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 +template 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 +template void __insertion_sort_3(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; _RandomAccessIterator __j = __first + difference_type(2); - _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + difference_type(1), __j, __comp); + std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), __j, __comp); for (_RandomAccessIterator __i = __j + difference_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 @@ } } -template -bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { +template +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>::difference_type difference_type; switch (__last - __first) { case 0: @@ -267,32 +348,33 @@ 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 + difference_type(1), --__last, __comp); + std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), --__last, __comp); return true; case 4: - _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2), - --__last, __comp); + std::__sort4_maybe_branchless<_AlgPolicy, _Compare>( + __first, __first + difference_type(1), __first + difference_type(2), --__last, __comp); return true; case 5: - _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2), - __first + difference_type(3), --__last, __comp); + std::__sort5_maybe_branchless<_AlgPolicy, _Compare>( + __first, __first + difference_type(1), __first + difference_type(2), __first + difference_type(3), + --__last, __comp); return true; } typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; _RandomAccessIterator __j = __first + difference_type(2); - _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + difference_type(1), __j, __comp); + std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), __j, __comp); const unsigned __limit = 8; unsigned __count = 0; for (_RandomAccessIterator __i = __j + difference_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 @@ return true; } -template +template 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 __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(); 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(); 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(); } } @@ -332,9 +416,11 @@ } } -template +template void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __depth) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; const difference_type __limit = @@ -348,28 +434,29 @@ 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 + difference_type(1), --__last, __comp); + std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), --__last, __comp); return; case 4: - _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2), - --__last, __comp); + std::__sort4_maybe_branchless<_AlgPolicy, _Compare>( + __first, __first + difference_type(1), __first + difference_type(2), --__last, __comp); return; case 5: - _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2), - __first + difference_type(3), --__last, __comp); + std::__sort5_maybe_branchless<_AlgPolicy, _Compare>( + __first, __first + difference_type(1), __first + difference_type(2), __first + difference_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 @@ __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 @@ 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 @@ ; if (__i >= __j) break; - swap(*__i, *__j); + _Ops::iter_swap(__i, __j); ++__n_swaps; ++__i; } @@ -443,7 +531,7 @@ 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 @@ ; 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 @@ } // [__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 + difference_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 + difference_type(1), __last, __wrapped_comp)) { if (__fs) return; __last = __i; @@ -497,10 +587,10 @@ } // 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 + difference_type(1), __last, __comp, __depth); + std::__introsort<_AlgPolicy, _Compare>(__i + difference_type(1), __last, __comp, __depth); __last = __i; } } @@ -525,17 +615,22 @@ return __log2; } -template -void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { +template +void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) { typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; difference_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 inline _LIBCPP_INLINE_VISIBILITY void __sort(_Tp** __first, _Tp** __last, __less<_Tp*>&) { __less __comp; - _VSTD::__sort<__less&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp); + std::__sort<__less&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp); } extern template _LIBCPP_FUNC_VIS void __sort<__less&, char*>(char*, char*, __less&); @@ -576,22 +671,27 @@ extern template _LIBCPP_FUNC_VIS unsigned __sort5<__less&, long double*>(long double*, long double*, long double*, long double*, long double*, __less&); -template +template 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 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 diff --git a/libcxx/include/__algorithm/sort_heap.h b/libcxx/include/__algorithm/sort_heap.h --- 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 +template 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 @@ using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; for (difference_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 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 diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h --- 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 #include @@ -26,12 +26,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template +template 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 __h(__result, __d); @@ -40,111 +42,115 @@ if (__first1 == __last1) { for (; __first2 != __last2; ++__first2, (void) ++__result, __d.template __incr()) - ::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()) - ::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(); ++__first2; } else { - ::new ((void*)__result) value_type(_VSTD::move(*__first1)); + ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); __d.template __incr(); ++__first1; } } } -template +template 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 +template void __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len, typename iterator_traits<_RandomAccessIterator>::value_type* __buff, ptrdiff_t __buff_size); -template +template void __stable_sort_move(_RandomAccessIterator __first1, _RandomAccessIterator __last1, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_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 __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(); ++__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(); ++__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>::difference_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 @@ -153,7 +159,7 @@ static const unsigned value = 128*is_trivially_copy_assignable<_Tp>::value; }; -template +template void __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len, @@ -168,12 +174,12 @@ return; case 2: if (__comp(*--__last, *__first)) - swap(*__first, *__last); + _IterOps<_AlgPolicy>::iter_swap(__first, __last); return; } if (__len <= static_cast(__stable_sort_switch::value)) { - _VSTD::__insertion_sort<_Compare>(__first, __last, __comp); + std::__insertion_sort<_AlgPolicy, _Compare>(__first, __last, __comp); return; } typename iterator_traits<_RandomAccessIterator>::difference_type __l2 = __len / 2; @@ -182,11 +188,12 @@ { __destruct_n __d(0); unique_ptr __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(__buff), // move_iterator(__buff + __l2), // move_iterator<_RandomAccessIterator>(__buff + __l2), @@ -194,12 +201,12 @@ // __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 +template 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 @@ } 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 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 diff --git a/libcxx/include/__debug_utils/randomize_range.h b/libcxx/include/__debug_utils/randomize_range.h --- 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 +template _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 @@ # 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 --- a/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp +++ b/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp @@ -34,7 +34,7 @@ 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()); + std::__nth_element(v.begin(), v.begin() + kSize / 2, v.end(), std::less()); return v; } diff --git a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp --- a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp +++ b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp @@ -34,7 +34,7 @@ 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()); + std::__partial_sort(v.begin(), v.begin() + kSize / 2, v.end(), std::less()); 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 --- /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 + +// +// +// 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 + +#include +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" + +template +constexpr void test(Func&& func, Input& in, Args&& ...args) { + func(in.begin(), in.end(), std::forward(args)...); + func(in, std::forward(args)...); +} + +template +constexpr void test(Func&& func, Range1& r1, Range2& r2, Args&& ...args) { + func(r1.begin(), r1.end(), r2.begin(), r2.end(), std::forward(args)...); + func(r1, r2, std::forward(args)...); +} + +template +constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t mid, Args&& ...args) { + func(in.begin(), mid, in.end(), std::forward(args)...); + func(in, mid, std::forward(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 x{num}; + int count = 1; + + auto unary_pred = [](const Proxy& val) { return val.getData() > 0; }; + //auto binary_pred = [](const Proxy& lhs, const Proxy& rhs) { return lhs.getData() == rhs.getData(); }; + auto binary_func = [](const Proxy& lhs, const Proxy&) -> Proxy { return lhs.getData(); }; + //auto gen = [] { return Proxy(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_difference, in, in2, out); + test(std::ranges::set_intersection, in, in2, out); + test(std::ranges::set_symmetric_difference, 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 --- a/libcxx/test/support/test.support/test_proxy.pass.cpp +++ b/libcxx/test/support/test.support/test_proxy.pass.cpp @@ -58,10 +58,20 @@ 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 p5{i}; + // `Other` is a prvalue. p5 = Proxy{j}; assert(p5.data == 6); + // `Other` is a const lvalue. + const Proxy p_ref{k}; + p5 = p_ref; + assert(p5.data == 7); + // `Other` is an xvalue. + Proxy px{x}; + p5 = std::move(px); + assert(p5.data == 8); } // const assignment @@ -87,6 +97,18 @@ Proxy p2{6}; assert(p1 != p2); assert(p1 < p2); + + // Comparing `T` and `T&`. + int i = 5, j = 6; + Proxy p_ref{i}; + Proxy 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 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -827,12 +827,12 @@ // ====================================================================== // 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 struct Proxy; @@ -878,17 +878,40 @@ 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{}, Proxy{}) 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 + requires (std::equality_comparable && !std::is_reference_v) = default; + // Helps compare e.g. `Proxy` and `Proxy`. Note that the default equality comparison operator is deleted + // when `T` is a reference type. + template + friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) + requires std::equality_comparable_with, std::decay_t> { + return lhs.data == rhs.data; + } + friend constexpr auto operator<=>(const Proxy&, const Proxy&) - requires std::three_way_comparable + requires (std::three_way_comparable && !std::is_reference_v) = default; + + // Helps compare e.g. `Proxy` and `Proxy`. Note that the default 3-way comparison operator is deleted when + // `T` is a reference type. + template + friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) + requires std::three_way_comparable_with, std::decay_t> { + return lhs.data <=> rhs.data; + } }; // This is to make ProxyIterator model `std::indirectly_readable` @@ -920,7 +943,7 @@ template requires std::derived_from< typename std::iterator_traits::iterator_category, - std::input_iterator_tag> + std::input_iterator_tag> struct ProxyIteratorBase { using iterator_category = std::input_iterator_tag; }; @@ -951,8 +974,8 @@ = default; constexpr ProxyIterator(Base base) : base_{std::move(base)} {} - - template + + template requires std::constructible_from constexpr ProxyIterator(T&& t) : base_{std::forward(t)} {} @@ -1076,6 +1099,7 @@ static_assert(std::indirectly_readable>); static_assert(std::indirectly_writable, Proxy>); +static_assert(std::indirectly_writable, Proxy>); template struct ProxySentinel {