use crate::{BitSet, ir::variable::SsaVarId};
#[derive(Debug, Clone)]
pub struct VarSet {
bits: BitSet,
}
impl VarSet {
#[must_use]
pub fn new(capacity: usize) -> Self {
Self {
bits: BitSet::new(capacity),
}
}
pub fn insert(&mut self, var: SsaVarId) -> bool {
if var.is_placeholder() {
return false;
}
self.bits.ensure_capacity(var.index());
self.bits.insert_checked(var.index())
}
#[must_use]
pub fn contains(&self, var: SsaVarId) -> bool {
!var.is_placeholder() && self.bits.contains_checked(var.index())
}
pub fn remove(&mut self, var: SsaVarId) -> bool {
if !self.contains(var) {
return false;
}
self.bits.remove(var.index());
true
}
#[must_use]
pub fn len(&self) -> usize {
self.bits.count()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&self) -> impl Iterator<Item = SsaVarId> + '_ {
self.bits.iter().map(SsaVarId::from_index)
}
#[must_use]
pub fn bits(&self) -> &BitSet {
&self.bits
}
}
#[derive(Debug, Clone)]
pub struct VarMap<T> {
slots: Vec<Option<T>>,
}
impl<T> VarMap<T> {
#[must_use]
pub fn new(capacity: usize) -> Self {
let mut slots = Vec::new();
slots.resize_with(capacity, || None);
Self { slots }
}
#[must_use]
pub fn get(&self, var: SsaVarId) -> Option<&T> {
if var.is_placeholder() {
return None;
}
self.slots.get(var.index()).and_then(Option::as_ref)
}
pub fn get_mut(&mut self, var: SsaVarId) -> Option<&mut T> {
if var.is_placeholder() {
return None;
}
self.slots.get_mut(var.index()).and_then(Option::as_mut)
}
#[must_use]
pub fn contains(&self, var: SsaVarId) -> bool {
self.get(var).is_some()
}
pub fn insert(&mut self, var: SsaVarId, value: T) {
if var.is_placeholder() {
return;
}
if let Some(slot) = self.slots.get_mut(var.index()) {
*slot = Some(value);
}
}
pub fn or_insert(&mut self, var: SsaVarId, value: T) {
if var.is_placeholder() {
return;
}
if let Some(slot) = self.slots.get_mut(var.index())
&& slot.is_none()
{
*slot = Some(value);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn placeholder_is_not_a_variable() {
let mut set = VarSet::new(8);
assert!(!set.insert(SsaVarId::PLACEHOLDER));
assert!(!set.contains(SsaVarId::PLACEHOLDER));
assert!(set.is_empty());
let mut map: VarMap<u32> = VarMap::new(8);
map.insert(SsaVarId::PLACEHOLDER, 7);
assert_eq!(map.get(SsaVarId::PLACEHOLDER), None);
assert!(!map.contains(SsaVarId::PLACEHOLDER));
}
#[test]
fn placeholder_ids_are_ignored() {
let mut set = VarSet::new(4);
assert!(!set.insert(SsaVarId::PLACEHOLDER));
assert!(!set.contains(SsaVarId::PLACEHOLDER));
let mut map: VarMap<u32> = VarMap::new(4);
map.insert(SsaVarId::PLACEHOLDER, 1);
assert_eq!(map.get(SsaVarId::PLACEHOLDER), None);
}
#[test]
fn out_of_range_reads_are_tolerated() {
let set = VarSet::new(4);
assert!(!set.contains(SsaVarId::from_index(9)));
let map: VarMap<u32> = VarMap::new(4);
assert_eq!(map.get(SsaVarId::from_index(9)), None);
}
#[test]
fn inserting_an_out_of_range_id_grows_the_set() {
let mut set = VarSet::new(4);
assert!(set.insert(SsaVarId::from_index(9)));
assert!(
set.contains(SsaVarId::from_index(9)),
"the write must not be silently lost"
);
assert_eq!(set.len(), 1);
let mut set = VarSet::new(4);
assert!(set.insert(SsaVarId::from_index(1)));
assert!(set.insert(SsaVarId::from_index(300)));
assert!(set.contains(SsaVarId::from_index(1)));
assert!(set.contains(SsaVarId::from_index(300)));
assert_eq!(set.len(), 2);
}
#[test]
fn real_ids_round_trip() {
let mut set = VarSet::new(8);
assert!(set.insert(SsaVarId::from_index(3)));
assert!(!set.insert(SsaVarId::from_index(3)));
assert!(set.contains(SsaVarId::from_index(3)));
assert_eq!(set.len(), 1);
assert_eq!(
set.iter().collect::<Vec<_>>(),
vec![SsaVarId::from_index(3)]
);
assert!(set.remove(SsaVarId::from_index(3)));
assert!(set.is_empty());
let mut map: VarMap<&str> = VarMap::new(8);
map.insert(SsaVarId::from_index(2), "a");
map.or_insert(SsaVarId::from_index(2), "b");
assert_eq!(map.get(SsaVarId::from_index(2)), Some(&"a"));
map.insert(SsaVarId::from_index(2), "c");
assert_eq!(map.get(SsaVarId::from_index(2)), Some(&"c"));
}
}