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