Navigation Menu

Skip to content

Commit

Permalink
vec: Use less code bloat specialized Vec::from_iter
Browse files Browse the repository at this point in the history
Vec::from_iter's general case allocates the vector up front;
this is redundant for the TrustedLen case, and can then be avoided
to reduce the size of the code.
  • Loading branch information
bluss committed Nov 13, 2016
1 parent 2b3a37b commit c36edc7
Showing 1 changed file with 31 additions and 20 deletions.
51 changes: 31 additions & 20 deletions src/libcollections/vec.rs
Expand Up @@ -1499,26 +1499,7 @@ impl<T> ops::DerefMut for Vec<T> {
impl<T> FromIterator<T> for Vec<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
// 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 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(iterator);
vector
<Self as SpecExtend<_>>::from_iter(iter.into_iter())
}
}

Expand Down Expand Up @@ -1590,13 +1571,37 @@ impl<T> Extend<T> for Vec<T> {
}
}

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

impl<I, T> SpecExtend<I> for Vec<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) {
self.extend_desugared(iter)
}
Expand All @@ -1605,6 +1610,12 @@ impl<I, T> SpecExtend<I> for Vec<T>
impl<I, T> SpecExtend<I> for Vec<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) {
// This is the case for a TrustedLen iterator.
let (low, high) = iterator.size_hint();
Expand Down

0 comments on commit c36edc7

Please sign in to comment.