Skip to content

Commit 2154588

Browse files
authored
Auto merge of #37740 - bluss:corrected-vec-collect, r=alexcrichton
Restore Vec::from_iter() specialization Since I said "no intentional functional change" in the previous commit, I guess it was inevitable there were unintentional changes. Not functional, but optimization-wise. This restores the extend specialization's use in Vec::from_iter. (commit 1). Also use specialization in from_iter to reduce allocation code duplication for the TrustedLen case (commit 2). Bug introduced in PR #37709
2 parents 766f6e4 + c36edc7 commit 2154588

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

src/libcollections/vec.rs

+31-20
Original file line numberDiff line numberDiff line change
@@ -1499,26 +1499,7 @@ impl<T> ops::DerefMut for Vec<T> {
14991499
impl<T> FromIterator<T> for Vec<T> {
15001500
#[inline]
15011501
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
1502-
// Unroll the first iteration, as the vector is going to be
1503-
// expanded on this iteration in every case when the iterable is not
1504-
// empty, but the loop in extend_desugared() is not going to see the
1505-
// vector being full in the few subsequent loop iterations.
1506-
// So we get better branch prediction.
1507-
let mut iterator = iter.into_iter();
1508-
let mut vector = match iterator.next() {
1509-
None => return Vec::new(),
1510-
Some(element) => {
1511-
let (lower, _) = iterator.size_hint();
1512-
let mut vector = Vec::with_capacity(lower.saturating_add(1));
1513-
unsafe {
1514-
ptr::write(vector.get_unchecked_mut(0), element);
1515-
vector.set_len(1);
1516-
}
1517-
vector
1518-
}
1519-
};
1520-
vector.extend_desugared(iterator);
1521-
vector
1502+
<Self as SpecExtend<_>>::from_iter(iter.into_iter())
15221503
}
15231504
}
15241505

@@ -1590,13 +1571,37 @@ impl<T> Extend<T> for Vec<T> {
15901571
}
15911572
}
15921573

1574+
// Specialization trait used for Vec::from_iter and Vec::extend
15931575
trait SpecExtend<I> {
1576+
fn from_iter(iter: I) -> Self;
15941577
fn spec_extend(&mut self, iter: I);
15951578
}
15961579

15971580
impl<I, T> SpecExtend<I> for Vec<T>
15981581
where I: Iterator<Item=T>,
15991582
{
1583+
default fn from_iter(mut iterator: I) -> Self {
1584+
// Unroll the first iteration, as the vector is going to be
1585+
// expanded on this iteration in every case when the iterable is not
1586+
// empty, but the loop in extend_desugared() is not going to see the
1587+
// vector being full in the few subsequent loop iterations.
1588+
// So we get better branch prediction.
1589+
let mut vector = match iterator.next() {
1590+
None => return Vec::new(),
1591+
Some(element) => {
1592+
let (lower, _) = iterator.size_hint();
1593+
let mut vector = Vec::with_capacity(lower.saturating_add(1));
1594+
unsafe {
1595+
ptr::write(vector.get_unchecked_mut(0), element);
1596+
vector.set_len(1);
1597+
}
1598+
vector
1599+
}
1600+
};
1601+
vector.spec_extend(iterator);
1602+
vector
1603+
}
1604+
16001605
default fn spec_extend(&mut self, iter: I) {
16011606
self.extend_desugared(iter)
16021607
}
@@ -1605,6 +1610,12 @@ impl<I, T> SpecExtend<I> for Vec<T>
16051610
impl<I, T> SpecExtend<I> for Vec<T>
16061611
where I: TrustedLen<Item=T>,
16071612
{
1613+
fn from_iter(iterator: I) -> Self {
1614+
let mut vector = Vec::new();
1615+
vector.spec_extend(iterator);
1616+
vector
1617+
}
1618+
16081619
fn spec_extend(&mut self, iterator: I) {
16091620
// This is the case for a TrustedLen iterator.
16101621
let (low, high) = iterator.size_hint();

0 commit comments

Comments
 (0)