/* * Creates a <code>RangeDifference3</code> given the state of two * DifferenceIterators. */ private static RangeDifference createRangeDifference3( DifferencesIterator myIter, DifferencesIterator yourIter, List diff3, IRangeComparator right, IRangeComparator left, int changeRangeStart, int changeRangeEnd) { int rightStart, rightEnd; int leftStart, leftEnd; int kind = RangeDifference.ERROR; RangeDifference last = (RangeDifference) diff3.get(diff3.size() - 1); Assert.isTrue((myIter.getCount() != 0 || yourIter.getCount() != 0)); // At // least // one // range // array // must // be // non-empty // // find corresponding lines to fChangeRangeStart/End in right and left // if (myIter.getCount() == 0) { // only left changed rightStart = changeRangeStart - last.ancestorEnd() + last.rightEnd(); rightEnd = changeRangeEnd - last.ancestorEnd() + last.rightEnd(); kind = RangeDifference.LEFT; } else { RangeDifference f = (RangeDifference) myIter.fRange.get(0); RangeDifference l = (RangeDifference) myIter.fRange.get(myIter.fRange.size() - 1); rightStart = changeRangeStart - f.fLeftStart + f.fRightStart; rightEnd = changeRangeEnd - l.leftEnd() + l.rightEnd(); } if (yourIter.getCount() == 0) { // only right changed leftStart = changeRangeStart - last.ancestorEnd() + last.leftEnd(); leftEnd = changeRangeEnd - last.ancestorEnd() + last.leftEnd(); kind = RangeDifference.RIGHT; } else { RangeDifference f = (RangeDifference) yourIter.fRange.get(0); RangeDifference l = (RangeDifference) yourIter.fRange.get(yourIter.fRange.size() - 1); leftStart = changeRangeStart - f.fLeftStart + f.fRightStart; leftEnd = changeRangeEnd - l.leftEnd() + l.rightEnd(); } if (kind == RangeDifference.ERROR) { // overlapping change (conflict) // -> compare the changed ranges if (rangeSpansEqual( right, rightStart, rightEnd - rightStart, left, leftStart, leftEnd - leftStart)) kind = RangeDifference.ANCESTOR; else kind = RangeDifference.CONFLICT; } return new RangeDifference( kind, rightStart, rightEnd - rightStart, leftStart, leftEnd - leftStart, changeRangeStart, changeRangeEnd - changeRangeStart); }
/** * Finds the differences among three <code>IRangeComparator</code>s. The differences are returned * as a list of <code>RangeDifference</code>s. If no differences are detected an empty list is * returned. If the ancestor range comparator is <code>null</code>, a two-way comparison is * performed. * * @param pm if not <code>null</code> used to report progress * @param ancestor the ancestor range comparator or <code>null</code> * @param left the left range comparator * @param right the right range comparator * @return an array of range differences, or an empty array if no differences were found * @since 2.0 */ public static RangeDifference[] findDifferences( IProgressMonitor pm, LCSSettings settings, IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) { try { if (ancestor == null) return findDifferences(pm, settings, left, right); SubMonitor monitor = SubMonitor.convert(pm, CompareMessages.RangeComparatorLCS_0, 100); RangeDifference[] leftAncestorScript = null; RangeDifference[] rightAncestorScript = findDifferences(monitor.newChild(50), settings, ancestor, right); if (rightAncestorScript != null) { monitor.setWorkRemaining(100); leftAncestorScript = findDifferences(monitor.newChild(50), settings, ancestor, left); } if (rightAncestorScript == null || leftAncestorScript == null) return null; DifferencesIterator myIter = new DifferencesIterator(rightAncestorScript); DifferencesIterator yourIter = new DifferencesIterator(leftAncestorScript); List diff3 = new ArrayList(); diff3.add(new RangeDifference(RangeDifference.ERROR)); // add a // sentinel int changeRangeStart = 0; int changeRangeEnd = 0; // // Combine the two two-way edit scripts into one // monitor.setWorkRemaining(rightAncestorScript.length + leftAncestorScript.length); while (myIter.fDifference != null || yourIter.fDifference != null) { DifferencesIterator startThread; myIter.removeAll(); yourIter.removeAll(); // // take the next diff that is closer to the start // if (myIter.fDifference == null) startThread = yourIter; else if (yourIter.fDifference == null) startThread = myIter; else { // not at end of both scripts take the lowest range if (myIter.fDifference.fLeftStart <= yourIter.fDifference.fLeftStart) // 2 // -> // common // (Ancestor) // change // range startThread = myIter; else startThread = yourIter; } changeRangeStart = startThread.fDifference.fLeftStart; changeRangeEnd = startThread.fDifference.leftEnd(); startThread.next(); monitor.worked(1); // // check for overlapping changes with other thread // merge overlapping changes with this range // DifferencesIterator other = startThread.other(myIter, yourIter); while (other.fDifference != null && other.fDifference.fLeftStart <= changeRangeEnd) { int newMax = other.fDifference.leftEnd(); other.next(); monitor.worked(1); if (newMax >= changeRangeEnd) { changeRangeEnd = newMax; other = other.other(myIter, yourIter); } } diff3.add( createRangeDifference3( myIter, yourIter, diff3, right, left, changeRangeStart, changeRangeEnd)); } // remove sentinel diff3.remove(0); return (RangeDifference[]) diff3.toArray(EMPTY_RESULT); } finally { if (pm != null) pm.done(); } }