mesa/src/compiler/rust/bitset.rs
Christian Gmeiner 05bf03c3db nak: Move bitset to compiler crate
This commit intorduces src/compiler/rust crate, which will have
different modules that help to write a backend compiler in Rust.

Signed-off-by: Christian Gmeiner <cgmeiner@igalia.com>
Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30443>
2024-08-07 21:08:18 +00:00

253 lines
5.8 KiB
Rust

// Copyright © 2022 Collabora, Ltd.
// SPDX-License-Identifier: MIT
use std::ops::{
BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Range,
};
#[derive(Clone)]
pub struct BitSet {
words: Vec<u32>,
}
impl BitSet {
pub fn new() -> BitSet {
BitSet { words: Vec::new() }
}
fn reserve_words(&mut self, words: usize) {
if self.words.len() < words {
self.words.resize(words, 0);
}
}
pub fn reserve(&mut self, bits: usize) {
self.reserve_words(bits.div_ceil(32));
}
pub fn clear(&mut self) {
for w in self.words.iter_mut() {
*w = 0;
}
}
pub fn get(&self, idx: usize) -> bool {
let w = idx / 32;
let b = idx % 32;
if w < self.words.len() {
self.words[w] & (1_u32 << b) != 0
} else {
false
}
}
pub fn is_empty(&self) -> bool {
for w in self.words.iter() {
if *w != 0 {
return false;
}
}
true
}
pub fn iter(&self) -> BitSetIter<'_> {
BitSetIter::new(self, 0)
}
pub fn get_word(&self, word: usize) -> u32 {
self.words.get(word).cloned().unwrap_or(0)
}
pub fn next_unset(&self, start: usize) -> usize {
if start >= self.words.len() * 32 {
return start;
}
let mut w = start / 32;
let mut mask = !(u32::MAX << (start % 32));
while w < self.words.len() {
let b = (self.words[w] | mask).trailing_ones();
if b < 32 {
return w * 32 + usize::try_from(b).unwrap();
}
mask = 0;
w += 1;
}
self.words.len() * 32
}
pub fn insert(&mut self, idx: usize) -> bool {
let w = idx / 32;
let b = idx % 32;
self.reserve_words(w + 1);
let exists = self.words[w] & (1_u32 << b) != 0;
self.words[w] |= 1_u32 << b;
!exists
}
pub fn remove(&mut self, idx: usize) -> bool {
let w = idx / 32;
let b = idx % 32;
self.reserve_words(w + 1);
let exists = self.words[w] & (1_u32 << b) != 0;
self.words[w] &= !(1_u32 << b);
exists
}
#[inline]
fn set_word(
&mut self,
w: usize,
mask: u32,
f: &mut impl FnMut(usize) -> u32,
) {
self.words[w] = (self.words[w] & !mask) | (f(w) & mask);
}
pub fn set_words(
&mut self,
bits: Range<usize>,
mut f: impl FnMut(usize) -> u32,
) {
if bits.is_empty() {
return;
}
let first_word = bits.start / 32;
let last_word = (bits.end - 1) / 32;
let start_mask = !0_u32 << (bits.start % 32);
let end_mask = !0_u32 >> (31 - ((bits.end - 1) % 32));
self.reserve(last_word + 1);
if first_word == last_word {
self.set_word(first_word, start_mask & end_mask, &mut f);
} else {
self.set_word(first_word, start_mask, &mut f);
for w in (first_word + 1)..last_word {
self.set_word(w, !0, &mut f);
}
self.set_word(last_word, end_mask, &mut f);
}
}
pub fn union_with(&mut self, other: &BitSet) -> bool {
let mut added_bits = false;
self.reserve_words(other.words.len());
for w in 0..other.words.len() {
let uw = self.words[w] | other.words[w];
if uw != self.words[w] {
added_bits = true;
self.words[w] = uw;
}
}
added_bits
}
}
impl Default for BitSet {
fn default() -> BitSet {
BitSet::new()
}
}
impl BitAndAssign for BitSet {
fn bitand_assign(&mut self, rhs: BitSet) {
self.reserve_words(rhs.words.len());
for w in 0..rhs.words.len() {
self.words[w] &= rhs.words[w];
}
}
}
impl BitAnd<BitSet> for BitSet {
type Output = BitSet;
fn bitand(self, rhs: BitSet) -> BitSet {
let mut res = self;
res.bitand_assign(rhs);
res
}
}
impl BitOrAssign for BitSet {
fn bitor_assign(&mut self, rhs: BitSet) {
self.reserve_words(rhs.words.len());
for w in 0..rhs.words.len() {
self.words[w] |= rhs.words[w];
}
}
}
impl BitOr<BitSet> for BitSet {
type Output = BitSet;
fn bitor(self, rhs: BitSet) -> BitSet {
let mut res = self;
res.bitor_assign(rhs);
res
}
}
impl BitXorAssign for BitSet {
fn bitxor_assign(&mut self, rhs: BitSet) {
self.reserve_words(rhs.words.len());
for w in 0..rhs.words.len() {
self.words[w] ^= rhs.words[w];
}
}
}
impl BitXor<BitSet> for BitSet {
type Output = BitSet;
fn bitxor(self, rhs: BitSet) -> BitSet {
let mut res = self;
res.bitxor_assign(rhs);
res
}
}
impl Not for BitSet {
type Output = BitSet;
fn not(self) -> BitSet {
let mut res = self;
for w in 0..res.words.len() {
res.words[w] = !res.words[w];
}
res
}
}
pub struct BitSetIter<'a> {
set: &'a BitSet,
w: usize,
mask: u32,
}
impl<'a> BitSetIter<'a> {
fn new(set: &'a BitSet, start: usize) -> Self {
Self {
set,
w: start / 32,
mask: u32::MAX << (start % 32),
}
}
}
impl<'a> Iterator for BitSetIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
while self.w < self.set.words.len() {
let b = (self.set.words[self.w] & self.mask).trailing_zeros();
if b < 32 {
return Some(self.w * 32 + usize::try_from(b).unwrap());
}
self.mask = u32::MAX;
self.w += 1;
}
None
}
}