From d0a2b6ee81f2622704d0c33bc830b6ea2a727bb2 Mon Sep 17 00:00:00 2001 From: Matt Paras Date: Wed, 21 Jan 2026 16:33:35 -0800 Subject: [PATCH 1/5] add into iter impl --- src/lib.rs | 9 ++- src/shared.rs | 54 ++++++------- src/vector.rs | 218 ++++++++++++++++++++++++++++++-------------------- 3 files changed, 163 insertions(+), 118 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 243a1be..d7fe0ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,18 @@ #![cfg_attr(feature = "nightly", feature(allocator_api))] #![doc = include_str!("../README.md")] +mod drain; +mod intoiter; mod raw; mod shared; -mod vector; -mod drain; mod splice; +mod vector; pub use raw::{AtomicRefCount, BufferSize, DefaultRefCount, RefCount}; pub use shared::{AtomicSharedVector, RefCountedVector, SharedVector}; -pub use vector::{Vector, RawVector}; +pub use vector::{RawVector, Vector}; + +pub use intoiter::IntoIter; pub mod alloc { pub use allocator_api2::alloc::{AllocError, Allocator, Global}; diff --git a/src/shared.rs b/src/shared.rs index f28f3bf..56059f9 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -1,13 +1,13 @@ use core::fmt::Debug; use core::ops::{Deref, DerefMut, Index, IndexMut}; use core::ptr::NonNull; -use core::{mem, ptr}; use core::sync::atomic::Ordering; +use core::{mem, ptr}; -use crate::raw; use crate::alloc::{AllocError, Allocator, Global}; +use crate::raw; use crate::raw::{BufferSize, HeaderBuffer}; -use crate::vector::{Vector, RawVector}; +use crate::vector::{RawVector, Vector}; use crate::{grow_amortized, AtomicRefCount, DefaultRefCount, RefCount}; /// A heap allocated, atomically reference counted, immutable contiguous buffer containing elements of type `T`. @@ -100,10 +100,13 @@ impl RefCountedVector { Ok(RefCountedVector { inner: HeaderBuffer::from_raw(ptr.cast()), }) - } + } } - pub fn try_from_slice_in(slice: &[T], allocator: A) -> Result where T: Clone { + pub fn try_from_slice_in(slice: &[T], allocator: A) -> Result + where + T: Clone, + { let mut v = Self::try_with_capacity_in(slice.len(), allocator)?; unsafe { @@ -151,7 +154,7 @@ impl RefCountedVector { unsafe { self.inner.as_ref().ref_count.add_ref(); RefCountedVector { - inner: HeaderBuffer::from_raw(self.inner.header) + inner: HeaderBuffer::from_raw(self.inner.header), } } } @@ -159,9 +162,7 @@ impl RefCountedVector { /// Extracts a slice containing the entire vector. #[inline] pub fn as_slice(&self) -> &[T] { - unsafe { - core::slice::from_raw_parts(self.data_ptr(), self.len()) - } + unsafe { core::slice::from_raw_parts(self.data_ptr(), self.len()) } } /// Returns true if this is the only existing handle to the buffer. @@ -232,7 +233,10 @@ impl RefCountedVector { #[inline] pub fn data_ptr(&self) -> *mut T { - unsafe { (self.inner.as_ptr() as *mut u8).add(raw::header_size::, T>()) as *mut T } + unsafe { + (self.inner.as_ptr() as *mut u8).add(raw::header_size::, T>()) + as *mut T + } } // SAFETY: call this only if the vector is unique. @@ -261,10 +265,7 @@ impl RefCountedVector { mem::forget(self); Vector { - raw: RawVector { - data, - header, - }, + raw: RawVector { data, header }, allocator, } } @@ -286,9 +287,7 @@ impl RefCountedVector { pub fn pop(&mut self) -> Option { self.ensure_unique(); - unsafe { - raw::pop(self.data_ptr(), &mut self.vec_header_mut()) - } + unsafe { raw::pop(self.data_ptr(), &mut self.vec_header_mut()) } } /// Removes an element from the vector and returns it. @@ -392,9 +391,7 @@ impl RefCountedVector { A: Clone, { self.ensure_unique(); - unsafe { - core::slice::from_raw_parts_mut(self.data_ptr(), self.len()) - } + unsafe { core::slice::from_raw_parts_mut(self.data_ptr(), self.len()) } } /// Allocates a duplicate of this buffer (infallible). @@ -430,7 +427,7 @@ impl RefCountedVector { raw::extend_from_slice_assuming_capacity( clone.data_ptr(), clone.vec_header_mut(), - self.as_slice() + self.as_slice(), ); Ok(clone) @@ -539,12 +536,18 @@ impl RefCountedVector { if other.is_unique() { // Fast path: memcpy raw::move_data( - other.data_ptr(), &mut other.inner.header.as_mut().vec, - self.data_ptr(), &mut self.inner.as_mut().vec, + other.data_ptr(), + &mut other.inner.header.as_mut().vec, + self.data_ptr(), + &mut self.inner.as_mut().vec, ) } else { // Slow path, clone each item. - raw::extend_from_slice_assuming_capacity(self.data_ptr(), self.vec_header_mut(), other.as_slice()); + raw::extend_from_slice_assuming_capacity( + self.data_ptr(), + self.vec_header_mut(), + other.as_slice(), + ); *other = Self::try_with_capacity_in(other.capacity(), self.inner.allocator().clone()) @@ -611,7 +614,6 @@ impl RefCountedVector { Ok(()) } - // TODO: remove this one? /// Returns the concatenation of two vectors. pub fn concatenate(mut self, mut other: Self) -> Self @@ -642,7 +644,6 @@ impl Drop for RefCountedVector { } } - unsafe impl Send for AtomicSharedVector {} unsafe impl Sync for AtomicSharedVector {} @@ -842,7 +843,6 @@ fn ensure_unique_empty() { v.ensure_unique(); } - #[test] fn shrink_to_zero() { let mut v: SharedVector = SharedVector::new(); diff --git a/src/vector.rs b/src/vector.rs index 05e6e41..eb28d5a 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -1,13 +1,14 @@ use core::fmt::Debug; +use core::ops::RangeBounds; use core::ops::{Deref, DerefMut, Index, IndexMut}; use core::ptr::NonNull; use core::{mem, ptr}; -use core::ops::RangeBounds; use crate::alloc::{AllocError, Allocator, Global}; use crate::drain::Drain; use crate::raw::{ - self, buffer_layout, AtomicRefCount, BufferSize, Header, HeaderBuffer, RefCount, VecHeader, move_data, + self, buffer_layout, move_data, AtomicRefCount, BufferSize, Header, HeaderBuffer, RefCount, + VecHeader, }; use crate::shared::{AtomicSharedVector, SharedVector}; use crate::splice::Splice; @@ -42,13 +43,19 @@ pub struct RawVector { impl RawVector { /// Creates an empty, unallocated raw vector. pub fn new() -> Self { - RawVector { data: NonNull::dangling(), header: VecHeader { len: 0, cap: 0 } } + RawVector { + data: NonNull::dangling(), + header: VecHeader { len: 0, cap: 0 }, + } } /// Creates an empty pre-allocated vector with a given storage capacity. /// /// Does not allocate memory if `cap` is zero. - pub fn try_with_capacity(allocator: &A, cap: usize) -> Result, AllocError> { + pub fn try_with_capacity( + allocator: &A, + cap: usize, + ) -> Result, AllocError> { if cap == 0 { return Ok(RawVector::new()); } @@ -60,7 +67,10 @@ impl RawVector { )); Ok(RawVector { data, - header: VecHeader { cap: cap as BufferSize, len: 0 }, + header: VecHeader { + cap: cap as BufferSize, + len: 0, + }, }) } } @@ -91,8 +101,8 @@ impl RawVector { for _ in 0..(n - 1) { v.push(allocator, elem.clone()) } - - v.push(allocator, elem); + + v.push(allocator, elem); } Ok(v) @@ -160,9 +170,7 @@ impl RawVector { /// Clears the vector, removing all values. pub fn clear(&mut self) { - unsafe { - raw::clear(self.data_ptr(), &mut self.header) - } + unsafe { raw::clear(self.data_ptr(), &mut self.header) } } unsafe fn base_ptr(&self, _allocator: &A) -> NonNull { @@ -211,9 +219,7 @@ impl RawVector { /// Removes the last element from the vector and returns it, or `None` if it is empty. #[inline] pub fn pop(&mut self) -> Option { - unsafe { - raw::pop(self.data_ptr(), &mut self.header) - } + unsafe { raw::pop(self.data_ptr(), &mut self.header) } } /// Removes and returns the element at position `index` within the vector, @@ -354,7 +360,12 @@ impl RawVector { self.try_reserve(allocator, other.len()).unwrap(); unsafe { - move_data(other.data_ptr(), &mut other.header, self.data_ptr(), &mut self.header); + move_data( + other.data_ptr(), + &mut other.header, + self.data_ptr(), + &mut self.header, + ); } } @@ -363,7 +374,11 @@ impl RawVector { /// # Safety /// /// The provided allocator must be the one this raw vector was created with. - pub unsafe fn extend(&mut self, allocator: &A, data: impl IntoIterator) { + pub unsafe fn extend( + &mut self, + allocator: &A, + data: impl IntoIterator, + ) { let mut iter = data.into_iter(); let (min, max) = iter.size_hint(); self.try_reserve(allocator, max.unwrap_or(min)).unwrap(); @@ -413,11 +428,14 @@ impl RawVector { where T: Clone, { - let mut clone = - Self::try_with_capacity(allocator, cap.max(self.len())).unwrap(); + let mut clone = Self::try_with_capacity(allocator, cap.max(self.len())).unwrap(); unsafe { - raw::extend_from_slice_assuming_capacity(clone.data_ptr(), &mut clone.header, self.as_slice()); + raw::extend_from_slice_assuming_capacity( + clone.data_ptr(), + &mut clone.header, + self.as_slice(), + ); } clone @@ -425,7 +443,11 @@ impl RawVector { // Note: Marking this #[inline(never)] is a pretty large regression in the push benchmark. #[cold] - unsafe fn try_realloc_additional(&mut self, allocator: &A, additional: usize) -> Result<(), AllocError> { + unsafe fn try_realloc_additional( + &mut self, + allocator: &A, + additional: usize, + ) -> Result<(), AllocError> { let new_cap = grow_amortized(self.len(), additional); if new_cap < self.len() { return Err(AllocError); @@ -435,7 +457,11 @@ impl RawVector { } #[cold] - unsafe fn try_realloc_with_capacity(&mut self, allocator: &A, new_cap: usize) -> Result<(), AllocError> { + unsafe fn try_realloc_with_capacity( + &mut self, + allocator: &A, + new_cap: usize, + ) -> Result<(), AllocError> { type R = DefaultRefCount; unsafe { @@ -486,7 +512,11 @@ impl RawVector { /// /// The provided allocator must be the one this raw vector was created with. #[inline] - pub unsafe fn try_reserve(&mut self, allocator: &A, additional: usize) -> Result<(), AllocError> { + pub unsafe fn try_reserve( + &mut self, + allocator: &A, + additional: usize, + ) -> Result<(), AllocError> { if self.remaining_capacity() < additional { self.try_realloc_additional(allocator, additional)?; } @@ -507,7 +537,11 @@ impl RawVector { /// # Safety /// /// The provided allocator must be the one this raw vector was created with. - pub unsafe fn try_reserve_exact(&mut self, allocator: &A, additional: usize) -> Result<(), AllocError> { + pub unsafe fn try_reserve_exact( + &mut self, + allocator: &A, + additional: usize, + ) -> Result<(), AllocError> { if self.remaining_capacity() >= additional { return Ok(()); } @@ -523,14 +557,14 @@ impl RawVector { /// # Safety /// /// The provided allocator must be the one this raw vector was created with. - pub unsafe fn shrink_to(&mut self, allocator: &A, min_capacity: usize) - { + pub unsafe fn shrink_to(&mut self, allocator: &A, min_capacity: usize) { let min_capacity = min_capacity.max(self.len()); if self.capacity() <= min_capacity { return; } - self.try_realloc_with_capacity(allocator, min_capacity).unwrap(); + self.try_realloc_with_capacity(allocator, min_capacity) + .unwrap(); } /// Shrinks the capacity of the vector as much as possible. @@ -538,8 +572,7 @@ impl RawVector { /// # Safety /// /// The provided allocator must be the one this raw vector was created with. - pub unsafe fn shrink_to_fit(&mut self, allocator: &A) - { + pub unsafe fn shrink_to_fit(&mut self, allocator: &A) { self.shrink_to(allocator, self.len()) } @@ -580,12 +613,12 @@ impl RawVector { let end = match range.end_bound() { Included(n) => *n + 1, Excluded(n) => *n, - Unbounded => len + Unbounded => len, }; let start = match range.start_bound() { Included(n) => *n, - Excluded(n) => *n+1, - Unbounded => 0 + Excluded(n) => *n + 1, + Unbounded => 0, }; assert!(end <= len); assert!(start <= end); @@ -600,7 +633,7 @@ impl RawVector { iter: range_slice.iter(), vec: NonNull::from(self), } - } + } } /// Creates a splicing iterator that replaces the specified range in the vector @@ -631,7 +664,7 @@ impl RawVector { &'l mut self, allocator: &'l A, range: R, - replace_with: I + replace_with: I, ) -> Splice<'l, ::IntoIter, A> where A: Allocator, @@ -696,7 +729,9 @@ impl RawVector { unsafe { ptr::copy( self.v.as_ptr().add(self.processed_len), - self.v.as_mut_ptr().add(self.processed_len - self.deleted_cnt), + self.v + .as_mut_ptr() + .add(self.processed_len - self.deleted_cnt), self.original_len - self.processed_len, ); } @@ -706,7 +741,12 @@ impl RawVector { } } - let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; + let mut g = BackshiftOnDrop { + v: self, + processed_len: 0, + deleted_cnt: 0, + original_len, + }; fn process_loop( original_len: usize, @@ -772,9 +812,7 @@ impl> PartialEq<&[T]> for RawVector { } } -impl Eq for RawVector { - -} +impl Eq for RawVector {} impl AsRef<[T]> for RawVector { fn as_ref(&self) -> &[T] { @@ -849,12 +887,14 @@ impl Debug for RawVector { } impl core::hash::Hash for RawVector { - fn hash(&self, state: &mut H) where H: core::hash::Hasher { + fn hash(&self, state: &mut H) + where + H: core::hash::Hasher, + { self.as_slice().hash(state) } } - /// A heap allocated, mutable contiguous buffer containing elements of type `T`. /// /// @@ -891,8 +931,6 @@ impl Vector { } } - - /// Creates an empty pre-allocated vector with a given storage capacity. /// /// Does not allocate memory if `cap` is zero. @@ -911,7 +949,10 @@ impl Vector { where T: Clone, { - Vector { raw: RawVector::try_from_slice(&Global, data).unwrap(), allocator: Global } + Vector { + raw: RawVector::try_from_slice(&Global, data).unwrap(), + allocator: Global, + } } /// Creates a vector with `n` clones of `elem`. @@ -919,7 +960,10 @@ impl Vector { where T: Clone, { - Vector { raw: RawVector::try_from_elem(&Global, elem, n).unwrap(), allocator: Global } + Vector { + raw: RawVector::try_from_elem(&Global, elem, n).unwrap(), + allocator: Global, + } } } @@ -945,7 +989,6 @@ impl Vector { Ok(Vector { raw, allocator }) } - #[inline(always)] /// Returns `true` if the vector contains no elements. pub fn is_empty(&self) -> bool { @@ -988,9 +1031,7 @@ impl Vector { /// Clears the vector, removing all values. pub fn clear(&mut self) { - unsafe { - raw::clear(self.raw.data_ptr(), &mut self.raw.header) - } + unsafe { raw::clear(self.raw.data_ptr(), &mut self.raw.header) } } unsafe fn into_header_buffer(mut self) -> HeaderBuffer @@ -1112,7 +1153,7 @@ impl Vector { /// Panics if `index > len`. #[inline(always)] pub fn insert(&mut self, index: usize, element: T) { - unsafe { self.raw.insert(&self.allocator, index, element) } + unsafe { self.raw.insert(&self.allocator, index, element) } } /// Clones and appends the contents of the slice to the back of a collection. @@ -1121,9 +1162,7 @@ impl Vector { where T: Clone, { - unsafe { - self.raw.extend_from_slice(&self.allocator, data) - } + unsafe { self.raw.extend_from_slice(&self.allocator, data) } } /// Moves all the elements of `other` into `self`, leaving `other` empty. @@ -1132,17 +1171,13 @@ impl Vector { where T: Clone, { - unsafe { - self.raw.append(&self.allocator, &mut other.raw) - } + unsafe { self.raw.append(&self.allocator, &mut other.raw) } } /// Appends the contents of an iterator to the back of a collection. #[inline(always)] pub fn extend(&mut self, data: impl IntoIterator) { - unsafe { - self.raw.extend(&self.allocator, data) - } + unsafe { self.raw.extend(&self.allocator, data) } } /// Allocates a clone of this buffer. @@ -1175,16 +1210,12 @@ impl Vector { #[inline(always)] pub fn reserve(&mut self, additional: usize) { - unsafe { - self.raw.try_reserve(&self.allocator, additional).unwrap() - } + unsafe { self.raw.try_reserve(&self.allocator, additional).unwrap() } } #[inline(always)] pub fn try_reserve(&mut self, additional: usize) -> Result<(), AllocError> { - unsafe { - self.raw.try_reserve(&self.allocator, additional) - } + unsafe { self.raw.try_reserve(&self.allocator, additional) } } /// Reserves the minimum capacity for at least `additional` elements to be inserted in the given vector. @@ -1214,9 +1245,7 @@ impl Vector { /// Note that the allocator may give the collection more space than it requests. Therefore, capacity can not /// be relied upon to be precisely minimal. Prefer `try_reserve` if future insertions are expected. pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), AllocError> { - unsafe { - self.raw.try_reserve_exact(&self.allocator, additional) - } + unsafe { self.raw.try_reserve_exact(&self.allocator, additional) } } /// Shrinks the capacity of the vector with a lower bound. @@ -1228,9 +1257,7 @@ impl Vector { where T: Clone, { - unsafe { - self.raw.shrink_to(&self.allocator, min_capacity) - } + unsafe { self.raw.shrink_to(&self.allocator, min_capacity) } } /// Shrinks the capacity of the vector as much as possible. @@ -1239,9 +1266,7 @@ impl Vector { where T: Clone, { - unsafe { - self.raw.shrink_to_fit(&self.allocator) - } + unsafe { self.raw.shrink_to_fit(&self.allocator) } } /// Removes the specified range from the vector in bulk, returning all @@ -1296,7 +1321,7 @@ impl Vector { pub fn splice( &mut self, range: R, - replace_with: I + replace_with: I, ) -> Splice<'_, ::IntoIter, A> where R: RangeBounds, @@ -1345,9 +1370,7 @@ impl Vector { impl Drop for Vector { fn drop(&mut self) { - unsafe { - self.raw.deallocate(&self.allocator) - } + unsafe { self.raw.deallocate(&self.allocator) } } } @@ -1454,7 +1477,10 @@ impl From> for Vector core::hash::Hash for Vector { - fn hash(&self, state: &mut H) where H: core::hash::Hasher { + fn hash(&self, state: &mut H) + where + H: core::hash::Hasher, + { self.as_slice().hash(state) } } @@ -1580,14 +1606,16 @@ fn borrowd_dyn_alloc() { impl DataStructure<'static> { fn new() -> DataStructure<'static> { DataStructure { - data: Vector::new_in(&Global as &'static dyn Allocator) + data: Vector::new_in(&Global as &'static dyn Allocator), } } } impl<'a> DataStructure<'a> { fn new_in(allocator: &'a dyn Allocator) -> DataStructure<'a> { - DataStructure { data: Vector::new_in(allocator) } + DataStructure { + data: Vector::new_in(allocator), + } } fn push(&mut self, val: u32) { @@ -1598,10 +1626,9 @@ fn borrowd_dyn_alloc() { let mut ds1 = DataStructure::new(); ds1.push(1); - let alloc = Global; + let alloc = Global; let mut ds2 = DataStructure::new_in(&alloc); ds2.push(2); - } #[test] @@ -1613,17 +1640,32 @@ fn splice1() { #[test] fn drain1() { - let mut vectors: [Vector>; 4] = [ - Vector::new(), - Vector::new(), - Vector::new(), - Vector::new(), - ]; + let mut vectors: [Vector>; 4] = + [Vector::new(), Vector::new(), Vector::new(), Vector::new()]; vectors[0].shrink_to(3906369431118283232); vectors[2].extend_from_slice(&[Box::new(1), Box::new(2), Box::new(3)]); let vec = &mut vectors[2]; let len = vec.len(); - let start = if len > 0 { 16059518370053021184 % len } else { 0 }; + let start = if len > 0 { + 16059518370053021184 % len + } else { + 0 + }; let end = 16059518370053021185.min(len); vectors[2].drain(start..end); } + +#[test] +fn into_iter() { + let mut vector = Vector::new(); + vector.push(10); + vector.push(20); + vector.push(30); + vector.push(40); + vector.push(50); + vector.push(60); + + let res = vector.into_iter().collect::>(); + + dbg!(res); +} From 6a8d3029c0c9b5939a51bfcb85038c651ed0e815 Mon Sep 17 00:00:00 2001 From: Matt Paras Date: Wed, 21 Jan 2026 16:37:32 -0800 Subject: [PATCH 2/5] add into iter --- src/intoiter.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/intoiter.rs diff --git a/src/intoiter.rs b/src/intoiter.rs new file mode 100644 index 0000000..5e0b51f --- /dev/null +++ b/src/intoiter.rs @@ -0,0 +1,114 @@ +use std::{ + mem, + ptr::{self, NonNull}, +}; + +use crate::{RawVector, Vector}; + +pub struct IntoIter { + _buf: RawVector, // we don't actually care about this. Just need it to live. + iter: RawValIter, +} + +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} + +impl ExactSizeIterator for IntoIter {} + +impl Drop for IntoIter { + fn drop(&mut self) { + for _ in &mut *self {} + } +} + +impl IntoIterator for Vector { + type Item = T; + type IntoIter = IntoIter; + fn into_iter(self) -> IntoIter { + let (iter, buf) = unsafe { (RawValIter::new(&self), ptr::read(&self.raw)) }; + + mem::forget(self); + + IntoIter { iter, _buf: buf } + } +} + +struct RawValIter { + start: *const T, + end: *const T, +} + +impl RawValIter { + unsafe fn new(slice: &[T]) -> Self { + RawValIter { + start: slice.as_ptr(), + end: if mem::size_of::() == 0 { + ((slice.as_ptr() as usize) + slice.len()) as *const _ + } else if slice.len() == 0 { + slice.as_ptr() + } else { + slice.as_ptr().add(slice.len()) + }, + } + } +} + +impl Iterator for RawValIter { + type Item = T; + fn next(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + if mem::size_of::() == 0 { + self.start = (self.start as usize + 1) as *const _; + Some(ptr::read(NonNull::::dangling().as_ptr())) + } else { + let old_ptr = self.start; + self.start = self.start.offset(1); + Some(ptr::read(old_ptr)) + } + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let elem_size = mem::size_of::(); + let len = + (self.end as usize - self.start as usize) / if elem_size == 0 { 1 } else { elem_size }; + (len, Some(len)) + } +} + +impl DoubleEndedIterator for RawValIter { + fn next_back(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + if mem::size_of::() == 0 { + self.end = (self.end as usize - 1) as *const _; + Some(ptr::read(NonNull::::dangling().as_ptr())) + } else { + self.end = self.end.offset(-1); + Some(ptr::read(self.end)) + } + } + } + } +} + +impl ExactSizeIterator for RawValIter {} From 45d01533ff91f63aea260c30fedcd54f1bb78f79 Mon Sep 17 00:00:00 2001 From: Matt Paras Date: Wed, 21 Jan 2026 19:14:25 -0800 Subject: [PATCH 3/5] get tests passing --- src/intoiter.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++----- src/raw.rs | 26 +++++++++++++++++------ src/vector.rs | 17 +++++++++++++++ 3 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/intoiter.rs b/src/intoiter.rs index 5e0b51f..dd607e4 100644 --- a/src/intoiter.rs +++ b/src/intoiter.rs @@ -5,12 +5,15 @@ use std::{ use crate::{RawVector, Vector}; -pub struct IntoIter { +use crate::alloc::{Allocator, Global}; + +pub struct IntoIter { _buf: RawVector, // we don't actually care about this. Just need it to live. iter: RawValIter, + pub(crate) allocator: A, } -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { self.iter.next() @@ -28,13 +31,18 @@ impl DoubleEndedIterator for IntoIter { impl ExactSizeIterator for IntoIter {} -impl Drop for IntoIter { +impl Drop for IntoIter { fn drop(&mut self) { + // drop any remaining elements for _ in &mut *self {} + + unsafe { + self._buf.deallocate_no_drop(&self.allocator); + } } } -impl IntoIterator for Vector { +impl IntoIterator for Vector { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { @@ -42,7 +50,11 @@ impl IntoIterator for Vector { mem::forget(self); - IntoIter { iter, _buf: buf } + IntoIter { + iter, + _buf: buf, + allocator: Global, + } } } @@ -112,3 +124,37 @@ impl DoubleEndedIterator for RawValIter { } impl ExactSizeIterator for RawValIter {} + +#[cfg(test)] +mod tests { + #[test] + fn into_iter_test() { + struct Foo { + value: Box, + } + + impl Foo { + pub fn new(value: i32) -> Self { + Self { + value: Box::new(value), + } + } + } + + impl Drop for Foo { + fn drop(&mut self) {} + } + + let mut vector = crate::Vector::new(); + + for i in 0..=100 { + vector.push(Foo::new(i)); + } + + let resulting = vector.into_iter().collect::>(); + + let sum = resulting.into_iter().map(|x| *x.value).sum::(); + + assert_eq!(sum, 5050) + } +} diff --git a/src/raw.rs b/src/raw.rs index 6490f24..a0cfd9e 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -30,7 +30,9 @@ pub struct VecHeader { } impl VecHeader { - fn remaining_capacity(&self) -> u32 { self.cap - self.len } + fn remaining_capacity(&self) -> u32 { + self.cap - self.len + } } #[repr(C)] @@ -173,8 +175,13 @@ impl HeaderBuffer { } } -pub unsafe fn move_data(src_data: *mut T, src_vec: &mut VecHeader, dst_data: *mut T, dst_vec: &mut VecHeader) { - debug_assert!(dst_vec.cap - dst_vec.len >= src_vec.len); +pub unsafe fn move_data( + src_data: *mut T, + src_vec: &mut VecHeader, + dst_data: *mut T, + dst_vec: &mut VecHeader, +) { + debug_assert!(dst_vec.cap - dst_vec.len >= src_vec.len); let len = src_vec.len; if len > 0 { unsafe { @@ -189,8 +196,11 @@ pub unsafe fn move_data(src_data: *mut T, src_vec: &mut VecHeader, dst_data: } } -pub unsafe fn extend_from_slice_assuming_capacity(data: *mut T, vec: &mut VecHeader, slice: &[T]) -where +pub unsafe fn extend_from_slice_assuming_capacity( + data: *mut T, + vec: &mut VecHeader, + slice: &[T], +) where T: Clone, { let len = slice.len() as u32; @@ -209,7 +219,11 @@ where } // Returns true if the iterator was emptied. -pub unsafe fn extend_within_capacity>(data: *mut T, vec: &mut VecHeader, iter: &mut I) -> bool { +pub unsafe fn extend_within_capacity>( + data: *mut T, + vec: &mut VecHeader, + iter: &mut I, +) -> bool { let inital_len = vec.len; let mut ptr = data.add(inital_len as usize); diff --git a/src/vector.rs b/src/vector.rs index eb28d5a..b6008c8 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -129,6 +129,19 @@ impl RawVector { self.header.len = 0; } + pub unsafe fn deallocate_no_drop(&mut self, allocator: &A) { + if self.header.cap == 0 { + return; + } + + self.clear_without_drop(); + self.deallocate_buffer(allocator); + + self.data = NonNull::dangling(); + self.header.cap = 0; + self.header.len = 0; + } + #[inline] /// Returns `true` if the vector contains no elements. pub fn is_empty(&self) -> bool { @@ -173,6 +186,10 @@ impl RawVector { unsafe { raw::clear(self.data_ptr(), &mut self.header) } } + pub fn clear_without_drop(&mut self) { + self.header.len = 0; + } + unsafe fn base_ptr(&self, _allocator: &A) -> NonNull { debug_assert!(self.header.cap > 0); raw::header_from_data_ptr::, T>(self.data).cast() From 9d24b3fce625c5a843c5d3ce89055c555582734b Mon Sep 17 00:00:00 2001 From: Matt Paras Date: Wed, 21 Jan 2026 19:24:42 -0800 Subject: [PATCH 4/5] add some more tests --- src/intoiter.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/intoiter.rs b/src/intoiter.rs index dd607e4..cfac1a5 100644 --- a/src/intoiter.rs +++ b/src/intoiter.rs @@ -127,6 +127,8 @@ impl ExactSizeIterator for RawValIter {} #[cfg(test)] mod tests { + use std::sync::atomic::AtomicUsize; + #[test] fn into_iter_test() { struct Foo { @@ -157,4 +159,72 @@ mod tests { assert_eq!(sum, 5050) } + + #[test] + fn into_iter_drops_everything() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct Foo { + value: Box, + } + + impl Foo { + pub fn new(value: i32) -> Self { + Self { + value: Box::new(value), + } + } + } + + impl Drop for Foo { + fn drop(&mut self) { + COUNTER.fetch_add(1, std::sync::atomic::Ordering::Acquire); + } + } + + let mut vector = crate::Vector::new(); + + for i in 0..=100 { + vector.push(Foo::new(i)); + } + + let resulting = vector.into_iter().collect::>(); + let sum = resulting.into_iter().map(|x| *x.value).sum::(); + assert_eq!(sum, 5050); + assert_eq!(COUNTER.load(std::sync::atomic::Ordering::Relaxed), 101); + } + + #[test] + fn into_iter_drops_everything_partial_usage() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct Foo {} + + impl Foo { + pub fn new() -> Self { + Self {} + } + } + + impl Drop for Foo { + fn drop(&mut self) { + COUNTER.fetch_add(1, std::sync::atomic::Ordering::Acquire); + } + } + + let mut vector = crate::Vector::new(); + + for _ in 0..=100 { + vector.push(Foo::new()); + } + + let mut iter = vector.into_iter(); + + iter.next(); + iter.next(); + + drop(iter); + + assert_eq!(COUNTER.load(std::sync::atomic::Ordering::Relaxed), 101); + } } From 48d64a5ab54e982e38a10f73ff81b8d50e8dc2e2 Mon Sep 17 00:00:00 2001 From: Matt Paras Date: Wed, 21 Jan 2026 19:46:35 -0800 Subject: [PATCH 5/5] remove extraneous test --- src/vector.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/vector.rs b/src/vector.rs index b6008c8..201ba4e 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -1671,18 +1671,3 @@ fn drain1() { let end = 16059518370053021185.min(len); vectors[2].drain(start..end); } - -#[test] -fn into_iter() { - let mut vector = Vector::new(); - vector.push(10); - vector.push(20); - vector.push(30); - vector.push(40); - vector.push(50); - vector.push(60); - - let res = vector.into_iter().collect::>(); - - dbg!(res); -}