Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/bforest/src/pool.rs
1692 views
1
//! B+-tree node pool.
2
3
#[cfg(test)]
4
use super::Comparator;
5
use super::{Forest, Node, NodeData};
6
use crate::entity::PrimaryMap;
7
#[cfg(test)]
8
use core::fmt;
9
use core::ops::{Index, IndexMut};
10
11
/// A pool of nodes, including a free list.
12
pub(super) struct NodePool<F: Forest> {
13
nodes: PrimaryMap<Node, NodeData<F>>,
14
freelist: Option<Node>,
15
}
16
17
impl<F: Forest> NodePool<F> {
18
/// Allocate a new empty pool of nodes.
19
pub fn new() -> Self {
20
Self {
21
nodes: PrimaryMap::new(),
22
freelist: None,
23
}
24
}
25
26
/// Free all nodes.
27
pub fn clear(&mut self) {
28
self.nodes.clear();
29
self.freelist = None;
30
}
31
32
/// Allocate a new node containing `data`.
33
pub fn alloc_node(&mut self, data: NodeData<F>) -> Node {
34
debug_assert!(!data.is_free(), "can't allocate free node");
35
match self.freelist {
36
Some(node) => {
37
// Remove this node from the free list.
38
match self.nodes[node] {
39
NodeData::Free { next } => self.freelist = next,
40
_ => panic!("Invalid {} on free list", node),
41
}
42
self.nodes[node] = data;
43
node
44
}
45
None => {
46
// The free list is empty. Allocate a new node.
47
self.nodes.push(data)
48
}
49
}
50
}
51
52
/// Free a node.
53
pub fn free_node(&mut self, node: Node) {
54
// Quick check for a double free.
55
debug_assert!(!self.nodes[node].is_free(), "{node} is already free");
56
self.nodes[node] = NodeData::Free {
57
next: self.freelist,
58
};
59
self.freelist = Some(node);
60
}
61
62
/// Free the entire tree rooted at `node`.
63
pub fn free_tree(&mut self, node: Node) {
64
if let NodeData::Inner { size, tree, .. } = self[node] {
65
// Note that we have to capture `tree` by value to avoid borrow checker trouble.
66
for i in 0..usize::from(size + 1) {
67
// Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`,
68
// and since most trees have less than a handful of nodes, it is worthwhile to
69
// avoid the heap allocation for an iterative tree traversal.
70
self.free_tree(tree[i]);
71
}
72
}
73
self.free_node(node);
74
}
75
}
76
77
#[cfg(test)]
78
impl<F: Forest> NodePool<F> {
79
/// Verify the consistency of the tree rooted at `node`.
80
pub fn verify_tree<C: Comparator<F::Key>>(&self, node: Node, comp: &C)
81
where
82
NodeData<F>: fmt::Display,
83
F::Key: fmt::Display,
84
{
85
use crate::entity::EntitySet;
86
use alloc::vec::Vec;
87
use core::borrow::Borrow;
88
use core::cmp::Ordering;
89
90
// The root node can't be an inner node with just a single sub-tree. It should have been
91
// pruned.
92
if let NodeData::Inner { size, .. } = self[node] {
93
assert!(size > 0, "Root must have more than one sub-tree");
94
}
95
96
let mut done = match self[node] {
97
NodeData::Inner { size, .. } | NodeData::Leaf { size, .. } => {
98
EntitySet::with_capacity(size.into())
99
}
100
_ => EntitySet::new(),
101
};
102
103
let mut todo = Vec::new();
104
105
// Todo-list entries are:
106
// 1. Optional LHS key which must be <= all node entries.
107
// 2. The node reference.
108
// 3. Optional RHS key which must be > all node entries.
109
todo.push((None, node, None));
110
111
while let Some((lkey, node, rkey)) = todo.pop() {
112
assert!(done.insert(node), "Node appears more than once in tree");
113
let mut lower = lkey;
114
115
match self[node] {
116
NodeData::Inner { size, keys, tree } => {
117
let size = size as usize;
118
let capacity = tree.len();
119
let keys = &keys[0..size];
120
121
// Verify occupancy.
122
// Right-most nodes can be small, but others must be at least half full.
123
assert!(
124
rkey.is_none() || (size + 1) * 2 >= capacity,
125
"Only {}/{} entries in {}:{}, upper={}",
126
size + 1,
127
capacity,
128
node,
129
self[node],
130
rkey.unwrap()
131
);
132
133
// Queue up the sub-trees, checking for duplicates.
134
for i in 0..size + 1 {
135
// Get an upper bound for node[i].
136
let upper = keys.get(i).cloned().or(rkey);
137
138
// Check that keys are strictly monotonic.
139
if let (Some(a), Some(b)) = (lower, upper) {
140
assert_eq!(
141
comp.cmp(a, b),
142
Ordering::Less,
143
"Key order {} < {} failed in {}: {}",
144
a,
145
b,
146
node,
147
self[node]
148
);
149
}
150
151
// Queue up the sub-tree.
152
todo.push((lower, tree[i], upper));
153
154
// Set a lower bound for the next tree.
155
lower = upper;
156
}
157
}
158
NodeData::Leaf { size, keys, .. } => {
159
let size = size as usize;
160
let capacity = keys.borrow().len();
161
let keys = &keys.borrow()[0..size];
162
163
// Verify occupancy.
164
// Right-most nodes can be small, but others must be at least half full.
165
assert!(size > 0, "Leaf {node} is empty");
166
assert!(
167
rkey.is_none() || size * 2 >= capacity,
168
"Only {}/{} entries in {}:{}, upper={}",
169
size,
170
capacity,
171
node,
172
self[node],
173
rkey.unwrap()
174
);
175
176
for i in 0..size + 1 {
177
let upper = keys.get(i).cloned().or(rkey);
178
179
// Check that keys are strictly monotonic.
180
if let (Some(a), Some(b)) = (lower, upper) {
181
let wanted = if i == 0 {
182
Ordering::Equal
183
} else {
184
Ordering::Less
185
};
186
assert_eq!(
187
comp.cmp(a, b),
188
wanted,
189
"Key order for {} - {} failed in {}: {}",
190
a,
191
b,
192
node,
193
self[node]
194
);
195
}
196
197
// Set a lower bound for the next key.
198
lower = upper;
199
}
200
}
201
NodeData::Free { .. } => panic!("Free {} reached", node),
202
}
203
}
204
}
205
}
206
207
impl<F: Forest> Index<Node> for NodePool<F> {
208
type Output = NodeData<F>;
209
210
fn index(&self, index: Node) -> &Self::Output {
211
self.nodes.index(index)
212
}
213
}
214
215
impl<F: Forest> IndexMut<Node> for NodePool<F> {
216
fn index_mut(&mut self, index: Node) -> &mut Self::Output {
217
self.nodes.index_mut(index)
218
}
219
}
220
221