Skip to content

Commit 96539ff

Browse files
bors[bot]phimuemue
andauthored
Merge #450
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 <[email protected]>
2 parents b00d7c6 + 617ed42 commit 96539ff

File tree

2 files changed

+235
-211
lines changed

2 files changed

+235
-211
lines changed

src/adaptors/coalesce.rs

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
use std::fmt;
2+
use std::iter::FusedIterator;
3+
4+
use crate::size_hint;
5+
6+
pub struct CoalesceBy<I, F, T>
7+
where
8+
I: Iterator,
9+
{
10+
iter: I,
11+
last: Option<T>,
12+
f: F,
13+
}
14+
15+
impl<I: Clone, F: Clone, T: Clone> Clone for CoalesceBy<I, F, T>
16+
where
17+
I: Iterator,
18+
{
19+
clone_fields!(last, iter, f);
20+
}
21+
22+
impl<I, F, T> fmt::Debug for CoalesceBy<I, F, T>
23+
where
24+
I: Iterator + fmt::Debug,
25+
T: fmt::Debug,
26+
{
27+
debug_fmt_fields!(CoalesceBy, iter);
28+
}
29+
30+
pub trait CoalescePredicate<Item, T> {
31+
fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)>;
32+
}
33+
34+
impl<I, F, T> Iterator for CoalesceBy<I, F, T>
35+
where
36+
I: Iterator,
37+
F: CoalescePredicate<I::Item, T>,
38+
{
39+
type Item = T;
40+
41+
fn next(&mut self) -> Option<Self::Item> {
42+
// this fuses the iterator
43+
let mut last = match self.last.take() {
44+
None => return None,
45+
Some(x) => x,
46+
};
47+
for next in &mut self.iter {
48+
match self.f.coalesce_pair(last, next) {
49+
Ok(joined) => last = joined,
50+
Err((last_, next_)) => {
51+
self.last = Some(next_);
52+
return Some(last_);
53+
}
54+
}
55+
}
56+
Some(last)
57+
}
58+
59+
fn size_hint(&self) -> (usize, Option<usize>) {
60+
let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_some() as usize);
61+
((low > 0) as usize, hi)
62+
}
63+
64+
fn fold<Acc, FnAcc>(self, acc: Acc, mut fn_acc: FnAcc) -> Acc
65+
where
66+
FnAcc: FnMut(Acc, Self::Item) -> Acc,
67+
{
68+
if let Some(last) = self.last {
69+
let mut f = self.f;
70+
let (last, acc) = self.iter.fold((last, acc), |(last, acc), elt| {
71+
match f.coalesce_pair(last, elt) {
72+
Ok(joined) => (joined, acc),
73+
Err((last_, next_)) => (next_, fn_acc(acc, last_)),
74+
}
75+
});
76+
fn_acc(acc, last)
77+
} else {
78+
acc
79+
}
80+
}
81+
}
82+
83+
impl<I: Iterator, F: CoalescePredicate<I::Item, T>, T> FusedIterator for CoalesceBy<I, F, T> {}
84+
85+
/// An iterator adaptor that may join together adjacent elements.
86+
///
87+
/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information.
88+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
89+
pub type Coalesce<I, F> = CoalesceBy<I, F, <I as Iterator>::Item>;
90+
91+
impl<F, Item, T> CoalescePredicate<Item, T> for F
92+
where
93+
F: FnMut(T, Item) -> Result<T, (T, T)>,
94+
{
95+
fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)> {
96+
self(t, item)
97+
}
98+
}
99+
100+
/// Create a new `Coalesce`.
101+
pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F>
102+
where
103+
I: Iterator,
104+
{
105+
Coalesce {
106+
last: iter.next(),
107+
iter,
108+
f,
109+
}
110+
}
111+
112+
/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function.
113+
///
114+
/// See [`.dedup_by()`](../trait.Itertools.html#method.dedup_by) or [`.dedup()`](../trait.Itertools.html#method.dedup) for more information.
115+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
116+
pub type DedupBy<I, Pred> = CoalesceBy<I, DedupPred2CoalescePred<Pred>, <I as Iterator>::Item>;
117+
118+
#[derive(Clone)]
119+
pub struct DedupPred2CoalescePred<DP>(DP);
120+
121+
pub trait DedupPredicate<T> {
122+
// TODO replace by Fn(&T, &T)->bool once Rust supports it
123+
fn dedup_pair(&mut self, a: &T, b: &T) -> bool;
124+
}
125+
126+
impl<DP, T> CoalescePredicate<T, T> for DedupPred2CoalescePred<DP>
127+
where
128+
DP: DedupPredicate<T>,
129+
{
130+
fn coalesce_pair(&mut self, t: T, item: T) -> Result<T, (T, T)> {
131+
if self.0.dedup_pair(&t, &item) {
132+
Ok(t)
133+
} else {
134+
Err((t, item))
135+
}
136+
}
137+
}
138+
139+
#[derive(Clone)]
140+
pub struct DedupEq;
141+
142+
impl<T: PartialEq> DedupPredicate<T> for DedupEq {
143+
fn dedup_pair(&mut self, a: &T, b: &T) -> bool {
144+
a == b
145+
}
146+
}
147+
148+
impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F {
149+
fn dedup_pair(&mut self, a: &T, b: &T) -> bool {
150+
self(a, b)
151+
}
152+
}
153+
154+
/// Create a new `DedupBy`.
155+
pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred>
156+
where
157+
I: Iterator,
158+
{
159+
DedupBy {
160+
last: iter.next(),
161+
iter,
162+
f: DedupPred2CoalescePred(dedup_pred),
163+
}
164+
}
165+
166+
/// An iterator adaptor that removes repeated duplicates.
167+
///
168+
/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information.
169+
pub type Dedup<I> = DedupBy<I, DedupEq>;
170+
171+
/// Create a new `Dedup`.
172+
pub fn dedup<I>(iter: I) -> Dedup<I>
173+
where
174+
I: Iterator,
175+
{
176+
dedup_by(iter, DedupEq)
177+
}
178+
179+
/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
180+
/// repeated elements were present. This will determine equality using a comparison function.
181+
///
182+
/// See [`.dedup_by_with_count()`](../trait.Itertools.html#method.dedup_by_with_count) or
183+
/// [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information.
184+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
185+
pub type DedupByWithCount<I, Pred> =
186+
CoalesceBy<I, DedupPredWithCount2CoalescePred<Pred>, (usize, <I as Iterator>::Item)>;
187+
188+
#[derive(Clone)]
189+
pub struct DedupPredWithCount2CoalescePred<DP>(DP);
190+
191+
impl<DP, T> CoalescePredicate<T, (usize, T)> for DedupPredWithCount2CoalescePred<DP>
192+
where
193+
DP: DedupPredicate<T>,
194+
{
195+
fn coalesce_pair(
196+
&mut self,
197+
(c, t): (usize, T),
198+
item: T,
199+
) -> Result<(usize, T), ((usize, T), (usize, T))> {
200+
if self.0.dedup_pair(&t, &item) {
201+
Ok((c + 1, t))
202+
} else {
203+
Err(((c, t), (1, item)))
204+
}
205+
}
206+
}
207+
208+
/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
209+
/// repeated elements were present.
210+
///
211+
/// See [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information.
212+
pub type DedupWithCount<I> = DedupByWithCount<I, DedupEq>;
213+
214+
/// Create a new `DedupByWithCount`.
215+
pub fn dedup_by_with_count<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred>
216+
where
217+
I: Iterator,
218+
{
219+
DedupByWithCount {
220+
last: iter.next().map(|v| (1, v)),
221+
iter,
222+
f: DedupPredWithCount2CoalescePred(dedup_pred),
223+
}
224+
}
225+
226+
/// Create a new `DedupWithCount`.
227+
pub fn dedup_with_count<I>(iter: I) -> DedupWithCount<I>
228+
where
229+
I: Iterator,
230+
{
231+
dedup_by_with_count(iter, DedupEq)
232+
}

0 commit comments

Comments
 (0)