From: Ian Jackson Date: Tue, 2 Mar 2021 19:18:20 +0000 (+0000) Subject: hidden notch: tests of the data structure X-Git-Tag: otter-0.4.0~253 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=494fdd540cc37d8304625c2810ad2fdec02e00f0;p=otter.git hidden notch: tests of the data structure Signed-off-by: Ian Jackson --- diff --git a/src/hidden.rs b/src/hidden.rs index c5d96900..cae26ca5 100644 --- a/src/hidden.rs +++ b/src/hidden.rs @@ -252,7 +252,123 @@ mod vpid { self.table[notch] = NR::Free(old_next); } } + + #[cfg(test)] + fn check(&self) { + let mut count_free = 0; + let mut walk = self.freelist; + while let Some(here) = walk { + count_free += 1; + let next_walk = self.table[here].unwrap_free(); + if let Some(more) = next_walk { + assert!(more > here); + } + walk = next_walk; + } + assert_eq!( + count_free, + self.table.iter() + .filter(|nr| matches!(nr, NR::Free(_))) + .count() + ); + let pieces = self.table.iter() + .filter_map(|nr| if let NR::Piece(p) = nr { Some(p) } else { None }) + .collect::>(); + assert_eq!( + count_free + pieces.len(), + self.table.len(), + ); + } } + + #[test] + fn exhaustive() { + enum Can { + Insert(PieceId), + Remove(PieceId), + } + impl Debug for Can { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> { + let (c, p) = match self { + Can::Insert(p) => ('+', p), + Can::Remove(p) => ('-', p), + }; + let (idx, _vsn) = p.data().get_idx_version(); + write!(f, "{}{}", c, idx) + } + } + + #[derive(Debug)] + struct State { + todo: Vec, + can: Vec, + } + + const NPIECES: usize = 4; + const DEPTH: usize = 7; + + impl State { + fn implement(&self) { + eprintln!("implement {:?}", self); + let mut notches: Notches = default(); + let mut pieces = SecondarySlotMap::new(); + for op in &self.todo { match op { + &Can::Insert(p) => { + let notch = notches.insert(p); + notches.check(); + pieces.insert(p, notch); + }, + &Can::Remove(p) => { + let notch = pieces[p]; + notches.remove(p, notch).unwrap(); + notches.check(); + }, + }} + } + + fn recurse(&mut self) { + if self.todo.len() == DEPTH { self.implement(); return; } + eprintln!(" recurse {:?}", &self); + + for i in 0..self.can.len() { + let op = self.can.swap_remove(i); + + let l = self.can.len(); + match &op { + &Can::Insert(p) => { self.can.push(Can::Remove(p)) }, + &Can::Remove(_) => { }, + } + + self.todo.push(op); + self.recurse(); + let op = self.todo.pop().unwrap(); + + self.can.truncate(l); + + let last = if i < self.can.len() { + mem::replace(&mut self.can[i], op) + } else { + op + }; + self.can.push(last); + } + } + } + + + let mut st = State { + todo: vec![], + can: { + let mut slotmap: DenseSlotMap = default(); + (0..NPIECES) + .map(|_| slotmap.insert(())) + .map(|p| Can::Insert(p)) + .collect() + }, + }; + + st.recurse(); + } } pub use vpid::*;