• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::size_hint;
2 use crate::Itertools;
3 
4 use alloc::vec::Vec;
5 use std::mem::replace;
6 use std::fmt;
7 
8 /// Head element and Tail iterator pair
9 ///
10 /// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
11 /// first items (which are guaranteed to exist).
12 ///
13 /// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
14 /// `KMerge` into a min-heap.
15 #[derive(Debug)]
16 struct HeadTail<I>
17     where I: Iterator
18 {
19     head: I::Item,
20     tail: I,
21 }
22 
23 impl<I> HeadTail<I>
24     where I: Iterator
25 {
26     /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
new(mut it: I) -> Option<HeadTail<I>>27     fn new(mut it: I) -> Option<HeadTail<I>> {
28         let head = it.next();
29         head.map(|h| {
30             HeadTail {
31                 head: h,
32                 tail: it,
33             }
34         })
35     }
36 
37     /// Get the next element and update `head`, returning the old head in `Some`.
38     ///
39     /// Returns `None` when the tail is exhausted (only `head` then remains).
next(&mut self) -> Option<I::Item>40     fn next(&mut self) -> Option<I::Item> {
41         if let Some(next) = self.tail.next() {
42             Some(replace(&mut self.head, next))
43         } else {
44             None
45         }
46     }
47 
48     /// Hints at the size of the sequence, same as the `Iterator` method.
size_hint(&self) -> (usize, Option<usize>)49     fn size_hint(&self) -> (usize, Option<usize>) {
50         size_hint::add_scalar(self.tail.size_hint(), 1)
51     }
52 }
53 
54 impl<I> Clone for HeadTail<I>
55     where I: Iterator + Clone,
56           I::Item: Clone
57 {
58     clone_fields!(head, tail);
59 }
60 
61 /// Make `data` a heap (min-heap w.r.t the sorting).
heapify<T, S>(data: &mut [T], mut less_than: S) where S: FnMut(&T, &T) -> bool62 fn heapify<T, S>(data: &mut [T], mut less_than: S)
63     where S: FnMut(&T, &T) -> bool
64 {
65     for i in (0..data.len() / 2).rev() {
66         sift_down(data, i, &mut less_than);
67     }
68 }
69 
70 /// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S) where S: FnMut(&T, &T) -> bool71 fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
72     where S: FnMut(&T, &T) -> bool
73 {
74     debug_assert!(index <= heap.len());
75     let mut pos = index;
76     let mut child = 2 * pos + 1;
77     // the `pos` conditional is to avoid a bounds check
78     while pos < heap.len() && child < heap.len() {
79         let right = child + 1;
80 
81         // pick the smaller of the two children
82         if right < heap.len() && less_than(&heap[right], &heap[child]) {
83             child = right;
84         }
85 
86         // sift down is done if we are already in order
87         if !less_than(&heap[child], &heap[pos]) {
88             return;
89         }
90         heap.swap(pos, child);
91         pos = child;
92         child = 2 * pos + 1;
93     }
94 }
95 
96 /// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
97 /// If all base iterators are sorted (ascending), the result is sorted.
98 ///
99 /// Iterator element type is `I::Item`.
100 ///
101 /// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information.
102 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
103 pub type KMerge<I> = KMergeBy<I, KMergeByLt>;
104 
105 pub trait KMergePredicate<T> {
kmerge_pred(&mut self, a: &T, b: &T) -> bool106     fn kmerge_pred(&mut self, a: &T, b: &T) -> bool;
107 }
108 
109 #[derive(Clone)]
110 pub struct KMergeByLt;
111 
112 impl<T: PartialOrd> KMergePredicate<T> for KMergeByLt {
kmerge_pred(&mut self, a: &T, b: &T) -> bool113     fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
114         a < b
115     }
116 }
117 
118 impl<T, F: FnMut(&T, &T)->bool> KMergePredicate<T> for F {
kmerge_pred(&mut self, a: &T, b: &T) -> bool119     fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
120         self(a, b)
121     }
122 }
123 
124 /// Create an iterator that merges elements of the contained iterators using
125 /// the ordering function.
126 ///
127 /// Equivalent to `iterable.into_iter().kmerge()`.
128 ///
129 /// ```
130 /// use itertools::kmerge;
131 ///
132 /// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
133 ///     /* loop body */
134 /// }
135 /// ```
kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter> where I: IntoIterator, I::Item: IntoIterator, <<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd136 pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
137     where I: IntoIterator,
138           I::Item: IntoIterator,
139           <<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
140 {
141     kmerge_by(iterable, KMergeByLt)
142 }
143 
144 /// An iterator adaptor that merges an abitrary number of base iterators
145 /// according to an ordering function.
146 ///
147 /// Iterator element type is `I::Item`.
148 ///
149 /// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more
150 /// information.
151 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
152 pub struct KMergeBy<I, F>
153     where I: Iterator,
154 {
155     heap: Vec<HeadTail<I>>,
156     less_than: F,
157 }
158 
159 impl<I, F> fmt::Debug for KMergeBy<I, F>
160     where I: Iterator + fmt::Debug,
161           I::Item: fmt::Debug,
162 {
163     debug_fmt_fields!(KMergeBy, heap);
164 }
165 
166 /// Create an iterator that merges elements of the contained iterators.
167 ///
168 /// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
kmerge_by<I, F>(iterable: I, mut less_than: F) -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F> where I: IntoIterator, I::Item: IntoIterator, F: KMergePredicate<<<I as IntoIterator>::Item as IntoIterator>::Item>,169 pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
170     -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
171     where I: IntoIterator,
172           I::Item: IntoIterator,
173           F: KMergePredicate<<<I as IntoIterator>::Item as IntoIterator>::Item>,
174 {
175     let iter = iterable.into_iter();
176     let (lower, _) = iter.size_hint();
177     let mut heap: Vec<_> = Vec::with_capacity(lower);
178     heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
179     heapify(&mut heap, |a, b| less_than.kmerge_pred(&a.head, &b.head));
180     KMergeBy { heap, less_than }
181 }
182 
183 impl<I, F> Clone for KMergeBy<I, F>
184     where I: Iterator + Clone,
185           I::Item: Clone,
186           F: Clone,
187 {
188     clone_fields!(heap, less_than);
189 }
190 
191 impl<I, F> Iterator for KMergeBy<I, F>
192     where I: Iterator,
193           F: KMergePredicate<I::Item>
194 {
195     type Item = I::Item;
196 
next(&mut self) -> Option<Self::Item>197     fn next(&mut self) -> Option<Self::Item> {
198         if self.heap.is_empty() {
199             return None;
200         }
201         let result = if let Some(next) = self.heap[0].next() {
202             next
203         } else {
204             self.heap.swap_remove(0).head
205         };
206         let less_than = &mut self.less_than;
207         sift_down(&mut self.heap, 0, |a, b| less_than.kmerge_pred(&a.head, &b.head));
208         Some(result)
209     }
210 
size_hint(&self) -> (usize, Option<usize>)211     fn size_hint(&self) -> (usize, Option<usize>) {
212         self.heap.iter()
213                  .map(|i| i.size_hint())
214                  .fold1(size_hint::add)
215                  .unwrap_or((0, Some(0)))
216     }
217 }
218