| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //! Defines bitmap types. |
| |
| use anyhow::bail; |
| use anyhow::Result; |
| |
| pub struct BitMap<'a> { |
| inner: &'a mut [u8], |
| } |
| |
| impl<'a> BitMap<'a> { |
| /// Creates a new bitmap from an underlying buffer. |
| pub fn from_slice_mut(inner: &'a mut [u8]) -> Self { |
| Self { inner } |
| } |
| |
| /// Sets the bit at the given index. |
| pub fn set(&mut self, index: usize, value: bool) -> Result<()> { |
| let i = index / 8; |
| let j = index % 8; |
| if i >= self.inner.len() { |
| bail!("index out of range"); |
| } |
| if value { |
| self.inner[i] |= 1 << j; |
| } else { |
| self.inner[i] &= !(1 << j); |
| } |
| Ok(()) |
| } |
| |
| /// Marks the first `n` bits in the bitmap with the given value. |
| pub fn mark_first_elems(&mut self, n: usize, value: bool) { |
| self.inner |
| .iter_mut() |
| .take(n / 8) |
| .for_each(|v| *v = if value { 0xff } else { 0 }); |
| if n % 8 != 0 { |
| if value { |
| self.inner[n / 8] |= 0xff >> (8 - n % 8); |
| } else { |
| self.inner[n / 8] &= !(0xff >> (8 - n % 8)); |
| } |
| } |
| } |
| |
| // Returns the number of bits in the bitmap. |
| pub fn len(&self) -> usize { |
| self.inner.len() * 8 |
| } |
| } |
| |
| // Implements test utility methods. |
| #[cfg(test)] |
| impl<'a> BitMap<'a> { |
| // Returns the number of bits in the bitmap that are set. |
| pub fn count_zeros(&self) -> usize { |
| self.inner.iter().map(|b| b.count_zeros() as usize).sum() |
| } |
| |
| pub fn as_slice(&self) -> &[u8] { |
| self.inner |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[test] |
| fn test_mark_first_elems() { |
| let mut s = [0; 10]; |
| let mut b = BitMap::from_slice_mut(&mut s); |
| b.mark_first_elems(28, true); |
| // (28 + 1) = 8 * 3 + 4. So, the first 3 bytes and 4 bits should be set. |
| assert_eq!(b.as_slice(), &[0xff, 0xff, 0xff, 0b1111, 0, 0, 0, 0, 0, 0]); |
| } |
| |
| #[test] |
| fn test_set() { |
| let mut s = [0; 10]; |
| let mut b = BitMap::from_slice_mut(&mut s); |
| b.set(42, true).unwrap(); |
| // (42 + 1) == 8 * 5 + 3. So, 3rd bit at 6th byte should be set. |
| // Note that "+1" is needed as this is 0-indexed. |
| assert_eq!(b.as_slice(), &[0, 0, 0, 0, 0, 0b100, 0, 0, 0, 0]); |
| } |
| } |