Rewrite &[T].to_owned() to allocate directly
This used to create a Vec<T> and then call .move_iter().collect() to convert to a ~[T]. We can't do that anymore, so construct the ~[T] in place instead. This has the added benefit of avoiding an unnecessary memory copy (from the Vec<T> to the ~[T]).
This commit is contained in:
parent
bf1e065371
commit
4af84313d6
@ -315,15 +315,23 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn to_owned(&self) -> ~[T] {
|
fn to_owned(&self) -> ~[T] {
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
let mut result = Vec::with_capacity(len);
|
let data_size = len.checked_mul(&mem::size_of::<T>());
|
||||||
// Unsafe code so this can be optimised to a memcpy (or something
|
let data_size = data_size.expect("overflow in to_owned()");
|
||||||
// similarly fast) when T is Copy. LLVM is easily confused, so any
|
let size = mem::size_of::<RawVec<()>>().checked_add(&data_size);
|
||||||
// extra operations during the loop can prevent this optimisation
|
let size = size.expect("overflow in to_owned()");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let ret = malloc_raw(size) as *mut RawVec<()>;
|
||||||
|
|
||||||
|
(*ret).fill = len * mem::nonzero_size_of::<T>();
|
||||||
|
(*ret).alloc = len * mem::nonzero_size_of::<T>();
|
||||||
|
|
||||||
|
// Be careful with the following loop. We want it to be optimized
|
||||||
|
// to a memcpy (or something similarly fast) when T is Copy. LLVM
|
||||||
|
// is easily confused, so any extra operations during the loop can
|
||||||
|
// prevent this optimization.
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let p = result.as_mut_ptr();
|
let p = &mut (*ret).data as *mut _ as *mut T;
|
||||||
// Use try_finally here otherwise the write to length
|
|
||||||
// inside the loop stops LLVM from optimising this.
|
|
||||||
try_finally(
|
try_finally(
|
||||||
&mut i, (),
|
&mut i, (),
|
||||||
|i, ()| while *i < len {
|
|i, ()| while *i < len {
|
||||||
@ -332,9 +340,15 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
|
|||||||
self.unsafe_ref(*i).clone());
|
self.unsafe_ref(*i).clone());
|
||||||
*i += 1;
|
*i += 1;
|
||||||
},
|
},
|
||||||
|i| result.set_len(*i));
|
|i| if *i < len {
|
||||||
|
// we must be failing, clean up after ourselves
|
||||||
|
for j in range(0, *i as int) {
|
||||||
|
ptr::read(&*p.offset(j));
|
||||||
|
}
|
||||||
|
exchange_free(ret as *u8);
|
||||||
|
});
|
||||||
|
cast::transmute(ret)
|
||||||
}
|
}
|
||||||
result.move_iter().collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
Loading…
Reference in New Issue
Block a user