121 lines
3.5 KiB
Rust
121 lines
3.5 KiB
Rust
use super::derivation::descendants;
|
|
use super::tree::CapTree;
|
|
|
|
const N: usize = 12;
|
|
|
|
/// The tree as a plain parent array, updated by the rules the tree must
|
|
/// follow; `descendants` from derivation.rs answers subtree questions.
|
|
struct Model {
|
|
live: [bool; N],
|
|
parents: [Option<u16>; N],
|
|
}
|
|
|
|
impl Model {
|
|
fn detach(&mut self, i: usize) {
|
|
let grandparent = self.parents[i];
|
|
for p in self.parents.iter_mut() {
|
|
if *p == Some(i as u16) {
|
|
*p = grandparent;
|
|
}
|
|
}
|
|
self.live[i] = false;
|
|
self.parents[i] = None;
|
|
}
|
|
|
|
fn below(&self, root: usize) -> [bool; N] {
|
|
let mut d = descendants(&self.parents, root);
|
|
d[root] = false;
|
|
d
|
|
}
|
|
}
|
|
|
|
struct Rng(u64);
|
|
impl Rng {
|
|
fn below(&mut self, n: usize) -> usize {
|
|
self.0 ^= self.0 << 13;
|
|
self.0 ^= self.0 >> 7;
|
|
self.0 ^= self.0 << 17;
|
|
(self.0 % n as u64) as usize
|
|
}
|
|
}
|
|
|
|
fn check(t: &CapTree<N>, m: &Model) {
|
|
for i in 0..N {
|
|
assert_eq!(t.is_live(i), m.live[i], "liveness of {i}");
|
|
assert_eq!(t.parent(i), m.parents[i].map(usize::from), "parent of {i}");
|
|
if !m.live[i] {
|
|
continue;
|
|
}
|
|
let mut out = [0u16; N];
|
|
let n = t.descendants(i, &mut out);
|
|
let mut got = [false; N];
|
|
for d in &out[..n] {
|
|
assert!(!got[*d as usize], "{d} listed twice under {i}");
|
|
got[*d as usize] = true;
|
|
}
|
|
assert_eq!(got, m.below(i), "subtree of {i}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn matches_the_parent_array_model_under_random_operations() {
|
|
for seed in 1..200u64 {
|
|
let mut rng = Rng(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15));
|
|
let mut t = CapTree::<N>::new();
|
|
let mut m = Model {
|
|
live: [false; N],
|
|
parents: [None; N],
|
|
};
|
|
for _ in 0..300 {
|
|
let i = rng.below(N);
|
|
match rng.below(4) {
|
|
0 | 1 => {
|
|
let parent = match rng.below(3) {
|
|
0 => None,
|
|
_ => Some(rng.below(N)),
|
|
};
|
|
let ok = !m.live[i] && parent.is_none_or(|p| p != i && m.live[p]);
|
|
assert_eq!(t.attach(i, parent), ok, "attach {i} under {parent:?}");
|
|
if ok {
|
|
m.live[i] = true;
|
|
m.parents[i] = parent.map(|p| p as u16);
|
|
}
|
|
}
|
|
2 => {
|
|
t.detach(i);
|
|
if m.live[i] {
|
|
m.detach(i);
|
|
}
|
|
}
|
|
_ => {
|
|
t.remove_descendants(i);
|
|
if m.live[i] {
|
|
let below = m.below(i);
|
|
for (j, b) in below.iter().enumerate() {
|
|
if *b {
|
|
m.live[j] = false;
|
|
m.parents[j] = None;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
check(&t, &m);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn detaching_a_middle_node_hands_its_children_up() {
|
|
let mut t = CapTree::<4>::new();
|
|
assert!(t.attach(0, None));
|
|
assert!(t.attach(1, Some(0)));
|
|
assert!(t.attach(2, Some(1)));
|
|
assert!(t.attach(3, Some(1)));
|
|
t.detach(1);
|
|
assert_eq!(t.parent(2), Some(0));
|
|
assert_eq!(t.parent(3), Some(0));
|
|
let mut out = [0u16; 4];
|
|
assert_eq!(t.descendants(0, &mut out), 2);
|
|
}
|