From 73d23791852a247a0eb5a62b4b9a5bfd01a28a1a Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 16 May 2023 10:37:38 +0200 Subject: [PATCH] classlib: add Integer/Long parse subsequence --- .../teavm/classlib/java/lang/TInteger.java | 43 +++++++++++++------ .../org/teavm/classlib/java/lang/TLong.java | 40 +++++++++++------ .../teavm/classlib/java/lang/IntegerTest.java | 9 +++- .../teavm/classlib/java/lang/LongTest.java | 11 +++++ 4 files changed, 76 insertions(+), 27 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java index e8b7886f6..a42a2a358 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java @@ -16,6 +16,7 @@ package org.teavm.classlib.java.lang; import static org.teavm.classlib.impl.IntegerUtil.toUnsignedLogRadixString; +import java.util.Objects; import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.interop.NoSideEffects; @@ -63,42 +64,56 @@ public class TInteger extends TNumber implements TComparable { } public static int parseInt(String s, int radix) throws TNumberFormatException { + if (s == null) { + throw new TNumberFormatException("String is null"); + } + return parseIntImpl(s, 0, s.length(), radix); + } + + public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix) throws TNumberFormatException { + return parseIntImpl(Objects.requireNonNull(s), beginIndex, endIndex, radix); + } + + private static int parseIntImpl(CharSequence s, int beginIndex, int endIndex, int radix) + throws TNumberFormatException { + if (beginIndex == endIndex) { + throw new TNumberFormatException("String is empty"); + } if (radix < TCharacter.MIN_RADIX || radix > TCharacter.MAX_RADIX) { throw new TNumberFormatException("Illegal radix: " + radix); } - if (s == null || s.isEmpty()) { - throw new TNumberFormatException("String is null or empty"); - } boolean negative = false; - int index = 0; - switch (s.charAt(0)) { + int index = beginIndex; + switch (s.charAt(index)) { case '-': negative = true; - index = 1; + index++; break; case '+': - index = 1; + index++; break; } int value = 0; - if (index == s.length()) { + if (index == endIndex) { throw new TNumberFormatException(); } - while (index < s.length()) { + while (index < endIndex) { int digit = TCharacter.getNumericValue(s.charAt(index++)); if (digit < 0) { - throw new TNumberFormatException("String contains invalid digits: " + s); + throw new TNumberFormatException("String contains invalid digits: " + + s.subSequence(beginIndex, endIndex)); } if (digit >= radix) { - throw new TNumberFormatException("String contains digits out of radix " + radix - + ": " + s); + throw new TNumberFormatException("String contains digits out of radix " + radix + ": " + + s.subSequence(beginIndex, endIndex)); } value = radix * value + digit; if (value < 0) { - if (index == s.length() && value == MIN_VALUE && negative) { + if (index == endIndex && value == MIN_VALUE && negative) { return MIN_VALUE; } - throw new TNumberFormatException("The value is too big for int type: " + s); + throw new TNumberFormatException("The value is too big for int type: " + + s.subSequence(beginIndex, endIndex)); } } return negative ? -value : value; diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java index 200b79ba4..d7b9e0881 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java @@ -16,6 +16,7 @@ package org.teavm.classlib.java.lang; import static org.teavm.classlib.impl.IntegerUtil.toUnsignedLogRadixString; +import java.util.Objects; import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.interop.NoSideEffects; @@ -39,39 +40,54 @@ public class TLong extends TNumber implements TComparable { } public static long parseLong(String s, int radix) throws TNumberFormatException { + if (s == null) { + throw new TNumberFormatException("String is null"); + } + return parseLongImpl(s, 0, s.length(), radix); + } + + public static long parseLong(CharSequence s, int beginIndex, int endIndex, int radix) + throws TNumberFormatException { + return parseLongImpl(Objects.requireNonNull(s), beginIndex, endIndex, radix); + } + + private static long parseLongImpl(CharSequence s, int beginIndex, int endIndex, int radix) + throws TNumberFormatException { if (radix < TCharacter.MIN_RADIX || radix > TCharacter.MAX_RADIX) { throw new TNumberFormatException("Illegal radix: " + radix); } - if (s == null || s.isEmpty()) { - throw new TNumberFormatException("String is null or empty"); + if (beginIndex == endIndex) { + throw new TNumberFormatException("String is empty"); } boolean negative = false; - int index = 0; - switch (s.charAt(0)) { + int index = beginIndex; + switch (s.charAt(index)) { case '-': negative = true; - index = 1; + index++; break; case '+': - index = 1; + index++; break; } long value = 0; - while (index < s.length()) { + while (index < endIndex) { int digit = TCharacter.getNumericValue(s.charAt(index++)); if (digit < 0) { - throw new TNumberFormatException("String contains invalid digits: " + s); + throw new TNumberFormatException("String contains invalid digits: " + + s.subSequence(beginIndex, endIndex)); } if (digit >= radix) { - throw new TNumberFormatException("String contains digits out of radix " + radix - + ": " + s); + throw new TNumberFormatException("String contains digits out of radix " + radix + ": " + + s.subSequence(beginIndex, endIndex)); } value = radix * value + digit; if (value < 0) { - if (index == s.length() && value == MIN_VALUE && negative) { + if (index == endIndex && value == MIN_VALUE && negative) { return MIN_VALUE; } - throw new TNumberFormatException("The value is too big for int type: " + s); + throw new TNumberFormatException("The value is too big for int type: " + + s.subSequence(beginIndex, endIndex)); } } return negative ? -value : value; diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java index f484ede3c..6405b8bfa 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java @@ -38,6 +38,14 @@ public class IntegerTest { assertEquals(411787, Integer.parseInt("Kona", 27)); } + @Test + public void parsesIntegerInSubstring() { + assertEquals(0, Integer.parseInt("[0]", 1, 2, 10)); + assertEquals(473, Integer.parseInt("[473]", 1, 4, 10)); + assertEquals(42, Integer.parseInt("[+42]", 1, 4, 10)); + assertEquals(-255, Integer.parseInt("[-FF]", 1, 4, 16)); + } + @Test public void parsesMinInteger() { assertEquals(-2147483648, Integer.parseInt("-2147483648", 10)); @@ -141,7 +149,6 @@ public class IntegerTest { assertTrue(Integer.compare(Integer.MIN_VALUE, Integer.MAX_VALUE) < 0); } - @Test public void getFromSystemProperty() { System.setProperty("test.foo", "23"); diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java index 4b0f35fbe..1d4bfdfda 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java @@ -21,9 +21,20 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.SkipJVM; import org.teavm.junit.TeaVMTestRunner; +import org.teavm.junit.WholeClassCompilation; @RunWith(TeaVMTestRunner.class) +@WholeClassCompilation public class LongTest { + + @Test + public void parsesLongInSubstring() { + assertEquals(0, Long.parseLong("[0]", 1, 2, 10)); + assertEquals(473, Long.parseLong("[473]", 1, 4, 10)); + assertEquals(42, Long.parseLong("[+42]", 1, 4, 10)); + assertEquals(-255, Long.parseLong("[-FF]", 1, 4, 16)); + } + @Test public void compares() { assertTrue(Long.compare(10, 5) > 0);