subms_merge_iterator/features/
priority.rs1use std::cmp::Reverse;
14use std::collections::BinaryHeap;
15
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct PriorityEntry<K, V> {
18 pub key: K,
19 pub value: V,
20}
21
22impl<K, V> PriorityEntry<K, V> {
23 pub fn new(key: K, value: V) -> Self {
24 Self { key, value }
25 }
26}
27
28pub struct PrioritySource<I> {
32 pub priority: i32,
33 pub stream: I,
34}
35
36impl<I> PrioritySource<I> {
37 pub fn new(priority: i32, stream: I) -> Self {
38 Self { priority, stream }
39 }
40}
41
42pub struct PriorityMergeIterator<K, V, I>
43where
44 K: Ord,
45 I: Iterator<Item = PriorityEntry<K, V>>,
46{
47 streams: Vec<I>,
48 priorities: Vec<i32>,
49 heap: BinaryHeap<Reverse<HeapItem<K, V>>>,
50}
51
52struct HeapItem<K, V> {
53 key: K,
54 priority: i32,
56 source: usize,
57 value: V,
58}
59
60impl<K: Ord, V> PartialEq for HeapItem<K, V> {
61 fn eq(&self, other: &Self) -> bool {
62 self.key == other.key && self.source == other.source
63 }
64}
65impl<K: Ord, V> Eq for HeapItem<K, V> {}
66
67impl<K: Ord, V> PartialOrd for HeapItem<K, V> {
68 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
69 Some(self.cmp(other))
70 }
71}
72impl<K: Ord, V> Ord for HeapItem<K, V> {
73 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
74 self.key
78 .cmp(&other.key)
79 .then(other.priority.cmp(&self.priority))
80 .then(other.source.cmp(&self.source))
81 }
82}
83
84impl<K, V, I> PriorityMergeIterator<K, V, I>
85where
86 K: Ord,
87 I: Iterator<Item = PriorityEntry<K, V>>,
88{
89 pub fn new<S: IntoIterator<Item = PrioritySource<I>>>(sources: S) -> Self {
90 let sources: Vec<PrioritySource<I>> = sources.into_iter().collect();
91 let mut streams: Vec<I> = Vec::with_capacity(sources.len());
92 let mut priorities: Vec<i32> = Vec::with_capacity(sources.len());
93 let mut heap: BinaryHeap<Reverse<HeapItem<K, V>>> =
94 BinaryHeap::with_capacity(sources.len());
95 for (i, src) in sources.into_iter().enumerate() {
96 streams.push(src.stream);
97 priorities.push(src.priority);
98 if let Some(e) = streams[i].next() {
99 heap.push(Reverse(HeapItem {
100 key: e.key,
101 priority: src.priority,
102 source: i,
103 value: e.value,
104 }));
105 }
106 }
107 Self {
108 streams,
109 priorities,
110 heap,
111 }
112 }
113
114 fn advance(&mut self, source: usize) {
115 if let Some(e) = self.streams[source].next() {
116 let p = self.priorities[source];
117 self.heap.push(Reverse(HeapItem {
118 key: e.key,
119 priority: p,
120 source,
121 value: e.value,
122 }));
123 }
124 }
125}
126
127impl<K, V, I> Iterator for PriorityMergeIterator<K, V, I>
128where
129 K: Ord,
130 I: Iterator<Item = PriorityEntry<K, V>>,
131{
132 type Item = PriorityEntry<K, V>;
133
134 fn next(&mut self) -> Option<PriorityEntry<K, V>> {
135 let Reverse(HeapItem {
136 key: winning_key,
137 source,
138 value: winning_value,
139 ..
140 }) = self.heap.pop()?;
141 self.advance(source);
142 while let Some(Reverse(item)) = self.heap.peek() {
143 if item.key == winning_key {
144 let Reverse(item) = self.heap.pop().unwrap();
145 self.advance(item.source);
146 } else {
147 break;
148 }
149 }
150 Some(PriorityEntry {
151 key: winning_key,
152 value: winning_value,
153 })
154 }
155}
156
157#[cfg(test)]
158#[path = "priority_tests.rs"]
159mod tests;