pub mod buf;
use buf::FixedBuf;
use off64::usz;
use std::alloc::alloc_zeroed;
use std::alloc::Layout;
use std::cmp::max;
use std::collections::VecDeque;
use std::mem::size_of;
use std::sync::Arc;
#[derive(Clone, Default)]
struct BufPoolForSize(Arc<parking_lot::Mutex<VecDeque<usize>>>);
struct Inner {
align: usize,
sizes: Vec<BufPoolForSize>,
}
#[derive(Clone)]
pub struct FixedBufPool {
inner: Arc<Inner>,
}
impl FixedBufPool {
pub fn with_alignment(align: usize) -> Self {
assert!(align > 64);
assert!(align.is_power_of_two());
let mut sizes = Vec::new();
for _ in 0..64 {
sizes.push(Default::default());
}
Self {
inner: Arc::new(Inner { align, sizes }),
}
}
pub fn new() -> Self {
Self::with_alignment(max(64, size_of::<usize>()))
}
pub fn allocate_from_data(&self, data: impl AsRef<[u8]>) -> FixedBuf {
let mut buf = self.allocate_with_zeros(data.as_ref().len());
buf.copy_from_slice(data.as_ref());
buf
}
pub fn allocate_with_zeros(&self, cap: usize) -> FixedBuf {
assert!(cap.is_power_of_two());
let cap = cap.next_power_of_two();
let existing = self.inner.sizes[usz!(cap.ilog2())].0.lock().pop_front();
let ptr_and_cap = if let Some(ptr_and_cap) = existing {
ptr_and_cap
} else {
let ptr = unsafe { alloc_zeroed(Layout::from_size_align(cap, self.inner.align).unwrap()) };
assert!(!ptr.is_null());
let raw = ptr as usize;
assert_eq!(raw & (self.inner.align - 1), 0);
raw | usz!(cap.ilog2())
};
FixedBuf {
ptr_and_cap,
pool: self.clone(),
}
}
}