From 9d6b93c3e6609aa104da23cb9091c6c2e277f71e Mon Sep 17 00:00:00 2001 From: Joshua Wong Date: Sun, 12 May 2024 19:56:03 -0500 Subject: [PATCH] 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. --- library/alloc/src/vec/into_iter.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 28082143402..c4798933770 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -289,13 +289,38 @@ fn count(self) -> usize { }; } - fn try_fold(&mut self, init: B, mut f: F) -> R + fn fold(mut self, mut accum: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + if T::IS_ZST { + while self.ptr.as_ptr() != self.end.cast_mut() { + // SAFETY: we just checked that `self.ptr` is in bounds. + let tmp = unsafe { self.ptr.read() }; + // See `next` for why we subtract from `end` here. + self.end = self.end.wrapping_byte_sub(1); + accum = f(accum, tmp); + } + } else { + // SAFETY: `self.end` can only be null if `T` is a ZST. + while self.ptr != non_null!(self.end, T) { + // SAFETY: we just checked that `self.ptr` is in bounds. + let tmp = unsafe { self.ptr.read() }; + // SAFETY: the maximum this can be is `self.end`. + // Increment `self.ptr` first to avoid double dropping in the event of a panic. + self.ptr = unsafe { self.ptr.add(1) }; + accum = f(accum, tmp); + } + } + accum + } + + fn try_fold(&mut self, mut accum: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: core::ops::Try, { - let mut accum = init; if T::IS_ZST { while self.ptr.as_ptr() != self.end.cast_mut() { // SAFETY: we just checked that `self.ptr` is in bounds.