Skip to content

Commit fd787df

Browse files
authored
Merge pull request #30 from rust-scraper/shouya/master
Add support for appending and prepending subtree
2 parents f43f884 + b6316ab commit fd787df

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/lib.rs

+36
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,30 @@ impl<T> Tree<T> {
205205
self.vec.push(Node::new(value));
206206
unsafe { self.get_unchecked_mut(id) }
207207
}
208+
209+
/// Merge with another tree as orphan, returning the new root of tree being merged.
210+
// Allowing this for compactness.
211+
#[allow(clippy::option_map_unit_fn)]
212+
pub fn extend_tree(&mut self, mut other_tree: Tree<T>) -> NodeMut<T> {
213+
let offset = self.vec.len();
214+
let offset_id = |id: NodeId| -> NodeId {
215+
let old_index = id.to_index();
216+
let new_index = old_index + offset;
217+
unsafe { NodeId::from_index(new_index) }
218+
};
219+
let other_tree_root_id = offset_id(other_tree.root().id);
220+
for node in other_tree.vec.iter_mut() {
221+
node.parent.as_mut().map(|id| *id = offset_id(*id));
222+
node.prev_sibling.as_mut().map(|id| *id = offset_id(*id));
223+
node.next_sibling.as_mut().map(|id| *id = offset_id(*id));
224+
node.children.as_mut().map(|(id1, id2)| {
225+
*id1 = offset_id(*id1);
226+
*id2 = offset_id(*id2);
227+
});
228+
}
229+
self.vec.extend(other_tree.vec);
230+
unsafe { self.get_unchecked_mut(other_tree_root_id) }
231+
}
208232
}
209233

210234
impl<'a, T: 'a> NodeRef<'a, T> {
@@ -341,6 +365,18 @@ impl<'a, T: 'a> NodeMut<'a, T> {
341365
self.prepend_id(id)
342366
}
343367

368+
/// Appends a subtree, return the root of the merged subtree.
369+
pub fn append_subtree(&mut self, subtree: Tree<T>) -> NodeMut<T> {
370+
let root_id = self.tree.extend_tree(subtree).id;
371+
self.append_id(root_id)
372+
}
373+
374+
/// Prepends a subtree, return the root of the merged subtree.
375+
pub fn prepend_subtree(&mut self, subtree: Tree<T>) -> NodeMut<T> {
376+
let root_id = self.tree.extend_tree(subtree).id;
377+
self.prepend_id(root_id)
378+
}
379+
344380
/// Inserts a new sibling before this node.
345381
///
346382
/// # Panics

tests/subtree.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#[macro_use]
2+
extern crate ego_tree;
3+
4+
#[cfg(test)]
5+
mod test {
6+
#[test]
7+
fn prepend_subtree() {
8+
let mut tree = tree!('a' => { 'b', 'c' => { 'd', 'e' } });
9+
let node_id = tree.root().first_child().unwrap().id();
10+
let mut node = tree.get_mut(node_id).unwrap();
11+
assert_eq!(node.value(), &'b');
12+
13+
let subtree = tree!('f' => { 'g', 'h' => { 'i', 'j' } });
14+
let mut root_subtree = node.prepend_subtree(subtree);
15+
assert_eq!(root_subtree.parent().unwrap().value(), &'b');
16+
assert_eq!(
17+
root_subtree.parent().unwrap().parent().unwrap().value(),
18+
&'a'
19+
);
20+
21+
let new_tree =
22+
tree!('a' => { 'b' => { 'f' => { 'g', 'h' => { 'i', 'j' } } }, 'c' => { 'd', 'e' } });
23+
assert_eq!(format!("{:#?}", tree), format!("{:#?}", new_tree));
24+
}
25+
26+
#[test]
27+
fn append_subtree() {
28+
let mut tree = tree!('a' => { 'b', 'c' });
29+
let mut node = tree.root_mut();
30+
assert_eq!(node.value(), &'a');
31+
32+
let subtree = tree!('d' => { 'e', 'f' });
33+
let mut root_subtree = node.append_subtree(subtree);
34+
assert_eq!(root_subtree.parent().unwrap().value(), &'a');
35+
36+
let new_tree = tree!('a' => { 'b', 'c', 'd' => { 'e', 'f' } });
37+
assert_eq!(format!("{:#?}", tree), format!("{:#?}", new_tree));
38+
}
39+
}

0 commit comments

Comments
 (0)