diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 8d92dcc..40585e0 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1,6 +1,7 @@ pub mod drain; pub mod extractif; pub mod intoiter; +pub mod splice; #[cfg(feature = "rayon")] mod rayon; diff --git a/src/iterators/splice.rs b/src/iterators/splice.rs new file mode 100644 index 0000000..4f99e2f --- /dev/null +++ b/src/iterators/splice.rs @@ -0,0 +1,100 @@ +use crate::{ + Drain, + Global, + SmallVec +}; + +pub struct Splice<'a, I: Iterator + 'a, const N: usize> { + drain: Drain<'a, I::Item, N, Global>, + replace_with: I +} + +impl<'a, I: Iterator + 'a, const N: usize> Splice<'a, I, N> { + pub(crate) fn new(drain: Drain<'a, I::Item, N, Global>, replace_with: I) -> Self { + Self { + drain, + replace_with + } + } +} + +impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> +where + I: core::fmt::Debug + Iterator + 'a, + ::Item: core::fmt::Debug +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Splice").field(&self.drain).finish() + } +} + +impl Iterator for Splice<'_, I, N> { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.drain.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +impl DoubleEndedIterator for Splice<'_, I, N> { + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +impl ExactSizeIterator for Splice<'_, I, N> {} + +impl Drop for Splice<'_, I, N> { + fn drop(&mut self) { + self.drain.by_ref().for_each(drop); + // At this point draining is done and the only remaining tasks are + // splicing and moving things into the final place. + // Which means we can replace the slice::Iter with pointers that won't + // point to deallocated memory, so that Drain::drop is still + // allowed to call iter.len(), otherwise it would break the + // ptr.sub_ptr contract. + self.drain.iter = [].iter(); + + unsafe { + if self.drain.tail_len == 0 { + self.drain.vec.as_mut().extend(self.replace_with.by_ref()); + return; + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return; + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return; + } + } + + // Collect any remaining elements. + let mut collected = self + .replace_with + .by_ref() + .collect::>() + .into_iter(); + // Now we have an exact count. + if collected.len() > 0 { + self.drain.move_tail(collected.len()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore + // `vec.length`. + } +} diff --git a/src/lib.rs b/src/lib.rs index eca6495..7bdde64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,8 @@ mod iterators; pub use iterators::{ drain::Drain, extractif::ExtractIf, - intoiter::IntoIter + intoiter::IntoIter, + splice::Splice }; mod macros; #[cfg(feature = "malloc_size_of")] @@ -154,92 +155,6 @@ impl Default for SmallVec { } } -pub struct Splice<'a, I: Iterator + 'a, const N: usize> { - drain: Drain<'a, I::Item, N, Global>, - replace_with: I -} - -impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> -where - I: Debug + Iterator + 'a, - ::Item: Debug -{ - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("Splice").field(&self.drain).finish() - } -} - -impl Iterator for Splice<'_, I, N> { - type Item = I::Item; - - fn next(&mut self) -> Option { - self.drain.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.drain.size_hint() - } -} - -impl DoubleEndedIterator for Splice<'_, I, N> { - fn next_back(&mut self) -> Option { - self.drain.next_back() - } -} - -impl ExactSizeIterator for Splice<'_, I, N> {} - -impl Drop for Splice<'_, I, N> { - fn drop(&mut self) { - self.drain.by_ref().for_each(drop); - // At this point draining is done and the only remaining tasks are - // splicing and moving things into the final place. - // Which means we can replace the slice::Iter with pointers that won't - // point to deallocated memory, so that Drain::drop is still - // allowed to call iter.len(), otherwise it would break the - // ptr.sub_ptr contract. - self.drain.iter = [].iter(); - - unsafe { - if self.drain.tail_len == 0 { - self.drain.vec.as_mut().extend(self.replace_with.by_ref()); - return; - } - - // First fill the range left by drain(). - if !self.drain.fill(&mut self.replace_with) { - return; - } - - // There may be more elements. Use the lower bound as an estimate. - // FIXME: Is the upper bound a better guess? Or something else? - let (lower_bound, _upper_bound) = self.replace_with.size_hint(); - if lower_bound > 0 { - self.drain.move_tail(lower_bound); - if !self.drain.fill(&mut self.replace_with) { - return; - } - } - - // Collect any remaining elements. - let mut collected = self - .replace_with - .by_ref() - .collect::>() - .into_iter(); - // Now we have an exact count. - if collected.len() > 0 { - self.drain.move_tail(collected.len()); - let filled = self.drain.fill(&mut collected); - debug_assert!(filled); - debug_assert_eq!(collected.len(), 0); - } - } - // Let `Drain::drop` move the tail back if necessary and restore - // `vec.length`. - } -} - impl SmallVec { #[inline] pub const fn new() -> SmallVec { @@ -391,10 +306,7 @@ impl SmallVec { R: core::ops::RangeBounds, I: IntoIterator { - Splice { - drain: self.drain(range), - replace_with: replace_with.into_iter() - } + Splice::new(self.drain(range), replace_with.into_iter()) } /// Creates a `SmallVec` directly from the raw components of another