oxihuman_core/
priority_queue_ext.rs1#![allow(dead_code)]
4
5use std::cmp::Reverse;
8use std::collections::{BinaryHeap, HashMap};
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct PqEntry {
13 pub key: String,
14 pub priority: i64,
15}
16
17impl Eq for PqEntry {}
18
19impl PartialOrd for PqEntry {
20 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
21 Some(self.cmp(other))
22 }
23}
24
25impl Ord for PqEntry {
26 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
27 self.priority.cmp(&other.priority) }
29}
30
31pub struct PriorityQueueExt {
33 heap: BinaryHeap<Reverse<PqEntry>>,
34 current: HashMap<String, i64>,
35}
36
37pub fn new_priority_queue_ext() -> PriorityQueueExt {
39 PriorityQueueExt {
40 heap: BinaryHeap::new(),
41 current: HashMap::new(),
42 }
43}
44
45impl PriorityQueueExt {
46 pub fn insert(&mut self, key: &str, priority: i64) {
48 self.current.insert(key.to_string(), priority);
49 self.heap.push(Reverse(PqEntry {
50 key: key.to_string(),
51 priority,
52 }));
53 }
54
55 pub fn decrease_key(&mut self, key: &str, new_priority: i64) {
57 if let Some(p) = self.current.get_mut(key) {
58 if new_priority < *p {
59 *p = new_priority;
60 self.heap.push(Reverse(PqEntry {
61 key: key.to_string(),
62 priority: new_priority,
63 }));
64 }
65 }
66 }
67
68 pub fn pop_min(&mut self) -> Option<PqEntry> {
70 while let Some(Reverse(entry)) = self.heap.pop() {
71 if let Some(&cur) = self.current.get(&entry.key) {
72 if cur == entry.priority {
73 self.current.remove(&entry.key);
74 return Some(entry);
75 }
76 }
78 }
79 None
80 }
81
82 pub fn peek_min(&self) -> Option<(&str, i64)> {
84 self.current
85 .iter()
86 .min_by_key(|(_, &p)| p)
87 .map(|(k, &p)| (k.as_str(), p))
88 }
89
90 pub fn len(&self) -> usize {
92 self.current.len()
93 }
94
95 pub fn is_empty(&self) -> bool {
97 self.current.is_empty()
98 }
99
100 pub fn contains(&self, key: &str) -> bool {
102 self.current.contains_key(key)
103 }
104
105 pub fn priority_of(&self, key: &str) -> Option<i64> {
107 self.current.get(key).copied()
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_empty() {
117 let pq = new_priority_queue_ext();
119 assert!(pq.is_empty());
120 assert_eq!(pq.len(), 0);
121 }
122
123 #[test]
124 fn test_insert_and_pop() {
125 let mut pq = new_priority_queue_ext();
127 pq.insert("a", 10);
128 let e = pq.pop_min().expect("should succeed");
129 assert_eq!(e.key, "a");
130 assert_eq!(e.priority, 10);
131 }
132
133 #[test]
134 fn test_min_heap_order() {
135 let mut pq = new_priority_queue_ext();
137 pq.insert("c", 30);
138 pq.insert("a", 10);
139 pq.insert("b", 20);
140 let first = pq.pop_min().expect("should succeed");
141 assert_eq!(first.priority, 10);
142 }
143
144 #[test]
145 fn test_decrease_key() {
146 let mut pq = new_priority_queue_ext();
148 pq.insert("a", 50);
149 pq.insert("b", 20);
150 pq.decrease_key("a", 5);
151 let first = pq.pop_min().expect("should succeed");
152 assert_eq!(first.key, "a");
153 assert_eq!(first.priority, 5);
154 }
155
156 #[test]
157 fn test_contains() {
158 let mut pq = new_priority_queue_ext();
160 pq.insert("x", 1);
161 assert!(pq.contains("x"));
162 assert!(!pq.contains("y"));
163 }
164
165 #[test]
166 fn test_priority_of() {
167 let mut pq = new_priority_queue_ext();
169 pq.insert("z", 42);
170 assert_eq!(pq.priority_of("z"), Some(42));
171 assert_eq!(pq.priority_of("missing"), None);
172 }
173
174 #[test]
175 fn test_pop_removes_from_len() {
176 let mut pq = new_priority_queue_ext();
178 pq.insert("a", 1);
179 pq.insert("b", 2);
180 assert_eq!(pq.len(), 2);
181 pq.pop_min();
182 assert_eq!(pq.len(), 1);
183 }
184
185 #[test]
186 fn test_decrease_key_no_increase() {
187 let mut pq = new_priority_queue_ext();
189 pq.insert("a", 10);
190 pq.decrease_key("a", 20);
191 assert_eq!(pq.priority_of("a"), Some(10));
192 }
193}