gistools/data_structures/flat_queue.rs
1use alloc::vec::Vec;
2
3/// # FlatQueue
4///
5/// ## Description
6/// A priority queue implemented using a binary heap.
7///
8/// A port from the [flatqueue](https://github.com/mourner/flatqueue) code.
9///
10/// ## Usage
11///
12/// ```rust
13/// use gistools::data_structures::FlatQueue;
14///
15/// let mut q = FlatQueue::new();
16/// q.push(1, 1.0);
17/// q.push(3, 3.0);
18/// q.push(2, 2.0);
19/// assert_eq!(q.pop(), Some(1));
20/// assert_eq!(q.pop(), Some(2));
21/// assert_eq!(q.pop(), Some(3));
22/// assert_eq!(q.pop(), None);
23/// ```
24pub struct FlatQueue<T> {
25 ids: Vec<T>,
26 values: Vec<f64>, // priority
27 len: usize,
28}
29impl<T: Clone> Default for FlatQueue<T> {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34impl<T: Clone> FlatQueue<T> {
35 /// Creates a new empty queue.
36 pub fn new() -> Self {
37 Self { ids: Vec::new(), values: Vec::new(), len: 0 }
38 }
39
40 /// Returns the number of items.
41 pub fn len(&self) -> usize {
42 self.len
43 }
44
45 /// Returns whether the queue is empty.
46 pub fn is_empty(&self) -> bool {
47 self.len == 0
48 }
49
50 /// Clears all items from the queue.
51 pub fn clear(&mut self) {
52 self.len = 0;
53 }
54
55 /// Adds `item` to the queue with the specified `priority`.
56 ///
57 /// `priority` must be a number. Items are sorted and returned from low to high priority. Multiple items
58 /// with the same priority value can be added to the queue, but there is no guaranteed order between these items.
59 ///
60 /// ## Parameters
61 /// - `item`: the item to add
62 /// - `priority`: the priority of the item
63 pub fn push(&mut self, item: T, priority: f64) {
64 let mut pos = self.len;
65 self.len += 1;
66
67 if self.ids.len() < self.len {
68 self.ids.resize(self.len, item.clone());
69 self.values.resize(self.len, priority);
70 }
71
72 while pos > 0 {
73 let parent = (pos - 1) >> 1;
74 let parent_value = self.values[parent];
75 if priority >= parent_value {
76 break;
77 }
78 self.ids[pos] = self.ids[parent].clone();
79 self.values[pos] = parent_value;
80 pos = parent;
81 }
82
83 self.ids[pos] = item;
84 self.values[pos] = priority;
85 }
86
87 /// Removes and returns the item from the head of this queue, which is one of
88 /// the items with the lowest priority. If this queue is empty, returns `undefined`.
89 ///
90 /// ## Returns
91 /// the item from the head of this queue
92 pub fn pop(&mut self) -> Option<T> {
93 if self.len == 0 {
94 return None;
95 }
96
97 let top = self.ids[0].clone();
98 self.len -= 1;
99
100 if self.len > 0 {
101 let id = self.ids[self.len].clone();
102 let value = self.values[self.len];
103 let mut pos = 0;
104 let half_len = self.len >> 1;
105
106 while pos < half_len {
107 let left = (pos << 1) + 1;
108 let right = left + 1;
109 let mut child = left;
110 if right < self.len && self.values[right] < self.values[left] {
111 child = right;
112 }
113 if self.values[child] >= value {
114 break;
115 }
116 self.ids[pos] = self.ids[child].clone();
117 self.values[pos] = self.values[child];
118 pos = child;
119 }
120
121 self.ids[pos] = id;
122 self.values[pos] = value;
123 }
124
125 Some(top)
126 }
127
128 /// Returns the item with the lowest priority without removing it.
129 pub fn peek(&self) -> Option<&T> {
130 if self.len > 0 { Some(&self.ids[0]) } else { None }
131 }
132
133 /// Returns the priority of the lowest-priority item.
134 pub fn peek_value(&self) -> Option<f64> {
135 if self.len > 0 { Some(self.values[0]) } else { None }
136 }
137
138 /// Shrinks underlying arrays to current length.
139 pub fn shrink(&mut self) {
140 self.ids.truncate(self.len);
141 self.values.truncate(self.len);
142 }
143}