use crate::pass::{AnalysisId, MAX_ANALYSES, Preserved};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Demand(u64);
impl Demand {
pub const NONE: Demand = Demand(0);
#[inline]
#[must_use]
pub const fn with(self, group: AnalysisId) -> Demand {
Demand(self.0 | bit(group))
}
#[inline]
#[must_use]
pub const fn contains(self, group: AnalysisId) -> bool {
self.0 & bit(group) != 0
}
#[inline]
#[must_use]
pub const fn union(self, other: Demand) -> Demand {
Demand(self.0 | other.0)
}
#[inline]
#[must_use]
pub const fn intersect(self, other: Demand) -> Demand {
Demand(self.0 & other.0)
}
#[inline]
#[must_use]
pub const fn minus(self, other: Demand) -> Demand {
Demand(self.0 & !other.0)
}
#[inline]
#[must_use]
pub const fn is_subset_of(self, other: Demand) -> bool {
self.0 & !other.0 == 0
}
#[inline]
#[must_use]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
#[inline]
#[must_use]
pub const fn len(self) -> u32 {
self.0.count_ones()
}
#[inline]
#[must_use]
pub const fn surviving(self, preserved: Preserved) -> Demand {
Demand(self.0 & preserved.to_bits())
}
#[inline]
#[must_use]
pub const fn to_bits(self) -> u64 {
self.0
}
#[inline]
#[must_use]
pub const fn from_bits(bits: u64) -> Demand {
Demand(bits)
}
pub fn iter(self) -> impl Iterator<Item = AnalysisId> {
(0..MAX_ANALYSES)
.filter(move |index| self.0 & (1u64 << index) != 0)
.map(AnalysisId::new)
}
}
#[inline]
const fn bit(group: AnalysisId) -> u64 {
1u64 << group.index()
}
#[cfg(test)]
mod tests {
use super::Demand;
use crate::pass::{AnalysisId, Preserved};
use alloc::vec::Vec;
const A: AnalysisId = AnalysisId::new(0);
const B: AnalysisId = AnalysisId::new(7);
const C: AnalysisId = AnalysisId::new(63);
#[test]
fn set_algebra_is_exact() {
let ab = Demand::NONE.with(A).with(B);
let bc = Demand::NONE.with(B).with(C);
assert_eq!(ab.union(bc), Demand::NONE.with(A).with(B).with(C));
assert_eq!(ab.intersect(bc), Demand::NONE.with(B));
assert_eq!(ab.minus(bc), Demand::NONE.with(A));
assert!(Demand::NONE.with(B).is_subset_of(ab));
assert!(!bc.is_subset_of(ab));
assert_eq!((ab.len(), Demand::NONE.len()), (2, 0));
assert!(Demand::NONE.is_empty() && !ab.is_empty());
}
#[test]
fn iteration_is_ascending_and_complete() {
let set = Demand::NONE.with(C).with(A).with(B);
let ids: Vec<u8> = set.iter().map(AnalysisId::index).collect();
assert_eq!(ids, [0, 7, 63]);
}
#[test]
fn surviving_reads_a_preserved_mask_in_the_same_identity_space() {
let set = Demand::NONE.with(A).with(B);
assert_eq!(set.surviving(Preserved::NONE.with(B)), Demand::NONE.with(B));
assert_eq!(set.surviving(Preserved::ALL), set);
assert_eq!(set.surviving(Preserved::NONE), Demand::NONE);
}
#[test]
fn bits_round_trip() {
let set = Demand::NONE.with(A).with(C);
assert_eq!(Demand::from_bits(set.to_bits()), set);
assert_eq!(set.to_bits(), 1 | (1 << 63));
}
}