diff --git a/Cargo.lock b/Cargo.lock index f13a66b..0b103d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,10 +146,6 @@ version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" dependencies = [ - "bitflags", - "clap_lex", - "indexmap 1.9.3", - "textwrap", "clap_builder", ] @@ -319,37 +315,12 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.14.1" @@ -357,7 +328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" dependencies = [ "equivalent", - "hashbrown 0.17.1", + "hashbrown", ] [[package]] @@ -705,7 +676,7 @@ version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ - "indexmap 2.14.1", + "indexmap", "toml_datetime", "toml_parser", "winnow", diff --git a/src/iterators/extractif.rs b/src/iterators/extractif.rs new file mode 100644 index 0000000..9c93dd7 --- /dev/null +++ b/src/iterators/extractif.rs @@ -0,0 +1,102 @@ +use { + super::super::SmallVec, + core::fmt::{ + Debug, + Formatter, + Result as Format + } +}; + +/// An iterator which uses a closure to determine if an element should be +/// removed. +/// +/// Returned from [`SmallVec::extract_if`][1]. +/// +/// [1]: struct.SmallVec.html#method.extract_if +pub struct ExtractIf<'a, T, const N: usize, F> +where F: FnMut(&mut T) -> bool +{ + vec: &'a mut SmallVec, + /// The index of the item that will be inspected by the next call to `next`. + idx: usize, + /// Elements at and beyond this point will be retained. Must be equal or + /// smaller than `old_len`. + end: usize, + /// The number of items that have been drained (removed) thus far. + del: usize, + /// The original length of `vec` prior to draining. + old_len: usize, + /// The filter test predicate. + pred: F +} + +impl Debug for ExtractIf<'_, T, N, F> +where + F: FnMut(&mut T) -> bool, + T: Debug +{ + fn fmt(&self, f: &mut Formatter<'_>) -> Format { + f.debug_tuple("ExtractIf") + .field(&self.vec.as_slice()) + .finish() + } +} + +impl Iterator for ExtractIf<'_, T, N, F> +where F: FnMut(&mut T) -> bool +{ + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + while self.idx < self.end { + let i = self.idx; + let v = core::slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); + let drained = (self.pred)(&mut v[i]); + // Update the index *after* the predicate is called. If the + // index is updated prior and the predicate + // panics, the element at this index would be + // leaked. + self.idx += 1; + if drained { + self.del += 1; + return Some(core::ptr::read(&v[i])); + } else if self.del > 0 { + let del = self.del; + let src: *const T = &v[i]; + let dst: *mut T = &mut v[i - del]; + core::ptr::copy_nonoverlapping(src, dst, 1); + } + } + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.end - self.idx)) + } +} + +impl Drop for ExtractIf<'_, T, N, F> +where F: FnMut(&mut T) -> bool +{ + fn drop(&mut self) { + unsafe { + if self.idx < self.old_len && self.del > 0 { + // This is a pretty messed up state, and there isn't really an + // obviously right thing to do. We don't want to keep trying + // to execute `pred`, so we just backshift all the unprocessed + // elements and tell the vec that they still exist. The + // backshift is required to prevent a + // double-drop of the last successfully + // drained item prior to a panic in the predicate. + let ptr = self.vec.as_mut_ptr(); + let src = ptr.add(self.idx); + let dst = src.sub(self.del); + let tail_len = self.old_len - self.idx; + src.copy_to(dst, tail_len); + } + self.vec.set_len(self.old_len - self.del); + } + } +} diff --git a/src/iterators/intoiter.rs b/src/iterators/intoiter.rs new file mode 100644 index 0000000..76afff8 --- /dev/null +++ b/src/iterators/intoiter.rs @@ -0,0 +1,192 @@ +use { + super::super::{ + DropDealloc, + SmallVec, + rawsmallvec::RawSmallVec, + taggedlen::TaggedLen + }, + core::{ + fmt::{ + Debug, + Formatter, + Result as Format + }, + iter::FusedIterator, + marker::PhantomData, + mem::ManuallyDrop, + ptr::{ + NonNull, + slice_from_raw_parts_mut + } + } +}; + +/// 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, + begin: usize, + end: TaggedLen, + _marker: PhantomData +} + +// 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 where T: Send {} +unsafe impl Sync for IntoIter where T: Sync {} + +impl IntoIter { + #[inline] + const fn as_ptr(&self) -> *const T { + let on_heap = self.end.on_heap(); + if on_heap { + // SAFETY: vector is on the heap + unsafe { self.raw.as_ptr_heap() } + } else { + self.raw.as_ptr_inline() + } + } + + #[inline] + const fn as_mut_ptr(&mut self) -> *mut T { + let on_heap = self.end.on_heap(); + if on_heap { + // SAFETY: vector is on the heap + unsafe { self.raw.as_mut_ptr_heap() } + } else { + self.raw.as_mut_ptr_inline() + } + } + + #[inline] + pub const fn as_slice(&self) -> &[T] { + // SAFETY: The members in self.begin..self.end.value() are all + // initialized So the pointer arithmetic is valid, and so is the + // construction of the slice + unsafe { + let ptr = self.as_ptr(); + core::slice::from_raw_parts(ptr.add(self.begin), self.end.value() - self.begin) + } + } + + #[inline] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: see above + unsafe { + let ptr = self.as_mut_ptr(); + core::slice::from_raw_parts_mut(ptr.add(self.begin), self.end.value() - self.begin) + } + } +} + +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + if self.begin == self.end.value() { + None + } else { + // SAFETY: see above + unsafe { + let ptr = self.as_mut_ptr(); + let value = ptr.add(self.begin).read(); + self.begin += 1; + Some(value) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.end.value() - self.begin; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + let mut end = self.end.value(); + if self.begin == end { + None + } else { + // SAFETY: see above + unsafe { + let ptr = self.as_mut_ptr(); + let on_heap = self.end.on_heap(); + end -= 1; + self.end = TaggedLen::new(end, on_heap); + let value = ptr.add(end).read(); + Some(value) + } + } + } +} +impl ExactSizeIterator for IntoIter {} +impl FusedIterator for IntoIter {} + +impl Drop for IntoIter { + fn drop(&mut self) { + // SAFETY: see above + unsafe { + let on_heap = self.end.on_heap(); + let begin = self.begin; + let end = self.end.value(); + let ptr = self.as_mut_ptr(); + 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::() + }) + } else { + None + }; + slice_from_raw_parts_mut(ptr.add(begin), end - begin).drop_in_place(); + } + } +} + +impl Clone for IntoIter { + #[inline] + fn clone(&self) -> IntoIter { + SmallVec::from(self.as_slice()).into_iter() + } +} + +impl Debug for IntoIter { + fn fmt(&self, f: &mut Formatter<'_>) -> Format { + f.debug_tuple("IntoIter").field(&self.as_slice()).finish() + } +} + +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 len to zero as `IntoIter` drop handles dropping of + // the elements + let this = ManuallyDrop::new(self); + IntoIter { + raw: (&this.raw as *const RawSmallVec).read(), + begin: 0, + end: this.len, + _marker: PhantomData + } + } + } +} diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs new file mode 100644 index 0000000..09029b0 --- /dev/null +++ b/src/iterators/mod.rs @@ -0,0 +1,46 @@ +pub mod extractif; +pub mod intoiter; + +use { + super::SmallVec, + core::{ + iter::FromIterator, + slice::{ + Iter, + IterMut + } + } +}; + +impl FromIterator for SmallVec { + #[inline] + fn from_iter>(iter: I) -> Self { + #[cfg(feature = "specialization")] + { + super::spec_traits::SpecFromIterator::::spec_from_iter(iter.into_iter()) + } + + #[cfg(not(feature = "specialization"))] + { + Self::from_iter_fallback(iter.into_iter()) + } + } +} + +impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { + type IntoIter = Iter<'a, T>; + type Item = &'a T; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { + type IntoIter = IterMut<'a, T>; + type Item = &'a mut T; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} diff --git a/src/lib.rs b/src/lib.rs index e359c6d..44e9946 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ extern crate std; #[cfg(feature = "borsh")] mod borsh; +mod iterators; mod macros; #[cfg(feature = "malloc_size_of")] mod mallocsizeof; @@ -87,6 +88,10 @@ use defmt::{ Formatter as DeFormatter, write as dewrite }; +pub use iterators::{ + extractif::ExtractIf, + intoiter::IntoIter +}; #[cfg(feature = "std")] use std::io; use { @@ -408,100 +413,6 @@ impl Drain<'_, T, N> { } } -/// An iterator which uses a closure to determine if an element should be -/// removed. -/// -/// Returned from [`SmallVec::extract_if`][1]. -/// -/// [1]: struct.SmallVec.html#method.extract_if -pub struct ExtractIf<'a, T, const N: usize, F> -where F: FnMut(&mut T) -> bool -{ - vec: &'a mut SmallVec, - /// The index of the item that will be inspected by the next call to `next`. - idx: usize, - /// Elements at and beyond this point will be retained. Must be equal or - /// smaller than `old_len`. - end: usize, - /// The number of items that have been drained (removed) thus far. - del: usize, - /// The original length of `vec` prior to draining. - old_len: usize, - /// The filter test predicate. - pred: F -} - -impl core::fmt::Debug for ExtractIf<'_, T, N, F> -where - F: FnMut(&mut T) -> bool, - T: core::fmt::Debug -{ - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("ExtractIf") - .field(&self.vec.as_slice()) - .finish() - } -} - -impl Iterator for ExtractIf<'_, T, N, F> -where F: FnMut(&mut T) -> bool -{ - type Item = T; - - fn next(&mut self) -> Option { - unsafe { - while self.idx < self.end { - let i = self.idx; - let v = core::slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); - let drained = (self.pred)(&mut v[i]); - // Update the index *after* the predicate is called. If the - // index is updated prior and the predicate - // panics, the element at this index would be - // leaked. - self.idx += 1; - if drained { - self.del += 1; - return Some(core::ptr::read(&v[i])); - } else if self.del > 0 { - let del = self.del; - let src: *const T = &v[i]; - let dst: *mut T = &mut v[i - del]; - core::ptr::copy_nonoverlapping(src, dst, 1); - } - } - None - } - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.end - self.idx)) - } -} - -impl Drop for ExtractIf<'_, T, N, F> -where F: FnMut(&mut T) -> bool -{ - fn drop(&mut self) { - unsafe { - if self.idx < self.old_len && self.del > 0 { - // This is a pretty messed up state, and there isn't really an - // obviously right thing to do. We don't want to keep trying - // to execute `pred`, so we just backshift all the unprocessed - // elements and tell the vec that they still exist. The - // backshift is required to prevent a - // double-drop of the last successfully - // drained item prior to a panic in the predicate. - let ptr = self.vec.as_mut_ptr(); - let src = ptr.add(self.idx); - let dst = src.sub(self.del); - let tail_len = self.old_len - self.idx; - src.copy_to(dst, tail_len); - } - self.vec.set_len(self.old_len - self.del); - } - } -} - pub struct Splice<'a, I: Iterator + 'a, const N: usize> { drain: Drain<'a, I::Item, N>, replace_with: I @@ -588,119 +499,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, - begin: usize, - end: TaggedLen, - _marker: PhantomData -} - -// 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 where T: Send {} -unsafe impl Sync for IntoIter where T: Sync {} - -impl IntoIter { - #[inline] - const fn as_ptr(&self) -> *const T { - let on_heap = self.end.on_heap(); - if on_heap { - // SAFETY: vector is on the heap - unsafe { self.raw.as_ptr_heap() } - } else { - self.raw.as_ptr_inline() - } - } - - #[inline] - const fn as_mut_ptr(&mut self) -> *mut T { - let on_heap = self.end.on_heap(); - if on_heap { - // SAFETY: vector is on the heap - unsafe { self.raw.as_mut_ptr_heap() } - } else { - self.raw.as_mut_ptr_inline() - } - } - - #[inline] - pub const fn as_slice(&self) -> &[T] { - // SAFETY: The members in self.begin..self.end.value() are all - // initialized So the pointer arithmetic is valid, and so is the - // construction of the slice - unsafe { - let ptr = self.as_ptr(); - core::slice::from_raw_parts(ptr.add(self.begin), self.end.value() - self.begin) - } - } - - #[inline] - pub const fn as_mut_slice(&mut self) -> &mut [T] { - // SAFETY: see above - unsafe { - let ptr = self.as_mut_ptr(); - core::slice::from_raw_parts_mut(ptr.add(self.begin), self.end.value() - self.begin) - } - } -} - -impl Iterator for IntoIter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - if self.begin == self.end.value() { - None - } else { - // SAFETY: see above - unsafe { - let ptr = self.as_mut_ptr(); - let value = ptr.add(self.begin).read(); - self.begin += 1; - Some(value) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let size = self.end.value() - self.begin; - (size, Some(size)) - } -} - -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - let mut end = self.end.value(); - if self.begin == end { - None - } else { - // SAFETY: see above - unsafe { - let ptr = self.as_mut_ptr(); - let on_heap = self.end.on_heap(); - end -= 1; - self.end = TaggedLen::new(end, on_heap); - let value = ptr.add(end).read(); - Some(value) - } - } - } -} -impl ExactSizeIterator for IntoIter {} -impl core::iter::FusedIterator for IntoIter {} - impl SmallVec { #[inline] pub const fn new() -> SmallVec { @@ -1074,31 +872,31 @@ impl SmallVec { /// ); /// assert_eq!(ones.len(), 3); /// ``` - pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, N, F> - where - F: FnMut(&mut T) -> bool, - R: core::ops::RangeBounds - { - let old_len = self.len(); - let core::ops::Range { - start, - end - } = slice_range(range, ..old_len); - - // Guard against us getting leaked (leak amplification) - unsafe { - self.set_len(0); - } - - ExtractIf { - vec: self, - idx: start, - end, - del: 0, - old_len, - pred: filter - } - } + // pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, + // T, N, F> where + // F: FnMut(&mut T) -> bool, + // R: core::ops::RangeBounds + //{ + // let old_len = self.len(); + // let core::ops::Range { + // start, + // end + // } = slice_range(range, ..old_len); + // + // // Guard against us getting leaked (leak amplification) + // unsafe { + // self.set_len(0); + // } + // + // ExtractIf { + // vec: self, + // idx: start, + // end, + // del: 0, + // old_len, + // pred: filter + // } + //} pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, N> where @@ -1964,29 +1762,6 @@ impl Drop for SmallVec { } } -impl Drop for IntoIter { - fn drop(&mut self) { - // SAFETY: see above - unsafe { - let on_heap = self.end.on_heap(); - let begin = self.begin; - let end = self.end.value(); - let ptr = self.as_mut_ptr(); - 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::() - }) - } 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 thís function. #[doc(hidden)] @@ -2112,31 +1887,31 @@ mod spec_traits { } } - impl SpecExtend> for SmallVec { - fn spec_extend(&mut self, mut iter: IntoIter) { - let slice = iter.as_slice(); - let len = slice.len(); - let old_len = self.len(); - - self.reserve(len); - - // SAFETY: Additional memory has been reserved above. - // Therefore, the copy operates on valid memory. - unsafe { - let dst = self.as_mut_ptr().add(old_len); - let src = slice.as_ptr(); - copy_nonoverlapping(src, dst, len); - } - - // SAFETY: The elements were initialized above. - unsafe { - self.set_len(old_len + len); - } - - // Mark the iterator as fully consumed. - iter.begin = iter.end.value(); - } - } + // impl SpecExtend> for + // SmallVec { fn spec_extend(&mut self, mut iter: IntoIter) { let slice = iter.as_slice(); + // let len = slice.len(); + // let old_len = self.len(); + // + // self.reserve(len); + // + // // SAFETY: Additional memory has been reserved above. + // // Therefore, the copy operates on valid memory. + // unsafe { + // let dst = self.as_mut_ptr().add(old_len); + // let src = slice.as_ptr(); + // copy_nonoverlapping(src, dst, len); + // } + // + // // SAFETY: The elements were initialized above. + // unsafe { + // self.set_len(old_len + len); + // } + // + // // Mark the iterator as fully consumed. + // iter.begin = iter.end.value(); + // } + //} impl<'a, T: 'a, const N: usize, I> SpecExtend<&'a T, I> for SmallVec where @@ -2590,13 +2365,6 @@ impl Clone for SmallVec { } } -impl Clone for IntoIter { - #[inline] - fn clone(&self) -> IntoIter { - SmallVec::from(self.as_slice()).into_iter() - } -} - impl Extend for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2627,60 +2395,6 @@ impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { } } -impl core::iter::FromIterator for SmallVec { - #[inline] - fn from_iter>(iter: I) -> Self { - #[cfg(feature = "specialization")] - { - spec_traits::SpecFromIterator::::spec_from_iter(iter.into_iter()) - } - - #[cfg(not(feature = "specialization"))] - { - Self::from_iter_fallback(iter.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 len to zero as `IntoIter` drop handles dropping of - // the elements - let this = ManuallyDrop::new(self); - IntoIter { - raw: (&this.raw as *const RawSmallVec).read(), - begin: 0, - end: this.len, - _marker: PhantomData - } - } - } -} - -impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { - type IntoIter = core::slice::Iter<'a, T>; - type Item = &'a T; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { - type IntoIter = core::slice::IterMut<'a, T>; - type Item = &'a mut T; - - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - impl PartialEq> for SmallVec where T: PartialEq { @@ -2766,12 +2480,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() - } -} - impl Debug for Drain<'_, T, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()