Skip to main content

fixed_heap/
lib.rs

1//! A fixed-size heap structure with manually provided stateful comparison function.
2#![doc(html_root_url = "https://docs.rs/fixed_heap")]
3#![crate_name = "fixed_heap"]
4#![warn(
5    missing_debug_implementations,
6    trivial_casts,
7    trivial_numeric_casts,
8    unused_lifetimes,
9    unused_import_braces,
10    clippy::shadow_unrelated
11)]
12#![deny(missing_docs, unsafe_op_in_unsafe_fn)]
13#![cfg_attr(all(feature = "unstable"), feature(slice_swap_unchecked))]
14#![cfg_attr(not(test), no_std)]
15
16use core::{
17    fmt::{Debug, Formatter, Result},
18    iter::FusedIterator,
19    mem::{self, ManuallyDrop, MaybeUninit},
20    slice::{Iter, IterMut},
21};
22
23/// A fixed-size heap structure with manually provided stateful comparison function.
24pub struct FixedHeap<T, const N: usize> {
25    high: usize,
26    data: [MaybeUninit<T>; N],
27}
28
29impl<T, const N: usize> FixedHeap<T, N> {
30    /// Creates a new empty `FixedHeap`.
31    ///
32    /// Passing in a `comparer` and `state` is deferred so as to not hold a reference
33    /// preventing mutation of other parts of `state` that do not affect the heap order.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// # use fixed_heap::*;
39    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
40    /// ```
41    pub fn new() -> Self {
42        Self {
43            high: 0,
44            data: [const { MaybeUninit::uninit() }; N],
45        }
46    }
47
48    /// Copies `slice` into the backing storage, ignoring heap properties.
49    ///
50    /// Caution: this will not preserve the heap property of the structure
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// # use fixed_heap::*;
56    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
57    /// let array = [4; 12];
58    /// heap.copy_from_slice(&array[2..8]);
59    /// assert_eq!(heap.len(), 6);
60    /// ```
61    pub fn copy_from_slice(&mut self, slice: &[T])
62    where
63        T: Copy,
64    {
65        assert!(slice.len() <= N);
66        self.high = slice.len();
67        self.as_slice_mut().copy_from_slice(slice);
68    }
69
70    /// Returns a reference to the highest priority element.
71    ///
72    /// # Returns
73    ///
74    /// `None` if there are no elements in the heap.
75    ///
76    /// `Some(elem)` if there was an element. `elem` is higher priority than all other elements.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// # use fixed_heap::*;
82    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
83    /// assert_eq!(heap.add_last(1), None);
84    /// assert_eq!(heap.peek(), Some(&1));
85    /// ```
86    #[inline(always)]
87    pub fn peek(&self) -> Option<&T> {
88        self.peek_at(0)
89    }
90
91    /// Returns a reference to the element at `index`.
92    ///
93    /// # Returns
94    ///
95    /// `None` if there is no element at `index`.
96    ///
97    /// `Some(elem)` if there was an element.
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// # use fixed_heap::*;
103    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
104    /// assert_eq!(heap.add_last(1), None);
105    /// assert_eq!(heap.add_last(2), None);
106    /// assert_eq!(heap.peek_at(1), Some(&2));
107    /// ```
108    #[inline(always)]
109    pub fn peek_at(&self, index: usize) -> Option<&T> {
110        // # Safety
111        // If `index` is below `high` then `data[index]` is initialized.
112        if index < self.high {
113            Some(unsafe { self.data.get_unchecked(index).assume_init_ref() })
114        } else {
115            None
116        }
117    }
118
119    /// Tries to add `value` to the end, ignoring heap properties.
120    ///
121    /// Caution: this will not preserve the heap property of the structure
122    ///
123    /// # Returns
124    ///
125    /// `None` if there was spare capacity to accommodate `value`
126    ///
127    /// `Some(value)` if there was no spare capacity
128    ///
129    /// # Time Complexity
130    ///
131    /// O(1)
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// # use fixed_heap::*;
137    /// let mut heap: FixedHeap<i32, 1> = FixedHeap::new();
138    /// assert_eq!(heap.add_last(1), None);
139    /// assert_eq!(heap.add_last(2), Some(2));
140    /// ```
141    pub fn add_last(&mut self, value: T) -> Option<T> {
142        if self.high == N {
143            // Not enough space to add it
144            Some(value)
145        } else {
146            // There's enough space to add it
147            // # Safety
148            // `high` is guaranteed to be a valid index here because it is less than `N`
149            unsafe {
150                *self.data.get_unchecked_mut(self.high) = MaybeUninit::new(value);
151            }
152            self.high += 1;
153            None
154        }
155    }
156
157    /// Removes and returns the element at `index`, ignoring heap properties.
158    /// Use `pop_at` instead to preserve heap properties.
159    ///
160    /// Caution: this will not preserve the heap property of the structure
161    ///
162    /// # Returns
163    ///
164    /// `None` if there's no element at `index`.
165    ///
166    /// `Some(elem)` if there was an element at `index`.
167    ///
168    /// # Time Complexity
169    ///
170    /// O(1)
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// # use fixed_heap::*;
176    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
177    /// assert_eq!(heap.swap_remove(0), None); // []
178    /// assert_eq!(heap.add_last(1), None); // [1]
179    /// assert_eq!(heap.swap_remove(1), None); // [1]
180    /// assert_eq!(heap.add_last(2), None); // [1, 2]
181    /// assert_eq!(heap.swap_remove(0), Some(1)); // [2]
182    /// assert_eq!(heap.swap_remove(0), Some(2)); // []
183    /// ```
184    pub fn swap_remove(&mut self, index: usize) -> Option<T> {
185        if index < self.high {
186            self.high -= 1;
187
188            // # Safety
189            // `data[index]` holds an initialized value because `index` is less than `high`
190            // We just copy it because we're about to overwrite it anyways
191            let removed_node = unsafe { self.data.get_unchecked(index).assume_init_read() };
192            // We can also just copy the last element because the last index will now be treated as uninit
193            unsafe {
194                *self.data.get_unchecked_mut(index) =
195                    MaybeUninit::new(self.data.get_unchecked(self.high).assume_init_read());
196            }
197
198            Some(removed_node)
199        } else {
200            None
201        }
202    }
203
204    /// Tries to push `value` onto the heap, calling `comparer` with `state` to determine ordering.
205    ///
206    /// `comparer` should return true if its first argument is strictly higher priority than the second.
207    /// It is technically permitted to return true when given elements of equal priority,
208    /// although it is recommended to return false in those cases to avoid swaps for performance reasons.
209    /// A possible use case for returning true when equal is to have newly added elements take priority over older ones.
210    ///
211    /// Use `state` to pass in another datastructure in order to sort keys by associated values.
212    ///
213    /// The same comparer should always be used for `push` and `pop`, and `state` should be stable.
214    ///
215    /// If `comparer` judges that a particular element is higher priority than another one,
216    /// it is expected that that remains true for as long as those elements are in this heap.
217    ///
218    /// # Returns
219    ///
220    /// `None` if there was spare capacity to accommodate `value`
221    ///
222    /// `Some(elem)` if the lowest priority element `elem` had to be evicted to accommodate `value`.
223    /// `elem` may be `value` if all the elements already present were higher priority than `value`.
224    ///
225    /// # Time Complexity
226    ///
227    /// If there was spare capacity, average time complexity O(1) and worst case O(log N)
228    ///
229    /// If the heap was full, average time complexity O(log N) and worst case O(N)
230    /// It is recommended to avoid letting the heap reach capacity.
231    ///
232    /// # Examples
233    ///
234    /// ```
235    /// # use fixed_heap::*;
236    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
237    /// let comparer = |a: &i32, b: &i32, _: &()| a > b;
238    /// heap.push(1, &comparer, &());
239    /// ```
240    ///
241    /// With keys into another struct:
242    /// ```
243    /// # use fixed_heap::*;
244    /// let mut heap: FixedHeap<usize, 16> = FixedHeap::new();
245    /// let comparer = |a: &usize, b: &usize, state: &[i32; 4]| state[*a] > state[*b];
246    /// let state = [1, 3, 1, 2];
247    /// heap.push(0, &comparer, &state);
248    /// ```
249    pub fn push<S, F>(&mut self, value: T, comparer: &F, state: &S) -> Option<T>
250    where
251        F: Fn(&T, &T, &S) -> bool,
252    {
253        let mut result = None;
254        let mut node_index = self.high;
255        if let Some(value) = self.add_last(value) {
256            // There was no space for the value. Let's try to evict something.
257            if N == 0 {
258                // Trivial special case to avoid invalid array access
259                return Some(value);
260            } else if self.high == N {
261                // Slow path, replaces smallest element. Avoid if possible.
262                // # Safety
263                // All indexes are initialized because the heap is full
264                let mut smallest_index = N >> 1;
265                for index in N >> 1..N {
266                    let node = unsafe { self.data.get_unchecked(index).assume_init_ref() };
267                    let smallest =
268                        unsafe { self.data.get_unchecked(smallest_index).assume_init_ref() };
269                    if comparer(smallest, node, state) {
270                        smallest_index = index;
271                    }
272                }
273                let smallest = unsafe { self.data.get_unchecked(smallest_index).assume_init_ref() };
274                if comparer(&value, smallest, state) {
275                    let replaced = mem::replace(
276                        unsafe { self.data.get_unchecked_mut(smallest_index) },
277                        MaybeUninit::new(value),
278                    );
279                    node_index = smallest_index;
280                    result = Some(unsafe { replaced.assume_init() });
281                } else {
282                    return Some(value);
283                }
284            }
285        }
286
287        while node_index != 0 {
288            let parent_index = (node_index - 1) >> 1;
289            // # Safety
290            // These indices are initialized because they are in `0..high`
291            let node = unsafe { self.data.get_unchecked(node_index).assume_init_ref() };
292            let parent = unsafe { self.data.get_unchecked(parent_index).assume_init_ref() };
293            if !comparer(node, parent, state) {
294                break;
295            }
296
297            #[cfg(feature = "unstable")]
298            unsafe {
299                self.data.swap_unchecked(node_index, parent_index);
300            }
301            #[cfg(not(feature = "unstable"))]
302            self.data.swap(node_index, parent_index);
303
304            node_index = parent_index;
305        }
306
307        result
308    }
309
310    /// Removes and returns the highest priority element, calling `comparer` with `state` to determine ordering.
311    ///
312    /// `comparer` should return true if its first argument is strictly higher priority than the second.
313    /// It is technically permitted to return true when given elements of equal priority,
314    /// although it is recommended to return false in those cases to avoid swaps for performance reasons.
315    /// A possible use case for returning true when equal is to have newly added elements take priority over older ones.
316    ///
317    /// Use `state` to pass in another datastructure in order to sort keys by associated values.
318    ///
319    /// The same comparer should always be used for `push` and `pop`, and `state` should be stable.
320    ///
321    /// If `comparer` judges that a particular element is higher priority than another one,
322    /// it is expected that that remains true for as long as those elements are in this heap.
323    ///
324    /// # Returns
325    ///
326    /// `None` if there are no elements in the heap.
327    ///
328    /// `Some(elem)` if there was an element. `elem` is higher priority than all remaining elements.
329    ///
330    /// # Time Complexity
331    ///
332    /// Average time complexity O(1) and worst case O(log N)
333    ///
334    /// # Examples
335    ///
336    /// ```
337    /// # use fixed_heap::*;
338    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
339    /// let comparer = |a: &i32, b: &i32, _: &()| a > b;
340    /// heap.push(1, &comparer, &());
341    /// assert_eq!(heap.pop(&comparer, &()), Some(1));
342    /// ```
343    ///
344    /// With keys into another struct:
345    /// ```
346    /// # use fixed_heap::*;
347    /// let mut heap: FixedHeap<usize, 16> = FixedHeap::new();
348    /// let comparer = |a: &usize, b: &usize, state: &[i32; 4]| state[*a] > state[*b];
349    /// let state = [1, 3, 1, 2];
350    /// heap.push(1, &comparer, &state);
351    /// assert_eq!(heap.pop(&comparer, &state), Some(1));
352    /// ```
353    pub fn pop<S, F>(&mut self, comparer: &F, state: &S) -> Option<T>
354    where
355        F: Fn(&T, &T, &S) -> bool,
356    {
357        self.pop_at(0, comparer, state)
358    }
359
360    /// Removes and returns the element at index,
361    /// preserving the heap property by calling `comparer` with `state` to determine ordering.
362    ///
363    /// `comparer` should return true if its first argument is strictly higher priority than the second.
364    /// It is technically permitted to return true when given elements of equal priority,
365    /// although it is recommended to return false in those cases to avoid swaps for performance reasons.
366    /// A possible use case for returning true when equal is to have newly added elements take priority over older ones.
367    ///
368    /// Use `state` to pass in another datastructure in order to sort keys by associated values.
369    ///
370    /// The same comparer should always be used for `push` and `pop`, and `state` should be stable.
371    ///
372    /// If `comparer` judges that a particular element is higher priority than another one,
373    /// it is expected that that remains true for as long as those elements are in this heap.
374    ///
375    /// # Returns
376    ///
377    /// `None` if there is no element at `index`.
378    ///
379    /// `Some(elem)` if there was an element.
380    ///
381    /// # Time Complexity
382    ///
383    /// Average time complexity O(1) and worst case O(log N)
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// # use fixed_heap::*;
389    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
390    /// let comparer = |a: &i32, b: &i32, _: &()| a > b;
391    /// heap.push(1, &comparer, &());
392    /// heap.push(2, &comparer, &());
393    /// assert_eq!(heap.pop_at(1, &comparer, &()), Some(1));
394    /// ```
395    ///
396    /// With keys into another struct:
397    /// ```
398    /// # use fixed_heap::*;
399    /// let mut heap: FixedHeap<usize, 16> = FixedHeap::new();
400    /// let comparer = |a: &usize, b: &usize, state: &[i32; 4]| state[*a] > state[*b];
401    /// let state = [1, 3, 1, 2];
402    /// heap.push(1, &comparer, &state);
403    /// heap.push(2, &comparer, &state);
404    /// assert_eq!(heap.pop_at(1, &comparer, &state), Some(2));
405    /// ```
406    pub fn pop_at<S, F>(&mut self, index: usize, comparer: &F, state: &S) -> Option<T>
407    where
408        F: Fn(&T, &T, &S) -> bool,
409    {
410        if let Some(removed_node) = self.swap_remove(index) {
411            // If we removed the last element, swap_remove already decremented high
412            // and no sifting is needed. Sifting here would read a logically-dead slot.
413            if index >= self.high {
414                return Some(removed_node);
415            }
416            let mut node_index: usize = index;
417            loop {
418                let lchild_index = (node_index << 1) + 1;
419                let rchild_index = (node_index << 1) + 2;
420                // # Safety
421                // These indices are initialized because they are in `0..high`
422                let node = unsafe { self.data.get_unchecked(node_index).assume_init_ref() };
423                // Determine which child to sift upwards by comparing
424                let swap = if rchild_index < self.high {
425                    let lchild = unsafe { self.data.get_unchecked(lchild_index).assume_init_ref() };
426                    let rchild = unsafe { self.data.get_unchecked(rchild_index).assume_init_ref() };
427                    match comparer(lchild, rchild, state) {
428                        true => (comparer(lchild, node, state), lchild_index),
429                        false => (comparer(rchild, node, state), rchild_index),
430                    }
431                } else if lchild_index < self.high {
432                    let lchild = unsafe { self.data.get_unchecked(lchild_index).assume_init_ref() };
433                    (comparer(lchild, node, state), lchild_index)
434                } else {
435                    (false, 0)
436                };
437                // Sift upwards if the `compared_index` is higher priority
438                if let (true, compared_index) = swap {
439                    #[cfg(feature = "unstable")]
440                    unsafe {
441                        self.data.swap_unchecked(node_index, compared_index);
442                    }
443                    #[cfg(not(feature = "unstable"))]
444                    self.data.swap(node_index, compared_index);
445
446                    node_index = compared_index;
447                } else {
448                    break;
449                }
450            }
451
452            // If the element did not sift down, it may need to sift up.
453            // The replacement (formerly last) element could be higher priority than its new parent.
454            if node_index == index {
455                while node_index != 0 {
456                    let parent_index = (node_index - 1) >> 1;
457                    let node = unsafe { self.data.get_unchecked(node_index).assume_init_ref() };
458                    let parent = unsafe { self.data.get_unchecked(parent_index).assume_init_ref() };
459                    if !comparer(node, parent, state) {
460                        break;
461                    }
462
463                    #[cfg(feature = "unstable")]
464                    unsafe {
465                        self.data.swap_unchecked(node_index, parent_index);
466                    }
467                    #[cfg(not(feature = "unstable"))]
468                    self.data.swap(node_index, parent_index);
469
470                    node_index = parent_index;
471                }
472            }
473
474            Some(removed_node)
475        } else {
476            None
477        }
478    }
479
480    /// Provides immutable access to the backing array of the heap.
481    #[inline(always)]
482    pub fn as_slice(&self) -> &[T] {
483        unsafe { core::slice::from_raw_parts(self.data.as_ptr() as *const T, self.high) }
484    }
485
486    /// Provides mutable access to the backing array of the heap.
487    /// Caution: you must preserve the heap property of the structure
488    #[inline(always)]
489    pub fn as_slice_mut(&mut self) -> &mut [T] {
490        unsafe { core::slice::from_raw_parts_mut(self.data.as_mut_ptr() as *mut T, self.high) }
491    }
492
493    /// Provides immutable iteration of the heap's elements.
494    /// NOTE: The elements are NOT in the order they'd be popped in!
495    #[inline(always)]
496    pub fn iter(&self) -> Iter<'_, T> {
497        self.as_slice().iter()
498    }
499
500    /// Provides mutable iteration of the heap's elements.
501    /// NOTE: The elements are NOT in the order they'd be popped in!
502    /// Caution: you must preserve the heap property of the structure
503    #[inline(always)]
504    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
505        self.as_slice_mut().iter_mut()
506    }
507
508    /// Returns the number of elements.
509    ///
510    /// # Examples
511    ///
512    /// ```
513    /// # use fixed_heap::*;
514    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
515    /// let comparer = |a: &i32, b: &i32, _: &()| a > b;
516    /// heap.push(1, &comparer, &());
517    /// assert_eq!(heap.len(), 1);
518    /// ```
519    #[inline(always)]
520    pub fn len(&self) -> usize {
521        self.high
522    }
523
524    /// Returns true if there are no elements.
525    ///
526    /// # Examples
527    ///
528    /// ```
529    /// # use fixed_heap::*;
530    /// let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
531    /// let comparer = |a: &i32, b: &i32, _: &()| a > b;
532    /// assert!(heap.is_empty());
533    /// heap.push(1, &comparer, &());
534    /// assert!(!heap.is_empty());
535    /// ```
536    #[inline(always)]
537    pub fn is_empty(&self) -> bool {
538        self.high == 0
539    }
540
541    /// Returns true if there is no free space left.
542    ///
543    /// # Examples
544    ///
545    /// ```
546    /// # use fixed_heap::*;
547    /// let mut heap: FixedHeap<i32, 1> = FixedHeap::new();
548    /// let comparer = |a: &i32, b: &i32, _: &()| a > b;
549    /// assert!(!heap.is_full());
550    /// heap.push(1, &comparer, &());
551    /// assert!(heap.is_full());
552    /// ```
553    #[inline(always)]
554    pub fn is_full(&self) -> bool {
555        self.high == N
556    }
557}
558
559unsafe impl<T: Sync, const N: usize> Sync for FixedHeap<T, N> {}
560unsafe impl<T: Send, const N: usize> Send for FixedHeap<T, N> {}
561
562impl<T, const N: usize> Drop for FixedHeap<T, N> {
563    #[inline(always)]
564    fn drop(&mut self) {
565        for i in 0..self.high {
566            unsafe { self.data.get_unchecked_mut(i).assume_init_drop() };
567        }
568    }
569}
570
571impl<T, const N: usize> Debug for FixedHeap<T, N>
572where
573    T: Debug,
574{
575    fn fmt(&self, f: &mut Formatter) -> Result {
576        f.debug_struct("FixedHeap")
577            .field("high", &self.high)
578            .field("data", &self.as_slice())
579            .finish()
580    }
581}
582
583impl<T, const N: usize> Default for FixedHeap<T, N> {
584    fn default() -> Self {
585        Self::new()
586    }
587}
588
589impl<'a, T: 'a, const N: usize> IntoIterator for &'a FixedHeap<T, N> {
590    type Item = &'a T;
591    type IntoIter = Iter<'a, T>;
592
593    fn into_iter(self) -> Self::IntoIter {
594        self.iter()
595    }
596}
597
598impl<'a, T: 'a, const N: usize> IntoIterator for &'a mut FixedHeap<T, N> {
599    type Item = &'a mut T;
600    type IntoIter = IterMut<'a, T>;
601
602    fn into_iter(self) -> Self::IntoIter {
603        self.iter_mut()
604    }
605}
606
607impl<T, const N: usize> IntoIterator for FixedHeap<T, N> {
608    type Item = T;
609    type IntoIter = IntoIter<T, N>;
610
611    fn into_iter(self) -> Self::IntoIter {
612        IntoIter {
613            next: 0,
614            heap: ManuallyDrop::new(self),
615        }
616    }
617}
618
619/// Ownership transferring iterator
620#[derive(Debug)]
621pub struct IntoIter<T, const N: usize> {
622    next: usize,
623    heap: ManuallyDrop<FixedHeap<T, N>>,
624}
625
626impl<T, const N: usize> Iterator for IntoIter<T, N> {
627    type Item = T;
628
629    fn next(&mut self) -> Option<T> {
630        if self.next < self.heap.high {
631            let index = self.next;
632            self.next += 1;
633            // # Safety
634            // We can hand over this value without modifying the array,
635            // because we manually drop only the remainder of uniterated elements
636            Some(unsafe { self.heap.data.get_unchecked(index).assume_init_read() })
637        } else {
638            None
639        }
640    }
641
642    fn size_hint(&self) -> (usize, Option<usize>) {
643        let size = self.heap.high - self.next;
644        (size, Some(size))
645    }
646}
647
648impl<T, const N: usize> Drop for IntoIter<T, N> {
649    #[inline(always)]
650    fn drop(&mut self) {
651        for i in self.next..self.heap.high {
652            // # Safety
653            // We manually drop only the remainder of uniterated elements
654            unsafe { self.heap.data[i].assume_init_drop() };
655        }
656    }
657}
658
659impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {}
660impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}
661
662#[cfg(test)]
663mod test {
664    use crate::*;
665    use core::cell::RefCell;
666    use rand::{Rng, rngs::ThreadRng};
667
668    #[test]
669    fn test_default() {
670        let heap: FixedHeap<i32, 4> = FixedHeap::default();
671        assert_eq!(&[0; 0], heap.as_slice());
672    }
673
674    #[test]
675    fn test_copy_from_slice() {
676        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
677        heap.copy_from_slice(&[0, 3]);
678        assert_eq!(&[0, 3], heap.as_slice());
679        heap.copy_from_slice(&[]);
680        assert_eq!(&[0; 0], heap.as_slice());
681        heap.copy_from_slice(&[1, 3, 6, 2]);
682        assert_eq!(&[1, 3, 6, 2], heap.as_slice());
683    }
684
685    #[test]
686    fn test_push_peek_pop() {
687        let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
688        let comparer = |a: &i32, b: &i32, _: &()| a > b;
689        assert_eq!(None, heap.peek());
690        assert_eq!(heap.push(1, &comparer, &()), None);
691        assert_eq!(Some(&1), heap.peek());
692        assert_eq!(heap.push(3, &comparer, &()), None);
693        assert_eq!(Some(&3), heap.peek());
694        assert_eq!(heap.push(2, &comparer, &()), None);
695        assert_eq!(Some(&3), heap.peek());
696
697        assert_eq!(Some(3), heap.pop(&comparer, &()));
698        assert_eq!(Some(&2), heap.peek());
699        assert_eq!(Some(2), heap.pop(&comparer, &()));
700        assert_eq!(Some(&1), heap.peek());
701        assert_eq!(Some(1), heap.pop(&comparer, &()));
702        assert_eq!(None, heap.peek());
703        assert_eq!(None, heap.pop(&comparer, &()));
704    }
705
706    #[test]
707    fn test_add_last_swap_remove() {
708        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
709        assert_eq!(heap.add_last(1), None);
710        assert_eq!(heap.add_last(2), None);
711        assert_eq!(heap.add_last(4), None);
712        assert_eq!(heap.add_last(3), None);
713        assert_eq!(heap.add_last(5), Some(5));
714
715        assert_eq!(Some(1), heap.swap_remove(0));
716        assert_eq!(Some(3), heap.swap_remove(0));
717        assert_eq!(Some(4), heap.swap_remove(0));
718        assert_eq!(Some(2), heap.swap_remove(0));
719        assert_eq!(None, heap.swap_remove(0));
720    }
721
722    #[test]
723    fn test_push_full() {
724        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
725        let comparer = |a: &i32, b: &i32, _: &()| a > b;
726        assert_eq!(heap.push(1, &comparer, &()), None);
727        assert_eq!(heap.push(2, &comparer, &()), None);
728        assert_eq!(heap.push(4, &comparer, &()), None);
729        assert_eq!(heap.push(3, &comparer, &()), None);
730        assert_eq!(heap.push(5, &comparer, &()), Some(1));
731
732        assert_eq!(Some(5), heap.pop(&comparer, &()));
733        assert_eq!(Some(4), heap.pop(&comparer, &()));
734        assert_eq!(Some(3), heap.pop(&comparer, &()));
735        assert_eq!(Some(2), heap.pop(&comparer, &()));
736        assert_eq!(None, heap.pop(&comparer, &()));
737    }
738
739    #[test]
740    fn test_push_pop_equal() {
741        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
742        let comparer = |a: &i32, b: &i32, _: &()| a > b;
743        assert_eq!(heap.push(7, &comparer, &()), None);
744        assert_eq!(heap.push(7, &comparer, &()), None);
745        assert_eq!(heap.push(7, &comparer, &()), None);
746
747        assert_eq!(Some(7), heap.pop(&comparer, &()));
748        assert_eq!(Some(7), heap.pop(&comparer, &()));
749        assert_eq!(Some(7), heap.pop(&comparer, &()));
750        assert_eq!(None, heap.pop(&comparer, &()));
751    }
752
753    #[test]
754    fn test_keys() {
755        let mut heap: FixedHeap<usize, 4> = FixedHeap::new();
756        fn comparer(a: &usize, b: &usize, state: &[i32; 4]) -> bool {
757            state[*a] > state[*b]
758        }
759        let state = [1, 3, 1, 2];
760        assert_eq!(heap.push(0, &comparer, &state), None);
761        assert_eq!(heap.push(1, &comparer, &state), None);
762        assert_eq!(heap.push(3, &comparer, &state), None);
763
764        assert_eq!(Some(1), heap.pop(&comparer, &state));
765        assert_eq!(Some(3), heap.pop(&comparer, &state));
766        assert_eq!(Some(0), heap.pop(&comparer, &state));
767        assert_eq!(None, heap.pop(&comparer, &state));
768    }
769
770    #[test]
771    fn test_as_slice() {
772        let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
773        let comparer = |a: &i32, b: &i32, _: &()| a > b;
774        assert_eq!(heap.push(7, &comparer, &()), None);
775        assert_eq!(heap.push(9, &comparer, &()), None);
776        assert_eq!(heap.push(2, &comparer, &()), None);
777        assert_eq!(heap.push(5, &comparer, &()), None);
778        assert_eq!(heap.push(8, &comparer, &()), None);
779        assert_eq!(heap.push(8, &comparer, &()), None);
780        assert_eq!(heap.push(3, &comparer, &()), None);
781
782        let slice = heap.as_slice();
783        assert_eq!(7, slice.len());
784        assert_eq!(9, slice[0]);
785        assert_eq!(8, slice[1]);
786        assert_eq!(8, slice[2]);
787        assert_eq!(5, slice[3]);
788        assert_eq!(7, slice[4]);
789        assert_eq!(2, slice[5]);
790        assert_eq!(3, slice[6]);
791    }
792
793    #[test]
794    fn test_debug() {
795        let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
796        let comparer = |a: &i32, b: &i32, _: &()| a > b;
797        assert_eq!(heap.push(7, &comparer, &()), None);
798        assert_eq!(heap.push(9, &comparer, &()), None);
799        assert_eq!(heap.push(2, &comparer, &()), None);
800        assert_eq!(heap.push(5, &comparer, &()), None);
801        assert_eq!(heap.push(8, &comparer, &()), None);
802        assert_eq!(heap.push(8, &comparer, &()), None);
803        assert_eq!(heap.push(3, &comparer, &()), None);
804        assert_eq!(
805            format!("{:?}", heap.into_iter()),
806            "IntoIter { next: 0, heap: ManuallyDrop { value: FixedHeap { high: 7, data: [9, 8, 8, 5, 7, 2, 3] } } }"
807        );
808    }
809
810    #[test]
811    fn test_iter() {
812        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
813        assert_eq!(None, heap.iter().next());
814        heap.copy_from_slice(&[2, 3, 6]);
815        let mut iter = heap.iter();
816        assert_eq!(Some(&2), iter.next());
817        assert_eq!(Some(&3), iter.next());
818        assert_eq!(Some(&6), iter.next());
819        assert_eq!(None, iter.next());
820    }
821
822    #[test]
823    fn test_iter_mut() {
824        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
825        assert_eq!(None, heap.iter_mut().next());
826        heap.copy_from_slice(&[2, 3, 6]);
827        let mut iter = heap.iter_mut();
828        *iter.next().unwrap() = 5;
829        *iter.next().unwrap() = 4;
830        *iter.next().unwrap() = 2;
831        assert_eq!(&[5, 4, 2], heap.as_slice());
832    }
833
834    #[test]
835    fn test_into_iter() {
836        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
837        heap.copy_from_slice(&[2, 3, 6]);
838        let mut iter = heap.into_iter();
839        assert_eq!((3, Some(3)), iter.size_hint());
840        assert_eq!(Some(2), iter.next());
841        assert_eq!(Some(3), iter.next());
842        assert_eq!(Some(6), iter.next());
843        assert_eq!(None, iter.next());
844    }
845
846    #[test]
847    fn test_into_iter_ref() {
848        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
849        assert_eq!(None, (&heap).into_iter().next());
850        heap.copy_from_slice(&[2, 3, 6]);
851        let mut iter = (&heap).into_iter();
852        assert_eq!(Some(&2), iter.next());
853        assert_eq!(Some(&3), iter.next());
854        assert_eq!(Some(&6), iter.next());
855        assert_eq!(None, iter.next());
856    }
857
858    #[test]
859    fn test_into_iter_mut() {
860        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
861        assert_eq!(None, (&mut heap).into_iter().next());
862        heap.copy_from_slice(&[2, 3, 6]);
863        let mut iter = (&mut heap).into_iter();
864        *iter.next().unwrap() = 5;
865        *iter.next().unwrap() = 4;
866        *iter.next().unwrap() = 2;
867        assert_eq!(&[5, 4, 2], heap.as_slice());
868    }
869
870    #[test]
871    fn test_len() {
872        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
873        assert_eq!(0, heap.len());
874        heap.copy_from_slice(&[2, 3, 6]);
875        assert_eq!(3, heap.len());
876    }
877
878    #[test]
879    fn test_is_empty() {
880        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
881        assert!(heap.is_empty());
882        heap.copy_from_slice(&[2, 3, 6]);
883        assert!(!heap.is_empty());
884    }
885
886    #[test]
887    fn test_is_full() {
888        let mut heap: FixedHeap<i32, 4> = FixedHeap::new();
889        assert!(!heap.is_full());
890        heap.copy_from_slice(&[2, 3, 6]);
891        assert!(!heap.is_full());
892        heap.copy_from_slice(&[4, 1, 5, 3]);
893        assert!(heap.is_full());
894    }
895
896    #[test]
897    fn test_drop() {
898        let drops = RefCell::new(0usize);
899        {
900            let comparer = |_: &_, _: &_, _: &()| false;
901            let mut list: FixedHeap<DropCounted, 16> = FixedHeap::new();
902            for _ in 0..11 {
903                list.push(DropCounted(&drops), &comparer, &());
904            }
905            assert_eq!(*drops.borrow(), 0);
906
907            // Pop and drop a few
908            for _ in 0..4 {
909                list.pop(&comparer, &());
910            }
911            assert_eq!(*drops.borrow(), 4);
912
913            // Move it into a consuming iterator
914            let mut iter = list.into_iter();
915            assert_eq!(*drops.borrow(), 4);
916
917            // Consume the first item
918            iter.next();
919            assert_eq!(*drops.borrow(), 5);
920
921            // Let the rest drop
922        }
923        assert_eq!(*drops.borrow(), 11);
924    }
925
926    struct DropCounted<'a>(&'a RefCell<usize>);
927
928    impl<'a> Drop for DropCounted<'a> {
929        fn drop(&mut self) {
930            *self.0.borrow_mut() += 1;
931        }
932    }
933
934    #[test]
935    fn test_pop_at_sift_up() {
936        // This test fails if pop_at only sifts down and doesn't sift up.
937        let mut heap: FixedHeap<i32, 16> = FixedHeap::new();
938        let comparer = |a: &i32, b: &i32, _: &()| a > b;
939        for &v in &[50, 10, 30, 5, 8, 25, 28] {
940            heap.push(v, &comparer, &());
941        }
942        assert_eq!(heap.pop_at(3, &comparer, &()), Some(5));
943        assert_eq!(heap.pop(&comparer, &()), Some(50));
944        assert_eq!(heap.pop(&comparer, &()), Some(30));
945        assert_eq!(heap.pop(&comparer, &()), Some(28));
946        assert_eq!(heap.pop(&comparer, &()), Some(25));
947        assert_eq!(heap.pop(&comparer, &()), Some(10));
948        assert_eq!(heap.pop(&comparer, &()), Some(8));
949        assert_eq!(heap.pop(&comparer, &()), None);
950    }
951
952    #[test]
953    fn test_fuzz_gt_partial() {
954        let gt = |a: &i8, b: &i8, _: &()| a > b;
955        fuzz::<_, 8, 7>(10, &gt);
956        fuzz::<_, 9, 7>(10, &gt);
957        fuzz::<_, 10, 7>(10, &gt);
958        fuzz::<_, 11, 7>(10, &gt);
959        fuzz::<_, 12, 7>(10, &gt);
960        fuzz::<_, 13, 7>(10, &gt);
961        fuzz::<_, 14, 7>(10, &gt);
962        fuzz::<_, 15, 7>(10, &gt);
963        fuzz::<_, 16, 7>(10, &gt);
964    }
965
966    #[test]
967    fn test_fuzz_gt_full() {
968        let gt = |a: &i8, b: &i8, _: &()| a > b;
969        fuzz::<_, 0, 4>(10, &gt);
970        fuzz::<_, 1, 4>(10, &gt);
971        fuzz::<_, 2, 4>(10, &gt);
972        fuzz::<_, 3, 4>(10, &gt);
973        fuzz::<_, 8, 16>(10, &gt);
974        fuzz::<_, 9, 16>(10, &gt);
975        fuzz::<_, 10, 16>(10, &gt);
976        fuzz::<_, 11, 16>(10, &gt);
977        fuzz::<_, 12, 16>(10, &gt);
978        fuzz::<_, 13, 16>(10, &gt);
979        fuzz::<_, 14, 16>(10, &gt);
980        fuzz::<_, 15, 16>(10, &gt);
981    }
982
983    #[test]
984    fn test_fuzz_ge_partial() {
985        let ge = |a: &i8, b: &i8, _: &()| a >= b;
986        fuzz::<_, 8, 7>(10, &ge);
987        fuzz::<_, 9, 7>(10, &ge);
988        fuzz::<_, 10, 7>(10, &ge);
989        fuzz::<_, 11, 7>(10, &ge);
990        fuzz::<_, 12, 7>(10, &ge);
991        fuzz::<_, 13, 7>(10, &ge);
992        fuzz::<_, 14, 7>(10, &ge);
993        fuzz::<_, 15, 7>(10, &ge);
994        fuzz::<_, 16, 7>(10, &ge);
995    }
996
997    #[test]
998    fn test_fuzz_ge_full() {
999        let ge = |a: &i8, b: &i8, _: &()| a >= b;
1000        fuzz::<_, 0, 4>(10, &ge);
1001        fuzz::<_, 1, 4>(10, &ge);
1002        fuzz::<_, 2, 4>(10, &ge);
1003        fuzz::<_, 3, 4>(10, &ge);
1004        fuzz::<_, 8, 16>(10, &ge);
1005        fuzz::<_, 9, 16>(10, &ge);
1006        fuzz::<_, 10, 16>(10, &ge);
1007        fuzz::<_, 11, 16>(10, &ge);
1008        fuzz::<_, 12, 16>(10, &ge);
1009        fuzz::<_, 13, 16>(10, &ge);
1010        fuzz::<_, 14, 16>(10, &ge);
1011        fuzz::<_, 15, 16>(10, &ge);
1012    }
1013
1014    fn fuzz<F, const N: usize, const M: usize>(iters: usize, comparer: &F)
1015    where
1016        F: Fn(&i8, &i8, &()) -> bool,
1017    {
1018        for _ in 0..iters {
1019            let mut heap: FixedHeap<i8, N> = FixedHeap::new();
1020            let mut array = [0i8; M];
1021            rand::rng().fill(&mut array[..]);
1022            for element in array {
1023                heap.push(element, comparer, &());
1024            }
1025            array.sort_by(|a, b| b.cmp(a));
1026            for &element in array.iter().take(N) {
1027                assert_eq!(Some(element), heap.pop(comparer, &()));
1028            }
1029            assert_eq!(None, heap.pop(comparer, &()));
1030        }
1031    }
1032
1033    #[test]
1034    fn test_fuzz_true() {
1035        let comparer = |_: &usize, _: &usize, _: &()| true;
1036        fuzz_state::<_, _, 0, 4>(&comparer, &());
1037        fuzz_state::<_, _, 1, 4>(&comparer, &());
1038        fuzz_state::<_, _, 2, 4>(&comparer, &());
1039        fuzz_state::<_, _, 3, 4>(&comparer, &());
1040        fuzz_state::<_, _, 8, 16>(&comparer, &());
1041        fuzz_state::<_, _, 9, 16>(&comparer, &());
1042        fuzz_state::<_, _, 10, 16>(&comparer, &());
1043        fuzz_state::<_, _, 11, 16>(&comparer, &());
1044        fuzz_state::<_, _, 12, 16>(&comparer, &());
1045        fuzz_state::<_, _, 13, 16>(&comparer, &());
1046        fuzz_state::<_, _, 14, 16>(&comparer, &());
1047        fuzz_state::<_, _, 15, 16>(&comparer, &());
1048        fuzz_state::<_, _, 16, 16>(&comparer, &());
1049        fuzz_state::<_, _, 17, 16>(&comparer, &());
1050    }
1051
1052    #[test]
1053    fn test_fuzz_false() {
1054        let comparer = |_: &usize, _: &usize, _: &()| false;
1055        fuzz_state::<_, _, 0, 4>(&comparer, &());
1056        fuzz_state::<_, _, 1, 4>(&comparer, &());
1057        fuzz_state::<_, _, 2, 4>(&comparer, &());
1058        fuzz_state::<_, _, 3, 4>(&comparer, &());
1059        fuzz_state::<_, _, 8, 16>(&comparer, &());
1060        fuzz_state::<_, _, 9, 16>(&comparer, &());
1061        fuzz_state::<_, _, 10, 16>(&comparer, &());
1062        fuzz_state::<_, _, 11, 16>(&comparer, &());
1063        fuzz_state::<_, _, 12, 16>(&comparer, &());
1064        fuzz_state::<_, _, 13, 16>(&comparer, &());
1065        fuzz_state::<_, _, 14, 16>(&comparer, &());
1066        fuzz_state::<_, _, 15, 16>(&comparer, &());
1067        fuzz_state::<_, _, 16, 16>(&comparer, &());
1068        fuzz_state::<_, _, 17, 16>(&comparer, &());
1069    }
1070
1071    #[test]
1072    fn test_fuzz() {
1073        let rng = RefCell::new(rand::rng());
1074        fn comparer(_: &usize, _: &usize, rng: &RefCell<ThreadRng>) -> bool {
1075            rng.borrow_mut().random()
1076        }
1077        fuzz_state::<_, _, 0, 4>(&comparer, &rng);
1078        fuzz_state::<_, _, 1, 4>(&comparer, &rng);
1079        fuzz_state::<_, _, 2, 4>(&comparer, &rng);
1080        fuzz_state::<_, _, 3, 4>(&comparer, &rng);
1081        fuzz_state::<_, _, 8, 16>(&comparer, &rng);
1082        fuzz_state::<_, _, 9, 16>(&comparer, &rng);
1083        fuzz_state::<_, _, 10, 16>(&comparer, &rng);
1084        fuzz_state::<_, _, 11, 16>(&comparer, &rng);
1085        fuzz_state::<_, _, 12, 16>(&comparer, &rng);
1086        fuzz_state::<_, _, 13, 16>(&comparer, &rng);
1087        fuzz_state::<_, _, 14, 16>(&comparer, &rng);
1088        fuzz_state::<_, _, 15, 16>(&comparer, &rng);
1089        fuzz_state::<_, _, 16, 16>(&comparer, &rng);
1090        fuzz_state::<_, _, 17, 16>(&comparer, &rng);
1091    }
1092
1093    fn fuzz_state<S, F, const N: usize, const M: usize>(
1094        comparer: &F,
1095        state: &S,
1096    ) -> [Option<usize>; M]
1097    where
1098        F: Fn(&usize, &usize, &S) -> bool,
1099    {
1100        let mut heap: FixedHeap<usize, N> = FixedHeap::new();
1101        for i in 0..M {
1102            heap.push(i, comparer, state);
1103        }
1104        let mut result = [None; M];
1105        for item in result.iter_mut() {
1106            *item = heap.pop(comparer, state);
1107        }
1108        if N < M {
1109            for &item in result.iter().skip(N) {
1110                assert_eq!(None, item);
1111            }
1112        } else {
1113            assert_eq!(None, heap.pop(comparer, state));
1114        }
1115        result
1116    }
1117}