From eb846dbaca87f156419724e77fd52eb91ca01161 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 3 Dec 2021 21:36:51 -0800 Subject: Override `Iterator::advance(_back)_by` for `array::IntoIter` Because I happened to notice that `nth` is currently getting codegen'd as a loop even for `Copy` types: --- library/core/src/array/iter.rs | 44 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'library/core/src/array') diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 5d63cf03fcb..a146966c674 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -1,7 +1,7 @@ //! Defines the `IntoIter` owned iterator for arrays. use crate::{ - fmt, + cmp, fmt, iter::{self, ExactSizeIterator, FusedIterator, TrustedLen}, mem::{self, MaybeUninit}, ops::Range, @@ -150,6 +150,27 @@ impl Iterator for IntoIter { fn last(mut self) -> Option { self.next_back() } + + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let len = self.len(); + + // The number of elements to drop. Always in-bounds by construction. + let delta = cmp::min(n, len); + + let range_to_drop = self.alive.start..(self.alive.start + delta); + + // Moving the start marks them as conceptually "dropped", so if anything + // goes bad then our drop impl won't double-free them. + self.alive.start += delta; + + // SAFETY: These elements are currently initialized, so it's fine to drop them. + unsafe { + let slice = self.data.get_unchecked_mut(range_to_drop); + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); + } + + if n > len { Err(len) } else { Ok(()) } + } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] @@ -170,6 +191,27 @@ impl DoubleEndedIterator for IntoIter { unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } + + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let len = self.len(); + + // The number of elements to drop. Always in-bounds by construction. + let delta = cmp::min(n, len); + + let range_to_drop = (self.alive.end - delta)..self.alive.end; + + // Moving the end marks them as conceptually "dropped", so if anything + // goes bad then our drop impl won't double-free them. + self.alive.end -= delta; + + // SAFETY: These elements are currently initialized, so it's fine to drop them. + unsafe { + let slice = self.data.get_unchecked_mut(range_to_drop); + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); + } + + if n > len { Err(len) } else { Ok(()) } + } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -- cgit 1.4.1-3-g733a5