macro_rules! swap {
($xs:expr, $i:expr, $j:expr) => {
let scratch = $xs[$i];
$xs[$i] = $xs[$j];
$xs[$j] = scratch;
};
}
macro_rules! up {
($xs:expr, $xn:expr, $cmp:expr, $i:expr) => {{
use ::core::cmp::Ordering;
use $crate::core::r#const::heap;
let mut i = $i;
while let Some(j) = heap::parent(i) {
if let Ordering::Less = $cmp($xs[j], $xs[i]) {
swap!($xs, i, j);
i = j;
} else {
break;
}
}
i
}};
}
macro_rules! down {
($xs:expr, $xn:expr, $cmp:expr, $i:expr) => {{
use ::core::cmp::Ordering;
use $crate::core::r#const::heap;
let mut i = $i;
loop {
let j = match (heap::left(i, $xn), heap::right(i, $xn)) {
(Some(p), Some(q)) => match $cmp($xs[p], $xs[q]) {
Ordering::Less => Some(q),
_ => Some(p),
},
(Some(p), _) => Some(p),
(_, Some(q)) => Some(q),
(_, _) => break,
};
match j {
Some(j) => match $cmp($xs[i], $xs[j]) {
Ordering::Less => {
swap!($xs, i, j);
i = j;
}
_ => break,
},
_ => break,
}
}
i
}};
}
macro_rules! insert {
($xs:expr, $xn:expr, $cmp:expr, $x:expr) => {{
$xs[$xn] = $x;
$xn += 1;
up!($xs, $xn, $cmp, $xn - 1)
}};
}
macro_rules! drain {
($xs:expr, $xn:expr, $cmp:expr) => {{
let mut len = $xn;
while len > 1 {
len -= 1;
swap!($xs, 0, len);
down!($xs, len, $cmp, 0);
}
}};
}
pub const fn parent(i: usize) -> Option<usize> {
if i < 1 {
return None;
}
Some((i - 1) / 2)
}
pub const fn left(i: usize, len: usize) -> Option<usize> {
let result = i * 2 + 1;
if result < len {
Some(result)
} else {
None
}
}
pub const fn right(i: usize, len: usize) -> Option<usize> {
let result = i * 2 + 2;
if result < len {
Some(result)
} else {
None
}
}
#[cfg(test)]
mod test {
use super::super::cmp_k;
#[test]
pub fn insert() {
let mut xs = [11, 5, 8, 3, 4, 0, 0, 0];
let mut xn = 5;
assert_eq!(insert!(xs, xn, cmp_k, 15), 0);
assert_eq!(xs[..xn], [15, 5, 11, 3, 4, 8]);
assert_eq!(insert!(xs, xn, cmp_k, 12), 2);
assert_eq!(xs[..xn], [15, 5, 12, 3, 4, 8, 11]);
}
#[test]
pub fn drain() {
let mut xs = [11, 5, 8, 3, 4, 0, 0, 0];
let xn = 5;
drain!(xs, xn, cmp_k);
assert_eq!(xs[..xn], [3, 4, 5, 8, 11]);
assert_eq!(xn, 5); }
}