Postpone .next() call until iteration

This commit is contained in:
Yuri Astrakhan 2023-05-09 18:31:56 -04:00
parent f9259d1b73
commit b8d245e749

View File

@ -11,6 +11,7 @@ pub struct Intersperse<I: Iterator>
where
I::Item: Clone,
{
started: bool,
separator: I::Item,
next_item: Option<I::Item>,
iter: Fuse<I>,
@ -29,8 +30,7 @@ where
I::Item: Clone,
{
pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
let mut iter = iter.fuse();
Self { separator, next_item: iter.next(), iter }
Self { started: false, separator, next_item: None, iter: iter.fuse() }
}
}
@ -44,21 +44,26 @@ where
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let Some(v) = self.next_item.take() {
Some(v)
} else {
let next_item = self.iter.next();
if next_item.is_some() {
self.next_item = next_item;
Some(self.separator.clone())
if self.started {
if let Some(v) = self.next_item.take() {
Some(v)
} else {
None
let next_item = self.iter.next();
if next_item.is_some() {
self.next_item = next_item;
Some(self.separator.clone())
} else {
None
}
}
} else {
self.started = true;
self.iter.next()
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
intersperse_size_hint(&self.iter, self.next_item.is_some())
intersperse_size_hint(&self.iter, self.started, self.next_item.is_some())
}
fn fold<B, F>(self, init: B, f: F) -> B
@ -67,7 +72,7 @@ where
F: FnMut(B, Self::Item) -> B,
{
let separator = self.separator;
intersperse_fold(self.iter, init, f, move || separator.clone(), self.next_item)
intersperse_fold(self.iter, init, f, move || separator.clone(), self.started,self.next_item)
}
}
@ -80,6 +85,7 @@ pub struct IntersperseWith<I, G>
where
I: Iterator,
{
started: bool,
separator: G,
next_item: Option<I::Item>,
iter: Fuse<I>,
@ -102,6 +108,7 @@ where
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IntersperseWith")
.field("started", &self.started)
.field("separator", &self.separator)
.field("iter", &self.iter)
.field("next_item", &self.next_item)
@ -118,6 +125,7 @@ where
{
fn clone(&self) -> Self {
Self {
started: self.started,
separator: self.separator.clone(),
iter: self.iter.clone(),
next_item: self.next_item.clone(),
@ -131,8 +139,7 @@ where
G: FnMut() -> I::Item,
{
pub(in crate::iter) fn new(iter: I, separator: G) -> Self {
let mut iter = iter.fuse();
Self { separator, next_item: iter.next(), iter }
Self { started: false, separator, next_item: None, iter: iter.fuse() }
}
}
@ -146,21 +153,26 @@ where
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let Some(v) = self.next_item.take() {
Some(v)
} else {
let next_item = self.iter.next();
if next_item.is_some() {
self.next_item = next_item;
Some((self.separator)())
if self.started {
if let Some(v) = self.next_item.take() {
Some(v)
} else {
None
let next_item = self.iter.next();
if next_item.is_some() {
self.next_item = next_item;
Some((self.separator)())
} else {
None
}
}
} else {
self.started = true;
self.iter.next()
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
intersperse_size_hint(&self.iter, self.next_item.is_some())
intersperse_size_hint(&self.iter, self.started, self.next_item.is_some())
}
fn fold<B, F>(self, init: B, f: F) -> B
@ -168,26 +180,33 @@ where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
intersperse_fold(self.iter, init, f, self.separator, self.next_item)
intersperse_fold(self.iter, init, f, self.separator, self.started, self.next_item)
}
}
fn intersperse_size_hint<I>(iter: &I, next_is_elem: bool) -> (usize, Option<usize>)
fn intersperse_size_hint<I>(iter: &I, started: bool, next_is_some: bool) -> (usize, Option<usize>)
where
I: Iterator,
{
let (lo, hi) = iter.size_hint();
(
lo.saturating_add(next_is_elem as usize).saturating_add(lo),
hi.map(|hi| hi.saturating_add(next_is_elem as usize).saturating_add(hi)),
lo.saturating_sub(!started as usize)
.saturating_add(next_is_some as usize)
.saturating_add(lo),
hi.map(|hi| {
hi.saturating_sub(!started as usize)
.saturating_add(next_is_some as usize)
.saturating_add(hi)
}),
)
}
fn intersperse_fold<I, B, F, G>(
iter: I,
mut iter: I,
init: B,
mut f: F,
mut separator: G,
started: bool,
mut next_item: Option<I::Item>,
) -> B
where
@ -197,7 +216,8 @@ where
{
let mut accum = init;
if let Some(x) = next_item.take() {
let first = if started { next_item.take() } else { iter.next() };
if let Some(x) = first {
accum = f(accum, x);
}