forked from OSchip/llvm-project
[libc++][ranges] Implement `ranges::partial_sort`.
Differential Revision: https://reviews.llvm.org/D128744
This commit is contained in:
parent
c35807f271
commit
5dd19ada57
|
@ -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>`_,✅
|
||||
|
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue