Skip to content

Commit 45ce712

Browse files
committed
Auto merge of #68046 - Marwes:extend_for_each, r=<try>
perf: Use `for_each` in `Vec::extend` `for_each` are specialized for iterators such as `chain` allowing for faster iteration than a normal `for/while` loop. Note that since this only checks `size_hint` once at the start it may end up needing to call `reserve` more in the case that `size_hint` returns a larger and more accurate lower bound during iteration. This could maybe be alleviated with an implementation closure like the current one but the extra complexity will likely end up harming the normal case of an accurate or 0 (think `filter`) lower bound. ```rust while let Some(element) = iterator.next() { let (lower, _) = iterator.size_hint(); self.reserve(lower.saturating_add(1)); unsafe { let len = self.len(); ptr::write(self.get_unchecked_mut(len), element); // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); } iterator.by_ref().take(self.capacity()).for_each(|element| { unsafe { let len = self.len(); ptr::write(self.get_unchecked_mut(len), element); // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); } }); } // OR let (lower, _) = iterator.size_hint(); self.reserve(lower); loop { let result = iterator.by_ref().try_for_each(|element| { if self.len() == self.capacity() { return Err(element); } unsafe { let len = self.len(); ptr::write(self.get_unchecked_mut(len), element); // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); } Ok(()) }); match result { Ok(()) => break, Err(element) => { let (lower, _) = iterator.size_hint(); self.reserve(lower.saturating_add(1)); self.push(element); } } } ``` Closes #63340
2 parents adc6572 + fd175a8 commit 45ce712

File tree

1 file changed

+5
-13
lines changed

1 file changed

+5
-13
lines changed

src/liballoc/vec.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -2119,26 +2119,18 @@ where
21192119
}
21202120

21212121
impl<T> Vec<T> {
2122-
fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
2122+
fn extend_desugared<I: Iterator<Item = T>>(&mut self, iterator: I) {
21232123
// This is the case for a general iterator.
21242124
//
21252125
// This function should be the moral equivalent of:
21262126
//
21272127
// for item in iterator {
21282128
// self.push(item);
21292129
// }
2130-
while let Some(element) = iterator.next() {
2131-
let len = self.len();
2132-
if len == self.capacity() {
2133-
let (lower, _) = iterator.size_hint();
2134-
self.reserve(lower.saturating_add(1));
2135-
}
2136-
unsafe {
2137-
ptr::write(self.get_unchecked_mut(len), element);
2138-
// NB can't overflow since we would have had to alloc the address space
2139-
self.set_len(len + 1);
2140-
}
2141-
}
2130+
let (lower, _) = iterator.size_hint();
2131+
self.reserve(lower);
2132+
2133+
iterator.for_each(|element| self.push(element));
21422134
}
21432135

21442136
/// Creates a splicing iterator that replaces the specified range in the vector

0 commit comments

Comments
 (0)