mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
optimisation: visit only overlapping highlighters during paint
This commit is contained in:
@@ -23,7 +23,6 @@ import com.intellij.openapi.editor.impl.event.MarkupModelListener;
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.editor.impl.Interval;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.util.ProperTextRange;
|
||||
@@ -130,18 +129,15 @@ class MarkupModelWindow extends UserDataHolderBase implements MarkupModelEx {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Iterator<RangeHighlighterEx> iterator() {
|
||||
// todo
|
||||
return null;
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
|
||||
// todo convert
|
||||
return myHostModel.overlappingIterator(startOffset, endOffset);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterator<RangeHighlighterEx> iteratorFrom(@NotNull Interval interval) {
|
||||
// todo convert
|
||||
return myHostModel.iteratorFrom(interval);
|
||||
}
|
||||
public boolean sweep(int start, int end, @NotNull SweepProcessor<RangeHighlighterEx> sweepProcessor) {
|
||||
// todo convert
|
||||
return myHostModel.sweep(start, end, sweepProcessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.ex;
|
||||
|
||||
import com.intellij.openapi.editor.impl.Interval;
|
||||
import com.intellij.openapi.editor.impl.event.MarkupModelListener;
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
|
||||
import com.intellij.openapi.editor.markup.MarkupModel;
|
||||
@@ -31,7 +30,7 @@ import java.util.Iterator;
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public interface MarkupModelEx extends MarkupModel, Iterable<RangeHighlighterEx> {
|
||||
public interface MarkupModelEx extends MarkupModel {
|
||||
void dispose();
|
||||
|
||||
RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes);
|
||||
@@ -43,17 +42,18 @@ public interface MarkupModelEx extends MarkupModel, Iterable<RangeHighlighterEx>
|
||||
void setRangeHighlighterAttributes(@NotNull RangeHighlighter highlighter, TextAttributes textAttributes);
|
||||
|
||||
boolean processHighlightsOverlappingWith(int start, int end, @NotNull Processor<? super RangeHighlighterEx> processor);
|
||||
|
||||
@NotNull
|
||||
Iterator<RangeHighlighterEx> iteratorFrom(@NotNull Interval interval);
|
||||
Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset);
|
||||
|
||||
// optimization: creates highlighter and fires only one event: highlighterCreated
|
||||
RangeHighlighterEx addRangeHighlighterAndChangeAttributes(int startOffset,
|
||||
int endOffset,
|
||||
int layer,
|
||||
TextAttributes textAttributes,
|
||||
@NotNull HighlighterTargetArea targetArea,
|
||||
boolean isPersistent,
|
||||
Consumer<RangeHighlighterEx> changeAttributesAction);
|
||||
int endOffset,
|
||||
int layer,
|
||||
TextAttributes textAttributes,
|
||||
@NotNull HighlighterTargetArea targetArea,
|
||||
boolean isPersistent,
|
||||
Consumer<RangeHighlighterEx> changeAttributesAction);
|
||||
|
||||
// runs change attributes action and fires highlighterChanged event if there were changes
|
||||
void changeAttributesInBatch(@NotNull RangeHighlighterEx highlighter, @NotNull Consumer<RangeHighlighterEx> changeAttributesAction);
|
||||
|
||||
+19
-16
@@ -377,18 +377,23 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
void process(RangeHighlighter highlighter);
|
||||
}
|
||||
|
||||
private void processRangeHighlighters(RangeHighlighterProcessor processor, int startOffset, int endOffset) {
|
||||
final MarkupModelEx docMarkup = (MarkupModelEx)myEditor.getDocument().getMarkupModel(myEditor.getProject());
|
||||
Iterator<RangeHighlighterEx> docHighlighters = docMarkup.iterator();
|
||||
private void processRangeHighlighters(int startOffset, int endOffset, RangeHighlighterProcessor processor) {
|
||||
Document document = myEditor.getDocument();
|
||||
final MarkupModelEx docMarkup = (MarkupModelEx)document.getMarkupModel(myEditor.getProject());
|
||||
// we limit highlighters to process to between line starting at startOffset and line ending at endOffset
|
||||
int docLength = document.getTextLength();
|
||||
int patchedStartOffset = startOffset < docLength ? document.getLineStartOffset(document.getLineNumber(startOffset)) : docLength;
|
||||
int patchedEndOffset = endOffset <= docLength ? document.getLineEndOffset(document.getLineNumber(endOffset)) + 1 : docLength;
|
||||
Iterator<RangeHighlighterEx> docHighlighters = docMarkup.overlappingIterator(patchedStartOffset, patchedEndOffset);
|
||||
|
||||
final MarkupModelEx editorMarkup = (MarkupModelEx)myEditor.getMarkupModel();
|
||||
Iterator<RangeHighlighterEx> editorHighlighters = editorMarkup.iterator();
|
||||
Iterator<RangeHighlighterEx> editorHighlighters = editorMarkup.overlappingIterator(startOffset, endOffset);
|
||||
|
||||
RangeHighlighterEx lastDocHighlighter = null;
|
||||
RangeHighlighterEx lastEditorHighlighter = null;
|
||||
|
||||
while (true) {
|
||||
if (lastDocHighlighter == null && docHighlighters != null && docHighlighters.hasNext()) {
|
||||
if (lastDocHighlighter == null && docHighlighters.hasNext()) {
|
||||
lastDocHighlighter = docHighlighters.next();
|
||||
if (!lastDocHighlighter.isValid() || lastDocHighlighter.getAffectedAreaStartOffset() > endOffset) {
|
||||
lastDocHighlighter = null;
|
||||
@@ -396,12 +401,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
}
|
||||
if (lastDocHighlighter.getAffectedAreaEndOffset() < startOffset) {
|
||||
lastDocHighlighter = null;
|
||||
//docHighlighters = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastEditorHighlighter == null && editorHighlighters != null && editorHighlighters.hasNext()) {
|
||||
if (lastEditorHighlighter == null && editorHighlighters.hasNext()) {
|
||||
lastEditorHighlighter = editorHighlighters.next();
|
||||
if (!lastEditorHighlighter.isValid() || lastEditorHighlighter.getAffectedAreaStartOffset() > endOffset) {
|
||||
lastEditorHighlighter = null;
|
||||
@@ -409,7 +413,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
}
|
||||
if (lastEditorHighlighter.getAffectedAreaEndOffset() < startOffset) {
|
||||
lastEditorHighlighter = null;
|
||||
//editorHighlighters = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -431,10 +434,10 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
if (!lowerHighlighter.isValid()) continue;
|
||||
|
||||
int startLineIndex = lowerHighlighter.getDocument().getLineNumber(startOffset);
|
||||
if (startLineIndex < 0 || startLineIndex >= myEditor.getDocument().getLineCount()) continue;
|
||||
if (startLineIndex < 0 || startLineIndex >= document.getLineCount()) continue;
|
||||
|
||||
int endLineIndex = lowerHighlighter.getDocument().getLineNumber(endOffset);
|
||||
if (endLineIndex < 0 || endLineIndex >= myEditor.getDocument().getLineCount()) continue;
|
||||
if (endLineIndex < 0 || endLineIndex >= document.getLineCount()) continue;
|
||||
|
||||
if (lowerHighlighter.getEditorFilter().avaliableIn(myEditor)) {
|
||||
processor.process(lowerHighlighter);
|
||||
@@ -487,7 +490,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
private void calcIconAreaWidth() {
|
||||
myLineToGutterRenderers = new TIntObjectHashMap<ArrayList<GutterIconRenderer>>();
|
||||
|
||||
processRangeHighlighters(new RangeHighlighterProcessor() {
|
||||
processRangeHighlighters(0, myEditor.getDocument().getTextLength(), new RangeHighlighterProcessor() {
|
||||
public void process(RangeHighlighter highlighter) {
|
||||
GutterIconRenderer renderer = highlighter.getGutterIconRenderer();
|
||||
if (renderer == null) return;
|
||||
@@ -505,7 +508,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
renderers.add(renderer);
|
||||
}
|
||||
}
|
||||
}, 0, myEditor.getDocument().getTextLength());
|
||||
});
|
||||
|
||||
myIconsAreaWidth = START_ICON_AREA_WIDTH;
|
||||
|
||||
@@ -534,11 +537,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
Object hint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
try {
|
||||
processRangeHighlighters(new RangeHighlighterProcessor() {
|
||||
processRangeHighlighters(firstVisibleOffset, lastVisibleOffset, new RangeHighlighterProcessor() {
|
||||
public void process(RangeHighlighter highlighter) {
|
||||
paintLineMarkerRenderer(highlighter, g);
|
||||
}
|
||||
}, firstVisibleOffset, lastVisibleOffset);
|
||||
});
|
||||
}
|
||||
finally {
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint);
|
||||
@@ -1199,7 +1202,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
int lastVisibleOffset = myEditor.logicalPositionToOffset(
|
||||
myEditor.xyToLogicalPosition(new Point(0, clip.y + clip.height + myEditor.getLineHeight())));
|
||||
|
||||
processRangeHighlighters(new RangeHighlighterProcessor() {
|
||||
processRangeHighlighters(firstVisibleOffset, lastVisibleOffset, new RangeHighlighterProcessor() {
|
||||
public void process(RangeHighlighter highlighter) {
|
||||
if (gutterRenderer[0] != null) return;
|
||||
Rectangle rectangle = getLineRendererRectangle(highlighter);
|
||||
@@ -1218,7 +1221,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
}
|
||||
}
|
||||
}
|
||||
}, firstVisibleOffset, lastVisibleOffset);
|
||||
});
|
||||
return gutterRenderer[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -106,14 +106,12 @@ public class EmptyMarkupModel implements MarkupModelEx {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Iterator<RangeHighlighterEx> iterator() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
|
||||
return ContainerUtil.emptyIterator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterator<RangeHighlighterEx> iteratorFrom(@NotNull Interval interval) {
|
||||
return iterator();
|
||||
}
|
||||
public boolean sweep(int start, int end, @NotNull SweepProcessor<RangeHighlighterEx> sweepProcessor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* User: cdr
|
||||
*/
|
||||
public interface IntervalTree<T extends Interval> extends Iterable<T> {
|
||||
public interface IntervalTree<T extends Interval> {
|
||||
boolean process(@NotNull Processor<? super T> processor);
|
||||
boolean processOverlappingWith(int start, int end, @NotNull Processor<? super T> processor);
|
||||
boolean processOverlappingWith(int offset, @NotNull Processor<? super T> processor);
|
||||
|
||||
+122
-99
@@ -25,10 +25,7 @@ import gnu.trove.TLongHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
@@ -37,16 +34,15 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
/**
|
||||
* User: cdr
|
||||
*/
|
||||
public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBlackTree<T> implements IntervalTree<T> {
|
||||
public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBlackTree<T> implements IntervalTree<T>/*, Iterable<T>*/{
|
||||
private int keySize; // number of all intervals, counting all duplicates, some of them maybe gced
|
||||
protected final ReadWriteLock l = new ReentrantReadWriteLock();
|
||||
private IntervalNode minNode; // left most node in the tree
|
||||
|
||||
protected abstract EqualStartIntervalComparator<IntervalNode> getComparator();
|
||||
private final ReferenceQueue<T> myReferenceQueue = new ReferenceQueue<T>();
|
||||
private int deadReferenceCount;
|
||||
|
||||
protected class IntervalNode extends Node<T> implements MutableInterval {
|
||||
protected class IntervalNode extends RedBlackTree.Node<T> implements MutableInterval {
|
||||
private volatile int myStart;
|
||||
private volatile int myEnd;
|
||||
private volatile boolean isValid = true;
|
||||
@@ -314,6 +310,121 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Iterator<T> overlappingIterator(final int startOffset, final int endOffset) {
|
||||
final IntervalNode firstOverlap = findMinOverlappingWith(getRoot(), new TextRangeInterval(startOffset, endOffset), modCount, 0);
|
||||
if (firstOverlap == null) {
|
||||
return ContainerUtil.emptyIterator();
|
||||
}
|
||||
normalize();
|
||||
final int modCountBefore = modCount;
|
||||
return new Iterator<T>() {
|
||||
IntervalNode currentNode = firstOverlap;
|
||||
int[] deltaUpToRootExclusive = {0};
|
||||
private int indexInCurrentList = 0;
|
||||
T current;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (current != null) return true;
|
||||
if (currentNode == null) return false;
|
||||
|
||||
if (modCount != modCountBefore) throw new ConcurrentModificationException();
|
||||
while (indexInCurrentList != currentNode.intervals.size()) {
|
||||
T t = currentNode.intervals.get(indexInCurrentList++).get();
|
||||
if (t != null) {
|
||||
current = t;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
indexInCurrentList = 0;
|
||||
while (true) {
|
||||
currentNode = nextNode(currentNode, startOffset, endOffset, deltaUpToRootExclusive);
|
||||
if (currentNode == null) {
|
||||
return false;
|
||||
}
|
||||
if (overlaps(currentNode, startOffset, endOffset, deltaUpToRootExclusive[0])) {
|
||||
assert currentNode.intervalStart() >= firstOverlap.intervalStart();
|
||||
indexInCurrentList = 0;
|
||||
while (indexInCurrentList != currentNode.intervals.size()) {
|
||||
T t = currentNode.intervals.get(indexInCurrentList++).get();
|
||||
if (t != null) {
|
||||
current = t;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
indexInCurrentList = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
T t = current;
|
||||
current = null;
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean overlaps(IntervalNode root,
|
||||
int startOffset, int endOffset,
|
||||
int deltaUpToRootExclusive) {
|
||||
if (root == null) return false;
|
||||
int delta = root.delta + deltaUpToRootExclusive;
|
||||
int start = root.intervalStart() + delta;
|
||||
int end = root.intervalEnd() + delta;
|
||||
return Math.max(start, startOffset) <= Math.min(end, endOffset);
|
||||
}
|
||||
|
||||
private IntervalNode nextNode(@NotNull IntervalNode root,
|
||||
int startOffset, int endOffset,
|
||||
@NotNull int[] newDeltaUpToRootExclusive) {
|
||||
assert root.isValid();
|
||||
int deltaUpToRootExclusive = newDeltaUpToRootExclusive[0];
|
||||
int delta = deltaUpToRootExclusive + root.delta;
|
||||
//int myStartOffset = root.intervalStart() + delta;
|
||||
//int myEndOffset = root.intervalEnd() + delta;
|
||||
int myMaxEnd = maxEndOf(root, deltaUpToRootExclusive);
|
||||
assert startOffset <= myMaxEnd;
|
||||
|
||||
// try to go right down
|
||||
IntervalNode right = root.getRight();
|
||||
if (right != null) {
|
||||
int rightMaxEnd = maxEndOf(right, delta);
|
||||
if (startOffset <= rightMaxEnd) {
|
||||
int rightDelta = delta + right.delta;
|
||||
while (right.getLeft() != null && startOffset <= maxEndOf(right.getLeft(), rightDelta)) {
|
||||
right = right.getLeft();
|
||||
rightDelta += right.delta;
|
||||
}
|
||||
newDeltaUpToRootExclusive[0] = rightDelta - right.delta;
|
||||
return right;
|
||||
}
|
||||
}
|
||||
|
||||
// go up
|
||||
while (true) {
|
||||
IntervalNode parent = root.getParent();
|
||||
if (parent == null) return null;
|
||||
if (parent.intervalStart() + deltaUpToRootExclusive > endOffset) return null; // can't move right
|
||||
deltaUpToRootExclusive -= parent.delta;
|
||||
|
||||
if (parent.getLeft() == root) {
|
||||
newDeltaUpToRootExclusive[0] = deltaUpToRootExclusive;
|
||||
return parent;
|
||||
}
|
||||
|
||||
root = parent;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processOverlapping(IntervalNode root,
|
||||
int offset,
|
||||
Processor<? super T> processor,
|
||||
@@ -355,7 +466,7 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
node.setLeft(null);
|
||||
node.setRight(null);
|
||||
|
||||
List<IntervalNode> gced = new ArrayList<IntervalNode>();
|
||||
List<IntervalNode> gced = new SmartList<IntervalNode>();
|
||||
if (root == null) {
|
||||
root = node;
|
||||
}
|
||||
@@ -387,7 +498,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
node.delta = -delta;
|
||||
node.setParent(current);
|
||||
}
|
||||
linkNode(node);
|
||||
correctMaxUp(node);
|
||||
onInsertNode();
|
||||
assertUnderWriteLock();
|
||||
@@ -399,29 +509,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
return node;
|
||||
}
|
||||
|
||||
private void linkNode(@NotNull IntervalNode node) {
|
||||
IntervalNode previous = previous(node);
|
||||
if (previous == null) {
|
||||
node.next = minNode;
|
||||
minNode = node;
|
||||
}
|
||||
else {
|
||||
node.next = previous.next;
|
||||
previous.next = node;
|
||||
}
|
||||
}
|
||||
|
||||
private void unlinkNode(@NotNull IntervalNode node) {
|
||||
IntervalNode previous = previous(node);
|
||||
if (previous == null) {
|
||||
minNode = node.next;
|
||||
}
|
||||
else {
|
||||
previous.next = node.next;
|
||||
}
|
||||
node.next = null;
|
||||
}
|
||||
|
||||
// finds previous in the in-order traversal
|
||||
private IntervalNode previous(@NotNull IntervalNode node) {
|
||||
IntervalNode left = node.getLeft();
|
||||
@@ -447,7 +534,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
for (IntervalNode node : collectedAway) {
|
||||
removeNode(node);
|
||||
}
|
||||
checkMax(true);
|
||||
}
|
||||
finally {
|
||||
l.writeLock().unlock();
|
||||
@@ -493,10 +579,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
assert nodeSize() == nodeCounter.get() : "node size: "+ nodeSize() +"; actual: "+nodeCounter;
|
||||
assert keySize == keyCounter.get() : "key size: "+ keySize +"; actual: "+keyCounter;
|
||||
assert keySize >= nodeSize() : keySize + "; "+nodeSize();
|
||||
|
||||
IntervalNode left = getRoot();
|
||||
while (left != null && left.getLeft() != null) left = left.getLeft();
|
||||
assert minNode == left;
|
||||
}
|
||||
return allValid.get();
|
||||
}
|
||||
@@ -640,7 +722,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
assertUnderWriteLock();
|
||||
IntervalNode node = (IntervalNode)n;
|
||||
pushDeltaFromRoot(node);
|
||||
unlinkNode(node);
|
||||
|
||||
super.deleteNode(n);
|
||||
|
||||
@@ -744,6 +825,7 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
if (r2 != null) r2.setParent(n1);
|
||||
}
|
||||
|
||||
// returns real max endOffset of all intervals below
|
||||
private int maxEndOf(IntervalNode node, int deltaUpToRootExclusive) {
|
||||
if (node == null) {
|
||||
return 0;
|
||||
@@ -751,6 +833,7 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
if (node.isValid()) {
|
||||
return node.maxEnd + node.delta + deltaUpToRootExclusive;
|
||||
}
|
||||
// since node is invalid, ignore node.delta
|
||||
return Math.max(maxEndOf(node.getLeft(), deltaUpToRootExclusive), maxEndOf(node.getRight(), deltaUpToRootExclusive));
|
||||
}
|
||||
|
||||
@@ -831,14 +914,6 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
IntervalNode firstNode = minNode;
|
||||
if (firstNode == null) {
|
||||
return ContainerUtil.emptyIterator();
|
||||
}
|
||||
return createIteratorFrom(firstNode);
|
||||
}
|
||||
|
||||
private IntervalNode findMinOverlappingWith(IntervalNode root, Interval interval, int modCountBefore, int deltaUpToRootExclusive) {
|
||||
if (root == null) {
|
||||
return null;
|
||||
@@ -865,59 +940,7 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
return findMinOverlappingWith(root.getRight(), interval, modCountBefore, delta);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Iterator<T> iteratorFrom(@NotNull Interval interval) {
|
||||
IntervalNode firstOverlap = findMinOverlappingWith(getRoot(), interval, modCount, 0);
|
||||
if (firstOverlap == null) {
|
||||
return ContainerUtil.emptyIterator();
|
||||
}
|
||||
return createIteratorFrom(firstOverlap);
|
||||
}
|
||||
|
||||
private Iterator<T> createIteratorFrom(@NotNull final IntervalNode firstNode) {
|
||||
checkMax(true);
|
||||
normalize();
|
||||
|
||||
final int modCountBefore = modCount;
|
||||
return new Iterator<T>() {
|
||||
private IntervalNode node = firstNode;
|
||||
private int indexInCurrentList = 0;
|
||||
T current;
|
||||
|
||||
public boolean hasNext() {
|
||||
if (current != null) return true;
|
||||
while (node != null) {
|
||||
while (indexInCurrentList != node.intervals.size()) {
|
||||
current = node.intervals.get(indexInCurrentList).get();
|
||||
if (current != null) return true;
|
||||
indexInCurrentList++;
|
||||
}
|
||||
indexInCurrentList = 0;
|
||||
node = node.next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public T next() {
|
||||
assert modCount == modCountBefore : "Must not modify range markers during iterate";
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
|
||||
T t = current;
|
||||
current = null;
|
||||
|
||||
indexInCurrentList++;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
public void remove() {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected volatile boolean normalized = true;
|
||||
|
||||
public void normalize() {
|
||||
if (normalized) return;
|
||||
try {
|
||||
@@ -982,13 +1005,13 @@ public abstract class IntervalTreeImpl<T extends MutableInterval> extends RedBla
|
||||
List<IntervalNode> gced = new ArrayList<IntervalNode>();
|
||||
collectGced(getRoot(), gced);
|
||||
deleteNodes(gced);
|
||||
checkMax(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
keySize = 0;
|
||||
minNode = null;
|
||||
}
|
||||
|
||||
private void collectGced(IntervalNode root, List<IntervalNode> gced) {
|
||||
|
||||
@@ -120,13 +120,17 @@ public final class IterationState {
|
||||
private Iterator<RangeHighlighterEx> myIterator;
|
||||
|
||||
private void init(MarkupModelEx markupModel, int start) {
|
||||
myIterator = markupModel.iteratorFrom(new TextRangeInterval(start, myDocument.getTextLength()));
|
||||
|
||||
myIterator = markupModel.overlappingIterator(start, myDocument.getTextLength());
|
||||
int skipped = 0;
|
||||
while (myIterator.hasNext()) {
|
||||
myNextHighlighter = myIterator.next();
|
||||
if (!skipHighlighter(myNextHighlighter)) break;
|
||||
else myNextHighlighter = null;
|
||||
RangeHighlighterEx highlighter = myIterator.next();
|
||||
if (!skipHighlighter(highlighter)) {
|
||||
myNextHighlighter = highlighter;
|
||||
break;
|
||||
}
|
||||
skipped++;
|
||||
}
|
||||
int i = skipped;
|
||||
}
|
||||
|
||||
private void advance() {
|
||||
|
||||
@@ -231,13 +231,9 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx
|
||||
return myHighlighterTree.processOverlappingWith(start, end, processor);
|
||||
}
|
||||
|
||||
public Iterator<RangeHighlighterEx> iterator() {
|
||||
return myHighlighterTree.iterator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterator<RangeHighlighterEx> iteratorFrom(@NotNull Interval interval) {
|
||||
return myHighlighterTree.iteratorFrom(interval);
|
||||
public Iterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) {
|
||||
return myHighlighterTree.overlappingIterator(startOffset, endOffset);
|
||||
}
|
||||
|
||||
public boolean sweep(int start, int end, @NotNull SweepProcessor<RangeHighlighterEx> sweepProcessor) {
|
||||
|
||||
Reference in New Issue
Block a user