Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/itertools-0.11.0/src/merge_join.rs
Line
Count
Source (jump to first uncovered line)
1
use std::cmp::Ordering;
2
use std::iter::Fuse;
3
use std::fmt;
4
5
use either::Either;
6
7
use super::adaptors::{PutBack, put_back};
8
use crate::either_or_both::EitherOrBoth;
9
use crate::size_hint::{self, SizeHint};
10
#[cfg(doc)]
11
use crate::Itertools;
12
13
/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
14
///
15
/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
16
0
pub fn merge_join_by<I, J, F, T>(left: I, right: J, cmp_fn: F)
17
0
    -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
18
0
    where I: IntoIterator,
19
0
          J: IntoIterator,
20
0
          F: FnMut(&I::Item, &J::Item) -> T,
21
0
          T: OrderingOrBool<I::Item, J::Item>,
22
0
{
23
0
    MergeJoinBy {
24
0
        left: put_back(left.into_iter().fuse()),
25
0
        right: put_back(right.into_iter().fuse()),
26
0
        cmp_fn,
27
0
    }
28
0
}
29
30
/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
31
///
32
/// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information.
33
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
34
pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
35
    left: PutBack<Fuse<I>>,
36
    right: PutBack<Fuse<J>>,
37
    cmp_fn: F,
38
}
39
40
pub trait OrderingOrBool<L, R> {
41
    type MergeResult;
42
    fn left(left: L) -> Self::MergeResult;
43
    fn right(right: R) -> Self::MergeResult;
44
    // "merge" never returns (Some(...), Some(...), ...) so Option<Either<I::Item, J::Item>>
45
    // is appealing but it is always followed by two put_backs, so we think the compiler is
46
    // smart enough to optimize it. Or we could move put_backs into "merge".
47
    fn merge(self, left: L, right: R) -> (Option<L>, Option<R>, Self::MergeResult);
48
    fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint;
49
}
50
51
impl<L, R> OrderingOrBool<L, R> for Ordering {
52
    type MergeResult = EitherOrBoth<L, R>;
53
0
    fn left(left: L) -> Self::MergeResult {
54
0
        EitherOrBoth::Left(left)
55
0
    }
56
0
    fn right(right: R) -> Self::MergeResult {
57
0
        EitherOrBoth::Right(right)
58
0
    }
59
0
    fn merge(self, left: L, right: R) -> (Option<L>, Option<R>, Self::MergeResult) {
60
0
        match self {
61
0
            Ordering::Equal => (None, None, EitherOrBoth::Both(left, right)),
62
0
            Ordering::Less => (None, Some(right), EitherOrBoth::Left(left)),
63
0
            Ordering::Greater => (Some(left), None, EitherOrBoth::Right(right)),
64
        }
65
0
    }
66
0
    fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
67
0
        let (a_lower, a_upper) = left;
68
0
        let (b_lower, b_upper) = right;
69
0
        let lower = ::std::cmp::max(a_lower, b_lower);
70
0
        let upper = match (a_upper, b_upper) {
71
0
            (Some(x), Some(y)) => x.checked_add(y),
72
0
            _ => None,
73
        };
74
0
        (lower, upper)
75
0
    }
76
}
77
78
impl<L, R> OrderingOrBool<L, R> for bool {
79
    type MergeResult = Either<L, R>;
80
0
    fn left(left: L) -> Self::MergeResult {
81
0
        Either::Left(left)
82
0
    }
83
0
    fn right(right: R) -> Self::MergeResult {
84
0
        Either::Right(right)
85
0
    }
86
0
    fn merge(self, left: L, right: R) -> (Option<L>, Option<R>, Self::MergeResult) {
87
0
        if self {
88
0
            (None, Some(right), Either::Left(left))
89
        } else {
90
0
            (Some(left), None, Either::Right(right))
91
        }
92
0
    }
93
0
    fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
94
0
        // Not ExactSizeIterator because size may be larger than usize
95
0
        size_hint::add(left, right)
96
0
    }
97
}
98
99
impl<I, J, F> Clone for MergeJoinBy<I, J, F>
100
    where I: Iterator,
101
          J: Iterator,
102
          PutBack<Fuse<I>>: Clone,
103
          PutBack<Fuse<J>>: Clone,
104
          F: Clone,
