blob: 7fc7162f27edfa7ab70625e0dda7e60c396e0afb [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.diff;
import java.util.Arrays;
import java.util.BitSet;
/**
* @author dyoma
*/
class IntLCS {
private final int[] myFirst;
private final int[] mySecond;
private final int myStart1;
private final int myStart2;
private final LinkedDiffPaths myPathsMatrix;
private final int[] myPrevPathKey;
private int[] myPrevEnds;
private int[] myCurrentEnds;
private final int myMaxX;
private final int myMaxY;
private final BitSet myChanges1;
private final BitSet myChanges2;
public IntLCS(int[] first, int[] second) {
this(first, second, 0, first.length, 0, second.length, new BitSet(first.length), new BitSet(second.length));
}
public IntLCS(int[] first, int[] second, int start1, int count1, int start2, int count2, BitSet changes1, BitSet changes2) {
myFirst = first;
mySecond = second;
myStart1 = start1;
myStart2 = start2;
myMaxX = count1;
myMaxY = count2;
myChanges1 = changes1;
myChanges2 = changes2;
myPathsMatrix = new LinkedDiffPaths(myMaxX, myMaxY);
myPrevPathKey = new int[myMaxX + myMaxY + 1];
Arrays.fill(myPrevPathKey, -1);
myPrevEnds = new int[myMaxX + myMaxY + 1];
myCurrentEnds = new int[myMaxX + myMaxY + 1];
}
public int execute() throws FilesTooBigForDiffException {
for (int d =0; d <= myMaxX + myMaxY; d++) {
int minDiag = -calcBound(myMaxY, d);
int maxDiag = calcBound(myMaxX, d);
if (d != 0)
System.arraycopy(myPrevEnds, minDiag + myMaxY, myCurrentEnds, minDiag + myMaxY, maxDiag - minDiag);
else {
int end = skipEquals(0, 0);
if (end > 0) {
int xy = (end) - 1;
myPrevPathKey[myMaxY] = myPathsMatrix.encodeStep(xy, xy, end, false, -1);
}
if (myMaxX == myMaxY && end == myMaxX) return 0;
myPrevEnds[myMaxY] = end;
continue;
}
for (int k = minDiag; k <= maxDiag; k += 2) {
int end;
if (k == -d) {
int prevEndV = myPrevEnds[k + 1 + myMaxY];
int vertical = findDiagonalEnd(k + 1, prevEndV, true);
end = encodeStep(prevEndV, vertical, k, true);
} else if (k == d) {
int prevEndH = myPrevEnds[k - 1 + myMaxY];
int horisontal = findDiagonalEnd(k - 1, prevEndH, false);
end = encodeStep(prevEndH, horisontal, k, false);
} else {
int prevEndH = myPrevEnds[k - 1 + myMaxY];
int prevEndV = myPrevEnds[k + 1 + myMaxY];
if (prevEndH+1 > prevEndV) {
int horisontal = findDiagonalEnd(k - 1, prevEndH, false);
end = encodeStep(prevEndH, horisontal, k, false);
} else {
int vertical = findDiagonalEnd(k + 1, prevEndV, true);
end = encodeStep(prevEndV, vertical, k, true);
}
}
myCurrentEnds[k + myMaxY] = end;
if (k == myMaxX - myMaxY && end == myMaxX) {
myPathsMatrix.applyChanges(myStart1, myStart2, myChanges1, myChanges2);
return d;
}
}
int[] temps = myCurrentEnds;
myCurrentEnds = myPrevEnds;
myPrevEnds = temps;
}
throw new RuntimeException();
}
public BitSet[] getChanges() {
return new BitSet[]{myChanges1, myChanges2};
}
private int findDiagonalEnd(int prevDiagonal, int prevEnd, boolean isVertical) {
int x = prevEnd;
int y = x - prevDiagonal;
if (isVertical) y++;
else x++;
return skipEquals(x, y);
}
private int encodeStep(int prevEnd, int diagLength, int tDiagonal, boolean afterVertical) throws FilesTooBigForDiffException {
int end = prevEnd + diagLength;
int prevDiagonal = tDiagonal + myMaxY;
if (!afterVertical) end++;
if (afterVertical) prevDiagonal++;
else prevDiagonal--;
int x = end - 1;
int y = x - tDiagonal;
if (x == -1 || y == -1 || x >= myMaxX || y >= myMaxY) return end;
myPrevPathKey[tDiagonal + myMaxY] = myPathsMatrix.encodeStep(x, y, diagLength, afterVertical, myPrevPathKey[prevDiagonal]);
return end;
}
private int calcBound(int bound, int d) {
return (d <= bound) ? d : 2 * bound - d;
}
private int skipEquals(int x, int y) {
int skipped = 0;
while (x < myMaxX && y < myMaxY && myFirst[myStart1 + x] == mySecond[myStart2 + y]) {
skipped += 1;
x++;
y++;
}
return skipped;
}
}