Repository navigation
Conversation
|
Nice! I quite like the API and naming. |
|
I'm ok with the API concept. I'd prefer different names for The word On the word
As far as |
|
I think the most important part not covered there is that you want to take these zippers at a path, you may not have access to the root, nor want to pay the cost of re-descending. |
There are two possible interpretations of what you might want: 1. The ZipperBuffer represents the But if I assume you want 2. it does mean there is now a failure mode where the beginning of the buffer deviates from the So the ZH version of
Some amount of re-descending is unavoidable. There is no way a node stack can be transplanted from one base to another without redoing the work to descend from the new base. |
1c2a2ca to
5e4e6a7
Compare
A ZipperBuffer holds the path and ancestor-stack allocations of a read
zipper, so a later zipper can reuse them instead of growing new ones.
- ReadZipper{Untracked,Tracked,Owned}::into_zipper_buffer consumes a zipper
and keeps its (emptied) buffers
- PathMap::read_zipper_with_buffer creates a zipper at the map root on top
of a buffer
- ReadZipper{Untracked,Tracked}::clone_with_buffer is Clone, but writes the
path and ancestor stack into the buffer's allocations
The ancestor stack's element type borrows from the map, so the buffer
stores that allocation with its element type erased; traversal code is
unchanged.
5e4e6a7 to
81a420c
Compare
A WriteZipperBuffer holds the path, key-index and node-stack allocations
of a write zipper, so a later write zipper can reuse them.
- WriteZipper{Untracked,Tracked,Owned}::into_zipper_buffer consumes a
zipper and keeps its (emptied) buffers
- PathMap::write_zipper_with_buffer creates a write zipper at the map root
on top of a buffer
- ZipperCreation::write_zipper_at_exclusive_path_with_buffer(_unchecked)
creates a ZipperHead write zipper on top of a buffer
|
To reiterate what I said on discord (for the sake of project memory) I think it's crucial to document why these methods exist. I.e. that they are only optimizations to enable allocations to be reused; they don't provide any functionality beyond performance for rapid zipper destruction and recreation. There may still be a use for the methods, for the node stack, even after the path buffer is moved outside the zipper. But the people who will want to bother with them is probably limited to a very small handful. |
let mut map = PathMap::<usize>::new();
map.set_val_at(b"ab", 1);
let zh = map.zipper_head();
let (cloned, buffered) = {
let rz = zh.read_zipper_at_path(b"ab").unwrap();
let buffer = PathMap::<usize>::new().read_zipper().into_zipper_buffer();
(rz.clone(), rz.clone_with_buffer(buffer))
};
let _junk = Box::new([0xdead_usize; 2]);
println!("clone() -> {:?}", cloned.val());
println!("clone_with_buffer() -> {:?}", buffered.val()); |
This introduces
ZipperBuffer&WriteZipperBuffer. They are different because they store different things.This allows re-using zipper path and stack
Vecs.