diff --git a/src/iterators/intoiter.rs b/src/iterators/intoiter.rs new file mode 100644 index 0000000..ccb4c1d --- /dev/null +++ b/src/iterators/intoiter.rs @@ -0,0 +1,182 @@ +use { + crate::{ + Allocator, + DropDealloc, + Global, + RawSmallVec, + SmallVec, + TaggedLen + }, + core::{ + fmt::Debug, + mem::{ + ManuallyDrop, + align_of, + size_of + }, + ptr::NonNull + } +}; + +/// An iterator that consumes a `SmallVec` and yields its items by value. +/// +/// Returned from [`SmallVec::into_iter`][1]. +/// +/// [1]: struct.SmallVec.html#method.into_iter +pub struct IntoIter { + // # Safety + // + // `end` decides whether the data lives on the heap or not + // + // The members from begin..end are initialized + raw: RawSmallVec, + allocator: A, + begin: usize, + end: TaggedLen +} + +// SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) +// an `IntoIter` is equivalent to sending (or sharing) a `SmallVec`. +unsafe impl Send for IntoIter {} +unsafe impl Sync for IntoIter {} + +impl IntoIter { + #[inline] + pub const fn as_slice(&self) -> &[T] { + let (end, on_heap) = self.end.parts(); + // SAFETY: `end` tells which buffer is active, and the members in + // `self.begin..end` are all initialized. So the pointer arithmetic is + // valid, and so is the construction of the slice + unsafe { + let ptr = self.raw.as_ptr(on_heap); + core::slice::from_raw_parts(ptr.add(self.begin), end - self.begin) + } + } + + #[inline] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + let (end, on_heap) = self.end.parts(); + // SAFETY: see above + unsafe { + let ptr = self.raw.as_mut_ptr(on_heap); + core::slice::from_raw_parts_mut(ptr.add(self.begin), end - self.begin) + } + } + + #[cfg(feature = "specialization")] + pub(crate) fn mark_consumed(&mut self) { + self.begin = self.end.len(); + } +} + +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + let (end, on_heap) = self.end.parts(); + if self.begin == end { + None + } else { + // SAFETY: see above + unsafe { + let ptr = self.raw.as_mut_ptr(on_heap); + let value = ptr.add(self.begin).read(); + self.begin += 1; + Some(value) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.end.len() - self.begin; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + let (end, on_heap) = self.end.parts(); + if self.begin == end { + None + } else { + // SAFETY: see above + unsafe { + let ptr = self.raw.as_mut_ptr(on_heap); + self.end.sub(1); + let value = ptr.add(end - 1).read(); + Some(value) + } + } + } +} + +impl ExactSizeIterator for IntoIter {} +impl core::iter::FusedIterator for IntoIter {} + +impl Drop for IntoIter { + fn drop(&mut self) { + // SAFETY: see above + unsafe { + let (end, on_heap) = self.end.parts(); + let begin = self.begin; + let ptr = self.raw.as_mut_ptr(on_heap); + let _drop_dealloc = if on_heap { + let capacity = self.raw.heap.1; + Some(DropDealloc { + ptr: NonNull::new_unchecked(ptr as *mut u8), + size_bytes: capacity * size_of::(), + align: align_of::(), + allocator: &self.allocator + }) + } else { + None + }; + core::ptr::slice_from_raw_parts_mut(ptr.add(begin), end - begin).drop_in_place(); + } + } +} + +impl Clone for IntoIter { + #[inline] + fn clone(&self) -> IntoIter { + let mut vec = SmallVec { + length: TaggedLen::new(0, false), + raw: RawSmallVec::new(), + allocator: self.allocator.clone() + }; + + vec.extend(self.as_slice()); + + vec.into_iter() + } +} + +impl IntoIterator for SmallVec { + type IntoIter = IntoIter; + type Item = T; + + fn into_iter(self) -> Self::IntoIter { + // SAFETY: we move out of this.raw by reading the value at its address, + // which is fine since we don't drop it + unsafe { + // Set SmallVec length to zero as `IntoIter` drop handles dropping + // of the elements + let this = ManuallyDrop::new(self); + IntoIter { + raw: (&raw const this.raw).read(), + allocator: (&raw const this.allocator).read(), + begin: 0, + end: this.length + } + } + } +} + +impl Debug for IntoIter { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + } +} diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 76d773d..8d92dcc 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1,5 +1,6 @@ pub mod drain; pub mod extractif; +pub mod intoiter; #[cfg(feature = "rayon")] mod rayon; diff --git a/src/lib.rs b/src/lib.rs index 92c2656..eca6495 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,8 @@ mod errors; mod iterators; pub use iterators::{ drain::Drain, - extractif::ExtractIf + extractif::ExtractIf, + intoiter::IntoIter }; mod macros; #[cfg(feature = "malloc_size_of")] @@ -239,98 +240,6 @@ impl Drop for Splice<'_, I, N> { } } -/// An iterator that consumes a `SmallVec` and yields its items by value. -/// -/// Returned from [`SmallVec::into_iter`][1]. -/// -/// [1]: struct.SmallVec.html#method.into_iter -pub struct IntoIter { - // # Safety - // - // `end` decides whether the data lives on the heap or not - // - // The members from begin..end are initialized - raw: RawSmallVec, - allocator: A, - begin: usize, - end: TaggedLen -} - -// SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) -// an `IntoIter` is equivalent to sending (or sharing) a `SmallVec`. -unsafe impl Send for IntoIter {} -unsafe impl Sync for IntoIter {} - -impl IntoIter { - #[inline] - pub const fn as_slice(&self) -> &[T] { - let (end, on_heap) = self.end.parts(); - // SAFETY: `end` tells which buffer is active, and the members in - // `self.begin..end` are all initialized. So the pointer arithmetic is - // valid, and so is the construction of the slice - unsafe { - let ptr = self.raw.as_ptr(on_heap); - core::slice::from_raw_parts(ptr.add(self.begin), end - self.begin) - } - } - - #[inline] - pub const fn as_mut_slice(&mut self) -> &mut [T] { - let (end, on_heap) = self.end.parts(); - // SAFETY: see above - unsafe { - let ptr = self.raw.as_mut_ptr(on_heap); - core::slice::from_raw_parts_mut(ptr.add(self.begin), end - self.begin) - } - } -} - -impl Iterator for IntoIter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - let (end, on_heap) = self.end.parts(); - if self.begin == end { - None - } else { - // SAFETY: see above - unsafe { - let ptr = self.raw.as_mut_ptr(on_heap); - let value = ptr.add(self.begin).read(); - self.begin += 1; - Some(value) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let size = self.end.len() - self.begin; - (size, Some(size)) - } -} - -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - let (end, on_heap) = self.end.parts(); - if self.begin == end { - None - } else { - // SAFETY: see above - unsafe { - let ptr = self.raw.as_mut_ptr(on_heap); - self.end.sub(1); - let value = ptr.add(end - 1).read(); - Some(value) - } - } - } -} -impl ExactSizeIterator for IntoIter {} -impl core::iter::FusedIterator for IntoIter {} - impl SmallVec { #[inline] pub const fn new() -> SmallVec { @@ -1744,29 +1653,6 @@ impl Drop for SmallVec { } } -impl Drop for IntoIter { - fn drop(&mut self) { - // SAFETY: see above - unsafe { - let (end, on_heap) = self.end.parts(); - let begin = self.begin; - let ptr = self.raw.as_mut_ptr(on_heap); - let _drop_dealloc = if on_heap { - let capacity = self.raw.heap.1; - Some(DropDealloc { - ptr: NonNull::new_unchecked(ptr as *mut u8), - size_bytes: capacity * size_of::(), - align: align_of::(), - allocator: &self.allocator - }) - } else { - None - }; - core::ptr::slice_from_raw_parts_mut(ptr.add(begin), end - begin).drop_in_place(); - } - } -} - /// This function is used in the [`smallvec`] macro. /// It is recommended to use the macro instead of using this function. #[doc(hidden)] @@ -1988,21 +1874,6 @@ impl Clone for SmallVec } } -impl Clone for IntoIter { - #[inline] - fn clone(&self) -> IntoIter { - let mut vec = SmallVec { - length: TaggedLen::new(0, false), - raw: RawSmallVec::new(), - allocator: self.allocator.clone() - }; - - vec.extend(self.as_slice()); - - vec.into_iter() - } -} - impl Extend for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2048,27 +1919,6 @@ impl core::iter::FromIterator for SmallVec { } } -impl IntoIterator for SmallVec { - type IntoIter = IntoIter; - type Item = T; - - fn into_iter(self) -> Self::IntoIter { - // SAFETY: we move out of this.raw by reading the value at its address, - // which is fine since we don't drop it - unsafe { - // Set SmallVec length to zero as `IntoIter` drop handles dropping - // of the elements - let this = ManuallyDrop::new(self); - IntoIter { - raw: (&raw const this.raw).read(), - allocator: (&raw const this.allocator).read(), - begin: 0, - end: this.length - } - } - } -} - impl<'a, T, const N: usize, A: Allocator> IntoIterator for &'a SmallVec { type IntoIter = core::slice::Iter<'a, T>; type Item = &'a T; @@ -2099,12 +1949,6 @@ impl Debug for SmallVec { } } -impl Debug for IntoIter { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("IntoIter").field(&self.as_slice()).finish() - } -} - #[cfg(feature = "arbitrary")] #[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))] impl<'a, T, const N: usize> arbitrary::Arbitrary<'a> for SmallVec diff --git a/src/specialization.rs b/src/specialization.rs index 5dfed58..fc5f5fd 100644 --- a/src/specialization.rs +++ b/src/specialization.rs @@ -129,7 +129,7 @@ impl SpecExtend