use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;
use rand::Rng;
use adapton::macros::*;
use adapton::engine::*;
#[derive(Debug,PartialEq,Eq,Hash)]
pub struct Tree<E: 'static+Debug+Clone+Eq+Hash> {
level: u32,
name: Option<Name>,
link: Art<TreeNode<E>>
}
#[derive(Debug,PartialEq,Eq,Clone,Hash)]
struct TreeNode<E: 'static+Debug+Clone+Eq+Hash>{
data: E,
l_branch: Option<Tree<E>>,
r_branch: Option<Tree<E>>
}
impl<E: Debug+Clone+Eq+Hash+'static>
Tree<E> {
pub fn new(
level: u32,
name: Option<Name>,
data: E,
l_branch: Option<Tree<E>>,
r_branch: Option<Tree<E>>
) -> Option<Tree<E>> {
match name {
Some(name) => Some(Tree{
level: level, name: Some(name.clone()),
link: cell(name, TreeNode{
data: data,
l_branch: l_branch,
r_branch: r_branch
})
}),
None => Some(Tree{
level: level, name: None,
link: put(TreeNode{
data: data,
l_branch: l_branch,
r_branch: r_branch
})
}),
}
}
pub fn level(&self) -> u32 { self.level }
pub fn name(&self) -> Option<Name> { self.name.clone() }
pub fn l_tree(&self) -> Option<Tree<E>> { force(&self.link).l_branch.clone() }
pub fn r_tree(&self) -> Option<Tree<E>> { force(&self.link).r_branch.clone() }
pub fn peek(&self) -> E { force(&self.link).data }
pub fn fold_up<R:Eq+Clone+Hash+Debug+'static,F>(self, node_calc: Rc<F>) -> R where
F: 'static + Fn(Option<R>,E,Option<R>) -> R
{
self.fold_up_meta(Rc::new(move|l,d,_lv,_n,r|{node_calc(l,d,r)}))
}
pub fn fold_up_meta<R:Eq+Clone+Hash+Debug+'static,F>(self, node_calc: Rc<F>) -> R where
F: 'static + Fn(Option<R>,E,u32,Option<Name>,Option<R>) -> R
{
match force(&self.link) { TreeNode{ data, l_branch, r_branch } => {
let (l,r) = match self.name.clone() {
None => {(
l_branch.map(|t| t.fold_up_meta(node_calc.clone())),
r_branch.map(|t| t.fold_up_meta(node_calc.clone())),
)},
Some(name) => {
let (n1, n2) = name_fork(name);
(
l_branch.map(|t| memo!( n1 =>> Self::fold_up_meta , t:t ;; f:node_calc.clone() )),
r_branch.map(|t| memo!( n2 =>> Self::fold_up_meta , t:t ;; f:node_calc.clone() )),
)
}
};
node_calc(l, data, self.level, self.name, r)
}}
}
pub fn fold_lr<A,F>(self, accum: A, node_calc: Rc<F>) -> A where
A: 'static + Eq + Clone + Hash + Debug,
F: 'static + Fn(A,E) -> A,
{
let start_name = Some(name_of_string(String::from("start")));
self.fold_lr_meta(start_name,accum,Rc::new(move|a,e,_l,_n|{node_calc(a,e)}))
}
pub fn fold_lr_meta<A,F>(self, start_name: Option<Name>, accum: A, node_calc: Rc<F>) -> A where
A: 'static + Eq + Clone + Hash + Debug,
F: 'static + Fn(A,E,u32,Option<Name>) -> A,
{
let fold_memo = |memo_name:Option<Name>, carried_name:Option<Name>, accum, tree:Option<Tree<_>>|{
match tree { None => accum, Some(t) => {
match memo_name {
None => t.fold_lr_meta(carried_name,accum,node_calc.clone()),
Some(nm) => {
memo!(nm.clone() =>>
Self::fold_lr_meta, t:t, n:carried_name, a:accum ;; f:node_calc.clone()
)
}
}
}}
};
let (l_name,r_name) = match self.name.clone() {
None => (None,None),
Some(nm) => {
let (n1,n2) = name_fork(nm);
(Some(n1),Some(n2))
}
};
match force(&self.link) { TreeNode{ data, l_branch, r_branch } => {
match (l_branch,r_branch) {
(None, None) => node_calc(accum,data,self.level,start_name),
(l_branch, r_branch) => {
let accum = fold_memo(l_name,start_name,accum,l_branch);
let accum = node_calc(accum,data,self.level,self.name.clone());
let accum = fold_memo(r_name,self.name.clone(),accum,r_branch);
accum
},
}
}}
}
pub fn map<R:Eq+Clone+Hash+Debug+'static,F>(self, map_val: Rc<F>) -> Tree<R>
where
F: 'static + Fn(E,u32,Option<Name>,Option<&Tree<R>>,Option<&Tree<R>>) -> R
{
match force(&self.link) { TreeNode{ data, l_branch, r_branch } => {
let (l,r) = match self.name {
None => {(
l_branch.map(|t| t.map(map_val.clone())),
r_branch.map(|t| t.map(map_val.clone())),
)},
Some(ref name) => {
let (n1, n2) = name_fork(name.clone());
(
l_branch.map(|t| memo!( n1 =>> Self::map , t:t ;; f:map_val.clone() )),
r_branch.map(|t| memo!( n2 =>> Self::map , t:t ;; f:map_val.clone() )),
)
}
};
let new_data = map_val(data, self.level, self.name.clone(), l.as_ref(), r.as_ref());
Tree::new(self.level, self.name, new_data, l, r).unwrap()
}}
}
}
pub fn good_levels<E: Debug+Clone+Eq+Hash+'static>(tree: &Tree<E>) -> bool {
let mut good = true;
if let Some(ref t) = force(&tree.link).l_branch {
if t.level > tree.level {
println!("Tree with level {:?} has left branch with level {:?}", tree.level, t.level);
good = false;
}
if !good_levels(t) { good = false }
}
if let Some(ref t) = force(&tree.link).r_branch {
if t.level >= tree.level {
println!("Tree with level {:?} has right branch with level {:?}", tree.level, t.level);
good = false;
}
if !good_levels(t) { good = false }
}
good
}
impl<E: Debug+Clone+Eq+Hash+'static> Clone for Tree<E> {
fn clone(&self) -> Self {
Tree{level: self.level, name: self.name.clone(), link: self.link.clone()}
}
}
pub fn gen_branch_level<R:Rng>(rng: &mut R) -> u32 {
let num = rng.gen::<u64>();
(num << 1).trailing_zeros() as u32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fold_up() {
use std::cmp::max;
let t =
Tree::new(5, Some(name_of_usize(5)),None,
Tree::new(3, Some(name_of_usize(3)),None,
Tree::new(0,None,Some(1),None,None),
Tree::new(2, Some(name_of_usize(2)),None,
Tree::new(1, Some(name_of_usize(1)),None,
Tree::new(0,None,Some(2),None,None),
Tree::new(0,None,Some(3),None,None),
),
Tree::new(0,None,Some(4),None,None),
)
),
Tree::new(4, Some(name_of_usize(4)),None,
Tree::new(0,None,Some(5),None,None),
Tree::new(0,None,Some(6),None,None),
)
).unwrap();
let sum = t.clone().fold_up(Rc::new(|l: Option<usize>,c: Option<usize>,r: Option<usize>| {
l.unwrap_or(0) + c.unwrap_or(0) + r.unwrap_or(0)
}));
let depth = t.clone().fold_up(Rc::new(|l: Option<usize>,c: Option<usize>,r: Option<usize>| {
match c {
None => max(l.unwrap(),r.unwrap()) + 1,
Some(_) => 1,
}
}));
let in_order = t.clone().fold_up(Rc::new(|l: Option<bool>,c: Option<usize>,r: Option<bool>|{
match c {
None => l.unwrap() >= r.unwrap(),
Some(_) => true,
}
}));
assert_eq!(21, sum);
assert_eq!(5, depth);
assert_eq!(true, in_order);
}
#[test]
fn test_map() {
let t =
Tree::new(5, Some(name_of_usize(5)),None,
Tree::new(3, Some(name_of_usize(3)),None,
Tree::new(0,None,Some(1),None,None),
Tree::new(2, Some(name_of_usize(2)),None,
Tree::new(1, Some(name_of_usize(1)),None,
Tree::new(0,None,Some(2),None,None),
Tree::new(0,None,Some(3),None,None),
),
Tree::new(0,None,Some(4),None,None),
)
),
Tree::new(4, Some(name_of_usize(4)),None,
Tree::new(0,None,Some(5),None,None),
Tree::new(0,None,Some(6),None,None),
)
).unwrap();
let tree_plus1 = t.clone().map(Rc::new(|d: Option<usize>,_l,_n,_t1:Option<&_>,_t2:Option<&_>| {
d.map(|n|n+1)
}));
let leaf = tree_plus1.l_tree().unwrap().r_tree().unwrap().l_tree().unwrap().r_tree().unwrap();
assert_eq!(Some(4), leaf.peek());
let sum = tree_plus1.clone().fold_up(Rc::new(|l: Option<usize>,c: Option<usize>,r: Option<usize>| {
l.unwrap_or(0) + c.unwrap_or(0) + r.unwrap_or(0)
}));
assert_eq!(27, sum);
}
}