optimization: replace all occurrence is dramatically faster
[fedora-idea.git] / platform-impl / src / com / intellij / openapi / editor / impl / CharArray.java
blob37f6205bd0013b74247157a2f5683882af582cb9
1 package com.intellij.openapi.editor.impl;
3 import com.intellij.openapi.editor.event.DocumentEvent;
4 import com.intellij.util.LocalTimeCounter;
5 import com.intellij.util.text.CharArrayCharSequence;
6 import com.intellij.util.text.CharArrayUtil;
7 import com.intellij.util.text.CharSequenceBackedByArray;
9 import java.lang.ref.SoftReference;
11 /**
12 * @author cdr
14 abstract class CharArray implements CharSequenceBackedByArray {
15 private int myCount = 0;
16 private CharSequence myOriginalSequence;
17 private char[] myArray = null;
18 private SoftReference<String> myStringRef = null; // buffers String value - for not to generate it every time
19 private int myBufferSize;
21 // max chars to hold, bufferSize == 0 means unbounded
22 CharArray(int bufferSize) {
23 myBufferSize = bufferSize;
24 myOriginalSequence = "";
27 public void setBufferSize(int bufferSize) {
28 myBufferSize = bufferSize;
31 protected abstract DocumentEvent beforeChangedUpdate(int offset, CharSequence oldString, CharSequence newString, boolean wholeTextReplaced);
32 protected abstract void afterChangedUpdate(DocumentEvent event, long newModificationStamp);
34 public void replaceText(CharSequence chars) {
35 myOriginalSequence = chars;
36 myArray = null;
37 myCount = chars.length();
38 myStringRef = null;
39 trimToSize();
42 public void replace(int startOffset, int endOffset, CharSequence toDelete, CharSequence newString, long newModificationStamp,
43 boolean wholeTextReplaced) {
44 final DocumentEvent event = beforeChangedUpdate(startOffset, toDelete, newString, wholeTextReplaced);
45 doReplace(startOffset, endOffset, newString);
46 afterChangedUpdate(event, newModificationStamp);
49 private void doReplace(int startOffset, int endOffset, CharSequence newString) {
50 prepareForModification();
52 int newLength = newString.length();
53 int oldLength = endOffset - startOffset;
55 CharArrayUtil.getChars(newString, myArray, startOffset, Math.min(newLength, oldLength));
57 if (newLength > oldLength) {
58 doInsert(newString.subSequence(oldLength, newLength), endOffset);
60 else if (newLength < oldLength) {
61 doRemove(startOffset + newLength, startOffset + oldLength);
65 public void remove(int startIndex, int endIndex, CharSequence toDelete) {
66 DocumentEvent event = beforeChangedUpdate(startIndex, toDelete, null, false);
67 doRemove(startIndex, endIndex);
68 afterChangedUpdate(event, LocalTimeCounter.currentTime());
71 private void doRemove(final int startIndex, final int endIndex) {
72 if (startIndex == endIndex) {
73 return;
75 prepareForModification();
77 if (endIndex < myCount) {
78 System.arraycopy(myArray, endIndex, myArray, startIndex, myCount - endIndex);
80 myCount -= endIndex - startIndex;
83 public void insert(CharSequence s, int startIndex) {
84 DocumentEvent event = beforeChangedUpdate(startIndex, null, s, false);
85 doInsert(s, startIndex);
87 afterChangedUpdate(event, LocalTimeCounter.currentTime());
88 trimToSize();
91 private void doInsert(final CharSequence s, final int startIndex) {
92 prepareForModification();
94 int insertLength = s.length();
95 myArray = relocateArray(myArray, myCount + insertLength);
96 if (startIndex < myCount) {
97 System.arraycopy(myArray, startIndex, myArray, startIndex + insertLength, myCount - startIndex);
100 CharArrayUtil.getChars(s, myArray,startIndex);
101 myCount += insertLength;
104 private void prepareForModification() {
105 if (myOriginalSequence != null) {
106 myArray = new char[myOriginalSequence.length()];
107 CharArrayUtil.getChars(myOriginalSequence, myArray, 0);
108 myOriginalSequence = null;
110 myStringRef = null;
113 public CharSequence getCharArray() {
114 if (myOriginalSequence != null) return myOriginalSequence;
115 return this;
118 public String toString() {
119 String str = myStringRef != null ? myStringRef.get() : null;
120 if (str == null) {
121 if (myOriginalSequence != null) {
122 str = myOriginalSequence.toString();
124 else {
125 str = new String(myArray, 0, myCount);
127 myStringRef = new SoftReference<String>(str);
129 return str;
132 public final int length() {
133 return myCount;
136 public final char charAt(int i) {
137 if (i < 0 || i >= myCount) {
138 throw new IndexOutOfBoundsException("Wrong offset: " + i);
140 if (myOriginalSequence != null) return myOriginalSequence.charAt(i);
141 return myArray[i];
144 public CharSequence subSequence(int start, int end) {
145 if (start == 0 && end == myCount) return this;
146 if (myOriginalSequence != null) {
147 return myOriginalSequence.subSequence(start, end);
149 return new CharArrayCharSequence(myArray, start, end);
152 public char[] getChars() {
153 if (myOriginalSequence != null) {
154 if (myArray == null) {
155 myArray = CharArrayUtil.fromSequence(myOriginalSequence);
158 return myArray;
161 public void getChars(final char[] dst, final int dstOffset) {
162 if (myOriginalSequence != null) {
163 CharArrayUtil.getChars(myOriginalSequence,dst, dstOffset);
165 else {
166 System.arraycopy(myArray, 0, dst, dstOffset, length());
170 public CharSequence substring(int start, int end) {
171 if (start == end) return "";
172 if (myOriginalSequence != null) {
173 return myOriginalSequence.subSequence(start, end);
175 return new String(myArray, start, end - start);
178 private static char[] relocateArray(char[] array, int index) {
179 if (index < array.length) {
180 return array;
183 int newArraySize = array.length;
184 if (newArraySize == 0) {
185 newArraySize = 16;
187 while (newArraySize <= index) {
188 newArraySize = newArraySize * 12 / 10 + 1;
190 char[] newArray = new char[newArraySize];
191 System.arraycopy(array, 0, newArray, 0, array.length);
192 return newArray;
195 private void trimToSize() {
196 if (myBufferSize != 0 && myCount > myBufferSize) {
197 // make a copy
198 remove(0, myCount - myBufferSize, getCharArray().subSequence(0, myCount - myBufferSize).toString());