Skip to content

Commit

Permalink
Make CoalesceBy lazy
Browse files Browse the repository at this point in the history
Similar to what is done by `core::iter::Peekable`, a nested option is now used.
  • Loading branch information
Philippe-Cholet committed Nov 13, 2023
1 parent 2d32109 commit 5fdfb04
Showing 1 changed file with 34 additions and 23 deletions.
57 changes: 34 additions & 23 deletions src/adaptors/coalesce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ where
C: CountItem<I::Item>,
{
iter: I,
last: Option<C::CItem>,
last: Option<Option<C::CItem>>,
f: F,
}

Expand Down Expand Up @@ -45,36 +45,47 @@ where
type Item = C::CItem;

fn next(&mut self) -> Option<Self::Item> {
let Self { iter, last, f } = self;
// this fuses the iterator
let last = self.last.take()?;
let init = match last {
Some(elt) => elt.take(),
None => {
*last = Some(None);
iter.next().map(C::new)
}
}?;

let self_last = &mut self.last;
let self_f = &mut self.f;
Some(
self.iter
.try_fold(last, |last, next| match self_f.coalesce_pair(last, next) {
Ok(joined) => Ok(joined),
Err((last_, next_)) => {
*self_last = Some(next_);
Err(last_)
}
})
.unwrap_or_else(|x| x),
iter.try_fold(init, |accum, next| match f.coalesce_pair(accum, next) {
Ok(joined) => Ok(joined),
Err((last_, next_)) => {
*last = Some(Some(next_));
Err(last_)
}
})
.unwrap_or_else(|x| x),
)
}

fn size_hint(&self) -> (usize, Option<usize>) {
let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_some() as usize);
let (low, hi) = size_hint::add_scalar(
self.iter.size_hint(),
matches!(self.last, Some(Some(_))) as usize,
);
((low > 0) as usize, hi)
}

fn fold<Acc, FnAcc>(self, acc: Acc, mut fn_acc: FnAcc) -> Acc
where
FnAcc: FnMut(Acc, Self::Item) -> Acc,
{
if let Some(last) = self.last {
let mut f = self.f;
let (last, acc) = self.iter.fold((last, acc), |(last, acc), elt| {
let Self {
mut iter,
last,
mut f,
} = self;
if let Some(last) = last.unwrap_or_else(|| iter.next().map(C::new)) {
let (last, acc) = iter.fold((last, acc), |(last, acc), elt| {
match f.coalesce_pair(last, elt) {
Ok(joined) => (joined, acc),
Err((last_, next_)) => (next_, fn_acc(acc, last_)),
Expand Down Expand Up @@ -135,12 +146,12 @@ where
}

/// Create a new `Coalesce`.
pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F>
pub fn coalesce<I, F>(iter: I, f: F) -> Coalesce<I, F>
where
I: Iterator,
{
Coalesce {
last: iter.next(),
last: None,
iter,
f,
}
Expand Down Expand Up @@ -192,12 +203,12 @@ impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F {
}

/// Create a new `DedupBy`.
pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred>
pub fn dedup_by<I, Pred>(iter: I, dedup_pred: Pred) -> DedupBy<I, Pred>
where
I: Iterator,
{
DedupBy {
last: iter.next(),
last: None,
iter,
f: DedupPred2CoalescePred(dedup_pred),
}
Expand Down Expand Up @@ -251,12 +262,12 @@ where
pub type DedupWithCount<I> = DedupByWithCount<I, DedupEq>;

/// Create a new `DedupByWithCount`.
pub fn dedup_by_with_count<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred>
pub fn dedup_by_with_count<I, Pred>(iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred>
where
I: Iterator,
{
DedupByWithCount {
last: iter.next().map(WithCount::new),
last: None,
iter,
f: DedupPredWithCount2CoalescePred(dedup_pred),
}
Expand Down

0 comments on commit 5fdfb04

Please sign in to comment.