Adds java.lang.String methods. Makes intern on all string constants.

This commit is contained in:
konsoletyper 2014-03-17 00:53:22 +04:00
parent e8fc894bc9
commit 91a7a9ba22
4 changed files with 69 additions and 1 deletions

View File

@ -19,6 +19,9 @@ import org.teavm.classlib.impl.charset.*;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.io.TUnsupportedEncodingException;
import org.teavm.classlib.java.util.TArrays;
import org.teavm.classlib.java.util.TComparator;
import org.teavm.classlib.java.util.THashMap;
import org.teavm.classlib.java.util.TMap;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.InjectedBy;
import org.teavm.javascript.ni.Rename;
@ -28,8 +31,14 @@ import org.teavm.javascript.ni.Rename;
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TString extends TObject implements TSerializable, TComparable<TString>, TCharSequence {
public static final TComparator<TString> CASE_INSENSITIVE_ORDER = new TComparator<TString>() {
@Override public int compare(TString o1, TString o2) {
return o1.compareToIgnoreCase(o2);
}
};
private char[] characters;
private transient int hashCode;
private static TMap<TString, TString> pool = new THashMap<>();
public TString() {
this.characters = new char[0];
@ -183,6 +192,21 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
return length() - anotherString.length();
}
public int compareToIgnoreCase(TString anotherString) {
if (this == anotherString) {
return 0;
}
int l = TMath.min(length(), anotherString.length());
for (int i = 0; i < l; ++i) {
char a = TCharacter.toLowerCase(charAt(i));
char b = TCharacter.toLowerCase(anotherString.charAt(i));
if (a - b != 0) {
return a - b;
}
}
return length() - anotherString.length();
}
public boolean startsWith(TString prefix, int toffset) {
if (toffset + prefix.length() > length()) {
return false;
@ -548,4 +572,32 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
}
return new TString(codePoints, 0, codePointCount);
}
public TString toUpperCase() {
if (isEmpty()) {
return this;
}
int[] codePoints = new int[characters.length];
int codePointCount = 0;
for (int i = 0; i < characters.length; ++i) {
if (i == characters.length - 1 || !UTF16Helper.isHighSurrogate(characters[i]) ||
!UTF16Helper.isLowSurrogate(characters[i + 1])) {
codePoints[codePointCount++] = TCharacter.toUpperCase(characters[i]);
} else {
codePoints[codePointCount++] = TCharacter.toUpperCase(UTF16Helper.buildCodePoint(
characters[i], characters[i + 1]));
++i;
}
}
return new TString(codePoints, 0, codePointCount);
}
public TString intern() {
TString interned = pool.get(this);
if (interned == null) {
interned = this;
pool.put(interned, interned);
}
return interned;
}
}

View File

@ -290,4 +290,14 @@ public class StringTest {
public void makesLowerCase() {
assertEquals("foo bar", "FoO bAr".toLowerCase());
}
@Test
public void interns() {
assertSame(("ab" + "c").intern(), ("a" + "bc").intern());
}
@Test
public void internsConstants() {
assertSame("abc", ("a" + "bc").intern());
}
}

View File

@ -34,6 +34,8 @@ import org.teavm.model.*;
* @author Alexey Andreev
*/
public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext {
private static final MethodReference internRef = new MethodReference("java.lang.String", "intern",
ValueType.object("java.lang.String"));
private static final String variableNames = "abcdefghijkmnopqrstuvwxyz";
private NamingStrategy naming;
private SourceWriter writer;
@ -930,7 +932,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
ValueType type = (ValueType)cst;
return "$rt_cls(" + typeToClsString(naming, type) + ")";
} else if (cst instanceof String) {
return "$rt_str(\"" + escapeString((String)cst) + "\")";
return naming.getFullNameFor(internRef) + "($rt_str(\"" + escapeString((String)cst) + "\"))";
} else if (cst instanceof Long) {
long value = (Long)cst;
if (value == 0) {

View File

@ -174,6 +174,10 @@ public class TeaVM implements TeaVMHost {
dependencyChecker.linkMethod(new MethodReference("java.lang.String", "getChars",
ValueType.INTEGER, ValueType.INTEGER, ValueType.arrayOf(ValueType.CHARACTER), ValueType.INTEGER,
ValueType.VOID), DependencyStack.ROOT).use();
MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference("java.lang.String", "intern",
ValueType.object("java.lang.String")), DependencyStack.ROOT);
internDep.getVariable(0).propagate("java.lang.String");
internDep.use();
dependencyChecker.linkMethod(new MethodReference("java.lang.String", "length", ValueType.INTEGER),
DependencyStack.ROOT).use();
dependencyChecker.linkMethod(new MethodReference("java.lang.Object", new MethodDescriptor("clone",