Skip to content

Commit 438e2cc

Browse files
PaulXiCaofrederick-vs-jaldionne
authored
[libc++] Make std::stable_sort constexpr friendly (#110320)
Implementing `constexpr std::stable_sort`. This is part of P2562R1, tracked via issue #105360. Closes #119394 Co-authored-by: A. Jiang <[email protected]> Co-authored-by: Louis Dionne <[email protected]>
1 parent b1751fa commit 438e2cc

File tree

9 files changed

+278
-222
lines changed

9 files changed

+278
-222
lines changed

libcxx/docs/Status/Cxx2cPapers.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"`P2497R0 <https://wg21.link/P2497R0>`__","Testing for success or failure of ``<charconv>`` functions","2023-06 (Varna)","|Complete|","18",""
33
"`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","",""
44
"`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","","",""
5-
"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","","",""
5+
"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Partial|","20.0",""
66
"`P2545R4 <https://wg21.link/P2545R4>`__","Read-Copy Update (RCU)","2023-06 (Varna)","","",""
77
"`P2530R3 <https://wg21.link/P2530R3>`__","Hazard Pointers for C++26","2023-06 (Varna)","","",""
88
"`P2538R1 <https://wg21.link/P2538R1>`__","ADL-proof ``std::projected``","2023-06 (Varna)","|Complete|","18",""

libcxx/include/__algorithm/inplace_merge.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ class __invert // invert the sense of a comparison
4444
_Predicate __p_;
4545

4646
public:
47-
_LIBCPP_HIDE_FROM_ABI __invert() {}
47+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __invert() {}
4848

49-
_LIBCPP_HIDE_FROM_ABI explicit __invert(_Predicate __p) : __p_(__p) {}
49+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit __invert(_Predicate __p) : __p_(__p) {}
5050

5151
template <class _T1>
52-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x) {
52+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool operator()(const _T1& __x) {
5353
return !__p_(__x);
5454
}
5555

5656
template <class _T1, class _T2>
57-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x, const _T2& __y) {
57+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool operator()(const _T1& __x, const _T2& __y) {
5858
return __p_(__y, __x);
5959
}
6060
};
@@ -66,7 +66,7 @@ template <class _AlgPolicy,
6666
class _InputIterator2,
6767
class _Sent2,
6868
class _OutputIterator>
69-
_LIBCPP_HIDE_FROM_ABI void __half_inplace_merge(
69+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __half_inplace_merge(
7070
_InputIterator1 __first1,
7171
_Sent1 __last1,
7272
_InputIterator2 __first2,
@@ -91,7 +91,7 @@ _LIBCPP_HIDE_FROM_ABI void __half_inplace_merge(
9191
}
9292

9393
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
94-
_LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge(
94+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __buffered_inplace_merge(
9595
_BidirectionalIterator __first,
9696
_BidirectionalIterator __middle,
9797
_BidirectionalIterator __last,
@@ -122,7 +122,7 @@ _LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge(
122122
}
123123

124124
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
125-
void __inplace_merge(
125+
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge(
126126
_BidirectionalIterator __first,
127127
_BidirectionalIterator __middle,
128128
_BidirectionalIterator __last,

libcxx/include/__algorithm/sort.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
240240
// Sort the iterator range [__first, __last) using the comparator __comp using
241241
// the insertion sort algorithm.
242242
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
243-
_LIBCPP_HIDE_FROM_ABI void
243+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
244244
__insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) {
245245
using _Ops = _IterOps<_AlgPolicy>;
246246

libcxx/include/__algorithm/stable_sort.h

+40-36
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <__cstddef/ptrdiff_t.h>
2020
#include <__debug_utils/strict_weak_ordering_check.h>
2121
#include <__iterator/iterator_traits.h>
22+
#include <__memory/construct_at.h>
2223
#include <__memory/destruct_n.h>
2324
#include <__memory/unique_ptr.h>
2425
#include <__memory/unique_temporary_buffer.h>
@@ -41,7 +42,7 @@ _LIBCPP_PUSH_MACROS
4142
_LIBCPP_BEGIN_NAMESPACE_STD
4243

4344
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
44-
_LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
45+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __insertion_sort_move(
4546
_BidirectionalIterator __first1,
4647
_BidirectionalIterator __last1,
4748
typename iterator_traits<_BidirectionalIterator>::value_type* __first2,
@@ -53,19 +54,19 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
5354
__destruct_n __d(0);
5455
unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
5556
value_type* __last2 = __first2;
56-
::new ((void*)__last2) value_type(_Ops::__iter_move(__first1));
57+
std::__construct_at(__last2, _Ops::__iter_move(__first1));
5758
__d.template __incr<value_type>();
5859
for (++__last2; ++__first1 != __last1; ++__last2) {
5960
value_type* __j2 = __last2;
6061
value_type* __i2 = __j2;
6162
if (__comp(*__first1, *--__i2)) {
62-
::new ((void*)__j2) value_type(std::move(*__i2));
63+
std::__construct_at(__j2, std::move(*__i2));
6364
__d.template __incr<value_type>();
6465
for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
6566
*__j2 = std::move(*__i2);
6667
*__j2 = _Ops::__iter_move(__first1);
6768
} else {
68-
::new ((void*)__j2) value_type(_Ops::__iter_move(__first1));
69+
std::__construct_at(__j2, _Ops::__iter_move(__first1));
6970
__d.template __incr<value_type>();
7071
}
7172
}
@@ -74,7 +75,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
7475
}
7576

7677
template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2>
77-
_LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
78+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
7879
_InputIterator1 __first1,
7980
_InputIterator1 __last1,
8081
_InputIterator2 __first2,
@@ -89,30 +90,30 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
8990
for (; true; ++__result) {
9091
if (__first1 == __last1) {
9192
for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr<value_type>())
92-
::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
93+
std::__construct_at(__result, _Ops::__iter_move(__first2));
9394
__h.release();
9495
return;
9596
}
9697
if (__first2 == __last2) {
9798
for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr<value_type>())
98-
::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
99+
std::__construct_at(__result, _Ops::__iter_move(__first1));
99100
__h.release();
100101
return;
101102
}
102103
if (__comp(*__first2, *__first1)) {
103-
::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
104+
std::__construct_at(__result, _Ops::__iter_move(__first2));
104105
__d.template __incr<value_type>();
105106
++__first2;
106107
} else {
107-
::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
108+
std::__construct_at(__result, _Ops::__iter_move(__first1));
108109
__d.template __incr<value_type>();
109110
++__first1;
110111
}
111112
}
112113
}
113114

114115
template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
115-
_LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
116+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_assign(
116117
_InputIterator1 __first1,
117118
_InputIterator1 __last1,
118119
_InputIterator2 __first2,
@@ -140,41 +141,43 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
140141
}
141142

142143
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
143-
void __stable_sort(_RandomAccessIterator __first,
144-
_RandomAccessIterator __last,
145-
_Compare __comp,
146-
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
147-
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
148-
ptrdiff_t __buff_size);
144+
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort(
145+
_RandomAccessIterator __first,
146+
_RandomAccessIterator __last,
147+
_Compare __comp,
148+
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
149+
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
150+
ptrdiff_t __buff_size);
149151

150152
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
151-
void __stable_sort_move(_RandomAccessIterator __first1,
152-
_RandomAccessIterator __last1,
153-
_Compare __comp,
154-
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
155-
typename iterator_traits<_RandomAccessIterator>::value_type* __first2) {
153+
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
154+
_RandomAccessIterator __first1,
155+
_RandomAccessIterator __last1,
156+
_Compare __comp,
157+
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
158+
typename iterator_traits<_RandomAccessIterator>::value_type* __first2) {
156159
using _Ops = _IterOps<_AlgPolicy>;
157160

158161
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
159162
switch (__len) {
160163
case 0:
161164
return;
162165
case 1:
163-
::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
166+
std::__construct_at(__first2, _Ops::__iter_move(__first1));
164167
return;
165168
case 2:
166169
__destruct_n __d(0);
167170
unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
168171
if (__comp(*--__last1, *__first1)) {
169-
::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
172+
std::__construct_at(__first2, _Ops::__iter_move(__last1));
170173
__d.template __incr<value_type>();
171174
++__first2;
172-
::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
175+
std::__construct_at(__first2, _Ops::__iter_move(__first1));
173176
} else {
174-
::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
177+
std::__construct_at(__first2, _Ops::__iter_move(__first1));
175178
__d.template __incr<value_type>();
176179
++__first2;
177-
::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
180+
std::__construct_at(__first2, _Ops::__iter_move(__last1));
178181
}
179182
__h2.release();
180183
return;
@@ -218,12 +221,13 @@ _LIBCPP_HIDE_FROM_ABI constexpr unsigned __radix_sort_max_bound() {
218221
#endif // _LIBCPP_STD_VER >= 17
219222

220223
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
221-
void __stable_sort(_RandomAccessIterator __first,
222-
_RandomAccessIterator __last,
223-
_Compare __comp,
224-
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
225-
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
226-
ptrdiff_t __buff_size) {
224+
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort(
225+
_RandomAccessIterator __first,
226+
_RandomAccessIterator __last,
227+
_Compare __comp,
228+
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
229+
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
230+
ptrdiff_t __buff_size) {
227231
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
228232
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
229233
switch (__len) {
@@ -279,7 +283,7 @@ void __stable_sort(_RandomAccessIterator __first,
279283
}
280284

281285
template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
282-
inline _LIBCPP_HIDE_FROM_ABI void
286+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
283287
__stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
284288
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
285289
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
@@ -298,18 +302,18 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last,
298302
}
299303

300304
template <class _RandomAccessIterator, class _Compare>
301-
inline _LIBCPP_HIDE_FROM_ABI void
305+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
302306
stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
303307
std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
304308
}
305309

306310
template <class _RandomAccessIterator>
307-
inline _LIBCPP_HIDE_FROM_ABI void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
311+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
312+
stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
308313
std::stable_sort(__first, __last, __less<>());
309314
}
310315

311316
_LIBCPP_END_NAMESPACE_STD
312-
313317
_LIBCPP_POP_MACROS
314318

315319
#endif // _LIBCPP___ALGORITHM_STABLE_SORT_H

libcxx/include/__memory/destruct_n.h

+10-10
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,35 @@ struct __destruct_n {
2525
size_t __size_;
2626

2727
template <class _Tp>
28-
_LIBCPP_HIDE_FROM_ABI void __process(_Tp* __p, false_type) _NOEXCEPT {
28+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __process(_Tp* __p, false_type) _NOEXCEPT {
2929
for (size_t __i = 0; __i < __size_; ++__i, ++__p)
3030
__p->~_Tp();
3131
}
3232

3333
template <class _Tp>
34-
_LIBCPP_HIDE_FROM_ABI void __process(_Tp*, true_type) _NOEXCEPT {}
34+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __process(_Tp*, true_type) _NOEXCEPT {}
3535

36-
_LIBCPP_HIDE_FROM_ABI void __incr(false_type) _NOEXCEPT { ++__size_; }
37-
_LIBCPP_HIDE_FROM_ABI void __incr(true_type) _NOEXCEPT {}
36+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(false_type) _NOEXCEPT { ++__size_; }
37+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(true_type) _NOEXCEPT {}
3838

39-
_LIBCPP_HIDE_FROM_ABI void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; }
40-
_LIBCPP_HIDE_FROM_ABI void __set(size_t, true_type) _NOEXCEPT {}
39+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; }
40+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t, true_type) _NOEXCEPT {}
4141

4242
public:
43-
_LIBCPP_HIDE_FROM_ABI explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {}
43+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {}
4444

4545
template <class _Tp>
46-
_LIBCPP_HIDE_FROM_ABI void __incr() _NOEXCEPT {
46+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr() _NOEXCEPT {
4747
__incr(integral_constant<bool, is_trivially_destructible<_Tp>::value>());
4848
}
4949

5050
template <class _Tp>
51-
_LIBCPP_HIDE_FROM_ABI void __set(size_t __s, _Tp*) _NOEXCEPT {
51+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, _Tp*) _NOEXCEPT {
5252
__set(__s, integral_constant<bool, is_trivially_destructible<_Tp>::value>());
5353
}
5454

5555
template <class _Tp>
56-
_LIBCPP_HIDE_FROM_ABI void operator()(_Tp* __p) _NOEXCEPT {
56+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void operator()(_Tp* __p) _NOEXCEPT {
5757
__process(__p, integral_constant<bool, is_trivially_destructible<_Tp>::value>());
5858
}
5959
};

libcxx/include/algorithm

+2-2
Original file line numberDiff line numberDiff line change
@@ -1530,11 +1530,11 @@ template <class RandomAccessIterator, class Compare>
15301530
sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
15311531
15321532
template <class RandomAccessIterator>
1533-
void
1533+
constexpr void // constexpr in C++26
15341534
stable_sort(RandomAccessIterator first, RandomAccessIterator last);
15351535
15361536
template <class RandomAccessIterator, class Compare>
1537-
void
1537+
constexpr void // constexpr in C++26
15381538
stable_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
15391539
15401540
template <class RandomAccessIterator>

libcxx/include/module.modulemap

+4-1
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,10 @@ module std [system] {
819819
module sort_heap { header "__algorithm/sort_heap.h" }
820820
module sort { header "__algorithm/sort.h" }
821821
module stable_partition { header "__algorithm/stable_partition.h" }
822-
module stable_sort { header "__algorithm/stable_sort.h" }
822+
module stable_sort {
823+
header "__algorithm/stable_sort.h"
824+
export std.memory.unique_temporary_buffer // TODO: Workaround for https://github.com/llvm/llvm-project/issues/120108
825+
}
823826
module swap_ranges { header "__algorithm/swap_ranges.h" }
824827
module three_way_comp_ref_type { header "__algorithm/three_way_comp_ref_type.h" }
825828
module transform { header "__algorithm/transform.h" }

0 commit comments

Comments
 (0)