1 11 package org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.List ; 16 17 import org.eclipse.core.runtime.Assert; 18 import org.eclipse.core.runtime.IProgressMonitor; 19 20 21 import org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.LinkedRangeFactory.LowMemoryException; 22 23 45 public final class RangeDifferencer { 46 47 private static final RangeDifference[] EMPTY_RESULT= new RangeDifference[0]; 48 49 52 private RangeDifferencer() { 53 } 54 55 64 public static RangeDifference[] findDifferences(IRangeComparator left, IRangeComparator right) { 65 return findDifferences((IProgressMonitor)null, left, right); 66 } 67 68 79 private static RangeDifference[] findDifferences(IProgressMonitor pm, IRangeComparator left, IRangeComparator right) { 80 try { 81 return findDifferencesUkkonen(pm, left, right); 82 } catch (LowMemoryException e) { 83 return Levenshtein.findDifferences(pm, left, right); 84 } 85 } 86 87 99 private static RangeDifference[] findDifferencesUkkonen(IProgressMonitor pm, IRangeComparator left, IRangeComparator right) throws LowMemoryException { 100 101 Assert.isTrue(right.getClass().equals(left.getClass())); 103 104 int rightSize= right.getRangeCount(); 105 int leftSize= left.getRangeCount(); 106 int diagLen= 2 * Math.max(rightSize, leftSize); int maxDiagonal= diagLen; 112 int lastDiagonal[]= new int[diagLen + 1]; Arrays.fill(lastDiagonal, -1); 114 int origin= diagLen / 2; 117 LinkedRangeDifference script[]= new LinkedRangeDifference[diagLen + 1]; 119 int row, col; 120 121 for (row= 0; row < rightSize && row < leftSize && rangesEqual(right, row, left, row); ++row) { 123 } 125 126 lastDiagonal[origin]= row; 127 script[origin]= null; 128 int lower= (row == rightSize) ? origin + 1 : origin - 1; 129 int upper= (row == leftSize) ? origin - 1 : origin + 1; 130 131 if (lower > upper) 132 return EMPTY_RESULT; 133 134 LinkedRangeFactory factory= new LinkedRangeFactory(); 136 137 for (int d= 1; d <= maxDiagonal; ++d) { 140 if (pm != null) 141 pm.worked(1); 142 143 if (right.skipRangeComparison(d, maxDiagonal, left)) 144 return EMPTY_RESULT; 146 for (int k= lower; k <= upper; k += 2) { LinkedRangeDifference edit; 149 150 if (pm != null && pm.isCanceled()) 151 return EMPTY_RESULT; 152 153 if (k == origin - d || k != origin + d && lastDiagonal[k + 1] >= lastDiagonal[k - 1]) { 154 row= lastDiagonal[k + 1] + 1; 158 edit= factory.newRange(script[k + 1], LinkedRangeDifference.DELETE); 159 } else { 160 row= lastDiagonal[k - 1]; 164 edit= factory.newRange(script[k - 1], LinkedRangeDifference.INSERT); 165 } 166 col= row + k - origin; 167 edit.fRightStart= row; 168 edit.fLeftStart= col; 169 Assert.isTrue(k >= 0 && k <= maxDiagonal); 170 script[k]= edit; 171 172 while (row < rightSize && col < leftSize && rangesEqual(right, row, left, col) == true) { 174 ++row; 175 ++col; 176 } 177 178 Assert.isTrue(k >= 0 && k <= maxDiagonal); lastDiagonal[k]= row; 180 181 if (row == rightSize && col == leftSize) { 182 return createDifferencesRanges(script[k]); 184 } 185 if (row == rightSize) 186 lower= k + 2; 187 if (col == leftSize) 188 upper= k - 2; 189 } 190 --lower; 191 ++upper; 192 } 193 Assert.isTrue(false); 195 return null; 196 } 197 198 207 public static List findRanges(IRangeComparator left, IRangeComparator right) { 208 return findRanges((IProgressMonitor)null, left, right); 209 } 210 211 222 public static List findRanges(IProgressMonitor pm, IRangeComparator left, IRangeComparator right) { 223 RangeDifference[] in= findDifferences(pm, left, right); 224 List out= new ArrayList (); 225 226 RangeDifference rd; 227 228 int mstart= 0; 229 int ystart= 0; 230 231 for (int i= 0; i < in.length; i++) { 232 RangeDifference es= in[i]; 233 234 rd= new RangeDifference(RangeDifference.NOCHANGE, mstart, es.rightStart() - mstart, ystart, es.leftStart() - ystart); 235 if (rd.maxLength() != 0) 236 out.add(rd); 237 238 out.add(es); 239 240 mstart= es.rightEnd(); 241 ystart= es.leftEnd(); 242 } 243 rd= new RangeDifference(RangeDifference.NOCHANGE, mstart, right.getRangeCount() - mstart, ystart, left.getRangeCount() - ystart); 244 if (rd.maxLength() > 0) 245 out.add(rd); 246 247 return out; 248 } 249 250 252 261 private static RangeDifference[] createDifferencesRanges(LinkedRangeDifference start) { 262 263 LinkedRangeDifference ep= reverseDifferences(start); 264 ArrayList result= new ArrayList (); 265 RangeDifference es= null; 266 267 while (ep != null) { 268 es= new RangeDifference(RangeDifference.CHANGE); 269 270 if (ep.isInsert()) { 271 es.fRightStart= ep.fRightStart + 1; 272 es.fLeftStart= ep.fLeftStart; 273 RangeDifference b= ep; 274 do { 275 ep= ep.getNext(); 276 es.fLeftLength++; 277 } while (ep != null && ep.isInsert() && ep.fRightStart == b.fRightStart); 278 } else { 279 es.fRightStart= ep.fRightStart; 280 es.fLeftStart= ep.fLeftStart; 281 282 RangeDifference a= ep; 283 do { 287 a= ep; 288 ep= ep.getNext(); 289 es.fRightLength++; 290 } while (ep != null && ep.isDelete() && ep.fRightStart == a.fRightStart + 1); 291 292 boolean change= (ep != null && ep.isInsert() && ep.fRightStart == a.fRightStart); 293 294 if (change) { 295 RangeDifference b= ep; 296 do { 300 ep= ep.getNext(); 301 es.fLeftLength++; 302 } while (ep != null && ep.isInsert() && ep.fRightStart == b.fRightStart); 303 } else { 304 es.fLeftLength= 0; 305 } 306 es.fLeftStart++; 308 } 309 es.fRightStart--; 313 es.fLeftStart--; 314 result.add(es); 315 } 316 return (RangeDifference[]) result.toArray(EMPTY_RESULT); 317 } 318 319 328 private static boolean rangesEqual(IRangeComparator a, int ai, IRangeComparator b, int bi) { 329 return a.rangesEqual(ai, b, bi); 330 } 331 332 339 private static LinkedRangeDifference reverseDifferences(LinkedRangeDifference start) { 340 LinkedRangeDifference ep, behind, ahead; 341 342 ahead= start; 343 ep= null; 344 while (ahead != null) { 345 behind= ep; 346 ep= ahead; 347 ahead= ahead.getNext(); 348 ep.setNext(behind); 349 } 350 return ep; 351 } 352 } 353 354 | Popular Tags |