[libc++][ranges] Implement `ranges::partial_sort`.

Differential Revision: https://reviews.llvm.org/D128744
This commit is contained in:
varconst 2022-07-19 20:10:02 -07:00 committed by Konstantin Varlamov
parent c35807f271
commit 5dd19ada57
19 changed files with 385 additions and 35 deletions

View File

@ -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_difference,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>`_,✅

1 Category Algorithm Assignee CL Complete
59 Write sample Not assigned n/a Not started
60 Write unique_copy Not assigned n/a Not started
61 Write partition_copy Konstantin Varlamov n/a In progress
62 Write partial_sort_copy Not assigned Konstantin Varlamov n/a Not started In progress
63 Merge merge Hui Xie `D128611 <https://llvm.org/D128611>`_
64 Merge set_difference Hui Xie `D128983 <https://llvm.org/D128983>`_
65 Merge set_intersection Hui Xie `D129233 <https://llvm.org/D129233>`_
75 Permutation stable_partition Konstantin Varlamov `D129624 <https://llvm.org/D129624>`_
76 Permutation sort Konstantin Varlamov `D127557 <https://llvm.org/D127557>`_
77 Permutation stable_sort Konstantin Varlamov `D127834 <https://llvm.org/D127834>`_
Permutation partial_sort Konstantin Varlamov n/a In progress
78 Permutation nth_element Konstantin Varlamov `D128149 <https://llvm.org/D128149>`_
79 Permutation partial_sort Konstantin Varlamov `D128744 <https://llvm.org/D128744>`_
80 Permutation inplace_merge Not assigned n/a Not started
81 Permutation make_heap Konstantin Varlamov `D128115 <https://llvm.org/D128115>`_
82 Permutation push_heap Konstantin Varlamov `D128115 <https://llvm.org/D128115>`_

View File

@ -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

View File

@ -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>::difference_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>::difference_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>

View File

@ -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>::difference_type __len = __last - __first;
std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp, __len);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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>

View File

@ -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" }

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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'}}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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));