@@ -1092,6 +1092,39 @@ impl<T> [T] {
1092
1092
merge_sort ( self , |a, b| a. lt ( b) ) ;
1093
1093
}
1094
1094
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
+
1095
1128
/// Sorts the slice using `f` to extract a key to compare elements by.
1096
1129
///
1097
1130
/// 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] {
1122
1155
merge_sort ( self , |a, b| f ( a) . lt ( & f ( b) ) ) ;
1123
1156
}
1124
1157
1125
- /// Sorts the slice using `compare` to compare elements.
1158
+ /// Sorts the slice, but may not preserve the order of equal elements.
1126
1159
///
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.
1128
1162
///
1129
1163
/// # Current implementation
1130
1164
///
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 .
1135
1169
///
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.
1138
1207
///
1139
1208
/// # Examples
1140
1209
///
1141
1210
/// ```
1142
1211
/// 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));
1144
1213
/// assert!(v == [1, 2, 3, 4, 5]);
1145
1214
///
1146
1215
/// // reverse sorting
1147
- /// v.sort_by (|a, b| b.cmp(a));
1216
+ /// v.sort_unstable_by (|a, b| b.cmp(a));
1148
1217
/// assert!(v == [5, 4, 3, 2, 1]);
1149
1218
/// ```
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" ) ]
1151
1223
#[ inline]
1152
- pub fn sort_by < F > ( & mut self , mut compare : F )
1224
+ pub fn sort_unstable_by < F > ( & mut self , compare : F )
1153
1225
where F : FnMut ( & T , & T ) -> Ordering
1154
1226
{
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) ;
1156
1264
}
1157
1265
1158
1266
/// 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)
1553
1661
fn merge_sort < T , F > ( v : & mut [ T ] , mut is_less : F )
1554
1662
where F : FnMut ( & T , & T ) -> bool
1555
1663
{
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
+
1556
1669
// Sorting has no meaningful behavior on zero-sized types.
1557
1670
if size_of :: < T > ( ) == 0 {
1558
1671
return ;
1559
1672
}
1560
1673
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
-
1574
1674
let len = v. len ( ) ;
1575
1675
1576
1676
// Short arrays get sorted in-place via insertion sort to avoid allocations.
1577
- if len <= max_insertion {
1677
+ if len <= MAX_INSERTION {
1578
1678
if len >= 2 {
1579
1679
for i in ( 0 ..len-1 ) . rev ( ) {
1580
1680
insert_head ( & mut v[ i..] , & mut is_less) ;
@@ -1618,7 +1718,7 @@ fn merge_sort<T, F>(v: &mut [T], mut is_less: F)
1618
1718
1619
1719
// Insert some more elements into the run if it's too short. Insertion sort is faster than
1620
1720
// 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 {
1622
1722
start -= 1 ;
1623
1723
insert_head ( & mut v[ start..end] , & mut is_less) ;
1624
1724
}
0 commit comments