Coverage Report

Created: 2024-10-16 07:58

/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
}