Skip to content

Commit dc017e0

Browse files
committed
[libc++] Forward ranges::sort to instantiations in the dylib
This patch removes `_WrapAlgPolicy` and related functionality. Instead, we explicitly forward to `__sort` now if we have an instantiation inside the dylib. If we don't we just call `__introsort`. Reviewed By: ldionne, #libc Spies: sstefan1, libcxx-commits Differential Revision: https://reviews.llvm.org/D140824
1 parent 57690a8 commit dc017e0

File tree

3 files changed

+109
-119
lines changed

3 files changed

+109
-119
lines changed

libcxx/include/__algorithm/sort.h

Lines changed: 92 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <__memory/destruct_n.h>
3030
#include <__memory/unique_ptr.h>
3131
#include <__type_traits/conditional.h>
32+
#include <__type_traits/disjunction.h>
3233
#include <__type_traits/is_arithmetic.h>
3334
#include <__utility/move.h>
3435
#include <__utility/pair.h>
@@ -41,52 +42,6 @@
4142

4243
_LIBCPP_BEGIN_NAMESPACE_STD
4344

44-
// Wraps an algorithm policy tag and a comparator in a single struct, used to pass the policy tag around without
45-
// changing the number of template arguments (to keep the ABI stable). This is only used for the "range" policy tag.
46-
//
47-
// To create an object of this type, use `_WrapAlgPolicy<T, C>::type` -- see the specialization below for the rationale.
48-
template <class _PolicyT, class _CompT, class = void>
49-
struct _WrapAlgPolicy {
50-
using type = _WrapAlgPolicy;
51-
52-
using _AlgPolicy = _PolicyT;
53-
using _Comp = _CompT;
54-
_Comp& __comp;
55-
56-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
57-
_WrapAlgPolicy(_Comp& __c) : __comp(__c) {}
58-
};
59-
60-
// Specialization for the "classic" policy tag that avoids creating a struct and simply defines an alias for the
61-
// comparator. When unwrapping, a pristine comparator is always considered to have the "classic" tag attached. Passing
62-
// the pristine comparator where possible allows using template instantiations from the dylib.
63-
template <class _PolicyT, class _CompT>
64-
struct _WrapAlgPolicy<_PolicyT, _CompT, __enable_if_t<std::is_same<_PolicyT, _ClassicAlgPolicy>::value> > {
65-
using type = _CompT;
66-
};
67-
68-
// Unwraps a pristine functor (e.g. `std::less`) as if it were wrapped using `_WrapAlgPolicy`. The policy tag is always
69-
// set to "classic".
70-
template <class _CompT>
71-
struct _UnwrapAlgPolicy {
72-
using _AlgPolicy = _ClassicAlgPolicy;
73-
using _Comp = _CompT;
74-
75-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
76-
_Comp __get_comp(_Comp __comp) { return __comp; }
77-
};
78-
79-
// Unwraps a `_WrapAlgPolicy` struct.
80-
template <class... _Ts>
81-
struct _UnwrapAlgPolicy<_WrapAlgPolicy<_Ts...> > {
82-
using _Wrapped = _WrapAlgPolicy<_Ts...>;
83-
using _AlgPolicy = typename _Wrapped::_AlgPolicy;
84-
using _Comp = typename _Wrapped::_Comp;
85-
86-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
87-
_Comp __get_comp(_Wrapped& __w) { return __w.__comp; }
88-
};
89-
9045
// stable, 2-3 compares, 0-2 swaps
9146

9247
template <class _AlgPolicy, class _Compare, class _ForwardIterator>
@@ -151,27 +106,22 @@ unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator
151106

152107
// stable, 4-10 compares, 0-9 swaps
153108

