#[doc(hidden)]
pub trait IBitAlloc: Copy + Default {
const BITSET_LEN: usize;
fn allocate(&mut self) -> Option<u16>;
fn is_allocated(&self, id: u16) -> bool;
fn next_available(&self) -> Option<u16>;
fn deallocate(&mut self, index: u16);
fn next_allocated(&self, unit: u16) -> Option<u16>;
fn cells(&self) -> &[u64];
fn count_allocated(&self) -> usize {
let mut count = 0;
for &cell in self.cells() {
count += cell.count_ones() as usize;
}
count
}
}
#[derive(Clone, Copy)]
pub struct BitAlloc<const LEN: usize> {
cells: [u64; LEN],
}
impl<const LEN: usize> Default for BitAlloc<LEN> {
fn default() -> Self {
Self { cells: [0u64; LEN] }
}
}
impl<const LEN: usize> IBitAlloc for BitAlloc<LEN> {
const BITSET_LEN: usize = LEN;
fn allocate(&mut self) -> Option<u16> {
for i in 0..Self::BITSET_LEN {
let cell = self.cells[i];
if cell == u64::MAX {
continue;
}
let pos = cell.trailing_ones();
self.cells[i] = cell | 1 << pos;
return Some(i as u16 * 64 + pos as u16);
}
None
}
fn is_allocated(&self, id: u16) -> bool {
let (pos, bit) = (id >> 6, id & 0b11_1111);
self.cells[pos as usize] & (1 << bit as u32) != 0
}
fn next_available(&self) -> Option<u16> {
for i in 0..Self::BITSET_LEN {
let cell = self.cells[i];
if cell == u64::MAX {
continue;
}
let pos = cell.trailing_ones();
return Some(i as u16 * 64 + pos as u16);
}
None
}
fn deallocate(&mut self, index: u16) {
let (pos, bit) = (index >> 6, index & 0b11_1111);
let cell = self.cells[pos as usize];
self.cells[pos as usize] = cell & !(1 << bit as u32);
}
fn cells(&self) -> &[u64] {
&self.cells
}
fn next_allocated(&self, unit: u16) -> Option<u16> {
array_next_allocated(&self.cells, unit)
}
}
#[derive(Clone, Copy)]
pub struct SummaryAlloc<const LEN: usize> {
cells: [u64; LEN],
summary: u64,
}
impl<const LEN: usize> Default for SummaryAlloc<LEN> {
fn default() -> Self {
Self {
cells: [0u64; LEN],
summary: 0,
}
}
}
impl<const LEN: usize> IBitAlloc for SummaryAlloc<LEN> {
const BITSET_LEN: usize = LEN;
fn allocate(&mut self) -> Option<u16> {
if self.summary == Self::BITMASK_FULL {
return None;
}
let free_cell = self.summary.trailing_ones();
let mut cell = self.cells[free_cell as usize];
let pos = cell.trailing_ones();
cell |= 1 << pos;
self.cells[free_cell as usize] = cell;
if cell == u64::MAX {
self.summary |= 1 << free_cell;
}
Some((free_cell * 64 + pos) as u16)
}
fn is_allocated(&self, id: u16) -> bool {
let (pos, bit) = (id >> 6, id & 0b11_1111);
self.cells[pos as usize] & (1 << bit as u32) != 0
}
fn next_available(&self) -> Option<u16> {
if self.summary == Self::BITMASK_FULL {
return None;
}
let free_cell = self.summary.trailing_ones();
let cell = self.cells[free_cell as usize];
let pos = cell.trailing_ones();
Some((free_cell * 64 + pos) as u16)
}
fn deallocate(&mut self, index: u16) {
let (pos, bit) = (index >> 6, index & 0b11_1111);
let cell = self.cells[pos as usize];
self.cells[pos as usize] = cell & !(1 << bit as u32);
self.summary &= !(1 << pos);
}
fn cells(&self) -> &[u64] {
&self.cells
}
fn next_allocated(&self, unit: u16) -> Option<u16> {
array_next_allocated(&self.cells, unit)
}
}
impl<const LEN: usize> SummaryAlloc<LEN> {
const BITMASK_FULL: u64 = if LEN == 64 {
u64::MAX
} else if LEN > 64 {
panic!("SummaryAlloc supports up to 4096 units");
} else {
(1u64 << LEN) - 1
};
}
fn array_next_allocated<const LEN: usize>(cells: &[u64; LEN], start_unit: u16) -> Option<u16> {
let (mut pos, bit) = (start_unit >> 6, start_unit & 0b11_1111);
let mut cell = cells[pos as usize];
cell &= !((1 << bit as u32) - 1);
if cell != 0 {
let next_bit = cell.trailing_zeros();
return Some(pos * 64 + next_bit as u16);
}
pos += 1;
while (pos as usize) < LEN {
let cell = cells[pos as usize];
if cell != 0 {
let next_bit = cell.trailing_zeros();
return Some(pos * 64 + next_bit as u16);
}
pos += 1;
}
None
}