1 use std::cmp::Ordering;
2 use std::fmt;
3 use std::iter::{Fuse, FusedIterator};
4 use std::marker::PhantomData;
5
6 use either::Either;
7
8 use super::adaptors::{put_back, PutBack};
9 use crate::either_or_both::EitherOrBoth;
10 use crate::size_hint::{self, SizeHint};
11 #[cfg(doc)]
12 use crate::Itertools;
13
14 #[derive(Clone, Debug)]
15 pub struct MergeLte;
16
17 /// An iterator adaptor that merges the two base iterators in ascending order.
18 /// If both base iterators are sorted (ascending), the result is sorted.
19 ///
20 /// Iterator element type is `I::Item`.
21 ///
22 /// See [`.merge()`](crate::Itertools::merge_by) for more information.
23 pub type Merge<I, J> = MergeBy<I, J, MergeLte>;
24
25 /// Create an iterator that merges elements in `i` and `j`.
26 ///
27 /// [`IntoIterator`] enabled version of [`Itertools::merge`](crate::Itertools::merge).
28 ///
29 /// ```
30 /// use itertools::merge;
31 ///
32 /// for elt in merge(&[1, 2, 3], &[2, 3, 4]) {
33 /// /* loop body */
34 /// }
35 /// ```
merge<I, J>( i: I, j: J, ) -> Merge<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter> where I: IntoIterator, J: IntoIterator<Item = I::Item>, I::Item: PartialOrd,36 pub fn merge<I, J>(
37 i: I,
38 j: J,
39 ) -> Merge<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
40 where
41 I: IntoIterator,
42 J: IntoIterator<Item = I::Item>,
43 I::Item: PartialOrd,
44 {
45 merge_by_new(i, j, MergeLte)
46 }
47
48 /// An iterator adaptor that merges the two base iterators in ascending order.
49 /// If both base iterators are sorted (ascending), the result is sorted.
50 ///
51 /// Iterator element type is `I::Item`.
52 ///
53 /// See [`.merge_by()`](crate::Itertools::merge_by) for more information.
54 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
55 pub struct MergeBy<I: Iterator, J: Iterator, F> {
56 left: PutBack<Fuse<I>>,
57 right: PutBack<Fuse<J>>,
58 cmp_fn: F,
59 }
60
61 /// Create a `MergeBy` iterator.
merge_by_new<I, J, F>(a: I, b: J, cmp: F) -> MergeBy<I::IntoIter, J::IntoIter, F> where I: IntoIterator, J: IntoIterator<Item = I::Item>,62 pub fn merge_by_new<I, J, F>(a: I, b: J, cmp: F) -> MergeBy<I::IntoIter, J::IntoIter, F>
63 where
64 I: IntoIterator,
65 J: IntoIterator<Item = I::Item>,
66 {
67 MergeBy {
68 left: put_back(a.into_iter().fuse()),
69 right: put_back(b.into_iter().fuse()),
70 cmp_fn: cmp,
71 }
72 }
73
74 /// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
75 ///
76 /// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
merge_join_by<I, J, F, T>( left: I, right: J, cmp_fn: F, ) -> MergeJoinBy<I::IntoIter, J::IntoIter, F> where I: IntoIterator, J: IntoIterator, F: FnMut(&I::Item, &J::Item) -> T,77 pub fn merge_join_by<I, J, F, T>(
78 left: I,
79 right: J,
80 cmp_fn: F,
81 ) -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
82 where
83 I: IntoIterator,
84 J: IntoIterator,
85 F: FnMut(&I::Item, &J::Item) -> T,
86 {
87 MergeBy {
88 left: put_back(left.into_iter().fuse()),
89 right: put_back(right.into_iter().fuse()),
90 cmp_fn: MergeFuncLR(cmp_fn, PhantomData),
91 }
92 }
93
94 /// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
95 ///
96 /// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information.
97 pub type MergeJoinBy<I, J, F> =
98 MergeBy<I, J, MergeFuncLR<F, <F as FuncLR<<I as Iterator>::Item, <J as Iterator>::Item>>::T>>;
99
100 #[derive(Clone, Debug)]
101 pub struct MergeFuncLR<F, T>(F, PhantomData<T>);
102
103 pub trait FuncLR<L, R> {
104 type T;
105 }
106
107 impl<L, R, T, F: FnMut(&L, &R) -> T> FuncLR<L, R> for F {
108 type T = T;
109 }
110
111 pub trait OrderingOrBool<L, R> {
112 type MergeResult;
left(left: L) -> Self::MergeResult113 fn left(left: L) -> Self::MergeResult;
right(right: R) -> Self::MergeResult114 fn right(right: R) -> Self::MergeResult;
115 // "merge" never returns (Some(...), Some(...), ...) so Option<Either<I::Item, J::Item>>
116 // is appealing but it is always followed by two put_backs, so we think the compiler is
117 // smart enough to optimize it. Or we could move put_backs into "merge".
merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult)118 fn merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult);
size_hint(left: SizeHint, right: SizeHint) -> SizeHint119 fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint;
120 }
121
122 impl<L, R, F: FnMut(&L, &R) -> Ordering> OrderingOrBool<L, R> for MergeFuncLR<F, Ordering> {
123 type MergeResult = EitherOrBoth<L, R>;
left(left: L) -> Self::MergeResult124 fn left(left: L) -> Self::MergeResult {
125 EitherOrBoth::Left(left)
126 }
right(right: R) -> Self::MergeResult127 fn right(right: R) -> Self::MergeResult {
128 EitherOrBoth::Right(right)
129 }
merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult)130 fn merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult) {
131 match self.0(&left, &right) {
132 Ordering::Equal => (None, EitherOrBoth::Both(left, right)),
133 Ordering::Less => (Some(Either::Right(right)), EitherOrBoth::Left(left)),
134 Ordering::Greater => (Some(Either::Left(left)), EitherOrBoth::Right(right)),
135 }
136 }
size_hint(left: SizeHint, right: SizeHint) -> SizeHint137 fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
138 let (a_lower, a_upper) = left;
139 let (b_lower, b_upper) = right;
140 let lower = ::std::cmp::max(a_lower, b_lower);
141 let upper = match (a_upper, b_upper) {
142 (Some(x), Some(y)) => x.checked_add(y),
143 _ => None,
144 };
145 (lower, upper)
146 }
147 }
148
149 impl<L, R, F: FnMut(&L, &R) -> bool> OrderingOrBool<L, R> for MergeFuncLR<F, bool> {
150 type MergeResult = Either<L, R>;
left(left: L) -> Self::MergeResult151 fn left(left: L) -> Self::MergeResult {
152 Either::Left(left)
153 }
right(right: R) -> Self::MergeResult154 fn right(right: R) -> Self::MergeResult {
155 Either::Right(right)
156 }
merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult)157 fn merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult) {
158 if self.0(&left, &right) {
159 (Some(Either::Right(right)), Either::Left(left))
160 } else {
161 (Some(Either::Left(left)), Either::Right(right))
162 }
163 }
size_hint(left: SizeHint, right: SizeHint) -> SizeHint164 fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
165 // Not ExactSizeIterator because size may be larger than usize
166 size_hint::add(left, right)
167 }
168 }
169
170 impl<T, F: FnMut(&T, &T) -> bool> OrderingOrBool<T, T> for F {
171 type MergeResult = T;
left(left: T) -> Self::MergeResult172 fn left(left: T) -> Self::MergeResult {
173 left
174 }
right(right: T) -> Self::MergeResult175 fn right(right: T) -> Self::MergeResult {
176 right
177 }
merge(&mut self, left: T, right: T) -> (Option<Either<T, T>>, Self::MergeResult)178 fn merge(&mut self, left: T, right: T) -> (Option<Either<T, T>>, Self::MergeResult) {
179 if self(&left, &right) {
180 (Some(Either::Right(right)), left)
181 } else {
182 (Some(Either::Left(left)), right)
183 }
184 }
size_hint(left: SizeHint, right: SizeHint) -> SizeHint185 fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
186 // Not ExactSizeIterator because size may be larger than usize
187 size_hint::add(left, right)
188 }
189 }
190
191 impl<T: PartialOrd> OrderingOrBool<T, T> for MergeLte {
192 type MergeResult = T;
left(left: T) -> Self::MergeResult193 fn left(left: T) -> Self::MergeResult {
194 left
195 }
right(right: T) -> Self::MergeResult196 fn right(right: T) -> Self::MergeResult {
197 right
198 }
merge(&mut self, left: T, right: T) -> (Option<Either<T, T>>, Self::MergeResult)199 fn merge(&mut self, left: T, right: T) -> (Option<Either<T, T>>, Self::MergeResult) {
200 if left <= right {
201 (Some(Either::Right(right)), left)
202 } else {
203 (Some(Either::Left(left)), right)
204 }
205 }
size_hint(left: SizeHint, right: SizeHint) -> SizeHint206 fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
207 // Not ExactSizeIterator because size may be larger than usize
208 size_hint::add(left, right)
209 }
210 }
211
212 impl<I, J, F> Clone for MergeBy<I, J, F>
213 where
214 I: Iterator,
215 J: Iterator,
216 PutBack<Fuse<I>>: Clone,
217 PutBack<Fuse<J>>: Clone,
218 F: Clone,
219 {
220 clone_fields!(left, right, cmp_fn);
221 }
222
223 impl<I, J, F> fmt::Debug for MergeBy<I, J, F>
224 where
225 I: Iterator + fmt::Debug,
226 I::Item: fmt::Debug,
227 J: Iterator + fmt::Debug,
228 J::Item: fmt::Debug,
229 {
230 debug_fmt_fields!(MergeBy, left, right);
231 }
232
233 impl<I, J, F> Iterator for MergeBy<I, J, F>
234 where
235 I: Iterator,
236 J: Iterator,
237 F: OrderingOrBool<I::Item, J::Item>,
238 {
239 type Item = F::MergeResult;
240
next(&mut self) -> Option<Self::Item>241 fn next(&mut self) -> Option<Self::Item> {
242 match (self.left.next(), self.right.next()) {
243 (None, None) => None,
244 (Some(left), None) => Some(F::left(left)),
245 (None, Some(right)) => Some(F::right(right)),
246 (Some(left), Some(right)) => {
247 let (not_next, next) = self.cmp_fn.merge(left, right);
248 match not_next {
249 Some(Either::Left(l)) => {
250 self.left.put_back(l);
251 }
252 Some(Either::Right(r)) => {
253 self.right.put_back(r);
254 }
255 None => (),
256 }
257
258 Some(next)
259 }
260 }
261 }
262
fold<B, G>(mut self, init: B, mut f: G) -> B where Self: Sized, G: FnMut(B, Self::Item) -> B,263 fn fold<B, G>(mut self, init: B, mut f: G) -> B
264 where
265 Self: Sized,
266 G: FnMut(B, Self::Item) -> B,
267 {
268 let mut acc = init;
269 let mut left = self.left.next();
270 let mut right = self.right.next();
271
272 loop {
273 match (left, right) {
274 (Some(l), Some(r)) => match self.cmp_fn.merge(l, r) {
275 (Some(Either::Right(r)), x) => {
276 acc = f(acc, x);
277 left = self.left.next();
278 right = Some(r);
279 }
280 (Some(Either::Left(l)), x) => {
281 acc = f(acc, x);
282 left = Some(l);
283 right = self.right.next();
284 }
285 (None, x) => {
286 acc = f(acc, x);
287 left = self.left.next();
288 right = self.right.next();
289 }
290 },
291 (Some(l), None) => {
292 self.left.put_back(l);
293 acc = self.left.fold(acc, |acc, x| f(acc, F::left(x)));
294 break;
295 }
296 (None, Some(r)) => {
297 self.right.put_back(r);
298 acc = self.right.fold(acc, |acc, x| f(acc, F::right(x)));
299 break;
300 }
301 (None, None) => {
302 break;
303 }
304 }
305 }
306
307 acc
308 }
309
size_hint(&self) -> SizeHint310 fn size_hint(&self) -> SizeHint {
311 F::size_hint(self.left.size_hint(), self.right.size_hint())
312 }
313
nth(&mut self, mut n: usize) -> Option<Self::Item>314 fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
315 loop {
316 if n == 0 {
317 break self.next();
318 }
319 n -= 1;
320 match (self.left.next(), self.right.next()) {
321 (None, None) => break None,
322 (Some(_left), None) => break self.left.nth(n).map(F::left),
323 (None, Some(_right)) => break self.right.nth(n).map(F::right),
324 (Some(left), Some(right)) => {
325 let (not_next, _) = self.cmp_fn.merge(left, right);
326 match not_next {
327 Some(Either::Left(l)) => {
328 self.left.put_back(l);
329 }
330 Some(Either::Right(r)) => {
331 self.right.put_back(r);
332 }
333 None => (),
334 }
335 }
336 }
337 }
338 }
339 }
340
341 impl<I, J, F> FusedIterator for MergeBy<I, J, F>
342 where
343 I: Iterator,
344 J: Iterator,
345 F: OrderingOrBool<I::Item, J::Item>,
346 {
347 }
348