154-
template <class _WrappedComp, class _ForwardIterator>
155-
_LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3,
156-
_ForwardIterator __x4, _ForwardIterator __x5, _WrappedComp __wrapped_comp) {
157-
using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
158-
using _AlgPolicy = typename _Unwrap::_AlgPolicy;
109+
template <class _AlgPolicy, class _Comp, class _ForwardIterator>
110+
_LIBCPP_HIDE_FROM_ABI unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3,
111+
_ForwardIterator __x4, _ForwardIterator __x5, _Comp __comp) {
159112
using _Ops = _IterOps<_AlgPolicy>;
160113

161-
using _Compare = typename _Unwrap::_Comp;
162-
_Compare __c = _Unwrap::__get_comp(__wrapped_comp);
163-
164-
unsigned __r = std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
165-
if (__c(*__x5, *__x4)) {
114+
unsigned __r = std::__sort4<_AlgPolicy, _Comp>(__x1, __x2, __x3, __x4, __comp);
115+
if (__comp(*__x5, *__x4)) {
166116
_Ops::iter_swap(__x4, __x5);
167117
++__r;
168-
if (__c(*__x4, *__x3)) {
118+
if (__comp(*__x4, *__x3)) {
169119
_Ops::iter_swap(__x3, __x4);
170120
++__r;
171-
if (__c(*__x3, *__x2)) {
121+
if (__comp(*__x3, *__x2)) {
172122
_Ops::iter_swap(__x2, __x3);
173123
++__r;
174-
if (__c(*__x2, *__x1)) {
124+
if (__comp(*__x2, *__x1)) {
175125
_Ops::iter_swap(__x1, __x2);
176126
++__r;
177127
}
@@ -181,16 +131,6 @@ _LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _F
181131
return __r;
182132
}
183133

184-
template <class _AlgPolicy, class _Compare, class _ForwardIterator>
185-
_LIBCPP_HIDE_FROM_ABI unsigned __sort5_wrap_policy(
186-
_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4, _ForwardIterator __x5,
187-
_Compare __c) {
188-
using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
189-
_WrappedComp __wrapped_comp(__c);
190-
return std::__sort5<_WrappedComp, _ForwardIterator>(
191-
std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __wrapped_comp);
192-
}
193-
194134
// The comparator being simple is a prerequisite for using the branchless optimization.
195135
template <class _Tp>
196136
struct __is_simple_comparator : false_type {};
@@ -299,7 +239,8 @@ template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
299239
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
300240
__sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
301241
_RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
302-
std::__sort5_wrap_policy<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __x5, __c);
242+
std::__sort5<_AlgPolicy, _Compare, _RandomAccessIterator>(
243+
std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __c);
303244
}
304245

305246
// Assumes size > 0
@@ -370,16 +311,11 @@ __insertion_sort_unguarded(_RandomAccessIterator __first, _RandomAccessIterator
370311
}
371312
}
372313

373-
template <class _WrappedComp, class _RandomAccessIterator>
374-
_LIBCPP_HIDDEN bool __insertion_sort_incomplete(
375-
_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
376-
using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
377-
using _AlgPolicy = typename _Unwrap::_AlgPolicy;
314+
template <class _AlgPolicy, class _Comp, class _RandomAccessIterator>
315+
_LIBCPP_HIDE_FROM_ABI bool __insertion_sort_incomplete(
316+
_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
378317
using _Ops = _IterOps<_AlgPolicy>;
379318

380-
using _Compare = typename _Unwrap::_Comp;
381-
_Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
382-
383319
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
384320
switch (__last - __first) {
385321
case 0:
@@ -390,21 +326,21 @@ _LIBCPP_HIDDEN bool __insertion_sort_incomplete(
390326
_Ops::iter_swap(__first, __last);
391327
return true;
392328
case 3:
393-
std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), --__last, __comp);
329+
std::__sort3_maybe_branchless<_AlgPolicy, _Comp>(__first, __first + difference_type(1), --__last, __comp);
394330
return true;
395331
case 4:
396-
std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
332+
std::__sort4_maybe_branchless<_AlgPolicy, _Comp>(
397333
__first, __first + difference_type(1), __first + difference_type(2), --__last, __comp);
398334
return true;
399335
case 5:
400-
std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
336+
std::__sort5_maybe_branchless<_AlgPolicy, _Comp>(
401337
__first, __first + difference_type(1), __first + difference_type(2), __first + difference_type(3),
402338
--__last, __comp);
403339
return true;
404340
}
405341
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
406342
_RandomAccessIterator __j = __first + difference_type(2);
407-
std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), __j, __comp);
343+
std::__sort3_maybe_branchless<_AlgPolicy, _Comp>(__first, __first + difference_type(1), __j, __comp);
408344
const unsigned __limit = 8;
409345
unsigned __count = 0;
410346
for (_RandomAccessIterator __i = __j + difference_type(1); __i != __last; ++__i) {
@@ -862,10 +798,8 @@ void __introsort(_RandomAccessIterator __first,
862798
// [__first, __i) < *__i and *__i <= [__i+1, __last)
863799
// If we were given a perfect partition, see if insertion sort is quick...
864800
if (__ret.second) {
865-
using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
866-
_WrappedComp __wrapped_comp(__comp);
867-
bool __fs = std::__insertion_sort_incomplete<_WrappedComp>(__first, __i, __wrapped_comp);
868-
if (std::__insertion_sort_incomplete<_WrappedComp>(__i + difference_type(1), __last, __wrapped_comp)) {
801+
bool __fs = std::__insertion_sort_incomplete<_AlgPolicy, _Compare>(__first, __i, __comp);
802+
if (std::__insertion_sort_incomplete<_AlgPolicy, _Compare>(__i + difference_type(1), __last, __comp)) {
869803
if (__fs)
870804
return;
871805
__last = __i;
@@ -904,30 +838,8 @@ inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) {
904838
return __log2;
905839
}
906840

907-
template <class _WrappedComp, class _RandomAccessIterator>
908-
_LIBCPP_HIDDEN void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
909-
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
910-
difference_type __depth_limit = 2 * std::__log2i(__last - __first);
911-
912-
using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
913-
using _AlgPolicy = typename _Unwrap::_AlgPolicy;
914-
using _Compare = typename _Unwrap::_Comp;
915-
_Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
916-
// Only use bitset partitioning for arithmetic types. We should also check
917-
// that the default comparator is in use so that we are sure that there are no
918-
// branches in the comparator.
919-
std::__introsort<_AlgPolicy,
920-
_Compare,
921-
_RandomAccessIterator,
922-
__use_branchless_sort<_Compare, _RandomAccessIterator>::value>(
923-
__first, __last, __comp, __depth_limit);
924-
}
925-
926-
template <class _Compare, class _Tp>
927-
inline _LIBCPP_INLINE_VISIBILITY void __sort(_Tp** __first, _Tp** __last, __less<_Tp*>&) {
928-
__less<uintptr_t> __comp;
929-
std::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
930-
}
841+
template <class _Comp, class _RandomAccessIterator>
842+
void __sort(_RandomAccessIterator, _RandomAccessIterator, _Comp);
931843

932844
extern template _LIBCPP_FUNC_VIS void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
933845
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -947,20 +859,83 @@ extern template _LIBCPP_FUNC_VIS void __sort<__less<float>&, float*>(float*, flo
947859
extern template _LIBCPP_FUNC_VIS void __sort<__less<double>&, double*>(double*, double*, __less<double>&);
948860
extern template _LIBCPP_FUNC_VIS void __sort<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
949861

862+
template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
863+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
864+
__sort_dispatch(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
865+
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
866+
difference_type __depth_limit = 2 * std::__log2i(__last - __first);
867+
868+
// Only use bitset partitioning for arithmetic types. We should also check
869+
// that the default comparator is in use so that we are sure that there are no
870+
// branches in the comparator.
871+
std::__introsort<_AlgPolicy,
872+
_Comp&,
873+
_RandomAccessIterator,
874+
__use_branchless_sort<_Comp, _RandomAccessIterator>::value>(
875+
__first, __last, __comp, __depth_limit);
876+
}
877+
878+
template <class _Type, class... _Options>
879+
using __is_any_of = _Or<is_same<_Type, _Options>...>;
880+
881+
template <class _Type>
882+
using __sort_is_specialized_in_library = __is_any_of<
883+
_Type,
884+
char,
885+
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
886+
wchar_t,
887+
#endif
888+
signed char,
889+
unsigned char,
890+
short,
891+
unsigned short,
892+
int,
893+
unsigned int,
894+
long,
895+
unsigned long,
896+
long long,
897+
unsigned long long,
898+
float,
899+
double,
900+
long double>;
901+
902+
template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
903+
_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, __less<_Type>& __comp) {
904+
std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
905+
}
906+
907+
template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
908+
_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<_Type>&) {
909+
__less<_Type> __comp;
910+
std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
911+
}
912+
913+
#if _LIBCPP_STD_VER >= 14
914+
template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
915+
_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<>&) {
916+
__less<_Type> __comp;
917+
std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
918+
}
919+
#endif
920+
921+
#if _LIBCPP_STD_VER >= 20
922+
template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
923+
_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, ranges::less&) {
924+
__less<_Type> __comp;
925+
std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
926+
}
927+
#endif
928+
950929
template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
951930
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
952931
void __sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
953932
std::__debug_randomize_range<_AlgPolicy>(__first, __last);
954933

955-
using _Comp_ref = __comp_ref_type<_Comp>;
956934
if (__libcpp_is_constant_evaluated()) {
957-
std::__partial_sort<_AlgPolicy>(__first, __last, __last, __comp);
958-
935+
std::__partial_sort<_AlgPolicy>(
936+
std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__last), __comp);
959937
} else {
960-
using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Comp_ref>::type;
961-
_Comp_ref __comp_ref(__comp);
962-
_WrappedComp __wrapped_comp(__comp_ref);
963-
std::__sort<_WrappedComp>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __wrapped_comp);
938+
std::__sort_dispatch<_AlgPolicy>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __comp);
964939
}
965940
}
966941

