-   Notifications  You must be signed in to change notification settings 
- Fork 13.9k
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.