From 6ade73138cad3fc2a158205241708773da4732fc Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 15 Jun 2022 01:07:25 +0100 Subject: [PATCH] Skip printed lines when computing hunk matched lines This function is hot for textual diffs, such as the sample files in issue #293. For those files, this produces a 21% reduction in instruction count. --- src/display/hunks.rs | 16 ++++++++++++---- src/display/side_by_side.rs | 13 +++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/display/hunks.rs b/src/display/hunks.rs index 1e5d1e578a..6312035754 100644 --- a/src/display/hunks.rs +++ b/src/display/hunks.rs @@ -595,10 +595,10 @@ fn either_side_equal( false } -pub fn matched_lines_for_hunk<'a>( - matched_lines: &'a [(Option, Option)], +pub fn matched_lines_indexes_for_hunk( + matched_lines: &[(Option, Option)], hunk: &Hunk, -) -> &'a [(Option, Option)] { +) -> (usize, usize) { let mut hunk_lhs_novel = hunk.novel_lhs.iter().copied().collect::>(); hunk_lhs_novel.sort(); @@ -645,7 +645,7 @@ pub fn matched_lines_for_hunk<'a>( end_i = matched_lines.len(); } - &matched_lines[start_i..end_i] + (start_i, end_i) } #[cfg(test)] @@ -758,6 +758,14 @@ mod tests { assert_eq!(hunks[0].lines, vec![(Some(0.into()), Some(0.into()))]); } + fn matched_lines_for_hunk<'a>( + matched_lines: &'a [(Option, Option)], + hunk: &Hunk, + ) -> &'a [(Option, Option)] { + let (start_i, end_i) = matched_lines_indexes_for_hunk(matched_lines, hunk); + &matched_lines[start_i..end_i] + } + #[test] fn test_matched_lines_for_hunk() { let matched_lines = &[ diff --git a/src/display/side_by_side.rs b/src/display/side_by_side.rs index eac5c212bd..0368f517a7 100644 --- a/src/display/side_by_side.rs +++ b/src/display/side_by_side.rs @@ -7,7 +7,7 @@ use std::{cmp::max, collections::HashSet}; use crate::{ constants::Side, display::context::all_matched_lines_filled, - display::hunks::{matched_lines_for_hunk, Hunk}, + display::hunks::{matched_lines_indexes_for_hunk, Hunk}, display::style::{ self, apply_colors, color_positions, novel_style, split_and_apply, BackgroundColor, }, @@ -385,6 +385,7 @@ pub fn print( let mut prev_rhs_line_num = None; let matched_lines = all_matched_lines_filled(lhs_mps, rhs_mps, &lhs_lines, &rhs_lines); + let mut matched_lines_to_print = &matched_lines[..]; for (i, hunk) in hunks.iter().enumerate() { println!( @@ -399,7 +400,15 @@ pub fn print( ) ); - let aligned_lines = matched_lines_for_hunk(&matched_lines, hunk); + let (start_i, end_i) = matched_lines_indexes_for_hunk(matched_lines_to_print, hunk); + let aligned_lines = &matched_lines_to_print[start_i..end_i]; + // We iterate through hunks in order, so we know the next hunk + // must appear after start_i. This makes + // `matched_lines_indexes_for_hunk` faster on later + // iterations, and this function is hot on large textual + // diffs. + matched_lines_to_print = &matched_lines_to_print[start_i..]; + let no_lhs_changes = hunk.novel_lhs.is_empty(); let no_rhs_changes = hunk.novel_rhs.is_empty(); let same_lines = aligned_lines.iter().all(|(l, r)| l == r);