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