diff --git a/lib/cretonne/src/bforest/map.rs b/lib/cretonne/src/bforest/map.rs index e9709c0b17..45ff290ccd 100644 --- a/lib/cretonne/src/bforest/map.rs +++ b/lib/cretonne/src/bforest/map.rs @@ -118,6 +118,13 @@ where } } + /// Remove all entries. + pub fn clear(&mut self, forest: &mut MapForest) { + if let Some(root) = self.root.take() { + forest.nodes.free_tree(root); + } + } + /// Create a cursor for navigating this map. The cursor is initially positioned off the end of /// the map. pub fn cursor<'a>( @@ -322,6 +329,7 @@ mod test { let mut m = Map::::new(); assert!(m.is_empty()); + m.clear(&mut f); assert_eq!(m.get(7, &f, &()), None); @@ -459,6 +467,9 @@ mod test { m.insert(45, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(45, f, &()), Some(4.2)); + + m.clear(f); + assert!(m.is_empty()); } #[test] @@ -579,6 +590,9 @@ mod test { m.insert(805, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(805, f, &()), Some(4.2)); + + m.clear(f); + m.verify(f, &()); } // Make a tree with two barely healthy leaf nodes: diff --git a/lib/cretonne/src/bforest/pool.rs b/lib/cretonne/src/bforest/pool.rs index 778fa082f4..37801ee4ab 100644 --- a/lib/cretonne/src/bforest/pool.rs +++ b/lib/cretonne/src/bforest/pool.rs @@ -52,6 +52,20 @@ impl NodePool { self.nodes[node] = NodeData::Free { next: self.freelist }; self.freelist = Some(node); } + + /// Free the entire tree rooted at `node`. + pub fn free_tree(&mut self, node: Node) { + if let NodeData::Inner { size, tree, .. } = self[node] { + // Note that we have to capture `tree` by value to avoid borrow checker trouble. + for i in 0..usize::from(size + 1) { + // Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`, + // and since most trees have less than a handful of nodes, it is worthwhile to + // avoid the heap allocation for an iterative tree traversal. + self.free_tree(tree[i]); + } + } + self.free_node(node); + } } #[cfg(test)] diff --git a/lib/cretonne/src/bforest/set.rs b/lib/cretonne/src/bforest/set.rs index efdf39b4c7..b716cb2e33 100644 --- a/lib/cretonne/src/bforest/set.rs +++ b/lib/cretonne/src/bforest/set.rs @@ -115,6 +115,13 @@ where } } + /// Remove all entries. + pub fn clear(&mut self, forest: &mut SetForest) { + if let Some(root) = self.root.take() { + forest.nodes.free_tree(root); + } + } + /// Create a cursor for navigating this set. The cursor is initially positioned off the end of /// the set. pub fn cursor<'a>( @@ -283,6 +290,7 @@ mod test { let mut s = Set::::new(); assert!(s.is_empty()); + s.clear(&mut f); assert!(!s.contains(7, &f, &())); let c = SetCursor::new(&mut s, &mut f, &()); @@ -483,4 +491,10 @@ mod test { assert!(c.is_empty()); } + #[test] + fn four_level_clear() { + let mut f = SetForest::::new(); + let mut s = dense4l(&mut f); + s.clear(&mut f); + } }