No way to get mutable reference to Vec member without expressing uniqueness over the full VecΒ #134507
Description
I've ran into the following standard library defect. There appears to be no possible sound way to go from a Vec<T>
to a &mut T
without expressing uniqueness over the full Vec
. Vec::as_mut_ptr
does not suffice because it takes a &mut self
which expresses unique access over the full vec. A function which goes from *mut Vec<T> -> *mut T
is necessary, but missing. The same is true for *mut [T] -> *mut T
.
Consider the following example, where I have a v: Vec<Vec<u32>>
where m.len() == n
and m[i].len() == t
for all i
. I have t
threads and I now want to process this array mutably in parallel, transposed. For example suppose I want to do the following in-place cumulative sum:
(0..t).into_par_iter().map(|thread_idx| {
let mut cumsum = 0;
for i in 0..n {
// This obviously doesn't work, but you can't write this soundly with pointers either.
let x: &mut u32 = &mut v[i][thread_idx];
cumsum += *x;
*x = cumsum;
}
})
As far as I can tell, there is no way to write this soundly without introducing (potentially significant) overhead at all. The only way to write this soundly is to first create a temporary array of pointers and to modify the inner loop to use those pointers:
let ptrs: Vec<*mut u32> = v.iter_mut().map(|vi| vi.as_mut_ptr()).collect();
// ...
let x: &mut u32 = unsafe { &mut *ptrs[i].add(thread_idx) };
}
I really think the standard library should offer some kind of way to write this loop soundly without the unnecessary overhead of creating a pointer array. The simplest solution I think is to add functions which go from *mut Vec<T> -> *mut T
and *mut [T] -> *mut T
without creating an intermediate unique reference to the entire Vec
or slice.
Activity