2016-04-28 55 views
5

我目前正在研究doing more stuff with arrays,但我認爲如果我們被允許以某種方式轉變爲陣列的前置陣列,那麼這些操作的性能可能會更好,只是爲了在函數結束時不泄漏它。這將讓我們使用泄漏放大而不a)引入不安全並且b)設置catch_panic(_)。 Rust在某種程度上可能嗎?有沒有辦法預先泄漏一個值?

例如,創建從一個迭代的通用陣列(這顯然是行不通的):

#[inline] 
fn map_inner<I, S, F, T, N>(list: I, f: F) -> GenericArray<T, N> 
where I: IntoIterator<Item=S>, F: Fn(&S) -> T, N: ArrayLength<T> { 
    unsafe { 
     // pre-leak the whole array, it's uninitialized anyway 
     let mut res : GenericArray<Leaked<T>, N> = std::mem::uninitialized(); 
     let i = list.into_iter(); 
     for r in res.iter_mut() { 
      // this could panic anytime 
      std::ptr::write(r, Leaked::new(f(i.next().unwrap()))) 
     } 
     // transmuting un-leaks the array 
     std::mem::transmute::<GenericArray<Leaked<T>, N>, 
           GenericArray<T, N>>(res) 
    } 
} 

我要指出,如果我們要麼不得不編譯時獲得的T大小或類型可以隱藏它的內部(例如Leaked<T>),這是完全可行的。

+0

您期待的性能提升有哪些?不增加'len'? – malbarbo

+0

如果我試圖通過捕捉恐慌來防止泄漏(目前只能在beta/nightly上運行),那麼吞吐量比收集「Vec」的吞吐量高出約45%。我認爲我可以通過預先泄漏獲得更好的結果。 – llogiq

回答

3

它可能使用nodrop,但它可能會泄漏。

fn map_inner<I, S, F, T, N>(list: I, f: F) -> GenericArray<T, N> 
where I: IntoIterator<Item=S>, F: Fn(&S) -> T, N: ArrayLength<T> { 
    unsafe { 
     // pre-leak the whole array, it's uninitialized anyway 
     let mut res : NoDrop<GenericArray<T, N>> = NoDrop::new(std::mem::uninitialized()); 
     let i = list.into_iter(); 
     for r in res.iter_mut() { 
      // this could panic anytime 
      std::ptr::write(r, f(i.next().unwrap())) 
     } 
     res.into_inner() 
    } 
} 

讓我們假設第一項(a)後,從i消耗並寫入r,恐慌發生。從i其餘項目將下降,但項目a不會。儘管泄漏的內存is not被認爲是不安全的,但並不可取。

我認爲問題鏈接中描述的方法是最好的選擇。它類似於VecArrayVec的實現。我在編寫的數組庫中使用了類似的方法。

+0

謝謝!這正是我所期待的。 – llogiq

+1

@llogiq如果你感興趣,我寫了一些代碼來回答其他問題,使這種構造不泄漏。請參閱http://stackoverflow.com/questions/36925673/how-can-i-initialize-an-array-using-a-function – malbarbo

+0

再次感謝 - 這大部分與我想出的相同。我的基準測試也非常有前途 - 非常接近普通陣列結構。 – llogiq

相關問題