Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/line_list_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1925,15 +1925,16 @@ impl<V: Clone + Send + Sync, A: Allocator> TrieNode<V, A> for LineListNode<V, A>
remove_0 = !mask.test_bit(key0[key_len]);
} else {
//We can only get here if key0 == key, and the calling code should have descend
// through this node if that key specifies an onward link
debug_assert!(!self.is_child_ptr::<0>());
// through this node if that key specifies a non-dangling onward link
debug_assert!(!self.is_used_child_0() || unsafe{ self.child_in_slot::<0>().is_empty() });
}
}
if starts_with(key1, key) {
if key1.len() > key_len {
remove_1 = !mask.test_bit(key1[key_len]);
} else {
debug_assert!(!self.is_child_ptr::<1>()); //See comment above
//See comment above
debug_assert!(!self.is_used_child_1() || unsafe{ self.child_in_slot::<1>().is_empty() });
}
}
self.remove_subtries(remove_0, remove_1, key0_starts_with, prune, key.len());
Expand Down
42 changes: 37 additions & 5 deletions src/write_zipper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2269,18 +2269,18 @@ impl <'a, 'path, V: Clone + Send + Sync + Unpin, A: Allocator + 'a> WriteZipperC
}
/// See [WriteZipper::remove_unmasked_branches]
pub fn remove_unmasked_branches(&mut self, mask: ByteMask, prune: bool) {
let mut focus_node = self.focus_stack.top_mut().unwrap();
let node_key = self.key.node_key();
let mut focus_node = self.focus_stack.top_mut().unwrap();
if node_key.len() > 0 {
match focus_node.node_get_child_mut(node_key) {
Some((consumed_bytes, child_node)) => {
if node_key.len() >= consumed_bytes {
if node_key.len() >= consumed_bytes && !child_node.is_empty() {
child_node.make_mut().node_remove_unmasked_branches(&node_key[consumed_bytes..], mask, prune);
if child_node.as_tagged().node_is_empty() {
focus_node.node_remove_all_branches(&node_key[..consumed_bytes], prune);
}
} else {
//Zipper is positioned at non-existent node. Removing anything from nothing is nothing
//Zipper is positioned at non-existent or dangling node. Removing anything from nothing is nothing
}
},
None => {
Expand Down Expand Up @@ -3738,7 +3738,7 @@ mod tests {
assert_eq!(*wz.get_val_or_set_mut_with(|| 3), 3);
assert_eq!(wz.val(), Some(&3));
}
assert_eq!(m0.get_val_at(&[0u8, 0, 0]), Some(&3));
assert_eq!(m0.val_at(&[0u8, 0, 0]), Some(&3));
assert_eq!(m0.val_count(), 1);

// through meet_into with prune
Expand All @@ -3753,7 +3753,7 @@ mod tests {
assert_eq!(*wz.get_val_or_set_mut_with(|| 3), 3);
assert_eq!(wz.val(), Some(&3));
}
assert_eq!(m0.get_val_at(&[0u8, 0, 0]), Some(&3));
assert_eq!(m0.val_at(&[0u8, 0, 0]), Some(&3));
}


Expand Down Expand Up @@ -6753,6 +6753,38 @@ mod tests {
assert_eq!(keys(&m), ["cx", "cy", "d"]);
}

/// `remove_unmasked_branches` at or below a dangling path does nothing
#[test]
fn write_zipper_test_remove_unmasked_branches_dangling_focus() {
//List node root: onward link at [0], dangling stub at [1, 0]
let mut map = PathMap::<u64>::new();
map.set_val_at([0u8], 0);
map.set_val_at([0u8, 0], 1);
assert!(map.create_path([1u8, 0]));

//Focus exactly on the dangling path
let mut wz = map.write_zipper_at_path(&[1u8, 0]);
assert!(wz.path_exists());
wz.remove_unmasked_branches(ByteMask::EMPTY, false);
assert!(wz.path_exists());
drop(wz);

//Focus below the dangling path
let mut wz = map.write_zipper_at_path(&[1u8, 0, 7]);
wz.remove_unmasked_branches(ByteMask::EMPTY, false);
drop(wz);

//Nothing may have changed
assert_eq!(map.val_at([0u8]), Some(&0));
assert_eq!(map.val_at([0u8, 0]), Some(&1));
assert_eq!(map.val_at([1u8, 0]), None);
let mut rz = map.read_zipper();
rz.descend_to([1u8, 0]);
assert!(rz.path_exists());
drop(rz);
assert_eq!(map.val_count(), 2);
}

/// Every location in `map`, dangling ones included, with its value
fn all_locations(map: &PathMap<u64>) -> Vec<(Vec<u8>, Option<u64>)> {
let mut rz = map.read_zipper();
Expand Down
Loading