Path: blob/main/cranelift/bforest/src/pool.rs
1692 views
//! B+-tree node pool.12#[cfg(test)]3use super::Comparator;4use super::{Forest, Node, NodeData};5use crate::entity::PrimaryMap;6#[cfg(test)]7use core::fmt;8use core::ops::{Index, IndexMut};910/// A pool of nodes, including a free list.11pub(super) struct NodePool<F: Forest> {12nodes: PrimaryMap<Node, NodeData<F>>,13freelist: Option<Node>,14}1516impl<F: Forest> NodePool<F> {17/// Allocate a new empty pool of nodes.18pub fn new() -> Self {19Self {20nodes: PrimaryMap::new(),21freelist: None,22}23}2425/// Free all nodes.26pub fn clear(&mut self) {27self.nodes.clear();28self.freelist = None;29}3031/// Allocate a new node containing `data`.32pub fn alloc_node(&mut self, data: NodeData<F>) -> Node {33debug_assert!(!data.is_free(), "can't allocate free node");34match self.freelist {35Some(node) => {36// Remove this node from the free list.37match self.nodes[node] {38NodeData::Free { next } => self.freelist = next,39_ => panic!("Invalid {} on free list", node),40}41self.nodes[node] = data;42node43}44None => {45// The free list is empty. Allocate a new node.46self.nodes.push(data)47}48}49}5051/// Free a node.52pub fn free_node(&mut self, node: Node) {53// Quick check for a double free.54debug_assert!(!self.nodes[node].is_free(), "{node} is already free");55self.nodes[node] = NodeData::Free {56next: self.freelist,57};58self.freelist = Some(node);59}6061/// Free the entire tree rooted at `node`.62pub fn free_tree(&mut self, node: Node) {63if let NodeData::Inner { size, tree, .. } = self[node] {64// Note that we have to capture `tree` by value to avoid borrow checker trouble.65for i in 0..usize::from(size + 1) {66// Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`,67// and since most trees have less than a handful of nodes, it is worthwhile to68// avoid the heap allocation for an iterative tree traversal.69self.free_tree(tree[i]);70}71}72self.free_node(node);73}74}7576#[cfg(test)]77impl<F: Forest> NodePool<F> {78/// Verify the consistency of the tree rooted at `node`.79pub fn verify_tree<C: Comparator<F::Key>>(&self, node: Node, comp: &C)80where81NodeData<F>: fmt::Display,82F::Key: fmt::Display,83{84use crate::entity::EntitySet;85use alloc::vec::Vec;86use core::borrow::Borrow;87use core::cmp::Ordering;8889// The root node can't be an inner node with just a single sub-tree. It should have been90// pruned.91if let NodeData::Inner { size, .. } = self[node] {92assert!(size > 0, "Root must have more than one sub-tree");93}9495let mut done = match self[node] {96NodeData::Inner { size, .. } | NodeData::Leaf { size, .. } => {97EntitySet::with_capacity(size.into())98}99_ => EntitySet::new(),100};101102let mut todo = Vec::new();103104// Todo-list entries are:105// 1. Optional LHS key which must be <= all node entries.106// 2. The node reference.107// 3. Optional RHS key which must be > all node entries.108todo.push((None, node, None));109110while let Some((lkey, node, rkey)) = todo.pop() {111assert!(done.insert(node), "Node appears more than once in tree");112let mut lower = lkey;113114match self[node] {115NodeData::Inner { size, keys, tree } => {116let size = size as usize;117let capacity = tree.len();118let keys = &keys[0..size];119120// Verify occupancy.121// Right-most nodes can be small, but others must be at least half full.122assert!(123rkey.is_none() || (size + 1) * 2 >= capacity,124"Only {}/{} entries in {}:{}, upper={}",125size + 1,126capacity,127node,128self[node],129rkey.unwrap()130);131132// Queue up the sub-trees, checking for duplicates.133for i in 0..size + 1 {134// Get an upper bound for node[i].135let upper = keys.get(i).cloned().or(rkey);136137// Check that keys are strictly monotonic.138if let (Some(a), Some(b)) = (lower, upper) {139assert_eq!(140comp.cmp(a, b),141Ordering::Less,142"Key order {} < {} failed in {}: {}",143a,144b,145node,146self[node]147);148}149150// Queue up the sub-tree.151todo.push((lower, tree[i], upper));152153// Set a lower bound for the next tree.154lower = upper;155}156}157NodeData::Leaf { size, keys, .. } => {158let size = size as usize;159let capacity = keys.borrow().len();160let keys = &keys.borrow()[0..size];161162// Verify occupancy.163// Right-most nodes can be small, but others must be at least half full.164assert!(size > 0, "Leaf {node} is empty");165assert!(166rkey.is_none() || size * 2 >= capacity,167"Only {}/{} entries in {}:{}, upper={}",168size,169capacity,170node,171self[node],172rkey.unwrap()173);174175for i in 0..size + 1 {176let upper = keys.get(i).cloned().or(rkey);177178// Check that keys are strictly monotonic.179if let (Some(a), Some(b)) = (lower, upper) {180let wanted = if i == 0 {181Ordering::Equal182} else {183Ordering::Less184};185assert_eq!(186comp.cmp(a, b),187wanted,188"Key order for {} - {} failed in {}: {}",189a,190b,191node,192self[node]193);194}195196// Set a lower bound for the next key.197lower = upper;198}199}200NodeData::Free { .. } => panic!("Free {} reached", node),201}202}203}204}205206impl<F: Forest> Index<Node> for NodePool<F> {207type Output = NodeData<F>;208209fn index(&self, index: Node) -> &Self::Output {210self.nodes.index(index)211}212}213214impl<F: Forest> IndexMut<Node> for NodePool<F> {215fn index_mut(&mut self, index: Node) -> &mut Self::Output {216self.nodes.index_mut(index)217}218}219220221