optimization: replace all occurrence is dramatically faster
[fedora-idea.git] / platform-impl / src / com / intellij / openapi / editor / impl / RangeIterator.java
blob3236bd71877acc5e498c2e78ab1285652e4674ad
1 package com.intellij.openapi.editor.impl;
3 import com.intellij.openapi.diagnostic.Logger;
4 import com.intellij.openapi.editor.FoldingModel;
5 import com.intellij.openapi.editor.highlighter.HighlighterIterator;
6 import com.intellij.openapi.editor.markup.TextAttributes;
7 import com.intellij.openapi.util.Condition;
8 import com.intellij.openapi.util.TextRange;
9 import gnu.trove.Equality;
11 class RangeIterator {
12 private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeIterator");
13 private static final int NO_NEXT = -1;
14 private int myRangeEnd;
16 public interface Gaps {
17 boolean isGapAt(int offset);
20 private final HighlighterIterator mySource;
21 private final Equality<TextAttributes> myEquality;
22 private final Gaps myGaps;
23 private final Condition<TextAttributes> myFilter;
24 private boolean mySourceOutOfRange = false;
26 private int myStart;
27 private int myEnd;
28 private TextAttributes myTextAttributes;
29 private int myNextExpanded;
31 public RangeIterator(Gaps foldingModel, Equality<TextAttributes> equality,
32 HighlighterIterator source, Condition<TextAttributes> filter) {
33 mySource = source;
34 myGaps = foldingModel;
35 myEquality = equality;
36 myFilter = filter;
39 public void init(TextRange range) {
40 int rangeStart = range.getStartOffset();
41 myRangeEnd = range.getEndOffset();
42 while(!mySource.atEnd()) {
43 boolean sourceBeforeRange = rangeStart > mySource.getEnd();
44 if (!sourceBeforeRange) break;
45 mySource.advance();
47 while (!mySource.atEnd() && !checkOutOfRange()) {
48 if (myFilter.value(mySource.getTextAttributes())) break;
49 mySource.advance();
52 if (mySource.atEnd() || mySourceOutOfRange) myNextExpanded = NO_NEXT;
53 else {
54 myNextExpanded = findExpanded(mySource.getStart());
55 if (myNextExpanded == NO_NEXT) myStart = NO_NEXT;
59 private boolean checkOutOfRange() {
60 if (mySourceOutOfRange) return true;
61 mySourceOutOfRange = mySource.getStart() > myRangeEnd;
62 return mySourceOutOfRange;
65 private void doAdvanceFrom(int start) {
66 myStart = start;
67 myEnd = myStart;
68 doAdvance();
69 if (mySource.atEnd()) myNextExpanded = NO_NEXT;
70 else myNextExpanded = findExpanded(Math.max(myEnd, mySource.getStart()));
73 private void doAdvance() {
74 myStart = findExpanded(myStart);
75 myEnd = findFolding(myStart, mySource.getEnd(), true);
76 myTextAttributes = mySource.getTextAttributes();
77 while (myEnd == mySource.getEnd()) {
78 if (!advanceSource()) return;
79 if (mySource.getStart() != myEnd) return;
80 if (!myEquality.equals(myTextAttributes, mySource.getTextAttributes())) return;
81 myEnd = findFolding(myEnd, mySource.getEnd(), true);
85 private boolean advanceSource() {
86 if (mySource.atEnd()) return false;
87 do {
88 mySource.advance();
89 } while (!(mySource.atEnd() || checkOutOfRange() || myFilter.value(mySource.getTextAttributes())));
90 return !mySource.atEnd();
93 private int findExpanded(int start) {
94 start = findFolding(start, mySource.getEnd(), false);
95 while (start == mySource.getEnd()) {
96 if (!advanceSource()) return NO_NEXT;
97 start = findFolding(mySource.getStart(), mySource.getEnd(), false);
99 return start;
102 private int findFolding(int start, int end, boolean collapsed) {
103 int position = start;
104 while (position < end) {
105 if (myGaps.isGapAt(position) == collapsed) break;
106 else position++;
108 return position;
111 public int getStart() {
112 return myStart;
115 public int getEnd() {
116 return myEnd;
119 public TextAttributes getTextAttributes() {
120 LOG.assertTrue(myFilter.value(myTextAttributes));
121 return myTextAttributes;
124 public void advance() {
125 doAdvanceFrom(myNextExpanded);
128 public boolean atEnd() {
129 return myStart == NO_NEXT || mySourceOutOfRange ||
130 (mySource.atEnd() && (myNextExpanded == NO_NEXT ||
131 myNextExpanded == mySource.getEnd()));
134 public static class FoldingGaps implements Gaps {
135 private final FoldingModel myFoldingModel;
137 public FoldingGaps(FoldingModel foldingModel) {
138 myFoldingModel = foldingModel;
141 public boolean isGapAt(int offset) {
142 return myFoldingModel.isOffsetCollapsed(offset);