Skip to content

Commit a118b93

Browse files
committed
Optimize Vec::from_iter and extend
Use one loop, efficient for both sized and size-ignorant iterators (including iterators lying about their size).
1 parent dcc6ce2 commit a118b93

File tree

1 file changed

+26
-42
lines changed

1 file changed

+26
-42
lines changed

src/libcollections/vec.rs

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,42 +1410,8 @@ impl<T> ops::DerefMut for Vec<T> {
14101410
impl<T> FromIterator<T> for Vec<T> {
14111411
#[inline]
14121412
fn from_iter<I: IntoIterator<Item=T>>(iterable: I) -> Vec<T> {
1413-
let mut iterator = iterable.into_iter();
1414-
let (lower, _) = iterator.size_hint();
1415-
let mut vector = Vec::with_capacity(lower);
1416-
1417-
// This function should be the moral equivalent of:
1418-
//
1419-
// for item in iterator {
1420-
// vector.push(item);
1421-
// }
1422-
//
1423-
// This equivalent crucially runs the iterator precisely once. Below we
1424-
// actually in theory run the iterator twice (one without bounds checks
1425-
// and one with). To achieve the "moral equivalent", we use the `if`
1426-
// statement below to break out early.
1427-
//
1428-
// If the first loop has terminated, then we have one of two conditions.
1429-
//
1430-
// 1. The underlying iterator returned `None`. In this case we are
1431-
// guaranteed that less than `vector.capacity()` elements have been
1432-
// returned, so we break out early.
1433-
// 2. The underlying iterator yielded `vector.capacity()` elements and
1434-
// has not yielded `None` yet. In this case we run the iterator to
1435-
// its end below.
1436-
for element in iterator.by_ref().take(vector.capacity()) {
1437-
let len = vector.len();
1438-
unsafe {
1439-
ptr::write(vector.get_unchecked_mut(len), element);
1440-
vector.set_len(len + 1);
1441-
}
1442-
}
1443-
1444-
if vector.len() == vector.capacity() {
1445-
for element in iterator {
1446-
vector.push(element);
1447-
}
1448-
}
1413+
let mut vector = Vec::new();
1414+
vector.extend(iterable);
14491415
vector
14501416
}
14511417
}
@@ -1482,13 +1448,31 @@ impl<'a, T> IntoIterator for &'a mut Vec<T> {
14821448

14831449
#[unstable(feature = "collections", reason = "waiting on Extend stability")]
14841450
impl<T> Extend<T> for Vec<T> {
1485-
#[inline]
14861451
fn extend<I: IntoIterator<Item=T>>(&mut self, iterable: I) {
1487-
let iterator = iterable.into_iter();
1488-
let (lower, _) = iterator.size_hint();
1489-
self.reserve(lower);
1490-
for element in iterator {
1491-
self.push(element)
1452+
let mut iterator = iterable.into_iter();
1453+
1454+
// This function should be the moral equivalent of:
1455+
//
1456+
// for item in iterator {
1457+
// self.push(item);
1458+
// }
1459+
loop {
1460+
match iterator.next() {
1461+
None => {
1462+
break;
1463+
}
1464+
Some(element) => {
1465+
let len = self.len();
1466+
if len == self.capacity() {
1467+
let (lower, _) = iterator.size_hint();
1468+
self.reserve(lower + 1);
1469+
}
1470+
unsafe {
1471+
ptr::write(self.get_unchecked_mut(len), element);
1472+
self.set_len(len + 1);
1473+
}
1474+
}
1475+
}
14921476
}
14931477
}
14941478
}

0 commit comments

Comments
 (0)