diff --git a/src/adaptors/coalesce.rs b/src/adaptors/coalesce.rs new file mode 100644 index 000000000..116f688f5 --- /dev/null +++ b/src/adaptors/coalesce.rs @@ -0,0 +1,232 @@ +use std::fmt; +use std::iter::FusedIterator; + +use crate::size_hint; + +pub struct CoalesceBy +where + I: Iterator, +{ + iter: I, + last: Option, + f: F, +} + +impl Clone for CoalesceBy +where + I: Iterator, +{ + clone_fields!(last, iter, f); +} + +impl fmt::Debug for CoalesceBy +where + I: Iterator + fmt::Debug, + T: fmt::Debug, +{ + debug_fmt_fields!(CoalesceBy, iter); +} + +pub trait CoalescePredicate { + fn coalesce_pair(&mut self, t: T, item: Item) -> Result; +} + +impl Iterator for CoalesceBy +where + I: Iterator, + F: CoalescePredicate, +{ + type Item = T; + + fn next(&mut self) -> Option { + // this fuses the iterator + let mut last = match self.last.take() { + None => return None, + Some(x) => x, + }; + for next in &mut self.iter { + match self.f.coalesce_pair(last, next) { + Ok(joined) => last = joined, + Err((last_, next_)) => { + self.last = Some(next_); + return Some(last_); + } + } + } + Some(last) + } + + fn size_hint(&self) -> (usize, Option) { + let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_some() as usize); + ((low > 0) as usize, hi) + } + + fn fold(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| { + match f.coalesce_pair(last, elt) { + Ok(joined) => (joined, acc), + Err((last_, next_)) => (next_, fn_acc(acc, last_)), + } + }); + fn_acc(acc, last) + } else { + acc + } + } +} + +impl, T> FusedIterator for CoalesceBy {} + +/// An iterator adaptor that may join together adjacent elements. +/// +/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub type Coalesce = CoalesceBy::Item>; + +impl CoalescePredicate for F +where + F: FnMut(T, Item) -> Result, +{ + fn coalesce_pair(&mut self, t: T, item: Item) -> Result { + self(t, item) + } +} + +/// Create a new `Coalesce`. +pub fn coalesce(mut iter: I, f: F) -> Coalesce +where + I: Iterator, +{ + Coalesce { + last: iter.next(), + iter, + f, + } +} + +/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function. +/// +/// See [`.dedup_by()`](../trait.Itertools.html#method.dedup_by) or [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub type DedupBy = CoalesceBy, ::Item>; + +#[derive(Clone)] +pub struct DedupPred2CoalescePred(DP); + +pub trait DedupPredicate { + // TODO replace by Fn(&T, &T)->bool once Rust supports it + fn dedup_pair(&mut self, a: &T, b: &T) -> bool; +} + +impl CoalescePredicate for DedupPred2CoalescePred +where + DP: DedupPredicate, +{ + fn coalesce_pair(&mut self, t: T, item: T) -> Result { + if self.0.dedup_pair(&t, &item) { + Ok(t) + } else { + Err((t, item)) + } + } +} + +#[derive(Clone)] +pub struct DedupEq; + +impl DedupPredicate for DedupEq { + fn dedup_pair(&mut self, a: &T, b: &T) -> bool { + a == b + } +} + +impl bool> DedupPredicate for F { + fn dedup_pair(&mut self, a: &T, b: &T) -> bool { + self(a, b) + } +} + +/// Create a new `DedupBy`. +pub fn dedup_by(mut iter: I, dedup_pred: Pred) -> DedupBy +where + I: Iterator, +{ + DedupBy { + last: iter.next(), + iter, + f: DedupPred2CoalescePred(dedup_pred), + } +} + +/// An iterator adaptor that removes repeated duplicates. +/// +/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. +pub type Dedup = DedupBy; + +/// Create a new `Dedup`. +pub fn dedup(iter: I) -> Dedup +where + I: Iterator, +{ + dedup_by(iter, DedupEq) +} + +/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many +/// repeated elements were present. This will determine equality using a comparison function. +/// +/// See [`.dedup_by_with_count()`](../trait.Itertools.html#method.dedup_by_with_count) or +/// [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub type DedupByWithCount = + CoalesceBy, (usize, ::Item)>; + +#[derive(Clone)] +pub struct DedupPredWithCount2CoalescePred(DP); + +impl CoalescePredicate for DedupPredWithCount2CoalescePred +where + DP: DedupPredicate, +{ + fn coalesce_pair( + &mut self, + (c, t): (usize, T), + item: T, + ) -> Result<(usize, T), ((usize, T), (usize, T))> { + if self.0.dedup_pair(&t, &item) { + Ok((c + 1, t)) + } else { + Err(((c, t), (1, item))) + } + } +} + +/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many +/// repeated elements were present. +/// +/// See [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information. +pub type DedupWithCount = DedupByWithCount; + +/// Create a new `DedupByWithCount`. +pub fn dedup_by_with_count(mut iter: I, dedup_pred: Pred) -> DedupByWithCount +where + I: Iterator, +{ + DedupByWithCount { + last: iter.next().map(|v| (1, v)), + iter, + f: DedupPredWithCount2CoalescePred(dedup_pred), + } +} + +/// Create a new `DedupWithCount`. +pub fn dedup_with_count(iter: I) -> DedupWithCount +where + I: Iterator, +{ + dedup_by_with_count(iter, DedupEq) +} diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 038fa6951..794cc6711 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -4,12 +4,14 @@ //! option. This file may not be copied, modified, or distributed //! except according to those terms. +mod coalesce; mod multi_product; +pub use self::coalesce::*; #[cfg(feature = "use_std")] pub use self::multi_product::*; use std::fmt; -use std::iter::{Fuse, Peekable, FromIterator, FusedIterator}; +use std::iter::{Fuse, Peekable, FromIterator}; use std::marker::PhantomData; use crate::size_hint; @@ -593,216 +595,6 @@ impl Iterator for MergeBy } } -/// An iterator adaptor that may join together adjacent elements. -/// -/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub type Coalesce = CoalesceBy::Item>; - -pub struct CoalesceBy - where I: Iterator -{ - iter: I, - last: Option, - f: F, -} - -pub trait CoalescePredicate { - fn coalesce_pair(&mut self, t: T, item: Item) -> Result; -} - -impl CoalescePredicate for F - where F: FnMut(T, Item) -> Result -{ - fn coalesce_pair(&mut self, t: T, item: Item) -> Result { - self(t, item) - } -} - -impl Clone for CoalesceBy - where I: Iterator, -{ - clone_fields!(last, iter, f); -} - -impl fmt::Debug for CoalesceBy - where I: Iterator + fmt::Debug, - T: fmt::Debug, -{ - debug_fmt_fields!(CoalesceBy, iter); -} - -/// Create a new `Coalesce`. -pub fn coalesce(mut iter: I, f: F) -> Coalesce - where I: Iterator -{ - Coalesce { - last: iter.next(), - iter, - f, - } -} - -impl Iterator for CoalesceBy - where I: Iterator, - F: CoalescePredicate -{ - type Item = T; - - fn next(&mut self) -> Option { - // this fuses the iterator - let mut last = match self.last.take() { - None => return None, - Some(x) => x, - }; - for next in &mut self.iter { - match self.f.coalesce_pair(last, next) { - Ok(joined) => last = joined, - Err((last_, next_)) => { - self.last = Some(next_); - return Some(last_); - } - } - } - Some(last) - } - - fn size_hint(&self) -> (usize, Option) { - let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), - self.last.is_some() as usize); - ((low > 0) as usize, hi) - } - - fn fold(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| { - match f.coalesce_pair(last, elt) { - Ok(joined) => (joined, acc), - Err((last_, next_)) => (next_, fn_acc(acc, last_)), - } - }); - fn_acc(acc, last) - } else { - acc - } - } -} - -impl, T> FusedIterator for CoalesceBy {} - -/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function. -/// -/// See [`.dedup_by()`](../trait.Itertools.html#method.dedup_by) or [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub type DedupBy = CoalesceBy, ::Item>; - -#[derive(Clone)] -pub struct DedupPred2CoalescePred(DP); - -impl CoalescePredicate for DedupPred2CoalescePred - where DP: DedupPredicate -{ - fn coalesce_pair(&mut self, t: T, item: T) -> Result { - if self.0.dedup_pair(&t, &item) { - Ok(t) - } else { - Err((t, item)) - } - } -} - -pub trait DedupPredicate { // TODO replace by Fn(&T, &T)->bool once Rust supports it - fn dedup_pair(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct DedupEq; - -impl DedupPredicate for DedupEq { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - a == b - } -} - -implbool> DedupPredicate for F { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// An iterator adaptor that removes repeated duplicates. -/// -/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. -pub type Dedup=DedupBy; - -/// Create a new `DedupBy`. -pub fn dedup_by(mut iter: I, dedup_pred: Pred) -> DedupBy - where I: Iterator, -{ - DedupBy { - last: iter.next(), - iter, - f: DedupPred2CoalescePred(dedup_pred), - } -} - -/// Create a new `Dedup`. -pub fn dedup(iter: I) -> Dedup - where I: Iterator -{ - dedup_by(iter, DedupEq) -} - -/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many -/// repeated elements were present. This will determine equality using a comparison function. -/// -/// See [`.dedup_by_with_count()`](../trait.Itertools.html#method.dedup_by_with_count) or -/// [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub type DedupByWithCount = CoalesceBy, (usize, ::Item)>; - -#[derive(Clone)] -pub struct DedupPredWithCount2CoalescePred(DP); - -impl CoalescePredicate for DedupPredWithCount2CoalescePred - where DP: DedupPredicate -{ - fn coalesce_pair(&mut self, (c, t): (usize, T), item: T) -> Result<(usize, T), ((usize, T), (usize, T))> { - if self.0.dedup_pair(&t, &item) { - Ok((c + 1, t)) - } else { - Err(((c, t), (1, item))) - } - } -} - -/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many -/// repeated elements were present. -/// -/// See [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information. -pub type DedupWithCount = DedupByWithCount; - -/// Create a new `DedupByWithCount`. -pub fn dedup_by_with_count(mut iter: I, dedup_pred: Pred) -> DedupByWithCount - where I: Iterator, -{ - DedupByWithCount { - last: iter.next().map(|v| (1, v)), - iter, - f: DedupPredWithCount2CoalescePred(dedup_pred), - } -} - -/// Create a new `DedupWithCount`. -pub fn dedup_with_count(iter: I) -> DedupWithCount - where I: Iterator -{ - dedup_by_with_count(iter, DedupEq) -} - /// An iterator adaptor that borrows from a `Clone`-able iterator /// to only pick off elements while the predicate returns `true`. ///