diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -59,7 +59,7 @@ Write,sample,Not assigned,n/a,Not started Write,unique_copy,Not assigned,n/a,Not started Write,partition_copy,Not assigned,n/a,Not started -Write,partial_sort_copy,Not assigned,n/a,Not started +Write,partial_sort_copy,Konstantin Varlamov,n/a,In progress Merge,merge,Hui Xie,`D128611 `_,✅ Merge,set_difference,Hui Xie,n/a,Not started Merge,set_intersection,Hui Xie,n/a,Not started @@ -75,7 +75,7 @@ Permutation,stable_partition,Not assigned,n/a,Not started Permutation,sort,Konstantin Varlamov,`D127557 `_,✅ Permutation,stable_sort,Konstantin Varlamov,`D127834 `_,✅ -Permutation,partial_sort,Konstantin Varlamov,n/a,In progress +Permutation,partial_sort,Konstantin Varlamov,`D128744 `_,✅ Permutation,nth_element,Not assigned,n/a,Not started Permutation,inplace_merge,Not assigned,n/a,Not started Permutation,make_heap,Not assigned,n/a,Not started diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -103,6 +103,7 @@ __algorithm/ranges_move.h __algorithm/ranges_move_backward.h __algorithm/ranges_none_of.h + __algorithm/ranges_partial_sort.h __algorithm/ranges_remove.h __algorithm/ranges_remove_if.h __algorithm/ranges_replace.h diff --git a/libcxx/include/__algorithm/equal_range.h b/libcxx/include/__algorithm/equal_range.h --- a/libcxx/include/__algorithm/equal_range.h +++ b/libcxx/include/__algorithm/equal_range.h @@ -55,7 +55,7 @@ _ForwardIterator __mp1 = __m; return pair<_ForwardIterator, _ForwardIterator> ( - _VSTD::__lower_bound_impl<_StdIterOps>(__first, __m, __value_, __comp, __proj), + _VSTD::__lower_bound_impl<_STLClassicAlgorithms>(__first, __m, __value_, __comp, __proj), _VSTD::__upper_bound<_Compare>(++__mp1, __last, __value_, __comp) ); } 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 @@ -6,13 +6,19 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___ALGORIHTM_ITERATOR_OPERATIONS_H -#define _LIBCPP___ALGORIHTM_ITERATOR_OPERATIONS_H +#ifndef _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H +#define _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H +#include <__algorithm/iter_swap.h> #include <__config> #include <__iterator/advance.h> #include <__iterator/distance.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> #include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__utility/forward.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -20,28 +26,63 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template struct _IterOps; + #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) -struct _RangesIterOps { +struct _RangesAlgorithms {}; + +template <> +struct _IterOps<_RangesAlgorithms> { static constexpr auto advance = ranges::advance; static constexpr auto distance = ranges::distance; + static constexpr auto iter_move = ranges::iter_move; + static constexpr auto iter_swap = ranges::iter_swap; + static constexpr auto next = ranges::next; }; #endif -struct _StdIterOps { +struct _STLClassicAlgorithms {}; - template - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11 void advance(_Iterator& __iter, _Distance __count) { - return std::advance(__iter, __count); +template <> +struct _IterOps<_STLClassicAlgorithms> { + + // advance + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 + static void advance(_Iter& __iter, _Distance __count) { + std::advance(__iter, __count); } - template - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11 - typename iterator_traits<_Iterator>::difference_type distance(_Iterator __first, _Iterator __last) { + // distance + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 + static typename iterator_traits<_Iter>::difference_type distance(_Iter __first, _Iter __last) { return std::distance(__first, __last); } + // iter_move + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 + // Declaring the return type is necessary for the C++03 mode (which doesn't support placeholder return types). + static typename iterator_traits::type>::value_type&& iter_move(_Iter&& __i) { + return std::move(*std::forward<_Iter>(__i)); + } + + // iter_swap + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 + static void iter_swap(_Iter1&& __a, _Iter2&& __b) { + std::iter_swap(std::forward<_Iter1>(__a), std::forward<_Iter2>(__b)); + } + + // next + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 + static _Iter next(const _Iter& __first, const _Iter& __last) { + return std::next(__first, std::distance(__first, __last)); + } }; _LIBCPP_END_NAMESPACE_STD -#endif // _LIBCPP___ALGORIHTM_ITERATOR_OPERATIONS_H +#endif // _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H diff --git a/libcxx/include/__algorithm/lower_bound.h b/libcxx/include/__algorithm/lower_bound.h --- a/libcxx/include/__algorithm/lower_bound.h +++ b/libcxx/include/__algorithm/lower_bound.h @@ -27,15 +27,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template +template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter __lower_bound_impl(_Iter __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { - auto __len = _IterOps::distance(__first, __last); + auto __len = _IterOps<_Tag>::distance(__first, __last); while (__len != 0) { auto __l2 = std::__half_positive(__len); _Iter __m = __first; - _IterOps::advance(__m, __l2); + _IterOps<_Tag>::advance(__m, __l2); if (std::__invoke(__comp, std::__invoke(__proj, *__m), __value)) { __first = ++__m; __len -= __l2 + 1; @@ -52,7 +52,7 @@ static_assert(__is_callable<_Compare, decltype(*__first), const _Tp&>::value, "The comparator has to be callable"); auto __proj = std::__identity(); - return std::__lower_bound_impl<_StdIterOps>(__first, __last, __value_, __comp, __proj); + return std::__lower_bound_impl<_STLClassicAlgorithms>(__first, __last, __value_, __comp, __proj); } template 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,9 +11,11 @@ #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> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -21,7 +23,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template +template _LIBCPP_CONSTEXPR_AFTER_CXX11 void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { @@ -32,7 +34,7 @@ // start from the first parent, there is no need to consider children for (difference_type __start = (__n - 2) / 2; __start >= 0; --__start) { - _VSTD::__sift_down<_Compare>(__first, __comp, __n, __first + __start); + std::__sift_down<_Tag, _Compare>(__first, __comp, __n, __first + __start); } } } @@ -43,7 +45,7 @@ make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { typedef typename __comp_ref_type<_Compare>::type _Comp_ref; - _VSTD::__make_heap<_Comp_ref>(__first, __last, __comp); + std::__make_heap<_STLClassicAlgorithms, _Comp_ref>(std::move(__first), 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,6 +19,8 @@ #include <__debug> #include <__debug_utils/randomize_range.h> #include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__utility/move.h> #include <__utility/swap.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -26,24 +29,51 @@ _LIBCPP_BEGIN_NAMESPACE_STD -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); +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +_RandomAccessIterator __partial_sort_impl( + _RandomAccessIterator __first, _RandomAccessIterator __middle, _Sentinel __last, _Compare __comp) { + if (__first == __middle) { + return _IterOps<_Tag>::next(__middle, __last); + } + + std::__make_heap<_Tag, _Compare>(__first, __middle, __comp); + typename iterator_traits<_RandomAccessIterator>::difference_type __len = __middle - __first; - for (_RandomAccessIterator __i = __middle; __i != __last; ++__i) - { + _RandomAccessIterator __i = __middle; + for (; __i != __last; ++__i) { if (__comp(*__i, *__first)) { - swap(*__i, *__first); - _VSTD::__sift_down<_Compare>(__first, __comp, __len, __first); + _IterOps<_Tag>::iter_swap(__i, __first); + std::__sift_down<_Tag, _Compare>(__first, __comp, __len, __first); } } - _VSTD::__sort_heap<_Compare>(__first, __middle, __comp); + std::__sort_heap<_Tag, _Compare>(std::move(__first), std::move(__middle), __comp); + + return __i; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +void __maybe_randomize(_RandomAccessIterator __first, _Sentinel __last) { + std::__debug_randomize_range(__first, _IterOps<_Tag>::next(__first, __last)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +_RandomAccessIterator __partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, + _Sentinel __last, _Compare& __comp) { + if (__first == __middle) + return _IterOps<_Tag>::next(__middle, __last); + + std::__maybe_randomize<_Tag>(__first, __last); + + using _Comp_ref = typename __comp_ref_type<_Compare>::type; + auto __last_iter = std::__partial_sort_impl<_Tag, _Comp_ref>(std::move(__first), __middle, __last, __comp); + + std::__maybe_randomize<_Tag>(__middle, __last); + + return __last_iter; } template @@ -52,10 +82,7 @@ partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _Compare __comp) { - std::__debug_randomize_range(__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); + (void)std::__partial_sort<_STLClassicAlgorithms>(std::move(__first), std::move(__middle), std::move(__last), __comp); } template @@ -63,8 +90,8 @@ void partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) { - _VSTD::partial_sort(__first, __middle, __last, - __less::value_type>()); + std::partial_sort(std::move(__first), std::move(__middle), std::move(__last), + __less::value_type>()); } _LIBCPP_END_NAMESPACE_STD 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> @@ -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<_STLClassicAlgorithms, _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<_STLClassicAlgorithms, _Compare>(__result_first, __comp, __len, __result_first); } - _VSTD::__sort_heap<_Compare>(__result_first, __r, __comp); + std::__sort_heap<_STLClassicAlgorithms, _Compare>(__result_first, __r, __comp); } return __r; } 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 <__config> @@ -23,7 +24,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template +template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, @@ -33,16 +34,16 @@ if (__len > 1) { - value_type __top = std::move(*__first); // create a hole at __first - _RandomAccessIterator __hole = std::__floyd_sift_down<_Compare>(__first, __comp, __len); + value_type __top = _IterOps<_Tag>::iter_move(__first); // create a hole at __first + _RandomAccessIterator __hole = std::__floyd_sift_down<_Tag, _Compare>(__first, __comp, __len); --__last; if (__hole == __last) { *__hole = std::move(__top); } else { - *__hole = std::move(*__last); + *__hole = _IterOps<_Tag>::iter_move(__last); ++__hole; *__last = std::move(__top); - std::__sift_up<_Compare>(__first, __hole, __comp, __hole - __first); + std::__sift_up<_Tag, _Compare>(__first, __hole, __comp, __hole - __first); } } } @@ -53,7 +54,7 @@ pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { typedef typename __comp_ref_type<_Compare>::type _Comp_ref; - _VSTD::__pop_heap<_Comp_ref>(__first, __last, __comp, __last - __first); + std::__pop_heap<_STLClassicAlgorithms, _Comp_ref>(std::move(__first), std::move(__last), __comp, __last - __first); } 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_CONSTEXPR_AFTER_CXX11 void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len) @@ -33,10 +34,10 @@ _RandomAccessIterator __ptr = __first + __len; if (__comp(*__ptr, *--__last)) { - value_type __t(_VSTD::move(*__last)); + value_type __t(_IterOps<_Tag>::iter_move(__last)); do { - *__last = _VSTD::move(*__ptr); + *__last = _IterOps<_Tag>::iter_move(__ptr); __last = __ptr; if (__len == 0) break; @@ -54,7 +55,7 @@ push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { typedef typename __comp_ref_type<_Compare>::type _Comp_ref; - _VSTD::__sift_up<_Comp_ref>(__first, __last, __comp, __last - __first); + std::__sift_up<_STLClassicAlgorithms, _Comp_ref>(std::move(__first), std::move(__last), __comp, __last - __first); } template diff --git a/libcxx/include/__algorithm/ranges_binary_search.h b/libcxx/include/__algorithm/ranges_binary_search.h --- a/libcxx/include/__algorithm/ranges_binary_search.h +++ b/libcxx/include/__algorithm/ranges_binary_search.h @@ -35,7 +35,7 @@ indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { - auto __ret = std::__lower_bound_impl<_RangesIterOps>(__first, __last, __value, __comp, __proj); + auto __ret = std::__lower_bound_impl<_RangesAlgorithms>(__first, __last, __value, __comp, __proj); return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__first)); } @@ -45,7 +45,7 @@ bool operator()(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { auto __first = ranges::begin(__r); auto __last = ranges::end(__r); - auto __ret = std::__lower_bound_impl<_RangesIterOps>(__first, __last, __value, __comp, __proj); + auto __ret = std::__lower_bound_impl<_RangesAlgorithms>(__first, __last, __value, __comp, __proj); return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__first)); } }; diff --git a/libcxx/include/__algorithm/ranges_lower_bound.h b/libcxx/include/__algorithm/ranges_lower_bound.h --- a/libcxx/include/__algorithm/ranges_lower_bound.h +++ b/libcxx/include/__algorithm/ranges_lower_bound.h @@ -39,7 +39,7 @@ indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { - return std::__lower_bound_impl<_RangesIterOps>(__first, __last, __value, __comp, __proj); + return std::__lower_bound_impl<_RangesAlgorithms>(__first, __last, __value, __comp, __proj); } template (ranges::begin(__r), ranges::end(__r), __value, __comp, __proj); + return std::__lower_bound_impl<_RangesAlgorithms>(ranges::begin(__r), ranges::end(__r), __value, __comp, __proj); } }; } // namespace __lower_bound diff --git a/libcxx/include/__algorithm/ranges_partial_sort.h b/libcxx/include/__algorithm/ranges_partial_sort.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_partial_sort.h @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H +#define _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/partial_sort.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __partial_sort { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static + _Iter __partial_sort_fn_impl(_Iter __first, _Iter __middle, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj); + return std::__partial_sort<_RangesAlgorithms>(std::move(__first), std::move(__middle), __last, __projected_comp); + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr + _Iter operator()(_Iter __first, _Iter __middle, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __partial_sort_fn_impl(std::move(__first), std::move(__middle), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr + borrowed_iterator_t<_Range> operator()(_Range&& __r, iterator_t<_Range> __middle, _Comp __comp = {}, + _Proj __proj = {}) const { + return __partial_sort_fn_impl(ranges::begin(__r), std::move(__middle), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __partial_sort + +inline namespace __cpo { + inline constexpr auto partial_sort = __partial_sort::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +#endif // _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H diff --git a/libcxx/include/__algorithm/ranges_upper_bound.h b/libcxx/include/__algorithm/ranges_upper_bound.h --- a/libcxx/include/__algorithm/ranges_upper_bound.h +++ b/libcxx/include/__algorithm/ranges_upper_bound.h @@ -40,7 +40,7 @@ return !std::invoke(__comp, __rhs, __lhs); }; - return std::__lower_bound_impl<_RangesIterOps>(__first, __last, __value, __comp_lhs_rhs_swapped, __proj); + return std::__lower_bound_impl<_RangesAlgorithms>(__first, __last, __value, __comp_lhs_rhs_swapped, __proj); } template (ranges::begin(__r), + return std::__lower_bound_impl<_RangesAlgorithms>(ranges::begin(__r), ranges::end(__r), __value, __comp_lhs_rhs_swapped, 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,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template +template _LIBCPP_CONSTEXPR_AFTER_CXX11 void __sift_down(_RandomAccessIterator __first, _Compare __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len, @@ -49,11 +50,11 @@ // we are, __start is larger than its largest child return; - value_type __top(_VSTD::move(*__start)); + value_type __top(_IterOps<_Tag>::iter_move(__start)); do { // we are not in heap-order, swap the parent with its largest child - *__start = _VSTD::move(*__child_i); + *__start = _IterOps<_Tag>::iter_move(__child_i); __start = __child_i; if ((__len - 2) / 2 < __child) @@ -74,7 +75,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 +98,7 @@ } // swap __hole with its largest child - *__hole = std::move(*__child_i); + *__hole = _IterOps<_Tag>::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> @@ -369,7 +370,7 @@ // __len > 5 if (__depth == 0) { // Fallback to heap sort as Introsort suggests. - _VSTD::__partial_sort<_Compare>(__first, __last, __last, __comp); + std::__partial_sort_impl<_STLClassicAlgorithms, _Compare>(__first, __last, __last, __comp); return; } --__depth; @@ -582,7 +583,7 @@ std::__debug_randomize_range(__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_impl<_STLClassicAlgorithms, _Comp_ref>(__first, __last, __last, _Comp_ref(__comp)); } else { std::__sort<_Comp_ref>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), _Comp_ref(__comp)); } 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,9 +11,11 @@ #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> +#include <__utility/move.h> #include // swap #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -22,13 +24,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template +template _LIBCPP_CONSTEXPR_AFTER_CXX17 void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; for (difference_type __n = __last - __first; __n > 1; --__last, (void) --__n) - _VSTD::__pop_heap<_Compare>(__first, __last, __comp, __n); + std::__pop_heap<_Tag, _Compare>(__first, __last, __comp, __n); } template @@ -37,7 +39,7 @@ sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { typedef typename __comp_ref_type<_Compare>::type _Comp_ref; - _VSTD::__sort_heap<_Comp_ref>(__first, __last, __comp); + std::__sort_heap<_STLClassicAlgorithms, _Comp_ref>(std::move(__first), std::move(__last), __comp); } template diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -316,6 +316,17 @@ borrowed_iterator_t ranges::stable_sort(R&& r, Comp comp = {}, Proj proj = {}); // since C++20 + template S, class Comp = ranges::less, + class Proj = identity> + requires sortable + constexpr I + ranges::partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {}); // since C++20 + + template + requires sortable, Comp, Proj> + constexpr borrowed_iterator_t + ranges::partial_sort(R&& r, iterator_t middle, Comp comp = {}, Proj proj = {}); // since C++20 + template O, sentinel_for S> constexpr O ranges::fill(O first, S last, const T& value); // since C++20 @@ -1295,6 +1306,7 @@ #include <__algorithm/ranges_move.h> #include <__algorithm/ranges_move_backward.h> #include <__algorithm/ranges_none_of.h> +#include <__algorithm/ranges_partial_sort.h> #include <__algorithm/ranges_remove.h> #include <__algorithm/ranges_remove_if.h> #include <__algorithm/ranges_replace.h> diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -342,6 +342,7 @@ module ranges_move { private header "__algorithm/ranges_move.h" } module ranges_move_backward { private header "__algorithm/ranges_move_backward.h" } module ranges_none_of { private header "__algorithm/ranges_none_of.h" } + module ranges_partial_sort { private header "__algorithm/ranges_partial_sort.h" } module ranges_remove { private header "__algorithm/ranges_remove.h" } module ranges_remove_if { private header "__algorithm/ranges_remove_if.h" } module ranges_replace { private header "__algorithm/ranges_replace.h" } 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_impl(v.begin(), v.begin() + kSize / 2, v.end(), std::less()); return v; } diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp --- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp +++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp @@ -171,8 +171,8 @@ (void)std::ranges::none_of(a, UnaryTrue(&copies)); assert(copies == 0); //(void)std::ranges::nth_element(first, mid, last, Less(&copies)); assert(copies == 0); //(void)std::ranges::nth_element(a, mid, Less(&copies)); assert(copies == 0); - //(void)std::ranges::partial_sort(first, mid, last, Less(&copies)); assert(copies == 0); - //(void)std::ranges::partial_sort(a, mid, Less(&copies)); assert(copies == 0); + (void)std::ranges::partial_sort(first, mid, last, Less(&copies)); assert(copies == 0); + (void)std::ranges::partial_sort(a, mid, Less(&copies)); assert(copies == 0); //(void)std::ranges::partial_sort_copy(first, last, first2, mid2, Less(&copies)); assert(copies == 0); //(void)std::ranges::partial_sort_copy(a, b, Less(&copies)); assert(copies == 0); //(void)std::ranges::partition(first, last, UnaryTrue(&copies)); assert(copies == 0); diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp --- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp +++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp @@ -154,8 +154,8 @@ (void)std::ranges::none_of(a, UnaryTrue(), Proj(&copies)); assert(copies == 0); //(void)std::ranges::nth_element(first, mid, last, Less(), Proj(&copies)); assert(copies == 0); //(void)std::ranges::nth_element(a, mid, Less(), Proj(&copies)); assert(copies == 0); - //(void)std::ranges::partial_sort(first, mid, last, Less(), Proj(&copies)); assert(copies == 0); - //(void)std::ranges::partial_sort(a, mid, Less(), Proj(&copies)); assert(copies == 0); + (void)std::ranges::partial_sort(first, mid, last, Less(), Proj(&copies)); assert(copies == 0); + (void)std::ranges::partial_sort(a, mid, Less(), Proj(&copies)); assert(copies == 0); //(void)std::ranges::partial_sort_copy(first, last, first2, mid2, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0); //(void)std::ranges::partial_sort_copy(a, b, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0); //(void)std::ranges::partition(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0); diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -140,6 +140,7 @@ #include <__algorithm/ranges_move.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_move.h'}} #include <__algorithm/ranges_move_backward.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_move_backward.h'}} #include <__algorithm/ranges_none_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_none_of.h'}} +#include <__algorithm/ranges_partial_sort.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_partial_sort.h'}} #include <__algorithm/ranges_remove.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_remove.h'}} #include <__algorithm/ranges_remove_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_remove_if.h'}} #include <__algorithm/ranges_replace.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_replace.h'}} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp @@ -0,0 +1,290 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template S, class Comp = ranges::less, +// class Proj = identity> +// requires sortable +// constexpr I +// ranges::partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {}); // since C++20 +// +// template +// requires sortable, Comp, Proj> +// constexpr borrowed_iterator_t +// ranges::partial_sort(R&& r, iterator_t middle, Comp comp = {}, Proj proj = {}); // since C++20 + +#include +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +// SFINAE tests. + +using BadComparator = ComparatorNotCopyable; +static_assert(!std::sortable); + +template , class Comp = std::ranges::less> +concept HasPartialSortIt = requires(Iter first, Iter mid, Sent last, Comp comp) { + std::ranges::partial_sort(first, mid, last, comp); +}; + +static_assert(HasPartialSortIt); +static_assert(!HasPartialSortIt); +static_assert(!HasPartialSortIt); +static_assert(!HasPartialSortIt); +static_assert(!HasPartialSortIt); +static_assert(!HasPartialSortIt); +static_assert(!HasPartialSortIt); // Doesn't satisfy `sortable`. + +template +concept HasPartialSortR = requires(Range range, std::ranges::iterator_t mid, Comp comp) { + std::ranges::partial_sort(range, mid, comp); +}; + +static_assert(HasPartialSortR>); +static_assert(!HasPartialSortR); +static_assert(!HasPartialSortR); +static_assert(!HasPartialSortR>); +static_assert(!HasPartialSortR>); +static_assert(!HasPartialSortR, BadComparator>); +static_assert(!HasPartialSortR>); // Doesn't satisfy `sortable`. + +template +constexpr void test_one(std::array input, size_t mid_index, std::array sorted) { + { // (iterator, sentinel) overload. + auto partially_sorted = input; + auto b = Iter(partially_sorted.data()); + auto m = b + mid_index; + auto e = Sent(Iter(partially_sorted.data() + partially_sorted.size())); + + std::same_as decltype(auto) last = std::ranges::partial_sort(b, m, e); + assert(std::equal(partially_sorted.begin(), partially_sorted.begin() + mid_index, + sorted.begin(), sorted.begin() + mid_index)); + assert(base(last) == partially_sorted.data() + partially_sorted.size()); + } + + { // (range) overload. + auto partially_sorted = input; + auto b = Iter(partially_sorted.data()); + auto m = b + mid_index; + auto e = Sent(Iter(partially_sorted.data() + partially_sorted.size())); + auto range = std::ranges::subrange(b, e); + + std::same_as decltype(auto) last = std::ranges::partial_sort(range, m); + assert(std::equal(partially_sorted.begin(), partially_sorted.begin() + mid_index, + sorted.begin(), sorted.begin() + mid_index)); + assert(base(last) == partially_sorted.data() + partially_sorted.size()); + } +} + +template +constexpr void test_all_subsequences(std::array input) { + auto sorted = input; + std::sort(sorted.begin(), sorted.end()); + + for (size_t n = 0; n <= N; ++n) { + test_one(input, n, sorted); + } +} + +constexpr void test_iterators() { + auto check = [] { + // Empty sequence. + test_one({}, 0, {}); + + // 1-element sequence. + test_all_subsequences(std::array{1}); + + // 2-element sequence. + test_all_subsequences(std::array{2, 1}); + + // 3-element sequence. + test_all_subsequences(std::array{2, 1, 3}); + + // Longer sequence. + test_all_subsequences(std::array{2, 1, 3, 6, 8, 4, 11, 5}); + + // Longer sequence with duplicates. + test_all_subsequences(std::array{2, 1, 3, 6, 2, 8, 6}); + + // All elements are the same. + test_all_subsequences(std::array{1, 1, 1}); + + // Already sorted. + test_all_subsequences(std::array{1, 2, 3, 4, 5}); + + // Descending. + test_all_subsequences(std::array{5, 4, 3, 2, 1}); + + // Repeating pattern. + test_all_subsequences(std::array{1, 2, 1, 2, 1, 2}); + }; + + check.operator(), random_access_iterator>(); + check.operator(), sentinel_wrapper>>(); + check.operator(), contiguous_iterator>(); + check.operator(), sentinel_wrapper>>(); + check.operator()(); + check.operator()>(); +} + +constexpr bool test() { + test_iterators(); + + { // A custom comparator works. + const std::array orig_in = {1, 2, 3, 4, 5}; + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(b, m, in.end(), std::ranges::greater{}); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{5, 4} + )); + assert(last == in.end()); + } + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(in, m, std::ranges::greater{}); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{5, 4} + )); + assert(last == in.end()); + } + } + + { // A custom projection works. + struct A { + int a; + constexpr bool operator==(const A&) const = default; + }; + + const std::array orig_in = {A{2}, A{3}, A{1}}; + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(b, m, in.end(), {}, &A::a); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{A{1}, A{2}} + )); + assert(last == in.end()); + } + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(in, m, {}, &A::a); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{A{1}, A{2}} + )); + assert(last == in.end()); + } + } + + { // `std::invoke` is used in the implementation. + struct S { + int i; + constexpr S(int i_) : i(i_) {} + + constexpr bool comparator(const S& rhs) const { return i < rhs.i; } + constexpr const S& projection() const { return *this; } + + constexpr bool operator==(const S&) const = default; + }; + + const std::array orig_in = {S{2}, S{3}, S{1}}; + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(b, m, in.end(), &S::comparator, &S::projection); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{S{1}, S{2}} + )); + assert(last == in.end()); + } + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(in, m, &S::comparator, &S::projection); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{S{1}, S{2}} + )); + assert(last == in.end()); + } + } + + { // The comparator can return any type that's convertible to `bool`. + const std::array orig_in = {2, 1, 3}; + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(b, m, in.end(), + [](int i, int j) { return BooleanTestable{i < j}; }); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{1, 2} + )); + assert(last == in.end()); + } + + { + auto in = orig_in; + auto b = in.begin(); + auto m = b + 2; + + auto last = std::ranges::partial_sort(in, m, + [](int i, int j) { return BooleanTestable{i < j}; }); + assert(std::ranges::equal( + std::ranges::subrange(b, m), std::array{1, 2} + )); + assert(last == in.end()); + } + } + + { // `std::ranges::dangling` is returned. + static_assert(std::same_as(), nullptr))>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp --- a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp +++ b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp @@ -109,7 +109,7 @@ //static_assert(test(std::ranges::next_permutation, a)); static_assert(test(std::ranges::none_of, a, odd)); //static_assert(test(std::ranges::nth_element, a, a+5)); -//static_assert(test(std::ranges::partial_sort, a, a+5)); +static_assert(test(std::ranges::partial_sort, a, a+5)); //static_assert(test(std::ranges::partial_sort_copy, a, a)); //static_assert(test(std::ranges::partition, a, odd)); //static_assert(test(std::ranges::partition_copy, a, a, a, odd));