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; 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, 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::::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); }