Skip to content
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

[libc++][C++26] P2562R1: constexpr Stable Sorting #110320

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 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
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"`P2497R0 <https://wg21.link/P2497R0>`__","Testing for success or failure of ``<charconv>`` functions","2023-06 (Varna)","|Complete|","18.0",""
"`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","",""
"`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","","",""
"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","","",""
"`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Partial|","20.0",""
"`P2545R4 <https://wg21.link/P2545R4>`__","Read-Copy Update (RCU)","2023-06 (Varna)","","",""
"`P2530R3 <https://wg21.link/P2530R3>`__","Hazard Pointers for C++26","2023-06 (Varna)","","",""
"`P2538R1 <https://wg21.link/P2538R1>`__","ADL-proof ``std::projected``","2023-06 (Varna)","|Complete|","18.0",""
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__algorithm/sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
// Sort the iterator range [__first, __last) using the comparator __comp using
// the insertion sort algorithm.
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
_LIBCPP_HIDE_FROM_ABI void
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
__insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) {
using _Ops = _IterOps<_AlgPolicy>;

Expand Down
103 changes: 68 additions & 35 deletions libcxx/include/__algorithm/stable_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ _LIBCPP_PUSH_MACROS

_LIBCPP_BEGIN_NAMESPACE_STD

// Workaround for "constexpr placement new" bug in gcc (fixed in 14.2).
// See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715.
#define __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \
do { \
::new ((void*)__placement_arg) __type(__new_initializer_func(__new_initializer_arg)); \
} while (0)
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \
do { \
[__placement_arg, &__new_initializer_arg] { \
__STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \
}(); \
} while (0)
#else
# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \
do { \
__STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \
} while (0)
#endif
PaulXiCao marked this conversation as resolved.
Show resolved Hide resolved

template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
_LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
_BidirectionalIterator __first1,
Expand All @@ -47,19 +67,22 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
value_type* __last2 = __first2;
::new ((void*)__last2) value_type(_Ops::__iter_move(__first1));
__STABLE_SORT_NEW(__last2, value_type, _Ops::__iter_move, __first1);
__d.template __incr<value_type>();
for (++__last2; ++__first1 != __last1; ++__last2) {
value_type* __j2 = __last2;
value_type* __i2 = __j2;
if (__comp(*__first1, *--__i2)) {
::new ((void*)__j2) value_type(std::move(*__i2));
{
value_type& __tmp = *__i2;
__STABLE_SORT_NEW(__j2, value_type, std::move, __tmp);
}
__d.template __incr<value_type>();
for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
*__j2 = std::move(*__i2);
*__j2 = _Ops::__iter_move(__first1);
} else {
::new ((void*)__j2) value_type(_Ops::__iter_move(__first1));
__STABLE_SORT_NEW(__j2, value_type, _Ops::__iter_move, __first1);
__d.template __incr<value_type>();
}
}
Expand All @@ -68,7 +91,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
}

template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2>
_LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct(
_InputIterator1 __first1,
_InputIterator1 __last1,
_InputIterator2 __first2,
Expand All @@ -83,30 +106,35 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
for (; true; ++__result) {
if (__first1 == __last1) {
for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr<value_type>())
::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
__STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2);
__h.release();
return;
}
if (__first2 == __last2) {
for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr<value_type>())
::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
__STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
__h.release();
return;
}
if (__comp(*__first2, *__first1)) {
::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
__STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2);
__d.template __incr<value_type>();
++__first2;
} else {
::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
// __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1);
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)
[__result, &__first1] { ::new (__result) value_type(_Ops::__iter_move(__first1)); }();
#else
::new (__result) value_type(_Ops::__iter_move(__first1));
PaulXiCao marked this conversation as resolved.
Show resolved Hide resolved
#endif
__d.template __incr<value_type>();
++__first1;
}
}
}

template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
_LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_assign(
PaulXiCao marked this conversation as resolved.
Show resolved Hide resolved
_InputIterator1 __first1,
_InputIterator1 __last1,
_InputIterator2 __first2,
Expand Down Expand Up @@ -134,41 +162,43 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
}

template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void __stable_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
ptrdiff_t __buff_size);
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort(
_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
ptrdiff_t __buff_size);

template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void __stable_sort_move(_RandomAccessIterator __first1,
_RandomAccessIterator __last1,
_Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __first2) {
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move(
_RandomAccessIterator __first1,
_RandomAccessIterator __last1,
_Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __first2) {
using _Ops = _IterOps<_AlgPolicy>;

typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
switch (__len) {
case 0:
return;
case 1:
::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
__STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
return;
case 2:
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
if (__comp(*--__last1, *__first1)) {
::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
__STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
__d.template __incr<value_type>();
++__first2;
::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
__STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
} else {
::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
__STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1);
__d.template __incr<value_type>();
++__first2;
::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
__STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1);
}
__h2.release();
return;
Expand All @@ -190,12 +220,13 @@ struct __stable_sort_switch {
};

template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void __stable_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
ptrdiff_t __buff_size) {
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort(
_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __buff,
ptrdiff_t __buff_size) {
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
switch (__len) {
Expand Down Expand Up @@ -235,7 +266,7 @@ void __stable_sort(_RandomAccessIterator __first,
}

template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI void
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
__stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
Expand All @@ -254,18 +285,20 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last,
}

template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI void
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}

template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
std::stable_sort(__first, __last, __less<>());
}

#undef __STABLE_SORT_NEW
#undef __STABLE_SORT_NEW_IMPL
_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___ALGORITHM_STABLE_SORT_H
20 changes: 10 additions & 10 deletions libcxx/include/__memory/destruct_n.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,35 @@ struct __destruct_n {
size_t __size_;

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

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __process(_Tp*, true_type) _NOEXCEPT {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __process(_Tp*, true_type) _NOEXCEPT {}

_LIBCPP_HIDE_FROM_ABI void __incr(false_type) _NOEXCEPT { ++__size_; }
_LIBCPP_HIDE_FROM_ABI void __incr(true_type) _NOEXCEPT {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(false_type) _NOEXCEPT { ++__size_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(true_type) _NOEXCEPT {}

_LIBCPP_HIDE_FROM_ABI void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; }
_LIBCPP_HIDE_FROM_ABI void __set(size_t, true_type) _NOEXCEPT {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t, true_type) _NOEXCEPT {}

public:
_LIBCPP_HIDE_FROM_ABI explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __incr() _NOEXCEPT {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr() _NOEXCEPT {
__incr(integral_constant<bool, is_trivially_destructible<_Tp>::value>());
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __set(size_t __s, _Tp*) _NOEXCEPT {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, _Tp*) _NOEXCEPT {
__set(__s, integral_constant<bool, is_trivially_destructible<_Tp>::value>());
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void operator()(_Tp* __p) _NOEXCEPT {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void operator()(_Tp* __p) _NOEXCEPT {
__process(__p, integral_constant<bool, is_trivially_destructible<_Tp>::value>());
}
};
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -1530,11 +1530,11 @@ template <class RandomAccessIterator, class Compare>
sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

template <class RandomAccessIterator>
void
constexpr void // constexpr in C++26
stable_sort(RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
void
constexpr void // constexpr in C++26
stable_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

template <class RandomAccessIterator>
Expand Down
Loading
Loading