[libcxx-commits] [libcxx] dc017e0 - [libc++] Forward ranges::sort to instantiations in the dylib

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Feb 1 11:10:27 PST 2023


Author: Nikolas Klauser
Date: 2023-02-01T20:10:21+01:00
New Revision: dc017e03ca55ed0b2054e4a7d5e5ca049a054fcc

URL: https://github.com/llvm/llvm-project/commit/dc017e03ca55ed0b2054e4a7d5e5ca049a054fcc
DIFF: https://github.com/llvm/llvm-project/commit/dc017e03ca55ed0b2054e4a7d5e5ca049a054fcc.diff

LOG: [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

Added: 
    

Modified: 
    libcxx/include/__algorithm/sort.h
    libcxx/src/algorithm.cpp
    libcxx/test/libcxx/algorithms/sort_stability.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 303c3d3fd8cea..a0e56e2046f57 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -29,6 +29,7 @@
 #include <__memory/destruct_n.h>
 #include <__memory/unique_ptr.h>
 #include <__type_traits/conditional.h>
+#include <__type_traits/disjunction.h>
 #include <__type_traits/is_arithmetic.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
@@ -41,52 +42,6 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// Wraps an algorithm policy tag and a comparator in a single struct, used to pass the policy tag around without
-// changing the number of template arguments (to keep the ABI stable). This is only used for the "range" policy tag.
-//
-// To create an object of this type, use `_WrapAlgPolicy<T, C>::type` -- see the specialization below for the rationale.
-template <class _PolicyT, class _CompT, class = void>
-struct _WrapAlgPolicy {
-  using type = _WrapAlgPolicy;
-
-  using _AlgPolicy = _PolicyT;
-  using _Comp = _CompT;
-  _Comp& __comp;
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-  _WrapAlgPolicy(_Comp& __c) : __comp(__c) {}
-};
-
-// Specialization for the "classic" policy tag that avoids creating a struct and simply defines an alias for the
-// comparator. When unwrapping, a pristine comparator is always considered to have the "classic" tag attached. Passing
-// the pristine comparator where possible allows using template instantiations from the dylib.
-template <class _PolicyT, class _CompT>
-struct _WrapAlgPolicy<_PolicyT, _CompT, __enable_if_t<std::is_same<_PolicyT, _ClassicAlgPolicy>::value> > {
-  using type = _CompT;
-};
-
-// Unwraps a pristine functor (e.g. `std::less`) as if it were wrapped using `_WrapAlgPolicy`. The policy tag is always
-// set to "classic".
-template <class _CompT>
-struct _UnwrapAlgPolicy {
-  using _AlgPolicy = _ClassicAlgPolicy;
-  using _Comp = _CompT;
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
-  _Comp __get_comp(_Comp __comp) { return __comp; }
-};
-
-// Unwraps a `_WrapAlgPolicy` struct.
-template <class... _Ts>
-struct _UnwrapAlgPolicy<_WrapAlgPolicy<_Ts...> > {
-  using _Wrapped = _WrapAlgPolicy<_Ts...>;
-  using _AlgPolicy = typename _Wrapped::_AlgPolicy;
-  using _Comp = typename _Wrapped::_Comp;
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
-  _Comp __get_comp(_Wrapped& __w) { return __w.__comp; }
-};
-
 // stable, 2-3 compares, 0-2 swaps
 
 template <class _AlgPolicy, class _Compare, class _ForwardIterator>
@@ -151,27 +106,22 @@ unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator
 
 // stable, 4-10 compares, 0-9 swaps
 
-template <class _WrappedComp, class _ForwardIterator>
-_LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3,
-                                _ForwardIterator __x4, _ForwardIterator __x5, _WrappedComp __wrapped_comp) {
-  using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
-  using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+template <class _AlgPolicy, class _Comp, class _ForwardIterator>
+_LIBCPP_HIDE_FROM_ABI unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3,
+                                       _ForwardIterator __x4, _ForwardIterator __x5, _Comp __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
 
-  using _Compare = typename _Unwrap::_Comp;
-  _Compare __c = _Unwrap::__get_comp(__wrapped_comp);
-
-  unsigned __r = std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
-  if (__c(*__x5, *__x4)) {
+  unsigned __r = std::__sort4<_AlgPolicy, _Comp>(__x1, __x2, __x3, __x4, __comp);
+  if (__comp(*__x5, *__x4)) {
     _Ops::iter_swap(__x4, __x5);
     ++__r;
-    if (__c(*__x4, *__x3)) {
+    if (__comp(*__x4, *__x3)) {
       _Ops::iter_swap(__x3, __x4);
       ++__r;
-      if (__c(*__x3, *__x2)) {
+      if (__comp(*__x3, *__x2)) {
         _Ops::iter_swap(__x2, __x3);
         ++__r;
-        if (__c(*__x2, *__x1)) {
+        if (__comp(*__x2, *__x1)) {
           _Ops::iter_swap(__x1, __x2);
           ++__r;
         }
@@ -181,16 +131,6 @@ _LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _F
   return __r;
 }
 
-template <class _AlgPolicy, class _Compare, class _ForwardIterator>
-_LIBCPP_HIDE_FROM_ABI unsigned __sort5_wrap_policy(
-    _ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4, _ForwardIterator __x5,
-    _Compare __c) {
-  using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
-  _WrappedComp __wrapped_comp(__c);
-  return std::__sort5<_WrappedComp, _ForwardIterator>(
-      std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __wrapped_comp);
-}
-
 // The comparator being simple is a prerequisite for using the branchless optimization.
 template <class _Tp>
 struct __is_simple_comparator : false_type {};
@@ -299,7 +239,8 @@ template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
 __sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
                          _RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
-  std::__sort5_wrap_policy<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __x5, __c);
+  std::__sort5<_AlgPolicy, _Compare, _RandomAccessIterator>(
+      std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __c);
 }
 
 // Assumes size > 0
@@ -370,16 +311,11 @@ __insertion_sort_unguarded(_RandomAccessIterator __first, _RandomAccessIterator
   }
 }
 
-template <class _WrappedComp, class _RandomAccessIterator>
-_LIBCPP_HIDDEN bool __insertion_sort_incomplete(
-    _RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
-  using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
-  using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+template <class _AlgPolicy, class _Comp, class _RandomAccessIterator>
+_LIBCPP_HIDE_FROM_ABI bool __insertion_sort_incomplete(
+    _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
   using _Ops = _IterOps<_AlgPolicy>;
 
-  using _Compare = typename _Unwrap::_Comp;
-  _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
-
   typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
   switch (__last - __first) {
   case 0:
@@ -390,21 +326,21 @@ _LIBCPP_HIDDEN bool __insertion_sort_incomplete(
       _Ops::iter_swap(__first, __last);
     return true;
   case 3:
-    std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + 
diff erence_type(1), --__last, __comp);
+    std::__sort3_maybe_branchless<_AlgPolicy, _Comp>(__first, __first + 
diff erence_type(1), --__last, __comp);
     return true;
   case 4:
-    std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
+    std::__sort4_maybe_branchless<_AlgPolicy, _Comp>(
         __first, __first + 
diff erence_type(1), __first + 
diff erence_type(2), --__last, __comp);
     return true;
   case 5:
-    std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
+    std::__sort5_maybe_branchless<_AlgPolicy, _Comp>(
         __first, __first + 
diff erence_type(1), __first + 
diff erence_type(2), __first + 
diff erence_type(3),
         --__last, __comp);
     return true;
   }
   typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
   _RandomAccessIterator __j = __first + 
diff erence_type(2);
-  std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + 
diff erence_type(1), __j, __comp);
+  std::__sort3_maybe_branchless<_AlgPolicy, _Comp>(__first, __first + 
diff erence_type(1), __j, __comp);
   const unsigned __limit = 8;
   unsigned __count = 0;
   for (_RandomAccessIterator __i = __j + 
diff erence_type(1); __i != __last; ++__i) {
@@ -862,10 +798,8 @@ void __introsort(_RandomAccessIterator __first,
     // [__first, __i) < *__i and *__i <= [__i+1, __last)
     // If we were given a perfect partition, see if insertion sort is quick...
     if (__ret.second) {
-      using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
-      _WrappedComp __wrapped_comp(__comp);
-      bool __fs = std::__insertion_sort_incomplete<_WrappedComp>(__first, __i, __wrapped_comp);
-      if (std::__insertion_sort_incomplete<_WrappedComp>(__i + 
diff erence_type(1), __last, __wrapped_comp)) {
+      bool __fs = std::__insertion_sort_incomplete<_AlgPolicy, _Compare>(__first, __i, __comp);
+      if (std::__insertion_sort_incomplete<_AlgPolicy, _Compare>(__i + 
diff erence_type(1), __last, __comp)) {
         if (__fs)
           return;
         __last = __i;
@@ -904,30 +838,8 @@ inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) {
   return __log2;
 }
 
-template <class _WrappedComp, class _RandomAccessIterator>
-_LIBCPP_HIDDEN void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
-  typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
-  
diff erence_type __depth_limit = 2 * std::__log2i(__last - __first);
-
-  using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
-  using _AlgPolicy = typename _Unwrap::_AlgPolicy;
-  using _Compare = typename _Unwrap::_Comp;
-  _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
-  // Only use bitset partitioning for arithmetic types.  We should also check
-  // that the default comparator is in use so that we are sure that there are no
-  // branches in the comparator.
-  std::__introsort<_AlgPolicy,
-                   _Compare,
-                   _RandomAccessIterator,
-                   __use_branchless_sort<_Compare, _RandomAccessIterator>::value>(
-      __first, __last, __comp, __depth_limit);
-}
-
-template <class _Compare, class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY void __sort(_Tp** __first, _Tp** __last, __less<_Tp*>&) {
-  __less<uintptr_t> __comp;
-  std::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
-}
+template <class _Comp, class _RandomAccessIterator>
+void __sort(_RandomAccessIterator, _RandomAccessIterator, _Comp);
 
 extern template _LIBCPP_FUNC_VIS void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -947,20 +859,83 @@ extern template _LIBCPP_FUNC_VIS void __sort<__less<float>&, float*>(float*, flo
 extern template _LIBCPP_FUNC_VIS void __sort<__less<double>&, double*>(double*, double*, __less<double>&);
 extern template _LIBCPP_FUNC_VIS void __sort<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
 
+template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
+__sort_dispatch(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
+  typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
+  
diff erence_type __depth_limit = 2 * std::__log2i(__last - __first);
+
+  // Only use bitset partitioning for arithmetic types.  We should also check
+  // that the default comparator is in use so that we are sure that there are no
+  // branches in the comparator.
+  std::__introsort<_AlgPolicy,
+                   _Comp&,
+                   _RandomAccessIterator,
+                   __use_branchless_sort<_Comp, _RandomAccessIterator>::value>(
+      __first, __last, __comp, __depth_limit);
+}
+
+template <class _Type, class... _Options>
+using __is_any_of = _Or<is_same<_Type, _Options>...>;
+
+template <class _Type>
+using __sort_is_specialized_in_library = __is_any_of<
+    _Type,
+    char,
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+    wchar_t,
+#endif
+    signed char,
+    unsigned char,
+    short,
+    unsigned short,
+    int,
+    unsigned int,
+    long,
+    unsigned long,
+    long long,
+    unsigned long long,
+    float,
+    double,
+    long double>;
+
+template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, __less<_Type>& __comp) {
+  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+}
+
+template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<_Type>&) {
+  __less<_Type> __comp;
+  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+}
+
+#if _LIBCPP_STD_VER >= 14
+template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<>&) {
+  __less<_Type> __comp;
+  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+}
+#endif
+
+#if _LIBCPP_STD_VER >= 20
+template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, ranges::less&) {
+  __less<_Type> __comp;
+  std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
+}
+#endif
+
 template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
 void __sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
   std::__debug_randomize_range<_AlgPolicy>(__first, __last);
 
-  using _Comp_ref = __comp_ref_type<_Comp>;
   if (__libcpp_is_constant_evaluated()) {
-    std::__partial_sort<_AlgPolicy>(__first, __last, __last, __comp);
-
+    std::__partial_sort<_AlgPolicy>(
+        std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__last), __comp);
   } else {
-    using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Comp_ref>::type;
-    _Comp_ref __comp_ref(__comp);
-    _WrappedComp __wrapped_comp(__comp_ref);
-    std::__sort<_WrappedComp>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __wrapped_comp);
+    std::__sort_dispatch<_AlgPolicy>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __comp);
   }
 }
 

diff  --git a/libcxx/src/algorithm.cpp b/libcxx/src/algorithm.cpp
index b7535b7513b5e..5a47558fdaeb8 100644
--- a/libcxx/src/algorithm.cpp
+++ b/libcxx/src/algorithm.cpp
@@ -7,11 +7,24 @@
 //===----------------------------------------------------------------------===//
 
 #include <algorithm>
+#include <bit>
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// TODO(varconst): this currently doesn't benefit `ranges::sort` because it uses `ranges::less` instead of `__less`.
+template <class Comp, class RandomAccessIterator>
+void __sort(RandomAccessIterator first, RandomAccessIterator last, Comp comp) {
+  auto depth_limit = 2 * std::__bit_log2(static_cast<size_t>(last - first));
 
+  // Only use bitset partitioning for arithmetic types.  We should also check
+  // that the default comparator is in use so that we are sure that there are no
+  // branches in the comparator.
+  std::__introsort<_ClassicAlgPolicy,
+                   Comp&,
+                   RandomAccessIterator,
+                   __use_branchless_sort<Comp, RandomAccessIterator>::value>(first, last, comp, depth_limit);
+}
+
+// clang-format off
 template void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 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
 template void __sort<__less<float>&, float*>(float*, float*, __less<float>&);
 template void __sort<__less<double>&, double*>(double*, double*, __less<double>&);
 template void __sort<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
+// clang-format on
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp b/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp
index 664ea708a6ec8..712f12c255935 100644
--- a/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp
@@ -34,7 +34,8 @@ std::vector<EqualType> deterministic() {
   for (int i = 0; i < kSize; ++i) {
     v[i].value = kSize / 2 - i * (i % 2 ? -1 : 1);
   }
-  std::__sort(v.begin(), v.end(), std::less<EqualType>());
+  std::less<EqualType> comp;
+  std::__sort_dispatch<std::_ClassicAlgPolicy>(v.begin(), v.end(), comp);
   return v;
 }
 


        


More information about the libcxx-commits mailing list