Skip to content

Commit

Permalink
Improve Vec::resize so that it can be used in Read::read_to_end
Browse files Browse the repository at this point in the history
We needed a more efficient way to zerofill the vector in read_to_end.
This to reduce the memory intialization overhead to a minimum.

Use the implementation of `std::vec::from_elem` (used for the vec![]
macro) for Vec::resize as well. For simple element types like u8, this
compiles to memset, so it makes Vec::resize much more efficient.
  • Loading branch information
bluss committed Jul 8, 2015
1 parent 26f0cd5 commit 6ac0ba3
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 23 deletions.
49 changes: 28 additions & 21 deletions src/libcollections/vec.rs
Expand Up @@ -67,7 +67,7 @@ use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash};
use core::intrinsics::{arith_offset, assume};
use core::iter::{repeat, FromIterator};
use core::iter::FromIterator;
use core::marker::PhantomData;
use core::mem;
use core::ops::{Index, IndexMut, Deref};
Expand Down Expand Up @@ -1106,12 +1106,35 @@ impl<T: Clone> Vec<T> {
let len = self.len();

if new_len > len {
self.extend(repeat(value).take(new_len - len));
self.extend_with_element(new_len - len, value);
} else {
self.truncate(new_len);
}
}

/// Extend the vector by `n` additional clones of `value`.
fn extend_with_element(&mut self, n: usize, value: T) {
self.reserve(n);

unsafe {
let len = self.len();
let mut ptr = self.as_mut_ptr().offset(len as isize);
// Write all elements except the last one
for i in 1..n {
ptr::write(ptr, value.clone());
ptr = ptr.offset(1);
// Increment the length in every step in case clone() panics
self.set_len(len + i);
}

if n > 0 {
// We can write the last element directly without cloning needlessly
ptr::write(ptr, value);
self.set_len(len + n);
}
}
}

/// Appends all elements in a slice to the `Vec`.
///
/// Iterates over the slice `other`, clones each element, and then appends
Expand Down Expand Up @@ -1294,25 +1317,9 @@ unsafe fn dealloc<T>(ptr: *mut T, len: usize) {
#[doc(hidden)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
unsafe {
let mut v = Vec::with_capacity(n);
let mut ptr = v.as_mut_ptr();

// Write all elements except the last one
for i in 1..n {
ptr::write(ptr, Clone::clone(&elem));
ptr = ptr.offset(1);
v.set_len(i); // Increment the length in every step in case Clone::clone() panics
}

if n > 0 {
// We can write the last element directly without cloning needlessly
ptr::write(ptr, elem);
v.set_len(n);
}

v
}
let mut v = Vec::with_capacity(n);
v.extend_with_element(n, elem);
v
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
12 changes: 10 additions & 2 deletions src/libstd/io/mod.rs
Expand Up @@ -16,7 +16,7 @@ use cmp;
use rustc_unicode::str as core_str;
use error as std_error;
use fmt;
use iter::{self, Iterator, Extend};
use iter::{Iterator};
use marker::Sized;
use ops::{Drop, FnOnce};
use option::Option::{self, Some, None};
Expand Down Expand Up @@ -106,7 +106,7 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
if new_write_size < DEFAULT_BUF_SIZE {
new_write_size *= 2;
}
buf.extend(iter::repeat(0).take(new_write_size));
buf.resize(len + new_write_size, 0);
}

match r.read(&mut buf[len..]) {
Expand Down Expand Up @@ -984,6 +984,14 @@ mod tests {
let mut v = Vec::new();
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
assert_eq!(v, b"1");

let cap = 1024 * 1024;
let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
let mut v = Vec::new();
let (a, b) = data.split_at(data.len() / 2);
assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len());
assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len());
assert_eq!(v, data);
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions src/libstd/lib.rs
Expand Up @@ -146,6 +146,7 @@
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(vec_push_all)]
#![feature(vec_resize)]
#![feature(wrapping)]
#![feature(zero_one)]
#![cfg_attr(windows, feature(str_utf16))]
Expand Down

0 comments on commit 6ac0ba3

Please sign in to comment.