use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Serialize, Deserialize)]
struct PackedNode(u8);
impl PackedNode {
const fn empty() -> Self { Self(0b0000_1010) }
fn read(self, left: bool, full: bool) -> bool {
((self.0 >> 2 * left as u8) >> !full as u8) & 0b1 == 1
}
fn write(&mut self, left: bool, data: u8) {
self.0 &= !(0b11 << 2 * left as u8);
self.0 |= data << 2 * left as u8;
}
fn combine(self) -> u8 { (self.0 & 0b11) | (self.0 >> 2) }
}
impl fmt::Debug for PackedNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:04b}", self.0)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BinaryTree {
tree: Vec<PackedNode>,
height: u8,
size: usize, }
impl BinaryTree {
pub fn new() -> Self {
Self {
tree: Vec::new(),
height: 0,
size: 0,
}
}
fn capacity(&self) -> usize { self.tree.len() + 1}
fn root(&self) -> usize { (self.capacity() >> 1) - 1 }
pub fn resize(&mut self, size: usize) {
if self.size == size { return }
let last_safe_idx = size.min(self.size).saturating_sub(1);
let last_val = self.is_full(last_safe_idx);
let new_capacity = if size == 0 { 0 } else { size.next_power_of_two().max(2) };
self.height = if new_capacity == 0 { 0 } else { (new_capacity >> 1).ilog2() as u8 };
self.tree.truncate(size.saturating_sub(1)); self.tree.resize(new_capacity.saturating_sub(1), PackedNode::empty()); self.size = size;
if let Some(val) = last_val { self.set_leaf(last_safe_idx, val); } self.tree.shrink_to_fit();
}
fn find_leaf(&self, left: bool, full: bool) -> Option<usize> {
if self.size == 0 { return None }
let mut cur_idx = self.root();
for i in (0 .. self.height).rev() {
let step = 1 << i;
if self.tree[cur_idx].read(left, full) { cur_idx = if left { cur_idx - step } else {cur_idx + step} }
else if self.tree[cur_idx].read(!left, full) { cur_idx = if left { cur_idx + step } else {cur_idx - step} }
else { return None }
}
let result = cur_idx +
if self.tree[cur_idx].read(left, full) { !left as usize }
else if self.tree[cur_idx].read(!left, full) { left as usize }
else { return None };
(result < self.size).then_some(result)
}
pub fn find_first_free(&self) -> Option<usize> { self.find_leaf(true, false)}
pub fn find_last_full(&self) -> Option<usize> { self.find_leaf(false, true)}
pub fn set_leaf(&mut self, idx: usize, full: bool) -> Option<()> {
if idx >= self.size { return None }
let mut step = 1;
let mut cur_idx = idx & !1;
self.tree[cur_idx].write(idx & step == 0, ((!full as u8) << 1) | full as u8);
for _ in 0 .. self.height {
let combined = self.tree[cur_idx].combine();
let on_left = idx & (step << 1) == 0;
cur_idx = if on_left { cur_idx + step } else { cur_idx - step };
self.tree[cur_idx].write(on_left, combined);
step <<= 1;
}
Some(())
}
pub fn is_full(&self, idx: usize) -> Option<bool> {
if idx >= self.size { return None }
Some(self.tree[idx & !1].read(idx & 1 == 0, true))
}
}
#[test]
fn write() {
let mut tree = BinaryTree::new();
tree.resize(7);
tree.set_leaf(1, true);
assert_eq!(tree.is_full(1).unwrap(), true);
tree.set_leaf(3, true);
assert_eq!(tree.is_full(3).unwrap(), true);
tree.set_leaf(3, false);
assert_eq!(tree.is_full(3).unwrap(), false);
assert_eq!(tree.set_leaf(7, false), None);
}
#[test]
fn paths() {
let mut tree = BinaryTree::new();
tree.resize(8);
tree.set_leaf(0, true);
tree.set_leaf(1, true);
tree.set_leaf(6, true);
assert_eq!(tree.find_first_free().unwrap(), 2);
assert_eq!(tree.find_leaf(true, true).unwrap(), 0);
assert_eq!(tree.find_last_full().unwrap(), 6);
}
#[test]
fn resize() {
let mut tree = BinaryTree::new();
tree.resize(8);
tree.set_leaf(6, true);
tree.set_leaf(2, true);
tree.resize(3);
assert_eq!(tree.is_full(2).unwrap(), true);
tree.resize(8);
assert_eq!(tree.is_full(6).unwrap(), false); assert_eq!(tree.is_full(2).unwrap(), true); dbg!(&tree.tree);
assert_eq!(tree.find_leaf(true, true).unwrap(), 2);
assert_eq!(tree.find_last_full().unwrap(), 2);
}