use crate::collections::{AllocationError, BoxSliceExt};
const NONE: u32 = u32::MAX;
const ALLOCATED: u32 = u32::MAX - 1;
pub struct Pool {
links: Box<[u32]>,
free: u32,
available: u32,
}
impl Pool {
pub fn try_with_capacity(capacity: u32) -> Result<Self, AllocationError> {
let links = BoxSliceExt::try_box_with(capacity as usize, |index| {
let next = index as u32 + 1;
if next == capacity { NONE } else { next }
})?;
Ok(Self {
links,
free: if capacity == 0 { NONE } else { 0 },
available: capacity,
})
}
#[inline]
pub fn capacity(&self) -> u32 {
self.links.len() as u32
}
#[inline]
pub fn available(&self) -> u32 {
self.available
}
#[inline]
pub fn is_exhausted(&self) -> bool {
self.free == NONE
}
#[inline]
pub fn take(&mut self) -> Option<u32> {
if self.is_exhausted() {
return None;
}
Some(unsafe { self.take_available() })
}
#[inline]
pub unsafe fn take_available(&mut self) -> u32 {
let index = self.free;
debug_assert_ne!(index, NONE);
debug_assert!((index as usize) < self.links.len());
let entry = unsafe { self.links.get_unchecked_mut(index as usize) };
self.free = *entry;
*entry = ALLOCATED;
self.available -= 1;
index
}
#[inline]
pub unsafe fn release(&mut self, index: u32) {
debug_assert!((index as usize) < self.links.len());
let entry = unsafe { self.links.get_unchecked_mut(index as usize) };
debug_assert_eq!(*entry, ALLOCATED);
*entry = self.free;
self.free = index;
self.available += 1;
}
}