use core::{marker::PhantomData, ops::DerefMut, ptr::NonNull};
use maybe_dangling::MaybeDangling;
use stable_deref_trait::StableDeref;
pub struct MutCursorRootedVec<'l, RootT: 'l, NodeT: ?Sized + 'l> {
top: Option<NonNull<NodeT>>,
root: MaybeDangling<Option<RootT>>,
stack: alloc::vec::Vec<NonNull<NodeT>>,
_marker: PhantomData<(&'l RootT, &'l mut NodeT)>, }
unsafe impl<'l, RootT, NodeT: ?Sized> Sync for MutCursorRootedVec<'l, RootT, NodeT>
where
RootT: Sync,
NodeT: Sync,
{
}
unsafe impl<'l, RootT, NodeT: ?Sized> Send for MutCursorRootedVec<'l, RootT, NodeT>
where
RootT: Send,
NodeT: Send,
{
}
impl<'l, RootT: 'l, NodeT: ?Sized + 'l> MutCursorRootedVec<'l, RootT, NodeT> {
#[inline]
pub fn new(root: RootT) -> Self {
Self {
top: None,
root: MaybeDangling::new(Some(root)),
stack: alloc::vec::Vec::new(),
_marker: PhantomData,
}
}
#[inline]
pub fn new_with_capacity(root: RootT, capacity: usize) -> Self {
Self {
top: None,
root: MaybeDangling::new(Some(root)),
stack: alloc::vec::Vec::with_capacity(capacity),
_marker: PhantomData,
}
}
#[inline]
pub fn is_root(&self) -> bool {
self.top.is_none()
}
#[inline]
pub fn root(&self) -> Option<&RootT> {
if self.top.is_none() {
self.root.as_ref()
} else {
None
}
}
#[inline]
pub fn top(&self) -> Option<&NodeT> {
self.top.map(|node_ptr| unsafe{ node_ptr.as_ref() })
}
#[inline]
pub fn root_mut(&mut self) -> Option<&mut RootT> {
if self.top.is_none() {
self.root.as_mut()
} else {
None
}
}
#[inline]
pub fn take_root(&mut self) -> Option<RootT> {
self.to_root();
self.root.take()
}
#[inline]
pub fn replace_root(&mut self, root: RootT) {
if self.top.is_none() {
*self.root = Some(root);
} else {
panic!("Illegal operation, unable to replace borrowed root");
}
}
#[inline]
pub fn top_mut(&mut self) -> Option<&mut NodeT> {
self.top.map(|mut node_ptr| unsafe{ node_ptr.as_mut() })
}
#[inline]
pub fn top_or_advance_mut<F, NodeRef>(&mut self, step_f: F) -> &mut NodeT
where
F: FnOnce(&mut RootT) -> &mut NodeRef,
NodeRef: DerefMut<Target = NodeT> + StableDeref + 'l,
{
match &self.top {
Some(mut node_ptr) => unsafe{ node_ptr.as_mut() },
None => {
debug_assert_eq!(self.stack.len(), 0);
let new_node_stable_ref = step_f(self.root.as_mut().unwrap());
let mut node_ptr = NonNull::from(&mut **new_node_stable_ref);
self.top = Some(node_ptr);
unsafe{ node_ptr.as_mut() }
}
}
}
#[inline]
pub fn top_or_advance_mut_twostep<F, G, IntermediateRef>(&mut self, step_f1: F, step_f2: G) -> &mut NodeT
where
F: FnOnce(&mut RootT) -> &mut IntermediateRef,
IntermediateRef: DerefMut + StableDeref + 'l,
G: FnOnce(&mut IntermediateRef::Target) -> &mut NodeT,
{
match &self.top {
Some(mut node_ptr) => unsafe{ node_ptr.as_mut() },
None => {
debug_assert_eq!(self.stack.len(), 0);
let intermediate_stable_ref = step_f1(self.root.as_mut().unwrap());
let new_node = step_f2(intermediate_stable_ref);
let mut node_ptr = NonNull::from(new_node);
self.top = Some(node_ptr);
unsafe{ node_ptr.as_mut() }
}
}
}
#[inline]
pub fn into_root(self) -> RootT {
MaybeDangling::into_inner(self.root).unwrap()
}
#[inline]
pub fn depth(&self) -> usize {
if self.top.is_some() {
self.stack.len() + 1
} else {
0
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.stack.capacity() + 1
}
#[inline]
pub fn advance_if_empty<F, NodeRef>(&mut self, step_f: F)
where
F: FnOnce(&mut RootT) -> &mut NodeRef,
NodeRef: DerefMut<Target = NodeT> + StableDeref + 'l,
{
self.advance_if_empty_twostep(step_f, |node| node);
}
#[inline]
pub fn advance_if_empty_twostep<F, G, IntermediateRef>(&mut self, step_f1: F, step_f2: G)
where
F: FnOnce(&mut RootT) -> &mut IntermediateRef,
IntermediateRef: DerefMut + StableDeref + 'l,
G: FnOnce(&mut IntermediateRef::Target) -> &mut NodeT,
{
if self.top.is_none() {
debug_assert_eq!(self.stack.len(), 0);
let intermediate_stable_ref = step_f1(self.root.as_mut().unwrap());
let new_node = step_f2(intermediate_stable_ref);
let node_ptr = NonNull::from(new_node);
self.top = Some(node_ptr);
}
}
#[inline]
pub fn advance_from_root<F, NodeRef>(&mut self, step_f: F) -> bool
where
F: FnOnce(&mut RootT) -> Option<&mut NodeRef>,
NodeRef: DerefMut<Target = NodeT> + StableDeref + 'l,
{
self.advance_from_root_twostep(step_f, |node| Some(node))
}
#[inline]
pub fn advance_from_root_twostep<F, G, IntermediateRef>(&mut self, step_f1: F, step_f2: G) -> bool
where
F: FnOnce(&mut RootT) -> Option<&mut IntermediateRef>,
IntermediateRef: DerefMut + StableDeref + 'l,
G: FnOnce(&mut IntermediateRef::Target) -> Option<&mut NodeT>,
{
self.to_root();
if let Some(intermediate_stable_ref) = step_f1(self.root.as_mut().unwrap()) {
if let Some(new_node) = step_f2(intermediate_stable_ref) {
let node_ptr = NonNull::from(new_node);
self.top = Some(node_ptr);
return true;
}
}
false
}
#[inline]
pub fn advance<F>(&mut self, step_f: F) -> bool
where
F: FnOnce(&mut NodeT) -> Option<&mut NodeT>,
{
match step_f(self.top_mut().expect("Cursor at root. Must call `advance_from_root` before `advance`")) {
Some(new_node) => {
let new_ptr = NonNull::from(new_node);
if let Some(old_top) = self.top.replace(new_ptr) {
self.stack.push(old_top);
}
true
},
None => false
}
}
#[inline]
pub fn backtrack(&mut self) {
match self.stack.pop() {
Some(top_ptr) => {
self.top = Some(top_ptr);
},
None => {
if self.top.is_some() {
self.top = None;
} else {
panic!("MutCursor must contain valid reference")
}
}
}
}
#[inline]
pub fn try_backtrack_node(&mut self) {
match self.stack.pop() {
Some(top_ptr) => {
self.top = Some(top_ptr);
},
None => {}
}
}
#[inline]
pub fn to_root(&mut self) {
self.top = None;
self.stack.clear();
}
#[inline]
pub fn to_bottom(&mut self) {
if self.stack.len() > 0 {
self.stack.truncate(1);
match self.stack.pop() {
Some(top_ptr) => self.top = Some(top_ptr),
None => debug_assert!(self.top.is_none())
}
}
}
}
#[cfg(test)]
mod test {
use std::*;
use std::boxed::*;
use std::vec::Vec;
use crate::*;
struct TreeNode {
val: usize,
next: Option<Box<TreeNode>>
}
impl TreeNode {
fn new(count: usize) -> Self {
if count > 0 {
Self {val: count, next: Some(Box::new(Self::new(count-1)))}
} else {
Self {val: 0, next: None}
}
}
fn traverse_to_box(&mut self) -> Option<&mut Box<Self>> {
self.next.as_mut()
}
fn traverse(&mut self) -> Option<&mut Self> {
self.traverse_to_box().map(|boxed| boxed as _)
}
}
#[test]
fn rooted_vec_basics() {
let tree = TreeNode::new(10);
let mut node_stack: MutCursorRootedVec::<TreeNode, TreeNode> = MutCursorRootedVec::new(tree);
node_stack.advance_from_root(|root| root.traverse_to_box());
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().unwrap().val, 0);
assert_eq!(node_stack.depth(), 10);
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 1);
assert_eq!(node_stack.depth(), 9);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 4);
assert_eq!(node_stack.depth(), 6);
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().unwrap().val, 0);
assert_eq!(node_stack.depth(), 10);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 6);
assert_eq!(node_stack.depth(), 4);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 9);
assert_eq!(node_stack.depth(), 1);
node_stack.backtrack();
assert!(node_stack.top().is_none());
assert_eq!(node_stack.root().unwrap().val, 10);
assert_eq!(node_stack.into_root().val, 10);
}
use std::{thread, thread::ScopedJoinHandle};
#[test]
fn rooted_vec_multi_thread_test() {
let thread_cnt = 128;
let mut data: Vec<TreeNode> = vec![];
for _ in 0..thread_cnt {
data.push(TreeNode::new(10));
}
thread::scope(|scope| {
let mut threads: Vec<ScopedJoinHandle<()>> = Vec::with_capacity(thread_cnt);
for _ in 0..thread_cnt {
let tree = data.pop().unwrap();
let mut node_stack: MutCursorRootedVec::<TreeNode, TreeNode> = MutCursorRootedVec::new(tree);
let thread = scope.spawn(move || {
node_stack.advance_from_root(|root| root.traverse_to_box());
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().unwrap().val, 0);
assert_eq!(node_stack.depth(), 10);
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 1);
assert_eq!(node_stack.depth(), 9);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 4);
assert_eq!(node_stack.depth(), 6);
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().unwrap().val, 0);
assert_eq!(node_stack.depth(), 10);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 6);
assert_eq!(node_stack.depth(), 4);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().unwrap().val, 9);
assert_eq!(node_stack.depth(), 1);
node_stack.backtrack();
assert!(node_stack.top().is_none());
assert_eq!(node_stack.root().unwrap().val, 10);
assert_eq!(node_stack.into_root().val, 10);
});
threads.push(thread);
};
for thread in threads {
thread.join().unwrap();
}
});
}
}