use std::sync::Arc;
use tokio::sync::Mutex;
const DEBRUIJN_POS: [u8; 32] = [
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7,
19, 27, 23, 6, 26, 5, 4, 31,
];
pub struct Allocator {
buffers: Vec<Arc<Mutex<Vec<Vec<u8>>>>>,
}
impl Allocator {
pub fn new() -> Self {
let mut buffers = Vec::with_capacity(17); for _i in 0..17 {
buffers.push(Arc::new(Mutex::new(Vec::new())));
}
Self { buffers }
}
pub async fn get(&self, size: usize) -> Option<Vec<u8>> {
if size == 0 || size > 65536 {
return None;
}
let bits = msb(size);
let actual_bits = if size == 1 << bits { bits } else { bits + 1 };
let pool = &self.buffers[actual_bits as usize];
let mut pool_guard = pool.lock().await;
if let Some(mut buf) = pool_guard.pop() {
buf.resize(size, 0);
Some(buf)
} else {
let mut buf = vec![0; 1 << actual_bits];
buf.resize(size, 0);
Some(buf)
}
}
pub async fn put(&self, mut buf: Vec<u8>) -> Result<(), String> {
let cap = buf.capacity();
if cap == 0 || cap > 65536 {
return Err("allocator Put() incorrect buffer size".to_string());
}
let bits = msb(cap);
if cap != 1 << bits {
return Err("allocator Put() incorrect buffer size".to_string());
}
buf.clear();
buf.resize(cap, 0);
let pool = &self.buffers[bits as usize];
let mut pool_guard = pool.lock().await;
pool_guard.push(buf);
Ok(())
}
}
impl Default for Allocator {
fn default() -> Self {
Self::new()
}
}
fn msb(size: usize) -> u8 {
let v = size as u32;
let v = v | (v >> 1);
let v = v | (v >> 2);
let v = v | (v >> 4);
let v = v | (v >> 8);
let v = v | (v >> 16);
DEBRUIJN_POS[((v.wrapping_mul(0x07C4ACDD)) >> 27) as usize]
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_allocator() {
let alloc = Allocator::new();
let buf1 = alloc.get(100).await.unwrap();
assert_eq!(buf1.len(), 100); assert!(buf1.capacity() >= 100); let cap1 = buf1.capacity();
alloc.put(buf1).await.unwrap();
let buf2 = alloc.get(100).await.unwrap();
assert_eq!(buf2.capacity(), cap1);
assert_eq!(buf2.len(), 100);
let buf3 = alloc.get(1000).await.unwrap();
assert_eq!(buf3.len(), 1000);
assert!(buf3.capacity() >= 1000);
alloc.put(buf3).await.unwrap();
assert!(alloc.get(0).await.is_none());
assert!(alloc.get(70000).await.is_none());
}
#[test]
fn test_msb() {
assert_eq!(msb(1), 0);
assert_eq!(msb(2), 1);
assert_eq!(msb(3), 1);
assert_eq!(msb(4), 2);
assert_eq!(msb(5), 2);
assert_eq!(msb(8), 3);
assert_eq!(msb(16), 4);
}
}