use std::cell::RefCell;
use std::rc::Rc;
pub(crate) struct Pool<T> {
objects: RefCell<Vec<T>>,
max_capacity: usize,
}
impl<T> Pool<T> {
pub(crate) fn new(max_capacity: usize) -> Self {
Self {
objects: RefCell::new(Vec::with_capacity(std::cmp::min(max_capacity, 16))),
max_capacity,
}
}
#[inline]
pub(crate) fn get<F>(&self, factory: F) -> T
where
F: FnOnce() -> T,
{
self.objects.borrow_mut().pop().unwrap_or_else(factory)
}
#[inline]
pub(crate) fn put(&self, object: T) {
let mut objects = self.objects.borrow_mut();
if objects.len() < self.max_capacity {
objects.push(object);
}
}
#[allow(dead_code)]
pub(crate) fn len(&self) -> usize {
self.objects.borrow().len()
}
#[allow(dead_code)]
pub(crate) fn is_empty(&self) -> bool {
self.objects.borrow().is_empty()
}
}
#[allow(dead_code)]
pub(crate) struct PooledVec<T> {
vec: Option<Vec<T>>,
pool: Rc<Pool<Vec<T>>>,
}
#[allow(dead_code)]
impl<T> PooledVec<T> {
pub(crate) fn new(pool: Rc<Pool<Vec<T>>>) -> Self {
let mut vec = pool.get(Vec::new);
vec.clear(); Self {
vec: Some(vec),
pool,
}
}
#[inline]
pub(crate) fn as_mut(&mut self) -> &mut Vec<T> {
self.vec.as_mut().unwrap()
}
pub(crate) fn take(mut self) -> Vec<T> {
self.vec.take().unwrap()
}
}
impl<T> Drop for PooledVec<T> {
fn drop(&mut self) {
if let Some(mut vec) = self.vec.take() {
vec.clear();
self.pool.put(vec);
}
}
}
impl<T> std::ops::Deref for PooledVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
self.vec.as_ref().unwrap()
}
}
impl<T> std::ops::DerefMut for PooledVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.vec.as_mut().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pool_get_and_put() {
let pool = Pool::new(10);
let vec = pool.get(Vec::new);
assert_eq!(vec.len(), 0);
pool.put(vec);
assert_eq!(pool.len(), 1);
let mut vec = pool.get(Vec::new);
vec.push(42);
pool.put(vec);
let vec = pool.get(Vec::new);
assert_eq!(vec.len(), 1);
assert_eq!(vec[0], 42);
}
#[test]
fn test_pool_max_capacity() {
let pool = Pool::new(2);
pool.put(vec![1]);
pool.put(vec![2]);
pool.put(vec![3]);
assert_eq!(pool.len(), 2);
}
#[test]
fn test_pooled_vec() {
let pool = Rc::new(Pool::new(10));
{
let mut vec = PooledVec::new(pool.clone());
vec.push(1);
vec.push(2);
assert_eq!(vec.len(), 2);
}
assert_eq!(pool.len(), 1);
let vec = PooledVec::new(pool.clone());
assert_eq!(vec.len(), 0); }
#[test]
fn test_pooled_vec_take() {
let pool = Rc::new(Pool::new(10));
let mut vec = PooledVec::new(pool.clone());
vec.push(1);
let inner = vec.take();
assert_eq!(inner.len(), 1);
assert_eq!(pool.len(), 0);
}
#[test]
fn test_pool_concurrent_operations() {
let pool = Rc::new(Pool::new(5));
for _ in 0..10 {
let mut vec = PooledVec::new(pool.clone());
vec.push(1);
vec.push(2);
vec.push(3);
}
assert!(pool.len() <= 5);
}
}