Skip to content

Commit 020d201

Browse files
committed
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.
2 parents 15952ac + a5cc17a commit 020d201

File tree

4 files changed

+40
-27
lines changed

4 files changed

+40
-27
lines changed

src/libcollections/vec.rs

+28-21
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use core::cmp::Ordering;
6767
use core::fmt;
6868
use core::hash::{self, Hash};
6969
use core::intrinsics::{arith_offset, assume};
70-
use core::iter::{repeat, FromIterator};
70+
use core::iter::FromIterator;
7171
use core::marker::PhantomData;
7272
use core::mem;
7373
use core::ops::{Index, IndexMut, Deref};
@@ -1106,12 +1106,35 @@ impl<T: Clone> Vec<T> {
11061106
let len = self.len();
11071107

11081108
if new_len > len {
1109-
self.extend(repeat(value).take(new_len - len));
1109+
self.extend_with_element(new_len - len, value);
11101110
} else {
11111111
self.truncate(new_len);
11121112
}
11131113
}
11141114

1115+
/// Extend the vector by `n` additional clones of `value`.
1116+
fn extend_with_element(&mut self, n: usize, value: T) {
1117+
self.reserve(n);
1118+
1119+
unsafe {
1120+
let len = self.len();
1121+
let mut ptr = self.as_mut_ptr().offset(len as isize);
1122+
// Write all elements except the last one
1123+
for i in 1..n {
1124+
ptr::write(ptr, value.clone());
1125+
ptr = ptr.offset(1);
1126+
// Increment the length in every step in case clone() panics
1127+
self.set_len(len + i);
1128+
}
1129+
1130+
if n > 0 {
1131+
// We can write the last element directly without cloning needlessly
1132+
ptr::write(ptr, value);
1133+
self.set_len(len + n);
1134+
}
1135+
}
1136+
}
1137+
11151138
/// Appends all elements in a slice to the `Vec`.
11161139
///
11171140
/// Iterates over the slice `other`, clones each element, and then appends
@@ -1294,25 +1317,9 @@ unsafe fn dealloc<T>(ptr: *mut T, len: usize) {
12941317
#[doc(hidden)]
12951318
#[stable(feature = "rust1", since = "1.0.0")]
12961319
pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
1297-
unsafe {
1298-
let mut v = Vec::with_capacity(n);
1299-
let mut ptr = v.as_mut_ptr();
1300-
1301-
// Write all elements except the last one
1302-
for i in 1..n {
1303-
ptr::write(ptr, Clone::clone(&elem));
1304-
ptr = ptr.offset(1);
1305-
v.set_len(i); // Increment the length in every step in case Clone::clone() panics
1306-
}
1307-
1308-
if n > 0 {
1309-
// We can write the last element directly without cloning needlessly
1310-
ptr::write(ptr, elem);
1311-
v.set_len(n);
1312-
}
1313-
1314-
v
1315-
}
1320+
let mut v = Vec::with_capacity(n);
1321+
v.extend_with_element(n, elem);
1322+
v
13161323
}
13171324

13181325
////////////////////////////////////////////////////////////////////////////////

src/libstd/io/buffered.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use error;
1919
use fmt;
2020
use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
2121
use ptr;
22-
use iter;
2322

2423
/// Wraps a `Read` and buffers input from it.
2524
///
@@ -63,11 +62,9 @@ impl<R: Read> BufReader<R> {
6362
/// Creates a new `BufReader` with the specified buffer capacity.
6463
#[stable(feature = "rust1", since = "1.0.0")]
6564
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
66-
let mut buf = Vec::with_capacity(cap);
67-
buf.extend(iter::repeat(0).take(cap));
6865
BufReader {
6966
inner: inner,
70-
buf: buf,
67+
buf: vec![0; cap],
7168
pos: 0,
7269
cap: 0,
7370
}

src/libstd/io/mod.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use cmp;
1616
use rustc_unicode::str as core_str;
1717
use error as std_error;
1818
use fmt;
19-
use iter::{self, Iterator, Extend};
19+
use iter::{Iterator};
2020
use marker::Sized;
2121
use ops::{Drop, FnOnce};
2222
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>
106106
if new_write_size < DEFAULT_BUF_SIZE {
107107
new_write_size *= 2;
108108
}
109-
buf.extend(iter::repeat(0).take(new_write_size));
109+
buf.resize(len + new_write_size, 0);
110110
}
111111

112112
match r.read(&mut buf[len..]) {
@@ -984,6 +984,14 @@ mod tests {
984984
let mut v = Vec::new();
985985
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
986986
assert_eq!(v, b"1");
987+
988+
let cap = 1024 * 1024;
989+
let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
990+
let mut v = Vec::new();
991+
let (a, b) = data.split_at(data.len() / 2);
992+
assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len());
993+
assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len());
994+
assert_eq!(v, data);
987995
}
988996

989997
#[test]

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
#![feature(unique)]
147147
#![feature(unsafe_no_drop_flag, filling_drop)]
148148
#![feature(vec_push_all)]
149+
#![feature(vec_resize)]
149150
#![feature(wrapping)]
150151
#![feature(zero_one)]
151152
#![cfg_attr(windows, feature(str_utf16))]

0 commit comments

Comments
 (0)