1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
//! This module contains the implementation of `clone()` for the trie.
use alloc::vec::Vec;
use crate::{
allocator::Allocator,
raw::{
match_concrete_inner_node_ptr, match_concrete_node_ptr, ConcreteInnerNodePtr,
ConcreteNodePtr, InnerNode, InnerNodeCommon, LeafNode, Node, NodePtr, OpaqueNodePtr,
},
AsBytes,
};
/// The result of cloning a trie
#[derive(Debug)]
pub struct CloneResult<K, V, const PREFIX_LEN: usize> {
/// The new root node of the trie
pub root: OpaqueNodePtr<K, V, PREFIX_LEN>,
/// The first leaf in the trie, aka the leaf with the minimum key
pub min_leaf: NodePtr<PREFIX_LEN, LeafNode<K, V, PREFIX_LEN>>,
/// The last leaf in the trie, aka the leaf with the maximum key
pub max_leaf: NodePtr<PREFIX_LEN, LeafNode<K, V, PREFIX_LEN>>,
}
/// Clone the given trie and all the key-values paired contained.
///
/// This function does not use recursion to clone, so it should not cause stack
/// overflow when cloning a deep trie.
///
/// # Safety
///
/// This function can only be called while there are no mutable references to
/// any of the nodes in this trie.
pub unsafe fn clone_unchecked<
K: Clone + AsBytes,
V: Clone,
A: Allocator,
const PREFIX_LEN: usize,
>(
root: OpaqueNodePtr<K, V, PREFIX_LEN>,
alloc: &A,
) -> CloneResult<K, V, PREFIX_LEN> {
/// Update the current parent node with the newly cloned child, inserting it
/// at the given key byte.
///
/// If the parent is finished, meaning it has the expected number of
/// children, this function pops that node off the unfinished stack.
///
/// This function also updates the "new root node", which is inferred by
/// recording the node that is passed when the unfinished stack is empty.
///
/// # Safety
///
/// This function can only be called while there are no other mutable
/// references to the nodes of the cloned (in-progress) trie
unsafe fn update_parent<N, K, V, const PREFIX_LEN: usize>(
unfinished_nodes_stack: &mut Vec<(usize, ConcreteInnerNodePtr<K, V, PREFIX_LEN>)>,
new_root_node: &mut Option<OpaqueNodePtr<K, V, PREFIX_LEN>>,
key_byte: u8,
new_node_ptr: NodePtr<PREFIX_LEN, N>,
) where
N: Node<PREFIX_LEN, Key = K, Value = V>,
{
let Some((expected_num_children, parent)) = unfinished_nodes_stack.last() else {
debug_assert!(
new_root_node.is_none(),
"First cloned node [{new_root_node:?}] is present while unfinished node stack is \
empty",
);
// We know this is the root node since it has no parent
*new_root_node = Some(new_node_ptr.to_opaque());
return;
};
let updated_num_children = match_concrete_inner_node_ptr!(match (parent) {
InnerNode(inner_ptr) => {
// SAFETY: Covered by function safety doc AND the lifetime of this mutable
// reference is scoped to this block, and does not escape
let inner = unsafe { inner_ptr.as_mut() };
inner.write_child(key_byte, new_node_ptr.to_opaque());
inner.header().num_children()
},
});
debug_assert!(
updated_num_children <= *expected_num_children,
"should never add more [{updated_num_children}] than the expected number of children \
[{expected_num_children}]"
);
if updated_num_children == *expected_num_children {
// This inner node is finished, all the children have been added
let _ = unfinished_nodes_stack.pop().expect("last was Some");
}
}
/// This function starts cloning the inner node, and updates the various
/// stacks so that the new node will be updated as tree traversal continues.
///
/// # Safety
///
/// - This function can only be called while there are no mutable
/// references to any of the nodes in the trie referenced by `inner_ptr`.
/// - Additionally, there must not be any other mutable references to nodes
/// in the `unfinished_nodes_stack` stack.
unsafe fn clone_inner_node<N, K, V, A, const PREFIX_LEN: usize>(
unfinished_nodes_stack: &mut Vec<(usize, ConcreteInnerNodePtr<K, V, PREFIX_LEN>)>,
dfs_stack: &mut Vec<(u8, OpaqueNodePtr<K, V, PREFIX_LEN>)>,
new_root_node: &mut Option<OpaqueNodePtr<K, V, PREFIX_LEN>>,
key_byte: u8,
inner_ptr: NodePtr<PREFIX_LEN, N>,
alloc: &A,
) where
N: InnerNode<PREFIX_LEN, Key = K, Value = V>,
ConcreteInnerNodePtr<K, V, PREFIX_LEN>: From<NodePtr<PREFIX_LEN, N>>,
A: Allocator,
{
// SAFETY: Covered by function safety comment
let inner = unsafe { inner_ptr.as_ref() };
// We add the node children in reverse order so that the first child lands on
// the top of the stack. That ensures we iterate DFS and visit the nodes
// in-order, not reversed
dfs_stack.extend(inner.iter().rev());
let mut header = inner.header().clone();
header.reset_num_children();
let new_node = N::from_header(header);
// At this point the header records 0 children, but has a copy of the prefix
// from the original node There are no child pointers in the node
let new_node_ptr = NodePtr::allocate_node_ptr(new_node, alloc);
// SAFETY: Covered by function safety doc, since there are no other mutable
// references to nodes in the `unfinished_nodes_stack` stack.
unsafe {
update_parent(
unfinished_nodes_stack,
new_root_node,
key_byte,
new_node_ptr,
)
};
// Get the expected number of children from the original header
let expected_num_children = inner.header().num_children();
unfinished_nodes_stack.push((
expected_num_children,
ConcreteInnerNodePtr::from(new_node_ptr),
));
}
// (expected number of children, Pointer to inner node)
let mut unfinished_nodes_stack: Vec<(usize, ConcreteInnerNodePtr<K, V, PREFIX_LEN>)> =
Vec::new();
// (Key byte of this node, node pointer)
let mut dfs_stack: Vec<(u8, OpaqueNodePtr<K, V, PREFIX_LEN>)> = Vec::new();
let mut new_root_node: Option<OpaqueNodePtr<K, V, PREFIX_LEN>> = None;
let mut first_leaf: Option<NodePtr<PREFIX_LEN, LeafNode<K, V, PREFIX_LEN>>> = None;
let mut previous_leaf: Option<NodePtr<PREFIX_LEN, LeafNode<K, V, PREFIX_LEN>>> = None;
// We're okay to fabricate a key_byte for the root, since it will never be
// inserted into a parent node
dfs_stack.push((u8::MAX, root));
while let Some((key_byte, current_ptr)) = dfs_stack.pop() {
match_concrete_node_ptr!(match (current_ptr.to_node_ptr()) {
InnerNode(inner_ptr) => unsafe {
// SAFETY: The `clone_unchecked` safety comment covers other mutable references
// to the original trie, and we guarantee here there are no mutable references
// to nodes in the `unfinished_node_stack`
clone_inner_node(
&mut unfinished_nodes_stack,
&mut dfs_stack,
&mut new_root_node,
key_byte,
inner_ptr,
alloc,
);
},
LeafNode(leaf_ptr) => {
// SAFETY: The `clone_unchecked` safety comment covers other mutable references
// to the original trie
let leaf = unsafe { leaf_ptr.as_ref() };
let new_leaf = leaf.clone_without_siblings();
let new_leaf_ptr = NodePtr::allocate_node_ptr(new_leaf, alloc);
if let Some(previous_ptr) = previous_leaf {
// SAFETY: The `clone_unchecked` safety comment covers other mutable references
// to the original trie
unsafe { LeafNode::insert_after(new_leaf_ptr, previous_ptr) };
}
previous_leaf = Some(new_leaf_ptr);
let _ = first_leaf.get_or_insert(new_leaf_ptr);
// SAFETY: There are no mutable references to any nodes in the
// `unfinished_nodes_stack`
unsafe {
update_parent(
&mut unfinished_nodes_stack,
&mut new_root_node,
key_byte,
new_leaf_ptr,
)
};
},
});
}
assert!(
unfinished_nodes_stack.is_empty(),
"The list of unfinished nodes must be empty when exiting the loop"
);
CloneResult {
root: new_root_node.expect("there should be at least one cloned node"),
min_leaf: first_leaf.expect("should visit at least one leaf in a non-empty trie"),
max_leaf: previous_leaf.expect("should visit at least one leaf in a non-empty trie"),
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use alloc::boxed::Box;
use core::fmt;
use super::*;
use crate::{
testing::{
generate_key_fixed_length, generate_key_with_prefix, generate_keys_skewed, swap,
PrefixExpansion,
},
visitor::WellFormedChecker,
TreeMap,
};
#[track_caller]
fn check<K: AsBytes + Clone + PartialEq + fmt::Debug>(keys: impl IntoIterator<Item = K>) {
let mut tree = TreeMap::new();
for (key, value) in keys.into_iter().enumerate().map(swap) {
tree.try_insert(key, value).unwrap();
}
let new_tree = tree.clone();
for (key, expected_value) in &tree {
assert_eq!(tree.get(key).unwrap(), expected_value);
}
assert_eq!(new_tree.len(), tree.len());
assert_eq!(new_tree, tree);
let _ = WellFormedChecker::check(&new_tree).expect("tree should be well-formed");
}
#[test]
fn clone_small_trees() {
check([[0u8, 0], [171, 171], [65, 229]]);
check(generate_key_fixed_length(if cfg!(miri) {
[3; 2]
} else {
[17; 2]
}));
check(generate_keys_skewed(if cfg!(miri) { 16 } else { 127 }));
}
#[test]
fn clone_empty_tree() {
check::<Box<[u8]>>([])
}
#[test]
fn clone_singleton_tree() {
check([[0, 0, 0, 0, 0]])
}
#[test]
fn clone_tree_with_prefixes() {
check(generate_key_with_prefix(
[2; 3],
[PrefixExpansion {
base_index: 0,
expanded_length: 3,
}],
))
}
}