summaryrefslogtreecommitdiffstats
path: root/third_party/rust/itertools/src/merge_join.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/itertools/src/merge_join.rs')
-rw-r--r--third_party/rust/itertools/src/merge_join.rs169
1 files changed, 169 insertions, 0 deletions
diff --git a/third_party/rust/itertools/src/merge_join.rs b/third_party/rust/itertools/src/merge_join.rs
new file mode 100644
index 0000000000..f2fbdea2c4
--- /dev/null
+++ b/third_party/rust/itertools/src/merge_join.rs
@@ -0,0 +1,169 @@
+use std::cmp::Ordering;
+use std::iter::Fuse;
+use std::fmt;
+
+use super::adaptors::{PutBack, put_back};
+use crate::either_or_both::EitherOrBoth;
+#[cfg(doc)]
+use crate::Itertools;
+
+/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
+///
+/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
+pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
+ -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
+ where I: IntoIterator,
+ J: IntoIterator,
+ F: FnMut(&I::Item, &J::Item) -> Ordering
+{
+ MergeJoinBy {
+ left: put_back(left.into_iter().fuse()),
+ right: put_back(right.into_iter().fuse()),
+ cmp_fn,
+ }
+}
+
+/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
+///
+/// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information.
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
+ left: PutBack<Fuse<I>>,
+ right: PutBack<Fuse<J>>,
+ cmp_fn: F
+}
+
+impl<I, J, F> Clone for MergeJoinBy<I, J, F>
+ where I: Iterator,
+ J: Iterator,
+ PutBack<Fuse<I>>: Clone,
+ PutBack<Fuse<J>>: Clone,
+ F: Clone,
+{
+ clone_fields!(left, right, cmp_fn);
+}
+
+impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
+ where I: Iterator + fmt::Debug,
+ I::Item: fmt::Debug,
+ J: Iterator + fmt::Debug,
+ J::Item: fmt::Debug,
+{
+ debug_fmt_fields!(MergeJoinBy, left, right);
+}
+
+impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
+ where I: Iterator,
+ J: Iterator,
+ F: FnMut(&I::Item, &J::Item) -> Ordering
+{
+ type Item = EitherOrBoth<I::Item, J::Item>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match (self.left.next(), self.right.next()) {
+ (None, None) => None,
+ (Some(left), None) =>
+ Some(EitherOrBoth::Left(left)),
+ (None, Some(right)) =>
+ Some(EitherOrBoth::Right(right)),
+ (Some(left), Some(right)) => {
+ match (self.cmp_fn)(&left, &right) {
+ Ordering::Equal =>
+ Some(EitherOrBoth::Both(left, right)),
+ Ordering::Less => {
+ self.right.put_back(right);
+ Some(EitherOrBoth::Left(left))
+ },
+ Ordering::Greater => {
+ self.left.put_back(left);
+ Some(EitherOrBoth::Right(right))
+ }
+ }
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (a_lower, a_upper) = self.left.size_hint();
+ let (b_lower, b_upper) = self.right.size_hint();
+
+ let lower = ::std::cmp::max(a_lower, b_lower);
+
+ let upper = match (a_upper, b_upper) {
+ (Some(x), Some(y)) => x.checked_add(y),
+ _ => None,
+ };
+
+ (lower, upper)
+ }
+
+ fn count(mut self) -> usize {
+ let mut count = 0;
+ loop {
+ match (self.left.next(), self.right.next()) {
+ (None, None) => break count,
+ (Some(_left), None) => break count + 1 + self.left.into_parts().1.count(),
+ (None, Some(_right)) => break count + 1 + self.right.into_parts().1.count(),
+ (Some(left), Some(right)) => {
+ count += 1;
+ match (self.cmp_fn)(&left, &right) {
+ Ordering::Equal => {}
+ Ordering::Less => self.right.put_back(right),
+ Ordering::Greater => self.left.put_back(left),
+ }
+ }
+ }
+ }
+ }
+
+ fn last(mut self) -> Option<Self::Item> {
+ let mut previous_element = None;
+ loop {
+ match (self.left.next(), self.right.next()) {
+ (None, None) => break previous_element,
+ (Some(left), None) => {
+ break Some(EitherOrBoth::Left(
+ self.left.into_parts().1.last().unwrap_or(left),
+ ))
+ }
+ (None, Some(right)) => {
+ break Some(EitherOrBoth::Right(
+ self.right.into_parts().1.last().unwrap_or(right),
+ ))
+ }
+ (Some(left), Some(right)) => {
+ previous_element = match (self.cmp_fn)(&left, &right) {
+ Ordering::Equal => Some(EitherOrBoth::Both(left, right)),
+ Ordering::Less => {
+ self.right.put_back(right);
+ Some(EitherOrBoth::Left(left))
+ }
+ Ordering::Greater => {
+ self.left.put_back(left);
+ Some(EitherOrBoth::Right(right))
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
+ loop {
+ if n == 0 {
+ break self.next();
+ }
+ n -= 1;
+ match (self.left.next(), self.right.next()) {
+ (None, None) => break None,
+ (Some(_left), None) => break self.left.nth(n).map(EitherOrBoth::Left),
+ (None, Some(_right)) => break self.right.nth(n).map(EitherOrBoth::Right),
+ (Some(left), Some(right)) => match (self.cmp_fn)(&left, &right) {
+ Ordering::Equal => {}
+ Ordering::Less => self.right.put_back(right),
+ Ordering::Greater => self.left.put_back(left),
+ },
+ }
+ }
+ }
+}