You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds benchmark coverage for graft behavior, node layout, prefix and product cases, streaming cases, write zipper cases, and owned zipper head cases.
The grouped graft benchmark exposed an existing graft_child_maps panic at zipper node boundaries. The branch now also fixes with_node_at_path so it does not ask a trie node for a child using an empty node key when the zipper is already at a node boundary.
Validation:
cargo check --benches
cargo test write_zipper_graft_child_maps_zero_child_with_root_value --lib
Benchmarking graft_child_maps/grouped_keep_unset/contiguous/1: Warming up for 150.00 ms
thread 'main' (9746966) panicked at src/dense_byte_node.rs:637:28:
index out of bounds: the len is 0 but the index is 0
stack backtrace:
0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: core::panicking::panic_bounds_check
3: <pathmap::trie_node::tagged_node_ref::TaggedNodeRefMut<u32, ()>>::node_get_child_mut
4: <pathmap::write_zipper::WriteZipperCore<u32, ()>>::graft_child_maps::<alloc::vec::Vec<pathmap::trie_map::PathMap<u32>>>
5: graft_child_maps_criterion::grouped_graft
6: <criterion::bencher::Bencher>::iter_batched::<(pathmap::trie_map::PathMap<u32>, alloc::vec::Vec<pathmap::trie_map::PathMap<u32>>, pathmap::utils::ByteMask), usize, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}::{closure#0}, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}::{closure#1}>
7: <criterion::routine::Function<criterion::measurement::WallTime, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}, graft_child_maps_criterion::GraftFixture> as criterion::routine::Routine<criterion::measurement::WallTime, graft_child_maps_criterion::GraftFixture>>::warm_up
8: <criterion::routine::Function<criterion::measurement::WallTime, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}, graft_child_maps_criterion::GraftFixture> as criterion::routine::Routine<criterion::measurement::WallTime, graft_child_maps_criterion::GraftFixture>>::sample
9: criterion::analysis::common::<criterion::measurement::WallTime, graft_child_maps_criterion::GraftFixture>
10: <criterion::benchmark_group::BenchmarkGroup<criterion::measurement::WallTime>>::bench_with_input::<criterion::benchmark_group::BenchmarkId, graft_child_maps_criterion::grouped_child_map_grafting::{closure#2}, graft_child_maps_criterion::GraftFixture>
11: graft_child_maps_criterion::main
The benchmark exposed a real bug in with_node_at_path. When the zipper is already at a node boundary, self.key.node_key() is empty, but the helper still called node_get_child_mut(key). DenseByteNode::node_get_child_mut expects a non-empty key. In debug builds that trips the assertion; in the bench profile it reaches the key[0] bounds check and panics with the out-of-bounds error you saw.
The fix skips the child lookup when the current node key is empty and uses the existing direct mutation path instead. I added write_zipper_graft_child_maps_zero_child_with_root_value to cover the zero child case with a root value and nested child data.
Checked locally:
cargo test write_zipper_graft_child_maps_zero_child_with_root_value --lib
confirmed gone. ran the exact bench on the parent commit and it still panics at dense_byte_node.rs:637, then on ad91856 it runs clean (grouped_keep_unset/contiguous/1 ~5.6µs).
the panic is just an empty key reaching node_get_child_mut. in release it's the key[0] index that blows up (what you saw), in debug the debug_assert!(key.len() > 0) in that same fn fires instead. nothing exercised a grouped graft sitting exactly on a node boundary before, so it slipped past the existing tests... write_zipper_graft_child_maps_zero_child_with_root_value locks that shape now.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds benchmark coverage for graft behavior, node layout, prefix and product cases, streaming cases, write zipper cases, and owned zipper head cases.
The grouped graft benchmark exposed an existing
graft_child_mapspanic at zipper node boundaries. The branch now also fixeswith_node_at_pathso it does not ask a trie node for a child using an empty node key when the zipper is already at a node boundary.Validation:
cargo check --benchescargo test write_zipper_graft_child_maps_zero_child_with_root_value --libcargo test --lib --testscargo bench --bench graft_child_maps_criterion -- graft_child_maps/grouped_keep_unset/contiguous/1 --warm-up-time 0.05 --measurement-time 0.1 --sample-size 10jscpd --reporters ai --format rust src/write_zipper.rs