1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker //! Defines bitmap types. 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail; 8*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result; 9*bb4ee6a4SAndroid Build Coastguard Worker 10*bb4ee6a4SAndroid Build Coastguard Worker pub struct BitMap<'a> { 11*bb4ee6a4SAndroid Build Coastguard Worker inner: &'a mut [u8], 12*bb4ee6a4SAndroid Build Coastguard Worker } 13*bb4ee6a4SAndroid Build Coastguard Worker 14*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> BitMap<'a> { 15*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a new bitmap from an underlying buffer. from_slice_mut(inner: &'a mut [u8]) -> Self16*bb4ee6a4SAndroid Build Coastguard Worker pub fn from_slice_mut(inner: &'a mut [u8]) -> Self { 17*bb4ee6a4SAndroid Build Coastguard Worker Self { inner } 18*bb4ee6a4SAndroid Build Coastguard Worker } 19*bb4ee6a4SAndroid Build Coastguard Worker 20*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the bit at the given index. set(&mut self, index: usize, value: bool) -> Result<()>21*bb4ee6a4SAndroid Build Coastguard Worker pub fn set(&mut self, index: usize, value: bool) -> Result<()> { 22*bb4ee6a4SAndroid Build Coastguard Worker let i = index / 8; 23*bb4ee6a4SAndroid Build Coastguard Worker let j = index % 8; 24*bb4ee6a4SAndroid Build Coastguard Worker if i >= self.inner.len() { 25*bb4ee6a4SAndroid Build Coastguard Worker bail!("index out of range"); 26*bb4ee6a4SAndroid Build Coastguard Worker } 27*bb4ee6a4SAndroid Build Coastguard Worker if value { 28*bb4ee6a4SAndroid Build Coastguard Worker self.inner[i] |= 1 << j; 29*bb4ee6a4SAndroid Build Coastguard Worker } else { 30*bb4ee6a4SAndroid Build Coastguard Worker self.inner[i] &= !(1 << j); 31*bb4ee6a4SAndroid Build Coastguard Worker } 32*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 33*bb4ee6a4SAndroid Build Coastguard Worker } 34*bb4ee6a4SAndroid Build Coastguard Worker 35*bb4ee6a4SAndroid Build Coastguard Worker /// Marks the first `n` bits in the bitmap with the given value. mark_first_elems(&mut self, n: usize, value: bool)36*bb4ee6a4SAndroid Build Coastguard Worker pub fn mark_first_elems(&mut self, n: usize, value: bool) { 37*bb4ee6a4SAndroid Build Coastguard Worker self.inner 38*bb4ee6a4SAndroid Build Coastguard Worker .iter_mut() 39*bb4ee6a4SAndroid Build Coastguard Worker .take(n / 8) 40*bb4ee6a4SAndroid Build Coastguard Worker .for_each(|v| *v = if value { 0xff } else { 0 }); 41*bb4ee6a4SAndroid Build Coastguard Worker if n % 8 != 0 { 42*bb4ee6a4SAndroid Build Coastguard Worker if value { 43*bb4ee6a4SAndroid Build Coastguard Worker self.inner[n / 8] |= 0xff >> (8 - n % 8); 44*bb4ee6a4SAndroid Build Coastguard Worker } else { 45*bb4ee6a4SAndroid Build Coastguard Worker self.inner[n / 8] &= !(0xff >> (8 - n % 8)); 46*bb4ee6a4SAndroid Build Coastguard Worker } 47*bb4ee6a4SAndroid Build Coastguard Worker } 48*bb4ee6a4SAndroid Build Coastguard Worker } 49*bb4ee6a4SAndroid Build Coastguard Worker 50*bb4ee6a4SAndroid Build Coastguard Worker // Returns the number of bits in the bitmap. len(&self) -> usize51*bb4ee6a4SAndroid Build Coastguard Worker pub fn len(&self) -> usize { 52*bb4ee6a4SAndroid Build Coastguard Worker self.inner.len() * 8 53*bb4ee6a4SAndroid Build Coastguard Worker } 54*bb4ee6a4SAndroid Build Coastguard Worker } 55*bb4ee6a4SAndroid Build Coastguard Worker 56*bb4ee6a4SAndroid Build Coastguard Worker // Implements test utility methods. 57*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 58*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> BitMap<'a> { 59*bb4ee6a4SAndroid Build Coastguard Worker // Returns the number of bits in the bitmap that are set. count_zeros(&self) -> usize60*bb4ee6a4SAndroid Build Coastguard Worker pub fn count_zeros(&self) -> usize { 61*bb4ee6a4SAndroid Build Coastguard Worker self.inner.iter().map(|b| b.count_zeros() as usize).sum() 62*bb4ee6a4SAndroid Build Coastguard Worker } 63*bb4ee6a4SAndroid Build Coastguard Worker as_slice(&self) -> &[u8]64*bb4ee6a4SAndroid Build Coastguard Worker pub fn as_slice(&self) -> &[u8] { 65*bb4ee6a4SAndroid Build Coastguard Worker self.inner 66*bb4ee6a4SAndroid Build Coastguard Worker } 67*bb4ee6a4SAndroid Build Coastguard Worker } 68*bb4ee6a4SAndroid Build Coastguard Worker 69*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 70*bb4ee6a4SAndroid Build Coastguard Worker mod tests { 71*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 72*bb4ee6a4SAndroid Build Coastguard Worker 73*bb4ee6a4SAndroid Build Coastguard Worker #[test] test_mark_first_elems()74*bb4ee6a4SAndroid Build Coastguard Worker fn test_mark_first_elems() { 75*bb4ee6a4SAndroid Build Coastguard Worker let mut s = [0; 10]; 76*bb4ee6a4SAndroid Build Coastguard Worker let mut b = BitMap::from_slice_mut(&mut s); 77*bb4ee6a4SAndroid Build Coastguard Worker b.mark_first_elems(28, true); 78*bb4ee6a4SAndroid Build Coastguard Worker // (28 + 1) = 8 * 3 + 4. So, the first 3 bytes and 4 bits should be set. 79*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(b.as_slice(), &[0xff, 0xff, 0xff, 0b1111, 0, 0, 0, 0, 0, 0]); 80*bb4ee6a4SAndroid Build Coastguard Worker } 81*bb4ee6a4SAndroid Build Coastguard Worker 82*bb4ee6a4SAndroid Build Coastguard Worker #[test] test_set()83*bb4ee6a4SAndroid Build Coastguard Worker fn test_set() { 84*bb4ee6a4SAndroid Build Coastguard Worker let mut s = [0; 10]; 85*bb4ee6a4SAndroid Build Coastguard Worker let mut b = BitMap::from_slice_mut(&mut s); 86*bb4ee6a4SAndroid Build Coastguard Worker b.set(42, true).unwrap(); 87*bb4ee6a4SAndroid Build Coastguard Worker // (42 + 1) == 8 * 5 + 3. So, 3rd bit at 6th byte should be set. 88*bb4ee6a4SAndroid Build Coastguard Worker // Note that "+1" is needed as this is 0-indexed. 89*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(b.as_slice(), &[0, 0, 0, 0, 0, 0b100, 0, 0, 0, 0]); 90*bb4ee6a4SAndroid Build Coastguard Worker } 91*bb4ee6a4SAndroid Build Coastguard Worker } 92