Add util::tree::remove_child, and some tests. Add eq requirement for util::tree::WriteMethods

This commit is contained in:
Brian J. Burg 2012-10-12 17:37:36 -07:00
parent 9c982693e1
commit 77c1b060fd
3 changed files with 119 additions and 11 deletions

View file

@ -158,6 +158,8 @@ impl NodeScope : tree::WriteMethods<Node> {
tree::add_child(&self, node, child) tree::add_child(&self, node, child)
} }
pure fn eq(a: &Node, b: &Node) -> bool { a == b }
fn with_tree_fields<R>(node: &Node, f: fn(&tree::Tree<Node>) -> R) -> R { fn with_tree_fields<R>(node: &Node, f: fn(&tree::Tree<Node>) -> R) -> R {
self.write(node, |n| f(&n.tree)) self.write(node, |n| f(&n.tree))
} }

View file

@ -326,10 +326,11 @@ impl FlowTree : tree::ReadMethods<@FlowContext> {
impl FlowTree : tree::WriteMethods<@FlowContext> { impl FlowTree : tree::WriteMethods<@FlowContext> {
fn add_child(parent: @FlowContext, child: @FlowContext) { fn add_child(parent: @FlowContext, child: @FlowContext) {
assert !core::box::ptr_eq(parent, child);
tree::add_child(&self, parent, child) tree::add_child(&self, parent, child)
} }
pure fn eq(a: &@FlowContext, b: &@FlowContext) -> bool { core::box::ptr_eq(*a, *b) }
fn with_tree_fields<R>(box: &@FlowContext, f: fn(&tree::Tree<@FlowContext>) -> R) -> R { fn with_tree_fields<R>(box: &@FlowContext, f: fn(&tree::Tree<@FlowContext>) -> R) -> R {
f(&box.d().tree) f(&box.d().tree)
} }

View file

@ -18,6 +18,7 @@ pub trait ReadMethods<T> {
pub trait WriteMethods<T> { pub trait WriteMethods<T> {
fn with_tree_fields<R>(&T, f: fn(&Tree<T>) -> R) -> R; fn with_tree_fields<R>(&T, f: fn(&Tree<T>) -> R) -> R;
pure fn eq(&T, &T) -> bool;
} }
pub fn each_child<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T, f: fn(&T) -> bool) { pub fn each_child<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T, f: fn(&T) -> bool) {
@ -42,6 +43,7 @@ pub fn empty<T>() -> Tree<T> {
} }
pub fn add_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) { pub fn add_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
assert !ops.eq(&parent, &child);
ops.with_tree_fields(&child, |child_tf| { ops.with_tree_fields(&child, |child_tf| {
match child_tf.parent { match child_tf.parent {
@ -58,7 +60,6 @@ pub fn add_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
parent_tf.first_child = Some(child); parent_tf.first_child = Some(child);
} }
Some(lc) => { Some(lc) => {
let lc = lc; // satisfy alias checker
ops.with_tree_fields(&lc, |lc_tf| { ops.with_tree_fields(&lc, |lc_tf| {
assert lc_tf.next_sibling.is_none(); assert lc_tf.next_sibling.is_none();
lc_tf.next_sibling = Some(child); lc_tf.next_sibling = Some(child);
@ -72,36 +73,90 @@ pub fn add_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
}); });
} }
pub fn remove_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
do ops.with_tree_fields(&child) |child_tf| {
match copy child_tf.parent {
None => { fail ~"Not a child"; }
Some(parent_n) => {
assert ops.eq(&parent, &parent_n);
// adjust parent fields
do ops.with_tree_fields(&parent) |parent_tf| {
match copy parent_tf.first_child {
None => { fail ~"parent had no first child??" },
Some(first_child) if ops.eq(&child, &first_child) => {
parent_tf.first_child = child_tf.next_sibling;
},
Some(_) => {}
};
match copy parent_tf.last_child {
None => { fail ~"parent had no last child??" },
Some(last_child) if ops.eq(&child, &last_child) => {
parent_tf.last_child = child_tf.prev_sibling;
},
Some(_) => {}
}
}
}
}
// adjust siblings
match child_tf.prev_sibling {
None => {},
Some(_) => {
do ops.with_tree_fields(&child_tf.prev_sibling.get()) |prev_tf| {
prev_tf.next_sibling = child_tf.next_sibling;
}
}
}
match child_tf.next_sibling {
None => {},
Some(_) => {
do ops.with_tree_fields(&child_tf.next_sibling.get()) |next_tf| {
next_tf.prev_sibling = child_tf.prev_sibling;
}
}
}
// clear child
child_tf.parent = None;
child_tf.next_sibling = None;
child_tf.prev_sibling = None;
}
}
pub fn get_parent<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> { pub fn get_parent<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
ops.with_tree_fields(node, |tf| tf.parent) ops.with_tree_fields(node, |tf| tf.parent)
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
enum dummy = @{ enum dummy = {
fields: Tree<dummy>, fields: Tree<@dummy>,
value: uint value: uint
}; };
enum dtree { dtree } enum dtree { dtree }
impl dtree : ReadMethods<dummy> { impl dtree : ReadMethods<@dummy> {
fn with_tree_fields<R>(d: &dummy, f: fn(&Tree<dummy>) -> R) -> R { fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
f(&d.fields) f(&d.fields)
} }
} }
impl dtree : WriteMethods<dummy> { impl dtree : WriteMethods<@dummy> {
fn with_tree_fields<R>(d: &dummy, f: fn(&Tree<dummy>) -> R) -> R { fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
f(&d.fields) f(&d.fields)
} }
pure fn eq(a: &@dummy, b: &@dummy) -> bool { core::box::ptr_eq(*a, *b) }
} }
fn new_dummy(v: uint) -> dummy { fn new_dummy(v: uint) -> @dummy {
dummy(@{fields: empty(), value: v}) @dummy({fields: empty(), value: v})
} }
fn parent_with_3_children() -> {p: dummy, children: ~[dummy]} { fn parent_with_3_children() -> {p: @dummy, children: ~[@dummy]} {
let children = ~[new_dummy(0u), let children = ~[new_dummy(0u),
new_dummy(1u), new_dummy(1u),
new_dummy(2u)]; new_dummy(2u)];
@ -135,4 +190,54 @@ mod test {
} }
assert i == 1u; assert i == 1u;
} }
#[test]
fn remove_first_child() {
let {p, children} = parent_with_3_children();
remove_child(&dtree, p, children[0]);
let mut i = 0;
for each_child(&dtree, &p) |_c| {
i += 1;
}
assert i == 2;
}
#[test]
fn remove_last_child() {
let {p, children} = parent_with_3_children();
remove_child(&dtree, p, children[2]);
let mut i = 0;
for each_child(&dtree, &p) |_c| {
i += 1;
}
assert i == 2;
}
#[test]
fn remove_middle_child() {
let {p, children} = parent_with_3_children();
remove_child(&dtree, p, children[1]);
let mut i = 0;
for each_child(&dtree, &p) |_c| {
i += 1;
}
assert i == 2;
}
#[test]
fn remove_all_child() {
let {p, children} = parent_with_3_children();
remove_child(&dtree, p, children[0]);
remove_child(&dtree, p, children[1]);
remove_child(&dtree, p, children[2]);
let mut i = 0;
for each_child(&dtree, &p) |_c| {
i += 1;
}
assert i == 0;
}
} }