diff --git a/src/lib.rs b/src/lib.rs index c8cc051..a60538a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ use std::{ - fmt::{Debug, Display}, + fmt::{Debug, Display, Write}, ops::Range, }; @@ -11,34 +11,10 @@ pub enum Operation { /// No operation Nop, /// Insert - /// - /// Insert n items at the given position. - /// - /// **Example:** - /// ```txt - /// Ins { pos: 1, val: [4, 5] } - /// [1,|2, 3] => [1, 4, 5, 2, 3] - /// ``` Ins { pos: usize, val: Vec }, /// Delete - /// - /// Delete n items at the given position. - /// - /// **Example:** - /// ```txt - /// Del { pos: 1, n: 2 } - /// [1, (2, 3), 4, 5] => [1, 4, 5] - /// ``` Del { pos: usize, n: usize }, /// Move - /// - /// Take n items at the given position and move them to another position. - /// - /// **Example:** - /// ```txt - /// Mov { pos: 0, n: 2, to: 4 } - /// [(1, 2), 3, 4,|5] => [3, 4, (1, 2), 5] - /// ``` Mov { pos: usize, n: usize, to: usize }, /// Sequence of operations Seq { ops: Vec> }, @@ -46,14 +22,9 @@ pub enum Operation { impl Operation { /// Get the number of elemets affected by the operation - /// - /// # Panics - /// - /// Panics if the operation is a [`Operation::Seq`] pub fn len(&self) -> usize { match self { - Operation::Nop => 0, - Operation::Seq { .. } => panic!("SEQ has no len"), + Operation::Nop | Operation::Seq { .. } => 0, Operation::Ins { val, .. } => val.len(), Operation::Del { n, .. } => *n, Operation::Mov { n, .. } => *n, @@ -61,13 +32,9 @@ impl Operation { } /// Get the starting position of the operation - /// - /// # Panics - /// - /// Panics if the operation is a [`Operation::Nop`] or [`Operation::Seq`] pub fn pos(&self) -> usize { match self { - Operation::Nop | Operation::Seq { .. } => panic!("NOP/SEQ has no pos"), + Operation::Nop | Operation::Seq { .. } => 0, Operation::Ins { pos, .. } | Operation::Del { pos, .. } | Operation::Mov { pos, .. } => *pos, @@ -75,13 +42,9 @@ impl Operation { } /// Get the range of the operation - /// - /// # Panics - /// - /// Panics if the operation is a [`Operation::Nop`] or [`Operation::Seq`] pub fn range(&self) -> Range { match self { - Operation::Nop | Operation::Seq { .. } => panic!("NOP/SEQ has no range"), + Operation::Nop | Operation::Seq { .. } => 0..0, Operation::Ins { pos, val } => *pos..(*pos + val.len()), Operation::Del { pos, n } => *pos..(*pos + *n), Operation::Mov { pos, n, .. } => *pos..(*pos + *n), @@ -89,13 +52,9 @@ impl Operation { } /// Get the target range of the operation - /// - /// # Panics - /// - /// Panics if the operation is a [`Operation::Nop`] or [`Operation::Seq`] pub fn target_range(&self) -> Range { match self { - Operation::Nop | Operation::Seq { .. } => panic!("NOP/SEQ has no target"), + Operation::Nop | Operation::Seq { .. } => 0..0, Operation::Ins { pos, val } => *pos..(*pos + val.len()), Operation::Del { pos, .. } => *pos..*pos, Operation::Mov { to, n, .. } => *to..(*to + *n), @@ -109,7 +68,7 @@ impl Operation { /// Panics if the operation is a [`Operation::Nop`] or [`Operation::Seq`] fn set_pos(&mut self, n_pos: usize) { match self { - Operation::Nop | Operation::Seq { .. } => panic!("cannot move NOP/SEQ"), + Operation::Nop | Operation::Seq { .. } => panic!("cannot move nop/seq"), Operation::Ins { pos, .. } | Operation::Del { pos, .. } | Operation::Mov { pos, .. } => { @@ -175,23 +134,11 @@ impl Operation { Operation::Nop => true, Operation::Ins { val, .. } => val.is_empty(), Operation::Del { n, .. } => *n == 0, - Operation::Mov { pos, n, to } => { - *n == 0 || pos == to || (*to >= *pos && *to <= *pos + *n) - } + Operation::Mov { pos, n, to } => *n == 0 || pos == to, Operation::Seq { ops } => ops.iter().all(Self::is_empty), } } - fn opname(&self) -> &'static str { - match self { - Operation::Nop => "NOP", - Operation::Ins { .. } => "INS", - Operation::Del { .. } => "DEL", - Operation::Mov { .. } => "MOV", - Operation::Seq { .. } => "SEQ", - } - } - /// Print the operation as it is applied on the given vector pub fn print_on(&self, vec: &[T]) -> Vec where @@ -204,92 +151,300 @@ impl Operation { } return v; } - - print!("// {}: [", self.opname()); - if matches!(self, Operation::Nop) { - for (i, itm) in vec.iter().enumerate() { - if i > 0 { - print!(", "); - } - print!("{itm}"); + print!(" NOP:"); + for itm in vec { + print!(" {itm} "); } - println!("]"); + println!(); return vec.to_vec(); } let r = self.range(); - let r2 = self.target_range(); let ins = matches!(self, Operation::Ins { .. }); - let del = matches!(self, Operation::Del { .. }); - let mov = matches!(self, Operation::Mov { .. }); + print!("FROM:"); for (i, itm) in vec.iter().enumerate() { - if i > 0 { - print!(", "); - } if i == r.start { if ins { print!("|"); } else { print!("("); } - } - if mov && i == r2.start { - print!("|"); + } else { + print!(" "); } print!("{itm}"); if i == r.end.saturating_sub(1) && !ins { print!(")"); + } else { + print!(" "); } } - print!("] => ["); - - let rt = if mov && r2.start > r.start { - (r2.start - r2.len())..r2.start - } else { - r2.clone() - }; + 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 > 0 { - print!(", "); - } - if i == rt.start { + if i == r2.start { if del { print!("|"); } else { print!("("); } + } else { + print!(" "); } print!("{itm}"); - if i == rt.end.saturating_sub(1) && !del { + if i == r2.end.saturating_sub(1) && !del { print!(")"); + } else { + print!(" "); } } - println!("]"); + println!(); v2 } - fn sanitize(&mut self) { + /// 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, + { + let mut res = String::new(); + if let Operation::Seq { ops } = self { - ops.iter_mut().for_each(Operation::sanitize); - for i in (0..ops.len()).rev() { - if matches!(ops[i], Operation::Nop) { - ops.remove(i); - } + let mut v = vec.to_vec(); + for op in ops { + let ores = op.print_on_string(&v); + v = ores.0; + res += &ores.1; } - if ops.is_empty() { - *self = Operation::Nop; - } else if ops.len() == 1 { - *self = ops.pop().unwrap(); - } - return; + return (v, res); } + if matches!(self, Operation::Nop) { + res += " NOP:"; + for itm in vec { + _ = write!(&mut res, " {itm} "); + } + res.push('\n'); + return (vec.to_vec(), res); + } + + let r = self.range(); + let ins = matches!(self, Operation::Ins { .. }); + + res += "FROM:"; + for (i, itm) in vec.iter().enumerate() { + if i == r.start { + if ins { + res.push('|'); + } else { + res.push('('); + } + } else { + res.push(' '); + } + _ = write!(&mut res, "{itm}"); + if i == r.end.saturating_sub(1) && !ins { + res.push(')'); + } else { + res.push(' '); + } + } + res.push('\n'); + + let r2 = self.target_range(); + let del = matches!(self, Operation::Del { .. }); + let mut v2 = vec.to_vec(); + self.clone().apply(&mut v2); + res += " TO:"; + for (i, itm) in v2.iter().enumerate() { + if i == r2.start { + if del { + res.push('|'); + } else { + res.push('('); + } + } else { + res.push(' '); + } + _ = write!(&mut res, "{itm}"); + if i == r2.end.saturating_sub(1) && !del { + res.push(')'); + } else { + res.push(' '); + } + } + res.push('\n'); + (v2, res) + } + + 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 } + }; } } } @@ -331,8 +486,8 @@ impl Debug for Operation { /// ``` pub fn transform(a: &mut Operation, b: &mut Operation) { transform_internal(a, b); - a.sanitize(); - b.sanitize(); + // a.consolidate_seq(); + // b.consolidate_seq(); } fn transform_internal(a: &mut Operation, b: &mut Operation) { @@ -458,6 +613,14 @@ fn transform_mov(a: &mut Operation, b: &mut Operation, first: bo to: m_to, } = a { + /* + if *m_n != 1 && matches!(b, 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); @@ -506,77 +669,12 @@ fn transform_mov(a: &mut Operation, b: &mut Operation, first: bo let (iba, ibt) = (rb.intersect_ext(&ra), rb.intersect_ext(&rtarget)); // delete within src - delete within dst - match &iba { - IntersectionExt::Less => { - // DEL before MOV - if m_to_start <= *d_pos { - // moved left from DEL - *m_pos -= *d_n; - *d_pos += *m_n; - } else if matches!( - ibt, - IntersectionExt::Over | IntersectionExt::LessOverlap - ) { - // moved inside DEL - let split_l = *m_to - *d_pos; - *m_pos -= *d_n; - *m_to -= split_l; - - let del_ops = vec![ - Operation::Del { - pos: rtarget.end, - n: *d_n - split_l, - }, - Operation::Del { - pos: rtarget.start - split_l, - n: split_l, - }, - ]; - *b = Operation::Seq { ops: del_ops }; - } else { - // moved right from DEL - *m_pos -= *d_n; - *m_to -= *d_n; - } - } - IntersectionExt::Greater => { - // DEL after MOV - if matches!(ibt, IntersectionExt::Over | IntersectionExt::GreaterOverlap) { - let split_l = *m_to - *d_pos; - if split_l == *d_n { - *m_to -= *d_n; - *d_pos -= *m_n; - } else { - // moved inside DEL - *m_to -= split_l; - - let del_ops = vec![ - Operation::Del { - pos: rtarget.end, - n: *d_n - split_l, - }, - Operation::Del { - pos: *d_pos - *m_n, - n: split_l, - }, - ]; - *b = Operation::Seq { ops: del_ops }; - } - } else if m_to_start < *d_pos { - if !matches!(ibt, IntersectionExt::Greater) { - *m_to -= *d_n; - *d_pos -= *m_n; - } - } else { - // moved right from DEL - *m_to -= *d_n; - *d_pos -= *m_n; - } - } + match (&iba, &ibt) { // Part of the source is deleted - IntersectionExt::LessOverlap => { + (IntersectionExt::LessOverlap, _) => { // MOV right end of DEL - let rest_len = *m_pos - *d_pos; + let d_pos_split = *m_pos; + let rest_len = d_pos_split - *d_pos; if m_to_right { let del_ops = vec![ @@ -599,28 +697,22 @@ fn transform_mov(a: &mut Operation, b: &mut Operation, first: bo &ibt, IntersectionExt::Over | IntersectionExt::LessOverlap ) { - /* - The DEL range is split by the MOV op in max 3 parts - 1. DEL before inserted items (d_pos..m_to) - 2. Inserted items: start may contain deleted items - DEL m_to..(m_to + l_intersect) - 3. DEL after inserted items (m_to+m_n..) - */ - - let intersection = ra.start.max(rb.start)..ra.end.min(rb.end); - let r_del_mov = *d_pos..(*m_to + intersection.len()); + let del_len = m_to_start + 1 - *d_pos; let del_ops = vec![ + // Delete rest (after MOV target) Operation::Del { pos: rtarget.end, - n: *d_n - r_del_mov.len(), + n: *d_n - del_len, }, + // Delete moved item Operation::Del { - pos: r_del_mov.start, - n: r_del_mov.len(), + pos: *d_pos, + n: del_len, }, ]; - *a = Operation::Nop; + *m_pos = *d_pos; + *m_n = ra.end - rb.end; *b = Operation::Seq { ops: del_ops }; } else { let del_ops = vec![ @@ -639,767 +731,41 @@ fn transform_mov(a: &mut Operation, b: &mut Operation, first: bo *m_n = ra.end - rb.end; *b = Operation::Seq { ops: del_ops }; } + + a.sanitize(); } - IntersectionExt::GreaterOverlap => { + (IntersectionExt::GreaterOverlap, _) => { // MOV left end of DEL - let rest_len = rb.end - ra.end; - let moved_len = *d_n - rest_len; - let intersection = ra.start.max(rb.start)..ra.end.min(rb.end); - - if !m_to_right { - // MOV to left - // todo!("GreaterOverlap => left"); - let del_ops = vec![ - // Delete rest - Operation::Del { - pos: rb.end - (*d_n - intersection.len()), - n: *d_n - intersection.len(), - }, - // Delete moved item - Operation::Del { - pos: rtarget.end - intersection.len(), - n: intersection.len(), - }, - ]; - *m_n -= intersection.len(); - *b = Operation::Seq { ops: del_ops }; - } else if matches!( - &ibt, - IntersectionExt::Over | IntersectionExt::GreaterOverlap - ) { - let n_right = *m_to - ra.end; - - let del_ops = vec![ - Operation::Del { - pos: rtarget.end - intersection.len(), - n: *d_n - n_right, - }, - Operation::Del { - pos: *m_pos, - n: n_right, - }, - ]; - *a = Operation::Nop; - *b = Operation::Seq { ops: del_ops }; - } else { - let del_ops = vec![ - // Delete moved item - Operation::Del { - pos: *m_to - moved_len, - n: moved_len, - }, - // Delete rest - Operation::Del { - pos: *m_pos, - n: rest_len, - }, - ]; - *m_n = *d_pos - *m_pos; - *m_to -= *d_n; - *b = Operation::Seq { ops: del_ops }; - } + let d_pos_split = *m_pos + *m_n; + unimplemented!("m_pos < d_pos"); } // DEL middle of the MOV op - IntersectionExt::Within => { - if m_to_right { - let delta = m_to_start - *m_pos; - *d_pos += delta; - *m_to -= *d_n; - } else { - let delta = *m_pos - m_to_start; - *d_pos -= delta; - } - *m_n -= *d_n; + (IntersectionExt::Within, _) => { + unimplemented!("DEL middle of MOV op"); } // DEL is split by the MOV op - IntersectionExt::Over => { - let intersection = ra.start.max(rb.start)..ra.end.min(rb.end); - if m_to_right { - let del_ops = vec![ - Operation::Del { - pos: rtarget.end - intersection.len(), - n: intersection.len(), - }, - Operation::Del { - pos: *d_pos, - n: *d_n - intersection.len(), - }, - ]; - *b = Operation::Seq { ops: del_ops }; - } else { - let del_ops = vec![ - Operation::Del { - pos: rb.end - (*d_n - intersection.len()), - n: *d_n - intersection.len(), - }, - Operation::Del { - pos: (*m_to).min(*d_pos), - n: intersection.len(), - }, - ]; - *b = Operation::Seq { ops: del_ops }; - } - *a = Operation::Nop; + (IntersectionExt::Over, _) => { + unimplemented!("DEL is split by the MOV op"); } // Entire source is deleted - IntersectionExt::Same => { + (IntersectionExt::Same, _) => { // Delete all moved items in A' *d_pos = m_to_start; *a = Operation::Nop; + return; } - IntersectionExt::Empty => {} + // Entire destination is deleted + // (_, Intersection::Full) => {} + (IntersectionExt::Empty, _) | (_, IntersectionExt::Empty) => {} + _ => unimplemented!("mov-del constellation {iba:?};{ibt:?}"), } } Operation::Mov { - pos: m2_pos, - n: m2_n, - to: m2_to, + pos: b_pos, + n: b_n, + to: b_to, } => { - // todo!("MOV-MOV"); - let m2_to_right = m2_to > m2_pos; - let m2_to_start = if m2_to_right { *m2_to - *m2_n } else { *m2_to }; - let rtarget2 = m2_to_start..(m2_to_start + *m2_n); - let rm2 = *m2_pos..(*m2_pos + *m2_n); - let im2 = ra.intersect_ext(&rm2); - - let a_split_by_b = *m2_to > ra.start && *m2_to < ra.end; - let b_split_by_a = *m_to > rm2.start && *m_to < rm2.end; - - if ra == rm2 { - // Asymmetrical, B has priority - *m2_pos = m_to_start; - *m2_to = m2_to_start; - if m2_to > m2_pos { - *m2_to += *m_n; - } - *a = Operation::Nop; - return; - } - if matches!(im2, IntersectionExt::Within) { - // A within B; B has priority, so A should be undone - let ops = vec![ - undo_mov(*m_pos, *m_n, m_to_start), - Operation::Mov { - pos: *m2_pos, - n: *m2_n, - to: *m2_to, - }, - ]; - *b = Operation::Seq { ops }; - *a = Operation::Nop; - return; - } - if matches!(im2, IntersectionExt::Over) { - // A over B - let m2_inside_offset = *m2_pos - *m_pos; - let a_before = *m_pos..*m2_pos; - let a_after = rm2.end..ra.end; - - if a_split_by_b { - // Split - *m2_pos = rtarget.start + m2_inside_offset; - if m_to_right { - *m2_to += rtarget.start - *m_pos; - } else { - *m2_to -= *m_pos - rtarget.start; - } - } else { - // A=>B2: - let m2_pos_n = rtarget.start + m2_inside_offset; - let m2_n_n = *m_n - (a_before.len() + a_after.len()); - let mut m2_to_n = *m2_to; - - if *m_pos < *m2_to && rtarget.end >= *m2_to { - m2_to_n -= *m_n; - } else if *m_pos >= *m2_to && *m_to < *m2_to { - m2_to_n += *m_n; - } - - // B=>A2: outer ranges a_before and a_after are lined up - // at m_pos if m2_to_right; at m_pos + m2_n if m2_to_left - let ab_together_start = if m2_to_right { - a_before.start - } else { - a_before.start + *m2_n - }; - - let m_pos_n = ab_together_start; - let m_n_n = a_before.len() + a_after.len(); - let mut m_to_n = *m_to; - - // Target can be shifted by m2_n to the left if the B operation - // source < m_to AND targetB.end >= m_to (B is moved right over m_to) - if *m2_pos < *m_to && rtarget2.end >= *m_to { - m_to_n -= *m2_n; - } - // Target shifted by m2_n to the right if the B operation - // source >= m_to AND m2_to < m_to (B is moved left over m_to) - else if *m2_pos >= *m_to && *m2_to < *m_to { - m_to_n += *m2_n; - } - - // If both operations have the same target or split, - // the B operation takes priority, A is inserted after it - if m_to == m2_to { - m2_to_n += *m2_n; - if rtarget.contains(&m2_to_n) { - m2_to_n = rtarget.end; - } - } - - *m_pos = m_pos_n; - *m_n = m_n_n; - *m_to = m_to_n; - *m2_pos = m2_pos_n; - *m2_n = m2_n_n; - *m2_to = m2_to_n; - } - return; - } - - if matches!(im2, IntersectionExt::LessOverlap) { - let intersection = *m2_pos..ra.end; - match (a_split_by_b, b_split_by_a) { - (true, _) => { - // Range A is split by B insertion - // B: to_left - // A=>B2: move intersection of A/B to m_pos - let left_of_m2_to = *m_pos..*m2_to; - let b_delta = *m2_pos - rtarget2.start; - let nleft = *m2_pos - *m_pos; - - let m2_pos_n = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - let m2_n_n = intersection.len(); - let mut m2_to_n = *m_pos; - if !m_to_right { - m2_to_n += *m_n; - } - - // B=>A2: - // 1. move part left of m2_to to m_to - // 2. move part right of m2 target to m_to - let wi = rm2.contains(m_to); // m_to within m2 source - let mut mto = *m_to; - if wi { - mto -= b_delta; - } - let a_ops = vec![ - Operation::Mov { - pos: left_of_m2_to.start, - n: left_of_m2_to.len(), - to: mto, - }, - Operation::Mov { - pos: if wi || !m_to_right { - rtarget2.end - } else { - rtarget2.end - left_of_m2_to.len() - }, - n: nleft - left_of_m2_to.len(), - to: if m_to_right { - mto - } else { - mto + left_of_m2_to.len() - }, - }, - ]; - *a = Operation::Seq { ops: a_ops }; - *m2_pos = m2_pos_n; - *m2_n = m2_n_n; - *m2_to = m2_to_n; - return; - } - (false, true) => { - // Range B is split by A insertion - let mut b_ops = None; - - // A=>B2 move intersection of A/B to m2_to - let mdelta = rtarget.start - *m_pos; - let m2_pos_n = intersection.start + mdelta; - - if m2_to < m_pos { - let r_before = - (*m2_to + intersection.len())..(*m_pos + intersection.len()); - b_ops = Some(vec![ - Operation::Mov { - pos: m2_pos_n, - n: intersection.len(), - to: *m2_to, - }, - Operation::Mov { - pos: r_before.start, - n: r_before.len(), - to: rm2.end, - }, - ]); - } - if m2_to_right && m2_to > m_to { - let delta = *m2_to - rm2.end; // delta of first op (->) - b_ops = Some(vec![ - Operation::Mov { - pos: *m_pos, - n: rm2.end - *m_pos, - to: *m2_to, - }, - Operation::Mov { - pos: project_mov_point( - *m_pos, - *m_n, - *m_to, - intersection.start, - ) + delta, - n: intersection.len(), - to: *m_pos + delta, - }, - ]); - } - - // B=>A2 move part left of intersection of A/B to m_to - if m2_to_right { - let mdelta = rtarget2.start - *m2_pos; - *m_to += mdelta; - } else { - let mdelta = *m2_pos - rtarget2.start; - *m_pos += *m2_n; - *m_to -= mdelta; - } - - *m_n -= intersection.len(); - - if let Some(ops) = b_ops { - *b = Operation::Seq { ops }; - } else { - *m2_n = intersection.len(); - *m2_pos = m2_pos_n; - } - return; - } - (false, false) => { - // LessOverlap - let intersection = ra.start.max(rm2.start)..ra.end.min(rm2.end); - let m_n_n = *m_n - intersection.len(); - let m_pos_n = project_mov_point(*m2_pos, *m2_n, *m2_to, *m_pos); - - let mut m_to_n = - project_mov_point(*m2_pos, *m2_n, *m2_to, m_to.saturating_sub(1)); - if *m_to > 0 { - m_to_n += 1; - } - - // A=>B2: - if m_to == m2_to { - *m2_n -= intersection.len(); - if m_to_right { - *m2_pos = m_pos_n; - *m2_to = *m_to; - } else { - *m2_pos = ra.end; - *m2_to = rtarget.end; - m_to_n = *m_to; - } - } else { - // undo A, apply B - let b_ops = vec![ - undo_mov(*m_pos, *m_n, m_to_start), - Operation::Mov { - pos: *m2_pos, - n: *m2_n, - to: *m2_to, - }, - Operation::Mov { - pos: m_pos_n, - n: m_n_n, - to: m_to_n, - }, - ]; - *b = Operation::Seq { ops: b_ops }; - } - - // B=>A2 mov part left from m2 to m_to - *m_pos = m_pos_n; - *m_n = m_n_n; - *m_to = m_to_n; - return; - } - } - } - - if matches!(im2, IntersectionExt::GreaterOverlap) { - let intersection = *m_pos..rm2.end; - match (a_split_by_b, b_split_by_a) { - (true, _) => { - // Range A is split by B insertion - // B: to_right - - // A=>B2: move intersection of A/B to m_pos - let right_of_m2_to = *m2_to..ra.end; - let b_delta = rtarget2.start - *m2_pos; - let nright = ra.end - rm2.end; // right from overlap - - let m2_pos_n = - project_mov_point(*m_pos, *m_n, *m_to, intersection.start); - let m2_n_n = intersection.len(); - let mut m2_to_n = *m_pos; - if !m_to_right { - m2_to_n += *m_n; - } - - // B=>A2: - // 1. move part right of m2_to to m_to - // 2. move part left of m2 target to m_to - let wi = rm2.contains(m_to); // m_to within m2 source - let mut mto = *m_to; - if wi { - mto += b_delta; - } - let prm2_end = project_mov_point(*m2_pos, *m2_n, *m2_to, rm2.end); - let a_ops = vec![ - Operation::Mov { - pos: right_of_m2_to.start, - n: right_of_m2_to.len(), - to: mto, - }, - Operation::Mov { - pos: if m_to_right || wi { - prm2_end - } else { - prm2_end + right_of_m2_to.len() - }, - n: nright - right_of_m2_to.len(), - to: if m_to_right { - mto - right_of_m2_to.len() - } else { - mto - }, - }, - ]; - *a = Operation::Seq { ops: a_ops }; - *m2_pos = m2_pos_n; - *m2_n = m2_n_n; - *m2_to = m2_to_n; - return; - } - (false, true) => { - // Range B is split by A insertion - - // A=>B2 move intersection of A/B to m2_to - let m2_pos_n = rtarget.start; - let mut b_ops = None; - - // B=>A2 - let r_mov = rm2.end..ra.end; - *m_pos = project_mov_point(*m2_pos, *m2_n, *m2_to, r_mov.start); - *m_n = r_mov.len(); - if m2_to_right { - let m2delta = rtarget2.start - *m2_pos; - *m_to += m2delta; - - if *m2_to > ra.end { - b_ops = Some(vec![ - Operation::Mov { - pos: m2_pos_n, - n: intersection.len(), - to: *m2_to, - }, - Operation::Mov { - pos: *m2_pos, - n: ra.end - *m2_pos - intersection.len(), - to: *m2_to - intersection.len(), - }, - ]); - } - } else { - let m2delta = *m2_pos - rtarget2.start; - *m_to -= m2delta; - let d1 = *m2_pos - *m2_to; - - b_ops = Some(vec![ - Operation::Mov { - pos: *m2_pos, - n: ra.end - *m2_pos, - to: *m2_to, - }, - Operation::Mov { - pos: m2_pos_n - d1, - n: intersection.len(), - to: ra.end - d1, - }, - ]); - } - - if let Some(b_ops) = b_ops { - *b = Operation::Seq { ops: b_ops } - } else { - *m2_pos = m2_pos_n; - *m2_n = intersection.len(); - } - return; - } - (false, false) => { - // GreaterOverlap - let intersection = ra.start.max(rm2.start)..ra.end.min(rm2.end); - let m_n_n = *m_n - intersection.len(); - let m_pos_pre = ra.end - m_n_n; - - let m_pos_n = project_mov_point(*m2_pos, *m2_n, *m2_to, m_pos_pre); - let mut m_to_n = project_mov_point(*m2_pos, *m2_n, *m2_to, *m_to); - - // A=>B2: - if m_to == m2_to { - *m2_n -= intersection.len(); - if m_to_right { - *m2_pos = m_pos_n; - *m2_to = rtarget.start; - m_to_n = *m_to; - } else { - *m2_pos = project_mov_point(*m_pos, *m_n, *m_to, rm2.start); - *m2_to = *m_to; - } - } else { - // undo A, apply B - let b_ops = vec![ - undo_mov(*m_pos, *m_n, m_to_start), - Operation::Mov { - pos: *m2_pos, - n: *m2_n, - to: *m2_to, - }, - Operation::Mov { - pos: m_pos_n, - n: m_n_n, - to: m_to_n, - }, - ]; - *b = Operation::Seq { ops: b_ops }; - } - - // B=>A2 mov part left from m2 to m_to - *m_pos = m_pos_n; - *m_n = m_n_n; - *m_to = m_to_n; - - return; - } - } - } - - if matches!(im2, IntersectionExt::Less) { - match (a_split_by_b, b_split_by_a) { - (true, false) => { - if m_to_right { - let mdelta = rtarget.start - *m_pos; - - // A=>B2: mov m2_src to m2_pos - let m2_pos_n = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - - // B=>A2: mov m1_range with inserted m2 items to m_to - *m_n += *m2_n; - if rm2.end > *m_to { - *m_to += *m2_n; - } - - *m2_pos = m2_pos_n; - *m2_to += mdelta; - } else { - let mdelta = *m_pos - rtarget.start; - let m2_pos_n = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - - *m_n += *m2_n; - - *m2_pos = m2_pos_n; - *m2_to -= mdelta; - } - return; - } - (false, true) => { - if m2_to_right { - let m2delta = rtarget2.start - *m2_pos; - let m2_pos_n = project_mov_point(*m2_pos, *m2_n, *m2_to, *m_pos); - - *m2_pos = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - *m2_n += *m_n; - - *m_pos = m2_pos_n; - *m_to += m2delta; - } else { - let m2delta = *m2_pos - rtarget2.start; - let m2_pos_n = project_mov_point(*m2_pos, *m2_n, *m2_to, *m_pos); - - *m2_pos = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - *m2_n += *m_n; - if ra.end <= *m2_to { - *m2_to -= *m_n; - } - - *m_pos = m2_pos_n; - *m_to -= m2delta; - } - return; - } - (true, true) => { - // A=>B2: move m2 items (split in 2 ranges) to m2_to - let mdelta = rtarget.start - *m_pos; - let left_r = *m2_pos..*m_to; - let to = *m2_to + mdelta; - let b_ops = vec![ - Operation::Mov { - pos: rtarget.end - *m_n - left_r.len(), - n: left_r.len(), - to, - }, - Operation::Mov { - pos: rtarget.end, - n: *m2_n - left_r.len(), - to, - }, - ]; - - let between = ra.end..rm2.start; - if between.is_empty() { - *a = Operation::Nop; - } else { - *m_pos = project_mov_point(*m2_pos, *m2_n, *m2_to, between.start); - *m_n = between.len(); - *m_to = ra.start; - } - - *b = Operation::Seq { ops: b_ops }; - return; - } - (false, false) => {} - } - } - - if matches!(im2, IntersectionExt::Greater) { - match (a_split_by_b, b_split_by_a) { - (true, false) => { - if m_to_right { - let mdelta = rtarget.start - *m_pos; - - // A=>B2: mov m2_src to m2_pos - let m2_pos_n = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - - // B=>A2: mov m1_range with inserted m2 items to m_to - let nl = *m2_to - *m_pos; - *m_pos = *m2_to - *m2_n - nl; - *m_n += *m2_n; - - *m2_pos = m2_pos_n; - *m2_to += mdelta; - } else { - let mdelta = *m_pos - rtarget.start; - let m2_pos_n = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - - let nl = *m2_to - *m_pos; - *m_pos = *m2_to - *m2_n - nl; - *m_n += *m2_n; - if *m_to > 0 && rm2.end <= *m_to { - *m_to -= *m2_n; - } - - *m2_pos = m2_pos_n; - *m2_to -= mdelta; - } - return; - } - (false, true) => { - if m2_to_right { - let m2delta = rtarget2.start - *m2_pos; - let m2_pos_n = project_mov_point(*m2_pos, *m2_n, *m2_to, *m_pos); - - *m2_pos = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - *m2_n += *m_n; - if *m2_to < ra.end { - *m2_to += *m_n; - } - - *m_pos = m2_pos_n; - *m_to += m2delta; - } else { - let m2delta = *m2_pos - rtarget2.start; - let m2_pos_n = project_mov_point(*m2_pos, *m2_n, *m2_to, *m_pos); - - *m2_pos = project_mov_point(*m_pos, *m_n, *m_to, *m2_pos); - *m2_n += *m_n; - - *m_pos = m2_pos_n; - *m_to -= m2delta; - } - return; - } - (true, true) => { - // A=>B2: move m2 items (split in 2 ranges) to m2_to - let mdelta = *m_pos - rtarget.start; - let left_r = *m2_pos..*m_to; - let to = *m2_to - mdelta; - let b_ops = vec![ - Operation::Mov { - pos: rtarget.end - *m_n - left_r.len(), - n: left_r.len(), - to, - }, - Operation::Mov { - pos: rtarget.end, - n: *m2_n - left_r.len(), - to, - }, - ]; - - let between = rm2.end..ra.start; - if between.is_empty() { - *a = Operation::Nop; - } else { - *m_pos = project_mov_point(*m2_pos, *m2_n, *m2_to, between.start); - *m_n = between.len(); - *m_to = ra.end; - } - - *b = Operation::Seq { ops: b_ops }; - return; - } - (false, false) => {} - } - } - - let mut ia = Operation::<()>::Ins { - pos: *m_to, - val: vec![(); *m_n], - }; - let mut da = Operation::<()>::Del { - pos: if m_to_right { *m_pos } else { *m_pos + *m_n }, - n: *m_n, - }; - let mut ib = Operation::<()>::Ins { - pos: *m2_to, - val: vec![(); *m2_n], - }; - let mut db = Operation::<()>::Del { - pos: if m2_to_right { - *m2_pos - } else { - *m2_pos + *m2_n - }, - n: *m2_n, - }; - - transform_internal(&mut ia, &mut ib); - transform_internal(&mut da, &mut ib); - transform_internal(&mut ia, &mut db); - transform_internal(&mut da, &mut db); - - *m_pos = if m_to_right { - da.pos() - } else { - da.pos() - *m_n - }; - *m_to = ia.pos(); - - *m2_pos = if m2_to_right { - db.pos() - } else { - db.pos() - *m2_n - }; - *m2_to = ib.pos(); + unimplemented!("mov-mov"); } Operation::Seq { ops } => transform_seq(ops, a, false), Operation::Nop => {} @@ -1407,6 +773,23 @@ fn transform_mov(a: &mut Operation, b: &mut Operation, first: bo } } +fn mov2seq(pos: usize, n: usize, to: usize) -> Operation { + Operation::Seq { + ops: if to < pos { + (0..n) + .rev() + .map(|_| Operation::Mov { + pos: pos + n - 1, + n: 1, + to, + }) + .collect() + } else { + (0..n).map(|_| Operation::Mov { pos, n: 1, to }).collect() + }, + } +} + fn splice_or_append(v1: &mut Vec, pos: usize, mut v2: Vec) { if pos < v1.len() { v1.splice(pos..pos, v2); @@ -1415,91 +798,22 @@ fn splice_or_append(v1: &mut Vec, pos: usize, mut v2: Vec) { } } -fn undo_mov(pos: usize, n: usize, m_to_start: usize) -> Operation { - let mop1_to = if pos > m_to_start { pos + n } else { pos }; - Operation::Mov { - pos: m_to_start, - n, - to: mop1_to, - } -} - -fn project_mov_point(m_pos: usize, m_n: usize, m_to: usize, point: usize) -> usize { - let m_to_right = m_to > m_pos; - let m_to_start = if m_to_right { m_to - m_n } else { m_to }; - let rmov = m_pos..(m_pos + m_n); - let rtarget = m_to_start..(m_to_start + m_n); - let m_delta = m_to_start as i64 - m_pos as i64; - - if (point < m_pos && point < rtarget.start) || (point >= rmov.end && point >= m_to) { - // unaffected - point - } else if rmov.contains(&point) { - // point is moved - (point as i64 + m_delta) as usize - } else if m_to_right { - point - m_n - } else { - point + m_n - } -} - #[cfg(test)] mod tests { - use super::*; - - fn filter_to(size: usize, pos: usize, to: usize) -> usize { - if pos == to { - if to >= size - 1 { - filter_to(size, pos, 0) - } else { - filter_to(size, pos, to + 1) - } - } else { - to - } - } + use crate::mov2seq; #[test] - fn t_project_mov_point() { - let size = 9; - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + fn t_mov2seq() { + let input = [0, 1, 2, 3, 4, 5, 6]; + let a = mov2seq::(1, 3, 6); + let b = mov2seq::(3, 3, 1); - (0..size).into_iter().for_each(|m_pos| { - (1..(size - m_pos)).into_iter().for_each(|m_n| { - (0..size).into_iter().for_each(|m_to| { - (0..size).into_iter().for_each(|point| { - let m_to = filter_to(size, m_pos, m_to); - let m_n = m_n.min(size - m_pos.max(m_to)); + let mut ia = input.to_vec(); + a.apply(&mut ia); + assert_eq!(ia, &[0, 4, 5, 1, 2, 3, 6]); - let mov = Operation::Mov { - pos: m_pos, - n: m_n, - to: m_to, - }; - if mov.is_empty() { - return; - } - - let res = project_mov_point(m_pos, m_n, m_to, point); - - let mut data = input.to_vec(); - mov.clone().apply(&mut data); - let moved_to = data - .iter() - .enumerate() - .find(|(_, itm)| **itm == point as i32) - .unwrap() - .0; - - if res != moved_to { - mov.print_on(&input); - println!("Point: {point}"); - assert_eq!(res, moved_to); - } - }) - }) - }) - }); + 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.rs b/tests/proptest.rs index 246d805..00af9c0 100644 --- a/tests/proptest.rs +++ b/tests/proptest.rs @@ -7,17 +7,24 @@ use otvec::Operation; use util::{print_cond_catch_ctr, test_transform_cond, test_transform_cond_catch, CondCatchCtr}; const ALL_SIZE: usize = 20; -const MIN_RANGE_LEN: usize = 1; - -const TEST_SIZE: usize = 9; -const TEST_MIN_RANGE_LEN: usize = 1; - const VEC_SIZE: usize = 100; fn testvec(len: usize) -> Vec { (0..len).collect::>() } +fn filter_to(size: usize, pos: usize, to: usize) -> usize { + if pos == to { + if to >= size - 1 { + filter_to(size, pos, 0) + } else { + filter_to(size, pos, to + 1) + } + } else { + to + } +} + fn t_ins_ins(size: usize, a_pos: usize, a_len: usize, b_pos: usize, b_len: usize) { let input = testvec(size); let a = Operation::Ins { @@ -76,7 +83,15 @@ fn t_mov_ins(size: usize, a_pos: usize, a_len: usize, a_to: usize, b_pos: usize, test_transform_cond(&b, &a, &input); } -fn t_mov_del(size: usize, a_pos: usize, a_len: usize, a_to: usize, b_pos: usize, b_len: usize) { +fn t_mov_del( + size: usize, + a_pos: usize, + a_len: usize, + a_to: usize, + b_pos: usize, + b_len: usize, + ctr: Option<&CondCatchCtr>, +) { let input = testvec(size); let a = Operation::Mov { pos: a_pos, @@ -87,31 +102,6 @@ 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(&a, &b, &input); - test_transform_cond(&b, &a, &input); -} - -fn t_mov_mov_catch( - size: usize, - a_pos: usize, - a_len: usize, - a_to: usize, - b_pos: usize, - b_len: usize, - b_to: usize, - ctr: Option<&CondCatchCtr>, -) { - let input = testvec(size); - let a = Operation::Mov { - pos: a_pos, - n: a_len, - to: a_to, - }; - let b = Operation::Mov { - pos: b_pos, - n: b_len, - to: b_to, - }; test_transform_cond_catch(&a, &b, &input, ctr); test_transform_cond_catch(&b, &a, &input, ctr); } @@ -143,247 +133,159 @@ fn t_mov_mov( #[test] fn all_ins_ins() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) - .into_par_iter() - .for_each(|a_len| { - (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) - .into_par_iter() - .for_each(|b_len| { - t_ins_ins(ALL_SIZE, a_pos, a_len, b_pos, b_len); - }); + (1..(ALL_SIZE - a_pos)).into_par_iter().for_each(|a_len| { + (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { + (1..(ALL_SIZE - b_pos)).into_par_iter().for_each(|b_len| { + t_ins_ins(ALL_SIZE, a_pos, a_len, b_pos, b_len); }); }); + }); }); } #[test] fn all_del_del() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) - .into_par_iter() - .for_each(|a_len| { - (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) - .into_par_iter() - .for_each(|b_len| { - t_del_del(ALL_SIZE, a_pos, a_len, b_pos, b_len); - }); + (1..(ALL_SIZE - a_pos)).into_par_iter().for_each(|a_len| { + (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { + (1..(ALL_SIZE - b_pos)).into_par_iter().for_each(|b_len| { + t_del_del(ALL_SIZE, a_pos, a_len, b_pos, b_len); }); }); + }); }); } #[test] fn all_ins_del() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) - .into_par_iter() - .for_each(|a_len| { - (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) - .into_par_iter() - .for_each(|b_len| { - t_ins_del(ALL_SIZE, a_pos, a_len, b_pos, b_len); - }); + (1..(ALL_SIZE - a_pos)).into_par_iter().for_each(|a_len| { + (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { + (1..(ALL_SIZE - b_pos)).into_par_iter().for_each(|b_len| { + t_ins_del(ALL_SIZE, a_pos, a_len, b_pos, b_len); }); }); + }); }); } #[test] fn all_mov_ins() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) - .into_par_iter() - .for_each(|a_len| { - (0..a_pos) - .into_par_iter() - .chain((a_pos + a_len + 1)..=ALL_SIZE) - .for_each(|a_to| { - (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) - .into_par_iter() - .for_each(|b_len| { - t_mov_ins(ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len); - }); - }); + (1..(ALL_SIZE - a_pos)).into_par_iter().for_each(|a_len| { + (0..ALL_SIZE).into_par_iter().for_each(|a_to| { + let a_to = filter_to(ALL_SIZE, a_pos, a_to); + let a_len = a_len.min(ALL_SIZE - a_pos.max(a_to)); + + (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { + (1..(ALL_SIZE - b_pos)).into_par_iter().for_each(|b_len| { + t_mov_ins(ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len); }); + }); }); + }); }); } #[test] fn all_mov_del() { - (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) - .into_par_iter() - .for_each(|a_len| { - (0..a_pos) - .into_par_iter() - .chain((a_pos + a_len + 1)..=ALL_SIZE) - .for_each(|a_to| { - (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) - .into_par_iter() - .for_each(|b_len| { - t_mov_del(ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len); - }); - }); - }); - }); - }); -} - -// For development (non-parallel and panic-catching) -#[test] -fn dev_all_mov_mov() { let ctr = CondCatchCtr::default(); - (0..TEST_SIZE).into_iter().for_each(|a_pos| { - (TEST_MIN_RANGE_LEN..=(TEST_SIZE - a_pos)) - .into_iter() - // .rev() - .for_each(|a_len| { - (0..a_pos) - .into_iter() - .chain((a_pos + a_len + 1)..=TEST_SIZE) - .for_each(|a_to| { - (0..TEST_SIZE).into_iter().for_each(|b_pos| { - (TEST_MIN_RANGE_LEN..=(TEST_SIZE - b_pos)) - .into_iter() - // .rev() - .for_each(|b_len| { - (0..b_pos) - .into_iter() - .chain((b_pos + b_len + 1)..=TEST_SIZE) - .for_each(|b_to| { - t_mov_mov_catch( - TEST_SIZE, - a_pos, - a_len, - a_to, - b_pos, - b_len, - b_to, - Some(&ctr), - ); - }); - }); - }); + + (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { + (1..(ALL_SIZE - a_pos)).into_par_iter().for_each(|a_len| { + (0..ALL_SIZE).into_par_iter().for_each(|a_to| { + let a_to = filter_to(ALL_SIZE, a_pos, a_to); + let a_len = a_len.min(ALL_SIZE - a_pos.max(a_to)); + + (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { + (1..(ALL_SIZE - b_pos)).into_par_iter().for_each(|b_len| { + t_mov_del(ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len, Some(&ctr)); }); + }); }); + }); }); print_cond_catch_ctr(&ctr); } +/* #[test] fn all_mov_mov() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) - .into_par_iter() - .for_each(|a_len| { - (0..a_pos) - .into_par_iter() - .chain((a_pos + a_len + 1)..=ALL_SIZE) - .for_each(|a_to| { - (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { - (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) - .into_par_iter() - .for_each(|b_len| { - (0..b_pos) - .into_par_iter() - .chain((b_pos + b_len + 1)..=ALL_SIZE) - .for_each(|b_to| { - t_mov_mov( - ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len, b_to, - ); - }); - }); + (1..(ALL_SIZE - a_pos)).into_par_iter().for_each(|a_len| { + (0..ALL_SIZE).into_par_iter().for_each(|a_to| { + let a_to = filter_to(ALL_SIZE, a_pos, a_to); + let a_len = a_len.min(ALL_SIZE - a_pos.max(a_to)); + + (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { + (1..(ALL_SIZE - b_pos)).into_par_iter().for_each(|b_len| { + (0..ALL_SIZE).into_par_iter().for_each(|b_to| { + let b_to = filter_to(ALL_SIZE, b_pos, b_to); + let b_len = b_len.min(ALL_SIZE - b_pos.max(b_to)); + + t_mov_mov(ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len, b_to); }); }); + }); }); + }); }); } - -fn test_params() -> impl Strategy { - ((MIN_RANGE_LEN + 1)..=VEC_SIZE) - .prop_flat_map(|vec_size| (Just(vec_size), mov_params(vec_size), mov_params(vec_size))) -} - -/// Parameters for a single test operation -fn mov_params(vec_size: usize) -> impl Strategy { - (0..(vec_size - MIN_RANGE_LEN)) - .prop_flat_map(move |pos| (Just(pos), MIN_RANGE_LEN..=(vec_size - pos))) - .prop_flat_map(move |(pos, len)| { - let rb = (pos + len + 1)..(vec_size + 1); - ( - Just(pos), - Just(len), - match (pos > 0, rb.end > rb.start) { - (true, true) => Strategy::boxed((0..pos).prop_union(rb)), - (true, false) => Strategy::boxed(0..pos), - (false, true) => Strategy::boxed(rb), - (false, false) => Strategy::boxed(Just(pos)), - }, - ) - }) -} +*/ proptest! { #[test] - fn transform_ins_ins((vec_len, a, b) in test_params(), a_len in 1usize..VEC_SIZE, b_len in 1usize..VEC_SIZE) { - t_ins_ins(vec_len, a.0, a_len, b.0, b_len) + fn transform_ins_ins(a_pos in 0usize..VEC_SIZE, a_len in 1usize..VEC_SIZE, b_pos in 0usize..VEC_SIZE, b_len in 1usize..VEC_SIZE) { + t_ins_ins(VEC_SIZE, a_pos, a_len, b_pos, b_len) } #[test] - fn transform_del_del((vec_len, a, b) in test_params()) { - t_del_del(vec_len, a.0, a.1, b.0, b.1) + fn transform_del_del(a_pos in 0usize..VEC_SIZE, a_len in 1usize..VEC_SIZE, b_pos in 0usize..VEC_SIZE, b_len in 1usize..VEC_SIZE) { + // Limit inputs + let a_len = a_len.min(VEC_SIZE - a_pos); + let b_len = b_len.min(VEC_SIZE - b_pos); + + t_del_del(VEC_SIZE, a_pos, a_len, b_pos, b_len) } #[test] - fn transform_ins_del((vec_len, a, b) in test_params(), i_len in 1usize..VEC_SIZE) { - t_ins_del(vec_len, a.0, i_len, b.0, b.1) + fn transform_ins_del(a_pos in 0usize..VEC_SIZE, a_len in 1usize..VEC_SIZE, b_pos in 0usize..VEC_SIZE, b_len in 1usize..VEC_SIZE) { + let b_len = b_len.min(VEC_SIZE - b_pos); + + t_ins_del(VEC_SIZE, a_pos, a_len, b_pos, b_len) } #[test] - fn transform_mov_ins((vec_len, a, b) in test_params(), i_len in 1usize..VEC_SIZE) { - t_mov_ins(vec_len, a.0, a.1, a.2, b.0, i_len) + fn transform_mov_ins(a_len in 1usize..VEC_SIZE, a_pos in 0usize..VEC_SIZE, a_to in 0usize..VEC_SIZE, b_pos in 0usize..VEC_SIZE, b_len in 1usize..VEC_SIZE) { + // Limit inputs + let a_to = filter_to(VEC_SIZE, a_pos, a_to); + let a_len = a_len.min(VEC_SIZE - a_pos.max(a_to)); + + t_mov_ins(VEC_SIZE, a_pos, a_len, a_to, b_pos, b_len) } + /* #[test] - fn transform_mov_del((vec_len, a, b) in test_params()) { - t_mov_del(vec_len, a.0, a.1, a.2, b.0, b.1) - } + fn transform_mov_del(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) { + // Limit inputs + let a_to = filter_to(VEC_SIZE, a_pos, a_to); + let a_len = a_len.min(VEC_SIZE - a_pos.max(a_to)); + let b_len = b_len.min(VEC_SIZE - b_pos); - #[test] - fn transform_mov_mov((vec_len, a, b) in test_params()) { - t_mov_mov(vec_len, a.0, a.1, a.2, b.0, b.1, b.2); + t_mov_del(VEC_SIZE, a_pos, a_len, a_to, b_pos, b_len, None) } + */ + /* #[test] - fn transform_seq((vec_len, a, b, a2, b2, a3, b3) in test_params().prop_flat_map(|(vec_len, a, b)| - (Just(vec_len), Just(a), Just(b), mov_params(vec_len), mov_params(vec_len), mov_params(vec_len), mov_params(vec_len))) - ) { - let input = testvec(vec_len); - let a = Operation::Seq { ops: vec![ - Operation::Mov { - pos: a.0, - n: a.1, - to: a.2, - }, - Operation::Ins { pos: a2.0, val: testvec(a3.1) }, - Operation::Del { pos: a3.0, n: a3.1 }, - ] }; - let b = Operation::Seq { ops: vec![ - Operation::Mov { - pos: b.0, - n: b.1, - to: b.2, - }, - Operation::Ins { pos: b2.0, val: testvec(b3.1) }, - Operation::Del { pos: b3.0, n: b3.1 }, - ] }; - test_transform_cond(&a, &b, &input); - test_transform_cond(&b, &a, &input); + 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 + let a_to = filter_to(VEC_SIZE, a_pos, a_to); + let a_len = a_len.min(VEC_SIZE - a_pos.max(a_to)); + let b_to = filter_to(VEC_SIZE, b_pos, b_to); + let b_len = b_len.min(VEC_SIZE - b_pos.max(b_to)); + + 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 e205ed0..0f1912f 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -16,18 +16,6 @@ fn apply_mov(#[case] pos: usize, #[case] n: usize, #[case] to: usize, #[case] ex assert_eq!(input, expect); } -#[test] -fn print() { - let input = vec![1, 2, 3, 4, 5]; - - let op = Operation::Mov { - pos: 1, - n: 2, - to: 4, - }; - op.print_on(&input); -} - #[test] fn transform_ins_ins() { let a = Operation::Ins { @@ -393,5 +381,5 @@ fn transform_mov_mov5() { n: 1, to: 3, }; - test_transform(&a, &b, &input, &[2, 3, 1, 4]); + test_transform(&a, &b, &input, &[2, 3, 4, 1]); } diff --git a/tests/tests_mov.rs b/tests/tests_mov.rs index 76fe21e..c1817d5 100644 --- a/tests/tests_mov.rs +++ b/tests/tests_mov.rs @@ -1,589 +1,42 @@ mod util; use otvec::Operation; -use util::{test_transform, test_transform_sym}; +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] -// 1 MOV-DEL; Intersection::Overlap, Intersection::Empty; right end; to right +// 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])] -// 2 MOV-DEL; Intersection::Overlap, Intersection::Empty; right end; to left +// 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])] -// 3 MOV-DEL; Intersection::LessOverlap, Intersection::Over; -// - +// 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])] -// 4 ibt: over - -// MOV: [0, 1, 2,|3, 4, (5, 6, 7), 8] => [0, 1, 2, (5, 6, 7), 3, 4, 8] + +// MOV: [0, 1, 2, 3, 4, (5, 6, 7), 8] => [0, 1, 2, (5, 6, 7), 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: 3}, Operation::Del {pos: 1, n: 5}, &[0, 6, 7, 8])] -// 5 MOV-DEL; Intersection::Overlap, Intersection::Over; ibt: LessOverlap -// - -// MOV: [0,|1, (2, 3, 4, 5, 6), 7, 8] => [0, (2, 3, 4, 5, 6), 1, 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}, &[3, 4, 5, 6, 7, 8])] -// 6 ibt: over ---- -// MOV: [|0, 1, 2, 3,(4, 5, 6), 7, 8] => [(4, 5, 6), 0, 1, 2, 3, 7, 8] => [(4, 5), 6, (0, 1, 2, 3), 7, 8] -// DEL: [(0, 1, 2, 3, 4, 5), 6, 7, 8] => [6, 7, 8] -#[case(Operation::Mov { pos: 4, n: 3, to: 0 }, Operation::Del { pos: 0, n: 6 }, &[6, 7, 8])] -// 7 -// MOV: [0, 1, 2, 3, 4, (5, 6), 7, 8] => [0, 1, 2, 3, (5, 6), 4, 7, 8] -// DEL: [(0, 1, 2, 3, 4, 5), 6, 7, 8] => [6, 7, 8] -#[case(Operation::Mov { pos: 5, n: 2, to: 4 }, Operation::Del { pos: 0, n: 6 }, &[6, 7, 8])] -// 8 less moved to DEL -// MOV: [0, 1, 2, 3, (4, 5),6, 7, 8] => [0,(4, 5),1, 2, 3, 6, 7, 8] => [0,(4, 5),3, 6, 7, 8] -// DEL: [0,(1, 2), 3, 4, 5, 6, 7, 8] => [0, 3,(4, 5), 6, 7, 8] => [0, (4, 5), 3, 6, 7, 8] -#[case(Operation::Mov { pos: 4, n: 2, to: 1 }, Operation::Del { pos: 1, n: 2 }, &[0, 4, 5, 3, 6, 7, 8])] -// 9 less moved right from del -// MOV: [0, 1, 2, 3, (4, 5),6, 7, 8] => [0, 1, 2, 3, 6, 7, (4, 5), 8] -// DEL: [0,(1, 2), 3, 4, 5, 6, 7, 8] => [0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 4, n: 2, to: 8 }, Operation::Del { pos: 1, n: 2 }, &[0, 3, 6, 7, 4, 5, 8])] -// 10 less moved inside DEL -// MOV: [0, 1, 2, 3,(4, 5),6, 7, 8] => [0, (1), 4, 5, (2), 3, 6, 7, 8] -// DEL: [0,(1, 2),3, 4, 5, 6, 7, 8] => [0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 4, n: 2, to: 2 }, Operation::Del { pos: 1, n: 2 }, &[0, 4, 5, 3, 6, 7, 8])] -// 11 less moved left from DEL -// MOV: [0, 1, 2, 3,(4, 5),6, 7, 8] => [(4, 5),0, 1, 2, 3, 6, 7, 8] -// DEL: [0,(1, 2),3, 4, 5, 6, 7, 8] => [0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 4, n: 2, to: 0 }, Operation::Del { pos: 1, n: 2 }, &[4, 5, 0, 3, 6, 7, 8])] -// 12 greater moved right from DEL -// MOV: [0,(1, 2),3, 4, 5, 6, 7, 8] => [0, 3, (4, 5), 6, 7, 1, 2, 8] => [0, 3, 6, 7, 1, 2, 8] -// DEL: [0, 1, 2, 3,(4, 5),6, 7, 8] => [0, (1, 2), 3, 6, 7, 8] => [0, 3, 6, 7, 1, 2, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 8 }, Operation::Del { pos: 4, n: 2 }, &[0, 3, 6, 7, 1, 2, 8])] -// 13 greater moved left from DEL -// MOV: [(0), 1, 2, 3, 4, 5, 6, 7, 8] => [1, 0, 2, 3, 4, 5, 6, 7, 8] -// DEL: [0, (1), 2, 3, 4, 5, 6, 7, 8] => [0, 2, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 1, to: 2 }, Operation::Del { pos: 1, n: 1 }, &[0, 2, 3, 4, 5, 6, 7, 8])] -// 14 greater moved left from DEL -// MOV: [(0), 1, 2, 3, 4, 5, 6, 7, 8] => [1, 0, 2, 3, 4, 5, 6, 7, 8] -// DEL: [0, 1, (2), 3, 4, 5, 6, 7, 8] => [0, 1, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 1, to: 2 }, Operation::Del { pos: 2, n: 1 }, &[1, 0, 3, 4, 5, 6, 7, 8])] -// 15 greater moved left from DEL -// MOV: [(0, 1), 2, 3, 4, 5, 6, 7, 8] => [2, 0, 1, 3, 4, 5, 6, 7, 8] -// DEL: [0, 1, (2), 3, 4, 5, 6, 7, 8] => [0, 1, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Del { pos: 2, n: 1 }, &[0, 1, 3, 4, 5, 6, 7, 8])] -// 16 greater moved inside DEL -// MOV: [(0, 1), 2, 3, 4, 5, 6, 7, 8] => [(2), 0, 1, (3, 4), 5, 6, 7, 8] -// DEL: [0, 1, (2, 3, 4), 5, 6, 7, 8] => [0, 1, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Del { pos: 2, n: 3 }, &[0, 1, 5, 6, 7, 8])] -// 14 greater moved to DEL -// MOV: [0,(1, 2),3, 4, 5, 6, 7, 8] => [0, 3, 4, 5,(1, 2),6, 7, 8] => [0, 3, (1, 2), 6, 7, 8] -// DEL: [0, 1, 2, 3,(4, 5),6, 7, 8] => [0, (1, 2), 3, 6, 7, 8] => [0, 3, (1, 2), 6, 7, 8] -// #[case(Operation::Mov { pos: 1, n: 2, to: 6 }, Operation::Del { pos: 4, n: 2 }, &[0, 3, 1, 2, 6, 7, 8])] -// -// MOV: [0, 1, 2, (3, 4, 5), 6, 7, 8] => [0, (3, 4, 5), 1, 2, 6, 7, 8] => [0, 4, 5, 6, 7, 8] -// DEL: [0, (1, 2, 3), 4, 5, 6, 7, 8] => [0, 4, 5, 6, 7, 8] -// #[case(Operation::Mov { pos: 3, n: 3, to: 1 }, Operation::Del { pos: 1, n: 3 }, &[0, 4, 5, 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); } - -#[rstest] -// MOV: (0) 1 2 3 4 5 6 7 8 => 1 (0) 2 3 4 5 6 7 8 -// DEL: 0 (1 2) 3 4 5 6 7 8 => 0 |3 4 5 6 7 8 -#[case(Operation::Mov { pos: 0, n: 1, to: 2 }, Operation::Del { pos: 1, n: 2 }, &[0, 3, 4, 5, 6, 7, 8])] -#[case(Operation::Mov { pos: 0, n: 1, to: 3 }, Operation::Del { pos: 2, n: 2 }, &[1, 0, 4, 5, 6, 7, 8])] -#[case(Operation::Mov { pos: 0, n: 1, to: 3 }, Operation::Del { pos: 1, n: 2 }, &[0, 3, 4, 5, 6, 7, 8])] -// MOV: (0) 1 2 3 4 5 6 7 8 => 1 (0) 2 3 4 5 6 7 8 -// DEL: 0 1 (2) 3 4 5 6 7 8 => 0 1 3 4 5 6 7 8 -#[case(Operation::Mov { pos: 0, n: 1, to: 2 }, Operation::Del { pos: 2, n: 1 }, &[1, 0, 3, 4, 5, 6, 7, 8])] -// MOV: [(0), 1, 2, 3, 4, 5, 6, 7, 8] => [(1), 0, 2, 3, 4, 5, 6, 7, 8] -// DEL: [0, (1), 2, 3, 4, 5, 6, 7, 8] => [0, 2, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 1, to: 2 }, Operation::Del { pos: 1, n: 1 }, &[0, 2, 3, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, 4, 5, 6, 7, 8] => [(2), 0, 1, 3, 4, 5, 6, 7, 8] -// DEL: [0, 1, (2), 3, 4, 5, 6, 7, 8] => [0, 1, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Del { pos: 2, n: 1 }, &[0, 1, 3, 4, 5, 6, 7, 8])] -fn transform2(#[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); -} - -#[rstest] -// MOV: [(0, 1), 2, 3, 4, 5, 6, 7, 8] => [(2), 0, (1), 3, 4, 5, 6, 7, 8] -// DEL: [0, (1, 2), 3, 4, 5, 6, 7, 8] => [0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Del { pos: 1, n: 2 }, &[0, 3, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2,|3, 4, 5, 6, 7, 8] => [(2),|0, (1, 3), 4, 5, 6, 7, 8] -// DEL: [0, (1, 2, 3), 4, 5, 6, 7, 8] => [0, 4, 5, 6, 7, 8] -// rtarget: 1-2 -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Del { pos: 1, n: 3 }, &[0, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3,|4, 5, 6, 7, 8] => [(2, 3), 0, (1), 4, 5, 6, 7, 8] -// DEL: [0, (1, 2, 3), 4, 5, 6, 7, 8] => [0, 4, 5, 6, 7, 8] -// rtarget: 2-3 -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Del { pos: 1, n: 3 }, &[0, 4, 5, 6, 7, 8])] -// MOV: [(0,1, 2),3,|4, 5, 6, 7, 8] => [(3), 0, 1, (2, 4, 5), 6, 7, 8] -// DEL: [0, 1,(2, 3, 4, 5), 6, 7, 8] => [0, 1, 6, 7, 8] -// rtarget: 1-3 -#[case(Operation::Mov { pos: 0, n: 3, to: 4 }, Operation::Del { pos: 2, n: 4 }, &[0, 1, 6, 7, 8])] -// MOV: [(0,1, 2),3,|4, 5, 6, 7, 8] => [(3), 0, (1, 2, 4), 5, 6, 7, 8] -// DEL: [0,(1, 2, 3, 4),5, 6, 7, 8] => [0, 5, 6, 7, 8] -// rtarget: 1-3 -#[case(Operation::Mov { pos: 0, n: 3, to: 4 }, Operation::Del { pos: 1, n: 4 }, &[0, 5, 6, 7, 8])] -// MOV: [0, (1, 2), 3, 4, 5, 6, 7, 8] => [1, (2), 0, (3), 4, 5, 6, 7, 8] -// DEL: [0, 1, (2, 3), 4, 5, 6, 7, 8] => [0, (1), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Del { pos: 2, n: 2 }, &[1, 0, 4, 5, 6, 7, 8])] -fn transform3(#[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); -} - -#[rstest] -// MOV: [(0, 1, 2), 3,|4, 5, 6, 7, 8] => [3, (0, 1), 2, 4, 5, 6, 7, 8] -// DEL: [(0, 1), 2, 3, 4, 5, 6, 7, 8] => [(2), 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 4 }, Operation::Del { pos: 0, n: 2 }, &[3, 2, 4, 5, 6, 7, 8])] -// MOV: [0, (1, 2, 3), 4, 5, 6, 7, 8] => [(1, 2), 3, 0, 4, 5, 6, 7, 8] -// DEL: [0, (1, 2), 3, 4, 5, 6, 7, 8] => [0, (3), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 3, to: 0 }, Operation::Del { pos: 1, n: 2 }, &[3, 0, 4, 5, 6, 7, 8])] -fn transform_mov_del_within( - #[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); -} - -#[rstest] -// MOV: [(0, 1), 2,|3, 4, 5, 6, 7, 8] => [(2), (0, 1), 3, 4, 5, 6, 7, 8] -// DEL: [(0, 1, 2), 3, 4, 5, 6, 7, 8] => [3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 5 }, Operation::Del { pos: 0, n: 3 }, &[3, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, 4,|5, 6, 7, 8] => [(2), 3, 4, (0, 1), 5, 6, 7, 8] -// DEL: [(0, 1, 2), 3, 4, 5, 6, 7, 8] => [3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 5 }, Operation::Del { pos: 0, n: 3 }, &[3, 4, 5, 6, 7, 8])] -// MOV: [0, (1, 2), 3, 4, 5, 6, 7, 8] => [(0), 3, (1, 2), 4, 5, 6, 7, 8] -// DEL: [(0, 1, 2), 3, 4, 5, 6, 7, 8] => [3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 4 }, Operation::Del { pos: 0, n: 3 }, &[3, 4, 5, 6, 7, 8])] -// MOV: [|0,(1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, (3), 4, 5, 6, 7, 8] -// DEL: [0, (1, 2, 3), 4, 5, 6, 7, 8] => [0, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Del { pos: 1, n: 3 }, &[0, 4, 5, 6, 7, 8])] -// MOV: [0,|1, (2, 3), 4, 5, 6, 7, 8] => [(0, 2, 3, 1), 4, 5, 6, 7, 8] -// DEL: [(0, 1, 2, 3), 4, 5, 6, 7, 8] => [4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Del { pos: 0, n: 4 }, &[4, 5, 6, 7, 8])] -fn transform_mov_del_over( - #[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); -} - -#[rstest] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3,|4, 5, 6, 7, 8] m2_to+0 -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [2, 3, (0, 1), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[2, 3, 0, 1, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [2,|3, (0,|1), 4, 5, 6, 7, 8] m2_to-mn -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[2, 0, 1, 3, 4, 5, 6, 7, 8])] -// MOV: [|0, 1, (2, 3), 4, 5, 6, 7, 8] => [(2,|3), 0,|1, 4, 5, 6, 7, 8] m2_to+mn -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [0, (2, 3), 1, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 0 }, Operation::Mov { pos: 2, n: 2, to: 1 }, &[0, 2, 3, 1, 4, 5, 6, 7, 8])] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, 3,|4, 5, 6, 7, 8] m2_to+0 -// MOV: [0, (1, 2), 3, |4, 5, 6, 7, 8] => [0, 3, (1, 2), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 1, n: 2, to: 4 }, &[0, 3, 1, 2, 4, 5, 6, 7, 8])] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [|0, (2, 3), 1, 4, 5, 6, 7, 8] m2_to+0 -// MOV: [|0, 1, (2, 3), 4, 5, 6, 7, 8] => [(2, 3), 0, 1, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Mov { pos: 2, n: 2, to: 0 }, &[2, 3, 0, 1, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, 4, |5, 6, 7, 8] => [2, 3, 4,|(0, 1), 5, 6, 7, 8] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 5 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[2, 0, 1, 3, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, 4, 5, |6, 7, 8] => [2, 3, 4, 5, (0, 1), 6, 7, 8] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 6 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[2, 0, 1, 3, 4, 5, 6, 7, 8])] -fn transform_mov_mov_same( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [|2, (0, 1), {3, 4}, 5, 6, 7, 8] Sa/Gr -// MOV: [|0, 1, 2, (3, 4), 5, 6, 7, 8] => [ (3, 4), {0, 1}, 2,|5, 6, 7, 8] => [3, 4, 2, (0, 1), 5, 6, 7, 8] -// -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 3, n: 2, to: 0 }, &[3, 4, 2, 0, 1, 5, 6, 7, 8], true)] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [|(1, 2), 0, {3, 4}, 5, 6, 7, 8] Go/Gr -// MOV: [|0, 1, 2, (3, 4), 5, 6, 7, 8] => [(3, 4),| 0, {1, 2}, 5, 6, 7, 8] -// #[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 3, n: 2, to: 0 }, &[3, 4, 1, 2, 0, 5, 6, 7, 8], false)] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 3, n: 2, to: 0 }, &[1, 2, 3, 4, 0, 5, 6, 7, 8], false)] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0,|{3, 4}, 5, 6, 7, 8] Sa/Gr -// MOV: [0, |1, 2, (3, 4), 5, 6, 7, 8] => [|0, (3, 4), {1, 2}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 3, n: 2, to: 1 }, &[1, 2, 0, 3, 4, 5, 6, 7, 8], true)] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, {3, 4}, 5,|6, 7, 8] Le/Gr -// MOV: [0, 1, 2, (3, 4), 5, |6, 7, 8] => [|0, {1, 2}, 5, (3, 4), 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 3, n: 2, to: 6 }, &[1, 2, 0, 5, 3, 4, 6, 7, 8], true)] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [|0, (2, 3), 1, {4, 5}, 6, 7, 8] Gr/Gr -// MOV: [|0, 1, 2, 3, (4, 5), 6, 7, 8] => [(4, 5), 0,| 1, {2, 3}, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Mov { pos: 4, n: 2, to: 0 }, &[4, 5, 0, 2, 3, 1, 6, 7, 8], true)] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [|(1, 2), 0, {3, 4, 5}, 6, 7, 8] -// MOV: [|0, 1, 2, (3, 4, 5), 6, 7, 8] => [(3, 4, 5),|0, {1, 2}, 6, 7, 8] -// #[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 3, n: 3, to: 0 }, &[3, 4, 5, 1, 2, 0, 6, 7, 8], false)] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 3, n: 3, to: 0 }, &[1, 2, 3, 4, 5, 0, 6, 7, 8], false)] -// MOV: [|0, 1, (2, 3), 4, 5, 6, 7, 8] => [(2, 3), 0,|1, {4, 5}, 6, 7, 8] Go/Gr -// MOV: [0, |1, 2, 3, (4, 5), 6, 7, 8] => [|0, (4, 5), 1, {2, 3}, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 0 }, Operation::Mov { pos: 4, n: 2, to: 1 }, &[2, 3, 0, 4, 5, 1, 6, 7, 8], false)] - -// MOV: [(0, 1), 2, 3, 4, |5, 6, 7, 8] => [{2, 3}, 4, (0, 1), 5, 6, 7, 8] -// MOV: [|0, 1, (2, 3), 4, 5, 6, 7, 8] => [(2, 3), {0, 1}, 4,|5, 6, 7, 8] -// #[case(Operation::Mov { pos: 0, n: 2, to: 5 }, Operation::Mov { pos: 2, n: 2, to: 0 }, &[2, 3, 4, 0, 1, 5, 6, 7, 8], false)] -fn transform_mov_mov_less( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], - #[case] sym: bool, -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - if sym { - test_transform_sym(&a, &b, &input, expect); - } else { - test_transform(&a, &b, &input, expect); - } -} - -#[rstest] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3, 4, 5, 6, 7, 8] => [0, 1, 2, 3, 4, 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0,|3, 4, 5, 6, 7, 8] => [0, (1, 2), 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[1, 2, 0, 3, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [{2}, (0, {1}), 3, 4, 5, 6, 7, 8] => [{2}, 0, 3, 1, 4..] => [0, 3, 1, 2, 4, 5, 6, 7, 8] -// MOV: [0, (1, 2), 3, |4, 5, 6, 7, 8] => [0, 3, (1, 2), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 1, n: 2, to: 4 }, &[3, 1, 2, 0, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3, 4, 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[1, 2, 0, 3, 4, 5, 6, 7, 8])] -// MOV: [0, (1, 2), 3, |4, 5, 6, 7, 8] => [0, 3, (1, 2), 4, 5, 6, 7, 8] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [{2}, (0, 1), 3,|4, 5, 6, 7, 8] => [0, 1, 3, 2, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 4 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[0, 1, 3, 2, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [2, 3, (0, 1), 4, 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[1, 2, 3, 0, 4, 5, 6, 7, 8])] -fn transform_mov_mov_truncated( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// MOV: [(0), 1, 2, 3, 4, 5, 6, 7, |8] => [1, 2, 3, 4, 5, 6, 7, (0), 8] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 1, to: 8 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[2, 0, 1, 3, 4, 5, 6, 7, 8])] -fn transform_mov_mov_within( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// MOV: [(0, 1, 2), 3, |4, 5, 6, 7, 8] => [3,(0,{1},2),4, 5, 6,|7, 8] -// MOV: [ 0,(1), 2, 3, 4, 5, 6, |7, 8] => [{0, 2}, 3,|4, 5, 6,(1), 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 4 }, Operation::Mov { pos: 1, n: 1, to: 7 }, &[3, 0, 2, 4, 5, 6, 1, 7, 8])] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [0, (2, 3), 1, 4, 5, 6, 7, 8] => [0, (2), 3, 1, 4, 5, 6, 7,|8] -// MOV: [0, 1, (2), 3, 4, 5, 6, 7, |8] => [0, 1, 3, 4, 5, 6, 7, (2), 8] => [0,|1, (3), 4, 5, 6, 7, 2, 8] !! -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Mov { pos: 2, n: 1, to: 8 }, &[0, 3, 1, 4, 5, 6, 7, 2, 8])] -// MOV: [|0,*(1, 2, 3), 4, 5, 6, 7, 8] => [(1, 2, 3), 0,*4, 5, 6, 7, 8] => [1, (2, 3), 0,|4, 5, 6, 7, 8] !!b2 -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [0, (2, 3), 1, 4, 5, 6, 7, 8] => [|0, 2, 3, (1), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 3, to: 0 }, Operation::Mov { pos: 2, n: 2, to: 1 }, &[1, 0, 2, 3, 4, 5, 6, 7, 8])] -// #equal targets -// MOV: [(0, 1, 2), 3, |4, 5, 6, 7, 8] => [3, (0, 1, 2), 4, 5, 6, 7, 8] => [ 3, (0, 1), 2,|4, 5, 6, 7, 8] ? +m2_n -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [2, 3, (0, 1), 4, 5, 6, 7, 8] => [(2), 3,|0, 1, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 4 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[3, 2, 0, 1, 4, 5, 6, 7, 8])] -// MOV: [(0, 1, 2), 3, 4, |5, 6, 7, 8] => [3, 4, ({0, 1},|2),|5, 6, 7, 8] -// MOV: [(0, 1), 2, 3, 4, |5, 6, 7, 8] => [{2}, 3, 4,|(0, 1), 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 5 }, Operation::Mov { pos: 0, n: 2, to: 5 }, &[3, 4, 2, 0, 1, 5, 6, 7, 8])] -// MOV: [|0, (1, 2, 3), 4, 5, 6, 7, 8] => [({1, 2}, 3),|0, 4, 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [|(1, 2), 0, {3}, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 3, to: 0 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[3, 1, 2, 0, 4, 5, 6, 7, 8])] -// #split -// MOV: [|0, (1, 2, 3,*4), 5, 6, 7, 8] => [|({1, 2}, 3,|4), 0, 5, 6, 7, 8] => [3, 1, 2, 4, 0, 5, 6, 7, 8] -// MOV: [0, (1, 2), 3,| 4, 5, 6, 7, 8] => [|0, {3, (1, 2), 4}, 5, 6, 7, 8] => [3, 1, 2, 4, 0, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 4, to: 0 }, Operation::Mov { pos: 1, n: 2, to: 4 }, &[3, 1, 2, 4, 0, 5, 6, 7, 8])] -// MOV: [|0, (1,*2, 3, 4), 5, 6, 7, 8] => [ (1,|2, {3, 4}), 0, 5, 6, 7, 8] -// MOV: [ 0, 1,|2, (3, 4), 5, 6, 7, 8] => [|0, {1,(3, 4), 2}, 5, 6, 7, 8] => [1, 3, 4, 2, 0, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 4, to: 0 }, Operation::Mov { pos: 3, n: 2, to: 2 }, &[1, 3, 4, 2, 0, 5, 6, 7, 8])] -fn transform_mov_mov_over( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// b split by a -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [|2, (0, {1}), 3, 4, 5, 6, 7, 8] -// MOV: [|0, (1, 2, 3), 4, 5, 6, 7, 8] => [(1, 2,|3), {0}, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 1, n: 3, to: 0 }, &[1, 2, 0, 3, 4, 5, 6, 7, 8])] -// MOV: [0, (1, 2), 3, |4, 5, 6, 7, 8] => [|{0}, 3, (1, {2}), 4,|5, 6, 7, 8] => [2, (0), 3, 1, 4,|5, 6, 7, 8] -// MOV: [|0, 1, (2, 3, 4), 5, 6, 7, 8] => [(2, 3,|4), 0, {1}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 4 }, Operation::Mov { pos: 2, n: 3, to: 0 }, &[2, 3, 1, 4, 0, 5, 6, 7, 8])] -// MOV: [0, (1, 2), 3, 4, |5, 6, 7, 8] => [0, 3, 4, (1, {2}), 5, 6, 7, 8] => [2, {0}, 3, 4, 1, 5,|6, 7, 8] -// MOV: [|0, 1, (2, 3, 4, 5), 6, 7, 8] => [(2, 3, 4,|5), 0, {1}, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 5 }, Operation::Mov { pos: 2, n: 4, to: 0 }, &[2, 3, 4, 1, 5, 0, 6, 7, 8])] -// MOV: [(0, 1, 2), 3, |4, 5, 6, 7, 8] => [{3, (0, 1, 2), 4}, 5,|6, 7, 8] => [5,|3, 0, 1, {2}, 4, 6, 7, 8] => [5, 2, 3, 0, 1, 4, 6, 7, 8] -// MOV: [0, 1, (2, 3, 4), 5, |6, 7, 8] => [(0, 1), 5, (2, 3,|4), 6, 7, 8] => [5, 2, 3, 0, 1, 4, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 4 }, Operation::Mov { pos: 2, n: 3, to: 6 }, &[5, 2, 3, 0, 1, 4, 6, 7, 8])] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [{2, (0, 1), 3}, 4, 5,|6, 7, 8] => [4, 5,|(2, 0, {1}, 3), 6, 7, 8] -// MOV: [0, (1, 2, 3), 4, 5, |6, 7, 8] => [{0}, 4, 5, (1, 2,|3), 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 1, n: 3, to: 6 }, &[4, 5, 1, 2, 0, 3, 6, 7, 8])] -// a split by b -// MOV: [(0, 1, 2), 3, |4, 5, 6, 7, 8] => [|3, (0, 1, {2}), 4, 5, 6, 7, 8] => [(2), 3, 0, 1, 4, 5, 6, 7, 8] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [{0},(2, 3), {1},|4, 5, 6, 7, 8] => [2, 3, (0), (1), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 4 }, Operation::Mov { pos: 2, n: 2, to: 1 }, &[2, 3, 0, 1, 4, 5, 6, 7, 8])] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [|4, (0, 1, {2, 3}), 5, 6, 7, 8] => [(2, 3), 4, 0, 1, 5, 6, 7, 8] -// MOV: [0, |1, (2, 3, 4), 5, 6, 7, 8] => [{0}, (2, 3, 4), {1},|5, 6, 7, 8] => [2, 3, 4, 0, 1, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 4, to: 5 }, Operation::Mov { pos: 2, n: 3, to: 1 }, &[2, 3, 4, 0, 1, 5, 6, 7, 8])] -// MOV: [(0, 1, 2), 3, 4, 5, |6, 7, 8] => [3, 4, 5, (0, 1, {2}), 6, 7, 8] => [2, 3, 4, 5, 0, 1, 6, 7, 8] -// MOV: [0, |1, (2, 3, 4), 5, 6, 7, 8] => [{0}, (2, 3, 4), {1}, 5,|6, 7, 8] => [2, 3, 4, 5, (0), (1), 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 6 }, Operation::Mov { pos: 2, n: 3, to: 1 }, &[2, 3, 4, 5, 0, 1, 6, 7, 8])] -// MOV: [|0, (1, 2, 3), 4, 5, 6, 7, 8] => [(1, 2, {3}), 0,| 4, 5, 6, 7, 8] -// MOV: [0, 1, |2, (3, 4), 5, 6, 7, 8] => [|0, {1}, (3, 4), {2}, 5, 6, 7, 8] => [1, 2, 0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 3, to: 0 }, Operation::Mov { pos: 3, n: 2, to: 2 }, &[1, 2, 0, 3, 4, 5, 6, 7, 8])] -// both split -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [|4, (0, 1, {2, 3}), 5, 6, 7, 8] => [2, 3, 4, 0, 1, 5, 6, 7, 8] -// MOV: [0, |1, (2, 3, 4, 5, 6, 7), 8] => [{0}, (2, 3, 4, 5, 6, 7), {1}, 8] => [2, 3, 4, 0, 1, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 4, to: 5 }, Operation::Mov { pos: 2, n: 6, to: 1 }, &[2, 3, 4, 0, 1, 5, 6, 7, 8])] -fn transform_mov_mov_split_ol_less( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// a split by b -// MOV: [|0, (1, 2, 3, 4, 5, 6, 7), 8] => [ ({1, 2, 3}, 4, 5, 6, 7), 0,|8] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [|{4}, (0, 1, 2, 3), {5, 6, 7}, 8] => [5, 6, 7, {4}, 0, 1, 2, 3, 8] -#[case(Operation::Mov { pos: 1, n: 7, to: 0 }, Operation::Mov { pos: 0, n: 4, to: 5 }, &[4, 5, 6, 7, 0, 1, 2, 3, 8])] -// MOV: [|0, (1, 2, 3), 4, 5, 6, 7, 8] => [({1}, 2, 3), 0,|4, 5, 6, 7, 8] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [{2}, (0, 1), {3}, 4, 5, 6, 7, 8] => [2, 3, 0, 1, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 3, to: 0 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[2, 3, 0, 1, 4, 5, 6, 7, 8])] -// MOV: [|0, 1, (2, 3, 4, 5, 6, 7), 8] => [({2, 3}, 4, 5, 6, 7), 0, 1,|8] => [4, 5, 6, 7, 0, 1, 2, 3, 8] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [|{4}, (0, 1, 2, 3), {5, 6, 7}, 8] => [4, 5, 6, 7, 0, 1, 2, 3, 8] -#[case(Operation::Mov { pos: 2, n: 6, to: 0 }, Operation::Mov { pos: 0, n: 4, to: 5 }, &[4, 5, 6, 7, 0, 1, 2, 3, 8])] -// MOV: [|0, 1, (2, 3, 4), 5, 6, 7, 8] => [({2}, 3, 4), 0, 1,|5, 6, 7, 8] -// MOV: [0, (1, 2), 3, |4, 5, 6, 7, 8] => [|0, {3}, (1, 2), {4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 3, to: 0 }, Operation::Mov { pos: 1, n: 2, to: 4 }, &[3, 4, 0, 1, 2, 5, 6, 7, 8])] -// MOV: [0, (1, 2, 3), 4, |5, 6, 7, 8] => [0,|4, ({1}, 2, 3), 5, 6, 7, 8] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [{2}, (0, 1), {3}, 4,|5, 6, 7, 8] => [{2}, 0, 1, 4,|(3), 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 3, to: 5 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[0, 1, 4, 2, 3, 5, 6, 7, 8])] -// MOV: [0, |1, (2, 3, 4), 5, 6, 7, 8] => [0, ({2}, 3, 4), 1,|5, 6, 7, 8] wi -// MOV: [(0, 1, 2), 3, |4, 5, 6, 7, 8] => [{3}, (0,|1, 2), {4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 3, to: 1 }, Operation::Mov { pos: 0, n: 3, to: 4 }, &[0, 3, 4, 1, 2, 5, 6, 7, 8])] -// b split by a, R -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [0, ({2}, 3), 1,|4, 5, 6, 7, 8] -// MOV: [(0, 1, 2), 3, |4, 5, 6, 7, 8] => [{3}, (0,|1, 2), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Mov { pos: 0, n: 3, to: 4 }, &[0, 3, 1, 2, 4, 5, 6, 7, 8])] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [{0, ({2}, 3), 1}, 4,|5, 6, 7, 8] => [{0, 3, 1}, 4,|2, 5, 6, 7, 8] -// MOV: [(0, 1, 2), 3, 4, |5, 6, 7, 8] => [{3}, 4, (0,|1, 2), 5, 6, 7, 8] => [4, 0, (3), 1, 2, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Mov { pos: 0, n: 3, to: 5 }, &[4, 0, 3, 1, 2, 5, 6, 7, 8])] -// b split by a, L -// MOV: [0, 1, |2, (3, 4), 5, 6, 7, 8] => [|0, {1, (3, 4), 2}, 5, 6, 7, 8] => [1, {3}, 4, 2,|0, 5, 6, 7, 8] -// MOV: [|0, (1, 2, 3), 4, 5, 6, 7, 8] => [(1,|2, 3), 0, {4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 3, n: 2, to: 2 }, Operation::Mov { pos: 1, n: 3, to: 0 }, &[1, 4, 2, 3, 0, 5, 6, 7 ,8])] -fn transform_mov_mov_split_ol_greater( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// MOV: [0, 1, (2, 3, 4), 5, |6, 7, 8] => [0, 1, 5, (2, 3, 4), 6, 7, 8] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [4, (0, 1, 2, 3), 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 3, to: 6 }, Operation::Mov { pos: 0, n: 4, to: 5 }, &[0, 1, 2, 3, 5, 4, 6, 7, 8])] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, 3, 4, 5, 6, 7, 8] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [2, 3, (0, 1), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[3, 2, 0, 1, 4, 5, 6, 7, 8])] -// MOV: [0, 1, (2, 3), 4, |5, 6, 7, 8] => [0, 1, 4, (2, 3), 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 5 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[1, 2, 0, 4, 3, 5, 6, 7, 8])] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [0, (2, 3), 1, 4, 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2), 0, 3, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[3, 1, 2, 0, 4, 5, 6, 7, 8])] -// same destination -// MOV: [0, (1, 2), 3, |4, 5, 6, 7, 8] => [{0}, 3,|(1, 2), 4, 5, 6, 7, 8] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [{2}, 3, (0, 1),|4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 4 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[3, 0, 1, 2, 4, 5, 6, 7, 8])] -// MOV: [0, (1, 2, 3), 4, |5, 6, 7, 8] => [{0}, 4,|(1, 2, 3), 5, 6, 7, 8] -// MOV: [(0, 1), 2, 3, 4, |5, 6, 7, 8] => [{2, 3}, 4, (0, 1),|5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 3, to: 5 }, Operation::Mov { pos: 0, n: 2, to: 5 }, &[4, 0, 1, 2, 3, 5, 6, 7, 8])] -// MOV: [|0, 1, (2, 3), 4, 5, 6, 7, 8] => [|(2, 3),0, {1}, 4, 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2),|0, {3}, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 0 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[1, 2, 3, 0, 4, 5, 6, 7, 8])] -// MOV: [|0, 1, (2, 3, 4), 5, 6, 7, 8] => [|(2, 3, 4), 0, {1}, 5, 6, 7, 8] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2),|0, {3, 4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 3, to: 0 }, Operation::Mov { pos: 1, n: 2, to: 0 }, &[1, 2, 3, 4, 0, 5, 6, 7, 8])] -// MOV: [0, |1, 2, (3, 4), 5, 6, 7, 8] => [0,|(3, 4), 1, {2}, 5, 6, 7, 8] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [0, (2, 3),|1, {4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 3, n: 2, to: 1 }, Operation::Mov { pos: 2, n: 2, to: 1 }, &[0, 2, 3, 4, 1, 5, 6, 7, 8])] -fn transform_mov_mov_ol_greater( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [|4, (0, 1, {2, 3}),*5, 6, 7, 8] => [|(2, 3), 4, 0, 1, {5}, 6, 7, 8] => [5, 2, 3, 4, 0, 1, 6, 7, 8] -// MOV: [0, 1, (2, 3, 4), 5, |6, 7, 8] => [{0, 1}, 5, (2, 3, 4),|6, 7, 8] => [5, 2, 3, 4, (0, 1), 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 4, to: 5 }, Operation::Mov { pos: 2, n: 3, to: 6 }, &[5, 2, 3, 4, 0, 1, 6, 7, 8])] -// MOV: [(0, 1, 2), 3, 4, 5, |6, 7, 8] => [{3},4, 5, (0, 1, {2}),*6,|7, 8] => [4, 5, 0, 1, 6, (2, 3), 7, 8] -// MOV: [0, 1, (2, 3), 4, 5, 6, |7, 8] => [{0, 1}, 4, 5,|6, (2, 3),*7, 8] => [4, 5, 0, 1, 6, 2, 3, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 6 }, Operation::Mov { pos: 2, n: 2, to: 7 }, &[4, 5, 0, 1, 6, 2, 3, 7, 8])] -// MOV: [(0, 1, 2), 3, 4, 5, |6, 7, 8] => [3, 4, 5, (0, 1, 2), 6, 7, 8] -// MOV: [0, (1, 2, 3), 4, |5, 6, 7, 8] => [{0}, 4, (1, 2, 3), 5,|6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 6 }, Operation::Mov { pos: 1, n: 3, to: 5 }, &[4, 1, 2, 3, 5, 0, 6, 7, 8])] -// MOV: [(0, 1, 2), 3, 4, 5, |6, 7, 8] => [3, 4, 5, (0, 1, 2), 6, 7, 8] -// MOV: [|0, (1, 2, 3, 4), 5, 6, 7, 8] => [(1, 2, 3, 4), 0, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 6 }, Operation::Mov { pos: 1, n: 4, to: 0 }, &[1, 2, 3, 4, 5, 0, 6, 7, 8])] -// same destination -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2),|0, {3, 4}, 5, 6, 7, 8] -// MOV: [|0, 1, (2, 3, 4), 5, 6, 7, 8] => [|(2, 3, 4), 0, {1}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 2, n: 3, to: 0 }, &[1, 2, 3, 4, 0, 5, 6, 7, 8])] -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1, 2),|0, {3}, 4, 5, 6, 7, 8] -// MOV: [|0, 1, (2, 3), 4, 5, 6, 7, 8] => [|(2, 3), 0, {1}, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 2, n: 2, to: 0 }, &[1, 2, 3, 0, 4, 5, 6, 7, 8])] -// MOV: [(0, 1, 2), 3, 4, 5, |6, 7, 8] => [3, 4, 5, (0, 1, 2), 6, 7, 8] -// MOV: [0, (1, 2, 3), 4, 5, |6, 7, 8] => [{0}, 4, 5, (1, 2, 3),|6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 6 }, Operation::Mov { pos: 1, n: 3, to: 6 }, &[4, 5, 0, 1, 2, 3, 6, 7, 8])] -fn transform_mov_mov_ol_less( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// info: 10 test items -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8, 9] => [{2, 3, (0, 1), 4}, 5,|6, 7, 8, 9] => [5,|2, 3, 0, {1}, 4, 6, 7, 8, 9] -// MOV: [0, (1, 2, 3, 4), 5, |6, 7, 8, 9] => [{0}, 5, (1, 2, 3,|4), 6, 7, 8, 9] => [5, 1, 2, 3, (0), 4, 6, 7, 8, 9] -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Mov { pos: 1, n: 4, to: 6 }, &[5, 1, 2, 3, 0, 4, 6, 7, 8, 9])] -fn transform_mov_mov_tmp( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// a_split_by_b, to right -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0,|1), {3, 4}, 5, 6, 7, 8] -// MOV: [0, |1, 2, (3, 4), 5, 6, 7, 8] => [{0, (3, 4), 1}, 2,|5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 3, n: 2, to: 1 }, &[2, 0, 3, 4, 1, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0,|1), {3, 4, 5}, 6, 7, 8] -// MOV: [0, |1, 2, (3, 4, 5), 6, 7, 8] => [{0, (3, 4, 5), 1}, 2,|6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 3, n: 3, to: 1 }, &[2, 0, 3, 4, 5, 1, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [{2, 3}, (0,|1), 4, 5, 6, 7, 8] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [{0, (2, 3), 1}, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Mov { pos: 2, n: 2, to: 1 }, &[0, 2, 3, 1, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [2, 3, (0,|1), {4, 5}, 6, 7, 8] end >= m2 -// MOV: [0, |1, 2, 3, (4, 5), 6, 7, 8] => [{0, (4, 5), 1}, 2, 3,|6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Mov { pos: 4, n: 2, to: 1 }, &[2, 3, 0, 4, 5, 1, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, 4, |5, 6, 7, 8] => [{2, 3}, 4, (0,|1), 5, 6, 7, 8] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [{0, (2, 3), 1}, 4,|5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 5 }, Operation::Mov { pos: 2, n: 2, to: 1 }, &[4, 0, 2, 3, 1, 5, 6, 7, 8])] -// a_split_by_b, to left -// MOV: [|0, (1, 2), 3, 4, 5, 6, 7, 8] => [(1,|2), 0, {3, 4}, 5, 6, 7, 8] -// MOV: [0, 1, |2, (3, 4), 5, 6, 7, 8] => [|0, {1, (3, 4), 2}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 1, n: 2, to: 0 }, Operation::Mov { pos: 3, n: 2, to: 2 }, &[1, 3, 4, 2, 0, 5, 6, 7, 8])] -// b_split_by_a, m2_to_right -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [{2, (0, 1), 3}, 4,|5, 6, 7, 8] -// MOV: [0, 1, (2, 3), 4, |5, 6, 7, 8] => [{0, 1}, 4, (2,|3), 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 2, n: 2, to: 5 }, &[4, 2, 0, 1, 3, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [2, {3, (0, 1), 4}, 5,|6, 7, 8] -// MOV: [0, 1, 2, (3, 4), 5, |6, 7, 8] => [{0, 1}, 2, 5, (3,|4), 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Mov { pos: 3, n: 2, to: 6 }, &[2, 5, 3, 0, 1, 4, 6, 7, 8])] -// b_split_by_a, m2_to_left -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0, 1), 3, 4, 5, 6, 7, 8] -// MOV: [|0, 1, (2, 3), 4, 5, 6, 7, 8] => [(2, 3), 0, 1, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 2, n: 2, to: 0 }, &[2, 0, 1, 3, 4, 5, 6, 7, 8])] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [|2, {3, (0, 1), 4}, 5, 6, 7, 8] -// MOV: [0, 1, |2, (3, 4), 5, 6, 7, 8] => [{0, 1}, (3,|4), 2, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 4 }, Operation::Mov { pos: 3, n: 2, to: 2 }, &[3, 0, 1, 4, 2, 5, 6, 7, 8])] -// both split -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [{2}, (0,|1), {3}, 4, 5, 6, 7, 8] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [0, (2, 3), 1, 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 0, n: 2, to: 3 }, Operation::Mov { pos: 2, n: 2, to: 1 }, &[0, 2, 3, 1, 4, 5, 6, 7, 8])] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [{4}, (0,|1, 2, 3), {5, 6, 7}, 8] -// MOV: [0, |1, 2, 3, (4, 5, 6, 7), 8] => [0, (4, 5, 6, 7), 1, 2, 3, 8] -#[case(Operation::Mov { pos: 0, n: 4, to: 5 }, Operation::Mov { pos: 4, n: 4, to: 1 }, &[0, 4, 5, 6, 7, 1, 2, 3, 8])] -// MOV: [(0, 1, 2), 3, 4, 5, |6, 7, 8] => [3, {4, 5}, (0,|1, 2), {6, 7}, 8] -// MOV: [0, |1, 2, 3, (4, 5, 6, 7), 8] => [|0, (4, 5, 6, 7), 1, 2, {3}, 8] -#[case(Operation::Mov { pos: 0, n: 3, to: 6 }, Operation::Mov { pos: 4, n: 4, to: 1 }, &[3, 0, 4, 5, 6, 7, 1, 2, 8])] -fn transform_mov_mov_split_less( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} - -#[rstest] -// a_split_by_b, to right -// MOV: [0, 1, 2, 3, (4, 5), 6, |7, 8] => [{0, 1, 2, 3}, 6, (4,|5), 7, 8] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [{4, (0, 1, 2, 3), 5}, 6,|7, 8] -#[case(Operation::Mov { pos: 4, n: 2, to: 7 }, Operation::Mov { pos: 0, n: 4, to: 5 }, &[6, 4, 0, 1, 2, 3, 5, 7, 8])] -// MOV: [0, 1, 2, 3, (4, 5), 6, |7, 8] => [{0, 1, 2}, 3, 6, (4,|5), 7, 8] -// MOV: [(0, 1, 2), 3, 4, |5, 6, 7, 8] => [3, {4, (0, 1, 2),*5}, 6,|7, 8] -#[case(Operation::Mov { pos: 4, n: 2, to: 7 }, Operation::Mov { pos: 0, n: 3, to: 5 }, &[3, 6, 4, 0, 1, 2, 5, 7, 8])] -// MOV: [0, 1, (2, 3, 4), 5, |6, 7, 8] => [{0}, 1, 5, (2,|3, 4), 6, 7, 8] -// MOV: [(0),1, 2,|3, 4, 5, 6, 7, 8] => [1, {2, (0),*3, 4}, 5,|6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 3, to: 6 }, Operation::Mov { pos: 0, n: 1, to: 3 }, &[1, 5, 2, 0, 3, 4, 6, 7, 8])] -// a_split_by_b, to left -// MOV: [0, 1, |2, (3, 4), 5, 6, 7, 8] => [{0, 1}, (3,|4), 2, 5, 6, 7, 8] m_to -m2_n -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [|2, {3, (0, 1), 4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 3, n: 2, to: 2 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[3, 0, 1, 4, 2, 5, 6, 7, 8])] -// MOV: [|0, 1, 2, 3, (4, 5, 6, 7), 8] => [(4,|5, 6, 7), {0, 1, 2, 3}, 8] -// MOV: [(0, 1, 2, 3), 4, |5, 6, 7, 8] => [{4, (0, 1, 2, 3), 5, 6, 7}, 8] -#[case(Operation::Mov { pos: 4, n: 4, to: 0 }, Operation::Mov { pos: 0, n: 4, to: 5 }, &[4, 0, 1, 2, 3, 5, 6, 7, 8])] -// MOV: [|0, 1, 2, (3, 4), 5, 6, 7, 8] => [(3,|4), {0, 1}, 2, 5, 6, 7, 8] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [|2, {3, (0, 1), 4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 3, n: 2, to: 0 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[3, 0, 1, 4, 2, 5, 6, 7, 8])] -// MOV: [0, 1, 2, |3, (4, 5), 6, 7, 8] => [{0, 1}, 2, (4,|5), 3, 6, 7, 8] -// MOV: [(0, 1), 2, 3, 4, |5, 6, 7, 8] => [2,|3, {4, (0, 1), 5}, 6, 7, 8] -#[case(Operation::Mov { pos: 4, n: 2, to: 3 }, Operation::Mov { pos: 0, n: 2, to: 5 }, &[2, 4, 0, 1, 5, 3, 6, 7, 8])] -// b_split_by_a, to right -// MOV: [0, |1, 2, (3, 4), 5, 6, 7, 8] => [{0, (3, 4), 1}, 2,|5, 6, 7, 8] -// MOV: [(0, 1), 2, |3, 4, 5, 6, 7, 8] => [2, (0,|1), {3, 4}, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 3, n: 2, to: 1 }, Operation::Mov { pos: 0, n: 2, to: 3 }, &[2, 0, 3, 4, 1, 5, 6, 7, 8])] -// MOV: [0, |1, (2, 3), 4, 5, 6, 7, 8] => [{0, (2, 3), 1}, 4, 5, 6, 7, 8] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [{2, 3}, (0,|1), 4, 5, 6, 7, 8] -#[case(Operation::Mov { pos: 2, n: 2, to: 1 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[0, 2, 3, 1, 4, 5, 6, 7, 8])] -// both split -// MOV: [0, |1, 2, (3, 4), 5, 6, 7, 8] => [{0}, (3,|4), {1}, 2, 5, 6, 7, 8] -// MOV: [(0, 1), 2, 3, |4, 5, 6, 7, 8] => [{2}, 3, (0, 1), 4,|5, 6, 7, 8] -#[case(Operation::Mov { pos: 3, n: 2, to: 1 }, Operation::Mov { pos: 0, n: 2, to: 4 }, &[3, 0, 1, 4, 2, 5, 6, 7, 8])] -fn transform_mov_mov_split_greater( - #[case] a: Operation, - #[case] b: Operation, - #[case] expect: &[i32], -) { - let input = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - test_transform(&a, &b, &input, expect); -} diff --git a/tests/util/mod.rs b/tests/util/mod.rs index 7cf85ae..60e8858 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -1,40 +1,29 @@ #![allow(dead_code)] -use std::{ - fmt::{Debug, Display}, - sync::atomic::AtomicUsize, -}; +use std::{fmt::Debug, sync::atomic::AtomicUsize}; use otvec::{transform, Operation}; -pub fn test_transform( +pub fn test_transform( a: &Operation, b: &Operation, input: &[T], expect: &[T], ) { - // Print operations - println!("A/B:"); - a.print_on(input); - b.print_on(input); - let (mut a2, mut b2) = (a.clone(), b.clone()); transform(&mut a2, &mut b2); dbg!(&a2, &b2); - check_op(&a2, a, b); - check_op(&b2, a, b); + 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, "OT condition unfulfilled"); - assert_eq!(data, expect, "a, b2"); - assert_eq!(data2, expect, "b, a2"); + + let mut data = input.to_vec(); + b.clone().apply(&mut data); + a2.apply(&mut data); + assert_eq!(data, expect, "b, a2"); } #[derive(Default)] @@ -43,20 +32,14 @@ pub struct CondCatchCtr { ok: AtomicUsize, } -pub fn test_transform_cond_catch< - T: PartialEq + Clone + Debug + Display + std::panic::RefUnwindSafe, ->( +pub fn test_transform_cond_catch( a: &Operation, b: &Operation, input: &[T], ctr: Option<&CondCatchCtr>, ) { - let do_count = !a.is_empty() && !b.is_empty(); - - if do_count { - if let Some(ctr) = ctr { - ctr.total.fetch_add(1, std::sync::atomic::Ordering::Relaxed); - } + if let Some(ctr) = ctr { + ctr.total.fetch_add(1, std::sync::atomic::Ordering::Relaxed); } let res = std::panic::catch_unwind(|| { @@ -66,8 +49,8 @@ pub fn test_transform_cond_catch< }); if let Ok((a2, b2)) = res { - // check_op(&a2, a, b); - // check_op(&b2, a, b); + check_op(&a2, a); + check_op(&b2, b); let mut data = input.to_vec(); a.clone().apply(&mut data); @@ -76,27 +59,10 @@ pub fn test_transform_cond_catch< let mut data2 = input.to_vec(); b.clone().apply(&mut data2); a2.apply(&mut data2); + assert_eq!(data, data2, "ops:\nA: {a:?}\nB: {b:?}"); - if data != data2 { - // Print operations - println!("A/B: Operation::{a:?}, Operation::{b:?}"); - a.print_on(input); - b.print_on(input); - - if let Some(ctr) = ctr { - let total = ctr.total.load(std::sync::atomic::Ordering::Relaxed); - let success = ctr.ok.load(std::sync::atomic::Ordering::Relaxed); - let perc = (success as f64 / total as f64) * 100.0; - println!("Cases passed: {success}/{total} ({perc:0.2}%)"); - } - - panic!("OT condition unfulfilled"); - } - - if do_count { - if let Some(ctr) = ctr { - ctr.ok.fetch_add(1, std::sync::atomic::Ordering::Relaxed); - } + if let Some(ctr) = ctr { + ctr.ok.fetch_add(1, std::sync::atomic::Ordering::Relaxed); } } } @@ -107,13 +73,11 @@ pub fn print_cond_catch_ctr(ctr: &CondCatchCtr) { let perc = (success as f64 / total as f64) * 100.0; if success < total { - panic!("❌ Cases passed: {success}/{total} ({perc:0.2}%)"); - } else { - println!("✅ Cases passed: {success}/{total} ({perc:0.2}%)"); + panic!("Cases passed: {success}/{total} ({perc:0.2}%)"); } } -pub fn test_transform_sym( +pub fn test_transform_sym( a: &Operation, b: &Operation, input: &[T], @@ -131,8 +95,8 @@ pub fn test_transform_cond( let (mut a2, mut b2) = (a.clone(), b.clone()); transform(&mut a2, &mut b2); // dbg!(&a2, &b2); - check_op(&a2, a, b); - check_op(&b2, a, b); + check_op(&a2, a); + check_op(&b2, b); let mut data = input.to_vec(); a.clone().apply(&mut data); @@ -144,16 +108,14 @@ pub fn test_transform_cond( assert_eq!(data, data2, "ops:\nA: {a:?}\nB: {b:?}"); } -fn check_op(op: &Operation, a: &Operation, b: &Operation) { +fn check_op(op: &Operation, a: &Operation) { match op { Operation::Nop => {} - Operation::Ins { val, .. } => { - assert!(val.len() > 0, "empty op: {op:?}\nfrom: {a:?}; {b:?}") - } - Operation::Del { n, .. } => assert!(*n > 0, "empty op: {op:?}\nfrom: {a:?}; {b:?}"), + Operation::Ins { val, .. } => assert!(val.len() > 0, "empty op: {op:?}\nfrom: {a:?}"), + Operation::Del { n, .. } => assert!(*n > 0, "empty op: {op:?}\nfrom: {a:?}"), Operation::Mov { pos, n, to } => { - assert!(pos != to && *n > 0, "empty op: {op:?}\nfrom: {a:?}; {b:?}") + assert!(pos != to && *n > 0, "empty op: {op:?}\nfrom: {a:?}") } - Operation::Seq { ops } => ops.iter().for_each(|op| check_op(op, a, b)), + Operation::Seq { ops } => ops.iter().for_each(|op| check_op(op, a)), } }