diff --git a/Cargo.toml b/Cargo.toml index 1fe391b..d8f01d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,3 @@ range-ext = "0.3.0" [dev-dependencies] proptest = "1.2.0" rayon = "1.0.0" -rstest = "0.22.0" diff --git a/src/lib.rs b/src/lib.rs index 97e351d..987ad12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ use std::{ use range_ext::intersect::{Intersect, IntersectionExt}; /// Operations to apply to a vector -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum Operation { /// No operation Nop, @@ -116,13 +116,8 @@ impl Operation { vec.splice(pos..(pos + n), None); } Operation::Mov { pos, n, to } => { - // If items are moved within the source range, the operation has no effect - if to > pos && to < pos + n { - return; - } let buf = (0..n).map(|_| vec.remove(pos)).collect::>(); - let n_to = if to > pos { to - n } else { to }; - splice_or_append(vec, n_to, buf); + splice_or_append(vec, to, buf); } Operation::Seq { ops } => ops.into_iter().for_each(|op| op.apply(vec)), } @@ -208,266 +203,6 @@ impl Operation { println!(); v2 } - - /// Print the operation as it is applied on the given vector - pub fn print_on_string(&self, vec: &[T]) -> (Vec, String) - where - T: Display + Clone, - { - if let Operation::Seq { ops } = self { - let mut v = vec.to_vec(); - for op in ops { - v = op.print_on(&v) - } - return v; - } - if matches!(self, Operation::Nop) { - print!(" NOP:"); - for itm in vec { - print!(" {itm} "); - } - println!(); - return vec.to_vec(); - } - - let r = self.range(); - let ins = matches!(self, Operation::Ins { .. }); - - print!("FROM:"); - for (i, itm) in vec.iter().enumerate() { - if i == r.start { - if ins { - print!("|"); - } else { - print!("("); - } - } else { - print!(" "); - } - print!("{itm}"); - if i == r.end.saturating_sub(1) && !ins { - print!(")"); - } else { - print!(" "); - } - } - println!(); - - let r2 = self.target_range(); - let del = matches!(self, Operation::Del { .. }); - let mut v2 = vec.to_vec(); - self.clone().apply(&mut v2); - print!(" TO:"); - for (i, itm) in v2.iter().enumerate() { - if i == r2.start { - if del { - print!("|"); - } else { - print!("("); - } - } else { - print!(" "); - } - print!("{itm}"); - if i == r2.end.saturating_sub(1) && !del { - print!(")"); - } else { - print!(" "); - } - } - println!(); - v2 - } - - fn sanitize(&mut self) { - if self.is_empty() { - *self = Operation::Nop; - return; - } - if let Operation::Mov { pos, n, to } = self { - // Invalid move operation - if *to >= *pos && *to <= *pos + *n { - *self = Operation::Nop; - return; - } - } - } - - /// During mov/del transformations with multiple items, mov operations are split - /// into multiple 1-item long operations. - /// - /// After transformation, these can be merged together if the positions of subsequent - /// operations line up. - /// - /// The function also collapses nested sequences and removes null operations. - fn consolidate_seq(&mut self) { - if let Operation::Seq { ops } = self { - struct MovTmp { - pos: usize, - to: usize, - n: usize, - dir: Option, - } - - struct DelTmp { - pos: usize, - n: usize, - dir: Option, - } - - let mut mov_tmp: Option = None; - let mut del_tmp: Option = None; - let mut buf = Vec::new(); - - fn do_push( - buf: &mut Vec>, - op: Option>, - mov_tmp: &mut Option, - del_tmp: &mut Option, - ) { - if let Some(dt) = del_tmp { - buf.push(Operation::Del { - pos: dt.pos, - n: dt.n, - }); - *del_tmp = None; - } - - if let Some(mt) = mov_tmp { - buf.push(Operation::Mov { - pos: if mt.dir.unwrap_or_default() { - mt.pos + 1 - mt.n - } else { - mt.pos - }, - n: mt.n, - to: if mt.dir.unwrap_or_default() { - mt.to + 1 - mt.n - } else { - mt.to - }, - }); - *mov_tmp = None; - } - - if let Some(op) = op { - buf.push(op); - } - } - - fn proc_op( - buf: &mut Vec>, - op: Operation, - mov_tmp: &mut Option, - del_tmp: &mut Option, - ) { - match op { - Operation::Ins { .. } => do_push(buf, Some(op), mov_tmp, del_tmp), - Operation::Del { pos, n } => { - if let Some(dt) = del_tmp { - if dt.dir.unwrap_or(true) && pos == dt.pos { - // delete from left to right (n times same index) - dt.dir = Some(true); - dt.n += n; - } else if !dt.dir.unwrap_or_default() && pos + n == dt.pos { - // delete from right to left (i-n) - dt.dir = Some(false); - dt.pos = pos; - dt.n += n; - } else { - do_push(buf, None, mov_tmp, del_tmp); - *del_tmp = Some(DelTmp { pos, n, dir: None }); - } - } else { - *del_tmp = Some(DelTmp { pos, n, dir: None }); - } - } - Operation::Mov { pos, n, to } => { - if n == 1 { - if let Some(mt) = mov_tmp { - if mt.dir.unwrap_or(true) - && mt.pos.checked_sub(mt.n).is_some_and(|p| pos == p) - && mt.to.checked_sub(mt.n).is_some_and(|t| to == t) - { - // move right (to > pos) - mt.dir = Some(true); - mt.n += 1; - } else if !mt.dir.unwrap_or(false) - && pos == mt.pos + mt.n - && to == mt.to + mt.n - { - // move left (to <= pos) - mt.dir = Some(false); - mt.n += 1; - } else { - do_push(buf, None, mov_tmp, del_tmp); - *mov_tmp = Some(MovTmp { - pos, - to, - n: 1, - dir: None, - }); - } - } else { - *mov_tmp = Some(MovTmp { - pos, - to, - n: 1, - dir: None, - }); - } - } else { - do_push(buf, Some(op), mov_tmp, del_tmp); - } - } - Operation::Seq { ops } => { - ops.into_iter() - .for_each(|op| proc_op(buf, op, mov_tmp, del_tmp)); - } - Operation::Nop => {} - } - } - - ops.reverse(); - while let Some(op) = ops.pop() { - proc_op(&mut buf, op, &mut mov_tmp, &mut del_tmp); - } - do_push(&mut buf, None, &mut mov_tmp, &mut del_tmp); - - *self = if buf.is_empty() { - Operation::Nop - } else if buf.len() == 1 { - buf.pop().unwrap() - } else { - Operation::Seq { ops: buf } - }; - } - } -} - -impl Debug for Operation { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Nop => write!(f, "Nop"), - Self::Ins { pos, val } => f - .debug_struct("Ins") - .field("pos", pos) - .field("val", &val.len()) - .finish(), - Self::Del { pos, n } => f - .debug_struct("Del") - .field("pos", pos) - .field("n", n) - .finish(), - Self::Mov { pos, n, to } => f - .debug_struct("Mov") - .field("pos", pos) - .field("n", n) - .field("to", to) - .finish(), - Self::Seq { ops } => f.debug_struct("Seq").field("ops", ops).finish(), - } - } } /// Transform the given pair of operations in-place @@ -482,14 +217,11 @@ impl Debug for Operation { /// ``` pub fn transform(a: &mut Operation, b: &mut Operation) { transform_internal(a, b); - // a.consolidate_seq(); - // b.consolidate_seq(); + consolidate_seq(a); + consolidate_seq(b); } fn transform_internal(a: &mut Operation, b: &mut Operation) { - a.sanitize(); - b.sanitize(); - match a { Operation::Nop => {} Operation::Ins { pos: p1, val: v1 } => match b { @@ -609,136 +341,101 @@ fn transform_mov(a: &mut Operation, b: &mut Operation, first: bo to: m_to, } = a { - /* - if *m_n != 1 && matches!(b, Operation::Mov { .. }) { + if *m_n != 1 && matches!(b, Operation::Del { .. } | Operation::Mov { .. }) { let new_a = mov2seq(*m_pos, *m_n, *m_to); *a = new_a; return transform_internal(a, b); } - */ - - let m_to_right = m_to > m_pos; - let m_to_start = if m_to_right { *m_to - *m_n } else { *m_to }; - let rtarget = m_to_start..(m_to_start + *m_n); match b { Operation::Ins { pos: i_pos, val } => { - // Is the MOV source split by the insert? + // Is the moved range split by the insert? if *i_pos > ra.start && *i_pos < ra.end { - let m_delta = m_to_start as i64 - *m_pos as i64; + let m_delta = *m_to as i64 - *m_pos as i64; *i_pos = (*i_pos as i64 + m_delta) as usize; *m_n += val.len(); - if m_to_right { - *m_to += val.len(); - } - } else { - let mut del = Operation::Del::<()> { - pos: *m_pos, - n: *m_n, - }; - let mut ins = Operation::Ins::<()> { - pos: m_to_start, - val: vec![(); *m_n], - }; - - if first { - transform_internal(&mut del, b); - transform_internal(&mut ins, b); - } else { - transform_internal(b, &mut del); - transform_internal(b, &mut ins); - } - - *m_pos = del.pos(); - *m_to = ins.pos(); - if m_to_right { - *m_to += *m_n; - } - if m_pos == m_to { - *a = Operation::Nop; - } + return; } } - Operation::Del { pos: d_pos, n: d_n } => { - let rb = *d_pos..(*d_pos + *d_n); - let (iba, ibt) = (rb.intersect_ext(&ra), rb.intersect_ext(&rtarget)); - - // delete within src - delete within dst - match (&iba, &ibt) { - // Part of the source is deleted - (IntersectionExt::LessOverlap, _) => { - // MOV right end of DEL - let d_pos_split = *m_pos; - let rest_len = d_pos_split - *d_pos; - - if m_to_right { - let del_ops = vec![ - // Delete moved item - Operation::Del { - pos: m_to_start, - n: *d_n - rest_len, - }, - // Delete rest - Operation::Del { - pos: *d_pos, - n: rest_len, - }, - ]; - *m_pos = *d_pos; - *m_n = ra.end - rb.end; - *m_to -= *d_n; - *b = Operation::Seq { ops: del_ops }; - } else { - if matches!(&ibt, IntersectionExt::Over | IntersectionExt::LessOverlap) { - unimplemented!("tmp") - } - - let del_ops = vec![ - // Delete rest - Operation::Del { - pos: *d_pos + *m_n, - n: rest_len, - }, - // Delete moved item - Operation::Del { - pos: m_to_start, - n: *d_n - rest_len, - }, - ]; - *m_pos = *d_pos; - *m_n = ra.end - rb.end; - *b = Operation::Seq { ops: del_ops }; + Operation::Del { pos: d_pos, n } => { + let rb = *d_pos..(*d_pos + *n); + // Delete move source + if ra == rb { + // Delete all moved items in A' + *d_pos = *m_to; + *a = Operation::Nop; + return; + } + // within src - within dst + match (rb.contains(m_pos), rb.contains(m_to)) { + (true, false) => { + let p_rest = if m_to <= d_pos { *d_pos + 1 } else { *d_pos }; + let mut ops = vec![ + // Delete moved item + Operation::Del { pos: *m_to, n: 1 }, + // Delete rest + Operation::Del { + pos: p_rest, + n: *n - 1, + }, + ]; + if *m_to < p_rest { + ops.swap(0, 1); } - if a.is_empty() { + *a = Operation::Nop; + *b = Operation::Seq { ops }; + return; + } + (false, true) => { + let mut p_start = *d_pos; + let to_r = m_to > m_pos; + let del_before_src = d_pos < m_pos; + + if !del_before_src { + p_start -= 1; + } + + // Number of items to delete before moved item + let n1 = *m_to - *d_pos + usize::from(to_r); + + *m_to -= n1; + if del_before_src { + *m_pos -= *n; + } + if m_pos == m_to { *a = Operation::Nop; } + + if n1 == *n { + *d_pos = p_start; + } else if n1 == 0 { + *d_pos = p_start + 1; + } else { + *b = Operation::Seq { + ops: vec![ + // Delete after moved item + Operation::Del { + pos: p_start + n1 + 1, + n: *n - n1, + }, + // Delete before moved item + Operation::Del { + pos: p_start, + n: n1, + }, + ], + }; + } + return; } - (IntersectionExt::GreaterOverlap, _) => { - // MOV left end of DEL - let d_pos_split = *m_pos + *m_n; - unimplemented!("m_pos < d_pos"); - } - // DEL middle of the MOV op - (IntersectionExt::Within, _) => { - unimplemented!("DEL middle of MOV op"); - } - // DEL is split by the MOV op - (IntersectionExt::Over, _) => { - unimplemented!("DEL is split by the MOV op"); - } - // Entire source is deleted - (IntersectionExt::Same, _) => { - // Delete all moved items in A' - *d_pos = m_to_start; + (true, true) => { + // Within src and dst: delete whole range *a = Operation::Nop; return; } - // Entire destination is deleted - // (_, Intersection::Full) => {} - (IntersectionExt::Empty, _) | (_, IntersectionExt::Empty) => {} - _ => unimplemented!("mov-del constellation {iba:?};{ibt:?}"), + (false, false) => {} } } Operation::Mov { @@ -746,31 +443,234 @@ fn transform_mov(a: &mut Operation, b: &mut Operation, first: bo n: b_n, to: b_to, } => { - unimplemented!("mov-mov"); + if *b_n != 1 { + let new_b = mov2seq(*b_pos, *b_n, *b_to); + *b = new_b; + return transform_internal(a, b); + } + + if m_pos == b_pos { + if first { + if b_to == m_to { + *b = Operation::Nop; + } else { + *b_pos = *m_to; + } + *a = Operation::Nop; + } else { + if m_to == b_to { + *a = Operation::Nop; + } else { + *m_pos = *b_to; + } + *b = Operation::Nop; + } + return; + } } - Operation::Seq { ops } => transform_seq(ops, a, false), - Operation::Nop => {} + Operation::Seq { ops } => return transform_seq(ops, a, false), + Operation::Nop => return, + } + + let mut del = Operation::Del::<()> { + pos: *m_pos, + n: *m_n, + }; + let mut ins = Operation::Ins::<()> { + pos: *m_to, + val: vec![(); *m_n], + }; + + if first { + transform_internal(&mut del, b); + transform_internal(&mut ins, b); + } else { + transform_internal(b, &mut del); + transform_internal(b, &mut ins); + } + + *m_pos = del.pos(); + *m_to = ins.pos(); + if m_pos == m_to { + *a = Operation::Nop; } } } fn mov2seq(pos: usize, n: usize, to: usize) -> Operation { Operation::Seq { - ops: if to < pos { - (0..n) + ops: if to > pos { + (pos..pos + n) .rev() - .map(|_| Operation::Mov { - pos: pos + n - 1, + .map(|i| Operation::Mov { + pos: i, n: 1, - to, + to: i + (to - pos), }) .collect() } else { - (0..n).map(|_| Operation::Mov { pos, n: 1, to }).collect() + (pos..pos + n) + .map(|i| Operation::Mov { + pos: i, + n: 1, + to: i - (pos - to), + }) + .collect() }, } } +/// During mov/del transformations with multiple items, mov operations are split +/// into multiple 1-item long operations. +/// +/// After transformation, these can be merged together if the positions of subsequent +/// operations line up. +/// +/// The function also collapses nested sequences and removes null operations. +fn consolidate_seq(op: &mut Operation) { + if let Operation::Seq { ops } = op { + struct MovTmp { + pos: usize, + to: usize, + n: usize, + dir: Option, + } + + struct DelTmp { + pos: usize, + n: usize, + dir: Option, + } + + let mut mov_tmp: Option = None; + let mut del_tmp: Option = None; + let mut buf = Vec::new(); + + fn do_push( + buf: &mut Vec>, + op: Option>, + mov_tmp: &mut Option, + del_tmp: &mut Option, + ) { + if let Some(dt) = del_tmp { + buf.push(Operation::Del { + pos: dt.pos, + n: dt.n, + }); + *del_tmp = None; + } + + if let Some(mt) = mov_tmp { + buf.push(Operation::Mov { + pos: if mt.dir.unwrap_or_default() { + mt.pos + 1 - mt.n + } else { + mt.pos + }, + n: mt.n, + to: if mt.dir.unwrap_or_default() { + mt.to + 1 - mt.n + } else { + mt.to + }, + }); + *mov_tmp = None; + } + + if let Some(op) = op { + buf.push(op); + } + } + + fn proc_op( + buf: &mut Vec>, + op: Operation, + mov_tmp: &mut Option, + del_tmp: &mut Option, + ) { + match op { + Operation::Ins { .. } => do_push(buf, Some(op), mov_tmp, del_tmp), + Operation::Del { pos, n } => { + if let Some(dt) = del_tmp { + if dt.dir.unwrap_or(true) && pos == dt.pos { + // delete from left to right (n times same index) + dt.dir = Some(true); + dt.n += n; + } else if !dt.dir.unwrap_or_default() && pos + n == dt.pos { + // delete from right to left (i-n) + dt.dir = Some(false); + dt.pos = pos; + dt.n += n; + } else { + do_push(buf, None, mov_tmp, del_tmp); + *del_tmp = Some(DelTmp { pos, n, dir: None }); + } + } else { + *del_tmp = Some(DelTmp { pos, n, dir: None }); + } + } + Operation::Mov { pos, n, to } => { + if n == 1 { + if let Some(mt) = mov_tmp { + if mt.dir.unwrap_or(true) + && mt.pos.checked_sub(mt.n).is_some_and(|p| pos == p) + && mt.to.checked_sub(mt.n).is_some_and(|t| to == t) + { + // move right (to > pos) + mt.dir = Some(true); + mt.n += 1; + } else if !mt.dir.unwrap_or(false) + && pos == mt.pos + mt.n + && to == mt.to + mt.n + { + // move left (to <= pos) + mt.dir = Some(false); + mt.n += 1; + } else { + do_push(buf, None, mov_tmp, del_tmp); + *mov_tmp = Some(MovTmp { + pos, + to, + n: 1, + dir: None, + }); + } + } else { + *mov_tmp = Some(MovTmp { + pos, + to, + n: 1, + dir: None, + }); + } + } else { + do_push(buf, Some(op), mov_tmp, del_tmp); + } + } + Operation::Seq { ops } => { + ops.into_iter() + .for_each(|op| proc_op(buf, op, mov_tmp, del_tmp)); + } + Operation::Nop => {} + } + } + + ops.reverse(); + while let Some(op) = ops.pop() { + proc_op(&mut buf, op, &mut mov_tmp, &mut del_tmp); + } + do_push(&mut buf, None, &mut mov_tmp, &mut del_tmp); + + *op = if buf.is_empty() { + Operation::Nop + } else if buf.len() == 1 { + buf.pop().unwrap() + } else { + Operation::Seq { ops: buf } + }; + } +} + fn splice_or_append(v1: &mut Vec, pos: usize, mut v2: Vec) { if pos < v1.len() { v1.splice(pos..pos, v2); @@ -778,23 +678,3 @@ fn splice_or_append(v1: &mut Vec, pos: usize, mut v2: Vec) { v1.append(&mut v2); } } - -#[cfg(test)] -mod tests { - use crate::mov2seq; - - #[test] - fn t_mov2seq() { - let input = [0, 1, 2, 3, 4, 5, 6]; - let a = mov2seq::(1, 3, 6); - let b = mov2seq::(3, 3, 1); - - let mut ia = input.to_vec(); - a.apply(&mut ia); - assert_eq!(ia, &[0, 4, 5, 1, 2, 3, 6]); - - let mut ib = input.to_vec(); - b.apply(&mut ib); - assert_eq!(ib, &[0, 3, 4, 5, 1, 2, 6]); - } -} diff --git a/tests/proptest.proptest-regressions b/tests/proptest.proptest-regressions index ee190bf..85fd27e 100644 --- a/tests/proptest.proptest-regressions +++ b/tests/proptest.proptest-regressions @@ -10,7 +10,3 @@ cc d4edfb3e7e78b85fe2a883940ac794afd21a3b2195aa932eb52b28cdccc2fdca # shrinks to cc 892dbd5d37c6440c9edb3a9d3384c90dcb0a8f267204fdaf818ae9003313f418 # shrinks to a_pos = 472, a_to = 0, b_pos = 0, b_to = 0 cc 62dd5b6206b18bf74368878df5d2e23ae39ca636e8ba3b64e8108282fab1a016 # shrinks to a_pos = 0, a_to = 99, b_pos = 67, b_len = 33 cc 14266631a1edc4c03fa98541c29f6bcb23847ad082382c4d109bbf539520c3e0 # shrinks to a_pos = 61, a_to = 11, b_pos = 11, b_len = 50 -cc 6dc10c336fa7355bd28d7711fdbdd8df6bbc535eee8d8c638114136d9d6bfe78 # shrinks to a_len = 28, a_pos = 8, a_to = 36, b_pos = 9, b_len = 1 -cc 77f1e77a151931af800f28ab89798968068928ea15207dead56b2b84b1e7a6db # shrinks to a_len = 18, a_pos = 0, a_to = 58, b_pos = 59, b_len = 1 -cc 848a2065da6479b78cfde677f86b967679752833b31caab9baa2abb3b5fae5c3 # shrinks to a_pos = 26, a_len = 16, a_to = 6, b_pos = 0, b_len = 27 -cc 7264170514471bbf16d27edd8153c228e9e62bc11afbc156712f855bd51a80d9 # shrinks to a_pos = 14, a_len = 37, a_to = 13, b_pos = 13, b_len = 2 diff --git a/tests/proptest.rs b/tests/proptest.rs index 9e0e993..248f0ed 100644 --- a/tests/proptest.rs +++ b/tests/proptest.rs @@ -4,7 +4,7 @@ use proptest::prelude::*; use rayon::prelude::*; use otvec::Operation; -use util::{test_transform_cond, test_transform_cond_catch}; +use util::test_transform_cond; const ALL_SIZE: usize = 20; const VEC_SIZE: usize = 100; @@ -94,8 +94,8 @@ fn t_mov_del(size: usize, a_pos: usize, a_len: usize, a_to: usize, b_pos: usize, pos: b_pos, n: b_len, }; - test_transform_cond_catch(&a, &b, &input); - test_transform_cond_catch(&b, &a, &input); + test_transform_cond(&a, &b, &input); + test_transform_cond(&b, &a, &input); } fn t_mov_mov( @@ -197,7 +197,6 @@ fn all_mov_del() { }); } -/* #[test] fn all_mov_mov() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { @@ -220,7 +219,6 @@ fn all_mov_mov() { }); }); } -*/ proptest! { #[test] @@ -263,7 +261,6 @@ proptest! { t_mov_del(VEC_SIZE, a_pos, a_len, a_to, b_pos, b_len) } - /* #[test] fn transform_mov_mov(a_pos in 0usize..VEC_SIZE, a_len in 0usize..VEC_SIZE, a_to in 0usize..VEC_SIZE, b_pos in 0usize..VEC_SIZE, b_len in 1usize..VEC_SIZE, b_to in 0usize..VEC_SIZE) { // Limit inputs @@ -274,5 +271,4 @@ proptest! { t_mov_mov(VEC_SIZE, a_pos, a_len, a_to, b_pos, b_len, b_to) } - */ } diff --git a/tests/tests.rs b/tests/tests.rs index dd75af7..4185c8c 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -3,19 +3,6 @@ mod util; use otvec::Operation; use util::{test_transform, test_transform_sym}; -use rstest::rstest; - -#[rstest] -#[case(0, 1, 0, &[1, 2, 3, 4, 5])] -#[case(0, 1, 1, &[1, 2, 3, 4, 5])] -#[case(0, 1, 2, &[2, 1, 3, 4, 5])] -fn apply_mov(#[case] pos: usize, #[case] n: usize, #[case] to: usize, #[case] expect: &[i32]) { - let mut input = vec![1, 2, 3, 4, 5]; - let op = Operation::Mov { pos, n, to }; - op.apply(&mut input); - assert_eq!(input, expect); -} - #[test] fn transform_ins_ins() { let a = Operation::Ins { diff --git a/tests/tests_mov.rs b/tests/tests_mov.rs deleted file mode 100644 index 7824bce..0000000 --- a/tests/tests_mov.rs +++ /dev/null @@ -1,39 +0,0 @@ -mod util; - -use otvec::Operation; -use util::test_transform_sym; - -use rstest::rstest; - -// MOV: [0, 1, 2, 3, 4, 5, 6, 7, 8] => [0, 1, 2, 3, 4, 5, 6, 7, 8] -// DEL: [0, 1, 2, 3, 4, 5, 6, 7, 8] => [0, 1, 2, 3, 4, 5, 6, 7, 8] - -#[rstest] -// MOV-DEL; Intersection::Overlap, Intersection::Empty; right end; to right -// MOV: [0, (1, 2, 3), 4, 5, 6, 7, 8] => [0, 4, 5, (1, 2, 3), 6, 7, 8] -// DEL: [(0, 1), 2, 3, 4, 5, 6, 7, 8] => [2, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov {pos: 1, n: 3, to: 6}, Operation::Del {pos: 0, n: 2}, &[4, 5, 2, 3, 6, 7, 8])] -// MOV-DEL; Intersection::Overlap, Intersection::Empty; right end; to left -// MOV: [0, 1, 2, (3, 4, 5), 6, 7, 8] => [0, (3, 4, 5), 1, 2, 6, 7, 8] -// DEL: [0, 1, (2, 3), 4, 5, 6, 7, 8] => [0, 1, 4, 5, 6, 7, 8] -#[case(Operation::Mov {pos: 3, n: 3, to: 1}, Operation::Del {pos: 2, n: 2}, &[0, 4, 5, 1, 6, 7, 8])] - -// current debugging - -// MOV-DEL; Intersection::Overlap, Intersection::Over; -// MOV: [0, 1, 2, 3, 4, (5, 6, 7), 8] => [0, 1, 5, 6, 7, 2, 3, 4, 8] -// DEL: [0, (1, 2, 3, 4, 5), 6, 7, 8] => [0, 6, 7, 8] -#[case(Operation::Mov {pos: 5, n: 3, to: 2}, Operation::Del {pos: 1, n: 5}, &[0, 6, 7, 8])] -// MOV-DEL; Intersection::Overlap, Intersection::Over; -// MOV: [0, 1, (2, 3, 4, 5, 6), 7, 8] => [0, 2, 3, 4, 5, 6, 1, 7, 8] -// DEL: [0, 1, 2, 3, 4, 5, 6, 7, 8] => [3, 4, 5, 6, 7, 8] -#[case(Operation::Mov {pos: 2, n: 5, to: 1}, Operation::Del {pos: 0, n: 3}, &[0, 6, 7, 8])] - -// MOV-DEL; Intersection::Overlap, Intersection::Empty; left end; to left -// MOV: [0, 1, 2, (3, 4, 5), 6, 7, 8] => [0, (3, 4, 5), 1, 2, 6, 7, 8] -// DEL: [0, 1, 2, 3, 4, (5, 6), 7, 8] => [0, 1, 2, 3, 4, 7, 8] -#[case(Operation::Mov {pos: 3, n: 3, to: 1}, Operation::Del {pos: 5, n: 2}, &[0, 6, 7, 1, 2, 3, 8])] -fn transform(#[case] a: Operation, #[case] b: Operation, #[case] expect: &[i32]) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform_sym(&a, &b, &input, expect); -} diff --git a/tests/tests_mult.rs b/tests/tests_mult.rs index 7f7f07f..df601e7 100644 --- a/tests/tests_mult.rs +++ b/tests/tests_mult.rs @@ -24,7 +24,7 @@ fn transform_mov_ins_mult_above() { let a = Operation::Mov { pos: 1, n: 2, - to: 5, + to: 3, }; let b = Operation::Ins { pos: 3, @@ -39,7 +39,7 @@ fn transform_mov_ins_mult_split() { let a = Operation::Mov { pos: 1, n: 2, - to: 5, + to: 3, }; // [1, 2, 3, 4, 5] => [1, 2, (7, 8, 9), 3, 4, 5] @@ -63,7 +63,7 @@ fn transform_mov_ins_mult_split2() { let a = Operation::Mov { pos: 1, n: 2, - to: 6, + to: 4, }; // [1, 2, 3, 4, 5, 6, 0] => [1, 2, (7, 8, 9), 3, 4, 5, 6, 0] @@ -89,7 +89,7 @@ fn transform_mov_ins_mult_split3() { let a = Operation::Mov { pos: 1, n: 3, - to: 6, + to: 3, }; // [1, 2, 3, 4, 5, 6, 0] => [1, 2, (7, 8, 9), 3, 4, 5, 6, 0] @@ -140,7 +140,7 @@ fn transform_mov_ins_mult_same() { let a = Operation::Mov { pos: 0, n: 2, - to: 5, + to: 3, }; let b = Operation::Ins { pos: 0, @@ -155,7 +155,7 @@ fn transform_mov_ins_mult_within() { let a = Operation::Mov { pos: 0, n: 3, - to: 5, + to: 2, }; // [1, 2, 3, 4, 5] => [1, 8, 9, 2, 3, 4, 5] let b = Operation::Ins { @@ -170,7 +170,7 @@ fn transform_mov_ins_mult_over() { let a = Operation::Mov { pos: 1, n: 2, - to: 4, + to: 2, }; let b = Operation::Ins { pos: 1, @@ -179,7 +179,6 @@ fn transform_mov_ins_mult_over() { test_transform_sym(&a, &b, &[1, 2, 3, 4, 5], &[1, 6, 7, 8, 4, 2, 3, 5]); } -/* // MOV - DEL #[test] @@ -435,30 +434,16 @@ fn transform_mov_del_below_overlap_l4() { #[test] fn transform_mov_del_above_overlap_r() { // [0, (1, 2, 3), 4, 5, 6] => [0, 4, 5, (1, 2, 3), 6] - let a = Operation::Mov { pos: 1, n: 3, - to: 6, + to: 3, }; // [(0, 1), 2, 3, 4, 5, 6] => [2, 3, 4, 5, 6] let b = Operation::Del { pos: 0, n: 2 }; test_transform_sym(&a, &b, &[0, 1, 2, 3, 4, 5, 6], &[4, 5, 2, 3, 6]); } -#[test] -fn transform_mov_del_other_dir() { - // [0, 1, 2, (3, 4, 5), 6] => [0, (3, 4, 5), 1, 2, 6] - let a = Operation::Mov { - pos: 3, - n: 3, - to: 1, - }; - // [0, 1, 2, 3, 4, (5, 6)] => [0, 1, 2, 3, 4] - let b = Operation::Del { pos: 5, n: 2 }; - test_transform_sym(&a, &b, &[0, 1, 2, 3, 4, 5, 6], &[4, 5, 2, 3, 6]); -} - #[test] fn transform_mov_del_above_overlap_r2() { // [0, (1, 2, 3, 4), 5, 6] => [0, 5, (1, 2, 3, 4), 6] @@ -510,4 +495,3 @@ fn transform_mov_del_above_overlap_l2() { let b = Operation::Del { pos: 1, n: 2 }; test_transform_sym(&a, &b, &[0, 1, 2, 3, 4, 5, 6], &[0, 3, 4, 5, 6]); } -*/ diff --git a/tests/util/mod.rs b/tests/util/mod.rs index daa3435..7aa2cfb 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -26,32 +26,6 @@ pub fn test_transform( assert_eq!(data, expect, "b, a2"); } -pub fn test_transform_cond_catch( - a: &Operation, - b: &Operation, - input: &[T], -) { - let res = std::panic::catch_unwind(|| { - let (mut a2, mut b2) = (a.clone(), b.clone()); - transform(&mut a2, &mut b2); - (a2, b2) - }); - - if let Ok((a2, b2)) = res { - check_op(&a2, a); - check_op(&b2, b); - - let mut data = input.to_vec(); - a.clone().apply(&mut data); - b2.apply(&mut data); - - let mut data2 = input.to_vec(); - b.clone().apply(&mut data2); - a2.apply(&mut data2); - assert_eq!(data, data2, "ops:\nA: {a:?}\nB: {b:?}"); - } -} - pub fn test_transform_sym( a: &Operation, b: &Operation,