classlib: minor improvements (#843)

* String.substring performance
* More argument validation in String methods
* Object.checkFromIndexSize corner case for large indexes
* ByteBuffer.wrap argument validation
This commit is contained in:
Ivan Hetman 2023-10-31 10:45:23 +02:00 committed by GitHub
parent a1cc817504
commit 5b5c26cf99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 20 deletions

View File

@ -15,7 +15,10 @@
*/ */
package org.teavm.classlib.java.lang; package org.teavm.classlib.java.lang;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import org.teavm.classlib.PlatformDetector; import org.teavm.classlib.PlatformDetector;
import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.io.TUnsupportedEncodingException; import org.teavm.classlib.java.io.TUnsupportedEncodingException;
@ -52,7 +55,7 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
private native void borrowChars(TString other); private native void borrowChars(TString other);
public TString(char[] characters) { public TString(char[] characters) {
this(characters, 0, characters.length); initWithCharArray(characters, 0, characters.length);
} }
public TString(Object nativeString) { public TString(Object nativeString) {
@ -61,9 +64,7 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
private native Object nativeString(); private native Object nativeString();
public TString(char[] value, int offset, int count) { public TString(char[] value, int offset, int count) {
if (offset < 0 || count < 0 || offset + count > value.length) { Objects.checkFromIndexSize(offset, count, value.length);
throw new IndexOutOfBoundsException();
}
initWithCharArray(value, offset, count); initWithCharArray(value, offset, count);
} }
@ -80,7 +81,7 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
private native void takeCharArray(char[] characters); private native void takeCharArray(char[] characters);
public TString(byte[] bytes, int offset, int length, TString charsetName) throws TUnsupportedEncodingException { public TString(byte[] bytes, int offset, int length, TString charsetName) throws TUnsupportedEncodingException {
this(bytes, offset, length, TCharset.forName(charsetName.toString())); initWithBytes(bytes, offset, length, TCharset.forName(charsetName.toString()));
} }
public TString(byte[] bytes, int offset, int length, TCharset charset) { public TString(byte[] bytes, int offset, int length, TCharset charset) {
@ -92,15 +93,15 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
} }
public TString(byte[] bytes) { public TString(byte[] bytes) {
this(bytes, 0, bytes.length); initWithBytes(bytes, 0, bytes.length, TUTF8Charset.INSTANCE);
} }
public TString(byte[] bytes, TString charsetName) throws TUnsupportedEncodingException { public TString(byte[] bytes, TString charsetName) throws TUnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName); initWithBytes(bytes, 0, bytes.length, TCharset.forName(charsetName.toString()));
} }
public TString(byte[] bytes, TCharset charset) { public TString(byte[] bytes, TCharset charset) {
this(bytes, 0, bytes.length, charset); initWithBytes(bytes, 0, bytes.length, charset);
} }
public TString(int[] codePoints, int offset, int count) { public TString(int[] codePoints, int offset, int count) {
@ -133,8 +134,12 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
takeCharArray(characters); takeCharArray(characters);
} }
public TString(TStringBuffer sb) {
initWithCharArray(sb.buffer, 0, sb.length());
}
public TString(TStringBuilder sb) { public TString(TStringBuilder sb) {
this(sb.buffer, 0, sb.length()); initWithCharArray(sb.buffer, 0, sb.length());
} }
private TString(int length) { private TString(int length) {
@ -418,20 +423,20 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
} }
public TString substring(int beginIndex, int endIndex) { public TString substring(int beginIndex, int endIndex) {
if (beginIndex > endIndex) { int length = charactersLength();
throw new TIndexOutOfBoundsException();
}
if (beginIndex == endIndex) { if (beginIndex == endIndex) {
return EMPTY; return EMPTY;
} }
if (PlatformDetector.isJavaScript()) { if (beginIndex == 0 && endIndex == length) {
var nativeSubstring = substringJS(nativeString(), beginIndex, endIndex); return this;
return nativeSubstring != nativeString() ? new TString(nativeSubstring) : this;
} }
if (beginIndex == 0 && endIndex == length()) { if (PlatformDetector.isJavaScript()) {
return this; if (beginIndex < 0 || beginIndex > endIndex || endIndex > length) {
throw new TStringIndexOutOfBoundsException();
}
return new TString(substringJS(nativeString(), beginIndex, endIndex));
} }
return new TString(fastCharArray(), beginIndex, endIndex - beginIndex); return new TString(fastCharArray(), beginIndex, endIndex - beginIndex);
} }
@ -669,7 +674,11 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
} }
public byte[] getBytes(TString charsetName) throws TUnsupportedEncodingException { public byte[] getBytes(TString charsetName) throws TUnsupportedEncodingException {
try {
return getBytes(TCharset.forName(charsetName.toString())); return getBytes(TCharset.forName(charsetName.toString()));
} catch (UnsupportedCharsetException | IllegalCharsetNameException x) {
throw new TUnsupportedEncodingException();
}
} }
public byte[] getBytes() { public byte[] getBytes() {

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.classlib.java.nio; package org.teavm.classlib.java.nio;
import java.util.Objects;
import org.teavm.classlib.java.lang.TComparable; import org.teavm.classlib.java.lang.TComparable;
public abstract class TByteBuffer extends TBuffer implements TComparable<TByteBuffer> { public abstract class TByteBuffer extends TBuffer implements TComparable<TByteBuffer> {
@ -45,6 +46,7 @@ public abstract class TByteBuffer extends TBuffer implements TComparable<TByteBu
} }
public static TByteBuffer wrap(byte[] array, int offset, int length) { public static TByteBuffer wrap(byte[] array, int offset, int length) {
Objects.checkFromIndexSize(offset, length, array.length);
return new TByteBufferImpl(0, array.length, array, offset, offset + length, false, false); return new TByteBufferImpl(0, array.length, array, offset, offset + length, false, false);
} }

View File

@ -158,14 +158,14 @@ public final class TObjects extends TObject {
} }
public static int checkFromIndexSize(int fromIndex, int size, int length) { public static int checkFromIndexSize(int fromIndex, int size, int length) {
if (fromIndex < 0 || size < 0 || fromIndex + size > length) { if (fromIndex < 0 || size < 0 || size > length - fromIndex) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
return fromIndex; return fromIndex;
} }
public static long checkFromIndexSize(long fromIndex, long size, long length) { public static long checkFromIndexSize(long fromIndex, long size, long length) {
if (fromIndex < 0 || size < 0 || fromIndex + size > length) { if (fromIndex < 0 || size < 0 || size > length - fromIndex) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
return fromIndex; return fromIndex;