Skip to content

Commit

Permalink
Separate IntoIter and PopIter, optimize PopIter
Browse files Browse the repository at this point in the history
  • Loading branch information
agerasev committed Apr 25, 2024
1 parent 1c966f7 commit 6caf6b9
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 20 deletions.
2 changes: 0 additions & 2 deletions src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
86 changes: 68 additions & 18 deletions src/traits/consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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<Self> + AsRef<Self>,
{
fn pop_iter(&mut self) -> PopIter<Self> {
PopIter::new(self)
}

Expand Down Expand Up @@ -256,37 +253,90 @@ pub trait Consumer: Observer {
}
}

/// Owning ring buffer iterator.
pub struct IntoIter<C: Consumer + ?Sized> {
inner: C,
}

impl<C: Consumer> IntoIter<C> {
pub fn new(inner: C) -> Self {
Self { inner }
}
pub fn into_inner(self) -> C {
self.inner
}
}

impl<C: Consumer> Iterator for IntoIter<C> {
type Item = C::Item;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.try_pop()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.inner.occupied_len(), None)
}
}

/// An iterator that removes items from the ring buffer.
pub struct PopIter<U: AsMut<C> + AsRef<C>, C: Consumer + ?Sized> {
inner: U,
_ghost: PhantomData<C>,
///
/// 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<C::Item>>, slice::Iter<'a, MaybeUninit<C::Item>>>,
count: usize,
len: usize,
}

impl<U: AsMut<C> + AsRef<C>, C: Consumer + ?Sized> PopIter<U, C> {
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<U: AsMut<C> + AsRef<C>, C: Consumer> Iterator for PopIter<U, C> {
impl<'a, C: Consumer> Iterator for PopIter<'a, C> {
type Item = C::Item;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
(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.*
Expand Down Expand Up @@ -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 = <Self as $crate::traits::Observer>::Item;
type IntoIter = $crate::traits::consumer::PopIter<Self, Self>;
type IntoIter = $crate::traits::consumer::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
$crate::traits::consumer::PopIter::new(self)
$crate::traits::consumer::IntoIter::new(self)
}
}

Expand Down

0 comments on commit 6caf6b9

Please sign in to comment.