mirror of
https://github.com/intel/llvm.git
synced 2026-02-05 13:21:04 +08:00
[libc++][ranges] Implement ranges::{,stable_}partition.
Differential Revision: https://reviews.llvm.org/D129624
This commit is contained in:
@@ -10,7 +10,7 @@ Search,adjacent_find,Nikolas Klauser,`D126610 <https://llvm.org/D126610>`_,✅
|
||||
Search,mismatch,Nikolas Klauser,`D117817 <https://llvm.org/D117817>`_,✅
|
||||
Search,equal,Nikolas Klauser,`D123681 <https://llvm.org/D123681>`_,✅
|
||||
Search,lexicographical_compare,Nikolas Klauser,`D127130 <https://llvm.org/D127130>`_,✅
|
||||
Search,partition_point,Christopher Di Bella,`D105794 <https://llvm.org/D105794>`_,Under review
|
||||
Search,partition_point,Konstantin Varlamov,n/a,In progress
|
||||
Search,lower_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
|
||||
Search,upper_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
|
||||
Search,equal_range,Christopher Di Bella,n/a,Not started
|
||||
@@ -58,7 +58,7 @@ Write,reverse_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
|
||||
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,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
|
||||
Merge,merge,Hui Xie,`D128611 <https://llvm.org/D128611>`_,✅
|
||||
Merge,set_difference,Hui Xie,`D128983 <https://llvm.org/D128983>`_,✅
|
||||
@@ -71,8 +71,8 @@ Permutation,reverse,Nikolas Klauser,`D125752 <https://llvm.org/D125752>`_,✅
|
||||
Permutation,rotate,Nikolas Klauser,`D124122 <https://llvm.org/D124122>`_,Under review
|
||||
Permutation,shuffle,Not assigned,n/a,Not started
|
||||
Permutation,unique,Not assigned,n/a,Not started
|
||||
Permutation,partition,Not assigned,n/a,Not started
|
||||
Permutation,stable_partition,Not assigned,n/a,Not started
|
||||
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
|
||||
|
||||
|
@@ -98,6 +98,7 @@ set(files
|
||||
__algorithm/ranges_is_partitioned.h
|
||||
__algorithm/ranges_is_sorted.h
|
||||
__algorithm/ranges_is_sorted_until.h
|
||||
__algorithm/ranges_iterator_concept.h
|
||||
__algorithm/ranges_lexicographical_compare.h
|
||||
__algorithm/ranges_lower_bound.h
|
||||
__algorithm/ranges_make_heap.h
|
||||
|
||||
@@ -85,6 +85,13 @@ struct _IterOps<_ClassicAlgPolicy> {
|
||||
return __last;
|
||||
}
|
||||
|
||||
template <class _Iter>
|
||||
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||
__uncvref_t<_Iter> next(_Iter&& __it,
|
||||
typename iterator_traits<__uncvref_t<_Iter> >::difference_type __n = 1){
|
||||
return std::next(std::forward<_Iter>(__it), __n);
|
||||
}
|
||||
|
||||
template <class _Iter>
|
||||
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||
void __advance_to(_Iter& __first, _Iter __last) {
|
||||
|
||||
@@ -27,6 +27,21 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
namespace ranges {
|
||||
|
||||
template <class _Pred, class _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr static
|
||||
decltype(auto) __make_projected_pred(_Pred& __pred, _Proj& __proj) {
|
||||
if constexpr (same_as<decay_t<_Proj>, identity> && !is_member_pointer_v<decay_t<_Pred>>) {
|
||||
// Avoid creating the lambda and just use the pristine predicate -- for certain algorithms, this would enable
|
||||
// optimizations that rely on the type of the predicate.
|
||||
return __pred;
|
||||
|
||||
} else {
|
||||
return [&](auto&& __x) {
|
||||
return std::invoke(__pred, std::invoke(__proj, std::forward<decltype(__x)>(__x)));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Comp, class _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr static
|
||||
decltype(auto) __make_projected_comp(_Comp& __comp, _Proj& __proj) {
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
#ifndef _LIBCPP___ALGORITHM_PARTITION_H
|
||||
#define _LIBCPP___ALGORITHM_PARTITION_H
|
||||
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__config>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__utility/swap.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/pair.h>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@@ -19,40 +22,45 @@
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _Predicate, class _ForwardIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
__partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag)
|
||||
template <class _Predicate, class _AlgPolicy, class _ForwardIterator, class _Sentinel>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_ForwardIterator, _ForwardIterator>
|
||||
__partition_impl(_ForwardIterator __first, _Sentinel __last, _Predicate __pred, forward_iterator_tag)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (__first == __last)
|
||||
return __first;
|
||||
return std::make_pair(std::move(__first), std::move(__first));
|
||||
if (!__pred(*__first))
|
||||
break;
|
||||
++__first;
|
||||
}
|
||||
for (_ForwardIterator __p = __first; ++__p != __last;)
|
||||
|
||||
_ForwardIterator __p = __first;
|
||||
while (++__p != __last)
|
||||
{
|
||||
if (__pred(*__p))
|
||||
{
|
||||
swap(*__first, *__p);
|
||||
_IterOps<_AlgPolicy>::iter_swap(__first, __p);
|
||||
++__first;
|
||||
}
|
||||
}
|
||||
return __first;
|
||||
return std::make_pair(std::move(__first), std::move(__p));
|
||||
}
|
||||
|
||||
template <class _Predicate, class _BidirectionalIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _BidirectionalIterator
|
||||
__partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
|
||||
template <class _Predicate, class _AlgPolicy, class _BidirectionalIterator, class _Sentinel>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_BidirectionalIterator, _BidirectionalIterator>
|
||||
__partition_impl(_BidirectionalIterator __first, _Sentinel __sentinel, _Predicate __pred,
|
||||
bidirectional_iterator_tag)
|
||||
{
|
||||
_BidirectionalIterator __original_last = _IterOps<_AlgPolicy>::next(__first, __sentinel);
|
||||
_BidirectionalIterator __last = __original_last;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (__first == __last)
|
||||
return __first;
|
||||
return std::make_pair(std::move(__first), std::move(__original_last));
|
||||
if (!__pred(*__first))
|
||||
break;
|
||||
++__first;
|
||||
@@ -60,20 +68,29 @@ __partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Pred
|
||||
do
|
||||
{
|
||||
if (__first == --__last)
|
||||
return __first;
|
||||
return std::make_pair(std::move(__first), std::move(__original_last));
|
||||
} while (!__pred(*__last));
|
||||
swap(*__first, *__last);
|
||||
_IterOps<_AlgPolicy>::iter_swap(__first, __last);
|
||||
++__first;
|
||||
}
|
||||
}
|
||||
|
||||
template <class _AlgPolicy, class _ForwardIterator, class _Sentinel, class _Predicate, class _IterCategory>
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
pair<_ForwardIterator, _ForwardIterator> __partition(
|
||||
_ForwardIterator __first, _Sentinel __last, _Predicate&& __pred, _IterCategory __iter_category) {
|
||||
return std::__partition_impl<__uncvref_t<_Predicate>&, _AlgPolicy>(
|
||||
std::move(__first), std::move(__last), __pred, __iter_category);
|
||||
}
|
||||
|
||||
template <class _ForwardIterator, class _Predicate>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
_ForwardIterator
|
||||
partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred)
|
||||
{
|
||||
return _VSTD::__partition<_Predicate&>(
|
||||
__first, __last, __pred, typename iterator_traits<_ForwardIterator>::iterator_category());
|
||||
using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
|
||||
auto __result = std::__partition<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __pred, _IterCategory());
|
||||
return __result.first;
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <__algorithm/find_end.h>
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/ranges_iterator_concept.h>
|
||||
#include <__config>
|
||||
#include <__functional/identity.h>
|
||||
#include <__functional/ranges_operations.h>
|
||||
@@ -29,23 +30,6 @@
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _Iter>
|
||||
consteval auto __get_iterator_concept() {
|
||||
if constexpr (contiguous_iterator<_Iter>)
|
||||
return contiguous_iterator_tag();
|
||||
else if constexpr (random_access_iterator<_Iter>)
|
||||
return random_access_iterator_tag();
|
||||
else if constexpr (bidirectional_iterator<_Iter>)
|
||||
return bidirectional_iterator_tag();
|
||||
else if constexpr (forward_iterator<_Iter>)
|
||||
return forward_iterator_tag();
|
||||
else if constexpr (input_iterator<_Iter>)
|
||||
return input_iterator_tag();
|
||||
}
|
||||
|
||||
template <class _Iter>
|
||||
using __iterator_concept = decltype(__get_iterator_concept<_Iter>());
|
||||
|
||||
namespace ranges {
|
||||
namespace __find_end {
|
||||
struct __fn {
|
||||
|
||||
51
libcxx/include/__algorithm/ranges_iterator_concept.h
Normal file
51
libcxx/include/__algorithm/ranges_iterator_concept.h
Normal file
@@ -0,0 +1,51 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_ITERATOR_CONCEPT_H
|
||||
#define _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H
|
||||
|
||||
#include <__config>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <type_traits>
|
||||
|
||||
#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 {
|
||||
|
||||
template <class _IterMaybeQualified>
|
||||
consteval auto __get_iterator_concept() {
|
||||
using _Iter = __uncvref_t<_IterMaybeQualified>;
|
||||
|
||||
if constexpr (contiguous_iterator<_Iter>)
|
||||
return contiguous_iterator_tag();
|
||||
else if constexpr (random_access_iterator<_Iter>)
|
||||
return random_access_iterator_tag();
|
||||
else if constexpr (bidirectional_iterator<_Iter>)
|
||||
return bidirectional_iterator_tag();
|
||||
else if constexpr (forward_iterator<_Iter>)
|
||||
return forward_iterator_tag();
|
||||
else if constexpr (input_iterator<_Iter>)
|
||||
return input_iterator_tag();
|
||||
}
|
||||
|
||||
template <class _Iter>
|
||||
using __iterator_concept = decltype(__get_iterator_concept<_Iter>());
|
||||
|
||||
} // namespace ranges
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
#endif // _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H
|
||||
@@ -9,8 +9,10 @@
|
||||
#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_H
|
||||
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_H
|
||||
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/make_projected.h>
|
||||
#include <__algorithm/partition.h>
|
||||
#include <__algorithm/ranges_iterator_concept.h>
|
||||
#include <__config>
|
||||
#include <__functional/identity.h>
|
||||
#include <__functional/invoke.h>
|
||||
@@ -21,10 +23,10 @@
|
||||
#include <__iterator/projected.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/dangling.h>
|
||||
#include <__ranges/subrange.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@@ -39,13 +41,21 @@ namespace __partition {
|
||||
|
||||
struct __fn {
|
||||
|
||||
template <class _Iter, class _Sent, class _Proj, class _Pred>
|
||||
_LIBCPP_HIDE_FROM_ABI static constexpr
|
||||
subrange<__uncvref_t<_Iter>> __partition_fn_impl(_Iter&& __first, _Sent&& __last, _Pred&& __pred, _Proj&& __proj) {
|
||||
auto&& __projected_pred = ranges::__make_projected_pred(__pred, __proj);
|
||||
auto __result = std::__partition<_RangeAlgPolicy>(
|
||||
std::move(__first), std::move(__last), __projected_pred, __iterator_concept<_Iter>());
|
||||
|
||||
return {std::move(__result.first), std::move(__result.second)};
|
||||
}
|
||||
|
||||
template <permutable _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
|
||||
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__first; (void)__last; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __partition_fn_impl(__first, __last, __pred, __proj);
|
||||
}
|
||||
|
||||
template <forward_range _Range, class _Proj = identity,
|
||||
@@ -53,9 +63,7 @@ struct __fn {
|
||||
requires permutable<iterator_t<_Range>>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
borrowed_subrange_t<_Range> operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__range; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#ifndef _LIBCPP___ALGORITHM_RANGES_STABLE_PARTITION_H
|
||||
#define _LIBCPP___ALGORITHM_RANGES_STABLE_PARTITION_H
|
||||
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/make_projected.h>
|
||||
#include <__algorithm/ranges_iterator_concept.h>
|
||||
#include <__algorithm/stable_partition.h>
|
||||
#include <__config>
|
||||
#include <__functional/identity.h>
|
||||
@@ -17,6 +19,7 @@
|
||||
#include <__functional/ranges_operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/permutable.h>
|
||||
#include <__iterator/projected.h>
|
||||
#include <__ranges/access.h>
|
||||
@@ -25,6 +28,7 @@
|
||||
#include <__ranges/subrange.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@@ -39,14 +43,25 @@ namespace __stable_partition {
|
||||
|
||||
struct __fn {
|
||||
|
||||
template <class _Iter, class _Sent, class _Proj, class _Pred>
|
||||
_LIBCPP_HIDE_FROM_ABI static
|
||||
subrange<__uncvref_t<_Iter>> __stable_partition_fn_impl(
|
||||
_Iter&& __first, _Sent&& __last, _Pred&& __pred, _Proj&& __proj) {
|
||||
auto __last_iter = ranges::next(__first, __last);
|
||||
|
||||
auto&& __projected_pred = ranges::__make_projected_pred(__pred, __proj);
|
||||
auto __result = std::__stable_partition<_RangeAlgPolicy>(
|
||||
std::move(__first), __last_iter, __projected_pred, __iterator_concept<_Iter>());
|
||||
|
||||
return {std::move(__result), std::move(__last_iter)};
|
||||
}
|
||||
|
||||
template <bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
|
||||
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
|
||||
requires permutable<_Iter>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__first; (void)__last; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __stable_partition_fn_impl(__first, __last, __pred, __proj);
|
||||
}
|
||||
|
||||
template <bidirectional_range _Range, class _Proj = identity,
|
||||
@@ -54,9 +69,7 @@ struct __fn {
|
||||
requires permutable<iterator_t<_Range>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
borrowed_subrange_t<_Range> operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__range; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __stable_partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifndef _LIBCPP___ALGORITHM_ROTATE_H
|
||||
#define _LIBCPP___ALGORITHM_ROTATE_H
|
||||
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/move.h>
|
||||
#include <__algorithm/move_backward.h>
|
||||
#include <__algorithm/swap_ranges.h>
|
||||
@@ -26,37 +27,40 @@
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _ForwardIterator>
|
||||
template <class _AlgPolicy, class _ForwardIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
|
||||
__rotate_left(_ForwardIterator __first, _ForwardIterator __last)
|
||||
{
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
|
||||
value_type __tmp = _VSTD::move(*__first);
|
||||
value_type __tmp = _IterOps<_AlgPolicy>::__iter_move(__first);
|
||||
// TODO(ranges): pass `_AlgPolicy` to `move`.
|
||||
_ForwardIterator __lm1 = _VSTD::move(_VSTD::next(__first), __last, __first);
|
||||
*__lm1 = _VSTD::move(__tmp);
|
||||
return __lm1;
|
||||
}
|
||||
|
||||
template <class _BidirectionalIterator>
|
||||
template <class _AlgPolicy, class _BidirectionalIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX11 _BidirectionalIterator
|
||||
__rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last)
|
||||
{
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
|
||||
// TODO(ranges): pass `_AlgPolicy` to `prev`.
|
||||
_BidirectionalIterator __lm1 = _VSTD::prev(__last);
|
||||
value_type __tmp = _VSTD::move(*__lm1);
|
||||
value_type __tmp = _IterOps<_AlgPolicy>::__iter_move(__lm1);
|
||||
// TODO(ranges): pass `_AlgPolicy` to `move_backward`.
|
||||
_BidirectionalIterator __fp1 = _VSTD::move_backward(__first, __lm1, __last);
|
||||
*__first = _VSTD::move(__tmp);
|
||||
return __fp1;
|
||||
}
|
||||
|
||||
template <class _ForwardIterator>
|
||||
template <class _AlgPolicy, class _ForwardIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX14 _ForwardIterator
|
||||
__rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
|
||||
{
|
||||
_ForwardIterator __i = __middle;
|
||||
while (true)
|
||||
{
|
||||
swap(*__first, *__i);
|
||||
_IterOps<_AlgPolicy>::iter_swap(__first, __i);
|
||||
++__first;
|
||||
if (++__i == __last)
|
||||
break;
|
||||
@@ -69,7 +73,7 @@ __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIt
|
||||
__i = __middle;
|
||||
while (true)
|
||||
{
|
||||
swap(*__first, *__i);
|
||||
_IterOps<_AlgPolicy>::iter_swap(__first, __i);
|
||||
++__first;
|
||||
if (++__i == __last)
|
||||
{
|
||||
@@ -98,7 +102,7 @@ __algo_gcd(_Integral __x, _Integral __y)
|
||||
return __x;
|
||||
}
|
||||
|
||||
template<typename _RandomAccessIterator>
|
||||
template <class _AlgPolicy, typename _RandomAccessIterator>
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX14 _RandomAccessIterator
|
||||
__rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last)
|
||||
{
|
||||
@@ -109,18 +113,19 @@ __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Ran
|
||||
const difference_type __m2 = __last - __middle;
|
||||
if (__m1 == __m2)
|
||||
{
|
||||
// TODO(ranges): pass `_AlgPolicy` to `swap_ranges`.
|
||||
_VSTD::swap_ranges(__first, __middle, __middle);
|
||||
return __middle;
|
||||
}
|
||||
const difference_type __g = _VSTD::__algo_gcd(__m1, __m2);
|
||||
for (_RandomAccessIterator __p = __first + __g; __p != __first;)
|
||||
{
|
||||
value_type __t(_VSTD::move(*--__p));
|
||||
value_type __t(_IterOps<_AlgPolicy>::__iter_move(--__p));
|
||||
_RandomAccessIterator __p1 = __p;
|
||||
_RandomAccessIterator __p2 = __p1 + __m1;
|
||||
do
|
||||
{
|
||||
*__p1 = _VSTD::move(*__p2);
|
||||
*__p1 = _IterOps<_AlgPolicy>::__iter_move(__p2);
|
||||
__p1 = __p2;
|
||||
const difference_type __d = __last - __p2;
|
||||
if (__m1 < __d)
|
||||
@@ -133,54 +138,66 @@ __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Ran
|
||||
return __first + __m2;
|
||||
}
|
||||
|
||||
template <class _ForwardIterator>
|
||||
template <class _AlgPolicy, class _ForwardIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
|
||||
__rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
|
||||
__rotate_impl(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
|
||||
_VSTD::forward_iterator_tag)
|
||||
{
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
|
||||
if (is_trivially_move_assignable<value_type>::value)
|
||||
{
|
||||
if (_VSTD::next(__first) == __middle)
|
||||
return _VSTD::__rotate_left(__first, __last);
|
||||
if (_IterOps<_AlgPolicy>::next(__first) == __middle)
|
||||
return std::__rotate_left<_AlgPolicy>(__first, __last);
|
||||
}
|
||||
return _VSTD::__rotate_forward(__first, __middle, __last);
|
||||
return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
|
||||
}
|
||||
|
||||
template <class _BidirectionalIterator>
|
||||
template <class _AlgPolicy, class _BidirectionalIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX11 _BidirectionalIterator
|
||||
__rotate(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
|
||||
__rotate_impl(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
|
||||
bidirectional_iterator_tag)
|
||||
{
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
|
||||
if (is_trivially_move_assignable<value_type>::value)
|
||||
{
|
||||
if (_VSTD::next(__first) == __middle)
|
||||
return _VSTD::__rotate_left(__first, __last);
|
||||
if (_VSTD::next(__middle) == __last)
|
||||
return _VSTD::__rotate_right(__first, __last);
|
||||
if (_IterOps<_AlgPolicy>::next(__first) == __middle)
|
||||
return std::__rotate_left<_AlgPolicy>(__first, __last);
|
||||
if (_IterOps<_AlgPolicy>::next(__middle) == __last)
|
||||
return std::__rotate_right<_AlgPolicy>(__first, __last);
|
||||
}
|
||||
return _VSTD::__rotate_forward(__first, __middle, __last);
|
||||
return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
|
||||
}
|
||||
|
||||
template <class _RandomAccessIterator>
|
||||
template <class _AlgPolicy, class _RandomAccessIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator
|
||||
__rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
|
||||
__rotate_impl(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
|
||||
random_access_iterator_tag)
|
||||
{
|
||||
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
|
||||
if (is_trivially_move_assignable<value_type>::value)
|
||||
{
|
||||
if (_VSTD::next(__first) == __middle)
|
||||
return _VSTD::__rotate_left(__first, __last);
|
||||
if (_VSTD::next(__middle) == __last)
|
||||
return _VSTD::__rotate_right(__first, __last);
|
||||
return _VSTD::__rotate_gcd(__first, __middle, __last);
|
||||
if (_IterOps<_AlgPolicy>::next(__first) == __middle)
|
||||
return std::__rotate_left<_AlgPolicy>(__first, __last);
|
||||
if (_IterOps<_AlgPolicy>::next(__middle) == __last)
|
||||
return std::__rotate_right<_AlgPolicy>(__first, __last);
|
||||
return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last);
|
||||
}
|
||||
return _VSTD::__rotate_forward(__first, __middle, __last);
|
||||
return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
|
||||
}
|
||||
|
||||
template <class _AlgPolicy, class _RandomAccessIterator, class _IterCategory>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||
_RandomAccessIterator __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle,
|
||||
_RandomAccessIterator __last, _IterCategory __iter_category) {
|
||||
if (__first == __middle)
|
||||
return __last;
|
||||
if (__middle == __last)
|
||||
return __first;
|
||||
|
||||
return std::__rotate_impl<_AlgPolicy>(std::move(__first), std::move(__middle), std::move(__last), __iter_category);
|
||||
}
|
||||
|
||||
template <class _ForwardIterator>
|
||||
@@ -188,12 +205,8 @@ inline _LIBCPP_INLINE_VISIBILITY
|
||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
||||
rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
|
||||
{
|
||||
if (__first == __middle)
|
||||
return __last;
|
||||
if (__middle == __last)
|
||||
return __first;
|
||||
return _VSTD::__rotate(__first, __middle, __last,
|
||||
typename iterator_traits<_ForwardIterator>::iterator_category());
|
||||
return std::__rotate<_ClassicAlgPolicy>(__first, __middle, __last,
|
||||
typename iterator_traits<_ForwardIterator>::iterator_category());
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
#ifndef _LIBCPP___ALGORITHM_STABLE_PARTITION_H
|
||||
#define _LIBCPP___ALGORITHM_STABLE_PARTITION_H
|
||||
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/rotate.h>
|
||||
#include <__config>
|
||||
#include <__iterator/advance.h>
|
||||
#include <__iterator/distance.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__utility/swap.h>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@@ -23,11 +24,13 @@
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
|
||||
template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
|
||||
_ForwardIterator
|
||||
__stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
|
||||
__stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
|
||||
_Distance __len, _Pair __p, forward_iterator_tag __fit)
|
||||
{
|
||||
using _Ops = _IterOps<_AlgPolicy>;
|
||||
|
||||
// *__first is known to be false
|
||||
// __len >= 1
|
||||
if (__len == 1)
|
||||
@@ -37,7 +40,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
|
||||
_ForwardIterator __m = __first;
|
||||
if (__pred(*++__m))
|
||||
{
|
||||
swap(*__first, *__m);
|
||||
_Ops::iter_swap(__first, __m);
|
||||
return __m;
|
||||
}
|
||||
return __first;
|
||||
@@ -50,7 +53,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
|
||||
// Move the falses into the temporary buffer, and the trues to the front of the line
|
||||
// Update __first to always point to the end of the trues
|
||||
value_type* __t = __p.first;
|
||||
::new ((void*)__t) value_type(_VSTD::move(*__first));
|
||||
::new ((void*)__t) value_type(_Ops::__iter_move(__first));
|
||||
__d.template __incr<value_type>();
|
||||
++__t;
|
||||
_ForwardIterator __i = __first;
|
||||
@@ -58,12 +61,12 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
|
||||
{
|
||||
if (__pred(*__i))
|
||||
{
|
||||
*__first = _VSTD::move(*__i);
|
||||
*__first = _Ops::__iter_move(__i);
|
||||
++__first;
|
||||
}
|
||||
else
|
||||
{
|
||||
::new ((void*)__t) value_type(_VSTD::move(*__i));
|
||||
::new ((void*)__t) value_type(_Ops::__iter_move(__i));
|
||||
__d.template __incr<value_type>();
|
||||
++__t;
|
||||
}
|
||||
@@ -72,7 +75,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
|
||||
// Move falses back into range, but don't mess up __first which points to first false
|
||||
__i = __first;
|
||||
for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void) ++__i)
|
||||
*__i = _VSTD::move(*__t2);
|
||||
*__i = _Ops::__iter_move(__t2);
|
||||
// __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
|
||||
return __first;
|
||||
}
|
||||
@@ -80,11 +83,12 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
|
||||
// __len >= 3
|
||||
_ForwardIterator __m = __first;
|
||||
_Distance __len2 = __len / 2; // __len2 >= 2
|
||||
_VSTD::advance(__m, __len2);
|
||||
_Ops::advance(__m, __len2);
|
||||
// recurse on [__first, __m), *__first know to be false
|
||||
// F?????????????????
|
||||
// f m l
|
||||
_ForwardIterator __first_false = _VSTD::__stable_partition<_Predicate&>(__first, __m, __pred, __len2, __p, __fit);
|
||||
_ForwardIterator __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
|
||||
__first, __m, __pred, __len2, __p, __fit);
|
||||
// TTTFFFFF??????????
|
||||
// f ff m l
|
||||
// recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
|
||||
@@ -99,18 +103,19 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
|
||||
}
|
||||
// TTTFFFFFTTTF??????
|
||||
// f ff m m1 l
|
||||
__second_false = _VSTD::__stable_partition<_Predicate&>(__m1, __last, __pred, __len_half, __p, __fit);
|
||||
__second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
|
||||
__m1, __last, __pred, __len_half, __p, __fit);
|
||||
__second_half_done:
|
||||
// TTTFFFFFTTTTTFFFFF
|
||||
// f ff m sf l
|
||||
return _VSTD::rotate(__first_false, __m, __second_false);
|
||||
return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false, __fit);
|
||||
// TTTTTTTTFFFFFFFFFF
|
||||
// |
|
||||
}
|
||||
|
||||
template <class _Predicate, class _ForwardIterator>
|
||||
template <class _AlgPolicy, class _Predicate, class _ForwardIterator>
|
||||
_ForwardIterator
|
||||
__stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
|
||||
__stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
|
||||
forward_iterator_tag)
|
||||
{
|
||||
const unsigned __alloc_limit = 3; // might want to make this a function of trivial assignment
|
||||
@@ -127,7 +132,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
|
||||
// *__first is known to be false
|
||||
typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
|
||||
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
|
||||
difference_type __len = _VSTD::distance(__first, __last);
|
||||
difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last);
|
||||
pair<value_type*, ptrdiff_t> __p(0, 0);
|
||||
unique_ptr<value_type, __return_temporary_buffer> __h;
|
||||
if (__len >= __alloc_limit)
|
||||
@@ -138,20 +143,23 @@ _LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
__h.reset(__p.first);
|
||||
}
|
||||
return _VSTD::__stable_partition<_Predicate&>(__first, __last, __pred, __len, __p, forward_iterator_tag());
|
||||
return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
|
||||
std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag());
|
||||
}
|
||||
|
||||
template <class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
|
||||
template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
|
||||
_BidirectionalIterator
|
||||
__stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
|
||||
__stable_partition_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
|
||||
_Distance __len, _Pair __p, bidirectional_iterator_tag __bit)
|
||||
{
|
||||
using _Ops = _IterOps<_AlgPolicy>;
|
||||
|
||||
// *__first is known to be false
|
||||
// *__last is known to be true
|
||||
// __len >= 2
|
||||
if (__len == 2)
|
||||
{
|
||||
swap(*__first, *__last);
|
||||
_Ops::iter_swap(__first, __last);
|
||||
return __last;
|
||||
}
|
||||
if (__len == 3)
|
||||
@@ -159,12 +167,12 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
|
||||
_BidirectionalIterator __m = __first;
|
||||
if (__pred(*++__m))
|
||||
{
|
||||
swap(*__first, *__m);
|
||||
swap(*__m, *__last);
|
||||
_Ops::iter_swap(__first, __m);
|
||||
_Ops::iter_swap(__m, __last);
|
||||
return __last;
|
||||
}
|
||||
swap(*__m, *__last);
|
||||
swap(*__first, *__m);
|
||||
_Ops::iter_swap(__m, __last);
|
||||
_Ops::iter_swap(__first, __m);
|
||||
return __m;
|
||||
}
|
||||
if (__len <= __p.second)
|
||||
@@ -175,7 +183,7 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
|
||||
// Move the falses into the temporary buffer, and the trues to the front of the line
|
||||
// Update __first to always point to the end of the trues
|
||||
value_type* __t = __p.first;
|
||||
::new ((void*)__t) value_type(_VSTD::move(*__first));
|
||||
::new ((void*)__t) value_type(_Ops::__iter_move(__first));
|
||||
__d.template __incr<value_type>();
|
||||
++__t;
|
||||
_BidirectionalIterator __i = __first;
|
||||
@@ -183,23 +191,23 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
|
||||
{
|
||||
if (__pred(*__i))
|
||||
{
|
||||
*__first = _VSTD::move(*__i);
|
||||
*__first = _Ops::__iter_move(__i);
|
||||
++__first;
|
||||
}
|
||||
else
|
||||
{
|
||||
::new ((void*)__t) value_type(_VSTD::move(*__i));
|
||||
::new ((void*)__t) value_type(_Ops::__iter_move(__i));
|
||||
__d.template __incr<value_type>();
|
||||
++__t;
|
||||
}
|
||||
}
|
||||
// move *__last, known to be true
|
||||
*__first = _VSTD::move(*__i);
|
||||
*__first = _Ops::__iter_move(__i);
|
||||
__i = ++__first;
|
||||
// All trues now at start of range, all falses in buffer
|
||||
// Move falses back into range, but don't mess up __first which points to first false
|
||||
for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void) ++__i)
|
||||
*__i = _VSTD::move(*__t2);
|
||||
*__i = _Ops::__iter_move(__t2);
|
||||
// __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
|
||||
return __first;
|
||||
}
|
||||
@@ -207,7 +215,7 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
|
||||
// __len >= 4
|
||||
_BidirectionalIterator __m = __first;
|
||||
_Distance __len2 = __len / 2; // __len2 >= 2
|
||||
_VSTD::advance(__m, __len2);
|
||||
_Ops::advance(__m, __len2);
|
||||
// recurse on [__first, __m-1], except reduce __m-1 until *(__m-1) is true, *__first know to be false
|
||||
// F????????????????T
|
||||
// f m l
|
||||
@@ -222,7 +230,8 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
|
||||
}
|
||||
// F???TFFF?????????T
|
||||
// f m1 m l
|
||||
__first_false = _VSTD::__stable_partition<_Predicate&>(__first, __m1, __pred, __len_half, __p, __bit);
|
||||
__first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
|
||||
__first, __m1, __pred, __len_half, __p, __bit);
|
||||
__first_half_done:
|
||||
// TTTFFFFF?????????T
|
||||
// f ff m l
|
||||
@@ -239,18 +248,19 @@ __first_half_done:
|
||||
}
|
||||
// TTTFFFFFTTTF?????T
|
||||
// f ff m m1 l
|
||||
__second_false = _VSTD::__stable_partition<_Predicate&>(__m1, __last, __pred, __len_half, __p, __bit);
|
||||
__second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
|
||||
__m1, __last, __pred, __len_half, __p, __bit);
|
||||
__second_half_done:
|
||||
// TTTFFFFFTTTTTFFFFF
|
||||
// f ff m sf l
|
||||
return _VSTD::rotate(__first_false, __m, __second_false);
|
||||
return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false, __bit);
|
||||
// TTTTTTTTFFFFFFFFFF
|
||||
// |
|
||||
}
|
||||
|
||||
template <class _Predicate, class _BidirectionalIterator>
|
||||
template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator>
|
||||
_BidirectionalIterator
|
||||
__stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
|
||||
__stable_partition_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
|
||||
bidirectional_iterator_tag)
|
||||
{
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
|
||||
@@ -276,7 +286,7 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
|
||||
// *__first is known to be false
|
||||
// *__last is known to be true
|
||||
// __len >= 2
|
||||
difference_type __len = _VSTD::distance(__first, __last) + 1;
|
||||
difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1;
|
||||
pair<value_type*, ptrdiff_t> __p(0, 0);
|
||||
unique_ptr<value_type, __return_temporary_buffer> __h;
|
||||
if (__len >= __alloc_limit)
|
||||
@@ -287,7 +297,16 @@ _LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
__h.reset(__p.first);
|
||||
}
|
||||
return _VSTD::__stable_partition<_Predicate&>(__first, __last, __pred, __len, __p, bidirectional_iterator_tag());
|
||||
return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
|
||||
std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag());
|
||||
}
|
||||
|
||||
template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _IterCategory>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
_ForwardIterator __stable_partition(
|
||||
_ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) {
|
||||
return std::__stable_partition_impl<_AlgPolicy, __uncvref_t<_Predicate>&>(
|
||||
std::move(__first), std::move(__last), __pred, __iter_category);
|
||||
}
|
||||
|
||||
template <class _ForwardIterator, class _Predicate>
|
||||
@@ -295,7 +314,9 @@ inline _LIBCPP_INLINE_VISIBILITY
|
||||
_ForwardIterator
|
||||
stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred)
|
||||
{
|
||||
return _VSTD::__stable_partition<_Predicate&>(__first, __last, __pred, typename iterator_traits<_ForwardIterator>::iterator_category());
|
||||
using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
|
||||
return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>(
|
||||
std::move(__first), std::move(__last), __pred, _IterCategory());
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
@@ -464,6 +464,28 @@ namespace ranges {
|
||||
ranges::less>
|
||||
constexpr bool binary_search(R&& r, const T& value, Comp comp = {},
|
||||
Proj proj = {}); // since C++20
|
||||
|
||||
template<permutable I, sentinel_for<I> S, class Proj = identity,
|
||||
indirect_unary_predicate<projected<I, Proj>> Pred>
|
||||
constexpr subrange<I>
|
||||
partition(I first, S last, Pred pred, Proj proj = {}); // Since C++20
|
||||
|
||||
template<forward_range R, class Proj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
requires permutable<iterator_t<R>>
|
||||
constexpr borrowed_subrange_t<R>
|
||||
partition(R&& r, Pred pred, Proj proj = {}); // Since C++20
|
||||
|
||||
template<bidirectional_iterator I, sentinel_for<I> S, class Proj = identity,
|
||||
indirect_unary_predicate<projected<I, Proj>> Pred>
|
||||
requires permutable<I>
|
||||
subrange<I> stable_partition(I first, S last, Pred pred, Proj proj = {}); // Since C++20
|
||||
|
||||
template<bidirectional_range R, class Proj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
requires permutable<iterator_t<R>>
|
||||
borrowed_subrange_t<R> stable_partition(R&& r, Pred pred, Proj proj = {}); // Since C++20
|
||||
|
||||
template<input_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2,
|
||||
class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
|
||||
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
|
||||
@@ -1496,6 +1518,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_partition.h>
|
||||
#include <__algorithm/ranges_pop_heap.h>
|
||||
#include <__algorithm/ranges_push_heap.h>
|
||||
#include <__algorithm/ranges_remove.h>
|
||||
@@ -1513,6 +1536,7 @@ template <class BidirectionalIterator, class Compare>
|
||||
#include <__algorithm/ranges_set_union.h>
|
||||
#include <__algorithm/ranges_sort.h>
|
||||
#include <__algorithm/ranges_sort_heap.h>
|
||||
#include <__algorithm/ranges_stable_partition.h>
|
||||
#include <__algorithm/ranges_stable_sort.h>
|
||||
#include <__algorithm/ranges_swap_ranges.h>
|
||||
#include <__algorithm/ranges_transform.h>
|
||||
|
||||
@@ -337,6 +337,7 @@ module std [system] {
|
||||
module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" }
|
||||
module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" }
|
||||
module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" }
|
||||
module ranges_iterator_concept { private header "__algorithm/ranges_iterator_concept.h" }
|
||||
module ranges_lexicographical_compare { private header "__algorithm/ranges_lexicographical_compare.h" }
|
||||
module ranges_lower_bound { private header "__algorithm/ranges_lower_bound.h" }
|
||||
module ranges_make_heap { private header "__algorithm/ranges_make_heap.h" }
|
||||
|
||||
@@ -175,8 +175,8 @@ constexpr bool all_the_algorithms()
|
||||
//(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);
|
||||
//(void)std::ranges::partition(a, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(a, UnaryTrue(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_point(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
||||
@@ -211,8 +211,8 @@ constexpr bool all_the_algorithms()
|
||||
(void)std::ranges::sort(a, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::sort_heap(first, last, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::sort_heap(a, Less(&copies)); assert(copies == 0);
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(first, last, UnaryTrue(&copies)); assert(copies == 0); }
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(a, UnaryTrue(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(first, last, UnaryTrue(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(a, UnaryTrue(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(first, last, Less(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(a, Less(&copies)); assert(copies == 0); }
|
||||
#if TEST_STD_VER > 20
|
||||
|
||||
@@ -158,8 +158,8 @@ constexpr bool all_the_algorithms()
|
||||
//(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);
|
||||
//(void)std::ranges::partition(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_point(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
@@ -202,8 +202,8 @@ constexpr bool all_the_algorithms()
|
||||
(void)std::ranges::sort(a, Less(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::sort_heap(first, last, Less(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::sort_heap(a, Less(), Proj(&copies)); assert(copies == 0);
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0); }
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(a, UnaryTrue(), Proj(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_partition(a, UnaryTrue(), Proj(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(first, last, Less(), Proj(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::stable_sort(a, Less(), Proj(&copies)); assert(copies == 0); }
|
||||
#if TEST_STD_VER > 20
|
||||
|
||||
@@ -135,6 +135,7 @@ END-SCRIPT
|
||||
#include <__algorithm/ranges_is_partitioned.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_partitioned.h'}}
|
||||
#include <__algorithm/ranges_is_sorted.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted.h'}}
|
||||
#include <__algorithm/ranges_is_sorted_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted_until.h'}}
|
||||
#include <__algorithm/ranges_iterator_concept.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_iterator_concept.h'}}
|
||||
#include <__algorithm/ranges_lexicographical_compare.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_lexicographical_compare.h'}}
|
||||
#include <__algorithm/ranges_lower_bound.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_lower_bound.h'}}
|
||||
#include <__algorithm/ranges_make_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_make_heap.h'}}
|
||||
|
||||
@@ -31,12 +31,174 @@
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// TODO: SFINAE tests.
|
||||
struct UnaryPred { bool operator()(int) const; };
|
||||
|
||||
// Test constraints of the (iterator, sentinel) overload.
|
||||
// ======================================================
|
||||
|
||||
template <class Iter = int*, class Sent = int*, class Pred = UnaryPred>
|
||||
concept HasPartitionIter =
|
||||
requires(Iter&& iter, Sent&& sent, Pred&& pred) {
|
||||
std::ranges::partition(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
static_assert(HasPartitionIter<int*, int*, UnaryPred>);
|
||||
|
||||
// !permutable<I>
|
||||
static_assert(!HasPartitionIter<PermutableNotForwardIterator>);
|
||||
static_assert(!HasPartitionIter<PermutableNotSwappable>);
|
||||
|
||||
// !sentinel_for<S, I>
|
||||
static_assert(!HasPartitionIter<int*, SentinelForNotSemiregular>);
|
||||
static_assert(!HasPartitionIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
|
||||
|
||||
// !indirect_unary_predicate<projected<I, Proj>>
|
||||
static_assert(!HasPartitionIter<int*, int*, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasPartitionIter<int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
// Test constraints of the (range) overload.
|
||||
// =========================================
|
||||
|
||||
template <class Range, class Pred>
|
||||
concept HasPartitionRange =
|
||||
requires(Range&& range, Pred&& pred) {
|
||||
std::ranges::partition(std::forward<Range>(range), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using R = UncheckedRange<T>;
|
||||
|
||||
static_assert(HasPartitionRange<R<int*>, UnaryPred>);
|
||||
|
||||
// !forward_range<R>
|
||||
static_assert(!HasPartitionRange<ForwardRangeNotDerivedFrom, UnaryPred>);
|
||||
static_assert(!HasPartitionRange<ForwardIteratorNotIncrementable, UnaryPred>);
|
||||
|
||||
// !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
static_assert(!HasPartitionRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasPartitionRange<R<int*>, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
// !permutable<iterator_t<R>>
|
||||
static_assert(!HasPartitionRange<R<PermutableNotForwardIterator>, UnaryPred>);
|
||||
static_assert(!HasPartitionRange<R<PermutableNotSwappable>, UnaryPred>);
|
||||
|
||||
// `partition` isn't a stable algorithm so this function cannot test the exact output.
|
||||
template <class Iter, class Sent, size_t N, class Pred>
|
||||
constexpr void test_one(std::array<int, N> input, Pred pred, size_t partition_point) {
|
||||
auto neg_pred = [&](int x) { return !pred(x); };
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
auto partitioned = input;
|
||||
auto b = Iter(partitioned.data());
|
||||
auto e = Sent(Iter(partitioned.data() + partitioned.size()));
|
||||
|
||||
std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::partition(b, e, pred);
|
||||
|
||||
assert(base(result.begin()) == partitioned.data() + partition_point);
|
||||
assert(base(result.end()) == partitioned.data() + partitioned.size());
|
||||
|
||||
assert(std::ranges::all_of(b, result.begin(), pred));
|
||||
assert(std::ranges::all_of(result.begin(), e, neg_pred));
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
auto partitioned = input;
|
||||
auto b = Iter(partitioned.data());
|
||||
auto e = Sent(Iter(partitioned.data() + partitioned.size()));
|
||||
auto range = std::ranges::subrange(b, e);
|
||||
|
||||
std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::partition(range, pred);
|
||||
|
||||
assert(base(result.begin()) == partitioned.data() + partition_point);
|
||||
assert(base(result.end()) == partitioned.data() + partitioned.size());
|
||||
|
||||
assert(std::ranges::all_of(b, result.begin(), pred));
|
||||
assert(std::ranges::all_of(result.begin(), e, neg_pred));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter, class Sent>
|
||||
constexpr void test_iterators_2() {
|
||||
auto is_odd = [](int x) { return x % 2 != 0; };
|
||||
|
||||
// Empty sequence.
|
||||
test_one<Iter, Sent, 0>({}, is_odd, 0);
|
||||
// 1-element sequence, the element satisfies the predicate.
|
||||
test_one<Iter, Sent, 1>({1}, is_odd, 1);
|
||||
// 1-element sequence, the element doesn't satisfy the predicate.
|
||||
test_one<Iter, Sent, 1>({2}, is_odd, 0);
|
||||
// 2-element sequence, not in order.
|
||||
test_one<Iter, Sent, 2>({2, 1}, is_odd, 1);
|
||||
// 2-element sequence, already in order.
|
||||
test_one<Iter, Sent, 2>({1, 2}, is_odd, 1);
|
||||
// 3-element sequence.
|
||||
test_one<Iter, Sent, 3>({2, 1, 3}, is_odd, 2);
|
||||
// Longer sequence.
|
||||
test_one<Iter, Sent, 8>({2, 1, 3, 6, 8, 4, 11, 5}, is_odd, 4);
|
||||
// Longer sequence with duplicates.
|
||||
test_one<Iter, Sent, 8>({2, 1, 3, 6, 2, 8, 1, 6}, is_odd, 3);
|
||||
// All elements are the same and satisfy the predicate.
|
||||
test_one<Iter, Sent, 3>({1, 1, 1}, is_odd, 3);
|
||||
// All elements are the same and don't satisfy the predicate.
|
||||
test_one<Iter, Sent, 3>({2, 2, 2}, is_odd, 0);
|
||||
// Already partitioned.
|
||||
test_one<Iter, Sent, 6>({1, 3, 5, 4, 6, 8}, is_odd, 3);
|
||||
// Reverse-partitioned.
|
||||
test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3);
|
||||
// Repeating pattern.
|
||||
test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
constexpr void test_iterators_1() {
|
||||
test_iterators_2<Iter, Iter>();
|
||||
test_iterators_2<Iter, sentinel_wrapper<Iter>>();
|
||||
}
|
||||
|
||||
constexpr void test_iterators() {
|
||||
test_iterators_1<forward_iterator<int*>>();
|
||||
test_iterators_1<bidirectional_iterator<int*>>();
|
||||
test_iterators_1<random_access_iterator<int*>>();
|
||||
test_iterators_1<contiguous_iterator<int*>>();
|
||||
test_iterators_1<int*>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// TODO: main tests.
|
||||
// TODO: A custom comparator works.
|
||||
// TODO: A custom projection works.
|
||||
test_iterators();
|
||||
|
||||
{ // A custom projection works.
|
||||
const std::array input = {1, -1};
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
auto negate = [](int x) { return -x; };
|
||||
const std::array expected_no_proj = {-1, 1};
|
||||
const std::array expected_with_proj = {1, -1};
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in.begin(), in.end(), is_negative);
|
||||
assert(in == expected_no_proj);
|
||||
}
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in.begin(), in.end(), is_negative, negate);
|
||||
assert(in == expected_with_proj);
|
||||
}
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in, is_negative);
|
||||
assert(in == expected_no_proj);
|
||||
}
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in, is_negative, negate);
|
||||
assert(in == expected_with_proj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,19 +30,216 @@
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// TODO: SFINAE tests.
|
||||
struct UnaryPred { bool operator()(int) const; };
|
||||
|
||||
constexpr bool test() {
|
||||
// TODO: main tests.
|
||||
// TODO: A custom comparator works.
|
||||
// TODO: A custom projection works.
|
||||
// Test constraints of the (iterator, sentinel) overload.
|
||||
// ======================================================
|
||||
|
||||
return true;
|
||||
template <class Iter = int*, class Sent = int*, class Pred = UnaryPred>
|
||||
concept HasStablePartitionIter =
|
||||
requires(Iter&& iter, Sent&& sent, Pred&& pred) {
|
||||
std::ranges::stable_partition(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
static_assert(HasStablePartitionIter<int*, int*, UnaryPred>);
|
||||
|
||||
// !bidirectional_iterator<I>
|
||||
static_assert(!HasStablePartitionIter<BidirectionalIteratorNotDerivedFrom>);
|
||||
static_assert(!HasStablePartitionIter<BidirectionalIteratorNotDecrementable>);
|
||||
|
||||
// !sentinel_for<S, I>
|
||||
static_assert(!HasStablePartitionIter<int*, SentinelForNotSemiregular>);
|
||||
static_assert(!HasStablePartitionIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
|
||||
|
||||
// !indirect_unary_predicate<projected<I, Proj>>
|
||||
static_assert(!HasStablePartitionIter<int*, int*, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasStablePartitionIter<int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
// !permutable<I>
|
||||
static_assert(!HasStablePartitionIter<PermutableNotForwardIterator>);
|
||||
static_assert(!HasStablePartitionIter<PermutableNotSwappable>);
|
||||
|
||||
// Test constraints of the (range) overload.
|
||||
// =========================================
|
||||
|
||||
template <class Range, class Pred>
|
||||
concept HasStablePartitionRange =
|
||||
requires(Range&& range, Pred&& pred) {
|
||||
std::ranges::stable_partition(std::forward<Range>(range), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using R = UncheckedRange<T>;
|
||||
|
||||
static_assert(HasStablePartitionRange<R<int*>, UnaryPred>);
|
||||
|
||||
// !bidirectional_range<R>
|
||||
static_assert(!HasStablePartitionRange<BidirectionalRangeNotDerivedFrom, UnaryPred>);
|
||||
static_assert(!HasStablePartitionRange<BidirectionalRangeNotDecrementable, UnaryPred>);
|
||||
|
||||
// !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
static_assert(!HasStablePartitionRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasStablePartitionRange<R<int*>, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
// !permutable<iterator_t<R>>
|
||||
static_assert(!HasStablePartitionRange<R<PermutableNotForwardIterator>, UnaryPred>);
|
||||
static_assert(!HasStablePartitionRange<R<PermutableNotSwappable>, UnaryPred>);
|
||||
|
||||
template <class Iter, class Sent, size_t N, class Pred>
|
||||
void test_one(std::array<int, N> input, Pred pred, size_t partition_point, std::array<int, N> expected) {
|
||||
auto neg_pred = [&](int x) { return !pred(x); };
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
auto partitioned = input;
|
||||
auto b = Iter(partitioned.data());
|
||||
auto e = Sent(Iter(partitioned.data() + partitioned.size()));
|
||||
|
||||
std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::stable_partition(b, e, pred);
|
||||
|
||||
assert(partitioned == expected);
|
||||
assert(base(result.begin()) == partitioned.data() + partition_point);
|
||||
assert(base(result.end()) == partitioned.data() + partitioned.size());
|
||||
|
||||
assert(std::ranges::all_of(b, result.begin(), pred));
|
||||
assert(std::ranges::all_of(result.begin(), e, neg_pred));
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
auto partitioned = input;
|
||||
auto b = Iter(partitioned.data());
|
||||
auto e = Sent(Iter(partitioned.data() + partitioned.size()));
|
||||
auto range = std::ranges::subrange(b, e);
|
||||
|
||||
std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::stable_partition(range, pred);
|
||||
|
||||
assert(partitioned == expected);
|
||||
assert(base(result.begin()) == partitioned.data() + partition_point);
|
||||
assert(base(result.end()) == partitioned.data() + partitioned.size());
|
||||
|
||||
assert(std::ranges::all_of(b, result.begin(), pred));
|
||||
assert(std::ranges::all_of(result.begin(), e, neg_pred));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter, class Sent>
|
||||
void test_iterators_2() {
|
||||
auto is_odd = [](int x) { return x % 2 != 0; };
|
||||
|
||||
// Empty sequence.
|
||||
test_one<Iter, Sent, 0>({}, is_odd, 0, {});
|
||||
// 1-element sequence, the element satisfies the predicate.
|
||||
test_one<Iter, Sent, 1>({1}, is_odd, 1, {1});
|
||||
// 1-element sequence, the element doesn't satisfy the predicate.
|
||||
test_one<Iter, Sent, 1>({2}, is_odd, 0, {2});
|
||||
// 2-element sequence, not in order.
|
||||
test_one<Iter, Sent, 2>({2, 1}, is_odd, 1, {1, 2});
|
||||
// 2-element sequence, already in order.
|
||||
test_one<Iter, Sent, 2>({1, 2}, is_odd, 1, {1, 2});
|
||||
// 3-element sequence.
|
||||
test_one<Iter, Sent, 3>({2, 1, 3}, is_odd, 2, {1, 3, 2});
|
||||
// Longer sequence.
|
||||
test_one<Iter, Sent, 8>({2, 1, 3, 6, 8, 4, 11, 5}, is_odd, 4, {1, 3, 11, 5, 2, 6, 8, 4});
|
||||
// Longer sequence with duplicates.
|
||||
test_one<Iter, Sent, 8>({2, 1, 3, 6, 2, 8, 1, 6}, is_odd, 3, {1, 3, 1, 2, 6, 2, 8, 6});
|
||||
// All elements are the same and satisfy the predicate.
|
||||
test_one<Iter, Sent, 3>({1, 1, 1}, is_odd, 3, {1, 1, 1});
|
||||
// All elements are the same and don't satisfy the predicate.
|
||||
test_one<Iter, Sent, 3>({2, 2, 2}, is_odd, 0, {2, 2, 2});
|
||||
// Already partitioned.
|
||||
test_one<Iter, Sent, 6>({1, 3, 5, 4, 6, 8}, is_odd, 3, {1, 3, 5, 4, 6, 8});
|
||||
// Reverse-partitioned.
|
||||
test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3, {1, 3, 5, 4, 6, 8});
|
||||
// Repeating pattern.
|
||||
test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3, {1, 1, 1, 2, 2, 2});
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void test_iterators_1() {
|
||||
test_iterators_2<Iter, Iter>();
|
||||
test_iterators_2<Iter, sentinel_wrapper<Iter>>();
|
||||
}
|
||||
|
||||
void test_iterators() {
|
||||
test_iterators_1<bidirectional_iterator<int*>>();
|
||||
test_iterators_1<random_access_iterator<int*>>();
|
||||
test_iterators_1<contiguous_iterator<int*>>();
|
||||
test_iterators_1<int*>();
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_iterators();
|
||||
|
||||
{ // The algorithm is stable (equivalent elements remain in the same order).
|
||||
struct OrderedValue {
|
||||
int value;
|
||||
double original_order;
|
||||
bool operator==(const OrderedValue&) const = default;
|
||||
};
|
||||
|
||||
auto is_odd = [](OrderedValue x) { return x.value % 2 != 0; };
|
||||
|
||||
using V = OrderedValue;
|
||||
using Array = std::array<V, 20>;
|
||||
Array orig_in = {
|
||||
V{10, 2.1}, {12, 2.2}, {3, 1.1}, {5, 1.2}, {3, 1.3}, {3, 1.4}, {11, 1.5}, {12, 2.3}, {4, 2.4}, {4, 2.5},
|
||||
{4, 2.6}, {1, 1.6}, {6, 2.7}, {3, 1.7}, {10, 2.8}, {8, 2.9}, {12, 2.10}, {1, 1.8}, {1, 1.9}, {5, 1.10}
|
||||
};
|
||||
Array expected = {
|
||||
V{3, 1.1}, {5, 1.2}, {3, 1.3}, {3, 1.4}, {11, 1.5}, {1, 1.6}, {3, 1.7}, {1, 1.8}, {1, 1.9}, {5, 1.10},
|
||||
{10, 2.1}, {12, 2.2}, {12, 2.3}, {4, 2.4}, {4, 2.5}, {4, 2.6}, {6, 2.7}, {10, 2.8}, {8, 2.9}, {12, 2.10}
|
||||
};
|
||||
|
||||
{
|
||||
auto in = orig_in;
|
||||
std::ranges::stable_partition(in.begin(), in.end(), is_odd);
|
||||
assert(in == expected);
|
||||
}
|
||||
|
||||
{
|
||||
auto in = orig_in;
|
||||
std::ranges::stable_partition(in, is_odd);
|
||||
assert(in == expected);
|
||||
}
|
||||
}
|
||||
|
||||
{ // A custom projection works.
|
||||
const std::array input = {1, -1};
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
auto negate = [](int x) { return -x; };
|
||||
const std::array expected_no_proj = {-1, 1};
|
||||
const std::array expected_with_proj = {1, -1};
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in.begin(), in.end(), is_negative);
|
||||
assert(in == expected_no_proj);
|
||||
}
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in.begin(), in.end(), is_negative, negate);
|
||||
assert(in == expected_with_proj);
|
||||
}
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in, is_negative);
|
||||
assert(in == expected_no_proj);
|
||||
}
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::partition(in, is_negative, negate);
|
||||
assert(in == expected_with_proj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
// Note: `stable_partition` is not `constexpr`.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ void test_all() {
|
||||
in2_out_pred(std::ranges::set_union, in, in2, out, binary_pred);
|
||||
in_pred(std::ranges::remove_if, in, unary_pred);
|
||||
//in_pred(std::ranges::unique, in, binary_pred);
|
||||
//in_pred(std::ranges::partition, in, binary_pred);
|
||||
//in_pred(std::ranges::stable_partition, in, binary_pred);
|
||||
in_pred(std::ranges::partition, in, unary_pred);
|
||||
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);
|
||||
|
||||
@@ -201,8 +201,8 @@ void test_all() {
|
||||
// `rotate` has neither a projection nor a predicate.
|
||||
// `shuffle` has neither a projection nor a predicate.
|
||||
//in_pred(std::ranges::unique, in, &Foo::binary_pred, &Bar::val);
|
||||
//in_pred(std::ranges::partition, in, &Foo::binary_pred, &Bar::val);
|
||||
//in_pred(std::ranges::stable_partition, in, &Foo::binary_pred, &Bar::val);
|
||||
in_pred(std::ranges::partition, in, &Foo::unary_pred, &Bar::val);
|
||||
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);
|
||||
|
||||
@@ -138,9 +138,9 @@ constexpr bool test_all() {
|
||||
//test_mid(std::ranges::rotate, in, mid);
|
||||
//test(std::ranges::shuffle, in, rand_gen);
|
||||
//test(std::ranges::unique, in);
|
||||
//test(std::ranges::partition, in, binary_pred);
|
||||
//if (!std::is_constant_evaluated())
|
||||
// test(std::ranges::stable_partition, in, binary_pred);
|
||||
test(std::ranges::partition, in, unary_pred);
|
||||
if (!std::is_constant_evaluated())
|
||||
test(std::ranges::stable_partition, in, unary_pred);
|
||||
test(std::ranges::sort, in);
|
||||
// TODO: `stable_sort` requires `ranges::rotate` to be implemented.
|
||||
//if (!std::is_constant_evaluated())
|
||||
|
||||
@@ -112,7 +112,7 @@ 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_copy, a, a));
|
||||
//static_assert(test(std::ranges::partition, a, odd));
|
||||
static_assert(test(std::ranges::partition, a, odd));
|
||||
//static_assert(test(std::ranges::partition_copy, a, a, a, odd));
|
||||
//static_assert(test(std::ranges::partition_point, a, odd));
|
||||
static_assert(test(std::ranges::pop_heap, a));
|
||||
@@ -140,7 +140,7 @@ static_assert(test(std::ranges::set_union, a, a, a));
|
||||
//static_assert(test(std::ranges::shuffle, a, g));
|
||||
static_assert(test(std::ranges::sort, a));
|
||||
static_assert(test(std::ranges::sort_heap, a));
|
||||
//static_assert(test(std::ranges::stable_partition, a, odd));
|
||||
static_assert(test(std::ranges::stable_partition, a, odd));
|
||||
static_assert(test(std::ranges::stable_sort, a));
|
||||
//static_assert(test(std::ranges::starts_with, a, a));
|
||||
static_assert(test(std::ranges::swap_ranges, a, a));
|
||||
|
||||
Reference in New Issue
Block a user