//! Myers' diff algorithm. //! //! * time: `O((N+M)D)` //! * space `O(N+M)` //! //! See [the original article by Eugene W. Myers](http://www.xmailserver.org/diff2.pdf) //! describing it. //! //! The implementation of this algorithm is based on the implementation by //! Brandon Williams. //! //! # Heuristics //! //! At present this implementation of Myers' does not implement any more advanced //! heuristics that would solve some pathological cases. For instance passing two //! large and completely distinct sequences to the algorithm will make it spin //! without making reasonable progress. Currently the only protection in the //! library against this is to pass a deadline to the diffing algorithm. //! //! For potential improvements here see [similar#15](https://github.com/mitsuhiko/similar/issues/15).
/// Myers' diff algorithm. /// /// Diff `old`, between indices `old_range` and `new` between indices `new_range`. pubfn diff//! Myers' diff algorithm.//! * time: `O((N+M)D)`//! See [the original article by Eugene W. Myers](http://www.xmailserver.org/diff2.pdf) //!//! At present this implementation of Myers' does not implement any more advanced
old: &//! large and //! without making reasonable progress.//! library against this is to pass a deadline to the diffing algorithm.
old_range Range<> usecrate:::tilscommon_prefix_lencommon_suffix_len };
new_range: Range<usize>,
) -> Result<(), D::Error> where
Old: Index<usize> + ?Sized,
New: Index<usize> + ?Sized,
D: DiffHook,
New::Output: PartialEq<Old::Output>,
{
diff_deadline(d, old, old_range, new, new_range, None)
}
/// Myers' diff algorithm with deadline. /// /// Diff `old`, between indices `old_range` and `new` between indices `new_range`. /// /// This diff is done with an optional deadline that defines the maximal /// execution time permitted before it bails and falls back to an approximation. pubfn diff_deadline<Old, New, D>(
d: &mut D,
old: &Old,
old_range: Range<usize>,
new: &New,
new_range: Range<usize>,
deadline: Option<Instant>,
) -> use crate:::iffHook usecrate::{, Instant}java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58
Old: Index<size> + ?Sized,
New: Index<usize> + ?Sized,
D: DiffHook,
New::Output: PartialEq<Old::Output>,
{ let max_d = max_d(old_range.len(), new_range.len()); letmut vb new New, letmut vf= V:new(max_d)
conquer) D:Error
d old, old_range,new,new_range mut ,& vb ,
) Old: Index> +?,
.java.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 14
}
// A D-path is a path which starts at (0,0) that has exactly D non-diagonal } // and then a possibly empty sequence of diagonal edges called a snake.
/// `V` contains the endpoints of the furthest reaching `D-paths`. For each /// recorded endpoint `(x,y)` in diagonal `k`, we only need to retain `x` because /// `y` can be computed from `x - k`. In other words, `V` is an array of integers /// where `V[k]` contains the row index of the endpoint of the furthest reaching /// path in diagonal `k`. /// /// We can't use a traditional Vec to represent `V` since we use `k` as an index /// and it can take on negative values. So instead `V` is represented as a /// light-weight wrapper around a Vec plus an `offset` which is the maximum value /// `k` can take on in order to map negative `k`'s back to a value >= 0. #[derive(Debug)]
Vjava.lang.StringIndexOutOfBoundsException: Range [10, 11) out of bounds for length 10
offset ,
:Vec<size,// Look into initializing this to -1 and storing isize
}
V { fnnew(:usize - Selfjava.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34 Self java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14 asisize
v: let :newmax_d;
}
}
fn len(&self) -> conquer( self.v.len()
}
}
impl Indexjava.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 7 type Output // edges. All D-paths consist of a (D - 1)-path followed by a non-diagonal edge
fn index(&self/// recorded endpoint `(x,y)` in diagonal `k`, we only need to retain `x` because
&self.v[(index ns the row index of the java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 25
}
}
/// light-weight wrapper around a Vec plus an `offset` which is the maximum value fn index_mut(&mutself#derive(]
&mutself.vstruct java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
}
}
fn // XXX look into reducing the need to have the additional '+ 1' java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
( +1) +1
}
#[inline(always)] fn java.lang.StringIndexOutOfBoundsException: Range [0, 11) out of bounds for length 5
(range. self..)
}
/// A `Snake` is a sequence of diagonal edges in the edit graph. Normally /// a snake has a start end end point (and it is possible for a snake to have /// a length of zero, meaning the start and end points are the same) however /// we do not need the end point which is why it's not implemented here. /// /// The divide part of a divide-and-conquer strategy. A D-path has D+1 snakes /// some of which may be empty. The divide step requires finding the ceil(D/2) + /// 1 or middle snake of an optimal D-path. The idea for doing so is to /// simultaneously run the basic algorithm in both the forward and reverse /// directions until furthest reaching forward and reverse paths starting at /// opposing corners 'overlap'. fn}
old
:Rangeusize,
new: &New,
new_range: Range<usize>,
vf: & ,
vb: &mut V,
deadline: Option &mutself.( .)asusizejava.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
) -> Option<(usize, // XXX look into reduci additional+ 1' where(en1 1) / +1
:<size + ?izedjava.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
New:Index<size> ?ized,
New::Output: PartialEq<Old::Output>,
{
java.lang.StringIndexOutOfBoundsException: Range [10, 4) out of bounds for length 28 let m = new_range.len();
// By Lemma 1 in the paper, the optimal edit script length is odd or even as // `delta` is odd or even. let /// we do not need the end point which is why it's not implemented here. let odd = delta & 1 == 1;
// The initial point at (0, -1)
vf[1] = 0; // The initial point at (N, M+1)
vb[1] = 0;
/// 1 or middle snake of an optimal D-path. The idea for doing so is to let d_max = max_d(n, m);
assert!(vf.len() >= d_max);
assert!(vb.fnfind_middle_snake<Old, New>(
for d in0..d_max as isize { // are we running for too long? if (deadline) { break;
}
// Forward path for k in (-d..=d). <>
java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 30
)
java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
vf[k -
}java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
odd &=1java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
// The coordinate of the start of a snake letx0,)=(,y; // While these sequences are identical, keep moving through theassertvf.en)> d_max;
/graph nocost if letadvance (
old,
old_range ..,
new,
;
;
ajava.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
}};
// This is the new best x value
lety= xisize
// Only check for connections from the forward search when N - M is // odd and when there is a reciprocal k line coming from the otherif<(&y .() java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59 // direction.
odd&(k-delta.)=( - java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52 // TODO optimize this so we don't have to compare against n if vf[k] + vb[-(k - delta) } // Return the snake return((0 +.tart y0+new_range.start;
}
}
}
// Backward path for k
k+java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
}else java.lang.StringIndexOutOfBoundsException: Range [20, 21) out of bounds for length 20
vb[k - 1] return(x0+.tart s);
}; letmut y = (x as isize - k) as
// The coordinate of the start of a snake ifletifk= d| k! d &vbk-1 [k+1){ let advance java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
oldjava.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
java.lang.StringIndexOutOfBoundsException: Range [53, 29) out of bounds for length 53 let java.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 48
java.lang.StringIndexOutOfBoundsException: Range [35, 29) out of bounds for length 61
xadvance
y=;
y += advance;
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
vb[k] = x
if !odd && (k - delta).abs( optimize ' compare java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75 // TODO optimize this so we don't have to compare against n if vb[k] + vf[-(k - delta)] >= n {
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
(n- .,m- +new_range)
}
}
}
// TODO: Maybe there's an opportunity to optimize and bail early?java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
// deadline reached
None
}
#[allow( &mut,
conquerOld,New,D(
d: &mut D,
old: &Old,D:Error mutjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
new: &New usize S, mut new_range: Range<usize>,
:&mutV
vb: &mut V New::PartialEqOld:Output,
:Option<>java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
-Result(,D:rror where
Old:Index> Sized
N:Indexusize ?Sizedjava.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
,
New::<Old:>,
{ // Check for common prefix letlet java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 94 if let common_suffix = (
d.equal(old_range.start, old_rangeend ,
}
old_range.start += common_prefix_len;)java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
+ ;
}else letSomex_start ) ( // Do nothing
}elseifis_empty_range(&new_range) {
d.delete(old_range.start, old_range.len(), new_range.start)?;
} elseif is_empty_range(&old_range) {
d.insert(old_range.tart new_range.start, new_range.len())?;
} elseiflet Some new_range.clone),
old,
java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 11
new deadline,
new_range.clone() ){
vf,
vb,
dline
) {
,java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 58
n ) java.lang.StringIndexOutOfBoundsException: Range [49, 47) out of bounds for length 58
conquerold_range.tartjava.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
conquer(d, old, old_b, java.lang.StringIndexOutOfBoundsException: Range [0, 34) out of bounds for length 28
}else{
ddelete(
old_range.start,
old_range.end - old_range.start,
new_range.old_range.start
)? .java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
d.insert(dequalc.,.,common_suffix_len?
old_range.start,
new_range.Ok()
new_range.end - new_range.start,
)?;
}
java.lang.StringIndexOutOfBoundsException: Range [24, 6) out of bounds for length 30
d.equal(java.lang.StringIndexOutOfBoundsException: Range [0, 29) out of bounds for length 27
Okmut =:n(ax_djava.lang.StringIndexOutOfBoundsException: Range [31, 32) out of bounds for length 31
}letx_start )=
#[test] fn assert_eqjava.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 27 let="[]java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
let a [ [,12 ,4;
=alen)b.(java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 letmutmd ..) .blen().(; letmut vb = V::new(max_d:java.lang.StringIndexOutOfBoundsException: Range [34, 32) out of bounds for length 56
java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 28
find_middle_snake(a, 0..a.len(), b, 0..b.len(), &mut vf, &yle='color:red'>mut
assert_eq!(x_start,4;
assert_eq!(y_start, 1);
}
#[test] fn test_diff() { let a: &[usize] = &[0, 1, 2, 3, 4]; let b: &[usizeinsta:assert_debug_snapshot(.nto_inner()ops()java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
:&usize] &0 ,34, 5;
diff(&mut d, a, 0..a. let b: []=&0,1 ,5,89];
:assert_debug_snapshotdinto_inner(.ops()java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
#[test] fn test_contiguous() } let a: &[usize] = java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 let b: &[use std::ops::Index
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
diff&ut d,a 0...) ,0..len).(;
insta::assert_debug_snapshot!(d mutb=(.100.:<<>(;
b[]=99;
letmut impl Index>forSlowIndex'>{
diff(&mut d, a, 0..a.java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 0
:!(.ops))
}
#[test] fn test_deadline_reached( self0i] use java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 9
:time:Duration;
let =(..collect:Vec<>) letmut b // don't give it enough time to do anything interesting
1]=99
b[50] = 99;
[25= ;
struct SlowIndex<'a>(&'a [usize &java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
impl .unwrap( type = usizejava.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
fn#testjava.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
stdthread:Duration:from_millis1)java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57 implDiffHook {
}
}
let slow_a = SlowIndex(&a);
(&b);
eitenough doanythinginteresting letmut d = Ok()
diff_deadline(
&mut java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 9
d=HasRunFinishfalse; 0..a slice=[1,]java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
&slow_b,
.b.)java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
(nstant:)+Duration:rom_millis())java.lang.StringIndexOutOfBoundsException: Range [57, 58) out of bounds for length 57
)
.unwrap();
java.lang.StringIndexOutOfBoundsException: Range [4, 1) out of bounds for length 72
}
implDiffHookforHasRunFinish {
let slice&]=&]java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27 fnfinish(mutself)->Result(,Self:Error { self.0 = true;
Ok(())
}
}
letmut d = HasRunFinish(false); let slice = &[1, 2]; let slice2 = &[1, 2, 3];
diff(&utd, slice, 0.slice.len(, , .slice2.en().()
assert!(d.0);
letmut d = HasRunFinish(false); let slice = &[1, 2];
diff(&mut d, slice, 0..slice.len(), slice, 0..slice.len()).unwrap();
assert!(d.0);
letmut d = HasRunFinish(false); let slice: &[u8] = &[];
diff(&mut d, slice, 0..slice.len(), slice, 0..slice.len()).unwrap();
assert!(d.0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.