[libcxx-commits] [libcxx] [libc++] Implement part of P2562R1: constexpr `std::stable_partition` (PR #128868)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Mar 1 09:52:32 PST 2025
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/128868
>From 1514bad72b504d520482f4c42623745b1d38a6b9 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Sun, 2 Mar 2025 01:48:34 +0800
Subject: [PATCH 1/2] [libc++] Implement constexpr `std::stable_partition`
Drive-by:
- Enables no-memory test cases for Clang.
---
libcxx/include/__algorithm/stable_partition.h | 21 ++++++-----
libcxx/include/algorithm | 2 +-
.../alg.partitions/stable_partition.pass.cpp | 37 ++++++++++++-------
...nst_proxy_iterators_lifetime_bugs.pass.cpp | 8 ++++
...robust_re_difference_type.compile.pass.cpp | 11 ++++--
5 files changed, 51 insertions(+), 28 deletions(-)
diff --git a/libcxx/include/__algorithm/stable_partition.h b/libcxx/include/__algorithm/stable_partition.h
index 2ba7239a3a039..b389ae2508c6e 100644
--- a/libcxx/include/__algorithm/stable_partition.h
+++ b/libcxx/include/__algorithm/stable_partition.h
@@ -16,6 +16,7 @@
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
+#include <__memory/construct_at.h>
#include <__memory/destruct_n.h>
#include <__memory/unique_ptr.h>
#include <__memory/unique_temporary_buffer.h>
@@ -33,7 +34,7 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
-_LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator __stable_partition_impl(
_ForwardIterator __first,
_ForwardIterator __last,
_Predicate __pred,
@@ -61,7 +62,7 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
// 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(_Ops::__iter_move(__first));
+ std::__construct_at(__t, _Ops::__iter_move(__first));
__d.template __incr<value_type>();
++__t;
_ForwardIterator __i = __first;
@@ -70,7 +71,7 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
*__first = _Ops::__iter_move(__i);
++__first;
} else {
- ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
+ std::__construct_at(__t, _Ops::__iter_move(__i));
__d.template __incr<value_type>();
++__t;
}
@@ -116,7 +117,7 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
}
template <class _AlgPolicy, class _Predicate, class _ForwardIterator>
-_LIBCPP_HIDE_FROM_ABI _ForwardIterator
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
__stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag) {
typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
@@ -145,7 +146,7 @@ __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Pred
}
template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
-_BidirectionalIterator __stable_partition_impl(
+_LIBCPP_CONSTEXPR_SINCE_CXX26 _BidirectionalIterator __stable_partition_impl(
_BidirectionalIterator __first,
_BidirectionalIterator __last,
_Predicate __pred,
@@ -179,7 +180,7 @@ _BidirectionalIterator __stable_partition_impl(
// 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(_Ops::__iter_move(__first));
+ std::__construct_at(__t, _Ops::__iter_move(__first));
__d.template __incr<value_type>();
++__t;
_BidirectionalIterator __i = __first;
@@ -188,7 +189,7 @@ _BidirectionalIterator __stable_partition_impl(
*__first = _Ops::__iter_move(__i);
++__first;
} else {
- ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
+ std::__construct_at(__t, _Ops::__iter_move(__i));
__d.template __incr<value_type>();
++__t;
}
@@ -247,7 +248,7 @@ _BidirectionalIterator __stable_partition_impl(
}
template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator>
-_LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _BidirectionalIterator __stable_partition_impl(
_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred, bidirectional_iterator_tag) {
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
@@ -283,14 +284,14 @@ _LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl(
}
template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _IterCategory>
-_LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator __stable_partition(
_ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) {
return std::__stable_partition_impl<_AlgPolicy, __remove_cvref_t<_Predicate>&>(
std::move(__first), std::move(__last), __pred, __iter_category);
}
template <class _ForwardIterator, class _Predicate>
-inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>(
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 7b4cb8e496196..0c7cea11d1a91 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1498,7 +1498,7 @@ template <class InputIterator, class OutputIterator1,
Predicate pred);
template <class ForwardIterator, class Predicate>
- ForwardIterator
+ constexpr ForwardIterator // constexpr in C++26
stable_partition(ForwardIterator first, ForwardIterator last, Predicate pred);
template<class ForwardIterator, class Predicate>
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp
index 44027543aaf16..73e12060e059c 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp
@@ -11,7 +11,7 @@
// template<BidirectionalIterator Iter, Predicate<auto, Iter::value_type> Pred>
// requires ShuffleIterator<Iter>
// && CopyConstructible<Pred>
-// Iter
+// constexpr Iter // constexpr since C++26
// stable_partition(Iter first, Iter last, Pred pred);
#include <algorithm>
@@ -25,17 +25,17 @@
struct is_odd
{
- bool operator()(const int& i) const {return i & 1;}
+ TEST_CONSTEXPR_CXX26 bool operator()(const int& i) const {return i & 1;}
};
struct odd_first
{
- bool operator()(const std::pair<int,int>& p) const
+ TEST_CONSTEXPR_CXX26 bool operator()(const std::pair<int,int>& p) const
{return p.first & 1;}
};
template <class Iter>
-void
+TEST_CONSTEXPR_CXX26 void
test()
{
{ // check mixed
@@ -282,9 +282,10 @@ test()
assert(array[9] == P(0, 2));
}
#if TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
- // TODO: Re-enable this test once we get recursive inlining fixed.
+ // TODO: Re-enable this test for GCC once we get recursive inlining fixed.
// For now it trips up GCC due to the use of always_inline.
-# if 0
+# if !defined(TEST_COMPILER_GCC)
+ if (!TEST_IS_CONSTANT_EVALUATED)
{ // check that the algorithm still works when no memory is available
std::vector<int> vec(150, 3);
vec[5] = 6;
@@ -309,11 +310,11 @@ test()
struct is_null
{
template <class P>
- bool operator()(const P& p) {return p == 0;}
+ TEST_CONSTEXPR_CXX26 bool operator()(const P& p) {return p == 0;}
};
template <class Iter>
-void
+TEST_CONSTEXPR_CXX26 void
test1()
{
const unsigned size = 5;
@@ -324,14 +325,22 @@ test1()
#endif // TEST_STD_VER >= 11
-int main(int, char**)
-{
- test<bidirectional_iterator<std::pair<int,int>*> >();
- test<random_access_iterator<std::pair<int,int>*> >();
- test<std::pair<int,int>*>();
+TEST_CONSTEXPR_CXX26 bool test() {
+ test<bidirectional_iterator<std::pair<int, int>*> >();
+ test<random_access_iterator<std::pair<int, int>*> >();
+ test<std::pair<int, int>*>();
#if TEST_STD_VER >= 11
- test1<bidirectional_iterator<std::unique_ptr<int>*> >();
+ test1<bidirectional_iterator<std::unique_ptr<int>*> >();
+#endif
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
#endif
return 0;
diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
index c89d6f5a229e8..6986479da4e72 100644
--- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
+++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
@@ -735,12 +735,20 @@ TEST_CONSTEXPR_CXX20 bool test() {
test(simple_in, [&](I b, I e) { (void) std::shuffle(b, e, rand_gen()); });
// TODO: unique
test(simple_in, [&](I b, I e) { (void) std::partition(b, e, is_neg); });
+#if TEST_STD_VER < 26
if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
test(simple_in, [&](I b, I e) { (void) std::stable_partition(b, e, is_neg); });
+ }
if (!TEST_IS_CONSTANT_EVALUATED)
test(sort_test_in, [&](I b, I e) { (void) std::sort(b, e); });
+#if TEST_STD_VER < 26
if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
test(sort_test_in, [&](I b, I e) { (void) std::stable_sort(b, e); });
+ }
// TODO: partial_sort
// TODO: nth_element
// TODO: inplace_merge
diff --git a/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp b/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
index 7d6be48430179..187113b0bdeae 100644
--- a/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
+++ b/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
@@ -240,9 +240,14 @@ TEST_CONSTEXPR_CXX20 bool all_the_algorithms()
(void)std::sort(first, last, std::less<void*>());
(void)std::sort_heap(first, last);
(void)std::sort_heap(first, last, std::less<void*>());
- if (!TEST_IS_CONSTANT_EVALUATED) (void)std::stable_partition(first, last, UnaryTrue());
- if (!TEST_IS_CONSTANT_EVALUATED) (void)std::stable_sort(first, last);
- if (!TEST_IS_CONSTANT_EVALUATED) (void)std::stable_sort(first, last, std::less<void*>());
+#if TEST_STD_VER < 26
+ if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+ {
+ (void)std::stable_partition(first, last, UnaryTrue());
+ (void)std::stable_sort(first, last);
+ (void)std::stable_sort(first, last, std::less<void*>());
+ }
(void)std::swap_ranges(first, last, first2);
(void)std::transform(first, last, first2, UnaryTransform());
(void)std::transform(first, mid, mid, first2, BinaryTransform());
>From 93d916749c0d40b7da5e381418e7f15ad34cdbcf Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Sun, 2 Mar 2025 01:51:34 +0800
Subject: [PATCH 2/2] clang-format some test files
---
.../alg.partitions/stable_partition.pass.cpp | 39 ++++++++-----------
...nst_proxy_iterators_lifetime_bugs.pass.cpp | 6 +--
2 files changed, 19 insertions(+), 26 deletions(-)
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp
index 73e12060e059c..4d843fdfc4169 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp
@@ -23,21 +23,16 @@
#include "test_iterators.h"
#include "test_macros.h"
-struct is_odd
-{
- TEST_CONSTEXPR_CXX26 bool operator()(const int& i) const {return i & 1;}
+struct is_odd {
+ TEST_CONSTEXPR_CXX26 bool operator()(const int& i) const { return i & 1; }
};
-struct odd_first
-{
- TEST_CONSTEXPR_CXX26 bool operator()(const std::pair<int,int>& p) const
- {return p.first & 1;}
+struct odd_first {
+ TEST_CONSTEXPR_CXX26 bool operator()(const std::pair<int, int>& p) const { return p.first & 1; }
};
template <class Iter>
-TEST_CONSTEXPR_CXX26 void
-test()
-{
+TEST_CONSTEXPR_CXX26 void test() {
{ // check mixed
typedef std::pair<int,int> P;
P array[] =
@@ -285,8 +280,7 @@ test()
// TODO: Re-enable this test for GCC once we get recursive inlining fixed.
// For now it trips up GCC due to the use of always_inline.
# if !defined(TEST_COMPILER_GCC)
- if (!TEST_IS_CONSTANT_EVALUATED)
- { // check that the algorithm still works when no memory is available
+ if (!TEST_IS_CONSTANT_EVALUATED) { // check that the algorithm still works when no memory is available
std::vector<int> vec(150, 3);
vec[5] = 6;
getGlobalMemCounter()->throw_after = 0;
@@ -307,20 +301,19 @@ test()
#if TEST_STD_VER >= 11
-struct is_null
-{
- template <class P>
- TEST_CONSTEXPR_CXX26 bool operator()(const P& p) {return p == 0;}
+struct is_null {
+ template <class P>
+ TEST_CONSTEXPR_CXX26 bool operator()(const P& p) {
+ return p == 0;
+ }
};
template <class Iter>
-TEST_CONSTEXPR_CXX26 void
-test1()
-{
- const unsigned size = 5;
- std::unique_ptr<int> array[size];
- Iter r = std::stable_partition(Iter(array), Iter(array+size), is_null());
- assert(r == Iter(array+size));
+TEST_CONSTEXPR_CXX26 void test1() {
+ const unsigned size = 5;
+ std::unique_ptr<int> array[size];
+ Iter r = std::stable_partition(Iter(array), Iter(array + size), is_null());
+ assert(r == Iter(array + size));
}
#endif // TEST_STD_VER >= 11
diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
index 6986479da4e72..e00f123538df8 100644
--- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
+++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
@@ -739,15 +739,15 @@ TEST_CONSTEXPR_CXX20 bool test() {
if (!TEST_IS_CONSTANT_EVALUATED)
#endif
{
- test(simple_in, [&](I b, I e) { (void) std::stable_partition(b, e, is_neg); });
+ test(simple_in, [&](I b, I e) { (void)std::stable_partition(b, e, is_neg); });
}
if (!TEST_IS_CONSTANT_EVALUATED)
- test(sort_test_in, [&](I b, I e) { (void) std::sort(b, e); });
+ test(sort_test_in, [&](I b, I e) { (void)std::sort(b, e); });
#if TEST_STD_VER < 26
if (!TEST_IS_CONSTANT_EVALUATED)
#endif
{
- test(sort_test_in, [&](I b, I e) { (void) std::stable_sort(b, e); });
+ test(sort_test_in, [&](I b, I e) { (void)std::stable_sort(b, e); });
}
// TODO: partial_sort
// TODO: nth_element
More information about the libcxx-commits
mailing list