diff options
| author | Jubilee <46493976+workingjubilee@users.noreply.github.com> | 2021-10-04 13:58:07 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-04 13:58:07 -0700 |
| commit | ca8a10845f42fcb3e01f21a8f874a507d0512447 (patch) | |
| tree | 7e9d65d2bdff8cf75d7e8a33d1b16bde113d4404 /library/alloc/src/vec | |
| parent | 4e9cf04c98dd65a7f4baedc2984fae18d5fecfd1 (diff) | |
| parent | ffd7ade2035eb92c77421ca7dcde4cf40c863c7b (diff) | |
| download | rust-ca8a10845f42fcb3e01f21a8f874a507d0512447.tar.gz rust-ca8a10845f42fcb3e01f21a8f874a507d0512447.zip | |
Rollup merge of #87091 - the8472:more-advance-by-impls, r=joshtriplett
implement advance_(back_)_by on more iterators Add more efficient, non-default implementations for `feature(iter_advance_by)` (#77404) on more iterators and adapters. This PR only contains implementations where skipping over items doesn't elide any observable side-effects such as user-provided closures or `clone()` functions. I'll put those in a separate PR.
Diffstat (limited to 'library/alloc/src/vec')
| -rw-r--r-- | library/alloc/src/vec/into_iter.rs | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 4cb0a4b10bd..8a2d254a834 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -162,6 +162,29 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> { } #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let step_size = self.len().min(n); + let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); + if mem::size_of::<T>() == 0 { + // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound + // effectively results in unsigned pointers representing positions 0..usize::MAX, + // which is valid for ZSTs. + self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T } + } else { + // SAFETY: the min() above ensures that step_size is in bounds + self.ptr = unsafe { self.ptr.add(step_size) }; + } + // SAFETY: the min() above ensures that step_size is in bounds + unsafe { + ptr::drop_in_place(to_drop); + } + if step_size < n { + return Err(step_size); + } + Ok(()) + } + + #[inline] fn count(self) -> usize { self.len() } @@ -203,6 +226,29 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { Some(unsafe { ptr::read(self.end) }) } } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let step_size = self.len().min(n); + if mem::size_of::<T>() == 0 { + // SAFETY: same as for advance_by() + self.end = unsafe { + arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T + } + } else { + // SAFETY: same as for advance_by() + self.end = unsafe { self.end.offset(step_size.wrapping_neg() as isize) }; + } + let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); + // SAFETY: same as for advance_by() + unsafe { + ptr::drop_in_place(to_drop); + } + if step_size < n { + return Err(step_size); + } + Ok(()) + } } #[stable(feature = "rust1", since = "1.0.0")] |
