about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-07-08 21:12:54 +0000
committerbors <bors@rust-lang.org>2015-07-08 21:12:54 +0000
commit020d201a661746359430610ee811b0aaa242dea8 (patch)
tree7fbc96b41a33a8773338b32861e6318a524b9afa
parent15952ac6cf39c593ae2b9c2cd161f2e221324e6a (diff)
parenta5cc17adaadf9bc4da3b6b375879fda55ed823c9 (diff)
downloadrust-020d201a661746359430610ee811b0aaa242dea8.tar.gz
rust-020d201a661746359430610ee811b0aaa242dea8.zip
Auto merge of #26849 - bluss:read-to-end-memset, r=alexcrichton
Improve zerofill in Vec::resize and Read::read_to_end

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.
-rw-r--r--src/libcollections/vec.rs49
-rw-r--r--src/libstd/io/buffered.rs5
-rw-r--r--src/libstd/io/mod.rs12
-rw-r--r--src/libstd/lib.rs1
4 files changed, 40 insertions, 27 deletions
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index c032471b6b6..3848263c530 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -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};
@@ -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
@@ -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
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index d389a0be117..98d8bc6bdaf 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -19,7 +19,6 @@ use error;
 use fmt;
 use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
 use ptr;
-use iter;
 
 /// Wraps a `Read` and buffers input from it.
 ///
@@ -63,11 +62,9 @@ impl<R: Read> BufReader<R> {
     /// Creates a new `BufReader` with the specified buffer capacity.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
-        let mut buf = Vec::with_capacity(cap);
-        buf.extend(iter::repeat(0).take(cap));
         BufReader {
             inner: inner,
-            buf: buf,
+            buf: vec![0; cap],
             pos: 0,
             cap: 0,
         }
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 9021f32fad0..50c44299dc7 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -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};
@@ -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..]) {
@@ -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]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 73e45619774..caf3f497e10 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -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))]