Skip to content

Commit 46d53ff

Browse files
authored
feat: add traverse_mut method (#6)
1 parent 86490ac commit 46d53ff

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "easy-tree"
3-
version = "0.1.3"
3+
version = "0.2.0"
44
authors = ["Anton Suprunchuk <[email protected]>"]
55
edition = "2021"
66
description = "A simple and efficient tree structure library for Rust with recursive traversal"

src/lib.rs

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ impl<T> Node<T> {
213213
#[derive(Clone)]
214214
pub struct Tree<T> {
215215
nodes: Vec<Node<T>>,
216+
/// Stack for traverse_mut to avoid allocations
217+
stack: Vec<(usize, bool)>,
216218
}
217219

218220
impl<T> Default for Tree<T> {
@@ -234,7 +236,10 @@ impl<T> Tree<T> {
234236
/// let tree: Tree<i32> = Tree::new();
235237
/// ```
236238
pub fn new() -> Self {
237-
Self { nodes: Vec::new() }
239+
Self {
240+
nodes: Vec::new(),
241+
stack: Vec::new(),
242+
}
238243
}
239244

240245
/// Adds a new node to the tree.
@@ -523,6 +528,42 @@ impl<T> Tree<T> {
523528
}
524529
}
525530

531+
/// Walks the tree recursively, applying the given functions before and after processing the
532+
/// children of each node. This version allows for mutable access to the nodes.
533+
pub fn traverse_mut<S>(
534+
&mut self,
535+
mut before_processing_children: impl FnMut(usize, &mut T, &mut S),
536+
mut after_processing_the_subtree: impl FnMut(usize, &mut T, &mut S),
537+
s: &mut S,
538+
) {
539+
if self.is_empty() {
540+
return;
541+
}
542+
543+
self.stack.clear();
544+
self.stack.push((0, false));
545+
546+
while let Some((index, children_visited)) = self.stack.pop() {
547+
if children_visited {
548+
// All children are processed, call f2
549+
let node = &mut self.nodes[index];
550+
after_processing_the_subtree(index, &mut node.data, s);
551+
} else {
552+
// Call f and mark this node's children for processing
553+
let node = &mut self.nodes[index];
554+
before_processing_children(index, &mut node.data, s);
555+
556+
// Re-push the current node with children_visited set to true
557+
self.stack.push((index, true));
558+
559+
// Push all children onto the stack
560+
for &child in node.children.iter().rev() {
561+
self.stack.push((child, false));
562+
}
563+
}
564+
}
565+
}
566+
526567
/// Returns an iterator over the indices and data of the nodes in the tree.
527568
pub fn iter(&self) -> impl Iterator<Item = (usize, &T)> {
528569
self.nodes
@@ -646,13 +687,10 @@ mod tests {
646687
let mut result = vec![];
647688

648689
tree.traverse(
649-
|index, node, result| {
650-
result.push(format!("Calling handler for node {}: {}", index, node))
651-
},
690+
|index, node, result| result.push(format!("Calling handler for node {index}: {node}")),
652691
|index, _node, result| {
653692
result.push(format!(
654-
"Finished handling node {} and all it's children",
655-
index
693+
"Finished handling node {index} and all its children"
656694
))
657695
},
658696
&mut result,
@@ -664,11 +702,11 @@ mod tests {
664702
"Calling handler for node 0: 0",
665703
"Calling handler for node 1: 1",
666704
"Calling handler for node 3: 3",
667-
"Finished handling node 3 and all it's children",
668-
"Finished handling node 1 and all it's children",
705+
"Finished handling node 3 and all its children",
706+
"Finished handling node 1 and all its children",
669707
"Calling handler for node 2: 2",
670-
"Finished handling node 2 and all it's children",
671-
"Finished handling node 0 and all it's children",
708+
"Finished handling node 2 and all its children",
709+
"Finished handling node 0 and all its children",
672710
]
673711
);
674712
}

0 commit comments

Comments
 (0)