Top Description Inners Fields Constructors Methods
org.eclipse.jgit.diff

public Class HistogramDiff

extends LowLevelDiffAlgorithm
Class Inheritance
Imports
java.util.ArrayList, .List

An extended form of Bram Cohen's patience diff algorithm.

This implementation was derived by using the 4 rules that are outlined in Bram Cohen's blog, and then was further extended to support low-occurrence common elements.

The basic idea of the algorithm is to create a histogram of occurrences for each element of sequence A. Each element of sequence B is then considered in turn. If the element also exists in sequence A, and has a lower occurrence count, the positions are considered as a candidate for the longest common subsequence (LCS). After scanning of B is complete the LCS that has the lowest number of occurrences is chosen as a split point. The region is split around the LCS, and the algorithm is recursively applied to the sections before and after the LCS.

By always selecting a LCS position with the lowest occurrence count, this algorithm behaves exactly like Bram Cohen's patience diff whenever there is a unique common element available between the two sequences. When no unique elements exist, the lowest occurrence element is chosen instead. This offers more readable diffs than simply falling back on the standard Myers' O(ND) algorithm would produce.

To prevent the algorithm from having an O(N^2) running time, an upper limit on the number of unique elements in a histogram bucket is configured by setMaxChainLength(int). If sequence A has more than this many elements that hash into the same hash bucket, the algorithm passes the region to setFallbackAlgorithm(DiffAlgorithm). If no fallback algorithm is configured, the region is emitted as a replace edit.

During scanning of sequence B, any element of A that occurs more than setMaxChainLength(int) times is never considered for an LCS match position, even if it is common between the two sequences. This limits the number of locations in sequence A that must be considered to find the LCS, and helps maintain a lower running time bound.

So long as setMaxChainLength(int) is a small constant (such as 64), the algorithm runs in O(N * D) time, where N is the sum of the input lengths and D is the number of edits in the resulting EditList. If the supplied org.eclipse.jgit.diff.SequenceComparator has a good hash function, this implementation typically out-performs org.eclipse.jgit.diff.MyersDiff, even though its theoretical running time is the same.

This implementation has an internal limitation that prevents it from handling sequences with more than 268,435,456 (2^28) elements.

Nested and Inner Type Summary

Modifier and TypeClass and Description
private class

Field Summary

Modifier and TypeField and Description
pack-priv DiffAlgorithm
fallback

Algorithm to use when there are too many element occurrences.

pack-priv int
maxChainLength

Maximum number of positions to consider for a given element hash.

Constructor Summary

AccessConstructor and Description
public

Method Summary

Modifier and TypeMethod and Description
public <S extends Sequence> void
diffNonCommon(EditList
result list to append the region's edits onto.
edits
,
HashedSequenceComparator<S>
the comparator supplying the element equivalence function.
cmp
,
HashedSequence<S>
the first (also known as old or pre-image) sequence. Edits returned by this algorithm will reference indexes using the 'A' side: org.eclipse.jgit.diff.Edit#getBeginA(), org.eclipse.jgit.diff.Edit#getEndA().
a
,
HashedSequence<S>
the second (also known as new or post-image) sequence. Edits returned by this algorithm will reference indexes using the 'B' side: org.eclipse.jgit.diff.Edit#getBeginB(), org.eclipse.jgit.diff.Edit#getEndB().
b
,
Edit
the region being compared within the two sequences.
region
)

Implements abstract org.eclipse.jgit.diff.LowLevelDiffAlgorithm.diffNonCommon.

Compare two sequences and identify a list of edits between them.

public void
setFallbackAlgorithm(DiffAlgorithm
the secondary algorithm. If null the region will be denoted as a single REPLACE block.
alg
)

Set the algorithm used when there are too many element occurrences.

public void
setMaxChainLength(int
new maximum length.
maxLen
)

Maximum number of positions to consider for a given element hash.

Inherited from org.eclipse.jgit.diff.LowLevelDiffAlgorithm:
diffNonCommon

