use super::{CheckedIterator, HasMaxDepth, HpxCell, HpxHash, MOCIterator};
pub fn compress<H, T>(it: T) -> CompressMocIter<H, CheckedIterator<H, T>>
where
H: HpxHash,
T: MOCIterator<H>,
{
let it = CheckedIterator::new(it);
compress_unchecked(it)
}
pub fn compress_unchecked<H, T>(it: T) -> CompressMocIter<H, T>
where
H: HpxHash,
T: MOCIterator<H>,
{
CompressMocIter::new_unchecked(it)
}
pub fn uncompress<H: HpxHash>(compressed: &[u8]) -> UncompressMocIter<'_, H> {
UncompressMocIter::new(compressed)
}
pub struct CompressMocIter<H, T>
where
H: HpxHash,
T: MOCIterator<H>,
{
it: T,
curr: Option<HpxCell<H>>,
d: u8,
h: H,
buff: u32, ibit: u8,
is_going_down: bool,
}
impl<H, T> CompressMocIter<H, T>
where
H: HpxHash,
T: MOCIterator<H>,
{
fn new_unchecked(mut it: T) -> CompressMocIter<H, T> {
let depth_max = it.depth_max();
let curr = it.next();
CompressMocIter {
it,
curr,
d: 0,
h: H::zero(),
buff: depth_max as u32,
ibit: 8,
is_going_down: true,
}
}
fn push_0(&mut self) {
self.ibit += 1;
}
fn push_0_x(&mut self, n: u8) {
self.ibit += n;
}
fn push_1(&mut self) {
self.buff |= 1_u32 << self.ibit;
self.push_0();
}
fn is_byte_full(&self) -> bool {
self.ibit > 7
}
fn take_byte(&mut self) -> u8 {
let r = self.buff as u8;
self.buff >>= 8;
self.ibit -= 8;
r
}
fn has_last_byte(&self) -> bool {
debug_assert!(self.ibit < 8);
self.ibit > 0
}
fn take_last_byte(&mut self) -> u8 {
debug_assert!(self.ibit < 8);
let r = self.buff as u8;
self.buff >>= 8;
self.ibit = 0;
r
}
fn push_n_empty_nodes_notest(&mut self, n: H) {
for _ in 0..n.to_u8().unwrap() {
self.push_1();
self.push_0();
}
}
fn push_node_full_notest(&mut self) {
self.push_1();
self.push_1();
}
fn push_node_partial(&mut self) -> bool {
self.push_node_partial_notest();
self.is_byte_full()
}
fn push_node_partial_notest(&mut self) {
self.push_0();
}
fn push_n_empty_leaves_notest(&mut self, n: H) {
self.push_0_x(n.to_u8().unwrap());
}
fn push_leaf_full_notest(&mut self) {
self.push_1();
}
}
impl<H, T> HasMaxDepth for CompressMocIter<H, T>
where
H: HpxHash,
T: MOCIterator<H>,
{
fn depth_max(&self) -> u8 {
self.it.depth_max()
}
}
impl<H, T> Iterator for CompressMocIter<H, T>
where
H: HpxHash,
T: MOCIterator<H>,
{
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
let three = H::one() | (H::one() << 1);
if self.is_byte_full() {
return Some(self.take_byte());
}
match &self.curr {
Some(hpx) => {
let (curr_d, curr_h) = (hpx.depth, hpx.hash);
if !self.is_going_down {
let target_h = if self.d > curr_d {
let dd = self.d - curr_d;
curr_h << ((dd << 1) as usize)
} else {
let dd = curr_d - self.d;
curr_h >> ((dd << 1) as usize)
};
let dd = ((63 - (self.h ^ target_h).leading_zeros()) >> 1) as u8;
let target_d = if dd > self.d { 0 } else { self.d - dd };
while self.d > target_d {
let n = three - (self.h & three);
debug_assert!(n <= three);
if self.d == self.depth_max() {
self.push_n_empty_leaves_notest(n); } else {
self.push_n_empty_nodes_notest(n); }
self.h >>= 2;
self.d -= 1;
if self.is_byte_full() {
return Some(self.take_byte());
}
}
self.h += H::one();
}
self.is_going_down = true;
let target_d = curr_d;
while self.d < target_d {
let dd = target_d - self.d;
let target_h = curr_h >> ((dd << 1) as usize);
let n = target_h - self.h;
self.h = target_h << 2;
self.d += 1;
debug_assert!(n <= three);
self.push_n_empty_nodes_notest(n); if self.push_node_partial() {
return Some(self.take_byte());
}
}
debug_assert_eq!(self.d, target_d);
let n = curr_h - self.h;
debug_assert!(
n <= three,
"n: {}, curr_h: {}, self.h: {}",
n,
curr_h,
self.h
);
if self.d == self.depth_max() {
self.push_n_empty_leaves_notest(n);
self.push_leaf_full_notest()
} else {
self.push_n_empty_nodes_notest(n);
self.push_node_full_notest();
}
self.h = curr_h;
self.curr = self.it.next();
self.is_going_down = false;
self.next()
}
None => {
if self.d == 0 {
let twelve = three << 2_usize;
let eleven = twelve - H::one();
if self.h < eleven {
let n = eleven - self.h;
self.h = twelve;
if self.d == self.depth_max() {
self.push_n_empty_leaves_notest(n); } else {
self.push_n_empty_nodes_notest(n); }
self.next()
} else if self.has_last_byte() {
debug_assert!(
self.d == 0 && self.h == eleven,
"d: {}, h: {}",
self.d,
self.h
);
Some(self.take_last_byte())
} else {
debug_assert!(
self.d == 0 && self.h == eleven,
"d: {}, h: {}",
self.d,
self.h
);
None
}
} else {
while {
let n = three - (self.h & three);
if self.d == self.depth_max() {
self.push_n_empty_leaves_notest(n); } else {
self.push_n_empty_nodes_notest(n); }
self.h >>= 2;
self.d -= 1;
if self.is_byte_full() {
return Some(self.take_byte());
}
self.d > 0
} {} self.next()
}
}
}
}
}
pub struct UncompressMocIter<'a, H: HpxHash> {
cmoc: &'a [u8],
depth_max: u8,
ibyte: usize,
ibit: u8,
depth: u8,
hash: H,
}
impl<'a, H: HpxHash> UncompressMocIter<'a, H> {
fn new(cmoc: &'a [u8]) -> UncompressMocIter<'a, H> {
let depth_max = cmoc[0];
UncompressMocIter {
cmoc,
depth_max,
ibyte: 1,
ibit: 0,
depth: 0,
hash: H::zero(),
}
}
fn get(&mut self) -> bool {
let r = (self.cmoc[self.ibyte] & (1_u8 << self.ibit)) != 0;
self.ibyte += (self.ibit == 7) as usize;
self.ibit += 1;
self.ibit &= 7;
r
}
fn get_current_cell(&self) -> HpxCell<H> {
HpxCell {
depth: self.depth,
hash: self.hash,
}
}
fn increment(&mut self) {
self.go_up_if_needed();
self.hash += H::one();
}
fn go_up_if_needed(&mut self) {
let three = H::one() | (H::one() << 1);
while self.hash & three == three && self.depth > 0 {
self.hash >>= 2;
self.depth -= 1;
}
}
fn go_down_of_1_depth(&mut self) {
self.hash <<= 2;
self.depth += 1;
}
}
impl<H> HasMaxDepth for UncompressMocIter<'_, H>
where
H: HpxHash,
{
fn depth_max(&self) -> u8 {
self.depth_max
}
}
impl<H: HpxHash> Iterator for UncompressMocIter<'_, H> {
type Item = HpxCell<H>;
fn next(&mut self) -> Option<Self::Item> {
let three = H::one() | (H::one() << 1);
let twelve = three << 2_usize;
while self.depth != 0 || self.hash != twelve {
if self.get() {
if self.depth == self.depth_max || self.get() {
let res = Some(self.get_current_cell());
self.increment();
return res;
} else {
self.increment();
}
} else if self.depth == self.depth_max {
self.increment();
} else {
debug_assert!(self.depth < self.depth_max);
self.go_down_of_1_depth();
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n_remains = 8 * (self.cmoc.len() - self.ibyte) - (self.ibit as usize);
(0, Some(n_remains))
}
}