Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
450: Introduce module coalesce r=jswrenn a=phimuemue Hi! As #440 (thanks for reviewing and merging, btw) presumably conflicts with any existing PRs touching `coalesce` et al, I thought we could just as well seize the opportunity and move these types into an own module (so to speak as a starting point for the problem mentioned in #423 (comment)). I cut-pasted `Coalesce` et al into an own module, rearranged the code so that specialized types follow their generic variants, and ran `cargo fmt` on the new module. I suggest to import the `coalesce` types into `adaptors` similarly to what we already have for `multi_product`. Co-authored-by: philipp <descpl@yahoo.de>
- Loading branch information
Showing
2 changed files
with
235 additions
and
211 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
use std::fmt; | ||
use std::iter::FusedIterator; | ||
|
||
use crate::size_hint; | ||
|
||
pub struct CoalesceBy<I, F, T> | ||
where | ||
I: Iterator, | ||
{ | ||
iter: I, | ||
last: Option<T>, | ||
f: F, | ||
} | ||
|
||
impl<I: Clone, F: Clone, T: Clone> Clone for CoalesceBy<I, F, T> | ||
where | ||
I: Iterator, | ||
{ | ||
clone_fields!(last, iter, f); | ||
} | ||
|
||
impl<I, F, T> fmt::Debug for CoalesceBy<I, F, T> | ||
where | ||
I: Iterator + fmt::Debug, | ||
T: fmt::Debug, | ||
{ | ||
debug_fmt_fields!(CoalesceBy, iter); | ||
} | ||
|
||
pub trait CoalescePredicate<Item, T> { | ||
fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)>; | ||
} | ||
|
||
impl<I, F, T> Iterator for CoalesceBy<I, F, T> | ||
where | ||
I: Iterator, | ||
F: CoalescePredicate<I::Item, T>, | ||
{ | ||
type Item = T; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
// 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<usize>) { | ||
let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_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| { | ||
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<I: Iterator, F: CoalescePredicate<I::Item, T>, T> FusedIterator for CoalesceBy<I, F, T> {} | ||
|
||
/// 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<I, F> = CoalesceBy<I, F, <I as Iterator>::Item>; | ||
|
||
impl<F, Item, T> CoalescePredicate<Item, T> for F | ||
where | ||
F: FnMut(T, Item) -> Result<T, (T, T)>, | ||
{ | ||
fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)> { | ||
self(t, item) | ||
} | ||
} | ||
|
||
/// Create a new `Coalesce`. | ||
pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F> | ||
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<I, Pred> = CoalesceBy<I, DedupPred2CoalescePred<Pred>, <I as Iterator>::Item>; | ||
|
||
#[derive(Clone)] | ||
pub struct DedupPred2CoalescePred<DP>(DP); | ||
|
||
pub trait DedupPredicate<T> { | ||
// TODO replace by Fn(&T, &T)->bool once Rust supports it | ||
fn dedup_pair(&mut self, a: &T, b: &T) -> bool; | ||
} | ||
|
||
impl<DP, T> CoalescePredicate<T, T> for DedupPred2CoalescePred<DP> | ||
where | ||
DP: DedupPredicate<T>, | ||
{ | ||
fn coalesce_pair(&mut self, t: T, item: T) -> Result<T, (T, T)> { | ||
if self.0.dedup_pair(&t, &item) { | ||
Ok(t) | ||
} else { | ||
Err((t, item)) | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct DedupEq; | ||
|
||
impl<T: PartialEq> DedupPredicate<T> for DedupEq { | ||
fn dedup_pair(&mut self, a: &T, b: &T) -> bool { | ||
a == b | ||
} | ||
} | ||
|
||
impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F { | ||
fn dedup_pair(&mut self, a: &T, b: &T) -> bool { | ||
self(a, b) | ||
} | ||
} | ||
|
||
/// Create a new `DedupBy`. | ||
pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred> | ||
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<I> = DedupBy<I, DedupEq>; | ||
|
||
/// Create a new `Dedup`. | ||
pub fn dedup<I>(iter: I) -> Dedup<I> | ||
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<I, Pred> = | ||
CoalesceBy<I, DedupPredWithCount2CoalescePred<Pred>, (usize, <I as Iterator>::Item)>; | ||
|
||
#[derive(Clone)] | ||
pub struct DedupPredWithCount2CoalescePred<DP>(DP); | ||
|
||
impl<DP, T> CoalescePredicate<T, (usize, T)> for DedupPredWithCount2CoalescePred<DP> | ||
where | ||
DP: DedupPredicate<T>, | ||
{ | ||
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<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> | ||
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<I>(iter: I) -> DedupWithCount<I> | ||
where | ||
I: Iterator, | ||
{ | ||
dedup_by_with_count(iter, DedupEq) | ||
} |
Oops, something went wrong.