Skip to content

Commit bf9bf29

Browse files
[libc++] Implement part of P2562R1: constexpr std::stable_partition (#128868)
Drive-by changes: - Enables no-memory case for Clang. - Enables `robust_re_difference_type.compile.pass.cpp` and `robust_against_proxy_iterators_lifetime_bugs.pass.cpp` test coverage for `std::stable_sort` in constant evaluation since C++26. The changes were missing in the PR making `std::stable_sort` `constexpr`.
1 parent f57756a commit bf9bf29

File tree

5 files changed

+66
-50
lines changed

5 files changed

+66
-50
lines changed

libcxx/include/__algorithm/stable_partition.h

+11-10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <__iterator/advance.h>
1717
#include <__iterator/distance.h>
1818
#include <__iterator/iterator_traits.h>
19+
#include <__memory/construct_at.h>
1920
#include <__memory/destruct_n.h>
2021
#include <__memory/unique_ptr.h>
2122
#include <__memory/unique_temporary_buffer.h>
@@ -33,7 +34,7 @@ _LIBCPP_PUSH_MACROS
3334
_LIBCPP_BEGIN_NAMESPACE_STD
3435

3536
template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
36-
_LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
37+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator __stable_partition_impl(
3738
_ForwardIterator __first,
3839
_ForwardIterator __last,
3940
_Predicate __pred,
@@ -61,7 +62,7 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
6162
// Move the falses into the temporary buffer, and the trues to the front of the line
6263
// Update __first to always point to the end of the trues
6364
value_type* __t = __p.first;
64-
::new ((void*)__t) value_type(_Ops::__iter_move(__first));
65+
std::__construct_at(__t, _Ops::__iter_move(__first));
6566
__d.template __incr<value_type>();
6667
++__t;
6768
_ForwardIterator __i = __first;
@@ -70,7 +71,7 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
7071
*__first = _Ops::__iter_move(__i);
7172
++__first;
7273
} else {
73-
::new ((void*)__t) value_type(_Ops::__iter_move(__i));
74+
std::__construct_at(__t, _Ops::__iter_move(__i));
7475
__d.template __incr<value_type>();
7576
++__t;
7677
}
@@ -116,7 +117,7 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
116117
}
117118

118119
template <class _AlgPolicy, class _Predicate, class _ForwardIterator>
119-
_LIBCPP_HIDE_FROM_ABI _ForwardIterator
120+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
120121
__stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag) {
121122
typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
122123
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
@@ -145,7 +146,7 @@ __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Pred
145146
}
146147

