mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Add util::tree::remove_child, and some tests. Add eq requirement for util::tree::WriteMethods
This commit is contained in:
parent
9c982693e1
commit
77c1b060fd
3 changed files with 119 additions and 11 deletions
|
@ -158,6 +158,8 @@ impl NodeScope : tree::WriteMethods<Node> {
|
|||
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 {
|
||||
self.write(node, |n| f(&n.tree))
|
||||
}
|
||||
|
|
|
@ -326,10 +326,11 @@ impl FlowTree : tree::ReadMethods<@FlowContext> {
|
|||
|
||||
impl FlowTree : tree::WriteMethods<@FlowContext> {
|
||||
fn add_child(parent: @FlowContext, child: @FlowContext) {
|
||||
assert !core::box::ptr_eq(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 {
|
||||
f(&box.d().tree)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ pub trait ReadMethods<T> {
|
|||
|
||||
pub trait WriteMethods<T> {
|
||||
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) {
|
||||
|
@ -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) {
|
||||
assert !ops.eq(&parent, &child);
|
||||
|
||||
ops.with_tree_fields(&child, |child_tf| {
|
||||
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);
|
||||
}
|
||||
Some(lc) => {
|
||||
let lc = lc; // satisfy alias checker
|
||||
ops.with_tree_fields(&lc, |lc_tf| {
|
||||
assert lc_tf.next_sibling.is_none();
|
||||
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> {
|
||||
ops.with_tree_fields(node, |tf| tf.parent)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
enum dummy = @{
|
||||
fields: Tree<dummy>,
|
||||
enum dummy = {
|
||||
fields: Tree<@dummy>,
|
||||
value: uint
|
||||
};
|
||||
|
||||
enum dtree { dtree }
|
||||
|
||||
impl dtree : ReadMethods<dummy> {
|
||||
fn with_tree_fields<R>(d: &dummy, f: fn(&Tree<dummy>) -> R) -> R {
|
||||
impl dtree : ReadMethods<@dummy> {
|
||||
fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
|
||||
f(&d.fields)
|
||||
}
|
||||
}
|
||||
|
||||
impl dtree : WriteMethods<dummy> {
|
||||
fn with_tree_fields<R>(d: &dummy, f: fn(&Tree<dummy>) -> R) -> R {
|
||||
impl dtree : WriteMethods<@dummy> {
|
||||
fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
|
||||
f(&d.fields)
|
||||
}
|
||||
pure fn eq(a: &@dummy, b: &@dummy) -> bool { core::box::ptr_eq(*a, *b) }
|
||||
}
|
||||
|
||||
fn new_dummy(v: uint) -> dummy {
|
||||
dummy(@{fields: empty(), value: v})
|
||||
fn new_dummy(v: uint) -> @dummy {
|
||||
@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),
|
||||
new_dummy(1u),
|
||||
new_dummy(2u)];
|
||||
|
@ -135,4 +190,54 @@ mod test {
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue