diff options
| author | Joshua Wong <joshuawong@anticentri.st> | 2024-05-12 19:56:03 -0500 |
|---|---|---|
| committer | Joshua Wong <joshuawong@anticentri.st> | 2024-05-18 18:30:20 -0500 |
| commit | 9d6b93c3e6609aa104da23cb9091c6c2e277f71e (patch) | |
| tree | a88298b12c4fdbaa92e85d0f0b7f9fd830eef0ba | |
| parent | 6165dca6dbf66d45a373e08f16d1fc85f7be0ac7 (diff) | |
| download | rust-9d6b93c3e6609aa104da23cb9091c6c2e277f71e.tar.gz rust-9d6b93c3e6609aa104da23cb9091c6c2e277f71e.zip | |
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.
| -rw-r--r-- | library/alloc/src/vec/into_iter.rs | 29 |
1 files 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 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> { }; } - fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R + fn fold<B, F>(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<B, F, R>(&mut self, mut accum: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: core::ops::Try<Output = B>, { - 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. |