105
{
106
    clone_fields!(left, right, cmp_fn);
107
}
108
109
impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
110
    where I: Iterator + fmt::Debug,
111
          I::Item: fmt::Debug,
112
          J: Iterator + fmt::Debug,
113
          J::Item: fmt::Debug,
114
{
115
    debug_fmt_fields!(MergeJoinBy, left, right);
116
}
117
118
impl<I, J, F, T> Iterator for MergeJoinBy<I, J, F>
119
    where I: Iterator,
120
          J: Iterator,
121
          F: FnMut(&I::Item, &J::Item) -> T,
122
          T: OrderingOrBool<I::Item, J::Item>,
123
{
124
    type Item = T::MergeResult;
125
126
0
    fn next(&mut self) -> Option<Self::Item> {
127
0
        match (self.left.next(), self.right.next()) {
128
0
            (None, None) => None,
129
0
            (Some(left), None) => Some(T::left(left)),
130
0
            (None, Some(right)) => Some(T::right(right)),
131
0
            (Some(left), Some(right)) => {
132
0
                let (left, right, next) = (self.cmp_fn)(&left, &right).merge(left, right);
133
0
                if let Some(left) = left {
134
0
                    self.left.put_back(left);
135
0
                }
136
0
                if let Some(right) = right {
137
0
                    self.right.put_back(right);
138
0
                }
139
0
                Some(next)
140
            }
141
        }
142
0
    }
143
144
0
    fn size_hint(&self) -> SizeHint {
145
0
        T::size_hint(self.left.size_hint(), self.right.size_hint())
146
0
    }
147
148
0
    fn count(mut self) -> usize {
149
0
        let mut count = 0;
150
        loop {
151
0
            match (self.left.next(), self.right.next()) {
152
0
                (None, None) => break count,
153
0
                (Some(_left), None) => break count + 1 + self.left.into_parts().1.count(),
154
0
                (None, Some(_right)) => break count + 1 + self.right.into_parts().1.count(),
155
0
                (Some(left), Some(right)) => {
156
0
                    count += 1;
157
0
                    let (left, right, _) = (self.cmp_fn)(&left, &right).merge(left, right);
158
0
                    if let Some(left) = left {
159
0
                        self.left.put_back(left);
160
0
                    }
161
0
                    if let Some(right) = right {
162
0
                        self.right.put_back(right);
163
0
                    }
164
                }
165
            }
166
        }
167
0
    }
168
169
0
    fn last(mut self) -> Option<Self::Item> {
170
0
        let mut previous_element = None;
171
        loop {
172
0
            match (self.left.next(), self.right.next()) {
173
0
                (None, None) => break previous_element,
174
0
                (Some(left), None) => {
175
0
                    break Some(T::left(
176
0
                        self.left.into_parts().1.last().unwrap_or(left),
177
0
                    ))
178
                }
179
0
                (None, Some(right)) => {
180
0
                    break Some(T::right(
181
0
                        self.right.into_parts().1.last().unwrap_or(right),
182
0
                    ))
183
                }
184
0
                (Some(left), Some(right)) => {
185
0
                    let (left, right, elem) = (self.cmp_fn)(&left, &right).merge(left, right);
186
0
                    if let Some(left) = left {
187
0
                        self.left.put_back(left);
188
0
                    }
189
0
                    if let Some(right) = right {
190
0
                        self.right.put_back(right);
191
0
                    }
192
0
                    previous_element = Some(elem);
193
                }
194
            }
195
        }
196
0
    }
197
198
0
    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
199
        loop {
200
0
            if n == 0 {
201
0
                break self.next();
202
0
            }
203
0
            n -= 1;
204
0
            match (self.left.next(), self.right.next()) {
205
0
                (None, None) => break None,
206
0
                (Some(_left), None) => break self.left.nth(n).map(T::left),
207
0
                (None, Some(_right)) => break self.right.nth(n).map(T::right),
208
0
                (Some(left), Some(right)) => {
209
0
                    let (left, right, _) = (self.cmp_fn)(&left, &right).merge(left, right);
210
0
                    if let Some(left) = left {
211
0
                        self.left.put_back(left);
212
0
                    }
213
0
                    if let Some(right) = right {
214
0
                        self.right.put_back(right);
215
0
                    }
216
                }
217
            }
218
        }
219
0
    }
220
}