cranelift_bforest/
pool.rs

1//! B+-tree node pool.
2
3#[cfg(test)]
4use super::Comparator;
5use super::{Forest, Node, NodeData};
6use crate::entity::PrimaryMap;
7#[cfg(test)]
8use core::fmt;
9use core::ops::{Index, IndexMut};
10
11/// A pool of nodes, including a free list.
12pub(super) struct NodePool<F: Forest> {
13    nodes: PrimaryMap<Node, NodeData<F>>,
14    freelist: Option<Node>,
15}
16
17impl<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(), "{} is already free", node);
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            #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_range_loop))]
67            for i in 0..usize::from(size + 1) {
68                // Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`,
69                // and since most trees have less than a handful of nodes, it is worthwhile to
70                // avoid the heap allocation for an iterative tree traversal.
71                self.free_tree(tree[i]);
72            }
73        }
74        self.free_node(node);
75    }
76}
77
78#[cfg(test)]
79impl<F: Forest> NodePool<F> {
80    /// Verify the consistency of the tree rooted at `node`.
81    pub fn verify_tree<C: Comparator<F::Key>>(&self, node: Node, comp: &C)
82    where
83        NodeData<F>: fmt::Display,
84        F::Key: fmt::Display,
85    {
86        use crate::entity::EntitySet;
87        use alloc::vec::Vec;
88        use core::borrow::Borrow;
89        use core::cmp::Ordering;
90
91        // The root node can't be an inner node with just a single sub-tree. It should have been
92        // pruned.
93        if let NodeData::Inner { size, .. } = self[node] {
94            assert!(size > 0, "Root must have more than one sub-tree");
95        }
96
97        let mut done = match self[node] {
98            NodeData::Inner { size, .. } | NodeData::Leaf { size, .. } => {
99                EntitySet::with_capacity(size.into())
100            }
101            _ => EntitySet::new(),
102        };
103
104        let mut todo = Vec::new();
105
106        // Todo-list entries are:
107        // 1. Optional LHS key which must be <= all node entries.
108        // 2. The node reference.
109        // 3. Optional RHS key which must be > all node entries.
110        todo.push((None, node, None));
111
112        while let Some((lkey, node, rkey)) = todo.pop() {
113            assert!(done.insert(node), "Node appears more than once in tree");
114            let mut lower = lkey;
115
116            match self[node] {
117                NodeData::Inner { size, keys, tree } => {
118                    let size = size as usize;
119                    let capacity = tree.len();
120                    let keys = &keys[0..size];
121
122                    // Verify occupancy.
123                    // Right-most nodes can be small, but others must be at least half full.
124                    assert!(
125                        rkey.is_none() || (size + 1) * 2 >= capacity,
126                        "Only {}/{} entries in {}:{}, upper={}",
127                        size + 1,
128                        capacity,
129                        node,
130                        self[node],
131                        rkey.unwrap()
132                    );
133
134                    // Queue up the sub-trees, checking for duplicates.
135                    for i in 0..size + 1 {
136                        // Get an upper bound for node[i].
137                        let upper = keys.get(i).cloned().or(rkey);
138
139                        // Check that keys are strictly monotonic.
140                        if let (Some(a), Some(b)) = (lower, upper) {
141                            assert_eq!(
142                                comp.cmp(a, b),
143                                Ordering::Less,
144                                "Key order {} < {} failed in {}: {}",
145                                a,
146                                b,
147                                node,
148                                self[node]
149                            );
150                        }
151
152                        // Queue up the sub-tree.
153                        todo.push((lower, tree[i], upper));
154
155                        // Set a lower bound for the next tree.
156                        lower = upper;
157                    }
158                }
159                NodeData::Leaf { size, keys, .. } => {
160                    let size = size as usize;
161                    let capacity = keys.borrow().len();
162                    let keys = &keys.borrow()[0..size];
163
164                    // Verify occupancy.
165                    // Right-most nodes can be small, but others must be at least half full.
166                    assert!(size > 0, "Leaf {} is empty", node);
167                    assert!(
168                        rkey.is_none() || size * 2 >= capacity,
169                        "Only {}/{} entries in {}:{}, upper={}",
170                        size,
171                        capacity,
172                        node,
173                        self[node],
174                        rkey.unwrap()
175                    );
176
177                    for i in 0..size + 1 {
178                        let upper = keys.get(i).cloned().or(rkey);
179
180                        // Check that keys are strictly monotonic.
181                        if let (Some(a), Some(b)) = (lower, upper) {
182                            let wanted = if i == 0 {
183                                Ordering::Equal
184                            } else {
185                                Ordering::Less
186                            };
187                            assert_eq!(
188                                comp.cmp(a, b),
189                                wanted,
190                                "Key order for {} - {} failed in {}: {}",
191                                a,
192                                b,
193                                node,
194                                self[node]
195                            );
196                        }
197
198                        // Set a lower bound for the next key.
199                        lower = upper;
200                    }
201                }
202                NodeData::Free { .. } => panic!("Free {} reached", node),
203            }
204        }
205    }
206}
207
208impl<F: Forest> Index<Node> for NodePool<F> {
209    type Output = NodeData<F>;
210
211    fn index(&self, index: Node) -> &Self::Output {
212        self.nodes.index(index)
213    }
214}
215
216impl<F: Forest> IndexMut<Node> for NodePool<F> {
217    fn index_mut(&mut self, index: Node) -> &mut Self::Output {
218        self.nodes.index_mut(index)
219    }
220}