mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
optimisation: avoid recalculating hashcode if possible
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package com.intellij.openapi.diff.impl.string;
|
||||
import com.intellij.openapi.diff.LineTokenizerBase;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -25,14 +26,9 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class DiffString implements CharSequence {
|
||||
public class DiffString extends CharArrayCharSequence {
|
||||
@NotNull public static final DiffString EMPTY = new DiffString(new char[0], 0, 0);
|
||||
|
||||
@NotNull private final char[] myData;
|
||||
private final int myStart;
|
||||
private final int myLength;
|
||||
private int myHash;
|
||||
|
||||
@Nullable
|
||||
public static DiffString createNullable(@Nullable String string) {
|
||||
if (string == null) return null;
|
||||
@@ -58,63 +54,43 @@ public class DiffString implements CharSequence {
|
||||
}
|
||||
|
||||
private DiffString(@NotNull char[] data, int start, int length) {
|
||||
myData = data;
|
||||
myStart = start;
|
||||
myLength = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return myLength;
|
||||
super(data, start, start + length);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myLength == 0;
|
||||
return length() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
if (index < 0 || index >= myLength) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
return data(index);
|
||||
}
|
||||
|
||||
public char data(int index) {
|
||||
return myData[myStart + index];
|
||||
private char data(int index) {
|
||||
return charAt(index);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiffString substring(int start) {
|
||||
return substring(start, myLength);
|
||||
return substring(start, length());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiffString substring(int start, int end) {
|
||||
if (start == 0 && end == myLength) return this;
|
||||
checkBounds(start, end - start, myLength);
|
||||
return create(myData, myStart + start, end - start);
|
||||
if (start == 0 && end == length()) return this;
|
||||
checkBounds(start, end - start, length());
|
||||
return create(myChars, myStart + start, end - start);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DiffString subSequence(int start, int end) {
|
||||
return substring(start, end);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String(myData, myStart, myLength);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiffString copy() {
|
||||
return create(Arrays.copyOfRange(myData, myStart, myStart + myLength));
|
||||
return create(Arrays.copyOfRange(myChars, myStart, myStart + length()));
|
||||
}
|
||||
|
||||
public void copyData(@NotNull char[] dst, int start) {
|
||||
checkBounds(start, myLength, dst.length);
|
||||
System.arraycopy(myData, myStart, dst, start, myLength);
|
||||
checkBounds(start, length(), dst.length);
|
||||
System.arraycopy(myChars, myStart, dst, start, length());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,26 +100,15 @@ public class DiffString implements CharSequence {
|
||||
|
||||
DiffString that = (DiffString)o;
|
||||
|
||||
if (myLength != that.myLength) return false;
|
||||
if (length() != that.length()) return false;
|
||||
if (hashCode() != that.hashCode()) return false;
|
||||
for (int i = 0; i < myLength; i++) {
|
||||
for (int i = 0; i < length(); i++) {
|
||||
if (data(i) != that.data(i)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = myHash;
|
||||
if (h == 0) {
|
||||
h = StringUtil.stringHashCode(myData, myStart, myStart + myLength);
|
||||
if (h == 0) h = 1;
|
||||
myHash = h;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static DiffString concatenateNullable(@Nullable DiffString s1, @Nullable DiffString s2) {
|
||||
if (s1 == null || s2 == null) {
|
||||
@@ -160,13 +125,13 @@ public class DiffString implements CharSequence {
|
||||
if (s1.isEmpty()) return s2;
|
||||
if (s2.isEmpty()) return s1;
|
||||
|
||||
if (s1.myData == s2.myData && s1.myStart + s1.myLength == s2.myStart) {
|
||||
return create(s1.myData, s1.myStart, s1.myLength + s2.myLength);
|
||||
if (s1.myChars == s2.myChars && s1.myStart + s1.length() == s2.myStart) {
|
||||
return create(s1.myChars, s1.myStart, s1.length() + s2.length());
|
||||
}
|
||||
|
||||
char[] data = new char[s1.myLength + s2.myLength];
|
||||
System.arraycopy(s1.myData, s1.myStart, data, 0, s1.myLength);
|
||||
System.arraycopy(s2.myData, s2.myStart, data, s1.myLength, s2.myLength);
|
||||
char[] data = new char[s1.length() + s2.length()];
|
||||
System.arraycopy(s1.myChars, s1.myStart, data, 0, s1.length());
|
||||
System.arraycopy(s2.myChars, s2.myStart, data, s1.length(), s2.length());
|
||||
return create(data);
|
||||
}
|
||||
|
||||
@@ -174,7 +139,7 @@ public class DiffString implements CharSequence {
|
||||
if (s1.isEmpty()) return true;
|
||||
if (s2.isEmpty()) return true;
|
||||
|
||||
if (s1.myData == s2.myData && s1.myStart + s1.myLength == s2.myStart) {
|
||||
if (s1.myChars == s2.myChars && s1.myStart + s1.length() == s2.myStart) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -193,7 +158,7 @@ public class DiffString implements CharSequence {
|
||||
int len = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
DiffString string = strings[start + i];
|
||||
len += string == null ? 0 : string.myLength;
|
||||
len += string == null ? 0 : string.length();
|
||||
}
|
||||
|
||||
if (len == 0) return EMPTY;
|
||||
@@ -203,32 +168,32 @@ public class DiffString implements CharSequence {
|
||||
for (int i = 0; i < length; i++) {
|
||||
DiffString string = strings[start + i];
|
||||
if (string == null || string.isEmpty()) continue;
|
||||
System.arraycopy(string.myData, string.myStart, data, index, string.myLength);
|
||||
index += string.myLength;
|
||||
System.arraycopy(string.myChars, string.myStart, data, index, string.length());
|
||||
index += string.length();
|
||||
}
|
||||
return create(data);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DiffString concatenate(@NotNull DiffString s, char c) {
|
||||
if (s.myStart + s.myLength < s.myData.length && s.data(s.myLength) == c) {
|
||||
return create(s.myData, s.myStart, s.myLength + 1);
|
||||
if (s.myStart + s.length() < s.myChars.length && s.data(s.length()) == c) {
|
||||
return create(s.myChars, s.myStart, s.length() + 1);
|
||||
}
|
||||
|
||||
char[] data = new char[s.myLength + 1];
|
||||
System.arraycopy(s.myData, s.myStart, data, 0, s.myLength);
|
||||
data[s.myLength] = c;
|
||||
char[] data = new char[s.length() + 1];
|
||||
System.arraycopy(s.myChars, s.myStart, data, 0, s.length());
|
||||
data[s.length()] = c;
|
||||
return create(data);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DiffString concatenate(char c, @NotNull DiffString s) {
|
||||
if (s.myStart > 0 && s.data(-1) == c) {
|
||||
return create(s.myData, s.myStart - 1, s.myLength + 1);
|
||||
return create(s.myChars, s.myStart - 1, s.length() + 1);
|
||||
}
|
||||
|
||||
char[] data = new char[s.myLength + 1];
|
||||
System.arraycopy(s.myData, s.myStart, data, 1, s.myLength);
|
||||
char[] data = new char[s.length() + 1];
|
||||
System.arraycopy(s.myChars, s.myStart, data, 1, s.length());
|
||||
data[0] = c;
|
||||
return create(data);
|
||||
}
|
||||
@@ -251,16 +216,16 @@ public class DiffString implements CharSequence {
|
||||
DiffString string = strings[start + i];
|
||||
if (string == null || string.isEmpty()) continue;
|
||||
if (data == null) {
|
||||
data = string.myData;
|
||||
data = string.myChars;
|
||||
startIndex = string.myStart;
|
||||
endIndex = string.myStart + string.myLength;
|
||||
endIndex = string.myStart + string.length();
|
||||
continue;
|
||||
}
|
||||
if (data != string.myData || string.myStart != endIndex) {
|
||||
if (data != string.myChars || string.myStart != endIndex) {
|
||||
linearized = false;
|
||||
break;
|
||||
}
|
||||
endIndex += string.myLength;
|
||||
endIndex += string.length();
|
||||
}
|
||||
|
||||
if (linearized) {
|
||||
@@ -288,7 +253,7 @@ public class DiffString implements CharSequence {
|
||||
public boolean isEmptyOrSpaces() {
|
||||
if (isEmpty()) return true;
|
||||
|
||||
for (int i = 0; i < myLength; i++) {
|
||||
for (int i = 0; i < length(); i++) {
|
||||
if (!isWhiteSpace(data(i))) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -297,7 +262,7 @@ public class DiffString implements CharSequence {
|
||||
@NotNull
|
||||
public DiffString trim() {
|
||||
int start = 0;
|
||||
int end = myLength;
|
||||
int end = length();
|
||||
|
||||
while (start < end && isWhiteSpace(data(start))) start++;
|
||||
while (end > start && isWhiteSpace(data(end - 1))) end--;
|
||||
@@ -309,14 +274,14 @@ public class DiffString implements CharSequence {
|
||||
public DiffString trimLeading() {
|
||||
int i = 0;
|
||||
|
||||
while (i < myLength && isWhiteSpace(data(i))) i++;
|
||||
while (i < length() && isWhiteSpace(data(i))) i++;
|
||||
|
||||
return substring(i, myLength);
|
||||
return substring(i, length());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiffString trimTrailing() {
|
||||
int end = myLength;
|
||||
int end = length();
|
||||
|
||||
while (end > 0 && isWhiteSpace(data(end - 1))) end--;
|
||||
|
||||
@@ -327,7 +292,7 @@ public class DiffString implements CharSequence {
|
||||
public DiffString getLeadingSpaces() {
|
||||
int i = 0;
|
||||
|
||||
while (i < myLength && data(i) == ' ') i++;
|
||||
while (i < length() && data(i) == ' ') i++;
|
||||
|
||||
return substring(0, i);
|
||||
}
|
||||
@@ -336,14 +301,14 @@ public class DiffString implements CharSequence {
|
||||
public DiffString skipSpaces() {
|
||||
DiffString s = trim();
|
||||
int count = 0;
|
||||
for (int i = 0; i < s.myLength; i++) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (isWhiteSpace(s.data(i))) count++;
|
||||
}
|
||||
if (count == 0) return s;
|
||||
|
||||
char[] data = new char[s.myLength - count];
|
||||
char[] data = new char[s.length() - count];
|
||||
int index = 0;
|
||||
for (int i = 0; i < s.myLength; i++) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (isWhiteSpace(s.data(i))) continue;
|
||||
data[index] = s.data(i);
|
||||
index++;
|
||||
@@ -357,7 +322,7 @@ public class DiffString implements CharSequence {
|
||||
|
||||
public boolean endsWith(char c) {
|
||||
if (isEmpty()) return false;
|
||||
return data(myLength - 1) == c;
|
||||
return data(length() - 1) == c;
|
||||
}
|
||||
|
||||
public static void checkBounds(int start, int length, int maxLength) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,4 +20,6 @@ package com.intellij.openapi.util.text;
|
||||
* @see com.intellij.openapi.util.text.StringUtil#stringHashCode(CharSequence)
|
||||
*/
|
||||
public interface CharSequenceWithStringHash extends CharSequence{
|
||||
@Override
|
||||
int hashCode();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.text.CharSequenceSubSequence;
|
||||
import com.intellij.util.text.StringFactory;
|
||||
@@ -859,9 +858,10 @@ public class StringUtil extends StringUtilRt {
|
||||
|
||||
@Contract(pure = true)
|
||||
public static int stringHashCode(@NotNull CharSequence chars) {
|
||||
if (chars instanceof String) return chars.hashCode();
|
||||
if (chars instanceof CharSequenceWithStringHash) return chars.hashCode();
|
||||
if (chars instanceof CharArrayCharSequence) return chars.hashCode();
|
||||
if (chars instanceof String || chars instanceof CharSequenceWithStringHash) {
|
||||
// we know for sure these classes have conformant (and maybe faster) hashCode()
|
||||
return chars.hashCode();
|
||||
}
|
||||
|
||||
return stringHashCode(chars, 0, chars.length());
|
||||
}
|
||||
@@ -966,6 +966,15 @@ public class StringUtil extends StringUtilRt {
|
||||
return s;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Contract(pure = true)
|
||||
public static String trimEnd(@NotNull String s, char suffix) {
|
||||
if (endsWithChar(s, suffix)) {
|
||||
return s.substring(0, s.length() - 1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Contract(pure = true)
|
||||
public static String trimLog(@NotNull final String text, final int limit) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.util.text;
|
||||
|
||||
import com.intellij.openapi.util.text.CharSequenceWithStringHash;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ByteArrayCharSequence implements CharSequenceWithStringHash {
|
||||
@@ -30,12 +31,7 @@ public class ByteArrayCharSequence implements CharSequenceWithStringHash {
|
||||
public int hashCode() {
|
||||
int h = hash;
|
||||
if (h == 0) {
|
||||
byte[] chars = myChars;
|
||||
|
||||
for (byte aChar : chars) {
|
||||
h = 31 * h + aChar;
|
||||
}
|
||||
hash = h;
|
||||
hash = h = StringUtil.stringHashCode(this, 0, length());
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
package com.intellij.util.text;
|
||||
|
||||
import com.intellij.openapi.util.text.CharSequenceWithStringHash;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CharArrayCharSequence implements CharSequenceBackedByArray {
|
||||
public class CharArrayCharSequence implements CharSequenceBackedByArray, CharSequenceWithStringHash {
|
||||
protected final char[] myChars;
|
||||
protected final int myStart;
|
||||
protected final int myEnd;
|
||||
@@ -29,9 +30,7 @@ public class CharArrayCharSequence implements CharSequenceBackedByArray {
|
||||
|
||||
public CharArrayCharSequence(@NotNull char[] chars, int start, int end) {
|
||||
if (start < 0 || end > chars.length || start > end) {
|
||||
throw new IndexOutOfBoundsException("chars.length:" + chars.length +
|
||||
", start:" + start +
|
||||
", end:" + end);
|
||||
throw new IndexOutOfBoundsException("chars.length:" + chars.length + ", start:" + start + ", end:" + end);
|
||||
}
|
||||
myChars = chars;
|
||||
myStart = start;
|
||||
@@ -48,6 +47,7 @@ public class CharArrayCharSequence implements CharSequenceBackedByArray {
|
||||
return myChars[index + myStart];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return start == 0 && end == length() ? this : new CharArrayCharSequence(myChars, myStart + start, myStart + end);
|
||||
@@ -62,17 +62,12 @@ public class CharArrayCharSequence implements CharSequenceBackedByArray {
|
||||
@Override
|
||||
@NotNull
|
||||
public char[] getChars() {
|
||||
if (myStart == 0 /*&& myEnd == myChars.length*/) return myChars;
|
||||
if (myStart == 0) return myChars;
|
||||
char[] chars = new char[length()];
|
||||
System.arraycopy(myChars, myStart, chars, 0, length());
|
||||
return chars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return StringUtil.stringHashCode(myChars, myStart, myEnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getChars(@NotNull char[] dst, int dstOffset) {
|
||||
System.arraycopy(myChars, myStart, dst, dstOffset, length());
|
||||
@@ -108,4 +103,14 @@ public class CharArrayCharSequence implements CharSequenceBackedByArray {
|
||||
System.arraycopy(myChars, myStart + start, cbuf, off, readChars);
|
||||
return readChars;
|
||||
}
|
||||
|
||||
private int hash;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = hash;
|
||||
if (h == 0) {
|
||||
hash = h = StringUtil.stringHashCode(this, 0, length());
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.intellij.util.text;
|
||||
|
||||
import com.intellij.openapi.util.text.CharSequenceWithStringHash;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CharSequenceSubSequence implements CharSequence, CharArrayExternalizable {
|
||||
public class CharSequenceSubSequence implements CharSequence, CharArrayExternalizable, CharSequenceWithStringHash {
|
||||
private final CharSequence myChars;
|
||||
private final int myStart;
|
||||
private final int myEnd;
|
||||
@@ -48,6 +50,7 @@ public class CharSequenceSubSequence implements CharSequence, CharArrayExternali
|
||||
return myChars.charAt(index + myStart);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
if (start == myStart && end == myEnd) return this;
|
||||
@@ -60,6 +63,7 @@ public class CharSequenceSubSequence implements CharSequence, CharArrayExternali
|
||||
return StringFactory.createShared(CharArrayUtil.fromSequence(myChars, myStart, myEnd));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CharSequence getBaseSequence() {
|
||||
return myChars;
|
||||
}
|
||||
@@ -69,4 +73,14 @@ public class CharSequenceSubSequence implements CharSequence, CharArrayExternali
|
||||
assert end - start <= myEnd - myStart;
|
||||
CharArrayUtil.getChars(myChars, dest, start + myStart, destPos, end - start);
|
||||
}
|
||||
|
||||
private int hash;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = hash;
|
||||
if (h == 0) {
|
||||
hash = h = StringUtil.stringHashCode(this, 0, length());
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
*/
|
||||
package com.intellij.util.text;
|
||||
|
||||
import com.intellij.openapi.util.text.CharSequenceWithStringHash;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -53,7 +55,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @version 5.3, January 10, 2007
|
||||
*/
|
||||
@SuppressWarnings({"AssignmentToForLoopParameter","UnnecessaryThis"})
|
||||
public final class ImmutableText extends ImmutableCharSequence implements CharArrayExternalizable {
|
||||
public final class ImmutableText extends ImmutableCharSequence implements CharArrayExternalizable, CharSequenceWithStringHash {
|
||||
/**
|
||||
* Holds the default size for primitive blocks of characters.
|
||||
*/
|
||||
@@ -248,6 +250,7 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
|
||||
return true;
|
||||
}
|
||||
|
||||
private int hash;
|
||||
/**
|
||||
* Returns the hash code for this text.
|
||||
*
|
||||
@@ -255,10 +258,9 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = 0;
|
||||
final int length = this.length();
|
||||
for (int i = 0; i < length;) {
|
||||
h = 31 * h + charAt(i++);
|
||||
int h = hash;
|
||||
if (h == 0) {
|
||||
hash = h = StringUtil.stringHashCode(this, 0, length());
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.refactoring.convertToJava;
|
||||
|
||||
import gnu.trove.TIntArrayList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* String builder for only append and remove from the end without insert.
|
||||
*
|
||||
* @author Medvedev Max
|
||||
*/
|
||||
public class MyStringBuilder implements CharSequence {
|
||||
private char[] arr = new char[16];
|
||||
|
||||
private int innerLen = 0;
|
||||
private int realLength = 0;
|
||||
|
||||
List<CharSequence> builders = new ArrayList<CharSequence>(4);
|
||||
TIntArrayList positions = new TIntArrayList(4);
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return realLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public MyStringBuilder append(char c) {
|
||||
if (innerLen == arr.length) {
|
||||
final char[] chars = new char[innerLen * 2];
|
||||
System.arraycopy(arr, 0, chars, 0, arr.length);
|
||||
arr = chars;
|
||||
}
|
||||
arr[innerLen] = c;
|
||||
innerLen++;
|
||||
realLength++;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MyStringBuilder append(CharSequence s) {
|
||||
builders.add(s);
|
||||
positions.add(innerLen);
|
||||
realLength += s.length();
|
||||
return this;
|
||||
}
|
||||
|
||||
public MyStringBuilder removeFromTheEnd(int count) {
|
||||
if (positions.isEmpty()) {
|
||||
innerLen -= count;
|
||||
realLength -= count;
|
||||
return this;
|
||||
}
|
||||
|
||||
final int lastIndex = positions.size() - 1;
|
||||
final int lastPos = positions.getQuick(lastIndex);
|
||||
|
||||
if (lastPos == innerLen) {
|
||||
final CharSequence last = builders.get(lastIndex);
|
||||
final int lastLength = last.length();
|
||||
if (lastLength <= count) {
|
||||
positions.remove(lastIndex);
|
||||
builders.remove(lastIndex);
|
||||
realLength -= lastLength;
|
||||
count -= lastLength;
|
||||
if (count > 0) removeFromTheEnd(count);
|
||||
}
|
||||
else {
|
||||
if (last instanceof MyStringBuilder) {
|
||||
((MyStringBuilder)last).removeFromTheEnd(count);
|
||||
realLength -= count;
|
||||
}
|
||||
else {
|
||||
positions.remove(lastIndex);
|
||||
builders.remove(lastIndex);
|
||||
realLength -= lastLength;
|
||||
int toAppend = lastLength - count;
|
||||
for (int i = 0; i < toAppend; i++) {
|
||||
append(last.charAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (lastPos+count<=innerLen) {
|
||||
innerLen-=count;
|
||||
realLength-=count;
|
||||
}
|
||||
else {
|
||||
final int removed = innerLen - lastPos;
|
||||
innerLen -= removed;
|
||||
realLength -= removed;
|
||||
count -= removed;
|
||||
if (count > 0) removeFromTheEnd(count);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
MyStringBuilder append(Object value) {
|
||||
return append(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (positions.isEmpty()) {
|
||||
return new String(arr);
|
||||
}
|
||||
|
||||
char[] chars = new char[realLength];
|
||||
innerToString(chars, 0);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
private int innerToString(char[] chars, int posInChars) {
|
||||
int posInInner = 0;
|
||||
final int size = positions.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final int pos = positions.get(i);
|
||||
final int length = pos - posInInner;
|
||||
System.arraycopy(arr, posInInner, chars, posInChars, length);
|
||||
posInChars += length;
|
||||
posInInner += length;
|
||||
CharSequence seq = builders.get(i);
|
||||
if (seq instanceof MyStringBuilder) {
|
||||
posInChars = ((MyStringBuilder)seq).innerToString(chars, posInChars);
|
||||
}
|
||||
else {
|
||||
final int seqLength = seq.length();
|
||||
for (int j = 0; j < seqLength; j++) {
|
||||
chars[posInChars] = seq.charAt(j);
|
||||
posInChars++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final int length = innerLen - posInInner;
|
||||
System.arraycopy(arr, posInInner, chars, posInChars, length);
|
||||
return posInChars + length;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user