mod collect;
pub mod traverse;
mod types;
pub use types::*;
use crate::entry::{Present, Spot};
use crate::types::{Error, HasIx, Ix, Root, Weak};
use alloc::vec::Vec;
impl<T> Region<T> {
#[inline]
pub fn capacity(&self) -> usize {
self.data.capacity()
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
#[allow(unused)]
pub(crate) fn check_ix(&self, ix: Ix<T>) -> Result<(), Error> {
#[cfg(feature = "debug-arena")]
ix.check_nonce((self.nonce, self.generation))?;
Ok(())
}
pub(crate) fn entry_raw_mut(&mut self, ix: Ix<T>) -> Entry<T> {
let entry = self.data.get_mut(ix.ix()).unwrap();
Entry {
ix,
present: entry.get_mut().unwrap(),
roots: &self.roots,
}
}
pub(crate) fn entry(&self, ix: Ix<T>) -> Result<Present<T>, Error> {
self.check_ix(ix)?;
let entry = self
.data
.get(ix.ix())
.ok_or(Error::Indeterminable)?;
Ok(entry.get().ok_or(Error::UnexpectedInternalState)?)
}
pub(crate) fn weak(&self, ix: Ix<T>) -> Result<Weak<T>, Error> {
self.check_ix(ix)?;
Ok(self.entry(ix)?.weak(ix))
}
pub(crate) fn root(&self, ix: Ix<T>) -> Result<Root<T>, Error> {
self.check_ix(ix)?;
let e = self.entry(ix)?;
let r = e.root(ix);
if !r.is_otherwise_rooted() {
self.roots.borrow_mut().push(r.clone());
}
Ok(r)
}
pub(crate) fn try_get_mut(&mut self, ix: Ix<T>) -> Result<&mut T, Error> {
self.check_ix(ix)?;
let entry = self.data.get_mut(ix.ix()).ok_or(Error::Indeterminable)?;
let present = entry.get_mut().ok_or(Error::UnexpectedInternalState)?;
Ok(present.get_mut())
}
pub(crate) fn try_get(&self, ix: Ix<T>) -> Result<&T, Error> {
self.check_ix(ix)?;
let entry = self.data.get(ix.ix()).ok_or(Error::Indeterminable)?;
let present = entry.get().ok_or(Error::UnexpectedInternalState)?;
Ok(present.get())
}
}
impl<T: 'static + HasIx<T>> Region<T> {
pub fn ensure(&mut self, additional: usize) {
let len = self.data.len();
let cap = self.data.capacity();
if cap >= len + additional {
return;
}
let mut dst = Vec::with_capacity(len + core::cmp::max(len, additional));
#[cfg(feature = "debug-arena")]
let new_gen = (self.nonce, self.generation + 1);
let roots = self.roots.get_mut();
Self::prim_gc_to(
&mut self.data,
&mut dst,
roots,
#[cfg(feature = "debug-arena")]
(self.nonce, self.generation),
#[cfg(feature = "debug-arena")]
new_gen,
);
*roots = roots.drain(..).filter(Root::is_otherwise_rooted).collect();
self.data = dst;
#[cfg(feature = "debug-arena")]
{
self.generation = new_gen.1;
}
}
pub fn alloc<F>(&mut self, make_t: F) -> Entry<T>
where
F: FnOnce(&Self) -> T,
{
self.ensure(1);
let n = self.data.len();
self.data.push(Spot::new(make_t(&self)));
self.entry_raw_mut(Ix::new(
n,
#[cfg(feature = "debug-arena")]
self.nonce,
#[cfg(feature = "debug-arena")]
self.generation,
))
}
pub fn gc(&mut self) {
let mut dst = Vec::with_capacity(self.data.len());
let roots = self.roots.get_mut();
Self::prim_gc_to(
&mut self.data,
&mut dst,
roots,
#[cfg(feature = "debug-arena")]
(self.nonce, self.generation),
#[cfg(feature = "debug-arena")]
(self.nonce, self.generation + 1),
);
let new_roots = self.take_valid_roots().collect();
self.roots.replace(new_roots);
self.data = dst;
#[cfg(feature = "debug-arena")]
{
self.generation = self.generation + 1;
}
}
pub fn gc_into(mut self, other: &mut Region<T>) {
other.ensure(self.data.len());
Self::prim_gc_to(
&mut self.data,
&mut other.data,
self.roots.get_mut(),
#[cfg(feature = "debug-arena")]
(self.nonce, self.generation),
#[cfg(feature = "debug-arena")]
(other.nonce, other.generation),
);
other.roots.get_mut().extend(self.take_valid_roots());
}
fn take_valid_roots(&mut self) -> impl Iterator<Item = Root<T>> + '_ {
self.roots
.get_mut()
.drain(..)
.filter(Root::is_otherwise_rooted)
}
#[inline(always)]
pub fn traverse<'a, I, Strategy, Pre, Post>(
&'a mut self,
strategy: Strategy,
start: I,
pre: Pre,
post: Post,
) where
T: HasIx<T>,
Pre: FnMut(Entry<T>),
Post: FnMut(Entry<T>),
Strategy: traverse::Strategy<T, traverse::PreAndPost>,
Strategy: traverse::Strategy<T, traverse::PreOnly>,
I: IntoIterator<Item = &'a Ix<T>>,
I::IntoIter: Clone,
{
Self::traverse_base::<_, _, traverse::PreAndPost, _>(
strategy,
&mut self.data,
start.into_iter(),
&self.roots,
traverse::PrePostVisitor { pre, post },
#[cfg(feature = "debug-arena")]
(self.nonce, self.generation),
)
}
pub fn traverse_with<'a, I, Strategy, State, Visit>(
&'a mut self,
strategy: Strategy,
start: I,
visitor: Visit,
) where
T: HasIx<T>,
Strategy: traverse::Strategy<T, State>,
Strategy: traverse::Strategy<T, traverse::PreOnly>,
Visit: traverse::Visitor<T, State>,
I: IntoIterator<Item = &'a Ix<T>>,
I::IntoIter: Clone,
{
Self::traverse_base::<_, _, State, _>(
strategy,
&mut self.data,
start.into_iter(),
&self.roots,
visitor,
#[cfg(feature = "debug-arena")]
(self.nonce, self.generation),
)
}
#[deprecated(
since = "0.3.0",
note = "Use Region::traverse with traverse::CallStack instead"
)]
pub fn dfs_mut_cstack<'a, I, F>(&'a mut self, start: I, pre: F)
where
T: HasIx<T>,
F: FnMut(Entry<T>),
I: IntoIterator<Item = &'a Ix<T>>,
I::IntoIter: Clone,
{
self.traverse(traverse::CallStack, start, pre, |_| {});
}
pub fn deep_clone_with<F>(&mut self, mut start: Root<T>, do_clone: F) -> Root<T>
where
F: FnMut(Entry<T>) -> T,
{
#[allow(deprecated)]
Self::deep_clone_with_mut(self, &mut start, do_clone);
start
}
pub fn deep_clone_into_with<F>(
&mut self,
other: &mut Region<T>,
mut start: Root<T>,
do_clone: F,
) -> Root<T>
where
F: FnMut(Entry<T>) -> T,
{
#[allow(deprecated)]
Self::deep_clone_into_with_mut(self, other, &mut start, do_clone);
start
}
#[deprecated(since = "0.3.0", note = "Use Region::deep_clone_with instead")]
pub fn deep_clone_with_mut<F>(&mut self, start: &mut Root<T>, do_clone: F)
where
F: FnMut(Entry<T>) -> T,
{
self.prim_clone_cstack_into(traverse::CallStack, None, start, do_clone);
}
#[deprecated(since = "0.3.0", note = "Use Region::deep_clone_into_with instead")]
pub fn deep_clone_into_with_mut<F>(
&mut self,
other: &mut Region<T>,
start: &mut Root<T>,
do_clone: F,
) where
F: FnMut(Entry<T>) -> T,
{
self.prim_clone_cstack_into(traverse::CallStack, Some(other), start, do_clone);
}
}
impl<T: 'static + HasIx<T> + Clone> Region<T> {
pub fn deep_clone(&mut self, mut start: Root<T>) -> Root<T> {
self.prim_clone_cstack_into(traverse::CallStack, None, &mut start, |e| e.get().clone());
start
}
pub fn deep_clone_into(&mut self, other: &mut Region<T>, mut start: Root<T>) -> Root<T> {
self.prim_clone_cstack_into(traverse::CallStack, Some(other), &mut start, |e| {
e.get().clone()
});
start
}
}