From cff6a230a34c9873f424b4c6d3b3dafd875aa6f6 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 27 Feb 2024 21:18:42 -0700 Subject: [PATCH] Remove alternate diff algorithms, only keep Patience --- Cargo.lock | 42 ++--- objdiff-cli/src/cmd/report.rs | 14 +- objdiff-core/Cargo.toml | 3 +- objdiff-core/src/diff/code.rs | 124 +------------ objdiff-core/src/diff/data.rs | 303 +------------------------------ objdiff-core/src/diff/editops.rs | 162 ----------------- objdiff-core/src/diff/mod.rs | 15 +- objdiff-gui/src/app.rs | 6 - objdiff-gui/src/jobs/objdiff.rs | 10 +- objdiff-gui/src/views/config.rs | 60 +----- 10 files changed, 42 insertions(+), 697 deletions(-) delete mode 100644 objdiff-core/src/diff/editops.rs diff --git a/Cargo.lock b/Cargo.lock index 274d7d8..086649b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,9 +110,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" dependencies = [ "cfg-if", "getrandom", @@ -1576,9 +1576,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a147e1a6641a55d994b3e4e9fa4d9b180c8d652c09b363af8c9bf1b8e04139" +checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" [[package]] name = "event-listener" @@ -2101,7 +2101,7 @@ dependencies = [ "presser", "thiserror", "winapi", - "windows 0.51.1", + "windows 0.52.0", ] [[package]] @@ -3004,7 +3004,6 @@ dependencies = [ "serde_json", "serde_yaml", "similar", - "twox-hash", ] [[package]] @@ -3456,9 +3455,9 @@ checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -4180,9 +4179,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand 2.0.1", @@ -4507,17 +4506,6 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "rand", - "static_assertions", -] - [[package]] name = "type-map" version = "0.5.0" @@ -5056,21 +5044,21 @@ dependencies = [ [[package]] name = "windows" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets 0.48.5", + "windows-targets 0.52.3", ] [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.3", ] [[package]] diff --git a/objdiff-cli/src/cmd/report.rs b/objdiff-cli/src/cmd/report.rs index b3bbcd3..c0d7f2f 100644 --- a/objdiff-cli/src/cmd/report.rs +++ b/objdiff-cli/src/cmd/report.rs @@ -108,7 +108,7 @@ pub fn run(args: Args) -> Result<()> { ) }) .collect::>>>()?; - report.units = units.into_iter().flatten().collect::>(); + report.units = units.into_iter().flatten().collect(); } for unit in &report.units { report.fuzzy_match_percent += unit.match_percent * unit.total_size as f32; @@ -198,10 +198,14 @@ fn report_object( continue; } } - let match_percent = symbol.match_percent.unwrap_or(if object.complete == Some(true) { - 100.0 - } else { - 0.0 + let match_percent = symbol.match_percent.unwrap_or_else(|| { + // Support cases where we don't have a target object, + // assume complete means 100% match + if object.complete == Some(true) { + 100.0 + } else { + 0.0 + } }); unit.match_percent += match_percent * symbol.size as f32; unit.total_size += symbol.size; diff --git a/objdiff-core/Cargo.toml b/objdiff-core/Cargo.toml index 4d03021..81c91f6 100644 --- a/objdiff-core/Cargo.toml +++ b/objdiff-core/Cargo.toml @@ -33,8 +33,7 @@ object = { version = "0.32.2", features = ["read_core", "std", "elf"], default-f ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618", optional = true } rabbitizer = { version = "1.8.1", optional = true } serde = { version = "1", features = ["derive"] } -similar = "2.4.0" -twox-hash = "1.6.3" +similar = { version = "2.4.0", default-features = false } # config globset = { version = "0.4.14", features = ["serde1"] } diff --git a/objdiff-core/src/diff/code.rs b/objdiff-core/src/diff/code.rs index c96f117..e79e9b4 100644 --- a/objdiff-core/src/diff/code.rs +++ b/objdiff-core/src/diff/code.rs @@ -8,10 +8,7 @@ use anyhow::Result; use similar::{capture_diff_slices_deadline, Algorithm}; use crate::{ - diff::{ - editops::{editops_find, LevEditType}, - DiffAlg, DiffObjConfig, ProcessCodeResult, - }, + diff::{DiffObjConfig, ProcessCodeResult}, obj, obj::{ ObjArchitecture, ObjInfo, ObjInsArg, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, @@ -101,45 +98,7 @@ pub fn diff_code( let mut left_diff = Vec::::new(); let mut right_diff = Vec::::new(); - match config.code_alg { - DiffAlg::Levenshtein => { - diff_instructions_lev( - &mut left_diff, - &mut right_diff, - left_symbol, - right_symbol, - &left_out, - &right_out, - )?; - } - DiffAlg::Lcs => { - diff_instructions_similar( - Algorithm::Lcs, - &mut left_diff, - &mut right_diff, - &left_out, - &right_out, - )?; - } - DiffAlg::Myers => { - diff_instructions_similar( - Algorithm::Myers, - &mut left_diff, - &mut right_diff, - &left_out, - &right_out, - )?; - } - DiffAlg::Patience => { - diff_instructions_similar( - Algorithm::Patience, - &mut left_diff, - &mut right_diff, - &left_out, - &right_out, - )?; - } - } + diff_instructions(&mut left_diff, &mut right_diff, &left_out, &right_out)?; resolve_branches(&mut left_diff); resolve_branches(&mut right_diff); @@ -168,15 +127,19 @@ pub fn diff_code( Ok(()) } -fn diff_instructions_similar( - alg: Algorithm, +fn diff_instructions( left_diff: &mut Vec, right_diff: &mut Vec, left_code: &ProcessCodeResult, right_code: &ProcessCodeResult, ) -> Result<()> { let deadline = Instant::now() + Duration::from_secs(5); - let ops = capture_diff_slices_deadline(alg, &left_code.ops, &right_code.ops, Some(deadline)); + let ops = capture_diff_slices_deadline( + Algorithm::Patience, + &left_code.ops, + &right_code.ops, + Some(deadline), + ); if ops.is_empty() { left_diff.extend( left_code @@ -217,75 +180,6 @@ fn diff_instructions_similar( Ok(()) } -fn diff_instructions_lev( - left_diff: &mut Vec, - right_diff: &mut Vec, - left_symbol: &ObjSymbol, - right_symbol: &ObjSymbol, - left_code: &ProcessCodeResult, - right_code: &ProcessCodeResult, -) -> Result<()> { - let edit_ops = editops_find(&left_code.ops, &right_code.ops); - - let mut op_iter = edit_ops.iter(); - let mut left_iter = left_code.insts.iter(); - let mut right_iter = right_code.insts.iter(); - let mut cur_op = op_iter.next(); - let mut cur_left = left_iter.next(); - let mut cur_right = right_iter.next(); - while let Some(op) = cur_op { - let left_addr = op.first_start as u32 * 4; - let right_addr = op.second_start as u32 * 4; - while let (Some(left), Some(right)) = (cur_left, cur_right) { - if (left.address - left_symbol.address as u32) < left_addr { - left_diff.push(ObjInsDiff { ins: Some(left.clone()), ..ObjInsDiff::default() }); - right_diff.push(ObjInsDiff { ins: Some(right.clone()), ..ObjInsDiff::default() }); - } else { - break; - } - cur_left = left_iter.next(); - cur_right = right_iter.next(); - } - if let (Some(left), Some(right)) = (cur_left, cur_right) { - debug_assert_eq!(left.address - left_symbol.address as u32, left_addr); - debug_assert_eq!(right.address - right_symbol.address as u32, right_addr); - match op.op_type { - LevEditType::Replace => { - left_diff.push(ObjInsDiff { ins: Some(left.clone()), ..ObjInsDiff::default() }); - right_diff - .push(ObjInsDiff { ins: Some(right.clone()), ..ObjInsDiff::default() }); - cur_left = left_iter.next(); - cur_right = right_iter.next(); - } - LevEditType::Insert => { - left_diff.push(ObjInsDiff::default()); - right_diff - .push(ObjInsDiff { ins: Some(right.clone()), ..ObjInsDiff::default() }); - cur_right = right_iter.next(); - } - LevEditType::Delete => { - left_diff.push(ObjInsDiff { ins: Some(left.clone()), ..ObjInsDiff::default() }); - right_diff.push(ObjInsDiff::default()); - cur_left = left_iter.next(); - } - } - } else { - break; - } - cur_op = op_iter.next(); - } - - // Finalize - while cur_left.is_some() || cur_right.is_some() { - left_diff.push(ObjInsDiff { ins: cur_left.cloned(), ..ObjInsDiff::default() }); - right_diff.push(ObjInsDiff { ins: cur_right.cloned(), ..ObjInsDiff::default() }); - cur_left = left_iter.next(); - cur_right = right_iter.next(); - } - - Ok(()) -} - fn resolve_branches(vec: &mut [ObjInsDiff]) { let mut branch_idx = 0usize; // Map addresses to indices diff --git a/objdiff-core/src/diff/data.rs b/objdiff-core/src/diff/data.rs index 34407a4..30ece33 100644 --- a/objdiff-core/src/diff/data.rs +++ b/objdiff-core/src/diff/data.rs @@ -1,28 +1,12 @@ use std::{ cmp::{max, min, Ordering}, - mem::take, time::{Duration, Instant}, }; -use anyhow::{ensure, Result}; +use anyhow::Result; use similar::{capture_diff_slices_deadline, Algorithm}; -use crate::{ - diff::{ - editops::{editops_find, LevEditType}, - DiffAlg, - }, - obj::{ObjDataDiff, ObjDataDiffKind, ObjSection, ObjSymbol}, -}; - -pub fn diff_data(alg: DiffAlg, left: &mut ObjSection, right: &mut ObjSection) -> Result<()> { - match alg { - DiffAlg::Levenshtein => diff_data_lev(left, right), - DiffAlg::Lcs => diff_data_similar(Algorithm::Lcs, left, right), - DiffAlg::Myers => diff_data_similar(Algorithm::Myers, left, right), - DiffAlg::Patience => diff_data_similar(Algorithm::Patience, left, right), - } -} +use crate::obj::{ObjDataDiff, ObjDataDiffKind, ObjSection, ObjSymbol}; pub fn diff_bss_symbols( left_symbols: &mut [ObjSymbol], @@ -40,67 +24,10 @@ pub fn diff_bss_symbols( Ok(()) } -// WIP diff-by-symbol -#[allow(dead_code)] -pub fn diff_data_symbols(left: &mut ObjSection, right: &mut ObjSection) -> Result<()> { - let mut left_ops = Vec::::with_capacity(left.symbols.len()); - let mut right_ops = Vec::::with_capacity(right.symbols.len()); - for left_symbol in &left.symbols { - let data = &left.data - [left_symbol.address as usize..(left_symbol.address + left_symbol.size) as usize]; - let hash = twox_hash::xxh3::hash64(data); - left_ops.push(hash as u32); - } - for symbol in &right.symbols { - let data = &right.data[symbol.address as usize..(symbol.address + symbol.size) as usize]; - let hash = twox_hash::xxh3::hash64(data); - right_ops.push(hash as u32); - } - - let edit_ops = editops_find(&left_ops, &right_ops); - if edit_ops.is_empty() && !left.data.is_empty() { - let mut left_iter = left.symbols.iter_mut(); - let mut right_iter = right.symbols.iter_mut(); - loop { - let (left_symbol, right_symbol) = match (left_iter.next(), right_iter.next()) { - (Some(l), Some(r)) => (l, r), - (None, None) => break, - _ => return Err(anyhow::Error::msg("L/R mismatch in diff_data_symbols")), - }; - let left_data = &left.data - [left_symbol.address as usize..(left_symbol.address + left_symbol.size) as usize]; - let right_data = &right.data[right_symbol.address as usize - ..(right_symbol.address + right_symbol.size) as usize]; - - left.data_diff.push(ObjDataDiff { - data: left_data.to_vec(), - kind: ObjDataDiffKind::None, - len: left_symbol.size as usize, - symbol: left_symbol.name.clone(), - }); - right.data_diff.push(ObjDataDiff { - data: right_data.to_vec(), - kind: ObjDataDiffKind::None, - len: right_symbol.size as usize, - symbol: right_symbol.name.clone(), - }); - left_symbol.diff_symbol = Some(right_symbol.name.clone()); - left_symbol.match_percent = Some(100.0); - right_symbol.diff_symbol = Some(left_symbol.name.clone()); - right_symbol.match_percent = Some(100.0); - } - return Ok(()); - } - Ok(()) -} - -pub fn diff_data_similar( - alg: Algorithm, - left: &mut ObjSection, - right: &mut ObjSection, -) -> Result<()> { +pub fn diff_data(left: &mut ObjSection, right: &mut ObjSection) -> Result<()> { let deadline = Instant::now() + Duration::from_secs(5); - let ops = capture_diff_slices_deadline(alg, &left.data, &right.data, Some(deadline)); + let ops = + capture_diff_slices_deadline(Algorithm::Patience, &left.data, &right.data, Some(deadline)); let mut left_diff = Vec::::new(); let mut right_diff = Vec::::new(); @@ -175,226 +102,6 @@ pub fn diff_data_similar( Ok(()) } -pub fn diff_data_lev(left: &mut ObjSection, right: &mut ObjSection) -> Result<()> { - let matrix_size = (left.data.len() as u64).saturating_mul(right.data.len() as u64); - ensure!( - matrix_size < 1_000_000_000, - "Data section {} too large for Levenshtein diff ({} * {} = {})", - left.name, - left.data.len(), - right.data.len(), - matrix_size - ); - - let edit_ops = editops_find(&left.data, &right.data); - if edit_ops.is_empty() && !left.data.is_empty() { - left.data_diff = vec![ObjDataDiff { - data: left.data.clone(), - kind: ObjDataDiffKind::None, - len: left.data.len(), - symbol: String::new(), - }]; - right.data_diff = vec![ObjDataDiff { - data: right.data.clone(), - kind: ObjDataDiffKind::None, - len: right.data.len(), - symbol: String::new(), - }]; - return Ok(()); - } - - let mut left_diff = Vec::::new(); - let mut right_diff = Vec::::new(); - let mut left_cur = 0usize; - let mut right_cur = 0usize; - let mut cur_op = LevEditType::Replace; - let mut cur_left_data = Vec::::new(); - let mut cur_right_data = Vec::::new(); - for op in edit_ops { - if cur_op != op.op_type || left_cur < op.first_start || right_cur < op.second_start { - match cur_op { - LevEditType::Replace => { - let left_data = take(&mut cur_left_data); - let right_data = take(&mut cur_right_data); - let left_data_len = left_data.len(); - let right_data_len = right_data.len(); - left_diff.push(ObjDataDiff { - data: left_data, - kind: ObjDataDiffKind::Replace, - len: left_data_len, - symbol: String::new(), - }); - right_diff.push(ObjDataDiff { - data: right_data, - kind: ObjDataDiffKind::Replace, - len: right_data_len, - symbol: String::new(), - }); - } - LevEditType::Insert => { - let right_data = take(&mut cur_right_data); - let right_data_len = right_data.len(); - left_diff.push(ObjDataDiff { - data: vec![], - kind: ObjDataDiffKind::Insert, - len: right_data_len, - symbol: String::new(), - }); - right_diff.push(ObjDataDiff { - data: right_data, - kind: ObjDataDiffKind::Insert, - len: right_data_len, - symbol: String::new(), - }); - } - LevEditType::Delete => { - let left_data = take(&mut cur_left_data); - let left_data_len = left_data.len(); - left_diff.push(ObjDataDiff { - data: left_data, - kind: ObjDataDiffKind::Delete, - len: left_data_len, - symbol: String::new(), - }); - right_diff.push(ObjDataDiff { - data: vec![], - kind: ObjDataDiffKind::Delete, - len: left_data_len, - symbol: String::new(), - }); - } - } - } - if left_cur < op.first_start { - left_diff.push(ObjDataDiff { - data: left.data[left_cur..op.first_start].to_vec(), - kind: ObjDataDiffKind::None, - len: op.first_start - left_cur, - symbol: String::new(), - }); - left_cur = op.first_start; - } - if right_cur < op.second_start { - right_diff.push(ObjDataDiff { - data: right.data[right_cur..op.second_start].to_vec(), - kind: ObjDataDiffKind::None, - len: op.second_start - right_cur, - symbol: String::new(), - }); - right_cur = op.second_start; - } - match op.op_type { - LevEditType::Replace => { - cur_left_data.push(left.data[left_cur]); - cur_right_data.push(right.data[right_cur]); - left_cur += 1; - right_cur += 1; - } - LevEditType::Insert => { - cur_right_data.push(right.data[right_cur]); - right_cur += 1; - } - LevEditType::Delete => { - cur_left_data.push(left.data[left_cur]); - left_cur += 1; - } - } - cur_op = op.op_type; - } - // if left_cur < left.data.len() { - // let len = left.data.len() - left_cur; - // left_diff.push(ObjDataDiff { - // data: left.data[left_cur..].to_vec(), - // kind: ObjDataDiffKind::Delete, - // len, - // }); - // right_diff.push(ObjDataDiff { data: vec![], kind: ObjDataDiffKind::Delete, len }); - // } else if right_cur < right.data.len() { - // let len = right.data.len() - right_cur; - // left_diff.push(ObjDataDiff { data: vec![], kind: ObjDataDiffKind::Insert, len }); - // right_diff.push(ObjDataDiff { - // data: right.data[right_cur..].to_vec(), - // kind: ObjDataDiffKind::Insert, - // len, - // }); - // } - - // TODO: merge with above - match cur_op { - LevEditType::Replace => { - let left_data = take(&mut cur_left_data); - let right_data = take(&mut cur_right_data); - let left_data_len = left_data.len(); - let right_data_len = right_data.len(); - left_diff.push(ObjDataDiff { - data: left_data, - kind: ObjDataDiffKind::Replace, - len: left_data_len, - symbol: String::new(), - }); - right_diff.push(ObjDataDiff { - data: right_data, - kind: ObjDataDiffKind::Replace, - len: right_data_len, - symbol: String::new(), - }); - } - LevEditType::Insert => { - let right_data = take(&mut cur_right_data); - let right_data_len = right_data.len(); - left_diff.push(ObjDataDiff { - data: vec![], - kind: ObjDataDiffKind::Insert, - len: right_data_len, - symbol: String::new(), - }); - right_diff.push(ObjDataDiff { - data: right_data, - kind: ObjDataDiffKind::Insert, - len: right_data_len, - symbol: String::new(), - }); - } - LevEditType::Delete => { - let left_data = take(&mut cur_left_data); - let left_data_len = left_data.len(); - left_diff.push(ObjDataDiff { - data: left_data, - kind: ObjDataDiffKind::Delete, - len: left_data_len, - symbol: String::new(), - }); - right_diff.push(ObjDataDiff { - data: vec![], - kind: ObjDataDiffKind::Delete, - len: left_data_len, - symbol: String::new(), - }); - } - } - - if left_cur < left.data.len() { - left_diff.push(ObjDataDiff { - data: left.data[left_cur..].to_vec(), - kind: ObjDataDiffKind::None, - len: left.data.len() - left_cur, - symbol: String::new(), - }); - } - if right_cur < right.data.len() { - right_diff.push(ObjDataDiff { - data: right.data[right_cur..].to_vec(), - kind: ObjDataDiffKind::None, - len: right.data.len() - right_cur, - symbol: String::new(), - }); - } - - left.data_diff = left_diff; - right.data_diff = right_diff; - Ok(()) -} - pub fn no_diff_data(section: &mut ObjSection) { section.data_diff = vec![ObjDataDiff { data: section.data.clone(), diff --git a/objdiff-core/src/diff/editops.rs b/objdiff-core/src/diff/editops.rs deleted file mode 100644 index 8e9ff95..0000000 --- a/objdiff-core/src/diff/editops.rs +++ /dev/null @@ -1,162 +0,0 @@ -/// Adapted from https://crates.io/crates/rapidfuzz -// Copyright 2020 maxbachmann -// -// Permission is hereby granted, free of charge, to any -// person obtaining a copy of this software and associated -// documentation files (the "Software"), to deal in the -// Software without restriction, including without -// limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice -// shall be included in all copies or substantial portions -// of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum LevEditType { - Replace, - Insert, - Delete, -} - -#[derive(Debug, PartialEq, Eq)] -pub struct LevEditOp { - pub op_type: LevEditType, /* editing operation type */ - pub first_start: usize, /* source block position */ - pub second_start: usize, /* destination position */ -} - -pub fn editops_find(query: &[T], choice: &[T]) -> Vec -where T: PartialEq { - let Affix { prefix_len, suffix_len } = Affix::find(query, choice); - - let first_string = &query[prefix_len..query.len() - suffix_len]; - let second_string = &choice[prefix_len..choice.len() - suffix_len]; - - let matrix_columns = first_string.len() + 1; - let matrix_rows = second_string.len() + 1; - - // TODO maybe use an actual matrix for readability - let mut cache_matrix: Vec = vec![0; matrix_rows * matrix_columns]; - for (i, elem) in cache_matrix.iter_mut().enumerate().take(matrix_rows) { - *elem = i; - } - for i in 1..matrix_columns { - cache_matrix[matrix_rows * i] = i; - } - - for (i, char1) in first_string.iter().enumerate() { - let mut prev = i * matrix_rows; - let current = prev + matrix_rows; - let mut x = i + 1; - for (p, char2p) in second_string.iter().enumerate() { - let mut c3 = cache_matrix[prev] + (char1 != char2p) as usize; - prev += 1; - x += 1; - if x >= c3 { - x = c3; - } - c3 = cache_matrix[prev] + 1; - if x > c3 { - x = c3; - } - cache_matrix[current + 1 + p] = x; - } - } - editops_from_cost_matrix(matrix_columns, matrix_rows, prefix_len, cache_matrix) -} - -fn editops_from_cost_matrix( - len1: usize, - len2: usize, - prefix_len: usize, - cache_matrix: Vec, -) -> Vec { - let mut ops = Vec::with_capacity(cache_matrix[len1 * len2 - 1]); - let mut dir = 0; - let mut i = len1 - 1; - let mut j = len2 - 1; - let mut p = len1 * len2 - 1; - - //TODO this is still pretty ugly - while i > 0 || j > 0 { - let current_value = cache_matrix[p]; - - // More than one operation can be possible at a time. We use `dir` to - // decide when ambiguous. - let is_insert = j > 0 && current_value == cache_matrix[p - 1] + 1; - let is_delete = i > 0 && current_value == cache_matrix[p - len2] + 1; - let is_replace = i > 0 && j > 0 && current_value == cache_matrix[p - len2 - 1] + 1; - - let (op_type, new_dir) = match (dir, is_insert, is_delete, is_replace) { - (_, false, false, false) => (None, 0), - (-1, true, _, _) => (Some(LevEditType::Insert), -1), - (1, _, true, _) => (Some(LevEditType::Delete), 1), - (_, _, _, true) => (Some(LevEditType::Replace), 0), - (0, true, _, _) => (Some(LevEditType::Insert), -1), - (0, _, true, _) => (Some(LevEditType::Delete), 1), - _ => panic!("something went terribly wrong"), - }; - - match new_dir { - -1 => { - j -= 1; - p -= 1; - } - 1 => { - i -= 1; - p -= len2; - } - 0 => { - i -= 1; - j -= 1; - p -= len2 + 1; - } - _ => panic!("something went terribly wrong"), - }; - dir = new_dir; - - if let Some(op_type) = op_type { - ops.insert(0, LevEditOp { - op_type, - first_start: i + prefix_len, - second_start: j + prefix_len, - }); - } - } - - ops -} - -pub struct Affix { - pub prefix_len: usize, - pub suffix_len: usize, -} - -impl Affix { - pub fn find(s1: &[T], s2: &[T]) -> Affix - where T: PartialEq { - let prefix_len = s1.iter().zip(s2.iter()).take_while(|t| t.0 == t.1).count(); - let suffix_len = s1[prefix_len..] - .iter() - .rev() - .zip(s2[prefix_len..].iter().rev()) - .take_while(|t| t.0 == t.1) - .count(); - - Affix { prefix_len, suffix_len } - } -} diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index c3e7686..bd7b20d 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -1,10 +1,8 @@ pub mod code; pub mod data; pub mod display; -pub mod editops; use anyhow::Result; -use serde::{Deserialize, Serialize}; use crate::{ diff::{ @@ -14,19 +12,8 @@ use crate::{ obj::{ObjInfo, ObjIns, ObjSectionKind}, }; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] -pub enum DiffAlg { - #[default] - Patience, - Levenshtein, - Myers, - Lcs, -} - #[derive(Debug, Clone, Default, Eq, PartialEq)] pub struct DiffObjConfig { - pub code_alg: DiffAlg, - pub data_alg: DiffAlg, pub relax_reloc_diffs: bool, } @@ -80,7 +67,7 @@ pub fn diff_objs( .and_then(|obj| obj.sections.iter_mut().find(|s| s.name == left_section.name)) { if left_section.kind == ObjSectionKind::Data { - diff_data(config.data_alg, left_section, right_section)?; + diff_data(left_section, right_section)?; } else if left_section.kind == ObjSectionKind::Bss { diff_bss_symbols(&mut left_section.symbols, &mut right_section.symbols)?; } diff --git a/objdiff-gui/src/app.rs b/objdiff-gui/src/app.rs index 933552e..26b46e8 100644 --- a/objdiff-gui/src/app.rs +++ b/objdiff-gui/src/app.rs @@ -106,10 +106,6 @@ pub struct AppConfig { #[serde(default)] pub recent_projects: Vec, #[serde(default)] - pub code_alg: DiffAlg, - #[serde(default)] - pub data_alg: DiffAlg, - #[serde(default)] pub relax_reloc_diffs: bool, #[serde(skip)] @@ -148,8 +144,6 @@ impl Default for AppConfig { auto_update_check: true, watch_patterns: DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect(), recent_projects: vec![], - code_alg: Default::default(), - data_alg: Default::default(), relax_reloc_diffs: false, objects: vec![], object_nodes: vec![], diff --git a/objdiff-gui/src/jobs/objdiff.rs b/objdiff-gui/src/jobs/objdiff.rs index fccac20..e2bc074 100644 --- a/objdiff-gui/src/jobs/objdiff.rs +++ b/objdiff-gui/src/jobs/objdiff.rs @@ -57,8 +57,6 @@ pub struct ObjDiffConfig { pub build_base: bool, pub build_target: bool, pub selected_obj: Option, - pub code_alg: DiffAlg, - pub data_alg: DiffAlg, pub relax_reloc_diffs: bool, } @@ -69,8 +67,6 @@ impl ObjDiffConfig { build_base: config.build_base, build_target: config.build_target, selected_obj: config.selected_obj.clone(), - code_alg: config.code_alg, - data_alg: config.data_alg, relax_reloc_diffs: config.relax_reloc_diffs, } } @@ -253,11 +249,7 @@ fn run_build( }; update_status(context, "Performing diff".to_string(), 4, total, &cancel)?; - let diff_config = DiffObjConfig { - code_alg: config.code_alg, - data_alg: config.data_alg, - relax_reloc_diffs: config.relax_reloc_diffs, - }; + let diff_config = DiffObjConfig { relax_reloc_diffs: config.relax_reloc_diffs }; diff_objs(&diff_config, first_obj.as_mut(), second_obj.as_mut())?; update_status(context, "Complete".to_string(), total, total, &cancel)?; diff --git a/objdiff-gui/src/views/config.rs b/objdiff-gui/src/views/config.rs index 4b7e506..cb1b050 100644 --- a/objdiff-gui/src/views/config.rs +++ b/objdiff-gui/src/views/config.rs @@ -14,10 +14,7 @@ use egui::{ SelectableLabel, TextFormat, Widget, WidgetText, }; use globset::Glob; -use objdiff_core::{ - config::{ProjectObject, DEFAULT_WATCH_PATTERNS}, - diff::DiffAlg, -}; +use objdiff_core::config::{ProjectObject, DEFAULT_WATCH_PATTERNS}; use self_update::cargo_crate_version; use crate::{ @@ -853,58 +850,3 @@ pub fn diff_options_window( diff_options_ui(ui, &mut config_guard, appearance); }); } - -fn diff_options_ui(ui: &mut egui::Ui, config: &mut AppConfig, appearance: &Appearance) { - let mut job = LayoutJob::default(); - job.append( - "Current default: ", - 0.0, - TextFormat::simple(appearance.ui_font.clone(), appearance.text_color), - ); - job.append( - diff_alg_to_string(DiffAlg::default()), - 0.0, - TextFormat::simple(appearance.ui_font.clone(), appearance.emphasized_text_color), - ); - ui.label(job); - let mut job = LayoutJob::default(); - job.append( - "Previous default: ", - 0.0, - TextFormat::simple(appearance.ui_font.clone(), appearance.text_color), - ); - job.append( - "Levenshtein", - 0.0, - TextFormat::simple(appearance.ui_font.clone(), appearance.emphasized_text_color), - ); - ui.label(job); - ui.label("Please provide feedback!"); - if diff_alg_ui(ui, "Code diff algorithm", &mut config.code_alg) { - config.queue_reload = true; - } - if diff_alg_ui(ui, "Data diff algorithm", &mut config.data_alg) { - config.queue_reload = true; - } -} - -fn diff_alg_ui(ui: &mut egui::Ui, label: impl Into, alg: &mut DiffAlg) -> bool { - let response = egui::ComboBox::from_label(label) - .selected_text(diff_alg_to_string(*alg)) - .show_ui(ui, |ui| { - ui.selectable_value(alg, DiffAlg::Patience, "Patience").changed() - | ui.selectable_value(alg, DiffAlg::Levenshtein, "Levenshtein").changed() - | ui.selectable_value(alg, DiffAlg::Myers, "Myers").changed() - | ui.selectable_value(alg, DiffAlg::Lcs, "LCS").changed() - }); - response.inner.unwrap_or(false) -} - -const fn diff_alg_to_string(alg: DiffAlg) -> &'static str { - match alg { - DiffAlg::Patience => "Patience", - DiffAlg::Levenshtein => "Levenshtein", - DiffAlg::Lcs => "LCS", - DiffAlg::Myers => "Myers", - } -}