Field Detail

fallbackback to summary
pack-priv DiffAlgorithm fallback

Algorithm to use when there are too many element occurrences.

maxChainLengthback to summary
pack-priv int maxChainLength

Maximum number of positions to consider for a given element hash. All elements with the same hash are stored into a single chain. The chain size is capped to ensure search is linear time at O(len_A + len_B) rather than quadratic at O(len_A * len_B).

Constructor Detail

HistogramDiffback to summary
public HistogramDiff()

Method Detail

diffNonCommonback to summary
public <S extends Sequence> void diffNonCommon(EditList edits, HashedSequenceComparator<S> cmp, HashedSequence<S> a, HashedSequence<S> b, Edit region)

Implements abstract org.eclipse.jgit.diff.LowLevelDiffAlgorithm.diffNonCommon.

Doc from org.eclipse.jgit.diff.LowLevelDiffAlgorithm.diffNonCommon.

Compare two sequences and identify a list of edits between them. This method should be invoked only after the two sequences have been proven to have no common starting or ending elements. The expected elimination of common starting and ending elements is automatically performed by the diff(SequenceComparator, Sequence, Sequence) method, which invokes this method using org.eclipse.jgit.diff.Subsequences.

Parameters
<S>
type of Sequence compared
edits:EditList

result list to append the region's edits onto.

cmp:HashedSequenceComparator<S>

the comparator supplying the element equivalence function.

a:HashedSequence<S>

the first (also known as old or pre-image) sequence. Edits returned by this algorithm will reference indexes using the 'A' side: org.eclipse.jgit.diff.Edit#getBeginA(), org.eclipse.jgit.diff.Edit#getEndA().

b:HashedSequence<S>

the second (also known as new or post-image) sequence. Edits returned by this algorithm will reference indexes using the 'B' side: org.eclipse.jgit.diff.Edit#getBeginB(), org.eclipse.jgit.diff.Edit#getEndB().

region:Edit

the region being compared within the two sequences.

Annotations
@Override
setFallbackAlgorithmback to summary
public void setFallbackAlgorithm(DiffAlgorithm alg)

Set the algorithm used when there are too many element occurrences.

Parameters
alg:DiffAlgorithm

the secondary algorithm. If null the region will be denoted as a single REPLACE block.

setMaxChainLengthback to summary
public void setMaxChainLength(int maxLen)

Maximum number of positions to consider for a given element hash. All elements with the same hash are stored into a single chain. The chain size is capped to ensure search is linear time at O(len_A + len_B) rather than quadratic at O(len_A * len_B).

Parameters
maxLen:int

new maximum length.

org.eclipse.jgit.diff back to summary

private Class HistogramDiff.State<S extends Sequence>

extends Object
Class Inheritance

Field Summary

Modifier and TypeField and Description
private final HashedSequence<S>
a

private final HashedSequence<S>
b

private final HashedSequenceComparator<S>
pack-priv final EditList
edits

Result edits we have determined that must be made to convert a to b.

private final List<Edit>

Constructor Summary

AccessConstructor and Description
pack-priv

Method Summary

Modifier and TypeMethod and Description
private void
pack-priv void
private void
private SubsequenceComparator<HashedSequence<S>>
Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

aback to summary
private final HashedSequence<S> a
bback to summary
private final HashedSequence<S> b
cmpback to summary
private final HashedSequenceComparator<S> cmp
editsback to summary
pack-priv final EditList edits

Result edits we have determined that must be made to convert a to b.

queueback to summary
private final List<Edit> queue

Constructor Detail

Stateback to summary
pack-priv State(EditList edits, HashedSequenceComparator<S> cmp, HashedSequence<S> a, HashedSequence<S> b)

Method Detail

diffback to summary
private void diff(Edit r)
diffRegionback to summary
pack-priv void diffRegion(Edit r)
diffReplaceback to summary
private void diffReplace(Edit r)
subcmpback to summary
private SubsequenceComparator<HashedSequence<S>> subcmp()