Skip to content

Commit 5803b10

Browse files
committed
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]).
1 parent 6d88571 commit 5803b10

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

src/libstd/slice.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -668,15 +668,23 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
668668
#[inline]
669669
fn to_owned(&self) -> ~[T] {
670670
let len = self.len();
671-
let mut result = Vec::with_capacity(len);
672-
// Unsafe code so this can be optimised to a memcpy (or something
673-
// similarly fast) when T is Copy. LLVM is easily confused, so any
674-
// extra operations during the loop can prevent this optimisation
671+
let data_size = len.checked_mul(&mem::size_of::<T>());
672+
let data_size = data_size.expect("overflow in to_owned()");
673+
let size = mem::size_of::<RawVec<()>>().checked_add(&data_size);
674+
let size = size.expect("overflow in to_owned()");
675+
675676
unsafe {
677+
let ret = malloc_raw(size) as *mut RawVec<()>;
678+
679+
(*ret).fill = len * mem::nonzero_size_of::<T>();
680+
(*ret).alloc = len * mem::nonzero_size_of::<T>();
681+
682+
// Be careful with the following loop. We want it to be optimized
683+
// to a memcpy (or something similarly fast) when T is Copy. LLVM
684+
// is easily confused, so any extra operations during the loop can
685+
// prevent this optimization.
676686
let mut i = 0;
677-
let p = result.as_mut_ptr();
678-
// Use try_finally here otherwise the write to length
679-
// inside the loop stops LLVM from optimising this.
687+
let p = &mut (*ret).data as *mut _ as *mut T;
680688
try_finally(
681689
&mut i, (),
682690
|i, ()| while *i < len {
@@ -685,9 +693,15 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
685693
self.unsafe_ref(*i).clone());
686694
*i += 1;
687695
},
688-
|i| result.set_len(*i));
696+
|i| if *i < len {
697+
// we must be failing, clean up after ourselves
698+
for j in range(0, *i as int) {
699+
ptr::read(&*p.offset(j));
700+
}
701+
exchange_free(ret as *u8);
702+
});
703+
cast::transmute(ret)
689704
}
690-
result.move_iter().collect()
691705
}
692706

693707
#[inline(always)]

0 commit comments

Comments
 (0)