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
5 changes: 4 additions & 1 deletion src/dense_byte_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,10 @@ impl<V: Clone + Send + Sync, A: Allocator, Cf: CoFree<V=V, A=A>> TrieNode<V, A>
}

fn node_remove_unmasked_branches(&mut self, key: &[u8], mask: ByteMask, _prune: bool) {
debug_assert!(key.len() == 0);
if key.len() > 0 {
//We're in a non-existent path below this node
return
}
// in the future we can use `drain_filter`, but that's experimental
let mut lead = 0;
let mut differs = false;
Expand Down
30 changes: 10 additions & 20 deletions src/experimental/zipper_algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,13 +515,11 @@ where
Out: ZipperWriting<V, A>,
{
if *lhs_grafts != ByteMask::EMPTY {
out.graft_masked_branches(lhs, *lhs_grafts, false);
*lhs_grafts = ByteMask::EMPTY;
out.graft_masked_branches(lhs, std::mem::take(lhs_grafts), false);
}

if *rhs_grafts != ByteMask::EMPTY {
out.graft_masked_branches(rhs, *rhs_grafts, false);
*rhs_grafts = ByteMask::EMPTY;
out.graft_masked_branches(rhs, std::mem::take(rhs_grafts), false);
}
}

Expand Down Expand Up @@ -731,18 +729,15 @@ where
Out: ZipperWriting<V, A>,
{
if *lhs_grafts != ByteMask::EMPTY {
out.graft_masked_branches(lhs, *lhs_grafts, false);
*lhs_grafts = ByteMask::EMPTY;
out.graft_masked_branches(lhs, std::mem::take(lhs_grafts), false);
}

if *mid_grafts != ByteMask::EMPTY {
out.graft_masked_branches(mid, *mid_grafts, false);
*mid_grafts = ByteMask::EMPTY;
out.graft_masked_branches(mid, std::mem::take(mid_grafts), false);
}

if *rhs_grafts != ByteMask::EMPTY {
out.graft_masked_branches(rhs, *rhs_grafts, false);
*rhs_grafts = ByteMask::EMPTY;
out.graft_masked_branches(rhs, std::mem::take(rhs_grafts), false);
}
}

Expand Down Expand Up @@ -1016,23 +1011,19 @@ fn zipper_merge4<P, V, Z0, Z1, Z2, Z3, Out, A>(
Out: ZipperWriting<V, A>,
{
if *z0_grafts != ByteMask::EMPTY {
out.graft_masked_branches(z0, *z0_grafts, false);
*z0_grafts = ByteMask::EMPTY;
out.graft_masked_branches(z0, std::mem::take(z0_grafts), false);
}

if *z1_grafts != ByteMask::EMPTY {
out.graft_masked_branches(z1, *z1_grafts, false);
*z1_grafts = ByteMask::EMPTY;
out.graft_masked_branches(z1, std::mem::take(z1_grafts), false);
}

if *z2_grafts != ByteMask::EMPTY {
out.graft_masked_branches(z2, *z2_grafts, false);
*z2_grafts = ByteMask::EMPTY;
out.graft_masked_branches(z2, std::mem::take(z2_grafts), false);
}

if *z3_grafts != ByteMask::EMPTY {
out.graft_masked_branches(z3, *z3_grafts, false);
*z3_grafts = ByteMask::EMPTY;
out.graft_masked_branches(z3, std::mem::take(z3_grafts), false);
}
}

Expand Down Expand Up @@ -1674,8 +1665,7 @@ where
{
for_each_bit(active, |i| {
if grafts[i] != ByteMask::EMPTY {
out.graft_masked_branches(&zs[i], grafts[i], false);
grafts[i] = ByteMask::EMPTY;
out.graft_masked_branches(&zs[i], std::mem::take(&mut grafts[i]), false);
}
});
}
Expand Down
156 changes: 103 additions & 53 deletions src/write_zipper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ pub trait ZipperWriting<V: Clone + Send + Sync, A: Allocator = GlobalAlloc>: Wri
///
/// Set bits that correspond to non-existent branches in `src` will be non-existent in `self` after this
/// function completes.
///
/// WARNING: The implementation may reserve space based on every set bit in `child_mask`, including for
/// branches that are absent from `src`. Don't use a mask with vastly more set bits than source branches to
/// avoid unnecessarily large allocations.
fn graft_masked_branches<Z: ZipperInfallibleSubtries<V, A>>(&mut self, src: &Z, child_mask: ByteMask, remove_unset: bool) {
if remove_unset {
self.remove_branches(false);
Expand Down Expand Up @@ -1501,66 +1505,100 @@ impl <'a, 'path, V: Clone + Send + Sync + Unpin, A: Allocator + 'a> WriteZipperC
}
/// See [ZipperWriting::graft_masked_branches]
pub fn graft_masked_branches<Z: ZipperInfallibleSubtries<V, A>>(&mut self, src: &Z, child_mask: ByteMask, remove_unset: bool) {
match src.get_focus().try_as_tagged() {
Some(src_tagged) => {
// Split the focus if we're in the middle of another node
let self_focus_node = match self.try_borrow_focus_mut() {
Some(node) => node,
None => {
self.split_at_focus();
self.try_borrow_focus_mut().unwrap()
}
};
match src_tagged {
TaggedNodeRef::DenseByteNode(src_node) => {
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, true>(self_focus_node, src_node, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, false>(self_focus_node, src_node, child_mask);
}
},
TaggedNodeRef::CellByteNode(src_node) => {
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::CellCoFree<V, A>, true>(self_focus_node, src_node, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::CellCoFree<V, A>, false>(self_focus_node, src_node, child_mask);
}
},
TaggedNodeRef::LineListNode(src_node) => {
let mut src_node = src_node.clone();
let src_dense = src_node.convert_to_dense::<crate::dense_byte_node::OrdinaryCoFree<V, A>>(3);
let src_dense = src_dense.as_tagged().as_dense().unwrap();
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, true>(self_focus_node, src_dense, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, false>(self_focus_node, src_dense, child_mask);
}
},
TaggedNodeRef::TinyRefNode(src_node) => {
let mut src_node = src_node.into_full().unwrap();
let src_dense = src_node.convert_to_dense::<crate::dense_byte_node::OrdinaryCoFree<V, A>>(3);
let src_dense = src_dense.as_tagged().as_dense().unwrap();
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, true>(self_focus_node, src_dense, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, false>(self_focus_node, src_dense, child_mask);
match child_mask.count_bits() {
0 => {
if remove_unset {
self.remove_branches(false);
}
}
1 => {
if remove_unset {
self.remove_branches(false);
}

let byte = child_mask.indexed_bit::<true>(0).expect("one bit set");
self.descend_to_byte(byte);
self.graft_src_at(src, &[byte]);
self.ascend_byte();
}
2 => {
if remove_unset {
self.remove_branches(false);
}

let first_byte = child_mask.indexed_bit::<true>(0).expect("some bit set");
self.descend_to_byte(first_byte);
self.graft_src_at(src, &[first_byte]);
self.ascend_byte();

let second_byte = child_mask.next_bit(first_byte).expect("two bits set");
self.descend_to_byte(second_byte);
self.graft_src_at(src, &[second_byte]);
self.ascend_byte();
}
_ => {
match src.get_focus().try_as_tagged() {
Some(src_tagged) => {
// Split the focus if we're in the middle of another node
let self_focus_node = match self.try_borrow_focus_mut() {
Some(node) => node,
None => {
self.split_at_focus();
self.try_borrow_focus_mut().unwrap()
}
};
match src_tagged {
TaggedNodeRef::DenseByteNode(src_node) => {
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, true>(self_focus_node, src_node, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, false>(self_focus_node, src_node, child_mask);
}
},
TaggedNodeRef::CellByteNode(src_node) => {
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::CellCoFree<V, A>, true>(self_focus_node, src_node, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::CellCoFree<V, A>, false>(self_focus_node, src_node, child_mask);
}
},
TaggedNodeRef::LineListNode(src_node) => {
let mut src_node = src_node.clone();
let src_dense = src_node.convert_to_dense::<crate::dense_byte_node::OrdinaryCoFree<V, A>>(3);
let src_dense = src_dense.as_tagged().as_dense().unwrap();
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, true>(self_focus_node, src_dense, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, false>(self_focus_node, src_dense, child_mask);
}
},
TaggedNodeRef::TinyRefNode(src_node) => {
let mut src_node = src_node.into_full().unwrap();
let src_dense = src_node.convert_to_dense::<crate::dense_byte_node::OrdinaryCoFree<V, A>>(3);
let src_dense = src_dense.as_tagged().as_dense().unwrap();
if remove_unset {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, true>(self_focus_node, src_dense, child_mask);
} else {
Self::merge_branches_into_focus::<crate::dense_byte_node::OrdinaryCoFree<V, A>, false>(self_focus_node, src_dense, child_mask);
}
},
TaggedNodeRef::EmptyNode => {
if remove_unset {
self.remove_branches(false);
} else {
self.remove_unmasked_branches(child_mask.not(), false);
}
},
}
},
TaggedNodeRef::EmptyNode => {
None => {
debug_assert_eq!(src.child_count(), 0);
if remove_unset {
self.remove_branches(false);
} else {
self.remove_unmasked_branches(child_mask.not(), false);
}
},
}
},
None => {
debug_assert_eq!(src.child_count(), 0);
if remove_unset {
self.remove_branches(false);
} else {
self.remove_unmasked_branches(child_mask.not(), false);
}
}
}
}
Expand Down Expand Up @@ -4364,6 +4402,18 @@ mod tests {
//Garfield was removed
assert_eq!(wr.val(), None);
}

#[test]
fn write_zipper_test_remove_unmasked_branches_non_existent_path() {
let mut map: PathMap<()> = PathMap::new();
for key in [b"a".as_slice(), b"b", b"c"] {
map.set_val_at(key, ());
}

let mut wz = map.write_zipper_at_path(b"a:x");
wz.remove_unmasked_branches(ByteMask::EMPTY, false);
}

#[test]
fn write_zipper_test_zipper_conversion() {
let keys = [
Expand Down