less text range allocations during smart pointer update (IDEA-49250)

This commit is contained in:
peter
2015-10-29 16:17:03 +01:00
parent 356dd34269
commit 164db31997
5 changed files with 42 additions and 36 deletions
@@ -19,6 +19,7 @@ import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
import com.intellij.openapi.editor.impl.event.RetargetRangeMarkers;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,19 +28,21 @@ import org.jetbrains.annotations.Nullable;
* A range marker that has to be manually updated with {@link #getUpdatedRange(DocumentEvent, FrozenDocument)}.
* Can hold PSI-based range and be updated when the document is committed.
*/
public class ManualRangeMarker {
private final TextRange myRange;
public class ManualRangeMarker implements Segment {
private final int myStart;
private final int myEnd;
private final boolean myGreedyLeft;
private final boolean myGreedyRight;
private final boolean mySurviveOnExternalChange;
private final PersistentRangeMarker.LinesCols myLinesCols;
public ManualRangeMarker(@NotNull TextRange range,
public ManualRangeMarker(int start, int end,
boolean greedyLeft,
boolean greedyRight,
boolean surviveOnExternalChange,
@Nullable PersistentRangeMarker.LinesCols linesCols) {
myRange = range;
myStart = start;
myEnd = end;
myGreedyLeft = greedyLeft;
myGreedyRight = greedyRight;
mySurviveOnExternalChange = surviveOnExternalChange;
@@ -50,34 +53,39 @@ public class ManualRangeMarker {
public ManualRangeMarker getUpdatedRange(@NotNull DocumentEvent event, @NotNull FrozenDocument documentBefore) {
if (event instanceof RetargetRangeMarkers) {
int start = ((RetargetRangeMarkers)event).getStartOffset();
if (myRange.getStartOffset() >= start && myRange.getEndOffset() <= ((RetargetRangeMarkers)event).getEndOffset()) {
TextRange range = myRange.shiftRight(((RetargetRangeMarkers)event).getMoveDestinationOffset() - start);
return new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null);
if (myStart >= start && myEnd <= ((RetargetRangeMarkers)event).getEndOffset()) {
int delta = ((RetargetRangeMarkers)event).getMoveDestinationOffset() - start;
return new ManualRangeMarker(myStart + delta, myEnd + delta, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null);
}
}
if (mySurviveOnExternalChange && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, myRange)) {
if (mySurviveOnExternalChange && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, myStart, myEnd)) {
PersistentRangeMarker.LinesCols linesCols = myLinesCols != null ? myLinesCols
: PersistentRangeMarker.storeLinesAndCols(myRange, documentBefore);
: PersistentRangeMarker.storeLinesAndCols(documentBefore, myStart, myEnd);
Pair<TextRange, PersistentRangeMarker.LinesCols> pair =
linesCols == null ? null : PersistentRangeMarker.translateViaDiff((DocumentEventImpl)event, linesCols);
if (pair != null) {
return new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, true, pair.second);
return new ManualRangeMarker(pair.first.getStartOffset(), pair.first.getEndOffset(), myGreedyLeft, myGreedyRight, true, pair.second);
}
}
TextRange range = RangeMarkerImpl.applyChange(event, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight);
return range == null ? null : new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null);
TextRange range = RangeMarkerImpl.applyChange(event, myStart, myEnd, myGreedyLeft, myGreedyRight);
return range == null ? null : new ManualRangeMarker(range.getStartOffset(), range.getEndOffset(), myGreedyLeft, myGreedyRight, mySurviveOnExternalChange, null);
}
@NotNull
public TextRange getRange() {
return myRange;
@Override
public int getStartOffset() {
return myStart;
}
@Override
public int getEndOffset() {
return myEnd;
}
@Override
public String toString() {
return "ManualRangeMarker" + myRange;
return "ManualRangeMarker" + TextRange.create(this);
}
}
@@ -41,18 +41,17 @@ class PersistentRangeMarker extends RangeMarkerImpl {
PersistentRangeMarker(DocumentEx document, int startOffset, int endOffset, boolean register) {
super(document, startOffset, endOffset, register);
myLinesCols = ObjectUtils.assertNotNull(storeLinesAndCols(this, document));
myLinesCols = ObjectUtils.assertNotNull(storeLinesAndCols(document, getStartOffset(), getEndOffset()));
}
@Nullable
static LinesCols storeLinesAndCols(Segment range, Document myDocument) {
static LinesCols storeLinesAndCols(Document myDocument, int startOffset, int endOffset) {
int myStartLine;
int myStartColumn;
int myEndLine;
int myEndColumn;
// document might have been changed already
int startOffset = range.getStartOffset();
if (startOffset <= myDocument.getTextLength()) {
myStartLine = myDocument.getLineNumber(startOffset);
myStartColumn = startOffset - myDocument.getLineStartOffset(myStartLine);
@@ -63,7 +62,6 @@ class PersistentRangeMarker extends RangeMarkerImpl {
else {
return null;
}
int endOffset = range.getEndOffset();
if (endOffset <= myDocument.getTextLength()) {
myEndLine = myDocument.getLineNumber(endOffset);
myEndColumn = endOffset - myDocument.getLineStartOffset(myEndLine);
@@ -130,7 +128,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
@Nullable
private static Pair<TextRange, LinesCols> applyChange(DocumentEvent event, Segment range, int intervalStart, int intervalEnd, boolean greedyLeft, boolean greedyRight, LinesCols linesCols) {
final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, range);
final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, range.getStartOffset(), range.getEndOffset());
Pair<TextRange, LinesCols> translated = null;
if (shouldTranslateViaDiff) {
translated = translateViaDiff((DocumentEventImpl)event, linesCols);
@@ -139,7 +137,7 @@ class PersistentRangeMarker extends RangeMarkerImpl {
TextRange fallback = applyChange(event, intervalStart, intervalEnd, greedyLeft, greedyRight);
if (fallback == null) return null;
LinesCols lc = storeLinesAndCols(fallback, event.getDocument());
LinesCols lc = storeLinesAndCols(event.getDocument(), fallback.getStartOffset(), fallback.getEndOffset());
if (lc == null) return null;
translated = Pair.create(fallback, lc);
@@ -16,7 +16,6 @@
package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.util.Segment;
import org.jetbrains.annotations.NotNull;
/**
@@ -29,17 +28,18 @@ class PersistentRangeMarkerUtil {
* identified by the given event.
*
* @param e event that describes document change
* @param rangeMarker target range marker which update strategy should be selected
* @param rangeStart target range marker start, for which update strategy should be selected
* @param rangeEnd target range marker end
* @return <code>true</code> if target document range referenced by the given range marker should be translated via
* diff algorithm; <code>false</code> otherwise
*/
static boolean shouldTranslateViaDiff(@NotNull DocumentEvent e, @NotNull Segment rangeMarker) {
static boolean shouldTranslateViaDiff(@NotNull DocumentEvent e, int rangeStart, int rangeEnd) {
if (e.isWholeTextReplaced()) {
// Perform translation if the whole text is replaced.
return true;
}
if (e.getOffset() >= rangeMarker.getEndOffset() || e.getOffset() + e.getOldLength() <= rangeMarker.getStartOffset()) {
if (e.getOffset() >= rangeEnd || e.getOffset() + e.getOldLength() <= rangeStart) {
// Don't perform complex processing if the change doesn't affect target range.
return false;
}
@@ -21,8 +21,8 @@ import com.intellij.openapi.editor.impl.ManualRangeMarker;
import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
import com.intellij.openapi.editor.impl.event.RetargetRangeMarkers;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.UnfairTextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -94,11 +94,12 @@ class MarkerCache {
while (i < markers.length) {
SelfElementInfo info = infos.get(i);
boolean forInjected = info.isForInjected();
TextRange range = ObjectUtils.assertNotNull(info.getPsiRange());
markers[i] = new ManualRangeMarker(range, forInjected, forInjected, !forInjected, null);
int start = info.getPsiStartOffset();
int end = info.getPsiEndOffset();
markers[i] = new ManualRangeMarker(start, end, forInjected, forInjected, !forInjected, null);
i++;
while (i < markers.length && rangeEquals(infos.get(i), range, forInjected)) {
while (i < markers.length && rangeEquals(infos.get(i), start, end, forInjected)) {
markers[i] = markers[i - 1];
i++;
}
@@ -106,8 +107,8 @@ class MarkerCache {
return markers;
}
private static boolean rangeEquals(SelfElementInfo info, TextRange range, boolean injected) {
return range.getStartOffset() == info.getPsiStartOffset() && range.getEndOffset() == info.getPsiEndOffset() && injected == info.isForInjected();
private static boolean rangeEquals(SelfElementInfo info, int start, int end, boolean injected) {
return start == info.getPsiStartOffset() && end == info.getPsiEndOffset() && injected == info.isForInjected();
}
private static UpdatedRanges applyEvents(@NotNull List<DocumentEvent> events, final UpdatedRanges struct) {
@@ -150,8 +151,7 @@ class MarkerCache {
UpdatedRanges updated = getUpdatedMarkers(frozen, events);
for (int i = 0; i < updated.myMarkers.length; i++) {
ManualRangeMarker newRangeMarker = updated.myMarkers[i];
updated.mySortedInfos.get(i).setRange(newRangeMarker == null ? null : newRangeMarker.getRange());
updated.mySortedInfos.get(i).setRange(updated.myMarkers[i]);
}
myUpdatedRanges = null;
@@ -180,7 +180,7 @@ class MarkerCache {
UpdatedRanges struct = getUpdatedMarkers(frozen, events);
int i = Collections.binarySearch(struct.mySortedInfos, info, BY_RANGE_KEY);
ManualRangeMarker updated = i >= 0 ? struct.myMarkers[i] : null;
return updated == null ? null : updated.getRange();
return updated == null ? null : new UnfairTextRange(updated.getStartOffset(), updated.getEndOffset());
}
void rangeChanged() {
@@ -59,7 +59,7 @@ class PersistentRangeHighlighterImpl extends RangeHighlighterImpl implements Ran
protected void changedUpdateImpl(@NotNull DocumentEvent e) {
// todo Denis Zhdanov
DocumentEventImpl event = (DocumentEventImpl)e;
final boolean shouldTranslateViaDiff = isValid() && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this);
final boolean shouldTranslateViaDiff = isValid() && PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, getStartOffset(), getEndOffset());
boolean wasTranslatedViaDiff = shouldTranslateViaDiff;
if (shouldTranslateViaDiff) {
wasTranslatedViaDiff = translatedViaDiff(e, event);