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
This commit is contained in:
commit
2154588f7a
1 changed files with 31 additions and 20 deletions
|
@ -1499,26 +1499,7 @@ impl<T> ops::DerefMut for Vec<T> {
|
||||||
impl<T> FromIterator<T> for Vec<T> {
|
impl<T> FromIterator<T> for Vec<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
|
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
|
||||||
// Unroll the first iteration, as the vector is going to be
|
<Self as SpecExtend<_>>::from_iter(iter.into_iter())
|
||||||
// expanded on this iteration in every case when the iterable is not
|
|
||||||
// empty, but the loop in extend_desugared() is not going to see the
|
|
||||||
// vector being full in the few subsequent loop iterations.
|
|
||||||
// So we get better branch prediction.
|
|
||||||
let mut iterator = iter.into_iter();
|
|
||||||
let mut vector = match iterator.next() {
|
|
||||||
None => return Vec::new(),
|
|
||||||
Some(element) => {
|
|
||||||
let (lower, _) = iterator.size_hint();
|
|
||||||
let mut vector = Vec::with_capacity(lower.saturating_add(1));
|
|
||||||
unsafe {
|
|
||||||
ptr::write(vector.get_unchecked_mut(0), element);
|
|
||||||
vector.set_len(1);
|
|
||||||
}
|
|
||||||
vector
|
|
||||||
}
|
|
||||||
};
|
|
||||||
vector.extend_desugared(iterator);
|
|
||||||
vector
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1590,13 +1571,37 @@ impl<T> Extend<T> for Vec<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialization trait used for Vec::from_iter and Vec::extend
|
||||||
trait SpecExtend<I> {
|
trait SpecExtend<I> {
|
||||||
|
fn from_iter(iter: I) -> Self;
|
||||||
fn spec_extend(&mut self, iter: I);
|
fn spec_extend(&mut self, iter: I);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T> SpecExtend<I> for Vec<T>
|
impl<I, T> SpecExtend<I> for Vec<T>
|
||||||
where I: Iterator<Item=T>,
|
where I: Iterator<Item=T>,
|
||||||
{
|
{
|
||||||
|
default fn from_iter(mut iterator: I) -> Self {
|
||||||
|
// Unroll the first iteration, as the vector is going to be
|
||||||
|
// expanded on this iteration in every case when the iterable is not
|
||||||
|
// empty, but the loop in extend_desugared() is not going to see the
|
||||||
|
// vector being full in the few subsequent loop iterations.
|
||||||
|
// So we get better branch prediction.
|
||||||
|
let mut vector = match iterator.next() {
|
||||||
|
None => return Vec::new(),
|
||||||
|
Some(element) => {
|
||||||
|
let (lower, _) = iterator.size_hint();
|
||||||
|
let mut vector = Vec::with_capacity(lower.saturating_add(1));
|
||||||
|
unsafe {
|
||||||
|
ptr::write(vector.get_unchecked_mut(0), element);
|
||||||
|
vector.set_len(1);
|
||||||
|
}
|
||||||
|
vector
|
||||||
|
}
|
||||||
|
};
|
||||||
|
vector.spec_extend(iterator);
|
||||||
|
vector
|
||||||
|
}
|
||||||
|
|
||||||
default fn spec_extend(&mut self, iter: I) {
|
default fn spec_extend(&mut self, iter: I) {
|
||||||
self.extend_desugared(iter)
|
self.extend_desugared(iter)
|
||||||
}
|
}
|
||||||
|
@ -1605,6 +1610,12 @@ impl<I, T> SpecExtend<I> for Vec<T>
|
||||||
impl<I, T> SpecExtend<I> for Vec<T>
|
impl<I, T> SpecExtend<I> for Vec<T>
|
||||||
where I: TrustedLen<Item=T>,
|
where I: TrustedLen<Item=T>,
|
||||||
{
|
{
|
||||||
|
fn from_iter(iterator: I) -> Self {
|
||||||
|
let mut vector = Vec::new();
|
||||||
|
vector.spec_extend(iterator);
|
||||||
|
vector
|
||||||
|
}
|
||||||
|
|
||||||
fn spec_extend(&mut self, iterator: I) {
|
fn spec_extend(&mut self, iterator: I) {
|
||||||
// This is the case for a TrustedLen iterator.
|
// This is the case for a TrustedLen iterator.
|
||||||
let (low, high) = iterator.size_hint();
|
let (low, high) = iterator.size_hint();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue