Functions median_idx
, partition_idx
, and partition_slice
are unchanged in the correct and the incorrect code.
// *******************************************************************
fn median_idx(v: &[i32]) -> usize {
let l = v.len() - 1;
let m = v.len() / 2;
if v[0] < v[m] {
if v[m] < v[l] {
m
} else if v[0] < v[l] {
l
} else {
0
}
} else {
if v[m] > v[l] {
m
} else if v[0] > v[l] {
l
} else {
0
}
}
}
// *******************************************************************
fn partition_idx(v: &mut [i32], px: usize) -> (usize, usize) {
let e = v.len();
let pivot = v[px];
let (mut l, mut m, mut r): (usize, usize, usize) = (0, 0, e);
while m < r {
if v[m] < pivot {
if l < m {
v.swap(l, m);
}
l += 1;
m += 1;
} else if pivot < v[m] {
if m + 1 < r {
v.swap(m, r - 1);
}
r -= 1;
} else {
// pivot == v[m]
m += 1;
}
}
assert!(l < m);
(l, m)
}
// *******************************************************************
pub fn partition_slice(v: &mut [i32], px: usize) -> (&mut [i32], &mut [i32]) {
let (l, m) = partition_idx(v, px);
let (left, mid_right) = v.split_at_mut(l);
let (_, right) = mid_right.split_at_mut(m - l);
(left, right)
}
When doing sequential recursion, code compiles correctly:
// *******************************************************************
pub fn qsort(vv: &mut [i32]) {
let mut v = vv;
while v.len() > 2 {
let px = median_idx(v);
let (left, right) = partition_slice(v, px);
let (smaller, larger) = if left.len() < right.len() {
(left, right)
} else {
(right, left)
};
if smaller.len() > 1 {
qsort(smaller);
}
v = larger;
}
if v.len() == 2 {
// 2 elements exactly
if v[0] > v[1] {
v.swap(0, 1);
}
}
}
However, when the recursive call is executed in a separate thread, the compiler errors:
// *******************************************************************
pub fn qsort(vv: &mut [i32]) {
let mut v = vv;
let handles = Vector::new();
while v.len() > 2 {
let px = median_idx(v);
let (left, right) = partition_slice(v, px);
let (smaller, larger) = if left.len() < right.len() {
(left, right)
} else {
(right, left)
};
if smaller.len() > 1 {
let handle = thread::spawn(|| { // recursive call in thread => error
qsort(smaller);
});
handles.push(handle);
}
v = larger;
}
if v.len() == 2 {
// 2 elements exactly
if v[0] > v[1] {
v.swap(0, 1);
}
}
for handle in handles {
handle.join();
}
}
The error message is shown below. The unexpected is that the error message does not refer to the recursive call wrapped in thread(), but to an unchanged called to partition_slice()
.
cargo build --release
Compiling escape v0.1.0 (src/escape)
error[E0521]: borrowed data escapes outside of function
--> src/lib.rs:69:29
|
64 | pub fn qsort(vv: &mut [i32]) {
| -- - let's call the lifetime of this reference `'1`
| |
| `vv` is a reference that is only valid in the function body
...
69 | let (left, right) = partition_slice(v, px);
| ^^^^^^^^^^^^^^^^^^^^^^
| |
| `vv` escapes the function body here
| argument requires that `'1` must outlive `'static`
For more information about this error, try `rustc --explain E0521`.
error: could not compile `escape` (lib) due to 1 previous error