use std::{
cell::RefCell,
collections::HashMap,
rc::Rc,
sync::atomic::{AtomicU32, Ordering},
};
use crate::prelude::ExpandElement;
use super::{Item, Matrix, Variable, VariableKind};
#[derive(Clone, Debug, Default)]
pub struct Allocator {
local_mut_pool: Rc<RefCell<HashMap<Item, Vec<ExpandElement>>>>,
next_id: Rc<AtomicU32>,
}
impl PartialEq for Allocator {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.local_mut_pool, &other.local_mut_pool)
&& Rc::ptr_eq(&self.next_id, &other.next_id)
}
}
impl Allocator {
pub fn create_local(&self, item: Item) -> ExpandElement {
let id = self.new_local_index();
let local = VariableKind::LocalConst { id };
ExpandElement::Plain(Variable::new(local, item))
}
pub fn create_local_mut(&self, item: Item) -> ExpandElement {
if item.elem.is_atomic() {
self.create_local_restricted(item)
} else {
self.reuse_local_mut(item)
.unwrap_or_else(|| ExpandElement::Managed(self.add_local_mut(item)))
}
}
pub fn create_local_restricted(&self, item: Item) -> ExpandElement {
let id = self.new_local_index();
let local = VariableKind::LocalMut { id };
ExpandElement::Plain(Variable::new(local, item))
}
pub fn create_local_array(&self, item: Item, array_size: u32) -> ExpandElement {
let id = self.new_local_index();
let local_array = Variable::new(
VariableKind::LocalArray {
id,
length: array_size,
},
item,
);
ExpandElement::Plain(local_array)
}
pub fn create_slice(&self, item: Item) -> ExpandElement {
let id = self.new_local_index();
let variable = Variable::new(VariableKind::Slice { id }, item);
ExpandElement::Plain(variable)
}
pub fn create_matrix(&self, matrix: Matrix) -> ExpandElement {
let id = self.new_local_index();
let variable = Variable::new(
VariableKind::Matrix { id, mat: matrix },
Item::new(matrix.elem),
);
ExpandElement::Plain(variable)
}
fn reuse_local_mut(&self, item: Item) -> Option<ExpandElement> {
self.local_mut_pool.borrow().get(&item).and_then(|vars| {
vars.iter()
.rev()
.find(|var| matches!(var, ExpandElement::Managed(v) if Rc::strong_count(v) == 1))
.cloned()
})
}
pub fn add_local_mut(&self, item: Item) -> Rc<Variable> {
let id = self.new_local_index();
let local = Variable::new(VariableKind::LocalMut { id }, item);
let var = Rc::new(local);
let expand = ExpandElement::Managed(var.clone());
let mut pool = self.local_mut_pool.borrow_mut();
let variables = pool.entry(item).or_default();
variables.push(expand);
var
}
pub fn new_local_index(&self) -> u32 {
self.next_id.fetch_add(1, Ordering::Release)
}
}