[libcxx-commits] [libcxx] 5dd19ad - [libc++][ranges] Implement `ranges::partial_sort`.
Konstantin Varlamov via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 19 20:11:54 PDT 2022
Author: varconst
Date: 2022-07-19T20:10:34-07:00
New Revision: 5dd19ada571b9190811f3c4d8cd1c2bb5f56227c
URL: https://github.com/llvm/llvm-project/commit/5dd19ada571b9190811f3c4d8cd1c2bb5f56227c
DIFF: https://github.com/llvm/llvm-project/commit/5dd19ada571b9190811f3c4d8cd1c2bb5f56227c.diff
LOG: [libc++][ranges] Implement `ranges::partial_sort`.
Differential Revision: https://reviews.llvm.org/D128744
Added:
libcxx/include/__algorithm/ranges_partial_sort.h
libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp
Modified:
libcxx/docs/Status/RangesAlgorithms.csv
libcxx/include/CMakeLists.txt
libcxx/include/__algorithm/partial_sort.h
libcxx/include/__algorithm/pop_heap.h
libcxx/include/__algorithm/push_heap.h
libcxx/include/__algorithm/sort.h
libcxx/include/__algorithm/sort_heap.h
libcxx/include/algorithm
libcxx/include/module.modulemap.in
libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
libcxx/test/libcxx/private_headers.verify.cpp
libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.compile.pass.cpp
libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.compile.pass.cpp
libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv
index 3376b6a8522df..a853c414396c4 100644
--- a/libcxx/docs/Status/RangesAlgorithms.csv
+++ b/libcxx/docs/Status/RangesAlgorithms.csv
@@ -59,7 +59,7 @@ Write,rotate_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
Write,sample,Not assigned,n/a,Not started
Write,unique_copy,Not assigned,n/a,Not started
Write,partition_copy,Konstantin Varlamov,n/a,In progress
-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 <https://llvm.org/D128611>`_,✅
Merge,set_
diff erence,Hui Xie,`D128983 <https://llvm.org/D128983>`_,✅
Merge,set_intersection,Hui Xie,`D129233 <https://llvm.org/D129233>`_,✅
@@ -75,8 +75,8 @@ Permutation,partition,Konstantin Varlamov,`D129624 <https://llvm.org/D129624>`_,
Permutation,stable_partition,Konstantin Varlamov,`D129624 <https://llvm.org/D129624>`_,✅
Permutation,sort,Konstantin Varlamov,`D127557 <https://llvm.org/D127557>`_,✅
Permutation,stable_sort,Konstantin Varlamov,`D127834 <https://llvm.org/D127834>`_,✅
-Permutation,partial_sort,Konstantin Varlamov,n/a,In progress
Permutation,nth_element,Konstantin Varlamov,`D128149 <https://llvm.org/D128149>`_,✅
+Permutation,partial_sort,Konstantin Varlamov,`D128744 <https://llvm.org/D128744>`_,✅
Permutation,inplace_merge,Not assigned,n/a,Not started
Permutation,make_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
Permutation,push_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 0193f6162cf72..a1c5a791a4ca9 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -114,6 +114,7 @@ set(files
__algorithm/ranges_move_backward.h
__algorithm/ranges_none_of.h
__algorithm/ranges_nth_element.h
+ __algorithm/ranges_partial_sort.h
__algorithm/ranges_partial_sort_copy.h
__algorithm/ranges_partition.h
__algorithm/ranges_partition_copy.h
diff --git a/libcxx/include/__algorithm/partial_sort.h b/libcxx/include/__algorithm/partial_sort.h
index 2c2468fc09acd..cb6887e39bfdd 100644
--- a/libcxx/include/__algorithm/partial_sort.h
+++ b/libcxx/include/__algorithm/partial_sort.h
@@ -19,6 +19,8 @@
#include <__debug>
#include <__debug_utils/randomize_range.h>
#include <__iterator/iterator_traits.h>
+#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -26,24 +28,55 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 void
-__partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
- _Compare __comp)
-{
- if (__first == __middle)
- return;
- std::__make_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
- typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __middle - __first;
- for (_RandomAccessIterator __i = __middle; __i != __last; ++__i)
- {
- if (__comp(*__i, *__first))
- {
- _IterOps<_AlgPolicy>::iter_swap(__i, __first);
- std::__sift_down<_AlgPolicy, _Compare>(__first, __comp, __len, __first);
- }
- }
- std::__sort_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator, class _Sentinel>
+_LIBCPP_CONSTEXPR_AFTER_CXX17
+_RandomAccessIterator __partial_sort_impl(
+ _RandomAccessIterator __first, _RandomAccessIterator __middle, _Sentinel __last, _Compare __comp) {
+ if (__first == __middle) {
+ return _IterOps<_AlgPolicy>::next(__middle, __last);
+ }
+
+ std::__make_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
+
+ typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __middle - __first;
+ _RandomAccessIterator __i = __middle;
+ for (; __i != __last; ++__i)
+ {
+ if (__comp(*__i, *__first))
+ {
+ _IterOps<_AlgPolicy>::iter_swap(__i, __first);
+ std::__sift_down<_AlgPolicy, _Compare>(__first, __comp, __len, __first);
+ }
+
+ }
+ std::__sort_heap<_AlgPolicy, _Compare>(std::move(__first), std::move(__middle), __comp);
+
+ return __i;
+}
+
+// TODO(ranges): once `ranges::shuffle` is implemented, remove this helper and make `__debug_randomize_range` support
+// sentinels.
+template <class _AlgPolicy, class _RandomAccessIterator, class _Sentinel>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
+void __maybe_randomize(_RandomAccessIterator __first, _Sentinel __last) {
+ std::__debug_randomize_range<_AlgPolicy>(__first, _IterOps<_AlgPolicy>::next(__first, __last));
+}
+
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator, class _Sentinel>
+_LIBCPP_CONSTEXPR_AFTER_CXX17
+_RandomAccessIterator __partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Sentinel __last,
+ _Compare& __comp) {
+ if (__first == __middle)
+ return _IterOps<_AlgPolicy>::next(__middle, __last);
+
+ std::__maybe_randomize<_AlgPolicy>(__first, __last);
+
+ using _Comp_ref = typename __comp_ref_type<_Compare>::type;
+ auto __last_iter = std::__partial_sort_impl<_AlgPolicy, _Comp_ref>(__first, __middle, __last, __comp);
+
+ std::__maybe_randomize<_AlgPolicy>(__middle, __last);
+
+ return __last_iter;
}
template <class _RandomAccessIterator, class _Compare>
@@ -52,10 +85,10 @@ void
partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
_Compare __comp)
{
- std::__debug_randomize_range<_ClassicAlgPolicy>(__first, __last);
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- std::__partial_sort<_ClassicAlgPolicy, _Comp_ref>(__first, __middle, __last, __comp);
- std::__debug_randomize_range<_ClassicAlgPolicy>(__middle, __last);
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
+ (void)std::__partial_sort<_ClassicAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/pop_heap.h b/libcxx/include/__algorithm/pop_heap.h
index e9852ddcc3f27..870af50c133e4 100644
--- a/libcxx/include/__algorithm/pop_heap.h
+++ b/libcxx/include/__algorithm/pop_heap.h
@@ -18,6 +18,7 @@
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -54,6 +55,9 @@ void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Co
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __last - __first;
std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp, __len);
}
diff --git a/libcxx/include/__algorithm/push_heap.h b/libcxx/include/__algorithm/push_heap.h
index a9aabb1dc24bd..716670b767887 100644
--- a/libcxx/include/__algorithm/push_heap.h
+++ b/libcxx/include/__algorithm/push_heap.h
@@ -15,6 +15,7 @@
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -59,6 +60,9 @@ void __push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
std::__push_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
diff --git a/libcxx/include/__algorithm/ranges_partial_sort.h b/libcxx/include/__algorithm/ranges_partial_sort.h
new file mode 100644
index 0000000000000..5e82bc6fcc325
--- /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 <class _Iter, class _Sent, class _Comp, class _Proj>
+ _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<_RangeAlgPolicy>(std::move(__first), std::move(__middle), __last, __projected_comp);
+ }
+
+ template <random_access_iterator _Iter, sentinel_for<_Iter> _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 <random_access_range _Range, class _Comp = ranges::less, class _Proj = identity>
+ requires sortable<iterator_t<_Range>, _Comp, _Proj>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ borrowed_iterator_t<_Range> operator()(_Range&& __r, iterator_t<_Range> __middle, _Comp __comp = {},
+ _Proj __proj = {}) const {
+ return __partial_sort_fn_impl(ranges::begin(__r), std::move(__middle), ranges::end(__r), __comp, __proj);
+ }
+};
+
+} // 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/sort.h b/libcxx/include/__algorithm/sort.h
index db658515b71bd..1ca2f1b81712a 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -678,7 +678,7 @@ void __sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
using _Comp_ref = typename __comp_ref_type<_Comp>::type;
if (__libcpp_is_constant_evaluated()) {
- std::__partial_sort<_AlgPolicy, _Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
+ std::__partial_sort<_AlgPolicy>(__first, __last, __last, __comp);
} else {
using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Comp_ref>::type;
diff --git a/libcxx/include/__algorithm/sort_heap.h b/libcxx/include/__algorithm/sort_heap.h
index d0620eadf4378..b9f0b2c9690d2 100644
--- a/libcxx/include/__algorithm/sort_heap.h
+++ b/libcxx/include/__algorithm/sort_heap.h
@@ -16,7 +16,7 @@
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
-#include <type_traits> // swap
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -38,6 +38,9 @@ void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
std::__sort_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index cc2c468c2976e..71d507adac25c 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -360,6 +360,17 @@ namespace ranges {
borrowed_iterator_t<R>
ranges::stable_sort(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
+ template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
+ class Proj = identity>
+ requires sortable<I, Comp, Proj>
+ constexpr I
+ ranges::partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {}); // since C++20
+
+ template<random_access_range R, class Comp = ranges::less, class Proj = identity>
+ requires sortable<iterator_t<R>, Comp, Proj>
+ constexpr borrowed_iterator_t<R>
+ ranges::partial_sort(R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {}); // since C++20
+
template<class T, output_iterator<const T&> O, sentinel_for<O> S>
constexpr O ranges::fill(O first, S last, const T& value); // since C++20
@@ -1518,6 +1529,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_move_backward.h>
#include <__algorithm/ranges_none_of.h>
#include <__algorithm/ranges_nth_element.h>
+#include <__algorithm/ranges_partial_sort.h>
#include <__algorithm/ranges_partition.h>
#include <__algorithm/ranges_pop_heap.h>
#include <__algorithm/ranges_push_heap.h>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 91ac0d2c753d7..9114e78d78054 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -353,6 +353,7 @@ module std [system] {
module ranges_move_backward { private header "__algorithm/ranges_move_backward.h" }
module ranges_none_of { private header "__algorithm/ranges_none_of.h" }
module ranges_nth_element { private header "__algorithm/ranges_nth_element.h" }
+ module ranges_partial_sort { private header "__algorithm/ranges_partial_sort.h" }
module ranges_partial_sort_copy { private header "__algorithm/ranges_partial_sort_copy.h" }
module ranges_partition { private header "__algorithm/ranges_partition.h" }
module ranges_partition_copy { private header "__algorithm/ranges_partition_copy.h" }
diff --git a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
index 99e0b0e127e92..3f9a5a0bd7708 100644
--- a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
@@ -34,7 +34,8 @@ std::vector<MyType> deterministic() {
for (int i = 0; i < kSize; ++i) {
v[i].value = (i % 2 ? 1 : kSize / 2 + i);
}
- std::__partial_sort<std::_ClassicAlgPolicy>(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
+ auto comp = std::less<MyType>();
+ std::__partial_sort_impl<std::_ClassicAlgPolicy>(v.begin(), v.begin() + kSize / 2, v.end(), comp);
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
index d980ba32efc0c..07450d29541e5 100644
--- 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 @@ constexpr bool all_the_algorithms()
(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
index 0a5758699e4a3..f29eb72d1946f 100644
--- 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 @@ constexpr bool all_the_algorithms()
(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
index dfed6560a7d3d..7afc3e879150f 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -151,6 +151,7 @@ END-SCRIPT
#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_nth_element.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_nth_element.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_partial_sort_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_partial_sort_copy.h'}}
#include <__algorithm/ranges_partition.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_partition.h'}}
#include <__algorithm/ranges_partition_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_partition_copy.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
index 0000000000000..f07bf918cf7f9
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp
@@ -0,0 +1,213 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// <algorithm>
+
+// template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
+// class Proj = identity>
+// requires sortable<I, Comp, Proj>
+// constexpr I
+// ranges::partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {}); // since C++20
+//
+// template<random_access_range R, class Comp = ranges::less, class Proj = identity>
+// requires sortable<iterator_t<R>, Comp, Proj>
+// constexpr borrowed_iterator_t<R>
+// ranges::partial_sort(R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {}); // since C++20
+
+#include <algorithm>
+#include <array>
+#include <concepts>
+#include <functional>
+#include <ranges>
+
+#include "almost_satisfies_types.h"
+#include "boolean_testable.h"
+#include "test_iterators.h"
+
+// SFINAE tests.
+
+using BadComparator = ComparatorNotCopyable<int*>;
+static_assert(!std::sortable<int*, BadComparator>);
+
+template <class Iter, class Sent = sentinel_wrapper<Iter>, 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<int*>);
+static_assert(!HasPartialSortIt<RandomAccessIteratorNotDerivedFrom>);
+static_assert(!HasPartialSortIt<RandomAccessIteratorBadIndex>);
+static_assert(!HasPartialSortIt<int*, SentinelForNotSemiregular>);
+static_assert(!HasPartialSortIt<int*, SentinelForNotWeaklyEqualityComparableWith>);
+static_assert(!HasPartialSortIt<int*, int*, BadComparator>);
+static_assert(!HasPartialSortIt<const int*>); // Doesn't satisfy `sortable`.
+
+template <class Range, class Comp = std::ranges::less>
+concept HasPartialSortR = requires(Range range, std::ranges::iterator_t<Range> mid, Comp comp) {
+ std::ranges::partial_sort(range, mid, comp);
+};
+
+static_assert(HasPartialSortR<UncheckedRange<int*>>);
+static_assert(!HasPartialSortR<RandomAccessRangeNotDerivedFrom>);
+static_assert(!HasPartialSortR<RandomAccessRangeBadIndex>);
+static_assert(!HasPartialSortR<UncheckedRange<int*, SentinelForNotSemiregular>>);
+static_assert(!HasPartialSortR<UncheckedRange<int*, SentinelForNotWeaklyEqualityComparableWith>>);
+static_assert(!HasPartialSortR<UncheckedRange<int*>, BadComparator>);
+static_assert(!HasPartialSortR<UncheckedRange<const int*>>); // Doesn't satisfy `sortable`.
+
+template <class Iter, class Sent, size_t N>
+constexpr void test_one(std::array<int, N> input, size_t mid_index, std::array<int, N> sorted) {
+ { // (iterator, sentinel) overload.
+ auto partially_sorted = input;
+ auto begin = Iter(partially_sorted.data());
+ auto mid = begin + mid_index;
+ auto end = Sent(Iter(partially_sorted.data() + partially_sorted.size()));
+
+ std::same_as<Iter> decltype(auto) last = std::ranges::partial_sort(begin, mid, end);
+ 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 begin = Iter(partially_sorted.data());
+ auto mid = begin + mid_index;
+ auto end = Sent(Iter(partially_sorted.data() + partially_sorted.size()));
+ auto range = std::ranges::subrange(begin, end);
+
+ std::same_as<Iter> decltype(auto) last = std::ranges::partial_sort(range, mid);
+ assert(std::ranges::equal(begin, begin + mid_index, sorted.begin(), sorted.begin() + mid_index));
+ assert(base(last) == partially_sorted.data() + partially_sorted.size());
+ }
+}
+
+template <class Iter, class Sent, size_t N>
+constexpr void test_all_subsequences(std::array<int, N> input) {
+ auto sorted = input;
+ std::sort(sorted.begin(), sorted.end());
+
+ for (size_t n = 0; n <= N; ++n) {
+ test_one<Iter, Sent, N>(input, n, sorted);
+ }
+}
+
+template <class Iter, class Sent>
+constexpr void test_iterator_and_sentinel() {
+ // Empty sequence.
+ test_one<Iter, Sent, 0>({}, 0, {});
+
+ // 1-element sequence.
+ test_all_subsequences<Iter, Sent>(std::array{1});
+
+ // 2-element sequence.
+ test_all_subsequences<Iter, Sent>(std::array{2, 1});
+
+ // 3-element sequence.
+ test_all_subsequences<Iter, Sent>(std::array{2, 1, 3});
+
+ // Longer sequence.
+ test_all_subsequences<Iter, Sent>(std::array{2, 1, 3, 6, 8, 4, 11, 5});
+
+ // Longer sequence with duplicates.
+ test_all_subsequences<Iter, Sent>(std::array{2, 1, 3, 6, 2, 8, 6});
+
+ // All elements are the same.
+ test_all_subsequences<Iter, Sent>(std::array{1, 1, 1});
+
+ // Already sorted.
+ test_all_subsequences<Iter, Sent>(std::array{1, 2, 3, 4, 5});
+
+ // Descending.
+ test_all_subsequences<Iter, Sent>(std::array{5, 4, 3, 2, 1});
+
+ // Repeating pattern.
+ test_all_subsequences<Iter, Sent>(std::array{1, 2, 1, 2, 1, 2});
+}
+
+constexpr void test_iterators() {
+ test_iterator_and_sentinel<random_access_iterator<int*>, random_access_iterator<int*>>();
+ test_iterator_and_sentinel<random_access_iterator<int*>, sentinel_wrapper<random_access_iterator<int*>>>();
+ test_iterator_and_sentinel<contiguous_iterator<int*>, contiguous_iterator<int*>>();
+ test_iterator_and_sentinel<contiguous_iterator<int*>, sentinel_wrapper<contiguous_iterator<int*>>>();
+ test_iterator_and_sentinel<int*, int*>();
+ test_iterator_and_sentinel<int*, sentinel_wrapper<int*>>();
+}
+
+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());
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.compile.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.compile.pass.cpp
index 439a16b103cec..183ea9a8aa94c 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.compile.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.compile.pass.cpp
@@ -160,7 +160,7 @@ void test_all() {
in_pred(std::ranges::stable_partition, in, unary_pred);
in_pred(std::ranges::sort, in, binary_pred);
in_pred(std::ranges::stable_sort, in, binary_pred);
- //in_mid_pred(std::ranges::partial_sort, in, mid, binary_pred);
+ in_mid_pred(std::ranges::partial_sort, in, mid, binary_pred);
in_mid_pred(std::ranges::nth_element, in, mid, binary_pred);
//in_mid_pred(std::ranges::inplace_merge, in, mid, binary_pred);
in_pred(std::ranges::make_heap, in, binary_pred);
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.compile.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.compile.pass.cpp
index 7709b88536bbd..616bb774cf121 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.compile.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.compile.pass.cpp
@@ -205,7 +205,7 @@ void test_all() {
in_pred(std::ranges::stable_partition, in, &Foo::unary_pred, &Bar::val);
in_pred(std::ranges::sort, in, &Foo::binary_pred, &Bar::val);
in_pred(std::ranges::stable_sort, in, &Foo::binary_pred, &Bar::val);
- //in_mid_pred(std::ranges::partial_sort, in, mid, binary_pred);
+ in_mid_pred(std::ranges::partial_sort, in, mid, &Foo::binary_pred, &Bar::val);
in_mid_pred(std::ranges::nth_element, in, mid, &Foo::binary_pred, &Bar::val);
//in_mid_pred(std::ranges::inplace_merge, in, mid, binary_pred);
in_pred(std::ranges::make_heap, in, &Foo::binary_pred, &Bar::val);
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
index 253087ee4cd73..0b2c463b097f2 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
@@ -156,7 +156,7 @@ constexpr void run_tests() {
// TODO(ranges): `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::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);
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
index 84fec22ca9d63..077fe65ccc855 100644
--- 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
@@ -110,7 +110,7 @@ static_assert(test(std::ranges::move_backward, a, a));
//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));
More information about the libcxx-commits
mailing list