use crate::core::types::NodeId;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet, VecDeque};
pub struct NodeSetPool {
pool: RefCell<Vec<HashSet<NodeId>>>,
max_size: usize,
}
impl NodeSetPool {
pub fn new(max_size: usize) -> Self {
Self {
pool: RefCell::new(Vec::with_capacity(max_size)),
max_size,
}
}
pub fn acquire(&self) -> PooledNodeSet<'_> {
let set = self.pool.borrow_mut().pop().unwrap_or_default();
PooledNodeSet { set, pool: self }
}
fn release(&self, mut set: HashSet<NodeId>) {
set.clear();
let mut pool = self.pool.borrow_mut();
if pool.len() < self.max_size {
pool.push(set);
}
}
pub fn available(&self) -> usize {
self.pool.borrow().len()
}
}
pub struct PooledNodeSet<'a> {
set: HashSet<NodeId>,
pool: &'a NodeSetPool,
}
impl std::ops::Deref for PooledNodeSet<'_> {
type Target = HashSet<NodeId>;
fn deref(&self) -> &Self::Target {
&self.set
}
}
impl std::ops::DerefMut for PooledNodeSet<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.set
}
}
impl Drop for PooledNodeSet<'_> {
fn drop(&mut self) {
let set = std::mem::take(&mut self.set);
self.pool.release(set);
}
}
pub struct NodeMapPool<T> {
pool: RefCell<Vec<HashMap<NodeId, T>>>,
max_size: usize,
}
impl<T> NodeMapPool<T> {
pub fn new(max_size: usize) -> Self {
Self {
pool: RefCell::new(Vec::with_capacity(max_size)),
max_size,
}
}
pub fn acquire(&self) -> PooledNodeMap<'_, T> {
let map = self.pool.borrow_mut().pop().unwrap_or_default();
PooledNodeMap { map, pool: self }
}
fn release(&self, mut map: HashMap<NodeId, T>) {
map.clear();
let mut pool = self.pool.borrow_mut();
if pool.len() < self.max_size {
pool.push(map);
}
}
pub fn available(&self) -> usize {
self.pool.borrow().len()
}
}
pub struct PooledNodeMap<'a, T> {
map: HashMap<NodeId, T>,
pool: &'a NodeMapPool<T>,
}
impl<T> std::ops::Deref for PooledNodeMap<'_, T> {
type Target = HashMap<NodeId, T>;
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<T> std::ops::DerefMut for PooledNodeMap<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.map
}
}
impl<T> Drop for PooledNodeMap<'_, T> {
fn drop(&mut self) {
let map = std::mem::take(&mut self.map);
self.pool.release(map);
}
}
pub struct NodeQueuePool {
pool: RefCell<Vec<VecDeque<NodeId>>>,
max_size: usize,
}
impl NodeQueuePool {
pub fn new(max_size: usize) -> Self {
Self {
pool: RefCell::new(Vec::with_capacity(max_size)),
max_size,
}
}
pub fn acquire(&self) -> PooledNodeQueue<'_> {
let queue = self.pool.borrow_mut().pop().unwrap_or_default();
PooledNodeQueue { queue, pool: self }
}
fn release(&self, mut queue: VecDeque<NodeId>) {
queue.clear();
let mut pool = self.pool.borrow_mut();
if pool.len() < self.max_size {
pool.push(queue);
}
}
pub fn available(&self) -> usize {
self.pool.borrow().len()
}
}
pub struct PooledNodeQueue<'a> {
queue: VecDeque<NodeId>,
pool: &'a NodeQueuePool,
}
impl std::ops::Deref for PooledNodeQueue<'_> {
type Target = VecDeque<NodeId>;
fn deref(&self) -> &Self::Target {
&self.queue
}
}
impl std::ops::DerefMut for PooledNodeQueue<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.queue
}
}
impl Drop for PooledNodeQueue<'_> {
fn drop(&mut self) {
let queue = std::mem::take(&mut self.queue);
self.pool.release(queue);
}
}
thread_local! {
static DEFAULT_SET_POOL: NodeSetPool = NodeSetPool::new(16);
static DEFAULT_MAP_POOL: NodeMapPool<f64> = NodeMapPool::new(16);
static DEFAULT_QUEUE_POOL: NodeQueuePool = NodeQueuePool::new(16);
}
pub fn acquire_node_set() -> PooledNodeSet<'static> {
DEFAULT_SET_POOL.with(|pool| unsafe {
let pool_ref: &'static NodeSetPool = std::mem::transmute(pool);
pool_ref.acquire()
})
}
pub fn acquire_node_map() -> PooledNodeMap<'static, f64> {
DEFAULT_MAP_POOL.with(|pool| unsafe {
let pool_ref: &'static NodeMapPool<f64> = std::mem::transmute(pool);
pool_ref.acquire()
})
}
pub fn acquire_node_queue() -> PooledNodeQueue<'static> {
DEFAULT_QUEUE_POOL.with(|pool| unsafe {
let pool_ref: &'static NodeQueuePool = std::mem::transmute(pool);
pool_ref.acquire()
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::types::NodeId;
#[test]
fn test_node_set_pool() {
let pool = NodeSetPool::new(5);
assert_eq!(pool.available(), 0);
{
let mut set1 = pool.acquire();
set1.insert(NodeId::new(petgraph::graph::NodeIndex::new(1)));
assert_eq!(set1.len(), 1);
}
assert_eq!(pool.available(), 1);
{
let set2 = pool.acquire();
assert_eq!(set2.len(), 0);
}
}
#[test]
fn test_node_map_pool() {
let pool = NodeMapPool::<i32>::new(5);
{
let mut map = pool.acquire();
map.insert(NodeId::new(petgraph::graph::NodeIndex::new(1)), 42);
assert_eq!(map.len(), 1);
}
assert_eq!(pool.available(), 1);
{
let map = pool.acquire();
assert_eq!(map.len(), 0);
}
}
#[test]
fn test_node_queue_pool() {
let pool = NodeQueuePool::new(5);
{
let mut queue = pool.acquire();
queue.push_back(NodeId::new(petgraph::graph::NodeIndex::new(1)));
assert_eq!(queue.len(), 1);
}
assert_eq!(pool.available(), 1);
{
let queue = pool.acquire();
assert_eq!(queue.len(), 0);
}
}
#[test]
fn test_pool_max_size() {
let pool = NodeSetPool::new(2);
{
let _set1 = pool.acquire();
let _set2 = pool.acquire();
let _set3 = pool.acquire();
assert_eq!(pool.available(), 0);
}
assert_eq!(pool.available(), 2);
}
#[test]
fn test_multiple_concurrent_acquisitions() {
let pool = NodeSetPool::new(5);
let set1 = pool.acquire();
let set2 = pool.acquire();
let set3 = pool.acquire();
assert_eq!(pool.available(), 0);
drop(set1);
assert_eq!(pool.available(), 1);
drop(set2);
drop(set3);
assert_eq!(pool.available(), 3);
}
#[test]
fn test_default_pools() {
{
let mut set = acquire_node_set();
set.insert(NodeId::new(petgraph::graph::NodeIndex::new(1)));
assert_eq!(set.len(), 1);
}
{
let mut map = acquire_node_map();
map.insert(NodeId::new(petgraph::graph::NodeIndex::new(1)), 3.14);
assert_eq!(map.len(), 1);
}
{
let mut queue = acquire_node_queue();
queue.push_back(NodeId::new(petgraph::graph::NodeIndex::new(1)));
assert_eq!(queue.len(), 1);
}
}
}