use super::plumbing::*; use super::*; use std::cmp; use std::iter::Fuse; /// `Interleave` is an iterator that interleaves elements of iterators /// `i` and `j` in one continuous iterator. This struct is created by /// the [`interleave()`] method on [`IndexedParallelIterator`] /// /// [`interleave()`]: trait.IndexedParallelIterator.html#method.interleave /// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[derive(Debug, Clone)] pub struct Interleave<I, J> where I: IndexedParallelIterator, J: IndexedParallelIterator<Item = I::Item>, { i: I, j: J, } impl<I, J> Interleave<I, J> where I: IndexedParallelIterator, J: IndexedParallelIterator<Item = I::Item>, { /// Creates a new `Interleave` iterator pub(super) fn new(i: I, j: J) -> Self { Interleave { i, j } } } impl<I, J> ParallelIterator for Interleave<I, J> where I: IndexedParallelIterator, J: IndexedParallelIterator<Item = I::Item>, { type Item = I::Item; fn drive_unindexed<C>(self, consumer: C) -> C::Result where C: Consumer<I::Item>, { bridge(self, consumer) } fn opt_len(&self) -> Option<usize> { Some(self.len()) } } impl<I, J> IndexedParallelIterator for Interleave<I, J> where I: IndexedParallelIterator, J: IndexedParallelIterator<Item = I::Item>, { fn drive<C>(self, consumer: C) -> C::Result where C: Consumer<Self::Item>, { bridge(self, consumer) } fn len(&self) -> usize { self.i.len().checked_add(self.j.len()).expect("overflow") } fn with_producer<CB>(self, callback: CB) -> CB::Output where CB: ProducerCallback<Self::Item>, { let (i_len, j_len) = (self.i.len(), self.j.len()); return self.i.with_producer(CallbackI { callback, i_len, j_len, i_next: false, j: self.j, }); struct CallbackI<CB, J> { callback: CB, i_len: usize, j_len: usize, i_next: bool, j: J, } impl<CB, J> ProducerCallback<J::Item> for CallbackI<CB, J> where J: IndexedParallelIterator, CB: ProducerCallback<J::Item>, { type Output = CB::Output; fn callback<I>(self, i_producer: I) -> Self::Output where I: Producer<Item = J::Item>, { self.j.with_producer(CallbackJ { i_producer, i_len: self.i_len, j_len: self.j_len, i_next: self.i_next, callback: self.callback, }) } } struct CallbackJ<CB, I> { callback: CB, i_len: usize, j_len: usize, i_next: bool, i_producer: I, } impl<CB, I> ProducerCallback<I::Item> for CallbackJ<CB, I> where I: Producer, CB: ProducerCallback<I::Item>, { type Output = CB::Output; fn callback<J>(self, j_producer: J) -> Self::Output where J: Producer<Item = I::Item>, { let producer = InterleaveProducer::new( self.i_producer, j_producer, self.i_len, self.j_len, self.i_next, ); self.callback.callback(producer) } } } } struct InterleaveProducer<I, J> where I: Producer, J: Producer<Item = I::Item>, { i: I, j: J, i_len: usize, j_len: usize, i_next: bool, } impl<I, J> InterleaveProducer<I, J> where I: Producer, J: Producer<Item = I::Item>, { fn new(i: I, j: J, i_len: usize, j_len: usize, i_next: bool) -> InterleaveProducer<I, J> { InterleaveProducer { i, j, i_len, j_len, i_next, } } } impl<I, J> Producer for InterleaveProducer<I, J> where I: Producer, J: Producer<Item = I::Item>, { type Item = I::Item; type IntoIter = InterleaveSeq<I::IntoIter, J::IntoIter>; fn into_iter(self) -> Self::IntoIter { InterleaveSeq { i: self.i.into_iter().fuse(), j: self.j.into_iter().fuse(), i_next: self.i_next, } } fn min_len(&self) -> usize { cmp::max(self.i.min_len(), self.j.min_len()) } fn max_len(&self) -> usize { cmp::min(self.i.max_len(), self.j.max_len()) } /// We know 0 < index <= self.i_len + self.j_len /// /// Find a, b satisfying: /// /// (1) 0 < a <= self.i_len /// (2) 0 < b <= self.j_len /// (3) a + b == index /// /// For even splits, set a = b = index/2. /// For odd splits, set a = (index/2)+1, b = index/2, if `i` /// should yield the next element, otherwise, if `j` should yield /// the next element, set a = index/2 and b = (index/2)+1 fn split_at(self, index: usize) -> (Self, Self) { #[inline] fn odd_offset(flag: bool) -> usize { (!flag) as usize } let even = index % 2 == 0; let idx = index >> 1; // desired split let (i_idx, j_idx) = ( idx + odd_offset(even || self.i_next), idx + odd_offset(even || !self.i_next), ); let (i_split, j_split) = if self.i_len >= i_idx && self.j_len >= j_idx { (i_idx, j_idx) } else if self.i_len >= i_idx { // j too short (index - self.j_len, self.j_len) } else { // i too short (self.i_len, index - self.i_len) }; let trailing_i_next = even == self.i_next; let (i_left, i_right) = self.i.split_at(i_split); let (j_left, j_right) = self.j.split_at(j_split); ( InterleaveProducer::new(i_left, j_left, i_split, j_split, self.i_next), InterleaveProducer::new( i_right, j_right, self.i_len - i_split, self.j_len - j_split, trailing_i_next, ), ) } } /// Wrapper for Interleave to implement DoubleEndedIterator and /// ExactSizeIterator. /// /// This iterator is fused. struct InterleaveSeq<I, J> { i: Fuse<I>, j: Fuse<J>, /// Flag to control which iterator should provide the next element. When /// `false` then `i` produces the next element, otherwise `j` produces the /// next element. i_next: bool, } /// Iterator implementation for InterleaveSeq. This implementation is /// taken more or less verbatim from itertools. It is replicated here /// (instead of calling itertools directly), because we also need to /// implement `DoubledEndedIterator` and `ExactSizeIterator`. impl<I, J> Iterator for InterleaveSeq<I, J> where I: Iterator, J: Iterator<Item = I::Item>, { type Item = I::Item; #[inline] fn next(&mut self) -> Option<Self::Item> { self.i_next = !self.i_next; if self.i_next { match self.i.next() { None => self.j.next(), r => r, } } else { match self.j.next() { None => self.i.next(), r => r, } } } fn size_hint(&self) -> (usize, Option<usize>) { let (ih, jh) = (self.i.size_hint(), self.j.size_hint()); let min = ih.0.saturating_add(jh.0); let max = match (ih.1, jh.1) { (Some(x), Some(y)) => x.checked_add(y), _ => None, }; (min, max) } } // The implementation for DoubleEndedIterator requires // ExactSizeIterator to provide `next_back()`. The last element will // come from the iterator that runs out last (ie has the most elements // in it). If the iterators have the same number of elements, then the // last iterator will provide the last element. impl<I, J> DoubleEndedIterator for InterleaveSeq<I, J> where I: DoubleEndedIterator + ExactSizeIterator, J: DoubleEndedIterator<Item = I::Item> + ExactSizeIterator<Item = I::Item>, { #[inline] fn next_back(&mut self) -> Option<I::Item> { match self.i.len().cmp(&self.j.len()) { Ordering::Less => self.j.next_back(), Ordering::Equal => { if self.i_next { self.i.next_back() } else { self.j.next_back() } } Ordering::Greater => self.i.next_back(), } } } impl<I, J> ExactSizeIterator for InterleaveSeq<I, J> where I: ExactSizeIterator, J: ExactSizeIterator<Item = I::Item>, { #[inline] fn len(&self) -> usize { self.i.len() + self.j.len() } }