[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