libcxx/src/algorithm.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,24 @@
77
//===----------------------------------------------------------------------===//
88

99
#include <algorithm>
10+
#include <bit>
1011

1112
_LIBCPP_BEGIN_NAMESPACE_STD
1213

13-
// TODO(varconst): this currently doesn't benefit `ranges::sort` because it uses `ranges::less` instead of `__less`.
14+
template <class Comp, class RandomAccessIterator>
15+
void __sort(RandomAccessIterator first, RandomAccessIterator last, Comp comp) {
16+
auto depth_limit = 2 * std::__bit_log2(static_cast<size_t>(last - first));
1417

18+
// Only use bitset partitioning for arithmetic types. We should also check
19+
// that the default comparator is in use so that we are sure that there are no
20+
// branches in the comparator.
21+
std::__introsort<_ClassicAlgPolicy,
22+
Comp&,
23+
RandomAccessIterator,
24+
__use_branchless_sort<Comp, RandomAccessIterator>::value>(first, last, comp, depth_limit);
25+
}
26+
27+
// clang-format off
1528
template void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
1629
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1730
template void __sort<__less<wchar_t>&, wchar_t*>(wchar_t*, wchar_t*, __less<wchar_t>&);
@@ -29,5 +42,6 @@ template void __sort<__less<unsigned long long>&, unsigned long long*>(unsigned
2942
template void __sort<__less<float>&, float*>(float*, float*, __less<float>&);
3043
template void __sort<__less<double>&, double*>(double*, double*, __less<double>&);
3144
template void __sort<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
45+
// clang-format on
3246

3347
_LIBCPP_END_NAMESPACE_STD

libcxx/test/libcxx/algorithms/sort_stability.pass.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ std::vector<EqualType> deterministic() {
3434
for (int i = 0; i < kSize; ++i) {
3535
v[i].value = kSize / 2 - i * (i % 2 ? -1 : 1);
3636
}
37-
std::__sort(v.begin(), v.end(), std::less<EqualType>());
37+
std::less<EqualType> comp;
38+
std::__sort_dispatch<std::_ClassicAlgPolicy>(v.begin(), v.end(), comp);
3839
return v;
3940
}
4041

0 commit comments

Comments
 (0)