Skip to content

Commit 4af8431

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 bf1e065 commit 4af8431

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
@@ -315,15 +315,23 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
315315
#[inline]
316316
fn to_owned(&self) -> ~[T] {
317317
let len = self.len();
318-
let mut result = Vec::with_capacity(len);
319-
// Unsafe code so this can be optimised to a memcpy (or something
320-
// similarly fast) when T is Copy. LLVM is easily confused, so any
321-
// extra operations during the loop can prevent this optimisation
318+
let data_size = len.checked_mul(&mem::size_of::<T>());
319+
let data_size = data_size.expect("overflow in to_owned()");
320+
let size = mem::size_of::<RawVec<()>>().checked_add(&data_size);
321+
let size = size.expect("overflow in to_owned()");
322+
322323
unsafe {
324+
let ret = malloc_raw(size) as *mut RawVec<()>;
325+
326+
(*ret).fill = len * mem::nonzero_size_of::<T>();
327+
(*ret).alloc = len * mem::nonzero_size_of::<T>();
328+
329+
// Be careful with the following loop. We want it to be optimized
330+
// to a memcpy (or something similarly fast) when T is Copy. LLVM
331+
// is easily confused, so any extra operations during the loop can
332+
// prevent this optimization.
323333
let mut i = 0;
324-
let p = result.as_mut_ptr();
325-
// Use try_finally here otherwise the write to length
326-
// inside the loop stops LLVM from optimising this.
334+
let p = &mut (*ret).data as *mut _ as *mut T;
327335
try_finally(
328336
&mut i, (),
329337
|i, ()| while *i < len {
@@ -332,9 +340,15 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
332340
self.unsafe_ref(*i).clone());
333341
*i += 1;
334342
},
335-
|i| result.set_len(*i));
343+
|i| if *i < len {
344+
// we must be failing, clean up after ourselves
345+
for j in range(0, *i as int) {
346+
ptr::read(&*p.offset(j));
347+
}
348+
exchange_free(ret as *u8);
349+
});
350+
cast::transmute(ret)
336351
}
337-
result.move_iter().collect()
338352
}
339353

340354
#[inline(always)]

0 commit comments

Comments
 (0)