Implement applying transactions to mark sets.
This commit is contained in:
parent
fa55afeebe
commit
9087019542
|
@ -128,6 +128,10 @@ impl MarkSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.marks.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.main_mark_idx = 0;
|
self.main_mark_idx = 0;
|
||||||
self.marks.clear();
|
self.marks.clear();
|
||||||
|
|
|
@ -359,8 +359,52 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the Transaction to a set of Marks.
|
/// Applies the Transaction to a set of Marks.
|
||||||
pub fn apply_to_marks(&self, _marks: &mut MarkSet) {
|
pub fn apply_to_marks(&self, marks: &mut MarkSet) {
|
||||||
todo!()
|
marks.make_consistent();
|
||||||
|
|
||||||
|
// We do this in two passes: first heads, then tails.
|
||||||
|
for tail in 0..=1 {
|
||||||
|
let mut mark_idx = 0;
|
||||||
|
let mut byte_idx_old = 0;
|
||||||
|
let mut byte_idx_new = 0;
|
||||||
|
for op in self.ops.iter() {
|
||||||
|
let old_len = op.len_pre();
|
||||||
|
let new_len = op.len_post();
|
||||||
|
|
||||||
|
while mark_idx < marks.len() {
|
||||||
|
let idx = if tail == 1 {
|
||||||
|
&mut marks[mark_idx].tail
|
||||||
|
} else {
|
||||||
|
&mut marks[mark_idx].head
|
||||||
|
};
|
||||||
|
|
||||||
|
if *idx < byte_idx_old {
|
||||||
|
mark_idx += 1;
|
||||||
|
} else if *idx < (byte_idx_old + old_len) {
|
||||||
|
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||||
|
*idx = (*idx).min(byte_idx_new + new_len);
|
||||||
|
mark_idx += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_idx_old += old_len;
|
||||||
|
byte_idx_new += new_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
while mark_idx < marks.len() {
|
||||||
|
let idx = if tail == 1 {
|
||||||
|
&mut marks[mark_idx].tail
|
||||||
|
} else {
|
||||||
|
&mut marks[mark_idx].head
|
||||||
|
};
|
||||||
|
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||||
|
mark_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
marks.make_consistent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the inverse of the Transaction to a set of Marks.
|
/// Applies the inverse of the Transaction to a set of Marks.
|
||||||
|
@ -368,8 +412,52 @@ impl Transaction {
|
||||||
/// This is essentially an "undo" of the Transaction. However, on
|
/// This is essentially an "undo" of the Transaction. However, on
|
||||||
/// marks this is a lossy operation and is not guaranteed to return
|
/// marks this is a lossy operation and is not guaranteed to return
|
||||||
/// the marks to their original count and position.
|
/// the marks to their original count and position.
|
||||||
pub fn apply_inverse_to_marks(&self, _marks: &mut MarkSet) {
|
pub fn apply_inverse_to_marks(&self, marks: &mut MarkSet) {
|
||||||
todo!()
|
marks.make_consistent();
|
||||||
|
|
||||||
|
// We do this in two passes: first heads, then tails.
|
||||||
|
for tail in 0..=1 {
|
||||||
|
let mut mark_idx = 0;
|
||||||
|
let mut byte_idx_old = 0;
|
||||||
|
let mut byte_idx_new = 0;
|
||||||
|
for op in self.ops.iter() {
|
||||||
|
let old_len = op.len_post();
|
||||||
|
let new_len = op.len_pre();
|
||||||
|
|
||||||
|
while mark_idx < marks.len() {
|
||||||
|
let idx = if tail == 1 {
|
||||||
|
&mut marks[mark_idx].tail
|
||||||
|
} else {
|
||||||
|
&mut marks[mark_idx].head
|
||||||
|
};
|
||||||
|
|
||||||
|
if *idx < byte_idx_old {
|
||||||
|
mark_idx += 1;
|
||||||
|
} else if *idx < (byte_idx_old + old_len) {
|
||||||
|
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||||
|
*idx = (*idx).min(byte_idx_new + new_len);
|
||||||
|
mark_idx += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_idx_old += old_len;
|
||||||
|
byte_idx_new += new_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
while mark_idx < marks.len() {
|
||||||
|
let idx = if tail == 1 {
|
||||||
|
&mut marks[mark_idx].tail
|
||||||
|
} else {
|
||||||
|
&mut marks[mark_idx].head
|
||||||
|
};
|
||||||
|
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||||
|
mark_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
marks.make_consistent();
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
|
@ -455,3 +543,143 @@ impl std::fmt::Debug for Transaction {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::marks::{Mark, MarkSet};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_to_marks_01() {
|
||||||
|
let trans = Transaction::from_edit(5, "", "hi");
|
||||||
|
|
||||||
|
let mut mark_set = MarkSet::new();
|
||||||
|
mark_set.add_mark(Mark::new(4, 4));
|
||||||
|
mark_set.add_mark(Mark::new(5, 5));
|
||||||
|
mark_set.add_mark(Mark::new(6, 6));
|
||||||
|
|
||||||
|
trans.apply_to_marks(&mut mark_set);
|
||||||
|
assert_eq!(mark_set.marks[0].head, 4);
|
||||||
|
assert_eq!(mark_set.marks[0].tail, 4);
|
||||||
|
assert_eq!(mark_set.marks[1].head, 7);
|
||||||
|
assert_eq!(mark_set.marks[1].tail, 7);
|
||||||
|
assert_eq!(mark_set.marks[2].head, 8);
|
||||||
|
assert_eq!(mark_set.marks[2].tail, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_to_marks_02() {
|
||||||
|
let trans = Transaction {
|
||||||
|
ops: vec![
|
||||||
|
Op::Retain(5),
|
||||||
|
Op::Replace {
|
||||||
|
old: (0, 0),
|
||||||
|
new: (0, 1),
|
||||||
|
},
|
||||||
|
Op::Replace {
|
||||||
|
old: (0, 0),
|
||||||
|
new: (1, 2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
buffer: "hi".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut mark_set = MarkSet::new();
|
||||||
|
mark_set.add_mark(Mark::new(4, 4));
|
||||||
|
mark_set.add_mark(Mark::new(5, 5));
|
||||||
|
mark_set.add_mark(Mark::new(6, 6));
|
||||||
|
|
||||||
|
trans.apply_to_marks(&mut mark_set);
|
||||||
|
assert_eq!(mark_set.marks[0].head, 4);
|
||||||
|
assert_eq!(mark_set.marks[0].tail, 4);
|
||||||
|
assert_eq!(mark_set.marks[1].head, 7);
|
||||||
|
assert_eq!(mark_set.marks[1].tail, 7);
|
||||||
|
assert_eq!(mark_set.marks[2].head, 8);
|
||||||
|
assert_eq!(mark_set.marks[2].tail, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_to_marks_03() {
|
||||||
|
let trans = Transaction::from_edit(5, "hi", "");
|
||||||
|
|
||||||
|
let mut mark_set = MarkSet::new();
|
||||||
|
mark_set.add_mark(Mark::new(4, 4));
|
||||||
|
mark_set.add_mark(Mark::new(6, 6));
|
||||||
|
mark_set.add_mark(Mark::new(8, 8));
|
||||||
|
|
||||||
|
trans.apply_to_marks(&mut mark_set);
|
||||||
|
assert_eq!(mark_set.marks[0].head, 4);
|
||||||
|
assert_eq!(mark_set.marks[0].tail, 4);
|
||||||
|
assert_eq!(mark_set.marks[1].head, 5);
|
||||||
|
assert_eq!(mark_set.marks[1].tail, 5);
|
||||||
|
assert_eq!(mark_set.marks[2].head, 6);
|
||||||
|
assert_eq!(mark_set.marks[2].tail, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_to_marks_04() {
|
||||||
|
let trans = Transaction {
|
||||||
|
ops: vec![
|
||||||
|
Op::Retain(5),
|
||||||
|
Op::Replace {
|
||||||
|
old: (0, 1),
|
||||||
|
new: (0, 0),
|
||||||
|
},
|
||||||
|
Op::Replace {
|
||||||
|
old: (1, 2),
|
||||||
|
new: (0, 0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
buffer: "hi".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut mark_set = MarkSet::new();
|
||||||
|
mark_set.add_mark(Mark::new(4, 4));
|
||||||
|
mark_set.add_mark(Mark::new(6, 6));
|
||||||
|
mark_set.add_mark(Mark::new(8, 8));
|
||||||
|
|
||||||
|
trans.apply_to_marks(&mut mark_set);
|
||||||
|
assert_eq!(mark_set.marks[0].head, 4);
|
||||||
|
assert_eq!(mark_set.marks[0].tail, 4);
|
||||||
|
assert_eq!(mark_set.marks[1].head, 5);
|
||||||
|
assert_eq!(mark_set.marks[1].tail, 5);
|
||||||
|
assert_eq!(mark_set.marks[2].head, 6);
|
||||||
|
assert_eq!(mark_set.marks[2].tail, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_inverse_to_marks_01() {
|
||||||
|
let trans = Transaction::from_edit(5, "hi", "");
|
||||||
|
|
||||||
|
let mut mark_set = MarkSet::new();
|
||||||
|
mark_set.add_mark(Mark::new(4, 4));
|
||||||
|
mark_set.add_mark(Mark::new(5, 5));
|
||||||
|
mark_set.add_mark(Mark::new(6, 6));
|
||||||
|
|
||||||
|
trans.apply_inverse_to_marks(&mut mark_set);
|
||||||
|
assert_eq!(mark_set.marks[0].head, 4);
|
||||||
|
assert_eq!(mark_set.marks[0].tail, 4);
|
||||||
|
assert_eq!(mark_set.marks[1].head, 7);
|
||||||
|
assert_eq!(mark_set.marks[1].tail, 7);
|
||||||
|
assert_eq!(mark_set.marks[2].head, 8);
|
||||||
|
assert_eq!(mark_set.marks[2].tail, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_inverse_to_marks_02() {
|
||||||
|
let trans = Transaction::from_edit(5, "", "hi");
|
||||||
|
|
||||||
|
let mut mark_set = MarkSet::new();
|
||||||
|
mark_set.add_mark(Mark::new(4, 4));
|
||||||
|
mark_set.add_mark(Mark::new(6, 6));
|
||||||
|
mark_set.add_mark(Mark::new(8, 8));
|
||||||
|
|
||||||
|
trans.apply_inverse_to_marks(&mut mark_set);
|
||||||
|
assert_eq!(mark_set.marks[0].head, 4);
|
||||||
|
assert_eq!(mark_set.marks[0].tail, 4);
|
||||||
|
assert_eq!(mark_set.marks[1].head, 5);
|
||||||
|
assert_eq!(mark_set.marks[1].tail, 5);
|
||||||
|
assert_eq!(mark_set.marks[2].head, 6);
|
||||||
|
assert_eq!(mark_set.marks[2].tail, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user