@@ -1092,6 +1092,39 @@ impl<T> [T] {
10921092 merge_sort ( self , |a, b| a. lt ( b) ) ;
10931093 }
10941094
1095+ /// Sorts the slice using `compare` to compare elements.
1096+ ///
1097+ /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case.
1098+ ///
1099+ /// # Current implementation
1100+ ///
1101+ /// The current algorithm is an adaptive, iterative merge sort inspired by
1102+ /// [timsort](https://en.wikipedia.org/wiki/Timsort).
1103+ /// It is designed to be very fast in cases where the slice is nearly sorted, or consists of
1104+ /// two or more sorted sequences concatenated one after another.
1105+ ///
1106+ /// Also, it allocates temporary storage half the size of `self`, but for short slices a
1107+ /// non-allocating insertion sort is used instead.
1108+ ///
1109+ /// # Examples
1110+ ///
1111+ /// ```
1112+ /// let mut v = [5, 4, 1, 3, 2];
1113+ /// v.sort_by(|a, b| a.cmp(b));
1114+ /// assert!(v == [1, 2, 3, 4, 5]);
1115+ ///
1116+ /// // reverse sorting
1117+ /// v.sort_by(|a, b| b.cmp(a));
1118+ /// assert!(v == [5, 4, 3, 2, 1]);
1119+ /// ```
1120+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1121+ #[ inline]
1122+ pub fn sort_by < F > ( & mut self , mut compare : F )
1123+ where F : FnMut ( & T , & T ) -> Ordering
1124+ {
1125+ merge_sort ( self , |a, b| compare ( a, b) == Less ) ;
1126+ }
1127+
10951128 /// Sorts the slice using `f` to extract a key to compare elements by.
10961129 ///
10971130 /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case.
@@ -1122,37 +1155,112 @@ impl<T> [T] {
11221155 merge_sort ( self , |a, b| f ( a) . lt ( & f ( b) ) ) ;
11231156 }
11241157
1125- /// Sorts the slice using `compare` to compare elements.
1158+ /// Sorts the slice, but may not preserve the order of equal elements.
11261159 ///
1127- /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case.
1160+ /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
1161+ /// and `O(n log n)` worst-case.
11281162 ///
11291163 /// # Current implementation
11301164 ///
1131- /// The current algorithm is an adaptive, iterative merge sort inspired by
1132- /// [timsort](https://en.wikipedia.org/wiki/Timsort).
1133- /// It is designed to be very fast in cases where the slice is nearly sorted, or consists of
1134- /// two or more sorted sequences concatenated one after another .
1165+ /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort],
1166+ /// which is a quicksort variant designed to be very fast on certain kinds of patterns,
1167+ /// sometimes achieving linear time. It is randomized but deterministic, and falls back to
1168+ /// heapsort on degenerate inputs .
11351169 ///
1136- /// Also, it allocates temporary storage half the size of `self`, but for short slices a
1137- /// non-allocating insertion sort is used instead.
1170+ /// It is generally faster than stable sorting, except in a few special cases, e.g. when the
1171+ /// slice consists of several concatenated sorted sequences.
1172+ ///
1173+ /// # Examples
1174+ ///
1175+ /// ```
1176+ /// let mut v = [-5, 4, 1, -3, 2];
1177+ ///
1178+ /// v.sort_unstable();
1179+ /// assert!(v == [-5, -3, 1, 2, 4]);
1180+ /// ```
1181+ ///
1182+ /// [pdqsort]: https://github.com/orlp/pdqsort
1183+ // FIXME #40585: Mention `sort_unstable` in the documentation for `sort`.
1184+ #[ unstable( feature = "sort_unstable" , issue = "40585" ) ]
1185+ #[ inline]
1186+ pub fn sort_unstable ( & mut self )
1187+ where T : Ord
1188+ {
1189+ core_slice:: SliceExt :: sort_unstable ( self ) ;
1190+ }
1191+
1192+ /// Sorts the slice using `compare` to compare elements, but may not preserve the order of
1193+ /// equal elements.
1194+ ///
1195+ /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
1196+ /// and `O(n log n)` worst-case.
1197+ ///
1198+ /// # Current implementation
1199+ ///
1200+ /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort],
1201+ /// which is a quicksort variant designed to be very fast on certain kinds of patterns,
1202+ /// sometimes achieving linear time. It is randomized but deterministic, and falls back to
1203+ /// heapsort on degenerate inputs.
1204+ ///
1205+ /// It is generally faster than stable sorting, except in a few special cases, e.g. when the
1206+ /// slice consists of several concatenated sorted sequences.
11381207 ///
11391208 /// # Examples
11401209 ///
11411210 /// ```
11421211 /// let mut v = [5, 4, 1, 3, 2];
1143- /// v.sort_by (|a, b| a.cmp(b));
1212+ /// v.sort_unstable_by (|a, b| a.cmp(b));
11441213 /// assert!(v == [1, 2, 3, 4, 5]);
11451214 ///
11461215 /// // reverse sorting
1147- /// v.sort_by (|a, b| b.cmp(a));
1216+ /// v.sort_unstable_by (|a, b| b.cmp(a));
11481217 /// assert!(v == [5, 4, 3, 2, 1]);
11491218 /// ```
1150- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1219+ ///
1220+ /// [pdqsort]: https://github.com/orlp/pdqsort
1221+ // FIXME #40585: Mention `sort_unstable_by` in the documentation for `sort_by`.
1222+ #[ unstable( feature = "sort_unstable" , issue = "40585" ) ]
11511223 #[ inline]
1152- pub fn sort_by < F > ( & mut self , mut compare : F )
1224+ pub fn sort_unstable_by < F > ( & mut self , compare : F )
11531225 where F : FnMut ( & T , & T ) -> Ordering
11541226 {
1155- merge_sort ( self , |a, b| compare ( a, b) == Less ) ;
1227+ core_slice:: SliceExt :: sort_unstable_by ( self , compare) ;
1228+ }
1229+
1230+ /// Sorts the slice using `f` to extract a key to compare elements by, but may not preserve the
1231+ /// order of equal elements.
1232+ ///
1233+ /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
1234+ /// and `O(n log n)` worst-case.
1235+ ///
1236+ /// # Current implementation
1237+ ///
1238+ /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort],
1239+ /// which is a quicksort variant designed to be very fast on certain kinds of patterns,
1240+ /// sometimes achieving linear time. It is randomized but deterministic, and falls back to
1241+ /// heapsort on degenerate inputs.
1242+ ///
1243+ /// It is generally faster than stable sorting, except in a few special cases, e.g. when the
1244+ /// slice consists of several concatenated sorted sequences.
1245+ ///
1246+ /// # Examples
1247+ ///
1248+ /// ```
1249+ /// let mut v = [-5i32, 4, 1, -3, 2];
1250+ ///
1251+ /// v.sort_unstable_by_key(|k| k.abs());
1252+ /// assert!(v == [1, 2, -3, 4, -5]);
1253+ ///
1254+ /// [pdqsort]: https://github.com/orlp/pdqsort
1255+ /// ```
1256+ // FIXME #40585: Mention `sort_unstable_by_key` in the documentation for `sort_by_key`.
1257+ #[ unstable( feature = "sort_unstable" , issue = "40585" ) ]
1258+ #[ inline]
1259+ pub fn sort_unstable_by_key < B , F > ( & mut self , f : F )
1260+ where F : FnMut ( & T ) -> B ,
1261+ B : Ord
1262+ {
1263+ core_slice:: SliceExt :: sort_unstable_by_key ( self , f) ;
11561264 }
11571265
11581266 /// Copies the elements from `src` into `self`.
@@ -1553,28 +1661,20 @@ unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
15531661fn merge_sort < T , F > ( v : & mut [ T ] , mut is_less : F )
15541662 where F : FnMut ( & T , & T ) -> bool
15551663{
1664+ // Slices of up to this length get sorted using insertion sort.
1665+ const MAX_INSERTION : usize = 16 ;
1666+ // Very short runs are extended using insertion sort to span at least this many elements.
1667+ const MIN_RUN : usize = 8 ;
1668+
15561669 // Sorting has no meaningful behavior on zero-sized types.
15571670 if size_of :: < T > ( ) == 0 {
15581671 return ;
15591672 }
15601673
1561- // FIXME #12092: These numbers are platform-specific and need more extensive testing/tuning.
1562- //
1563- // If `v` has length up to `max_insertion`, simply switch to insertion sort because it is going
1564- // to perform better than merge sort. For bigger types `T`, the threshold is smaller.
1565- //
1566- // Short runs are extended using insertion sort to span at least `min_run` elements, in order
1567- // to improve performance.
1568- let ( max_insertion, min_run) = if size_of :: < T > ( ) <= 2 * mem:: size_of :: < usize > ( ) {
1569- ( 64 , 32 )
1570- } else {
1571- ( 32 , 16 )
1572- } ;
1573-
15741674 let len = v. len ( ) ;
15751675
15761676 // Short arrays get sorted in-place via insertion sort to avoid allocations.
1577- if len <= max_insertion {
1677+ if len <= MAX_INSERTION {
15781678 if len >= 2 {
15791679 for i in ( 0 ..len-1 ) . rev ( ) {
15801680 insert_head ( & mut v[ i..] , & mut is_less) ;
@@ -1618,7 +1718,7 @@ fn merge_sort<T, F>(v: &mut [T], mut is_less: F)
16181718
16191719 // Insert some more elements into the run if it's too short. Insertion sort is faster than
16201720 // merge sort on short sequences, so this significantly improves performance.
1621- while start > 0 && end - start < min_run {
1721+ while start > 0 && end - start < MIN_RUN {
16221722 start -= 1 ;
16231723 insert_head ( & mut v[ start..end] , & mut is_less) ;
16241724 }
0 commit comments