This makes it easier to parametrize DiffFormatter with a different implementation, as we later plan to add PatienceDiff to JGit. Change-Id: Id35ef478d5fa20fe10a1ba297f9436fd7adde9ce Signed-off-by: Shawn O. Pearce <spearce@spearce.org>tags/v0.10.1
else | else | ||||
oldImage = new byte[0]; | oldImage = new byte[0]; | ||||
EditList edits = new MyersDiff<RawText>( | |||||
EditList edits = MyersDiff.INSTANCE.diff( | |||||
RawTextComparator.DEFAULT, new RawText(oldImage), | RawTextComparator.DEFAULT, new RawText(oldImage), | ||||
new RawText(openBlob(1))).getEdits(); | |||||
new RawText(openBlob(1))); | |||||
for (Edit e : edits) | for (Edit e : edits) | ||||
addedLines += e.getEndB() - e.getBeginB(); | addedLines += e.getEndB() - e.getBeginB(); | ||||
} | } |
CharArray ac = new CharArray(a); | CharArray ac = new CharArray(a); | ||||
CharArray bc = new CharArray(b); | CharArray bc = new CharArray(b); | ||||
CharCmp cmp = new CharCmp(); | CharCmp cmp = new CharCmp(); | ||||
MyersDiff<CharArray> myersDiff = null; | |||||
int D = 0; | |||||
int cpuTimeChanges = 0; | int cpuTimeChanges = 0; | ||||
long lastReadout = 0; | long lastReadout = 0; | ||||
long interimTime = 0; | long interimTime = 0; | ||||
int repetitions = 0; | int repetitions = 0; | ||||
stopwatch.start(); | stopwatch.start(); | ||||
while (cpuTimeChanges < minCPUTimerTicks && interimTime < longTaskBoundary) { | while (cpuTimeChanges < minCPUTimerTicks && interimTime < longTaskBoundary) { | ||||
myersDiff = new MyersDiff<CharArray>(cmp, ac, bc); | |||||
D = MyersDiff.INSTANCE.diff(cmp, ac, bc).size(); | |||||
repetitions++; | repetitions++; | ||||
interimTime = stopwatch.readout(); | interimTime = stopwatch.readout(); | ||||
if (interimTime != lastReadout) { | if (interimTime != lastReadout) { | ||||
} | } | ||||
ret.runningTime = stopwatch.stop() / repetitions; | ret.runningTime = stopwatch.stop() / repetitions; | ||||
ret.N = ac.size() + bc.size(); | ret.N = ac.size() + bc.size(); | ||||
ret.D = myersDiff.getEdits().size(); | |||||
ret.D = D; | |||||
return ret; | return ret; | ||||
} | } |
} | } | ||||
public void assertDiff(String a, String b, String edits) { | public void assertDiff(String a, String b, String edits) { | ||||
MyersDiff diff = new MyersDiff<CharArray>(new CharCmp(), | |||||
EditList editList = MyersDiff.INSTANCE.diff(new CharCmp(), | |||||
toCharArray(a), toCharArray(b)); | toCharArray(a), toCharArray(b)); | ||||
assertEquals(edits, toString(diff.getEdits())); | |||||
assertEquals(edits, toString(editList)); | |||||
} | } | ||||
private static String toString(EditList list) { | private static String toString(EditList list) { |
/* | |||||
* Copyright (C) 2010, Google Inc. | |||||
* and other copyright owners as documented in the project's IP log. | |||||
* | |||||
* This program and the accompanying materials are made available | |||||
* under the terms of the Eclipse Distribution License v1.0 which | |||||
* accompanies this distribution, is reproduced below, and is | |||||
* available at http://www.eclipse.org/org/documents/edl-v10.php | |||||
* | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or | |||||
* without modification, are permitted provided that the following | |||||
* conditions are met: | |||||
* | |||||
* - Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* - Redistributions in binary form must reproduce the above | |||||
* copyright notice, this list of conditions and the following | |||||
* disclaimer in the documentation and/or other materials provided | |||||
* with the distribution. | |||||
* | |||||
* - Neither the name of the Eclipse Foundation, Inc. nor the | |||||
* names of its contributors may be used to endorse or promote | |||||
* products derived from this software without specific prior | |||||
* written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | |||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package org.eclipse.jgit.diff; | |||||
/** | |||||
* Compares two {@link Sequence}s to create an {@link EditList} of changes. | |||||
* | |||||
* An algorithm's {@code diff} method must be callable from concurrent threads | |||||
* without data collisions. This permits some algorithms to use a singleton | |||||
* pattern, with concurrent invocations using the same singleton. Other | |||||
* algorithms may support parameterization, in which case the caller can create | |||||
* a unique instance per thread. | |||||
*/ | |||||
public interface DiffAlgorithm { | |||||
/** | |||||
* Compare two sequences and identify a list of edits between them. | |||||
* | |||||
* @param <S> | |||||
* type of sequence being compared. | |||||
* @param <C> | |||||
* type of comparator to evaluate the sequence elements. | |||||
* @param cmp | |||||
* the comparator supplying the element equivalence function. | |||||
* @param a | |||||
* the first (also known as old or pre-image) sequence. Edits | |||||
* returned by this algorithm will reference indexes using the | |||||
* 'A' side: {@link Edit#getBeginA()}, {@link Edit#getEndA()}. | |||||
* @param b | |||||
* the second (also known as new or post-image) sequence. Edits | |||||
* returned by this algorithm will reference indexes using the | |||||
* 'B' side: {@link Edit#getBeginB()}, {@link Edit#getEndB()}. | |||||
* @return a modifiable edit list comparing the two sequences. If empty, the | |||||
* sequences are identical according to {@code cmp}'s rules. The | |||||
* result list is never null. | |||||
*/ | |||||
public <S extends Sequence, C extends SequenceComparator<? super S>> EditList diff( | |||||
C cmp, S a, S b); | |||||
} |
private int abbreviationLength = 7; | private int abbreviationLength = 7; | ||||
private DiffAlgorithm diffAlgorithm = MyersDiff.INSTANCE; | |||||
private RawTextComparator comparator = RawTextComparator.DEFAULT; | private RawTextComparator comparator = RawTextComparator.DEFAULT; | ||||
private int binaryFileThreshold = DEFAULT_BINARY_FILE_THRESHOLD; | private int binaryFileThreshold = DEFAULT_BINARY_FILE_THRESHOLD; | ||||
abbreviationLength = count; | abbreviationLength = count; | ||||
} | } | ||||
/** | |||||
* Set the algorithm that constructs difference output. | |||||
* | |||||
* @param alg | |||||
* the algorithm to produce text file differences. | |||||
* @see MyersDiff#INSTANCE | |||||
*/ | |||||
public void setDiffAlgorithm(DiffAlgorithm alg) { | |||||
diffAlgorithm = alg; | |||||
} | |||||
/** | /** | ||||
* Set the line equivalence function for text file differences. | * Set the line equivalence function for text file differences. | ||||
* | * | ||||
} | } | ||||
private EditList diff(RawText a, RawText b) { | private EditList diff(RawText a, RawText b) { | ||||
return new MyersDiff<RawText>(comparator, a, b).getEdits(); | |||||
return diffAlgorithm.diff(comparator, a, b); | |||||
} | } | ||||
private void assertHaveRepository() { | private void assertHaveRepository() { |
* type of sequence. | * type of sequence. | ||||
*/ | */ | ||||
public class MyersDiff<S extends Sequence> { | public class MyersDiff<S extends Sequence> { | ||||
/** Singleton instance of MyersDiff. */ | |||||
public static final DiffAlgorithm INSTANCE = new DiffAlgorithm() { | |||||
public <S extends Sequence, C extends SequenceComparator<? super S>> EditList diff( | |||||
C cmp, S a, S b) { | |||||
return new MyersDiff<S>(cmp, a, b).getEdits(); | |||||
} | |||||
}; | |||||
/** | /** | ||||
* The list of edits found during the last call to {@link #calculateEdits()} | * The list of edits found during the last call to {@link #calculateEdits()} | ||||
*/ | */ | ||||
protected EditList edits; | protected EditList edits; | ||||
/** Comparison function for sequences. */ | /** Comparison function for sequences. */ | ||||
protected SequenceComparator<S> cmp; | |||||
protected SequenceComparator<? super S> cmp; | |||||
/** | /** | ||||
* The first text to be compared. Referred to as "Text A" in the comments | * The first text to be compared. Referred to as "Text A" in the comments | ||||
*/ | */ | ||||
protected S b; | protected S b; | ||||
/** | |||||
* The only constructor | |||||
* | |||||
* @param cmp comparison method for this execution. | |||||
* @param a the text A which should be compared | |||||
* @param b the text B which should be compared | |||||
*/ | |||||
public MyersDiff(SequenceComparator<S> cmp, S a, S b) { | |||||
private MyersDiff(SequenceComparator<? super S> cmp, S a, S b) { | |||||
this.cmp = cmp; | this.cmp = cmp; | ||||
this.a = a; | this.a = a; | ||||
this.b = b; | this.b = b; |
sequences.add(ours); | sequences.add(ours); | ||||
sequences.add(theirs); | sequences.add(theirs); | ||||
MergeResult result = new MergeResult<S>(sequences); | MergeResult result = new MergeResult<S>(sequences); | ||||
EditList oursEdits = new MyersDiff<S>(cmp, base, ours).getEdits(); | |||||
EditList oursEdits = MyersDiff.INSTANCE.diff(cmp, base, ours); | |||||
Iterator<Edit> baseToOurs = oursEdits.iterator(); | Iterator<Edit> baseToOurs = oursEdits.iterator(); | ||||
EditList theirsEdits = new MyersDiff<S>(cmp, base, theirs).getEdits(); | |||||
EditList theirsEdits = MyersDiff.INSTANCE.diff(cmp, base, theirs); | |||||
Iterator<Edit> baseToTheirs = theirsEdits.iterator(); | Iterator<Edit> baseToTheirs = theirsEdits.iterator(); | ||||
int current = 0; // points to the next line (first line is 0) of base | int current = 0; // points to the next line (first line is 0) of base | ||||
// which was not handled yet | // which was not handled yet |