nautilus_persistence/backend/
binary_heap.rs1#![deny(unsafe_op_in_unsafe_fn)]
23#![allow(
24 clippy::multiple_unsafe_ops_per_block,
25 reason = "vendored heap chains pointer ops; SAFETY comments justify each block"
26)]
27
28use std::{
29 fmt,
30 mem::{ManuallyDrop, swap},
31 ops::{Deref, DerefMut},
32 ptr,
33};
34
35use super::compare::Compare;
36
37pub struct BinaryHeap<T, C> {
42 data: Vec<T>,
43 cmp: C,
44}
45
46impl<T, C: Compare<T>> BinaryHeap<T, C> {
47 pub fn from_vec_cmp(vec: Vec<T>, cmp: C) -> Self {
49 let mut heap = Self { data: vec, cmp };
50 if !heap.data.is_empty() {
51 heap.rebuild();
52 }
53 heap
54 }
55
56 pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T, C>> {
59 if self.is_empty() {
60 None
61 } else {
62 Some(PeekMut {
63 heap: self,
64 sift: false,
65 })
66 }
67 }
68
69 pub fn pop(&mut self) -> Option<T> {
72 self.data.pop().map(|mut item| {
73 if !self.is_empty() {
74 swap(&mut item, &mut self.data[0]);
75 unsafe { self.sift_down_to_bottom(0) };
77 }
78 item
79 })
80 }
81
82 pub fn push(&mut self, item: T) {
84 let old_len = self.len();
85 self.data.push(item);
86 unsafe { self.sift_up(0, old_len) };
89 }
90
91 unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize {
97 let mut hole = unsafe { Hole::new(&mut self.data, pos) };
99
100 while hole.pos() > start {
101 let parent = (hole.pos() - 1) / 2;
102
103 if self
106 .cmp
107 .compares_le(hole.element(), unsafe { hole.get(parent) })
108 {
109 break;
110 }
111
112 unsafe { hole.move_to(parent) };
114 }
115
116 hole.pos()
117 }
118
119 unsafe fn sift_down_range(&mut self, pos: usize, end: usize) {
125 let mut hole = unsafe { Hole::new(&mut self.data, pos) };
127 let mut child = 2 * hole.pos() + 1;
128
129 while child <= end.saturating_sub(2) {
130 child +=
133 usize::from(unsafe { self.cmp.compares_le(hole.get(child), hole.get(child + 1)) });
134
135 if self
137 .cmp
138 .compares_ge(hole.element(), unsafe { hole.get(child) })
139 {
140 return;
141 }
142
143 unsafe { hole.move_to(child) };
145 child = 2 * hole.pos() + 1;
146 }
147
148 if child == end - 1
150 && self
151 .cmp
152 .compares_lt(hole.element(), unsafe { hole.get(child) })
153 {
154 unsafe { hole.move_to(child) };
155 }
156 }
157
158 unsafe fn sift_down(&mut self, pos: usize) {
164 let len = self.len();
165 unsafe { self.sift_down_range(pos, len) };
167 }
168
169 unsafe fn sift_down_to_bottom(&mut self, mut pos: usize) {
176 let end = self.len();
177 let start = pos;
178
179 let mut hole = unsafe { Hole::new(&mut self.data, pos) };
181 let mut child = 2 * hole.pos() + 1;
182
183 while child <= end.saturating_sub(2) {
184 child +=
187 usize::from(unsafe { self.cmp.compares_le(hole.get(child), hole.get(child + 1)) });
188
189 unsafe { hole.move_to(child) };
191 child = 2 * hole.pos() + 1;
192 }
193
194 if child == end - 1 {
195 unsafe { hole.move_to(child) };
197 }
198 pos = hole.pos();
199 drop(hole);
200
201 unsafe { self.sift_up(start, pos) };
203 }
204
205 fn rebuild(&mut self) {
207 let mut n = self.len() / 2;
208 while n > 0 {
209 n -= 1;
210 unsafe { self.sift_down(n) };
212 }
213 }
214}
215
216impl<T, C> BinaryHeap<T, C> {
217 #[must_use]
219 pub fn len(&self) -> usize {
220 self.data.len()
221 }
222
223 #[must_use]
225 pub fn is_empty(&self) -> bool {
226 self.len() == 0
227 }
228
229 pub fn clear(&mut self) {
231 self.data.clear();
232 }
233}
234
235impl<T: fmt::Debug, C> fmt::Debug for BinaryHeap<T, C> {
236 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237 f.debug_list().entries(self.data.iter()).finish()
238 }
239}
240
241impl<T: Clone, C: Clone> Clone for BinaryHeap<T, C> {
242 fn clone(&self) -> Self {
243 Self {
244 data: self.data.clone(),
245 cmp: self.cmp.clone(),
246 }
247 }
248}
249
250pub struct PeekMut<'a, T: 'a, C: 'a + Compare<T>> {
253 heap: &'a mut BinaryHeap<T, C>,
254 sift: bool,
255}
256
257impl<T: fmt::Debug, C: Compare<T>> fmt::Debug for PeekMut<'_, T, C> {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish()
260 }
261}
262
263impl<T, C: Compare<T>> Drop for PeekMut<'_, T, C> {
264 fn drop(&mut self) {
265 if self.sift {
266 unsafe { self.heap.sift_down(0) };
268 }
269 }
270}
271
272impl<T, C: Compare<T>> Deref for PeekMut<'_, T, C> {
273 type Target = T;
274 fn deref(&self) -> &T {
275 debug_assert!(!self.heap.is_empty());
276 unsafe { self.heap.data.get_unchecked(0) }
278 }
279}
280
281impl<T, C: Compare<T>> DerefMut for PeekMut<'_, T, C> {
282 fn deref_mut(&mut self) -> &mut T {
283 debug_assert!(!self.heap.is_empty());
284 self.sift = true;
285 unsafe { self.heap.data.get_unchecked_mut(0) }
287 }
288}
289
290impl<T, C: Compare<T>> PeekMut<'_, T, C> {
291 #[must_use]
298 pub fn pop(mut this: Self) -> T {
299 let value = this.heap.pop().unwrap();
300 this.sift = false;
301 value
302 }
303}
304
305struct Hole<'a, T: 'a> {
308 data: &'a mut [T],
309 elt: ManuallyDrop<T>,
310 pos: usize,
311}
312
313impl<'a, T> Hole<'a, T> {
314 #[inline]
320 unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
321 debug_assert!(pos < data.len());
322 let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
324 Hole {
325 data,
326 elt: ManuallyDrop::new(elt),
327 pos,
328 }
329 }
330
331 #[inline]
332 fn pos(&self) -> usize {
333 self.pos
334 }
335
336 #[inline]
338 fn element(&self) -> &T {
339 &self.elt
340 }
341
342 #[inline]
348 unsafe fn get(&self, index: usize) -> &T {
349 debug_assert_ne!(index, self.pos);
350 debug_assert!(index < self.data.len());
351 unsafe { self.data.get_unchecked(index) }
352 }
353
354 #[inline]
360 unsafe fn move_to(&mut self, index: usize) {
361 debug_assert_ne!(index, self.pos);
362 debug_assert!(index < self.data.len());
363 unsafe {
365 let ptr = self.data.as_mut_ptr();
366 let index_ptr: *const _ = ptr.add(index);
367 let hole_ptr = ptr.add(self.pos);
368 ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
369 }
370 self.pos = index;
371 }
372}
373
374impl<T> Drop for Hole<'_, T> {
375 #[inline]
376 fn drop(&mut self) {
377 unsafe {
380 let pos = self.pos;
381 ptr::copy_nonoverlapping(
382 ptr::from_ref(&*self.elt),
383 self.data.get_unchecked_mut(pos),
384 1,
385 );
386 }
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use std::cmp::Ordering;
393
394 use rstest::rstest;
395
396 use super::*;
397
398 struct MaxComparator;
399
400 impl Compare<i32> for MaxComparator {
401 fn compare(&self, a: &i32, b: &i32) -> Ordering {
402 a.cmp(b)
403 }
404 }
405
406 struct MinComparator;
407
408 impl Compare<i32> for MinComparator {
409 fn compare(&self, a: &i32, b: &i32) -> Ordering {
410 b.cmp(a)
411 }
412 }
413
414 #[rstest]
415 fn test_max_heap() {
416 let mut heap = BinaryHeap::from_vec_cmp(vec![], MaxComparator);
417 heap.push(3);
418 heap.push(1);
419 heap.push(5);
420
421 assert_eq!(heap.pop(), Some(5));
422 assert_eq!(heap.pop(), Some(3));
423 assert_eq!(heap.pop(), Some(1));
424 assert_eq!(heap.pop(), None);
425 }
426
427 #[rstest]
428 fn test_min_heap() {
429 let mut heap = BinaryHeap::from_vec_cmp(vec![], MinComparator);
430 heap.push(3);
431 heap.push(1);
432 heap.push(5);
433
434 assert_eq!(heap.pop(), Some(1));
435 assert_eq!(heap.pop(), Some(3));
436 assert_eq!(heap.pop(), Some(5));
437 assert_eq!(heap.pop(), None);
438 }
439
440 #[rstest]
441 fn test_peek_mut() {
442 let mut heap = BinaryHeap::from_vec_cmp(vec![1, 5, 2], MaxComparator);
443
444 if let Some(mut val) = heap.peek_mut() {
445 *val = 0;
446 }
447
448 assert_eq!(heap.pop(), Some(2));
449 }
450
451 #[rstest]
452 fn test_peek_mut_pop() {
453 let mut heap = BinaryHeap::from_vec_cmp(vec![1, 5, 2], MaxComparator);
454
455 if let Some(val) = heap.peek_mut() {
456 let popped = PeekMut::pop(val);
457 assert_eq!(popped, 5);
458 }
459
460 assert_eq!(heap.pop(), Some(2));
461 assert_eq!(heap.pop(), Some(1));
462 }
463
464 #[rstest]
465 fn test_clear() {
466 let mut heap = BinaryHeap::from_vec_cmp(vec![1, 2, 3], MaxComparator);
467 assert!(!heap.is_empty());
468
469 heap.clear();
470 assert!(heap.is_empty());
471 assert_eq!(heap.len(), 0);
472 }
473
474 #[rstest]
475 fn test_from_vec() {
476 let heap = BinaryHeap::from_vec_cmp(vec![3, 1, 4, 1, 5, 9, 2, 6], MaxComparator);
477 let mut sorted = Vec::new();
478 let mut heap = heap;
479 while let Some(v) = heap.pop() {
480 sorted.push(v);
481 }
482 assert_eq!(sorted, vec![9, 6, 5, 4, 3, 2, 1, 1]);
483 }
484}