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:
Kevin Ballard 2014-05-03 16:11:30 -07:00
parent bf1e065371
commit 4af84313d6

View File

@ -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)]