use std::{cell::RefCell, collections::BTreeMap};
const MIN_POOL_CAPACITY: usize = 64;
#[derive(Default, Debug)]
pub struct ObjectPool {
objects: RefCell<BTreeMap<usize, Vec<Vec<usize>>>>,
}
impl ObjectPool {
pub fn pull<'a>(&'a self, requested_capacity: usize) -> Pooled<'a> {
if requested_capacity < MIN_POOL_CAPACITY
|| self.objects.borrow().is_empty()
{
return Pooled::new(self, Vec::with_capacity(requested_capacity));
}
let mut objects = self.objects.borrow_mut();
if let Some((_, bucket)) = objects.range_mut(requested_capacity..).next() {
if let Some(mut object) = bucket.pop() {
object.clear();
return Pooled::new(self, object);
}
}
Pooled::new(self, Vec::with_capacity(requested_capacity))
}
fn return_to_pool(&self, object: Vec<usize>) {
if object.capacity() < MIN_POOL_CAPACITY {
return;
}
let mut objects = self.objects.borrow_mut();
let cap = object.capacity();
let bucket = objects.entry(cap).or_default();
bucket.push(object);
}
}
#[derive(Debug)]
pub struct Pooled<'object_pool> {
object: Option<Vec<usize>>,
pool: &'object_pool ObjectPool,
}
impl<'object_pool> Pooled<'object_pool> {
fn new(pool: &'object_pool ObjectPool, object: Vec<usize>) -> Self {
Pooled {
object: Some(object),
pool,
}
}
pub fn as_mut(&mut self) -> &mut Vec<usize> {
self.object.as_mut().unwrap()
}
pub fn as_ref(&self) -> &Vec<usize> {
self.object.as_ref().unwrap()
}
}
impl Drop for Pooled<'_> {
fn drop(&mut self) {
if let Some(object) = self.object.take() {
self.pool.return_to_pool(object);
}
}
}
impl std::ops::Deref for Pooled<'_> {
type Target = Vec<usize>;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl std::ops::DerefMut for Pooled<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}