use core::mem::swap;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use self::heap_helpers::StaticHeapHole;
pub use self::heap_helpers::StaticHeapPeekMut;
pub use self::heap_iterators::{StaticHeapDrainSorted, StaticHeapIntoIterSorted};
use crate::iterators::{StaticVecDrain, StaticVecIterConst, StaticVecIterMut};
use crate::StaticVec;
mod heap_helpers;
mod heap_iterators;
mod heap_trait_impls;
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct StaticHeap<T, const N: usize> {
pub(crate) data: StaticVec<T, N>,
}
impl<T: Ord, const N: usize> StaticHeap<T, N> {
#[inline(always)]
pub const fn new() -> StaticHeap<T, N> {
StaticHeap {
data: StaticVec::new(),
}
}
#[inline(always)]
pub const fn peek_mut(&mut self) -> Option<StaticHeapPeekMut<'_, T, N>> {
if self.is_empty() {
None
} else {
Some(StaticHeapPeekMut {
heap: self,
sift: true,
})
}
}
#[inline(always)]
pub unsafe fn pop_unchecked(&mut self) -> T {
let mut res = self.data.pop_unchecked();
if self.is_not_empty() {
swap(&mut res, self.data.get_unchecked_mut(0));
self.sift_down_to_bottom(0);
}
res
}
#[inline(always)]
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.pop_unchecked() })
}
}
#[inline(always)]
pub unsafe fn push_unchecked(&mut self, item: T) {
let old_length = self.len();
self.data.push_unchecked(item);
self.sift_up(0, old_length);
}
#[inline(always)]
pub fn push(&mut self, item: T) {
let old_length = self.len();
self.data.push(item);
self.sift_up(0, old_length);
}
#[inline]
pub fn into_sorted_staticvec(mut self) -> StaticVec<T, N> {
let mut end = self.len();
while end > 1 {
end -= 1;
self.data.swap(0, end);
self.sift_down_range(0, end);
}
self.into_staticvec()
}
#[inline]
fn sift_up(&mut self, start: usize, position: usize) {
unsafe {
let mut hole = StaticHeapHole::new(&mut self.data, position);
while hole.pos() > start {
let parent = (hole.pos() - 1) / 2;
if hole.elt() <= hole.get(parent) {
break;
}
hole.move_to(parent);
}
}
}
#[inline]
fn sift_down_range(&mut self, position: usize, end: usize) {
unsafe {
let mut hole = StaticHeapHole::new(&mut self.data, position);
let mut child = 2 * position + 1;
while child < end {
let right = child + 1;
if right < end && hole.get(child) <= hole.get(right) {
child = right;
}
if hole.elt() >= hole.get(child) {
break;
}
hole.move_to(child);
child = 2 * hole.pos() + 1;
}
}
}
#[inline]
fn sift_down_to_bottom(&mut self, mut position: usize) {
let end = self.len();
let start = position;
unsafe {
let mut hole = StaticHeapHole::new(&mut self.data, position);
let mut child = 2 * position + 1;
while child < end {
let right = child + 1;
if right < end && hole.get(child) <= hole.get(right) {
child = right;
}
hole.move_to(child);
child = 2 * hole.pos() + 1;
}
position = hole.position;
}
self.sift_up(start, position);
}
#[inline(always)]
fn rebuild(&mut self) {
let mut n = self.len() / 2;
while n > 0 {
n -= 1;
self.sift_down_range(n, self.len());
}
}
#[inline(always)]
pub fn append<const N2: usize>(&mut self, other: &mut StaticHeap<T, N2>) {
if other.is_empty() {
return;
}
self.data.append(&mut other.data);
self.rebuild();
}
#[inline(always)]
pub const fn drain_sorted(&mut self) -> StaticHeapDrainSorted<'_, T, N> {
StaticHeapDrainSorted { inner: self }
}
}
impl<T, const N: usize> StaticHeap<T, N> {
#[inline(always)]
pub const fn iter(&self) -> StaticVecIterConst<'_, T, N> {
self.data.iter()
}
#[inline(always)]
pub const fn iter_mut(&mut self) -> StaticVecIterMut<'_, T, N> {
self.data.iter_mut()
}
#[inline(always)]
pub const fn into_iter_sorted(self) -> StaticHeapIntoIterSorted<T, N> {
StaticHeapIntoIterSorted { inner: self }
}
#[inline(always)]
pub fn peek(&self) -> Option<&T> {
self.data.get(0)
}
#[inline(always)]
pub const fn capacity(&self) -> usize {
self.data.capacity()
}
#[inline(always)]
pub const fn remaining_capacity(&self) -> usize {
self.data.remaining_capacity()
}
#[inline(always)]
pub const fn size_in_bytes(&self) -> usize {
self.data.size_in_bytes()
}
#[inline(always)]
pub fn into_staticvec(self) -> StaticVec<T, N> {
self.data
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.data.len()
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
#[allow(clippy::len_zero)]
#[inline(always)]
pub const fn is_not_empty(&self) -> bool {
self.len() > 0
}
#[inline(always)]
pub const fn is_full(&self) -> bool {
self.len() == N
}
#[inline(always)]
pub const fn is_not_full(&self) -> bool {
self.len() < N
}
#[inline(always)]
pub fn drain(&mut self) -> StaticVecDrain<'_, T, N> {
self.data.drain_iter(..)
}
#[inline(always)]
pub fn clear(&mut self) {
self.data.clear();
}
}