Find the length of common prefix and suffix between two sequences, applying the **suffix-limiting heuristic** used by the display path. This optimization significantly speeds up diffing when changes are localized to a small portion of the file. # Suffix Limiting The suffix is reduced if stripping it would leave one middle section empty while the other still has content. In that case, the diff a
(old: &[T], new: &[T])
| 469 | /// heuristic is helpful for displaying diffs to users but corrupts |
| 470 | /// patch-theory graph semantics. |
| 471 | fn common_affixes<T: PartialEq>(old: &[T], new: &[T]) -> (usize, usize) { |
| 472 | // Common prefix |
| 473 | let prefix_len = old |
| 474 | .iter() |
| 475 | .zip(new.iter()) |
| 476 | .take_while(|(a, b)| a == b) |
| 477 | .count(); |
| 478 | |
| 479 | // Common suffix (but don't overlap with prefix) |
| 480 | let remaining_old = old.len() - prefix_len; |
| 481 | let remaining_new = new.len() - prefix_len; |
| 482 | let max_suffix = remaining_old.min(remaining_new); |
| 483 | |
| 484 | let suffix_len = old[prefix_len..] |
| 485 | .iter() |
| 486 | .rev() |
| 487 | .zip(new[prefix_len..].iter().rev()) |
| 488 | .take(max_suffix) |
| 489 | .take_while(|(a, b)| a == b) |
| 490 | .count(); |
| 491 | |
| 492 | // Don't let the suffix strip make one middle section empty while the |
| 493 | // other still has content. That hides modifications as pure inserts |
| 494 | // or pure deletes — the diff algorithm needs both sides non-empty |
| 495 | // to detect Replace operations. |
| 496 | let old_mid = remaining_old - suffix_len; |
| 497 | let new_mid = remaining_new - suffix_len; |
| 498 | |
| 499 | if (old_mid == 0) != (new_mid == 0) { |
| 500 | // One side is empty, the other isn't. Reduce suffix until both |
| 501 | // sides have content (or suffix is zero). |
| 502 | let mut reduced = suffix_len; |
| 503 | while reduced > 0 { |
| 504 | reduced -= 1; |
| 505 | let om = remaining_old - reduced; |
| 506 | let nm = remaining_new - reduced; |
| 507 | if (om > 0 && nm > 0) || reduced == 0 { |
| 508 | return (prefix_len, reduced); |
| 509 | } |
| 510 | } |
| 511 | return (prefix_len, 0); |
| 512 | } |
| 513 | |
| 514 | (prefix_len, suffix_len) |
| 515 | } |
| 516 | |
| 517 | /// Diff two byte slices as text, splitting on newlines. |
| 518 | /// |