Skip to content

Commit 6e066ce

Browse files
committed
specialize Iterator::fold for vec::IntoIter
LLVM currently adds a redundant check for the returned option, in addition to the `self.ptr != self.end` check when using the default `Iterator::fold` method that calls `vec::IntoIter::next` in a loop.
1 parent 7479403 commit 6e066ce

File tree

1 file changed

+27
-2
lines changed

1 file changed

+27
-2
lines changed

Diff for: alloc/src/vec/into_iter.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,38 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
289289
};
290290
}
291291

292-
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
292+
fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B
293+
where
294+
F: FnMut(B, Self::Item) -> B,
295+
{
296+
if T::IS_ZST {
297+
while self.ptr.as_ptr() != self.end.cast_mut() {
298+
// SAFETY: we just checked that `self.ptr` is in bounds.
299+
let tmp = unsafe { self.ptr.read() };
300+
// See `next` for why we subtract from `end` here.
301+
self.end = self.end.wrapping_byte_sub(1);
302+
accum = f(accum, tmp);
303+
}
304+
} else {
305+
// SAFETY: `self.end` can only be null if `T` is a ZST.
306+
while self.ptr != non_null!(self.end, T) {
307+
// SAFETY: we just checked that `self.ptr` is in bounds.
308+
let tmp = unsafe { self.ptr.read() };
309+
// SAFETY: the maximum this can be is `self.end`.
310+
// Increment `self.ptr` first to avoid double dropping in the event of a panic.
311+
self.ptr = unsafe { self.ptr.add(1) };
312+
accum = f(accum, tmp);
313+
}
314+
}
315+
accum
316+
}
317+
318+
fn try_fold<B, F, R>(&mut self, mut accum: B, mut f: F) -> R
293319
where
294320
Self: Sized,
295321
F: FnMut(B, Self::Item) -> R,
296322
R: core::ops::Try<Output = B>,
297323
{
298-
let mut accum = init;
299324
if T::IS_ZST {
300325
while self.ptr.as_ptr() != self.end.cast_mut() {
301326
// SAFETY: we just checked that `self.ptr` is in bounds.

0 commit comments

Comments
 (0)