#![allow(unsafe_code, reason = "Purpose is unsafe abstraction")]
use std::cell::UnsafeCell;
use hashbrown::HashMap;
use crate::NodeId;
#[derive(Debug)]
struct TreeNode<T> {
item: T,
children: Vec<NodeId>,
}
#[derive(Debug)]
struct DataMap<T> {
items: HashMap<NodeId, Box<UnsafeCell<TreeNode<T>>>>,
parents: HashMap<NodeId, Option<NodeId>>,
}
#[derive(Debug)]
pub struct TreeArena<T> {
data_map: DataMap<T>,
roots: Vec<NodeId>,
}
#[derive(Debug)]
pub struct ArenaRef<'arena, T> {
pub parent_id: Option<NodeId>,
pub item: &'arena T,
pub children: ArenaRefList<'arena, T>,
}
#[derive(Debug)]
pub struct ArenaRefList<'arena, T> {
parent_arena: &'arena DataMap<T>,
parent_id: Option<NodeId>,
}
#[derive(Debug)]
pub struct ArenaMut<'arena, T> {
pub parent_id: Option<NodeId>,
pub item: &'arena mut T,
pub children: ArenaMutList<'arena, T>,
}
#[derive(Debug)]
pub struct ArenaMutList<'arena, T> {
parent_arena: &'arena mut DataMap<T>,
parent_id: Option<NodeId>,
child_arr: &'arena mut Vec<NodeId>,
}
impl<Item> Clone for ArenaRef<'_, Item> {
fn clone(&self) -> Self {
*self
}
}
impl<Item> Copy for ArenaRef<'_, Item> {}
impl<T> Clone for ArenaRefList<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<Item> Copy for ArenaRefList<'_, Item> {}
impl<T> DataMap<T> {
fn new() -> Self {
Self {
items: HashMap::new(),
parents: HashMap::new(),
}
}
fn find_node(&self, id: NodeId) -> Option<&TreeNode<T>> {
let node_cell = self.items.get(&id)?;
Some(unsafe { node_cell.get().as_ref()? })
}
fn find_inner(&self, id: NodeId) -> Option<ArenaRef<'_, T>> {
let parent_id = *self.parents.get(&id)?;
let TreeNode { item, .. } = self.find_node(id)?;
let children = ArenaRefList {
parent_arena: self,
parent_id: Some(id),
};
Some(ArenaRef {
parent_id,
item,
children,
})
}
fn find_mut_inner(&mut self, id: NodeId) -> Option<ArenaMut<'_, T>> {
let parent_id = *self.parents.get(&id)?;
let node_cell = self.items.get(&id)?;
let TreeNode { item, children } = unsafe { node_cell.get().as_mut()? };
let children = ArenaMutList {
parent_arena: self,
parent_id: Some(id),
child_arr: children,
};
Some(ArenaMut {
parent_id,
item,
children,
})
}
fn get_id_path(&self, id: NodeId, start_id: Option<NodeId>) -> Vec<NodeId> {
let mut path = Vec::new();
if !self.parents.contains_key(&id) {
return path;
}
let mut current_id = Some(id);
while let Some(current) = current_id {
path.push(current);
current_id = *self.parents.get(¤t).unwrap();
if current_id == start_id {
break;
}
}
if current_id != start_id {
path.clear();
}
path
}
}
impl<T> TreeArena<T> {
pub fn new() -> Self {
Self {
data_map: DataMap::new(),
roots: Vec::new(),
}
}
pub fn roots(&self) -> ArenaRefList<'_, T> {
ArenaRefList {
parent_arena: &self.data_map,
parent_id: None,
}
}
pub fn root_ids(&self) -> impl Iterator<Item = NodeId> {
self.roots.iter().copied()
}
pub fn roots_mut(&mut self) -> ArenaMutList<'_, T> {
let roots = &mut self.roots;
ArenaMutList {
parent_arena: &mut self.data_map,
parent_id: None,
child_arr: roots,
}
}
pub fn find(&self, id: impl Into<NodeId>) -> Option<ArenaRef<'_, T>> {
self.data_map.find_inner(id.into())
}
pub fn find_mut(&mut self, id: impl Into<NodeId>) -> Option<ArenaMut<'_, T>> {
self.data_map.find_mut_inner(id.into())
}
pub fn get_id_path(&self, id: impl Into<NodeId>) -> Vec<NodeId> {
self.data_map.get_id_path(id.into(), None)
}
pub fn reparent(&mut self, child: impl Into<NodeId>, new_parent: impl Into<NodeId>) {
let child_id = child.into();
let new_parent_id = new_parent.into();
assert_ne!(
child_id, new_parent_id,
"expected child to be different from new_parent but both have id #{child_id}"
);
assert!(
!self.get_id_path(new_parent_id).contains(&child_id),
"cannot reparent because new_parent #{new_parent_id} is a child of the to-be-reparented node #{child_id}"
);
assert!(
!self.roots.contains(&child_id),
"reparenting of root nodes is currently not supported"
);
assert!(
self.data_map.items.contains_key(&new_parent_id),
"no node found for new_parent id #{new_parent_id}"
);
let old_parent_id = self
.data_map
.parents
.get(&child_id)
.unwrap_or_else(|| panic!("no node found for child id #{child_id}"))
.unwrap();
self.find_mut(old_parent_id)
.unwrap()
.children
.child_arr
.retain(|i| *i != child_id);
self.data_map.parents.insert(child_id, Some(new_parent_id));
self.find_mut(new_parent_id)
.unwrap_or_else(|| panic!("no node found for child id #{new_parent_id}"))
.children
.child_arr
.push(child_id);
}
}
impl<T> Default for TreeArena<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> ArenaRef<'_, T> {
pub fn id(&self) -> NodeId {
self.children
.parent_id
.expect("ArenaRefList always has a parent_id when it's a member of ArenaRef")
}
pub fn child_ids(&self) -> impl IntoIterator<Item = NodeId> {
self.children
.parent_arena
.find_node(self.id())
.into_iter()
.flat_map(|c: &TreeNode<T>| &c.children)
.copied()
}
}
impl<'arena, T> ArenaRefList<'arena, T> {
fn is_descendant(&self, id: NodeId) -> bool {
if self.parent_arena.items.contains_key(&id) {
let parent_id = self.parent_id;
if parent_id.is_none() {
return true;
}
!self.parent_arena.get_id_path(id, parent_id).is_empty()
} else {
false
}
}
pub fn has(&self, id: impl Into<NodeId>) -> bool {
let child_id = id.into();
let parent_id = self.parent_id;
self.parent_arena
.parents
.get(&child_id)
.map(|parent| *parent == parent_id) .unwrap_or_default()
}
pub fn item(&self, id: impl Into<NodeId>) -> Option<ArenaRef<'_, T>> {
let id = id.into();
if self.has(id) {
self.parent_arena.find_inner(id)
} else {
None
}
}
pub fn into_item(self, id: impl Into<NodeId>) -> Option<ArenaRef<'arena, T>> {
let id = id.into();
if self.has(id) {
self.parent_arena.find_inner(id)
} else {
None
}
}
pub fn find(self, id: impl Into<NodeId>) -> Option<ArenaRef<'arena, T>> {
let id: NodeId = id.into();
if self.is_descendant(id) {
self.parent_arena.find_inner(id)
} else {
None
}
}
}
impl<T> ArenaMut<'_, T> {
pub fn id(&self) -> NodeId {
self.children
.parent_id
.expect("ArenaMutList always has a parent_id when it's a member of ArenaMut")
}
pub fn reborrow(&mut self) -> ArenaRef<'_, T> {
ArenaRef {
parent_id: self.parent_id,
item: self.item,
children: self.children.reborrow(),
}
}
pub fn reborrow_mut(&mut self) -> ArenaMut<'_, T> {
ArenaMut {
parent_id: self.parent_id,
item: self.item,
children: self.children.reborrow_mut(),
}
}
}
impl<'arena, T> ArenaMutList<'arena, T> {
fn is_descendant(&self, id: NodeId) -> bool {
self.reborrow().is_descendant(id)
}
pub fn has(&self, id: impl Into<NodeId>) -> bool {
self.reborrow().has(id)
}
pub fn item(&self, id: impl Into<NodeId>) -> Option<ArenaRef<'_, T>> {
let id = id.into();
if self.has(id) {
self.parent_arena.find_inner(id)
} else {
None
}
}
pub fn item_mut(&mut self, id: impl Into<NodeId>) -> Option<ArenaMut<'_, T>> {
let id = id.into();
if self.has(id) {
self.parent_arena.find_mut_inner(id)
} else {
None
}
}
pub fn into_item(self, id: impl Into<NodeId>) -> Option<ArenaRef<'arena, T>> {
let id = id.into();
if self.has(id) {
self.parent_arena.find_inner(id)
} else {
None
}
}
pub fn into_item_mut(self, id: impl Into<NodeId>) -> Option<ArenaMut<'arena, T>> {
let id = id.into();
if self.has(id) {
self.parent_arena.find_mut_inner(id)
} else {
None
}
}
pub fn insert(&mut self, child_id: impl Into<NodeId>, value: T) -> ArenaMut<'_, T> {
let child_id: NodeId = child_id.into();
assert!(
!self.parent_arena.parents.contains_key(&child_id),
"Key already present"
);
self.parent_arena.parents.insert(child_id, self.parent_id);
self.child_arr.push(child_id);
let node = TreeNode {
item: value,
children: Vec::new(),
};
self.parent_arena
.items
.insert(child_id, Box::new(UnsafeCell::new(node)));
self.parent_arena.find_mut_inner(child_id).unwrap()
}
#[must_use]
pub fn remove(&mut self, child_id: impl Into<NodeId>) -> Option<T> {
let child_id: NodeId = child_id.into();
if self.has(child_id) {
fn remove_children<T>(id: NodeId, data_map: &mut DataMap<T>) -> T {
let node = data_map.items.remove(&id).unwrap().into_inner();
for child_id in node.children.into_iter() {
remove_children(child_id, data_map);
}
data_map.parents.remove(&id);
node.item
}
self.child_arr.retain(|i| *i != child_id);
Some(remove_children(child_id, self.parent_arena))
} else {
None
}
}
pub fn reborrow(&self) -> ArenaRefList<'_, T> {
ArenaRefList {
parent_arena: self.parent_arena,
parent_id: self.parent_id,
}
}
pub fn reborrow_mut(&mut self) -> ArenaMutList<'_, T> {
ArenaMutList {
parent_arena: self.parent_arena,
parent_id: self.parent_id,
child_arr: self.child_arr,
}
}
pub fn find(&self, id: impl Into<NodeId>) -> Option<ArenaRef<'_, T>> {
self.reborrow().find(id)
}
pub fn find_mut(self, id: impl Into<NodeId>) -> Option<ArenaMut<'arena, T>> {
let id = id.into();
if self.is_descendant(id) {
self.parent_arena.find_mut_inner(id)
} else {
None
}
}
#[doc(hidden)]
pub fn realloc_inner_storage(&mut self) {
let capacity = self.parent_arena.items.capacity();
let capacity = std::hint::black_box(capacity);
self.parent_arena.items.reserve(capacity + 32);
if std::hint::black_box(true) {
self.parent_arena.items.shrink_to_fit();
}
}
}