use std::ops::{Deref, DerefMut};
use std::mem::replace;
use std::rc::Rc;
use std::sync::Arc;
use crate::{Datum, DerefTryMut};
use crate::datum::{DatumBox, RcDatum, DatumRc, ArcDatum, DatumArc};
use Datum::{List, Combination};
use Datum::EmptyList as TempLeaf;
pub fn algo1<TT, ET, DR>(top_dr: &mut DR)
where DR: Algo1DatumRef<Target = Datum<TT, ET, DR>>,
{
#[derive(PartialEq, Eq, Copy, Clone)]
enum Class { Branch, Leaf }
#[derive(Copy, Clone)]
enum Side { Left, Right }
let trytake = |node: &mut DR| -> Option<Datum<TT, ET, DR>> {
Algo1DatumRef::try_replace(node, TempLeaf).ok()
};
let set = |node: &mut DR, val: Datum<TT, ET, DR>| {
Algo1DatumRef::set(node, val);
};
let temp_branch = |left_dr: DR, right_dr: DR| -> Datum<TT, ET, DR> {
List{elem: left_dr, next: right_dr}
};
let class = |node: &DR| {
match Deref::deref(node) {
Combination{..} | List{..} => Class::Branch,
_ => Class::Leaf
}
};
let mut mode_lock: Option<Side> = None;
if let Class::Leaf = class(top_dr) {
return; }
let mut top_datum = match trytake(top_dr) {
Some(datum) => datum,
None => return };
loop {
match top_datum {
| Combination{operator: mut left_dr, operands: mut right_dr}
| List{elem: mut left_dr, next: mut right_dr}
=> {
let (left_class, right_class) = (class(&left_dr), class(&right_dr));
let (mode, selected_datum, mut reuse_dr, other_class, other_dr)
= match (mode_lock, left_class, right_class)
{
| (_, Class::Branch, Class::Leaf)
| (Some(Side::Left), Class::Branch, Class::Branch)
=>
if let Some(left_datum) = trytake(&mut left_dr) {
(Side::Left, left_datum, left_dr, right_class, right_dr)
} else {
break
},
| (_, Class::Leaf, Class::Branch)
| (Some(Side::Right), Class::Branch, Class::Branch)
=>
if let Some(right_datum) = trytake(&mut right_dr) {
(Side::Right, right_datum, right_dr, left_class, left_dr)
} else {
break
},
| (None, Class::Branch, Class::Branch)
=>
if let Some(left_datum) = trytake(&mut left_dr) {
(Side::Left, left_datum, left_dr, right_class, right_dr)
} else if let Some(right_datum) = trytake(&mut right_dr) {
(Side::Right, right_datum, right_dr, left_class, left_dr)
} else {
break
},
| (_, Class::Leaf, Class::Leaf)
=> break
};
match (selected_datum, other_class) {
| (Combination{operator: sel_left, operands: sel_right},
Class::Branch)
| (List{elem: sel_left, next: sel_right},
Class::Branch)
=> {
let (oldsub, newsub_left, newsub_right) = match mode {
Side::Left => (sel_left, sel_right, other_dr),
Side::Right => (sel_right, other_dr, sel_left)
};
set(&mut reuse_dr, temp_branch(newsub_left, newsub_right));
let (top_left, top_right) = match mode {
Side::Left => (oldsub, reuse_dr),
Side::Right => (reuse_dr, oldsub)
};
top_datum = temp_branch(top_left, top_right);
if mode_lock.is_none() {
mode_lock = Some(mode);
}
},
(selected_datum, Class::Leaf) => {
top_datum = selected_datum;
mode_lock = None;
},
_ => unreachable!()
}
},
_ => unreachable!()
};
}
}
pub trait Algo1DatumRef: DerefTryMut
where <Self as Deref>::Target: Sized,
{
fn try_replace(this: &mut Self, val: Self::Target)
-> Result<Self::Target, Self::Target>;
fn set(this: &mut Self, val: Self::Target);
}
impl<TT, ET> Algo1DatumRef for DatumBox<TT, ET>
{
#[inline]
fn try_replace(this: &mut Self, val: Self::Target)
-> Result<Self::Target, Self::Target> {
Ok(replace(DerefMut::deref_mut(this), val))
}
#[inline]
fn set(this: &mut Self, val: Self::Target) {
*DerefMut::deref_mut(this) = val;
}
}
impl<TT, ET> Drop for DatumBox<TT, ET> {
#[inline]
fn drop(&mut self) {
algo1(self);
}
}
pub trait RcLike: DerefTryMut
where <Self as Deref>::Target: Sized,
{
type RC: Deref;
fn get_rc(this: &mut Self) -> &mut Self::RC;
fn new_rc(val: <Self as Deref>::Target) -> Self::RC;
fn try_unwrap(rc: Self::RC) -> Result<<Self as Deref>::Target, Self::RC>;
fn try_replace(this: &mut Self, val: <Self as Deref>::Target)
-> Result<<Self as Deref>::Target,
<Self as Deref>::Target>
{
let old_rc = replace(Self::get_rc(this), Self::new_rc(val));
match Self::try_unwrap(old_rc) {
Ok(datum)
=> Ok(datum),
Err(old_rc) => {
let new_rc = replace(Self::get_rc(this), old_rc);
let val = match Self::try_unwrap(new_rc) {
Ok(val) => val,
_ => unreachable!()
};
Err(val)
}
}
}
#[inline]
fn set(this: &mut Self, val: <Self as Deref>::Target) {
*DerefTryMut::get_mut(this).unwrap() = val;
}
}
pub trait RcLikeAtomicCounts: RcLike
where <Self as Deref>::Target: Sized,
{
fn counts(this: &Self) -> (usize, usize);
fn try_replace_optim(this: &mut Self, val: <Self as Deref>::Target)
-> Result<<Self as Deref>::Target,
<Self as Deref>::Target>
{
let (strong_count, weak_count) = Self::counts(this);
if strong_count == 1 {
if weak_count == 0 {
Ok(replace(DerefTryMut::get_mut(this).unwrap(), val))
} else {
Self::try_replace(this, val)
}
} else {
Err(val)
}
}
}
impl<TT, ET> RcLike for DatumRc<TT, ET>
{
type RC = Rc<RcDatum<TT, ET>>;
#[inline]
fn get_rc(this: &mut Self) -> &mut Self::RC {
&mut this.0
}
#[inline]
fn new_rc(val: <Self as Deref>::Target) -> Self::RC {
Rc::new(val)
}
#[inline]
fn try_unwrap(rc: Self::RC) -> Result<<Self as Deref>::Target, Self::RC> {
Rc::try_unwrap(rc)
}
}
impl<TT, ET> RcLikeAtomicCounts for DatumRc<TT, ET> {
#[inline]
fn counts(this: &Self) -> (usize, usize) {
(Rc::strong_count(&this.0), Rc::weak_count(&this.0))
}
}
impl<TT, ET> Algo1DatumRef for DatumRc<TT, ET>
{
#[inline]
fn try_replace(this: &mut Self, val: Self::Target)
-> Result<Self::Target, Self::Target> {
RcLikeAtomicCounts::try_replace_optim(this, val)
}
#[inline]
fn set(this: &mut Self, val: Self::Target) {
RcLike::set(this, val)
}
}
impl<TT, ET> Drop for DatumRc<TT, ET> {
#[inline]
fn drop(&mut self) {
algo1(self);
}
}
impl<TT, ET> RcLike for DatumArc<TT, ET>
{
type RC = Arc<ArcDatum<TT, ET>>;
#[inline]
fn get_rc(this: &mut Self) -> &mut Self::RC {
&mut this.0
}
#[inline]
fn new_rc(val: <Self as Deref>::Target) -> Self::RC {
Arc::new(val)
}
#[inline]
fn try_unwrap(rc: Self::RC) -> Result<<Self as Deref>::Target, Self::RC> {
Arc::try_unwrap(rc)
}
}
impl<TT, ET> Algo1DatumRef for DatumArc<TT, ET>
{
#[inline]
fn try_replace(this: &mut Self, val: Self::Target)
-> Result<Self::Target, Self::Target> {
RcLike::try_replace(this, val)
}
#[inline]
fn set(this: &mut Self, val: Self::Target) {
RcLike::set(this, val)
}
}
impl<TT, ET> Drop for DatumArc<TT, ET> {
#[inline]
fn drop(&mut self) {
algo1(self);
}
}
#[cfg(test)]
mod tests {
use kul_shared_tests::utils::tree_shapes::*;
#[test]
fn deep_box_list() {
let len = list_len(get_arg_tree_size());
let boxes = make_box_list(len);
drop(boxes);
}
#[test]
fn deep_rc_list() {
let len = list_len(get_arg_tree_size());
let rcs = make_rc_list(len);
drop(rcs);
}
#[test]
fn deep_arc_list() {
let len = list_len(get_arg_tree_size());
let arcs = make_arc_list(len);
drop(arcs);
}
#[test]
fn deep_box_nest() {
let depth = nest_depth(get_arg_tree_size());
let boxes = make_box_nest(depth);
drop(boxes);
}
#[test]
fn deep_rc_nest() {
let depth = nest_depth(get_arg_tree_size());
let rcs = make_rc_nest(depth);
drop(rcs);
}
#[test]
fn deep_arc_nest() {
let depth = nest_depth(get_arg_tree_size());
let arcs = make_arc_nest(depth);
drop(arcs);
}
#[test]
fn deep_box_zigzag() {
let depth = zigzag_depth(get_arg_tree_size());
let boxes = make_box_zigzag(depth);
drop(boxes);
}
#[test]
fn deep_rc_zigzag() {
let depth = zigzag_depth(get_arg_tree_size());
let rcs = make_rc_zigzag(depth);
drop(rcs);
}
#[test]
fn deep_arc_zigzag() {
let depth = zigzag_depth(get_arg_tree_size());
let arcs = make_arc_zigzag(depth);
drop(arcs);
}
#[test]
fn deep_box_fan() {
let depth = fan_depth(get_arg_tree_size());
let boxes = make_box_fan(depth);
drop(boxes);
}
#[test]
fn deep_rc_fan() {
let depth = fan_depth(get_arg_tree_size());
let rcs = make_rc_fan(depth);
drop(rcs);
}
#[test]
fn deep_arc_fan() {
let depth = fan_depth(get_arg_tree_size());
let arcs = make_arc_fan(depth);
drop(arcs);
}
fn vee2r_depths(size: usize) -> (usize, usize) {
let right_size = 2 + 1; let left_size = size - (1 + right_size); vee_depths(left_size, right_size)
}
#[test]
fn deep_box_vee2r() {
let (left_depth, right_depth) = vee2r_depths(get_arg_tree_size());
let boxes = make_box_vee(left_depth, right_depth);
drop(boxes);
}
#[test]
fn deep_rc_vee2r() {
let (left_depth, right_depth) = vee2r_depths(get_arg_tree_size());
let rcs = make_rc_vee(left_depth, right_depth);
drop(rcs);
}
#[test]
fn deep_arc_vee2r() {
let (left_depth, right_depth) = vee2r_depths(get_arg_tree_size());
let arcs = make_arc_vee(left_depth, right_depth);
drop(arcs);
}
#[test]
fn deep_rc_weak_list() {
let len = list_len(get_arg_tree_size());
let rcs = make_rc_weak_list(len);
drop(rcs);
}
#[test]
fn deep_arc_weak_list() {
let len = list_len(get_arg_tree_size());
let arcs = make_arc_weak_list(len);
drop(arcs);
}
#[test]
fn deep_rc_multi_strong_list() {
let len = list_len(get_arg_tree_size());
let strong_step = 1;
let (rcs, _strong_refs) = make_rc_multi_strong_list(len, strong_step);
drop(rcs);
}
#[test]
fn deep_arc_multi_strong_list() {
let len = list_len(get_arg_tree_size());
let strong_step = 1;
let (arcs, _strong_refs) = make_arc_multi_strong_list(len, strong_step);
drop(arcs);
}
}