about summary refs log tree commit diff
path: root/library/alloc/src/vec
diff options
context:
space:
mode:
authorThe8472 <git@infinite-source.de>2021-07-12 21:40:38 +0200
committerThe8472 <git@infinite-source.de>2021-09-30 21:23:28 +0200
commit2c6e67105e4967f8b37ebe9ed92880c6773eb29e (patch)
tree0f88634848fe9037428999d266c14ec0ea0e61b2 /library/alloc/src/vec
parent6dc08b909b469d58dd8fa54c57ab193b8cf95257 (diff)
downloadrust-2c6e67105e4967f8b37ebe9ed92880c6773eb29e.tar.gz
rust-2c6e67105e4967f8b37ebe9ed92880c6773eb29e.zip
implement advance_(back_)_by on more iterators
Diffstat (limited to 'library/alloc/src/vec')
-rw-r--r--library/alloc/src/vec/into_iter.rs45
1 files changed, 45 insertions, 0 deletions
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 4cb0a4b10bd..eae9ad076dc 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -162,6 +162,28 @@ 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);
+        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 {
+            let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
+            // SAFETY: the min() above ensures that step_size is in bounds
+            unsafe {
+                self.ptr = self.ptr.add(step_size);
+                ptr::drop_in_place(to_drop);
+            }
+        }
+        if step_size < n {
+            return Err(step_size);
+        }
+        Ok(())
+    }
+
+    #[inline]
     fn count(self) -> usize {
         self.len()
     }
@@ -203,6 +225,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")]