Don't unwrap to MAX number
This commit is contained in:
parent
b0ad819ac6
commit
c9c2b775a8
2 changed files with 42 additions and 39 deletions
|
|
@ -168,13 +168,14 @@ where
|
||||||
let result = operation.merge_operations(&mut last_other_op);
|
let result = operation.merge_operations(&mut last_other_op);
|
||||||
|
|
||||||
if let ref op @ (Operation::Insert { .. } | Operation::Equal { .. }) = result {
|
if let ref op @ (Operation::Insert { .. } | Operation::Equal { .. }) = result {
|
||||||
let merged_length_signed =
|
let merged_length_signed = isize::try_from(merged_length)
|
||||||
isize::try_from(merged_length).unwrap_or(isize::MAX);
|
.expect("merged_length must fit in isize");
|
||||||
let seen_left_length_signed =
|
let seen_left_length_signed = isize::try_from(seen_left_length)
|
||||||
isize::try_from(seen_left_length).unwrap_or(isize::MAX);
|
.expect("seen_left_length must fit in isize");
|
||||||
let op_len_signed = isize::try_from(op.len()).unwrap_or(isize::MAX);
|
let op_len_signed =
|
||||||
let original_length_signed =
|
isize::try_from(op.len()).expect("op.len() must fit in isize");
|
||||||
isize::try_from(original_length).unwrap_or(isize::MAX);
|
let original_length_signed = isize::try_from(original_length)
|
||||||
|
.expect("original_length must fit in isize");
|
||||||
|
|
||||||
let shift = merged_length_signed - seen_left_length_signed + op_len_signed
|
let shift = merged_length_signed - seen_left_length_signed + op_len_signed
|
||||||
- original_length_signed;
|
- original_length_signed;
|
||||||
|
|
@ -201,13 +202,14 @@ where
|
||||||
let result = operation.merge_operations(&mut last_other_op);
|
let result = operation.merge_operations(&mut last_other_op);
|
||||||
|
|
||||||
if let ref op @ (Operation::Insert { .. } | Operation::Equal { .. }) = result {
|
if let ref op @ (Operation::Insert { .. } | Operation::Equal { .. }) = result {
|
||||||
let merged_length_signed =
|
let merged_length_signed = isize::try_from(merged_length)
|
||||||
isize::try_from(merged_length).unwrap_or(isize::MAX);
|
.expect("merged_length must fit in isize");
|
||||||
let seen_right_length_signed =
|
let seen_right_length_signed = isize::try_from(seen_right_length)
|
||||||
isize::try_from(seen_right_length).unwrap_or(isize::MAX);
|
.expect("seen_right_length must fit in isize");
|
||||||
let op_len_signed = isize::try_from(op.len()).unwrap_or(isize::MAX);
|
let op_len_signed =
|
||||||
let original_length_signed =
|
isize::try_from(op.len()).expect("op.len() must fit in isize");
|
||||||
isize::try_from(original_length).unwrap_or(isize::MAX);
|
let original_length_signed = isize::try_from(original_length)
|
||||||
|
.expect("original_length must fit in isize");
|
||||||
|
|
||||||
let shift = merged_length_signed - seen_right_length_signed + op_len_signed
|
let shift = merged_length_signed - seen_right_length_signed + op_len_signed
|
||||||
- original_length_signed;
|
- original_length_signed;
|
||||||
|
|
@ -355,7 +357,7 @@ where
|
||||||
/// Inserts are represented as strings, deletes as negative integers,
|
/// Inserts are represented as strings, deletes as negative integers,
|
||||||
/// and equal spans as positive integers.
|
/// and equal spans as positive integers.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_changes(&self) -> Vec<NumberOrString> {
|
pub fn to_diff(&self) -> Vec<NumberOrString> {
|
||||||
let mut result: Vec<NumberOrString> = Vec::with_capacity(self.operations.len());
|
let mut result: Vec<NumberOrString> = Vec::with_capacity(self.operations.len());
|
||||||
let mut previous_equal: Option<usize> = None;
|
let mut previous_equal: Option<usize> = None;
|
||||||
|
|
||||||
|
|
@ -372,7 +374,7 @@ where
|
||||||
Operation::Insert { text, .. } => {
|
Operation::Insert { text, .. } => {
|
||||||
if let Some(prev_length) = previous_equal {
|
if let Some(prev_length) = previous_equal {
|
||||||
result.push(NumberOrString::Number(
|
result.push(NumberOrString::Number(
|
||||||
i64::try_from(prev_length).unwrap_or(i64::MAX),
|
i64::try_from(prev_length).expect("prev_length must fit in i64"),
|
||||||
));
|
));
|
||||||
previous_equal = None;
|
previous_equal = None;
|
||||||
}
|
}
|
||||||
|
|
@ -390,12 +392,13 @@ where
|
||||||
} => {
|
} => {
|
||||||
if let Some(prev_length) = previous_equal {
|
if let Some(prev_length) = previous_equal {
|
||||||
result.push(NumberOrString::Number(
|
result.push(NumberOrString::Number(
|
||||||
i64::try_from(prev_length).unwrap_or(i64::MAX),
|
i64::try_from(prev_length).expect("prev_length must fit in i64"),
|
||||||
));
|
));
|
||||||
previous_equal = None;
|
previous_equal = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = i64::try_from(*deleted_character_count).unwrap_or(i64::MAX);
|
let count = i64::try_from(*deleted_character_count)
|
||||||
|
.expect("deleted_character_count must fit in i64");
|
||||||
result.push(NumberOrString::Number(-count));
|
result.push(NumberOrString::Number(-count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +406,7 @@ where
|
||||||
|
|
||||||
if let Some(prev_length) = previous_equal {
|
if let Some(prev_length) = previous_equal {
|
||||||
result.push(NumberOrString::Number(
|
result.push(NumberOrString::Number(
|
||||||
i64::try_from(prev_length).unwrap_or(i64::MAX),
|
i64::try_from(prev_length).expect("prev_length must fit in i64"),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,19 +415,19 @@ where
|
||||||
|
|
||||||
/// Deserialize an `EditedText` from a change list and the original text.
|
/// Deserialize an `EditedText` from a change list and the original text.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_changes(
|
pub fn from_diff(
|
||||||
original_text: &'a str,
|
original_text: &'a str,
|
||||||
simple_operations: Vec<NumberOrString>,
|
diff: Vec<NumberOrString>,
|
||||||
tokenizer: &Tokenizer<T>,
|
tokenizer: &Tokenizer<T>,
|
||||||
) -> EditedText<'a, T> {
|
) -> EditedText<'a, T> {
|
||||||
let mut operations: Vec<Operation<T>> = Vec::with_capacity(simple_operations.len());
|
let mut operations: Vec<Operation<T>> = Vec::with_capacity(diff.len());
|
||||||
let mut order = 0;
|
let mut order = 0;
|
||||||
|
|
||||||
for simple_operation in simple_operations {
|
for item in diff {
|
||||||
match simple_operation {
|
match item {
|
||||||
NumberOrString::Number(length) => {
|
NumberOrString::Number(length) => {
|
||||||
if length >= 0 {
|
if length >= 0 {
|
||||||
let length = usize::try_from(length).unwrap_or(usize::MAX);
|
let length = usize::try_from(length).expect("length must fit in usize");
|
||||||
let original_characters: String =
|
let original_characters: String =
|
||||||
original_text.chars().skip(order).take(length).collect();
|
original_text.chars().skip(order).take(length).collect();
|
||||||
|
|
||||||
|
|
@ -435,7 +438,8 @@ where
|
||||||
order += token.get_original_length();
|
order += token.get_original_length();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let length = usize::try_from(-length).unwrap_or(usize::MAX);
|
let length =
|
||||||
|
usize::try_from(-length).expect("negative length must fit in usize");
|
||||||
operations.push(Operation::create_delete(order, length));
|
operations.push(Operation::create_delete(order, length));
|
||||||
order += length;
|
order += length;
|
||||||
}
|
}
|
||||||
|
|
@ -509,7 +513,7 @@ mod tests {
|
||||||
let original = "Merging text is hard!";
|
let original = "Merging text is hard!";
|
||||||
let changes = "Merging text is easy with reconcile!";
|
let changes = "Merging text is easy with reconcile!";
|
||||||
let result = EditedText::from_strings(original, &changes.into());
|
let result = EditedText::from_strings(original, &changes.into());
|
||||||
let serialized = serde_yaml::to_string(&result.to_changes()).unwrap();
|
let serialized = serde_yaml::to_string(&result.to_diff()).unwrap();
|
||||||
|
|
||||||
let expected = concat!("- 15\n", "- -6\n", "- ' easy with reconcile!'\n",);
|
let expected = concat!("- 15\n", "- -6\n", "- ' easy with reconcile!'\n",);
|
||||||
assert_eq!(serialized, expected);
|
assert_eq!(serialized, expected);
|
||||||
|
|
@ -523,9 +527,9 @@ mod tests {
|
||||||
|
|
||||||
let edited_text = EditedText::from_strings(original, &updated.into());
|
let edited_text = EditedText::from_strings(original, &updated.into());
|
||||||
|
|
||||||
let changes = edited_text.to_changes();
|
let changes = edited_text.to_diff();
|
||||||
let deserialized_edited_text =
|
let deserialized_edited_text =
|
||||||
EditedText::from_changes(original, changes, &*BuiltinTokenizer::Word);
|
EditedText::from_diff(original, changes, &*BuiltinTokenizer::Word);
|
||||||
|
|
||||||
assert_eq!(deserialized_edited_text.apply().text(), updated);
|
assert_eq!(deserialized_edited_text.apply().text(), updated);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ struct V {
|
||||||
impl V {
|
impl V {
|
||||||
fn new(max_d: usize) -> Self {
|
fn new(max_d: usize) -> Self {
|
||||||
// max_d should fit in isize for the algorithm to work correctly
|
// max_d should fit in isize for the algorithm to work correctly
|
||||||
let offset = isize::try_from(max_d).unwrap_or(isize::MAX);
|
let offset = isize::try_from(max_d).expect("max_d must fit in isize");
|
||||||
Self {
|
Self {
|
||||||
offset,
|
offset,
|
||||||
v: vec![0; 2 * max_d],
|
v: vec![0; 2 * max_d],
|
||||||
|
|
@ -101,16 +101,15 @@ impl Index<isize> for V {
|
||||||
type Output = usize;
|
type Output = usize;
|
||||||
|
|
||||||
fn index(&self, index: isize) -> &Self::Output {
|
fn index(&self, index: isize) -> &Self::Output {
|
||||||
let idx = usize::try_from(index + self.offset).unwrap_or(usize::MAX);
|
let idx = usize::try_from(index + self.offset).expect("index + offset must fit in usize");
|
||||||
&self.v[idx.min(self.v.len().saturating_sub(1))]
|
&self.v[idx]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<isize> for V {
|
impl IndexMut<isize> for V {
|
||||||
fn index_mut(&mut self, index: isize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: isize) -> &mut Self::Output {
|
||||||
let idx = usize::try_from(index + self.offset).unwrap_or(usize::MAX);
|
let idx = usize::try_from(index + self.offset).expect("index + offset must fit in usize");
|
||||||
let len = self.v.len();
|
&mut self.v[idx]
|
||||||
&mut self.v[idx.min(len.saturating_sub(1))]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,7 +144,7 @@ where
|
||||||
|
|
||||||
// By Lemma 1 in the paper, the optimal edit script length is odd or even as
|
// By Lemma 1 in the paper, the optimal edit script length is odd or even as
|
||||||
// `delta` is odd or even.
|
// `delta` is odd or even.
|
||||||
let delta = isize::try_from(n).unwrap_or(isize::MAX) - isize::try_from(m).unwrap_or(isize::MAX);
|
let delta = isize::try_from(n).expect("n must fit in isize") - isize::try_from(m).expect("m must fit in isize");
|
||||||
let odd = delta & 1 == 1;
|
let odd = delta & 1 == 1;
|
||||||
|
|
||||||
// The initial point at (0, -1)
|
// The initial point at (0, -1)
|
||||||
|
|
@ -157,7 +156,7 @@ where
|
||||||
assert!(vf.len() >= d_max);
|
assert!(vf.len() >= d_max);
|
||||||
assert!(vb.len() >= d_max);
|
assert!(vb.len() >= d_max);
|
||||||
|
|
||||||
let d_max_isize = isize::try_from(d_max).unwrap_or(isize::MAX);
|
let d_max_isize = isize::try_from(d_max).expect("d_max must fit in isize");
|
||||||
for d in 0..d_max_isize {
|
for d in 0..d_max_isize {
|
||||||
// Forward path
|
// Forward path
|
||||||
for k in (-d..=d).rev().step_by(2) {
|
for k in (-d..=d).rev().step_by(2) {
|
||||||
|
|
@ -166,7 +165,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
vf[k - 1] + 1
|
vf[k - 1] + 1
|
||||||
};
|
};
|
||||||
let y = usize::try_from(isize::try_from(x).unwrap_or(isize::MAX) - k).unwrap_or(0);
|
let y = usize::try_from(isize::try_from(x).expect("x must fit in isize") - k).expect("x - k must be non-negative and fit in usize");
|
||||||
|
|
||||||
// The coordinate of the start of a snake
|
// The coordinate of the start of a snake
|
||||||
let (x0, y0) = (x, y);
|
let (x0, y0) = (x, y);
|
||||||
|
|
@ -204,7 +203,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
vb[k - 1] + 1
|
vb[k - 1] + 1
|
||||||
};
|
};
|
||||||
let mut y = usize::try_from(isize::try_from(x).unwrap_or(isize::MAX) - k).unwrap_or(0);
|
let mut y = usize::try_from(isize::try_from(x).expect("x must fit in isize") - k).expect("x - k must be non-negative and fit in usize");
|
||||||
|
|
||||||
// The coordinate of the start of a snake
|
// The coordinate of the start of a snake
|
||||||
if x < n && y < m {
|
if x < n && y < m {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue