use petgraph::graph::NodeIndex;
#[derive(Debug, Clone, Default)]
pub struct NodeRemap {
dense: Vec<u32>,
live: usize,
}
impl NodeRemap {
const VACANT: u32 = u32::MAX;
pub(super) fn with_bound(bound: usize) -> Self {
NodeRemap {
dense: vec![Self::VACANT; bound],
live: 0,
}
}
pub(super) fn set(&mut self, old: usize, new: NodeIndex) {
self.dense[old] = new.index() as u32;
self.live += 1;
}
#[inline]
pub fn get(&self, old: NodeIndex) -> Option<NodeIndex> {
match self.dense.get(old.index()).copied() {
Some(Self::VACANT) | None => None,
Some(new) => Some(NodeIndex::new(new as usize)),
}
}
#[inline]
pub(super) fn raw(&self, old_raw: usize) -> u32 {
self.dense[old_raw]
}
#[inline]
pub(super) fn is_vacant(raw: u32) -> bool {
raw == Self::VACANT
}
#[inline]
pub fn len(&self) -> usize {
self.live
}
#[inline]
pub fn is_empty(&self) -> bool {
self.live == 0
}
#[inline]
pub fn describes_rebuild(&self) -> bool {
!self.dense.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (NodeIndex, NodeIndex)> + '_ {
self.dense
.iter()
.enumerate()
.filter(|(_, &new)| new != Self::VACANT)
.map(|(old, &new)| (NodeIndex::new(old), NodeIndex::new(new as usize)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vacant_slots_are_absent_and_uncounted() {
let mut remap = NodeRemap::with_bound(4);
remap.set(0, NodeIndex::new(0));
remap.set(3, NodeIndex::new(1));
assert_eq!(remap.len(), 2);
assert!(!remap.is_empty());
assert_eq!(remap.get(NodeIndex::new(0)), Some(NodeIndex::new(0)));
assert_eq!(remap.get(NodeIndex::new(1)), None);
assert_eq!(remap.get(NodeIndex::new(3)), Some(NodeIndex::new(1)));
assert_eq!(remap.get(NodeIndex::new(9)), None);
assert_eq!(
remap.iter().collect::<Vec<_>>(),
vec![
(NodeIndex::new(0), NodeIndex::new(0)),
(NodeIndex::new(3), NodeIndex::new(1)),
]
);
}
#[test]
fn an_untouched_mapping_is_empty() {
assert!(NodeRemap::default().is_empty());
assert!(NodeRemap::with_bound(8).is_empty());
assert_eq!(NodeRemap::with_bound(8).len(), 0);
}
#[test]
fn a_no_op_vacuum_is_distinguishable_from_a_rebuild_with_no_survivors() {
assert!(!NodeRemap::default().describes_rebuild());
let wiped = NodeRemap::with_bound(8);
assert!(wiped.is_empty());
assert!(wiped.describes_rebuild());
let mut kept = NodeRemap::with_bound(2);
kept.set(1, NodeIndex::new(0));
assert!(kept.describes_rebuild());
}
}