use crate::Zdd;
pub type HKey = u64;
pub type UnaryKey<Info> = (HKey, Info);
pub type BinaryKey = (HKey, HKey);
pub enum Res<D, NY> {
Done(D),
NYet(NY),
}
pub trait Zipper<Data> {
fn push(&mut self, data: Data);
fn pop(&mut self) -> Option<Data>;
}
macro_rules! mk_zip {
(
$(#[$meta:meta])*
$arity:ident $id:ident of (
$key:ty, $lbl:ident, $info:ty, $data:ty
) by $fun:ident
) => (
$(#[$meta])*
pub struct $id<$lbl: Clone> {
zip: Vec<$arity::Step<$key, $lbl, $info, $data>>,
}
pub fn $fun<$lbl: Clone>() -> $id<$lbl> { $id { zip: vec![] } }
impl<$lbl: Clone> $id<$lbl> {
#[inline(always)]
pub fn push(&mut self, step: $arity::Step<$key, $lbl, $info, $data>) {
self.zip.push(step)
}
}
impl<$lbl: Clone> Zipper<
$arity::Step<$key, $lbl, $info, $data>
> for $id<$lbl> {
#[inline(always)]
fn push(&mut self, step: $arity::Step<$key, $lbl, $info, $data>) {
self.zip.push(step)
}
#[inline(always)]
fn pop(&mut self) -> Option<$arity::Step<$key, $lbl, $info, $data>> {
self.zip.pop()
}
}
) ;
}
mk_zip! {
unary Count of (HKey, Label, (), usize) by count
}
mk_zip! {
unary Offset of (
(HKey,Label), Label, Label, Zdd<Label>
) by offset
}
mk_zip! {
unary Onset of (
(HKey,Label), Label, Label, Zdd<Label>
) by onset
}
mk_zip! {
unary Change of (
(HKey,Label), Label, Label, Zdd<Label>
) by change
}
mk_zip! {
binary Union of (
(HKey, HKey), Label, Label, Zdd<Label>
) by union
}
mk_zip! {
binary Inter of (
(HKey, HKey), Label, Label, Zdd<Label>
) by inter
}
mk_zip! {
binary Minus of (
(HKey, HKey), Label, Label, Zdd<Label>
) by minus
}
mk_zip! {
binary Subset of (
(HKey, HKey), Label, (), bool
) by subset
}
macro_rules! zip_up {
($has_zip:ident > $zip:ident > $data:expr) => {{
use $crate::zip::unary::Zip;
let data = $data;
match $has_zip.zip(data, &mut $zip) {
$crate::zip::Res::NYet(rgt) => rgt,
$crate::zip::Res::Done(data) => return data,
}
}};
($has_zip:ident >> $zip:ident > $data:expr) => {{
use $crate::zip::binary::Zip;
let data = $data;
match $has_zip.zip(data, &mut $zip) {
$crate::zip::Res::NYet(rgt) => rgt,
$crate::zip::Res::Done(data) => return data,
}
}};
}
pub mod unary {
pub use super::*;
pub enum Step<Key, Label, Info, Data> {
Lft(Key, Info, Zdd<Label>),
Rgt(Key, Info, Data),
}
pub trait Zip<Key, Label: Clone, Info, Data, Zip: super::Zipper<Step<Key, Label, Info, Data>>> {
fn cache_insert(&self, key: Key, data: &Data);
fn combine(&self, info: Info, lhs: Data, rhs: Data) -> Data;
fn zip(&self, mut data: Data, zip: &mut Zip) -> Res<Data, Zdd<Label>> {
loop {
data = match zip.pop() {
None => return Res::Done(data),
Some(Step::Lft(key, info, rgt)) => {
zip.push(Step::Rgt(key, info, data));
return Res::NYet(rgt);
}
Some(Step::Rgt(key, info, l_data)) => {
let data = self.combine(info, l_data, data);
self.cache_insert(key, &data);
data
}
}
}
}
}
}
pub mod binary {
use super::*;
pub enum Step<Key, Label, Info, Data> {
Lft(Key, Info, Zdd<Label>, Zdd<Label>),
TLft(Key, Info, Data),
Rgt(Key, Info, Data),
}
pub trait Zip<Key, Label, Info, Data, Zip: super::Zipper<Step<Key, Label, Info, Data>>> {
fn cache_insert(&self, key: Key, data: &Data);
fn combine(&self, info: Info, lhs: Data, rhs: Data) -> Data;
fn zip(&self, mut data: Data, zip: &mut Zip) -> Res<Data, (Zdd<Label>, Zdd<Label>)> {
loop {
data = match zip.pop() {
None => return Res::Done(data),
Some(Step::Lft(key, info, l_rgt, r_rgt)) => {
zip.push(Step::Rgt(key, info, data));
return Res::NYet((l_rgt, r_rgt));
}
Some(Step::TLft(key, info, r_data)) => {
let data = self.combine(info, data, r_data);
self.cache_insert(key, &data);
data
}
Some(Step::Rgt(key, info, l_data)) => {
let data = self.combine(info, l_data, data);
self.cache_insert(key, &data);
data
}
}
}
}
}
}