1pub mod buf;
2
3use buf::FixedBuf;
4use off64::usz;
5use std::alloc::alloc_zeroed;
6use std::alloc::Layout;
7use std::cmp::max;
8use std::collections::VecDeque;
9use std::mem::size_of;
10use std::sync::Arc;
11
12#[derive(Clone, Default)]
14struct BufPoolForSize(Arc<parking_lot::Mutex<VecDeque<usize>>>);
15
16struct Inner {
17 align: usize,
18 sizes: Vec<BufPoolForSize>,
19}
20
21#[derive(Clone)]
25pub struct FixedBufPool {
26 inner: Arc<Inner>,
27}
28
29impl FixedBufPool {
30 pub fn with_alignment(align: usize) -> Self {
31 assert!(align > 64);
32 assert!(align.is_power_of_two());
33 let mut sizes = Vec::new();
34 for _ in 0..64 {
35 sizes.push(Default::default());
36 }
37 Self {
38 inner: Arc::new(Inner { align, sizes }),
39 }
40 }
41
42 pub fn new() -> Self {
43 Self::with_alignment(max(64, size_of::<usize>()))
44 }
45
46 pub fn allocate_from_data(&self, data: impl AsRef<[u8]>) -> FixedBuf {
47 let mut buf = self.allocate_with_zeros(data.as_ref().len());
48 buf.copy_from_slice(data.as_ref());
49 buf
50 }
51
52 pub fn allocate_with_zeros(&self, cap: usize) -> FixedBuf {
54 assert!(cap.is_power_of_two());
56 let cap = cap.next_power_of_two();
58 let existing = self.inner.sizes[usz!(cap.ilog2())].0.lock().pop_front();
60 let ptr_and_cap = if let Some(ptr_and_cap) = existing {
61 ptr_and_cap
62 } else {
63 let ptr = unsafe { alloc_zeroed(Layout::from_size_align(cap, self.inner.align).unwrap()) };
64 assert!(!ptr.is_null());
66 let raw = ptr as usize;
67 assert_eq!(raw & (self.inner.align - 1), 0);
68 raw | usz!(cap.ilog2())
69 };
70 FixedBuf {
71 ptr_and_cap,
72 pool: self.clone(),
73 }
74 }
75}