147148
template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
148-
_BidirectionalIterator __stable_partition_impl(
149+
_LIBCPP_CONSTEXPR_SINCE_CXX26 _BidirectionalIterator __stable_partition_impl(
149150
_BidirectionalIterator __first,
150151
_BidirectionalIterator __last,
151152
_Predicate __pred,
@@ -179,7 +180,7 @@ _BidirectionalIterator __stable_partition_impl(
179180
// Move the falses into the temporary buffer, and the trues to the front of the line
180181
// Update __first to always point to the end of the trues
181182
value_type* __t = __p.first;
182-
::new ((void*)__t) value_type(_Ops::__iter_move(__first));
183+
std::__construct_at(__t, _Ops::__iter_move(__first));
183184
__d.template __incr<value_type>();
184185
++__t;
185186
_BidirectionalIterator __i = __first;
@@ -188,7 +189,7 @@ _BidirectionalIterator __stable_partition_impl(
188189
*__first = _Ops::__iter_move(__i);
189190
++__first;
190191
} else {
191-
::new ((void*)__t) value_type(_Ops::__iter_move(__i));
192+
std::__construct_at(__t, _Ops::__iter_move(__i));
192193
__d.template __incr<value_type>();
193194
++__t;
194195
}
@@ -247,7 +248,7 @@ _BidirectionalIterator __stable_partition_impl(
247248
}
248249

249250
template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator>
250-
_LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl(
251+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _BidirectionalIterator __stable_partition_impl(
251252
_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred, bidirectional_iterator_tag) {
252253
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
253254
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
@@ -283,14 +284,14 @@ _LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl(
283284
}
284285

285286
template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _IterCategory>
286-
_LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition(
287+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator __stable_partition(
287288
_ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) {
288289
return std::__stable_partition_impl<_AlgPolicy, __remove_cvref_t<_Predicate>&>(
289290
std::move(__first), std::move(__last), __pred, __iter_category);
290291
}
291292

292293
template <class _ForwardIterator, class _Predicate>
293-
inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
294+
_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX26 _ForwardIterator
294295
stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
295296
using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
296297
return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>(

libcxx/include/algorithm

+1-1
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ template <class InputIterator, class OutputIterator1,
14981498
Predicate pred);
14991499
15001500
template <class ForwardIterator, class Predicate>
1501-
ForwardIterator
1501+
constexpr ForwardIterator // constexpr in C++26
15021502
stable_partition(ForwardIterator first, ForwardIterator last, Predicate pred);
15031503
15041504
template<class ForwardIterator, class Predicate>

libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp

+35-33
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// template<BidirectionalIterator Iter, Predicate<auto, Iter::value_type> Pred>
1212
// requires ShuffleIterator<Iter>
1313
// && CopyConstructible<Pred>
14-
// Iter
14+
// constexpr Iter // constexpr since C++26
1515
// stable_partition(Iter first, Iter last, Pred pred);
1616

1717
#include <algorithm>
@@ -23,21 +23,16 @@
2323
#include "test_iterators.h"
2424
#include "test_macros.h"
2525

26-
struct is_odd
27-
{
28-
bool operator()(const int& i) const {return i & 1;}
26+
struct is_odd {
27+
TEST_CONSTEXPR_CXX26 bool operator()(const int& i) const { return i & 1; }
2928
};
3029

31-
struct odd_first
32-
{
33-
bool operator()(const std::pair<int,int>& p) const
34-
{return p.first & 1;}
30+
struct odd_first {
31+
TEST_CONSTEXPR_CXX26 bool operator()(const std::pair<int, int>& p) const { return p.first & 1; }
3532
};
3633

3734
template <class Iter>
38-
void
39-
test()
40-
{
35+
TEST_CONSTEXPR_CXX26 void test() {
4136
{ // check mixed
4237
typedef std::pair<int,int> P;
4338
P array[] =
@@ -282,10 +277,10 @@ test()
282277
assert(array[9] == P(0, 2));
283278
}
284279
#if TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
285-
// TODO: Re-enable this test once we get recursive inlining fixed.
280+
// TODO: Re-enable this test for GCC once we get recursive inlining fixed.
286281
// For now it trips up GCC due to the use of always_inline.
287-
# if 0
288-
{ // check that the algorithm still works when no memory is available
282+
# if !defined(TEST_COMPILER_GCC)
283+
if (!TEST_IS_CONSTANT_EVALUATED) { // check that the algorithm still works when no memory is available
289284
std::vector<int> vec(150, 3);
290285
vec[5] = 6;
291286
getGlobalMemCounter()->throw_after = 0;
@@ -300,38 +295,45 @@ test()
300295
assert(std::is_partitioned(vec.begin(), vec.end(), [](int i) { return i < 5; }));
301296
getGlobalMemCounter()->reset();
302297
}
303-
# endif
304-
#endif // TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
298+
# endif // !defined(TEST_COMPILER_GCC)
299+
#endif // TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
305300
}
306301

307302
#if TEST_STD_VER >= 11
308303

309-
struct is_null
310-
{
311-
template <class P>
312-
bool operator()(const P& p) {return p == 0;}
304+
struct is_null {
305+
template <class P>
306+
TEST_CONSTEXPR_CXX26 bool operator()(const P& p) {
307+
return p == 0;
308+
}
313309
};
314310

315311
template <class Iter>
316-
void
317-
test1()
318-
{
319-
const unsigned size = 5;
320-
std::unique_ptr<int> array[size];
321-
Iter r = std::stable_partition(Iter(array), Iter(array+size), is_null());
322-
assert(r == Iter(array+size));
312+
TEST_CONSTEXPR_CXX26 void test1() {
313+
const unsigned size = 5;
314+
std::unique_ptr<int> array[size];
315+
Iter r = std::stable_partition(Iter(array), Iter(array + size), is_null());
316+
assert(r == Iter(array + size));
323317
}
324318

325319
#endif // TEST_STD_VER >= 11
326320

327-
int main(int, char**)
328-
{
329-
test<bidirectional_iterator<std::pair<int,int>*> >();
330-
test<random_access_iterator<std::pair<int,int>*> >();
331-
test<std::pair<int,int>*>();
321+
TEST_CONSTEXPR_CXX26 bool test() {
322+
test<bidirectional_iterator<std::pair<int, int>*> >();
323+
test<random_access_iterator<std::pair<int, int>*> >();
324+
test<std::pair<int, int>*>();
332325

333326
#if TEST_STD_VER >= 11
334-
test1<bidirectional_iterator<std::unique_ptr<int>*> >();
327+
test1<bidirectional_iterator<std::unique_ptr<int>*> >();
328+
#endif
329+
330+
return true;
331+
}
332+
333+
int main(int, char**) {
334+
test();
335+
#if TEST_STD_VER >= 26
336+
static_assert(test());
335337
#endif
336338

337339
return 0;

libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -735,12 +735,20 @@ TEST_CONSTEXPR_CXX20 bool test() {
735735
test(simple_in, [&](I b, I e) { (void) std::shuffle(b, e, rand_gen()); });
736736
// TODO: unique
737737
test(simple_in, [&](I b, I e) { (void) std::partition(b, e, is_neg); });
738+
#if TEST_STD_VER < 26
738739
if (!TEST_IS_CONSTANT_EVALUATED)
739-
test(simple_in, [&](I b, I e) { (void) std::stable_partition(b, e, is_neg); });
740+
#endif
741+
{
742+
test(simple_in, [&](I b, I e) { (void)std::stable_partition(b, e, is_neg); });
743+
}
740744
if (!TEST_IS_CONSTANT_EVALUATED)
741-
test(sort_test_in, [&](I b, I e) { (void) std::sort(b, e); });
745+
test(sort_test_in, [&](I b, I e) { (void)std::sort(b, e); });
746+
#if TEST_STD_VER < 26
742747
if (!TEST_IS_CONSTANT_EVALUATED)
743-
test(sort_test_in, [&](I b, I e) { (void) std::stable_sort(b, e); });
748+
#endif
749+
{
750+
test(sort_test_in, [&](I b, I e) { (void)std::stable_sort(b, e); });
751+
}
744752
// TODO: partial_sort
745753
// TODO: nth_element
746754
// TODO: inplace_merge

libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,14 @@ TEST_CONSTEXPR_CXX20 bool all_the_algorithms()
240240
(void)std::sort(first, last, std::less<void*>());
241241
(void)std::sort_heap(first, last);
242242
(void)std::sort_heap(first, last, std::less<void*>());
243-
if (!TEST_IS_CONSTANT_EVALUATED) (void)std::stable_partition(first, last, UnaryTrue());
244-
if (!TEST_IS_CONSTANT_EVALUATED) (void)std::stable_sort(first, last);
245-
if (!TEST_IS_CONSTANT_EVALUATED) (void)std::stable_sort(first, last, std::less<void*>());
243+
#if TEST_STD_VER < 26
244+
if (!TEST_IS_CONSTANT_EVALUATED)
245+
#endif
246+
{
247+
(void)std::stable_partition(first, last, UnaryTrue());
248+
(void)std::stable_sort(first, last);
249+
(void)std::stable_sort(first, last, std::less<void*>());
250+
}
246251
(void)std::swap_ranges(first, last, first2);
247252
(void)std::transform(first, last, first2, UnaryTransform());
248253
(void)std::transform(first, mid, mid, first2, BinaryTransform());

0 commit comments

Comments
 (0)