From 6caf6b97877fd53c4b308df452650d061beb147f Mon Sep 17 00:00:00 2001 From: Alexey Gerasev Date: Thu, 25 Apr 2024 10:45:53 +0700 Subject: [PATCH] Separate IntoIter and PopIter, optimize PopIter --- src/storage.rs | 2 - src/traits/consumer.rs | 86 +++++++++++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/storage.rs b/src/storage.rs index 891af01..46e89d2 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -8,8 +8,6 @@ use core::{mem::forget, ptr}; /// /// Storage items must be stored as a contiguous array. /// -/// Storage is converted to internal representation before use (see [`Self::Internal`]). -/// /// # Safety /// /// Must not alias with its contents diff --git a/src/traits/consumer.rs b/src/traits/consumer.rs index 89ed088..9d31724 100644 --- a/src/traits/consumer.rs +++ b/src/traits/consumer.rs @@ -3,7 +3,7 @@ use super::{ utils::modulus, }; use crate::utils::{move_uninit_slice, slice_as_uninit_mut, slice_assume_init_mut, slice_assume_init_ref}; -use core::{iter::Chain, marker::PhantomData, mem::MaybeUninit, ptr, slice}; +use core::{iter::Chain, mem::MaybeUninit, ptr, slice}; #[cfg(feature = "std")] use std::io::{self, Write}; @@ -156,10 +156,7 @@ pub trait Consumer: Observer { } /// Returns an iterator that removes items one by one from the ring buffer. - fn pop_iter(&mut self) -> PopIter<&mut Self, Self> - where - Self: AsMut + AsRef, - { + fn pop_iter(&mut self) -> PopIter { PopIter::new(self) } @@ -256,37 +253,90 @@ pub trait Consumer: Observer { } } +/// Owning ring buffer iterator. +pub struct IntoIter { + inner: C, +} + +impl IntoIter { + pub fn new(inner: C) -> Self { + Self { inner } + } + pub fn into_inner(self) -> C { + self.inner + } +} + +impl Iterator for IntoIter { + type Item = C::Item; + + #[inline] + fn next(&mut self) -> Option { + self.inner.try_pop() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.inner.occupied_len(), None) + } +} + /// An iterator that removes items from the ring buffer. -pub struct PopIter + AsRef, C: Consumer + ?Sized> { - inner: U, - _ghost: PhantomData, +/// +/// Producer will see removed items only when iterator is dropped or [`PopIter::commit`] is called. +pub struct PopIter<'a, C: Consumer + ?Sized> { + inner: &'a C, + iter: Chain>, slice::Iter<'a, MaybeUninit>>, + count: usize, + len: usize, } -impl + AsRef, C: Consumer + ?Sized> PopIter { - pub fn new(inner: U) -> Self { +impl<'a, C: Consumer + ?Sized> Drop for PopIter<'a, C> { + fn drop(&mut self) { + self.commit(); + } +} + +impl<'a, C: Consumer + ?Sized> PopIter<'a, C> { + /// Create an iterator. + pub fn new(inner: &'a mut C) -> Self { + let (len, iter) = { + let (left, right) = inner.occupied_slices(); + (left.len() + right.len(), left.iter().chain(right)) + }; Self { inner, - _ghost: PhantomData, + iter, + count: 0, + len, } } - pub fn into_inner(self) -> U { - self.inner + + /// Send information about removed items to the ring buffer. + pub fn commit(&mut self) { + unsafe { self.inner.advance_read_index(self.count) }; + self.count = 0; } } -impl + AsRef, C: Consumer> Iterator for PopIter { +impl<'a, C: Consumer> Iterator for PopIter<'a, C> { type Item = C::Item; #[inline] fn next(&mut self) -> Option { - self.inner.as_mut().try_pop() + self.iter.next().map(|item| { + self.count += 1; + unsafe { item.assume_init_read() } + }) } #[inline] fn size_hint(&self) -> (usize, Option) { - (self.inner.as_ref().occupied_len(), None) + let remain = self.len - self.count; + (remain, Some(remain)) } } +impl<'a, C: Consumer> ExactSizeIterator for PopIter<'a, C> {} + /// Iterator over ring buffer contents. /// /// *Please do not rely on actual type, it may change in future.* @@ -376,9 +426,9 @@ macro_rules! impl_consumer_traits { ($type:ident $(< $( $param:tt $( : $first_bound:tt $(+ $next_bound:tt )* )? ),+ >)?) => { impl $(< $( $param $( : $first_bound $(+ $next_bound )* )? ),+ >)? core::iter::IntoIterator for $type $(< $( $param ),+ >)? where Self: Sized { type Item = ::Item; - type IntoIter = $crate::traits::consumer::PopIter; + type IntoIter = $crate::traits::consumer::IntoIter; fn into_iter(self) -> Self::IntoIter { - $crate::traits::consumer::PopIter::new(self) + $crate::traits::consumer::IntoIter::new(self) } }