@@ -61,8 +61,6 @@ pub(crate) fn quicksort<'a, T, F>(
61
61
62
62
// Partition the slice.
63
63
let num_lt = partition ( v, pivot_pos, is_less) ;
64
- // SAFETY: partition ensures that `num_lt` will be in-bounds.
65
- unsafe { intrinsics:: assume ( num_lt < v. len ( ) ) } ;
66
64
67
65
// Split the slice into `left`, `pivot`, and `right`.
68
66
let ( left, right) = v. split_at_mut ( num_lt) ;
@@ -84,6 +82,8 @@ pub(crate) fn quicksort<'a, T, F>(
84
82
/// on the left side of `v` followed by the other elements, notionally considered greater or
85
83
/// equal to `pivot`.
86
84
///
85
+ /// Aborts if the `pivot` or the returned value would be out of bounds of `v`.
86
+ ///
87
87
/// Returns the number of elements that are compared true for `is_less(elem, pivot)`.
88
88
///
89
89
/// If `is_less` does not implement a total order the resulting order and return value are
@@ -97,27 +97,18 @@ where
97
97
let len = v. len ( ) ;
98
98
99
99
// Allows for panic-free code-gen by proving this property to the compiler.
100
- if len == 0 {
101
- return 0 ;
102
- }
103
-
104
- if pivot >= len {
100
+ if len == 0 || pivot >= len {
105
101
intrinsics:: abort ( ) ;
106
102
}
107
103
108
- // SAFETY: We checked that `pivot` is in-bounds.
109
- unsafe {
110
- // Place the pivot at the beginning of slice.
111
- v. swap_unchecked ( 0 , pivot) ;
112
- }
113
- let ( pivot, v_without_pivot) = v. split_at_mut ( 1 ) ;
104
+ v. swap ( 0 , pivot) ;
105
+ let ( pivot, v_without_pivot) = v. split_first_mut ( ) . unwrap_or_else ( || intrinsics:: abort ( ) ) ;
114
106
115
107
// Assuming that Rust generates noalias LLVM IR we can be sure that a partition function
116
108
// signature of the form `(v: &mut [T], pivot: &T)` guarantees that pivot and v can't alias.
117
109
// Having this guarantee is crucial for optimizations. It's possible to copy the pivot value
118
110
// into a stack value, but this creates issues for types with interior mutability mandating
119
111
// a drop guard.
120
- let pivot = & mut pivot[ 0 ] ;
121
112
122
113
// This construct is used to limit the LLVM IR generated, which saves large amounts of
123
114
// compile-time by only instantiating the code that is needed. Idea by Frank Steffahn.
@@ -127,11 +118,8 @@ where
127
118
intrinsics:: abort ( ) ;
128
119
}
129
120
130
- // SAFETY: We checked that `num_lt` is in-bounds.
131
- unsafe {
132
- // Place the pivot between the two partitions.
133
- v. swap_unchecked ( 0 , num_lt) ;
134
- }
121
+ // Place the pivot between the two partitions.
122
+ v. swap ( 0 , num_lt) ;
135
123
136
124
num_lt
137
125
}
0 commit comments