use std::cell::Cell;
use std::collections::VecDeque;
pub(crate) mod tls_pool {
use std::cell::Cell;
use std::collections::VecDeque;
use std::thread::LocalKey;
pub(crate) const MAX_POOLED: usize = 64;
pub(crate) const MAX_POOLED_BYTES: usize = 2 * 1024 * 1024;
pub(crate) fn take<T>(pool: &'static LocalKey<Cell<VecDeque<T>>>, fits: impl Fn(&T) -> bool) -> Option<T> {
pool.try_with(|p| {
let mut items = p.take();
let item = items.iter().rposition(fits).and_then(|i| items.remove(i));
p.set(items);
item
})
.ok()
.flatten()
}
pub(crate) fn recycle<T>(pool: &'static LocalKey<Cell<VecDeque<T>>>, item: T, bytes: usize) {
if bytes == 0 || bytes > MAX_POOLED_BYTES {
return;
}
let _ = pool.try_with(|p| {
let mut items = p.take();
if items.len() == MAX_POOLED {
items.pop_front();
}
items.push_back(item);
p.set(items);
});
}
}
thread_local! {
static BUF_POOL: Cell<VecDeque<Vec<u8>>> = const { Cell::new(VecDeque::new()) };
}
pub(super) fn is_tight(capacity: usize, need: usize) -> bool {
capacity <= need.saturating_mul(2)
}
#[derive(Default)]
pub struct PooledBuf(pub Vec<u8>);
impl PooledBuf {
pub fn with_capacity(size: usize) -> Self {
if size == 0 {
return PooledBuf(Vec::new());
}
PooledBuf(
tls_pool::take(&BUF_POOL, |b| b.capacity() >= size && is_tight(b.capacity(), size))
.unwrap_or_else(|| Vec::with_capacity(size)),
)
}
#[allow(clippy::uninit_vec)]
pub(super) unsafe fn uninit(size: usize) -> Self {
let mut buf = Self::with_capacity(size);
unsafe { buf.0.set_len(size) };
buf
}
}
impl std::ops::Deref for PooledBuf {
type Target = Vec<u8>;
fn deref(&self) -> &Vec<u8> {
&self.0
}
}
impl std::ops::DerefMut for PooledBuf {
fn deref_mut(&mut self) -> &mut Vec<u8> {
&mut self.0
}
}
impl Drop for PooledBuf {
fn drop(&mut self) {
let mut buf = std::mem::take(&mut self.0);
buf.clear();
let cap = buf.capacity();
tls_pool::recycle(&BUF_POOL, buf, cap);
}
}
#[cfg(test)]
pub(super) fn drain_pool() -> VecDeque<Vec<u8>> {
BUF_POOL.with(Cell::take)
}
#[cfg(test)]
#[path = "tests/batch_pool.rs"]
mod tests;
#[cfg(test)]
#[path = "benches/batch_pool.rs"]
mod bench;