Skip to content

[libc++] Implement part of P2562R1: constexpr ranges::stable_partition #129839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions libcxx/include/__algorithm/ranges_stable_partition.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
struct __stable_partition {
template <class _Iter, class _Sent, class _Proj, class _Pred>
_LIBCPP_HIDE_FROM_ABI static subrange<__remove_cvref_t<_Iter>>
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX26 subrange<__remove_cvref_t<_Iter>>
__stable_partition_fn_impl(_Iter&& __first, _Sent&& __last, _Pred&& __pred, _Proj&& __proj) {
auto __last_iter = ranges::next(__first, __last);

Expand All @@ -60,15 +60,16 @@ struct __stable_partition {
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 {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 subrange<_Iter>
operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
return __stable_partition_fn_impl(__first, __last, __pred, __proj);
}

template <bidirectional_range _Range,
class _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
requires permutable<iterator_t<_Range>>
_LIBCPP_HIDE_FROM_ABI borrowed_subrange_t<_Range>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 borrowed_subrange_t<_Range>
operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
return __stable_partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
}
Expand Down
6 changes: 4 additions & 2 deletions libcxx/include/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -627,12 +627,14 @@ namespace ranges {
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
constexpr subrange<I> // constexpr since C++26
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
constexpr borrowed_subrange_t<R> // constexpr since C++26
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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
// 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
// constexpr subrange<I> // constexpr since C++26
// 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
// constexpr borrowed_subrange_t<R> // constexpr since C++26
// stable_partition(R&& r, Pred pred, Proj proj = {}); // Since C++20

#include <algorithm>
#include <array>
Expand Down Expand Up @@ -85,7 +87,8 @@ static_assert(!HasStablePartitionRange<R<PermutableNotForwardIterator>, UnaryPre
static_assert(!HasStablePartitionRange<R<PermutableNotSwappable>, UnaryPred>);

template <class Iter, class Sent, std::size_t N, class Pred>
void test_one(std::array<int, N> input, Pred pred, std::size_t partition_point, std::array<int, N> expected) {
TEST_CONSTEXPR_CXX26 void
test_one(std::array<int, N> input, Pred pred, std::size_t partition_point, std::array<int, N> expected) {
auto neg_pred = [&](int x) { return !pred(x); };

{ // (iterator, sentinel) overload.
Expand Down Expand Up @@ -121,7 +124,7 @@ void test_one(std::array<int, N> input, Pred pred, std::size_t partition_point,
}

template <class Iter, class Sent>
void test_iterators_2() {
TEST_CONSTEXPR_CXX26 void test_iterators_2() {
auto is_odd = [](int x) { return x % 2 != 0; };

// Empty sequence.
Expand Down Expand Up @@ -157,19 +160,19 @@ void test_iterators_2() {
}

template <class Iter>
void test_iterators_1() {
TEST_CONSTEXPR_CXX26 void test_iterators_1() {
test_iterators_2<Iter, Iter>();
test_iterators_2<Iter, sentinel_wrapper<Iter>>();
}

void test_iterators() {
TEST_CONSTEXPR_CXX26 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_CONSTEXPR_CXX26 bool test() {
test_iterators();

{ // The algorithm is stable (equivalent elements remain in the same order).
Expand Down Expand Up @@ -238,11 +241,15 @@ void test() {
}
}
}

return true;
}

int main(int, char**) {
test();
// Note: `stable_partition` is not `constexpr`.
#if TEST_STD_VER >= 26
static_assert(test());
#endif

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,12 @@ constexpr bool test_all() {
dangling_1st(std::ranges::shuffle, in, rand_gen());
dangling_1st(std::ranges::unique, in);
dangling_1st(std::ranges::partition, in, unary_pred);
#if TEST_STD_VER < 26
if (!std::is_constant_evaluated())
#endif
{
dangling_1st(std::ranges::stable_partition, in, unary_pred);
}
dangling_1st(std::ranges::sort, in);
if (!std::is_constant_evaluated())
dangling_1st(std::ranges::stable_sort, in);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,12 @@ constexpr bool test_all() {
// For `shuffle`, whether the given generator is invoked via `std::invoke` is not observable.
test(std::ranges::unique, in, &Foo::binary_pred, &Bar::val);
test(std::ranges::partition, in, &Foo::unary_pred, &Bar::val);
#if TEST_STD_VER < 26
if (!std::is_constant_evaluated())
#endif
{
test(std::ranges::stable_partition, in, &Foo::unary_pred, &Bar::val);
}
test(std::ranges::sort, in, &Foo::binary_pred, &Bar::val);
if (!std::is_constant_evaluated())
test(std::ranges::stable_sort, in, &Foo::binary_pred, &Bar::val);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,12 @@ constexpr void run_tests() {
}
test(std::ranges::unique, in);
test(std::ranges::partition, in, unary_pred);
#if TEST_STD_VER < 26
if (!std::is_constant_evaluated())
#endif
{
test(std::ranges::stable_partition, in, unary_pred);
}
test(std::ranges::sort, in);
if (!std::is_constant_evaluated())
test(std::ranges::stable_sort, in);
Expand Down