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