Skip to content

Commit 01810c5

Browse files
authored
Don't allocate on the heap for empty bit sets (#10495)
This commit fixes an issue where `CompoundBitSet::with_capacity(0)` would end up allocation space on the heap due to an off-by-one in the implementation. When calculating the maximum bit that might be set the implementation now subtracts one. This more accurately models the maximum bit that could be set and additionally guarantees the property that `with_capacity(0)` does not allocate anything on the heap.
1 parent b727aa1 commit 01810c5

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

cranelift/bitset/src/compound.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,13 @@ impl<T: ScalarBitSetStorage> CompoundBitSet<T> {
243243
/// ```
244244
#[inline]
245245
pub fn ensure_capacity(&mut self, n: usize) {
246-
let (word, _bit) = Self::word_and_bit(n);
246+
// Subtract one from the capacity to get the maximum bit that we might
247+
// set. If `n` is 0 then nothing need be done as no capacity needs to be
248+
// allocated.
249+
let (word, _bit) = Self::word_and_bit(match n.checked_sub(1) {
250+
None => return,
251+
Some(n) => n,
252+
});
247253
if word >= self.elems.len() {
248254
assert!(word < usize::try_from(isize::MAX).unwrap());
249255

@@ -552,3 +558,16 @@ impl<T: ScalarBitSetStorage> Iterator for Iter<'_, T> {
552558
}
553559
}
554560
}
561+
562+
#[cfg(test)]
563+
mod tests {
564+
use super::*;
565+
566+
#[test]
567+
fn zero_capacity_no_allocs() {
568+
let set = CompoundBitSet::<u32>::with_capacity(0);
569+
assert_eq!(set.capacity(), 0);
570+
let set = CompoundBitSet::new();
571+
assert_eq!(set.capacity(), 0);
572+
}
573+
}

0 commit comments

Comments
 (0)