-
Notifications
You must be signed in to change notification settings - Fork 9
Description
In the readme to this package you state:
It's very akin to
take_mut, though usesDropinstead ofstd::panic::catch_unwind()to react to unwinding, which avoids the optimisation barrier of calling theextern "C" __rust_maybe_catch_panic(). As such it's up to ∞x faster.
I was wondering if you could go into detail here, in particular whether catch_unwind() causes any optimisation barriers in the case where there is no panic (it seems like it does due to the "maybe").
I've also written the following function, which does an inplace replacement of a vector. It doesn't require Default or Clone. The behaviour on failure is to take the last element of the vector and move it in the vector in the spot where the function panicked, and then simply slice the last element from the vector (as it is now moved and doesn't need to be dropped). My implementation seems to work but uses catch_unwind. I was wondering whether there was a better approach here that avoids the catch_unwind() call, particularly if it inhibits optimisation as you suggest (feel free to include any of this in your library as well).
fn inplace_vec_map<T>(f: impl Fn(T) -> T, mut x: Vec<T>) -> Vec<T> {
let mut ptr_and_error: Option<(*mut T, _)> = None;
for item_ref in &mut x {
unsafe {
let y1: T = std::ptr::read(item_ref);
let y2 = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(y1)));
match y2 {
Ok(result) => std::ptr::write(item_ref, result),
Err(error) => {
ptr_and_error = Some((item_ref, error));
break;
}
}
}
}
if let Some((item_ptr, error)) = ptr_and_error {
let last_index = x.len() - 1;
unsafe {
std::ptr::write(item_ptr, std::ptr::read(x.get_unchecked(last_index)));
x.set_len(last_index);
std::panic::resume_unwind(error);
}
}
x
}