From faf295c43c2dd85fec519a03b6cad8aff5161cdc Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 21 Mar 2018 19:25:07 +0300 Subject: [PATCH] diff: use LineOffsets instead of helper List --- .../comparison/ComparisonManagerImpl.java | 212 ++++++++---------- .../com/intellij/diff/comparison/TrimUtil.kt | 15 +- 2 files changed, 106 insertions(+), 121 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java index 2ef74e856fbe..58583c3d12ff 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ComparisonManagerImpl.java @@ -19,6 +19,8 @@ import com.intellij.diff.comparison.iterables.DiffIterable; import com.intellij.diff.comparison.iterables.DiffIterableUtil; import com.intellij.diff.comparison.iterables.FairDiffIterable; import com.intellij.diff.fragments.*; +import com.intellij.diff.tools.util.text.LineOffsets; +import com.intellij.diff.tools.util.text.LineOffsetsUtil; import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.IntPair; import com.intellij.diff.util.MergeRange; @@ -56,14 +58,14 @@ public class ComparisonManagerImpl extends ComparisonManager { @NotNull CharSequence text2, @NotNull ComparisonPolicy policy, @NotNull ProgressIndicator indicator) throws DiffTooBigException { - List lines1 = getLines(text1); - List lines2 = getLines(text2); + LineOffsets lineOffsets1 = LineOffsetsUtil.create(text1); + LineOffsets lineOffsets2 = LineOffsetsUtil.create(text2); - List lineTexts1 = ContainerUtil.map(lines1, Line::getContent); - List lineTexts2 = ContainerUtil.map(lines2, Line::getContent); + List lineTexts1 = getLineContents(text1, lineOffsets1); + List lineTexts2 = getLineContents(text2, lineOffsets2); FairDiffIterable iterable = ByLine.compare(lineTexts1, lineTexts2, policy, indicator); - return convertIntoLineFragments(lines1, lines2, iterable); + return convertIntoLineFragments(lineOffsets1, lineOffsets2, iterable); } @NotNull @@ -73,13 +75,13 @@ public class ComparisonManagerImpl extends ComparisonManager { @NotNull CharSequence text3, @NotNull ComparisonPolicy policy, @NotNull ProgressIndicator indicator) throws DiffTooBigException { - List lines1 = getLines(text1); - List lines2 = getLines(text2); - List lines3 = getLines(text3); + LineOffsets lineOffsets1 = LineOffsetsUtil.create(text1); + LineOffsets lineOffsets2 = LineOffsetsUtil.create(text2); + LineOffsets lineOffsets3 = LineOffsetsUtil.create(text3); - List lineTexts1 = ContainerUtil.map(lines1, Line::getContent); - List lineTexts2 = ContainerUtil.map(lines2, Line::getContent); - List lineTexts3 = ContainerUtil.map(lines3, Line::getContent); + List lineTexts1 = getLineContents(text1, lineOffsets1); + List lineTexts2 = getLineContents(text2, lineOffsets2); + List lineTexts3 = getLineContents(text3, lineOffsets3); List ranges = ByLine.compare(lineTexts1, lineTexts2, lineTexts3, policy, indicator); return convertIntoMergeLineFragments(ranges); @@ -226,13 +228,13 @@ public class ComparisonManagerImpl extends ComparisonManager { } @NotNull - public static List convertIntoLineFragments(@NotNull List lines1, - @NotNull List lines2, + public static List convertIntoLineFragments(@NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, @NotNull FairDiffIterable changes) { List fragments = new ArrayList<>(); for (Range ch : changes.iterateChanges()) { - IntPair offsets1 = getOffsets(lines1, ch.start1, ch.end1); - IntPair offsets2 = getOffsets(lines2, ch.start2, ch.end2); + IntPair offsets1 = getOffsets(lineOffsets1, ch.start1, ch.end1); + IntPair offsets2 = getOffsets(lineOffsets2, ch.start2, ch.end2); fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2)); @@ -241,20 +243,20 @@ public class ComparisonManagerImpl extends ComparisonManager { } @NotNull - private static IntPair getOffsets(@NotNull List lines, int startIndex, int endIndex) { + private static IntPair getOffsets(@NotNull LineOffsets lineOffsets, int startIndex, int endIndex) { if (startIndex == endIndex) { int offset; - if (startIndex < lines.size()) { - offset = lines.get(startIndex).getOffset1(); + if (startIndex < lineOffsets.getLineCount()) { + offset = lineOffsets.getLineStart(startIndex); } else { - offset = lines.get(lines.size() - 1).getOffset2(); + offset = lineOffsets.getLineEnd(lineOffsets.getLineCount() - 1, true); } return new IntPair(offset, offset); } else { - int offset1 = lines.get(startIndex).getOffset1(); - int offset2 = lines.get(endIndex - 1).getOffset2(); + int offset1 = lineOffsets.getLineStart(startIndex); + int offset2 = lineOffsets.getLineEnd(endIndex - 1, true); return new IntPair(offset1, offset2); } } @@ -416,22 +418,29 @@ public class ComparisonManagerImpl extends ComparisonManager { } @NotNull - private static List getLines(@NotNull CharSequence text) { - List lines = new ArrayList<>(); - - int offset = 0; - while (true) { - int lineEnd = StringUtil.indexOf(text, '\n', offset); - if (lineEnd != -1) { - lines.add(new Line(text, offset, lineEnd, true)); - offset = lineEnd + 1; - } - else { - lines.add(new Line(text, offset, text.length(), false)); - break; - } + private static List getLineContents(@NotNull CharSequence text, @NotNull LineOffsets lineOffsets) { + List lines = new ArrayList<>(lineOffsets.getLineCount()); + for (int line = 0; line < lineOffsets.getLineCount(); line++) { + lines.add(new CharSequenceSubSequence(text, lineOffsets.getLineStart(line), lineOffsets.getLineEnd(line))); } + return lines; + } + @NotNull + private static List getNotIgnoredLineContents(@NotNull CharSequence text, + @NotNull LineOffsets lineOffsets, + @NotNull BitSet ignored) { + StringBuilder sb = new StringBuilder(); + + List lines = new ArrayList<>(lineOffsets.getLineCount()); + for (int line = 0; line < lineOffsets.getLineCount(); line++) { + for (int offset = lineOffsets.getLineStart(line); offset < lineOffsets.getLineEnd(line); offset++) { + if (ignored.get(offset)) continue; + sb.append(text.charAt(offset)); + } + lines.add(sb.toString()); + sb.setLength(0); + } return lines; } @@ -449,23 +458,25 @@ public class ComparisonManagerImpl extends ComparisonManager { BitSet ignored1 = collectIgnoredRanges(ignoredRanges1); BitSet ignored2 = collectIgnoredRanges(ignoredRanges2); - List lines1 = getLines(text1); - List lines2 = getLines(text2); + LineOffsets lineOffsets1 = LineOffsetsUtil.create(text1); + LineOffsets lineOffsets2 = LineOffsetsUtil.create(text2); + + List lineTexts1 = getNotIgnoredLineContents(text1, lineOffsets1, ignored1); + List lineTexts2 = getNotIgnoredLineContents(text2, lineOffsets2, ignored2); - List lineTexts1 = ContainerUtil.map(lines1, line -> line.getNotIgnoredContent(ignored1)); - List lineTexts2 = ContainerUtil.map(lines2, line -> line.getNotIgnoredContent(ignored2)); FairDiffIterable iterable = ByLine.compare(lineTexts1, lineTexts2, ComparisonPolicy.DEFAULT, indicator); - FairDiffIterable correctedIterable = correctIgnoredRangesSecondStep(iterable, lines1, lines2, ignored1, ignored2); + FairDiffIterable correctedIterable = correctIgnoredRangesSecondStep(iterable, text1, text2, lineOffsets1, lineOffsets2, + ignored1, ignored2); - List lineFragments = convertIntoLineFragments(lines1, lines2, correctedIterable); + List lineFragments = convertIntoLineFragments(lineOffsets1, lineOffsets2, correctedIterable); if (innerFragments) { lineFragments = createInnerFragments(lineFragments, text1, text2, ComparisonPolicy.DEFAULT, indicator); } return ContainerUtil.mapNotNull(lineFragments, fragment -> { - return trimIgnoredChanges(fragment, lines1, lines2, ignored1, ignored2); + return trimIgnoredChanges(fragment, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2); }); } @@ -480,17 +491,19 @@ public class ComparisonManagerImpl extends ComparisonManager { @NotNull private static FairDiffIterable correctIgnoredRangesSecondStep(@NotNull FairDiffIterable iterable, - @NotNull List lines1, - @NotNull List lines2, + @NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, @NotNull BitSet ignored1, @NotNull BitSet ignored2) { - DiffIterableUtil.ChangeBuilder builder = new DiffIterableUtil.ChangeBuilder(lines1.size(), lines2.size()); + DiffIterableUtil.ChangeBuilder builder = new DiffIterableUtil.ChangeBuilder(lineOffsets1.getLineCount(), lineOffsets2.getLineCount()); for (Range range : iterable.iterateUnchanged()) { int count = range.end1 - range.start1; for (int i = 0; i < count; i++) { int index1 = range.start1 + i; int index2 = range.start2 + i; - if (areIgnoredEqualLines(lines1.get(index1), lines2.get(index2), ignored1, ignored2)) { + if (areIgnoredEqualLines(index1, index2, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2)) { builder.markEqual(index1, index2); } } @@ -500,17 +513,19 @@ public class ComparisonManagerImpl extends ComparisonManager { @Nullable private static LineFragment trimIgnoredChanges(@NotNull LineFragment fragment, - @NotNull List lines1, - @NotNull List lines2, + @NotNull CharSequence text1, + @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, + @NotNull LineOffsets lineOffsets2, @NotNull BitSet ignored1, @NotNull BitSet ignored2) { // trim ignored lines - Range range = TrimUtil.trimExpandList(lines1, lines2, - fragment.getStartLine1(), fragment.getStartLine2(), - fragment.getEndLine1(), fragment.getEndLine2(), - (line1, line2) -> areIgnoredEqualLines(line1, line2, ignored1, ignored2), - line -> isIgnoredLine(line, ignored1), - line -> isIgnoredLine(line, ignored2)); + Range range = TrimUtil.trimExpandRange(fragment.getStartLine1(), fragment.getStartLine2(), + fragment.getEndLine1(), fragment.getEndLine2(), + (index1, index2) -> areIgnoredEqualLines(index1, index2, text1, text2, lineOffsets1, lineOffsets2, + ignored1, ignored2), + index -> isIgnoredLine(index, lineOffsets1, ignored1), + index -> isIgnoredLine(index, lineOffsets2, ignored2)); int startLine1 = range.start1; int startLine2 = range.start2; @@ -519,8 +534,8 @@ public class ComparisonManagerImpl extends ComparisonManager { if (startLine1 == endLine1 && startLine2 == endLine2) return null; - IntPair offsets1 = getOffsets(lines1, startLine1, endLine1); - IntPair offsets2 = getOffsets(lines2, startLine2, endLine2); + IntPair offsets1 = getOffsets(lineOffsets1, startLine1, endLine1); + IntPair offsets2 = getOffsets(lineOffsets2, startLine2, endLine2); int startOffset1 = offsets1.val1; int endOffset1 = offsets1.val2; int startOffset2 = offsets2.val1; @@ -556,28 +571,30 @@ public class ComparisonManagerImpl extends ComparisonManager { newInner); } - private static boolean isIgnoredLine(@NotNull Line line, @NotNull BitSet ignored) { - return isIgnoredRange(ignored, line.getOffset1(), line.getOffset2()); + private static boolean isIgnoredLine(int index, @NotNull LineOffsets lineOffsets, @NotNull BitSet ignored) { + return isIgnoredRange(ignored, lineOffsets.getLineStart(index), lineOffsets.getLineEnd(index, true)); } - private static boolean areIgnoredEqualLines(@NotNull Line line1, @NotNull Line line2, + private static boolean areIgnoredEqualLines(int index1, int index2, + @NotNull CharSequence text1, @NotNull CharSequence text2, + @NotNull LineOffsets lineOffsets1, @NotNull LineOffsets lineOffsets2, @NotNull BitSet ignored1, @NotNull BitSet ignored2) { - int start1 = line1.getOffset1(); - int end1 = line1.getOffset2(); - int start2 = line2.getOffset1(); - int end2 = line2.getOffset2(); - Range range = TrimUtil.trimExpandText(line1.getOriginalText(), line2.getOriginalText(), + int start1 = lineOffsets1.getLineStart(index1); + int end1 = lineOffsets1.getLineEnd(index1, true); + int start2 = lineOffsets2.getLineStart(index2); + int end2 = lineOffsets2.getLineEnd(index2, true); + Range range = TrimUtil.trimExpandText(text1, text2, start1, start2, end1, end2, ignored1, ignored2); if (!range.isEmpty()) return false; - List words1 = getNonIgnoredWords(line1, ignored1); - List words2 = getNonIgnoredWords(line2, ignored2); + List words1 = getNonIgnoredWords(index1, text1, lineOffsets1, ignored1); + List words2 = getNonIgnoredWords(index2, text2, lineOffsets2, ignored2); if (words1.size() != words2.size()) return false; for (int i = 0; i < words1.size(); i++) { - CharSequence word1 = getWordContent(line1, words1.get(i)); - CharSequence word2 = getWordContent(line2, words2.get(i)); + CharSequence word1 = getWordContent(index1, text1, lineOffsets1, words1.get(i)); + CharSequence word2 = getWordContent(index2, text2, lineOffsets2, words2.get(i)); if (!StringUtil.equals(word1, word2)) return false; } @@ -585,16 +602,22 @@ public class ComparisonManagerImpl extends ComparisonManager { } @NotNull - private static List getNonIgnoredWords(@NotNull Line line, @NotNull BitSet ignored) { - int offset = line.getOffset1(); - List innerChunks = ByWord.getInlineChunks(line.getContent()); + private static List getNonIgnoredWords(int index, + @NotNull CharSequence text, + @NotNull LineOffsets lineOffsets, + @NotNull BitSet ignored) { + int offset = lineOffsets.getLineStart(index); + List innerChunks = ByWord.getInlineChunks(getLineContent(index, text, lineOffsets)); return ContainerUtil.filter(innerChunks, it -> it instanceof ByWord.WordChunk && !isIgnoredRange(ignored, offset + it.getOffset1(), offset + it.getOffset2())); } @NotNull - private static CharSequence getWordContent(@NotNull Line line, @NotNull ByWord.InlineChunk word) { - return line.getContent().subSequence(word.getOffset1(), word.getOffset2()); + private static CharSequence getWordContent(int index, + @NotNull CharSequence text, + @NotNull LineOffsets lineOffsets, + @NotNull ByWord.InlineChunk word) { + return getLineContent(index, text, lineOffsets).subSequence(word.getOffset1(), word.getOffset2()); } @NotNull @@ -607,45 +630,8 @@ public class ComparisonManagerImpl extends ComparisonManager { return ignored.nextClearBit(start) >= end; } - private static class Line { - @NotNull private final CharSequence myChars; - private final int myOffset1; - private final int myOffset2; - private final boolean myNewline; - - public Line(@NotNull CharSequence chars, int offset1, int offset2, boolean newline) { - myChars = chars; - myOffset1 = offset1; - myOffset2 = offset2; - myNewline = newline; - } - - public int getOffset1() { - return myOffset1; - } - - public int getOffset2() { - return myOffset2 + (myNewline ? 1 : 0); - } - - @NotNull - public CharSequence getContent() { - return new CharSequenceSubSequence(myChars, myOffset1, myOffset2); - } - - @NotNull - public CharSequence getNotIgnoredContent(@NotNull BitSet ignored) { - StringBuilder sb = new StringBuilder(); - for (int i = myOffset1; i < myOffset2; i++) { - if (ignored.get(i)) continue; - sb.append(myChars.charAt(i)); - } - return sb.toString(); - } - - @NotNull - public CharSequence getOriginalText() { - return myChars; - } + @NotNull + private static CharSequence getLineContent(int index, @NotNull CharSequence text, @NotNull LineOffsets lineOffsets) { + return text.subSequence(lineOffsets.getLineStart(index), lineOffsets.getLineEnd(index, true)); } } diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt index 73ca73a629b8..f088196110f1 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt +++ b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt @@ -170,15 +170,14 @@ fun expandWhitespacesBackward(text1: CharSequence, text2: CharSequence, text3: C } -fun trimExpandList(text1: List, text2: List, - start1: Int, start2: Int, end1: Int, end2: Int, - equals: (T, T) -> Boolean, - ignored1: (T) -> Boolean, - ignored2: (T) -> Boolean): Range { +fun trimExpandRange(start1: Int, start2: Int, end1: Int, end2: Int, + equals: (Int, Int) -> Boolean, + ignored1: (Int) -> Boolean, + ignored2: (Int) -> Boolean): Range { return trimExpand(start1, start2, end1, end2, - { index1, index2 -> equals(text1[index1], text2[index2]) }, - { index -> ignored1(text1[index]) }, - { index -> ignored2(text2[index]) }) + { index1, index2 -> equals(index1, index2) }, + { index -> ignored1(index) }, + { index -> ignored2(index) }) } fun trimExpandText(text1: CharSequence, text2: CharSequence,