use super::*;
use std::cmp::{Ordering, max};
type CellIter<'a> = iter::CellIter<iter::SliceIter<'a>>;
#[inline(never)]
pub fn not(max_depth: u8, entries: &[u64]) -> MutableBmoc {
println!("not()");
let mut builder = MutableBmoc::<false>::with_capacity(max_depth, 3 * entries.len() + 12);
if entries.is_empty() {
return builder
.push_all_unchecked(0_u8, 0, 12, true)
.take()
.into_valid_unchecked();
}
let mut d = 0_u8;
let mut h = 0_u64;
let mut cell = Cell::decode(entries[0], max_depth);
go_down(&mut d, &mut h, cell.depth, cell.hash, true, &mut builder);
if !cell.is_full {
builder.push_raw_unchecked(cell.raw_value);
}
for &entry in &entries[1..] {
cell = Cell::decode(entry, max_depth);
let dd = dd_4_go_up(d, h, cell.depth, cell.hash);
go_up(&mut d, &mut h, dd, true, &mut builder);
go_down(&mut d, &mut h, cell.depth, cell.hash, true, &mut builder);
if !cell.is_full {
builder.push_raw_unchecked(cell.raw_value);
}
}
let delta_depth = d;
go_up(&mut d, &mut h, delta_depth, true, &mut builder); builder.push_all_unchecked(0, h, 12, true);
builder.into_valid_unchecked()
}
#[inline(never)]
pub fn and(lhs: BorrowedBmoc, rhs: BorrowedBmoc) -> MutableBmoc {
let mut builder = MutableBmoc::with_capacity(
max(lhs.max_depth, rhs.max_depth),
max(lhs.entries.len(), rhs.entries.len()),
);
let mut it_left = lhs.cells();
let mut it_right = rhs.cells();
let mut left = it_left.next();
let mut right = it_right.next();
while let (Some(l), Some(r)) = (&left, &right) {
match l.depth.cmp(&r.depth) {
Ordering::Less => {
let hr_at_dl = r.hash >> ((r.depth - l.depth) << 1);
match l.hash.cmp(&hr_at_dl) {
Ordering::Less => left = it_left.next(),
Ordering::Greater => right = it_right.next(),
Ordering::Equal => {
debug_assert_eq!(l.hash, hr_at_dl);
builder.push_unchecked(r.depth, r.hash, r.is_full && l.is_full);
right = it_right.next()
}
}
}
Ordering::Greater => {
let hl_at_dr = l.hash >> ((l.depth - r.depth) << 1);
match hl_at_dr.cmp(&r.hash) {
Ordering::Less => left = it_left.next(),
Ordering::Greater => right = it_right.next(),
Ordering::Equal => {
debug_assert_eq!(hl_at_dr, r.hash);
builder.push_unchecked(l.depth, l.hash, r.is_full && l.is_full);
left = it_left.next()
}
}
}
Ordering::Equal => {
debug_assert_eq!(l.depth, r.depth);
match l.hash.cmp(&r.hash) {
Ordering::Less => left = it_left.next(),
Ordering::Greater => right = it_right.next(),
Ordering::Equal => {
debug_assert_eq!(l.hash, r.hash);
builder.push_unchecked(l.depth, l.hash, r.is_full && l.is_full);
left = it_left.next();
right = it_right.next()
}
}
}
}
}
builder.into_valid_unchecked()
}
#[inline(never)]
pub fn or(lhs: BorrowedBmoc, rhs: BorrowedBmoc) -> MutableBmoc {
let mut builder = MutableBmoc::with_capacity(
max(lhs.max_depth, rhs.max_depth),
max(lhs.entries.len(), rhs.entries.len()),
);
let mut it_left = lhs.cells();
let mut it_right = rhs.cells();
let mut left = it_left.next();
let mut right = it_right.next();
while let (Some(l), Some(r)) = (&left, &right) {
match l.depth.cmp(&r.depth) {
Ordering::Less => {
let hr_at_dl = r.hash >> ((r.depth - l.depth) << 1);
if l.hash < hr_at_dl {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
} else if l.hash > hr_at_dl {
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
} else if l.is_full {
debug_assert_eq!(l.hash, hr_at_dl);
builder.push_unchecked(l.depth, l.hash, l.is_full);
right = consume_while_overlapped(l, &mut it_right);
left = it_left.next();
} else {
debug_assert_eq!(l.hash, hr_at_dl);
debug_assert!(!l.is_full);
let mut is_overlapped = false;
right =
consume_while_overlapped_and_partial(l, &mut it_right, &mut is_overlapped);
if is_overlapped {
right = not_in_cell_4_or(l, right.unwrap(), &mut it_right, &mut builder);
} else {
builder.push_unchecked(l.depth, l.hash, false);
}
left = it_left.next();
}
}
Ordering::Greater => {
let hl_at_dr = l.hash >> ((l.depth - r.depth) << 1);
if hl_at_dr < r.hash {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
} else if hl_at_dr > r.hash {
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
} else if r.is_full {
debug_assert_eq!(hl_at_dr, r.hash);
builder.push_unchecked(r.depth, r.hash, r.is_full);
left = consume_while_overlapped(r, &mut it_left);
right = it_right.next();
} else {
debug_assert_eq!(hl_at_dr, r.hash);
debug_assert!(!r.is_full);
let mut is_overlapped = false;
left =
consume_while_overlapped_and_partial(r, &mut it_left, &mut is_overlapped);
if is_overlapped {
left = not_in_cell_4_or(r, left.unwrap(), &mut it_left, &mut builder);
} else {
builder.push_unchecked(r.depth, r.hash, false);
}
right = it_right.next();
}
}
Ordering::Equal => {
debug_assert_eq!(l.depth, r.depth);
match l.hash.cmp(&r.hash) {
Ordering::Less => {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
}
Ordering::Greater => {
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
}
Ordering::Equal => {
debug_assert_eq!(l.hash, r.hash);
builder.push_unchecked(l.depth, l.hash, r.is_full || l.is_full);
left = it_left.next();
right = it_right.next();
}
}
}
}
}
while let Some(l) = &left {
debug_assert!(right.is_none());
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
}
while let Some(r) = &right {
debug_assert!(left.is_none());
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
}
builder.pack();
builder.into_valid_unchecked()
}
fn not_in_cell_4_or(
low_resolution: &Cell,
mut c: Cell,
iter: &mut CellIter,
builder: &mut MutableBmoc<false>,
) -> Option<Cell> {
let mut d = low_resolution.depth;
let mut h = low_resolution.hash;
debug_assert!(c.is_full);
go_down(&mut d, &mut h, c.depth, c.hash, false, builder);
builder.push_unchecked(c.depth, c.hash, true);
let mut is_overlapped = false;
let mut cell;
while {
cell = consume_while_overlapped_and_partial(low_resolution, iter, &mut is_overlapped);
is_overlapped
} {
c = cell.unwrap(); let dd = dd_4_go_up(d, h, c.depth, c.hash);
go_up(&mut d, &mut h, dd, false, builder);
go_down(&mut d, &mut h, c.depth, c.hash, false, builder);
builder.push_unchecked(c.depth, c.hash, true);
}
let dd = d - low_resolution.depth;
go_up(&mut d, &mut h, dd, false, builder);
go_down(
&mut d,
&mut h,
low_resolution.depth,
low_resolution.hash + 1,
false,
builder,
);
cell
}
#[inline(never)]
pub fn xor(lhs: BorrowedBmoc, rhs: BorrowedBmoc) -> MutableBmoc {
let mut builder = MutableBmoc::with_capacity(
max(lhs.max_depth, rhs.max_depth),
max(lhs.entries.len(), rhs.entries.len()),
);
let mut it_left = lhs.cells();
let mut it_right = rhs.cells();
let mut left = it_left.next();
let mut right = it_right.next();
while let (Some(l), Some(r)) = (&left, &right) {
match l.depth.cmp(&r.depth) {
Ordering::Less => {
let hr_at_dl = r.hash >> ((r.depth - l.depth) << 1);
if l.hash < hr_at_dl {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
} else if l.hash > hr_at_dl {
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
} else if l.is_full {
debug_assert_eq!(l.hash, hr_at_dl);
right = not_in_cell_4_xor(l, r, &mut it_right, &mut builder);
left = it_left.next();
} else {
debug_assert_eq!(l.hash, hr_at_dl);
debug_assert!(!l.is_full);
builder.push_unchecked(l.depth, l.hash, l.is_full);
right = consume_while_overlapped(l, &mut it_right);
left = it_left.next();
}
}
Ordering::Greater => {
let hl_at_dr = l.hash >> ((l.depth - r.depth) << 1);
if hl_at_dr < r.hash {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
} else if hl_at_dr > r.hash {
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
} else if r.is_full {
debug_assert_eq!(hl_at_dr, r.hash);
left = not_in_cell_4_xor(r, l, &mut it_left, &mut builder);
right = it_right.next();
} else {
debug_assert_eq!(hl_at_dr, r.hash);
debug_assert!(!r.is_full);
builder.push_unchecked(r.depth, r.hash, r.is_full);
left = consume_while_overlapped(r, &mut it_left);
right = it_right.next();
}
}
Ordering::Equal => {
debug_assert_eq!(l.depth, r.depth);
match l.hash.cmp(&r.hash) {
Ordering::Less => {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
}
Ordering::Greater => {
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
}
Ordering::Equal => {
debug_assert_eq!(l.hash, r.hash);
let both_fully_covered = r.is_full && l.is_full;
if !both_fully_covered {
builder.push_unchecked(l.depth, l.hash, both_fully_covered);
}
left = it_left.next();
right = it_right.next();
}
}
}
}
}
while let Some(l) = &left {
debug_assert!(right.is_none());
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
}
while let Some(r) = &right {
debug_assert!(left.is_none());
builder.push_unchecked(r.depth, r.hash, r.is_full);
right = it_right.next();
}
builder.pack();
builder.into_valid_unchecked()
}
fn not_in_cell_4_xor(
low_resolution: &Cell,
c: &Cell,
iter: &mut CellIter,
builder: &mut MutableBmoc<false>,
) -> Option<Cell> {
let mut d = low_resolution.depth;
let mut h = low_resolution.hash;
go_down(&mut d, &mut h, c.depth, c.hash, true, builder);
if !c.is_full {
builder.push_unchecked(c.depth, c.hash, false);
}
let mut cell = iter.next();
while let Some(c) = &cell {
if !is_in(low_resolution, c) {
break;
}
let dd = dd_4_go_up(d, h, c.depth, c.hash);
go_up(&mut d, &mut h, dd, true, builder);
go_down(&mut d, &mut h, c.depth, c.hash, true, builder);
if !c.is_full {
builder.push_unchecked(c.depth, c.hash, false);
}
cell = iter.next()
}
let dd = d - low_resolution.depth;
go_up(&mut d, &mut h, dd, true, builder);
go_down(
&mut d,
&mut h,
low_resolution.depth,
low_resolution.hash + 1,
true,
builder,
);
cell
}
#[inline(never)]
pub fn minus(lhs: BorrowedBmoc, rhs: BorrowedBmoc) -> MutableBmoc {
let mut builder = MutableBmoc::with_capacity(
max(lhs.max_depth, rhs.max_depth),
max(lhs.entries.len(), rhs.entries.len()),
);
let mut it_left = lhs.cells();
let mut it_right = rhs.cells();
let mut left = it_left.next();
let mut right = it_right.next();
while let (Some(l), Some(r)) = (&left, &right) {
match l.depth.cmp(&r.depth) {
Ordering::Less => {
let hr_at_dl = r.hash >> ((r.depth - l.depth) << 1);
if l.hash < hr_at_dl {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
} else if l.hash > hr_at_dl {
right = it_right.next();
} else if l.is_full {
debug_assert_eq!(l.hash, hr_at_dl);
right = not_in_cell_4_xor(l, r, &mut it_right, &mut builder);
left = it_left.next();
} else {
debug_assert_eq!(l.hash, hr_at_dl);
debug_assert!(!l.is_full);
builder.push_unchecked(l.depth, l.hash, false);
right = consume_while_overlapped(l, &mut it_right);
left = it_left.next();
}
}
Ordering::Greater => {
let hl_at_dr = l.hash >> ((l.depth - r.depth) << 1);
if hl_at_dr < r.hash {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
} else if hl_at_dr > r.hash {
right = it_right.next();
} else if !r.is_full || !l.is_full {
debug_assert_eq!(hl_at_dr, r.hash);
builder.push_unchecked(l.depth, l.hash, false);
left = it_left.next();
}
}
Ordering::Equal => {
debug_assert_eq!(l.depth, r.depth);
match l.hash.cmp(&r.hash) {
Ordering::Less => {
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
}
Ordering::Greater => {
right = it_right.next();
}
Ordering::Equal => {
debug_assert_eq!(l.hash, r.hash);
let both_fully_covered = r.is_full && l.is_full;
if !both_fully_covered {
builder.push_unchecked(l.depth, l.hash, both_fully_covered);
}
left = it_left.next();
right = it_right.next();
}
}
}
}
}
while let Some(l) = &left {
debug_assert!(right.is_none());
builder.push_unchecked(l.depth, l.hash, l.is_full);
left = it_left.next();
}
builder.pack();
builder.into_valid_unchecked()
}
#[inline]
fn consume_while_overlapped(low_resolution: &Cell, iter: &mut CellIter) -> Option<Cell> {
let mut cell = iter.next();
while {
match &cell {
Some(c) => is_in(low_resolution, c),
None => false,
}
} {
cell = iter.next();
}
cell
}
#[inline]
fn consume_while_overlapped_and_partial(
low_resolution: &Cell,
iter: &mut CellIter,
res_is_overlapped: &mut bool,
) -> Option<Cell> {
let mut cell = iter.next();
while {
match &cell {
Some(c) => {
if is_in(low_resolution, c) {
if c.is_full {
*res_is_overlapped = true;
false
} else {
true
}
} else {
false
}
}
None => false,
}
} {
cell = iter.next();
}
cell
}
fn go_up(
start_depth: &mut u8,
start_hash: &mut u64,
delta_depth: u8,
flag: bool,
builder: &mut MutableBmoc<false>,
) {
let output_depth = *start_depth - delta_depth; let output_hash = (*start_hash >> (delta_depth << 1)) + 1; for _ in 0_u8..delta_depth {
let target_hash = *start_hash | 3_u64;
for h in (*start_hash + 1)..=target_hash {
builder.push_unchecked(*start_depth, h, flag);
}
*start_hash >>= 2;
*start_depth -= 1;
}
*start_hash += 1;
debug_assert_eq!(*start_depth, output_depth);
debug_assert_eq!(*start_hash, output_hash);
}
fn go_down(
start_depth: &mut u8,
start_hash: &mut u64,
target_depth: u8,
target_hash: u64,
flag: bool,
builder: &mut MutableBmoc<false>,
) {
debug_assert!(
target_depth >= *start_depth,
"starting depth {start_depth} < target depth {target_depth}"
);
let mut twice_dd = (target_depth - *start_depth) << 1;
for d in *start_depth..=target_depth {
let target_h_at_d = target_hash >> twice_dd;
for h in *start_hash..target_h_at_d {
builder.push_unchecked(d, h, flag);
}
if d != target_depth {
*start_hash = target_h_at_d << 2;
twice_dd -= 2;
}
}
*start_depth = target_depth;
*start_hash = target_hash;
}
#[inline]
fn dd_4_go_up(d: u8, h: u64, next_d: u8, next_h: u64) -> u8 {
let target_h_at_d = if next_d < d {
next_h << ((d - next_d) << 1)
} else {
next_h >> ((next_d - d) << 1)
};
let xor = h ^ target_h_at_d;
if xor != 0 {
((63_u8 - (xor.leading_zeros() as u8)) >> 1).min(d)
} else {
0
}
}