From f43e57b3c07680eeb6cbab522beaf5eef6185f04 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Thu, 21 May 2026 13:39:58 -0400 Subject: [PATCH] compiler/rust/bitset: Add find_next_[un]set() helpers Reviewed-by: Mel Henning Part-of: --- src/compiler/rust/bitset.rs | 90 +++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/src/compiler/rust/bitset.rs b/src/compiler/rust/bitset.rs index 204912052b5..d9329156107 100644 --- a/src/compiler/rust/bitset.rs +++ b/src/compiler/rust/bitset.rs @@ -71,6 +71,8 @@ struct BitIndex { } impl BitIndex { + const ZERO: BitIndex = BitIndex { word: 0, bit: 0 }; + const fn flatten(self) -> usize { self.word * 32 + (self.bit as usize) } @@ -81,6 +83,10 @@ impl BitIndex { bit: (idx % 32) as u8, } } + + const fn from_word(word: usize) -> BitIndex { + BitIndex { word, bit: 0 } + } } impl From for BitIndex { @@ -112,6 +118,52 @@ impl Add for BitIndex { } } +#[inline] +fn find_next_set(words: &[u32], start: BitIndex) -> Option { + if start.word >= words.len() { + return None; + } + + let mut word = start.word; + let mut mask = u32::MAX << start.bit; + while word < words.len() { + let bit = (words[word] & mask).trailing_zeros(); + if bit < 32 { + return Some(BitIndex { + word, + bit: bit as u8, + }); + } + mask = u32::MAX; + word += 1; + } + + None +} + +#[inline] +fn find_next_unset(words: &[u32], start: BitIndex) -> BitIndex { + if start.word >= words.len() { + return start; + } + + let mut word = start.word; + let mut mask = !(u32::MAX << start.bit); + while word < words.len() { + let bit = (words[word] | mask).trailing_ones(); + if bit < 32 { + return BitIndex { + word, + bit: bit as u8, + }; + } + mask = 0; + word += 1; + } + + BitIndex::from_word(words.len()) +} + /// A set implemented as an array of bits /// /// Unlike `HashSet` and similar containers which actually store the provided @@ -199,21 +251,7 @@ impl BitSet { impl BitSet { 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 + find_next_unset(&self.words, start.into()).into() } /// Search for a set of `count` consecutive elements that are not present in @@ -513,16 +551,14 @@ binop!( struct BitSetIter<'a, K> { set: &'a BitSet, - w: usize, - mask: u32, + idx: BitIndex, } impl<'a, K> BitSetIter<'a, K> { fn new(set: &'a BitSet) -> Self { Self { set, - w: 0, - mask: u32::MAX, + idx: BitIndex::ZERO, } } } @@ -531,17 +567,13 @@ impl<'a, K: FromBitIndex> Iterator for BitSetIter<'a, K> { type Item = K; fn next(&mut self) -> Option { - while self.w < self.set.words.len() { - let b = (self.set.words[self.w] & self.mask).trailing_zeros(); - if b < 32 { - self.mask &= !(1 << b); - let idx = self.w * 32 + usize::try_from(b).unwrap(); - return Some(K::from_bit_index(idx)); - } - self.mask = u32::MAX; - self.w += 1; + if let Some(idx) = find_next_set(&self.set.words, self.idx) { + self.idx = idx + 1; + Some(K::from_bit_index(idx.into())) + } else { + self.idx = BitIndex::from_word(self.set.words.len()); + None } - None } }