Skip to main content

tess2_rust/
priorityq.rs

1// Copyright 2025 Lars Brubaker
2// License: SGI Free Software License B (MIT-compatible)
3//
4// Port of libtess2 priorityq.c/h
5//
6// A two-phase priority queue:
7//   Phase 1 (pre-init): inserts go into a sorted key array.
8//   Phase 2 (post-init): inserts go directly into a min-heap.
9// Deletion is supported via handles.
10//
11// In the original C, PQkey = void* (TESSvertex*).
12// Here, PQkey = u32 (VertIdx). INVALID_KEY = u32::MAX means "empty/null".
13
14use crate::mesh::INVALID;
15
16pub const INVALID_HANDLE: i32 = 0x0fff_ffff;
17
18/// A heap-based priority queue (used after initialization).
19struct Heap {
20    /// nodes[1..=size] are active; nodes[0] unused. Stores handle indices.
21    nodes: Vec<i32>,
22    /// handles[handle] = (key, node_pos)
23    handles: Vec<(u32, i32)>,
24    size: usize,
25    max: usize,
26    free_list: i32,
27    initialized: bool,
28    /// Comparison function: returns true iff key1 <= key2
29    leq: fn(u32, u32) -> bool,
30}
31
32impl Heap {
33    fn new(size: usize, leq: fn(u32, u32) -> bool) -> Self {
34        let mut nodes = vec![0i32; size + 2];
35        let mut handles = vec![(INVALID, 0i32); size + 2];
36        // nodes[1] = 1 so that minimum() returns NULL when empty
37        nodes[1] = 1;
38        handles[1] = (INVALID, 1);
39        Heap {
40            nodes,
41            handles,
42            size: 0,
43            max: size,
44            free_list: 0,
45            initialized: false,
46            leq,
47        }
48    }
49
50    #[inline]
51    fn key_of(&self, handle: i32) -> u32 {
52        self.handles[handle as usize].0
53    }
54
55    fn float_down(&mut self, mut curr: usize) {
56        let h_curr = self.nodes[curr];
57        loop {
58            let mut child = curr << 1;
59            if child < self.size {
60                let child_key = self.key_of(self.nodes[child + 1]);
61                let child_key0 = self.key_of(self.nodes[child]);
62                if (self.leq)(child_key, child_key0) {
63                    child += 1;
64                }
65            }
66            let h_child = self.nodes[child];
67            if child > self.size || (self.leq)(self.key_of(h_curr), self.key_of(h_child)) {
68                self.nodes[curr] = h_curr;
69                self.handles[h_curr as usize].1 = curr as i32;
70                break;
71            }
72            self.nodes[curr] = h_child;
73            self.handles[h_child as usize].1 = curr as i32;
74            curr = child;
75        }
76    }
77
78    fn float_up(&mut self, mut curr: usize) {
79        let h_curr = self.nodes[curr];
80        loop {
81            let parent = curr >> 1;
82            let h_parent = self.nodes[parent];
83            if parent == 0 || (self.leq)(self.key_of(h_parent), self.key_of(h_curr)) {
84                self.nodes[curr] = h_curr;
85                self.handles[h_curr as usize].1 = curr as i32;
86                break;
87            }
88            self.nodes[curr] = h_parent;
89            self.handles[h_parent as usize].1 = curr as i32;
90            curr = parent;
91        }
92    }
93
94    fn init(&mut self) {
95        for i in (1..=self.size).rev() {
96            self.float_down(i);
97        }
98        self.initialized = true;
99    }
100
101    fn insert(&mut self, key: u32) -> i32 {
102        self.size += 1;
103        let curr = self.size;
104
105        // Grow if needed
106        if curr * 2 > self.max {
107            self.max <<= 1;
108            self.nodes.resize(self.max + 2, 0);
109            self.handles.resize(self.max + 2, (INVALID, 0));
110        }
111
112        let free_handle = if self.free_list == 0 {
113            curr as i32
114        } else {
115            let f = self.free_list;
116            self.free_list = self.handles[f as usize].1;
117            f
118        };
119
120        self.nodes[curr] = free_handle;
121        self.handles[free_handle as usize] = (key, curr as i32);
122
123        if self.initialized {
124            self.float_up(curr);
125        }
126
127        free_handle
128    }
129
130    fn extract_min(&mut self) -> u32 {
131        let h_min = self.nodes[1];
132        let min_key = self.handles[h_min as usize].0;
133
134        if self.size > 0 {
135            self.nodes[1] = self.nodes[self.size];
136            self.handles[self.nodes[1] as usize].1 = 1;
137
138            self.handles[h_min as usize].0 = INVALID;
139            self.handles[h_min as usize].1 = self.free_list;
140            self.free_list = h_min;
141
142            self.size -= 1;
143            if self.size > 0 {
144                self.float_down(1);
145            }
146        }
147
148        min_key
149    }
150
151    fn delete(&mut self, h_curr: i32) {
152        debug_assert!(self.handles[h_curr as usize].0 != INVALID);
153        let curr = self.handles[h_curr as usize].1 as usize;
154
155        self.nodes[curr] = self.nodes[self.size];
156        self.handles[self.nodes[curr] as usize].1 = curr as i32;
157
158        if curr <= self.size {
159            self.size -= 1;
160            if curr <= 1 {
161                self.float_down(curr);
162            } else {
163                let parent_key = self.key_of(self.nodes[curr >> 1]);
164                let curr_key = self.key_of(self.nodes[curr]);
165                if (self.leq)(parent_key, curr_key) {
166                    self.float_down(curr);
167                } else {
168                    self.float_up(curr);
169                }
170            }
171        } else {
172            self.size -= 1;
173        }
174
175        self.handles[h_curr as usize].0 = INVALID;
176        self.handles[h_curr as usize].1 = self.free_list;
177        self.free_list = h_curr;
178    }
179
180    #[inline]
181    fn minimum(&self) -> u32 {
182        self.handles[self.nodes[1] as usize].0
183    }
184
185    #[inline]
186    fn is_empty(&self) -> bool {
187        self.size == 0
188    }
189}
190
191/// The combined priority queue (sort-array + heap).
192pub struct PriorityQ {
193    heap: Heap,
194    /// Pre-init key storage
195    keys: Vec<u32>,
196    /// Sorted indirect pointers into keys (indices)
197    order: Vec<usize>,
198    size: usize,
199    max: usize,
200    initialized: bool,
201    leq: fn(u32, u32) -> bool,
202}
203
204impl PriorityQ {
205    pub fn new(size: usize, leq: fn(u32, u32) -> bool) -> Self {
206        PriorityQ {
207            heap: Heap::new(size, leq),
208            keys: Vec::with_capacity(size),
209            order: Vec::new(),
210            size: 0,
211            max: size,
212            initialized: false,
213            leq,
214        }
215    }
216
217    /// Initialize the sort-array phase.
218    /// Must be called before extract_min/minimum/delete (but after all pre-init inserts).
219    pub fn init(&mut self) -> bool {
220        // Create indirect pointer array
221        self.order = (0..self.size).collect();
222
223        // Sort in descending order (so we pop from the end in ascending order)
224        let keys = &self.keys;
225        let leq = self.leq;
226        self.order.sort_unstable_by(|&a, &b| {
227            // descending: if keys[a] <= keys[b], b comes first
228            if (leq)(keys[a], keys[b]) {
229                std::cmp::Ordering::Greater
230            } else {
231                std::cmp::Ordering::Less
232            }
233        });
234
235        self.max = self.size;
236        self.initialized = true;
237        self.heap.init();
238        true
239    }
240
241    /// Insert a key. Returns a handle.
242    /// Negative handles are for the sort-array; non-negative for the heap.
243    pub fn insert(&mut self, key: u32) -> i32 {
244        if self.initialized {
245            return self.heap.insert(key);
246        }
247
248        let curr = self.size;
249        self.size += 1;
250
251        if self.size > self.max {
252            self.max <<= 1;
253        }
254
255        if curr >= self.keys.len() {
256            self.keys.push(key);
257        } else {
258            self.keys[curr] = key;
259        }
260
261        // Negative handles index the sort array
262        -(curr as i32 + 1)
263    }
264
265    /// Extract the minimum key.
266    pub fn extract_min(&mut self) -> u32 {
267        if self.size == 0 {
268            return self.heap.extract_min();
269        }
270
271        let sort_min = self.keys[self.order[self.size - 1]];
272
273        if !self.heap.is_empty() {
274            let heap_min = self.heap.minimum();
275            if (self.leq)(heap_min, sort_min) {
276                return self.heap.extract_min();
277            }
278        }
279
280        // Pop from sort array, skipping deleted (INVALID) entries
281        loop {
282            self.size -= 1;
283            if self.size == 0 || self.keys[self.order[self.size - 1]] != INVALID {
284                break;
285            }
286        }
287
288        sort_min
289    }
290
291    /// Peek at the minimum key without extracting.
292    pub fn minimum(&self) -> u32 {
293        if self.size == 0 {
294            return self.heap.minimum();
295        }
296
297        let sort_min = self.keys[self.order[self.size - 1]];
298
299        if !self.heap.is_empty() {
300            let heap_min = self.heap.minimum();
301            if (self.leq)(heap_min, sort_min) {
302                return heap_min;
303            }
304        }
305
306        sort_min
307    }
308
309    /// Returns true if the queue is empty.
310    pub fn is_empty(&self) -> bool {
311        self.size == 0 && self.heap.is_empty()
312    }
313
314    /// Delete the key with the given handle.
315    pub fn delete(&mut self, handle: i32) {
316        if handle >= 0 {
317            self.heap.delete(handle);
318            return;
319        }
320
321        let curr = (-(handle + 1)) as usize;
322        debug_assert!(curr < self.keys.len() && self.keys[curr] != INVALID);
323        self.keys[curr] = INVALID;
324
325        // Trim trailing deleted entries
326        while self.size > 0 && self.keys[self.order[self.size - 1]] == INVALID {
327            self.size -= 1;
328        }
329    }
330}
331
332#[cfg(test)]
333mod tests {
334    use super::*;
335    use crate::geom::vert_leq;
336
337    fn leq_u32(a: u32, b: u32) -> bool {
338        a <= b
339    }
340
341    #[test]
342    fn heap_basic() {
343        let mut h = Heap::new(8, leq_u32);
344        h.init();
345        h.insert(3);
346        h.insert(1);
347        h.insert(2);
348        assert_eq!(h.minimum(), 1);
349        assert_eq!(h.extract_min(), 1);
350        assert_eq!(h.extract_min(), 2);
351        assert_eq!(h.extract_min(), 3);
352        assert!(h.is_empty());
353    }
354
355    #[test]
356    fn pq_pre_init_insert_then_extract() {
357        let mut pq = PriorityQ::new(8, leq_u32);
358        pq.insert(5);
359        pq.insert(2);
360        pq.insert(8);
361        pq.insert(1);
362        pq.init();
363
364        assert_eq!(pq.extract_min(), 1);
365        assert_eq!(pq.extract_min(), 2);
366        assert_eq!(pq.extract_min(), 5);
367        assert_eq!(pq.extract_min(), 8);
368        assert!(pq.is_empty());
369    }
370
371    #[test]
372    fn pq_delete_from_sort_array() {
373        let mut pq = PriorityQ::new(8, leq_u32);
374        let h1 = pq.insert(10);
375        let _h2 = pq.insert(5);
376        let h3 = pq.insert(7);
377        pq.init();
378        pq.delete(h1);
379        assert_eq!(pq.extract_min(), 5);
380        assert_eq!(pq.extract_min(), 7);
381        assert!(pq.is_empty());
382    }
383
384    #[test]
385    fn pq_post_init_insert() {
386        let mut pq = PriorityQ::new(4, leq_u32);
387        pq.insert(3);
388        pq.init();
389        pq.insert(1); // goes into heap
390        assert_eq!(pq.minimum(), 1);
391        assert_eq!(pq.extract_min(), 1);
392        assert_eq!(pq.extract_min(), 3);
393    }
394}