@@ -102,6 +102,7 @@ use core::mem::size_of;
102102use core:: mem;
103103use core:: ptr;
104104use core:: slice as core_slice;
105+ use core:: { u8, u16, u32} ;
105106
106107use borrow:: { Borrow , BorrowMut , ToOwned } ;
107108use boxed:: Box ;
@@ -1302,7 +1303,8 @@ impl<T> [T] {
13021303
13031304 /// Sorts the slice with a key extraction function.
13041305 ///
1305- /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case.
1306+ /// This sort is stable (i.e. does not reorder equal elements) and `O(m n log(m n))`
1307+ /// worst-case, where the key function is `O(m)`.
13061308 ///
13071309 /// When applicable, unstable sorting is preferred because it is generally faster than stable
13081310 /// sorting and it doesn't allocate auxiliary memory.
@@ -1328,12 +1330,82 @@ impl<T> [T] {
13281330 /// ```
13291331 #[ stable( feature = "slice_sort_by_key" , since = "1.7.0" ) ]
13301332 #[ inline]
1331- pub fn sort_by_key < B , F > ( & mut self , mut f : F )
1332- where F : FnMut ( & T ) -> B , B : Ord
1333+ pub fn sort_by_key < K , F > ( & mut self , mut f : F )
1334+ where F : FnMut ( & T ) -> K , K : Ord
13331335 {
13341336 merge_sort ( self , |a, b| f ( a) . lt ( & f ( b) ) ) ;
13351337 }
13361338
1339+ /// Sorts the slice with a key extraction function.
1340+ ///
1341+ /// During sorting, the key function is called only once per element.
1342+ ///
1343+ /// This sort is stable (i.e. does not reorder equal elements) and `O(m n + n log n)`
1344+ /// worst-case, where the key function is `O(m)`.
1345+ ///
1346+ /// For simple key functions (e.g. functions that are property accesses or
1347+ /// basic operations), [`sort_by_key`](#method.sort_by_key) is likely to be
1348+ /// faster.
1349+ ///
1350+ /// # Current implementation
1351+ ///
1352+ /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
1353+ /// which combines the fast average case of randomized quicksort with the fast worst case of
1354+ /// heapsort, while achieving linear time on slices with certain patterns. It uses some
1355+ /// randomization to avoid degenerate cases, but with a fixed seed to always provide
1356+ /// deterministic behavior.
1357+ ///
1358+ /// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the
1359+ /// length of the slice.
1360+ ///
1361+ /// # Examples
1362+ ///
1363+ /// ```
1364+ /// #![feature(slice_sort_by_cached_key)]
1365+ /// let mut v = [-5i32, 4, 32, -3, 2];
1366+ ///
1367+ /// v.sort_by_cached_key(|k| k.to_string());
1368+ /// assert!(v == [-3, -5, 2, 32, 4]);
1369+ /// ```
1370+ ///
1371+ /// [pdqsort]: https://github.com/orlp/pdqsort
1372+ #[ unstable( feature = "slice_sort_by_cached_key" , issue = "34447" ) ]
1373+ #[ inline]
1374+ pub fn sort_by_cached_key < K , F > ( & mut self , f : F )
1375+ where F : FnMut ( & T ) -> K , K : Ord
1376+ {
1377+ // Helper macro for indexing our vector by the smallest possible type, to reduce allocation.
1378+ macro_rules! sort_by_key {
1379+ ( $t: ty, $slice: ident, $f: ident) => ( {
1380+ let mut indices: Vec <_> =
1381+ $slice. iter( ) . map( $f) . enumerate( ) . map( |( i, k) | ( k, i as $t) ) . collect( ) ;
1382+ // The elements of `indices` are unique, as they are indexed, so any sort will be
1383+ // stable with respect to the original slice. We use `sort_unstable` here because
1384+ // it requires less memory allocation.
1385+ indices. sort_unstable( ) ;
1386+ for i in 0 ..$slice. len( ) {
1387+ let mut index = indices[ i] . 1 ;
1388+ while ( index as usize ) < i {
1389+ index = indices[ index as usize ] . 1 ;
1390+ }
1391+ indices[ i] . 1 = index;
1392+ $slice. swap( i, index as usize ) ;
1393+ }
1394+ } )
1395+ }
1396+
1397+ let sz_u8 = mem:: size_of :: < ( K , u8 ) > ( ) ;
1398+ let sz_u16 = mem:: size_of :: < ( K , u16 ) > ( ) ;
1399+ let sz_u32 = mem:: size_of :: < ( K , u32 ) > ( ) ;
1400+ let sz_usize = mem:: size_of :: < ( K , usize ) > ( ) ;
1401+
1402+ let len = self . len ( ) ;
1403+ if sz_u8 < sz_u16 && len <= ( u8:: MAX as usize ) { return sort_by_key ! ( u8 , self , f) }
1404+ if sz_u16 < sz_u32 && len <= ( u16:: MAX as usize ) { return sort_by_key ! ( u16 , self , f) }
1405+ if sz_u32 < sz_usize && len <= ( u32:: MAX as usize ) { return sort_by_key ! ( u32 , self , f) }
1406+ sort_by_key ! ( usize , self , f)
1407+ }
1408+
13371409 /// Sorts the slice, but may not preserve the order of equal elements.
13381410 ///
13391411 /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
@@ -1410,7 +1482,7 @@ impl<T> [T] {
14101482 /// elements.
14111483 ///
14121484 /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
1413- /// and `O(n log n)` worst-case.
1485+ /// and `O(m n log(m n)) ` worst-case, where the key function is `O(m)` .
14141486 ///
14151487 /// # Current implementation
14161488 ///
@@ -1420,9 +1492,6 @@ impl<T> [T] {
14201492 /// randomization to avoid degenerate cases, but with a fixed seed to always provide
14211493 /// deterministic behavior.
14221494 ///
1423- /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
1424- /// slice consists of several concatenated sorted sequences.
1425- ///
14261495 /// # Examples
14271496 ///
14281497 /// ```
@@ -1435,9 +1504,8 @@ impl<T> [T] {
14351504 /// [pdqsort]: https://github.com/orlp/pdqsort
14361505 #[ stable( feature = "sort_unstable" , since = "1.20.0" ) ]
14371506 #[ inline]
1438- pub fn sort_unstable_by_key < B , F > ( & mut self , f : F )
1439- where F : FnMut ( & T ) -> B ,
1440- B : Ord
1507+ pub fn sort_unstable_by_key < K , F > ( & mut self , f : F )
1508+ where F : FnMut ( & T ) -> K , K : Ord
14411509 {
14421510 core_slice:: SliceExt :: sort_unstable_by_key ( self , f) ;
14431511 }
0 commit comments