/rust/registry/src/index.crates.io-6f17d22bba15001f/cranelift-bforest-0.91.1/src/pool.rs
Line | Count | Source (jump to first uncovered line) |
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 | 3.06M | pub fn new() -> Self { |
20 | 3.06M | Self { |
21 | 3.06M | nodes: PrimaryMap::new(), |
22 | 3.06M | freelist: None, |
23 | 3.06M | } |
24 | 3.06M | } <cranelift_bforest::pool::NodePool<cranelift_bforest::map::MapTypes<cranelift_codegen::ir::entities::Inst, cranelift_codegen::ir::entities::Block>>>::new Line | Count | Source | 19 | 1.53M | pub fn new() -> Self { | 20 | 1.53M | Self { | 21 | 1.53M | nodes: PrimaryMap::new(), | 22 | 1.53M | freelist: None, | 23 | 1.53M | } | 24 | 1.53M | } |
<cranelift_bforest::pool::NodePool<cranelift_bforest::set::SetTypes<cranelift_codegen::ir::entities::Block>>>::new Line | Count | Source | 19 | 1.53M | pub fn new() -> Self { | 20 | 1.53M | Self { | 21 | 1.53M | nodes: PrimaryMap::new(), | 22 | 1.53M | freelist: None, | 23 | 1.53M | } | 24 | 1.53M | } |
Unexecuted instantiation: <cranelift_bforest::pool::NodePool<_>>::new |
25 | | |
26 | | /// Free all nodes. |
27 | 3.34M | pub fn clear(&mut self) { |
28 | 3.34M | self.nodes.clear(); |
29 | 3.34M | self.freelist = None; |
30 | 3.34M | } <cranelift_bforest::pool::NodePool<cranelift_bforest::map::MapTypes<cranelift_codegen::ir::entities::Inst, cranelift_codegen::ir::entities::Block>>>::clear Line | Count | Source | 27 | 1.67M | pub fn clear(&mut self) { | 28 | 1.67M | self.nodes.clear(); | 29 | 1.67M | self.freelist = None; | 30 | 1.67M | } |
<cranelift_bforest::pool::NodePool<cranelift_bforest::set::SetTypes<cranelift_codegen::ir::entities::Block>>>::clear Line | Count | Source | 27 | 1.67M | pub fn clear(&mut self) { | 28 | 1.67M | self.nodes.clear(); | 29 | 1.67M | self.freelist = None; | 30 | 1.67M | } |
Unexecuted instantiation: <cranelift_bforest::pool::NodePool<_>>::clear |
31 | | |
32 | | /// Allocate a new node containing `data`. |
33 | 4.12M | pub fn alloc_node(&mut self, data: NodeData<F>) -> Node { |
34 | 4.12M | debug_assert!(!data.is_free(), "can't allocate free node"); |
35 | 4.12M | match self.freelist { |
36 | 10.1k | Some(node) => { |
37 | 10.1k | // Remove this node from the free list. |
38 | 10.1k | match self.nodes[node] { |
39 | 10.1k | NodeData::Free { next } => self.freelist = next, |
40 | 0 | _ => panic!("Invalid {} on free list", node), |
41 | | } |
42 | 10.1k | self.nodes[node] = data; |
43 | 10.1k | node |
44 | | } |
45 | | None => { |
46 | | // The free list is empty. Allocate a new node. |
47 | 4.11M | self.nodes.push(data) |
48 | | } |
49 | | } |
50 | 4.12M | } <cranelift_bforest::pool::NodePool<cranelift_bforest::map::MapTypes<cranelift_codegen::ir::entities::Inst, cranelift_codegen::ir::entities::Block>>>::alloc_node Line | Count | Source | 33 | 2.17M | pub fn alloc_node(&mut self, data: NodeData<F>) -> Node { | 34 | 2.17M | debug_assert!(!data.is_free(), "can't allocate free node"); | 35 | 2.17M | match self.freelist { | 36 | 5.08k | Some(node) => { | 37 | 5.08k | // Remove this node from the free list. | 38 | 5.08k | match self.nodes[node] { | 39 | 5.08k | NodeData::Free { next } => self.freelist = next, | 40 | 0 | _ => panic!("Invalid {} on free list", node), | 41 | | } | 42 | 5.08k | self.nodes[node] = data; | 43 | 5.08k | node | 44 | | } | 45 | | None => { | 46 | | // The free list is empty. Allocate a new node. | 47 | 2.16M | self.nodes.push(data) | 48 | | } | 49 | | } | 50 | 2.17M | } |
<cranelift_bforest::pool::NodePool<cranelift_bforest::set::SetTypes<cranelift_codegen::ir::entities::Block>>>::alloc_node Line | Count | Source | 33 | 1.95M | pub fn alloc_node(&mut self, data: NodeData<F>) -> Node { | 34 | 1.95M | debug_assert!(!data.is_free(), "can't allocate free node"); | 35 | 1.95M | match self.freelist { | 36 | 5.05k | Some(node) => { | 37 | 5.05k | // Remove this node from the free list. | 38 | 5.05k | match self.nodes[node] { | 39 | 5.05k | NodeData::Free { next } => self.freelist = next, | 40 | 0 | _ => panic!("Invalid {} on free list", node), | 41 | | } | 42 | 5.05k | self.nodes[node] = data; | 43 | 5.05k | node | 44 | | } | 45 | | None => { | 46 | | // The free list is empty. Allocate a new node. | 47 | 1.95M | self.nodes.push(data) | 48 | | } | 49 | | } | 50 | 1.95M | } |
Unexecuted instantiation: <cranelift_bforest::pool::NodePool<_>>::alloc_node |
51 | | |
52 | | /// Free a node. |
53 | 10.1k | pub fn free_node(&mut self, node: Node) { |
54 | 10.1k | // Quick check for a double free. |
55 | 10.1k | debug_assert!(!self.nodes[node].is_free(), "{} is already free", node); |
56 | 10.1k | self.nodes[node] = NodeData::Free { |
57 | 10.1k | next: self.freelist, |
58 | 10.1k | }; |
59 | 10.1k | self.freelist = Some(node); |
60 | 10.1k | } <cranelift_bforest::pool::NodePool<cranelift_bforest::map::MapTypes<cranelift_codegen::ir::entities::Inst, cranelift_codegen::ir::entities::Block>>>::free_node Line | Count | Source | 53 | 5.08k | pub fn free_node(&mut self, node: Node) { | 54 | 5.08k | // Quick check for a double free. | 55 | 5.08k | debug_assert!(!self.nodes[node].is_free(), "{} is already free", node); | 56 | 5.08k | self.nodes[node] = NodeData::Free { | 57 | 5.08k | next: self.freelist, | 58 | 5.08k | }; | 59 | 5.08k | self.freelist = Some(node); | 60 | 5.08k | } |
<cranelift_bforest::pool::NodePool<cranelift_bforest::set::SetTypes<cranelift_codegen::ir::entities::Block>>>::free_node Line | Count | Source | 53 | 5.06k | pub fn free_node(&mut self, node: Node) { | 54 | 5.06k | // Quick check for a double free. | 55 | 5.06k | debug_assert!(!self.nodes[node].is_free(), "{} is already free", node); | 56 | 5.06k | self.nodes[node] = NodeData::Free { | 57 | 5.06k | next: self.freelist, | 58 | 5.06k | }; | 59 | 5.06k | self.freelist = Some(node); | 60 | 5.06k | } |
Unexecuted instantiation: <cranelift_bforest::pool::NodePool<_>>::free_node |
61 | | |
62 | | /// Free the entire tree rooted at `node`. |
63 | 5.06k | pub fn free_tree(&mut self, node: Node) { |
64 | 5.06k | 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 | 0 | for i in 0..usize::from(size + 1) { |
68 | 0 | // Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`, |
69 | 0 | // and since most trees have less than a handful of nodes, it is worthwhile to |
70 | 0 | // avoid the heap allocation for an iterative tree traversal. |
71 | 0 | self.free_tree(tree[i]); |
72 | 0 | } |
73 | 5.06k | } |
74 | 5.06k | self.free_node(node); |
75 | 5.06k | } <cranelift_bforest::pool::NodePool<cranelift_bforest::set::SetTypes<cranelift_codegen::ir::entities::Block>>>::free_tree Line | Count | Source | 63 | 5.06k | pub fn free_tree(&mut self, node: Node) { | 64 | 5.06k | 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 | 0 | for i in 0..usize::from(size + 1) { | 68 | 0 | // Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`, | 69 | 0 | // and since most trees have less than a handful of nodes, it is worthwhile to | 70 | 0 | // avoid the heap allocation for an iterative tree traversal. | 71 | 0 | self.free_tree(tree[i]); | 72 | 0 | } | 73 | 5.06k | } | 74 | 5.06k | self.free_node(node); | 75 | 5.06k | } |
Unexecuted instantiation: <cranelift_bforest::pool::NodePool<_>>::free_tree |
76 | | } |
77 | | |
78 | | #[cfg(test)] |
79 | | impl<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 | | |
208 | | impl<F: Forest> Index<Node> for NodePool<F> { |
209 | | type Output = NodeData<F>; |
210 | | |
211 | 23.4M | fn index(&self, index: Node) -> &Self::Output { |
212 | 23.4M | self.nodes.index(index) |
213 | 23.4M | } <cranelift_bforest::pool::NodePool<cranelift_bforest::map::MapTypes<cranelift_codegen::ir::entities::Inst, cranelift_codegen::ir::entities::Block>> as core::ops::index::Index<cranelift_bforest::Node>>::index Line | Count | Source | 211 | 16.7M | fn index(&self, index: Node) -> &Self::Output { | 212 | 16.7M | self.nodes.index(index) | 213 | 16.7M | } |
<cranelift_bforest::pool::NodePool<cranelift_bforest::set::SetTypes<cranelift_codegen::ir::entities::Block>> as core::ops::index::Index<cranelift_bforest::Node>>::index Line | Count | Source | 211 | 6.69M | fn index(&self, index: Node) -> &Self::Output { | 212 | 6.69M | self.nodes.index(index) | 213 | 6.69M | } |
Unexecuted instantiation: <cranelift_bforest::pool::NodePool<_> as core::ops::index::Index<cranelift_bforest::Node>>::index |
214 | | } |
215 | | |
216 | | impl<F: Forest> IndexMut<Node> for NodePool<F> { |
217 | 379k | fn index_mut(&mut self, index: Node) -> &mut Self::Output { |
218 | 379k | self.nodes.index_mut(index) |
219 | 379k | } <cranelift_bforest::pool::NodePool<cranelift_bforest::map::MapTypes<cranelift_codegen::ir::entities::Inst, cranelift_codegen::ir::entities::Block>> as core::ops::index::IndexMut<cranelift_bforest::Node>>::index_mut Line | Count | Source | 217 | 98.4k | fn index_mut(&mut self, index: Node) -> &mut Self::Output { | 218 | 98.4k | self.nodes.index_mut(index) | 219 | 98.4k | } |
<cranelift_bforest::pool::NodePool<cranelift_bforest::set::SetTypes<cranelift_codegen::ir::entities::Block>> as core::ops::index::IndexMut<cranelift_bforest::Node>>::index_mut Line | Count | Source | 217 | 280k | fn index_mut(&mut self, index: Node) -> &mut Self::Output { | 218 | 280k | self.nodes.index_mut(index) | 219 | 280k | } |
Unexecuted instantiation: <cranelift_bforest::pool::NodePool<_> as core::ops::index::IndexMut<cranelift_bforest::Node>>::index_mut |
220 | | } |