Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion user/super/com/google/gwt/emul/java/lang/Byte.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public final class Byte extends Number implements Comparable<Byte> {
*/
private static class BoxedValues {
// Box all values according to JLS
private static Byte[] boxedValues = new Byte[256];
private static final Byte[] boxedValues = new Byte[256];

// This method should be marked with @HasNoSideEffects but it seems to trigger a bug
// in the optimizing pipeling and breaks one test.
Expand Down Expand Up @@ -70,6 +70,14 @@ public static String toString(byte b) {
return String.valueOf(b);
}

public static int toUnsignedInt(byte b) {
return b & 0xff;
}

public static long toUnsignedLong(byte b) {
return toUnsignedInt(b);
}

public static Byte valueOf(byte b) {
return BoxedValues.get(b);
}
Expand Down
2 changes: 1 addition & 1 deletion user/super/com/google/gwt/emul/java/lang/Character.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public java.lang.CharSequence subSequence(int start, int end) {
*/
private static class BoxedValues {
// Box values according to JLS - from \u0000 to \u007f
private static Character[] boxedValues = new Character[128];
private static final Character[] boxedValues = new Character[128];

@HasNoSideEffects
private static Character get(char c) {
Expand Down
57 changes: 53 additions & 4 deletions user/super/com/google/gwt/emul/java/lang/Integer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package java.lang;

import static javaemul.internal.Coercions.ensureInt;
import static javaemul.internal.Coercions.toUnsignedInt;

import javaemul.internal.JsUtils;
import javaemul.internal.annotations.HasNoSideEffects;

Expand All @@ -34,7 +37,7 @@ public final class Integer extends Number implements Comparable<Integer> {
*/
private static class BoxedValues {
// Box values according to JLS - between -128 and 127
private static Integer[] boxedValues = new Integer[256];
private static final Integer[] boxedValues = new Integer[256];

@HasNoSideEffects
private static Integer get(int i) {
Expand Down Expand Up @@ -81,10 +84,18 @@ public static int compare(int x, int y) {
}
}

public static int compareUnsigned(int a, int b) {
return compare(a ^ MIN_VALUE, b ^ MIN_VALUE);
}

public static Integer decode(String s) throws NumberFormatException {
return Integer.valueOf(__decodeAndValidateInt(s, MIN_VALUE, MAX_VALUE));
}

public static int divideUnsigned(int dividend, int divisor) {
return ensureInt(toUnsignedInt(dividend) / toUnsignedInt(divisor));
}

public static int hashCode(int i) {
return i;
}
Expand Down Expand Up @@ -170,6 +181,37 @@ public static int parseInt(String s, int radix) throws NumberFormatException {
return __parseAndValidateInt(s, radix, MIN_VALUE, MAX_VALUE);
}

public static int parseUnsignedInt(String s) throws NumberFormatException {
return parseUnsignedInt(s, 10);
}

public static int parseUnsignedInt(String s, int radix) throws NumberFormatException {
if (s == null) {
throw NumberFormatException.forNullInputString();
}

int len = s.length();
if (len == 0 || s.charAt(0) == '-') {
throw NumberFormatException.forInputString(s);
}

// Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
// Integer.MAX_VALUE in base 10 is 10 digits
if (len <= 5 || (radix == 10 && len <= 9)) {
return parseInt(s, radix);
}

long value = Long.parseLong(s, radix);
if (!Long.fitsInUint(value)) {
throw NumberFormatException.forInputString(s);
}
return (int) value;
}

public static int remainderUnsigned(int dividend, int divisor) {
return ensureInt(toUnsignedInt(dividend) % toUnsignedInt(divisor));
}

public static int reverse(int i) {
int[] nibbles = ReverseNibbles.reverseNibbles;
return (nibbles[i >>> 28]) | (nibbles[(i >> 24) & 0xf] << 4)
Expand Down Expand Up @@ -249,13 +291,20 @@ public static Integer valueOf(int i) {
return new Integer(i);
}

public static long toUnsignedLong(int x) {
return x & 0xffff_ffffL;
}

public static String toUnsignedString(int x) {
return toUnsignedString(x, 10);
}

public static Integer valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}

public static Integer valueOf(String s, int radix)
throws NumberFormatException {
return Integer.valueOf(Integer.parseInt(s, radix));
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return valueOf(parseInt(s, radix));
}

private final transient int value;
Expand Down
151 changes: 142 additions & 9 deletions user/super/com/google/gwt/emul/java/lang/Long.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public final class Long extends Number implements Comparable<Long> {
/** Use nested class to avoid clinit on outer. */
static class BoxedValues {
// Box values according to JLS - between -128 and 127
static Long[] boxedValues = new Long[256];
static final Long[] boxedValues = new Long[256];

@HasNoSideEffects
private static Long get(long l) {
Expand Down Expand Up @@ -59,11 +59,44 @@ public static int compare(long x, long y) {
}
}

public static int compareUnsigned(long a, long b) {
return compare(a ^ MIN_VALUE, b ^ MIN_VALUE);
}

public static Long decode(String s) throws NumberFormatException {
__Decode decode = __decodeNumberString(s);
return valueOf(decode.payload, decode.radix);
}

public static long divideUnsigned(long dividend, long divisor) {
if (divisor < 0) { // i.e., divisor >= 2^63:
if (compare(dividend, divisor) < 0) {
return 0; // dividend < divisor
} else {
return 1; // dividend >= divisor
}
}

// Optimization - use signed division if dividend < 2^63
if (dividend >= 0) {
return dividend / divisor;
}

/*
* Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
* guaranteed to be either exact or one less than the correct value. This follows from fact
* that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not
* quite trivial.
*/
long quotient = ((dividend >>> 1) / divisor) << 1;
long rem = dividend - quotient * divisor;
if (compare(rem, divisor) >= 0) {
return quotient + 1;
} else {
return quotient;
}
}

public static int hashCode(long l) {
return LongUtils.getHighBits(l) ^ (int) l;
}
Expand Down Expand Up @@ -121,6 +154,43 @@ public static long reverse(long l) {
return LongUtils.fromBits(Integer.reverse(high), Integer.reverse(low));
}

public static long parseUnsignedLong(String s) throws NumberFormatException {
return parseUnsignedLong(s, 10);
}

public static long parseUnsignedLong(String s, int radix) throws NumberFormatException {
return __parseAndValidateUnsignedLong(s, radix);
}

public static long remainderUnsigned(long dividend, long divisor) {
if (divisor < 0) { // i.e., divisor >= 2^63:
if (compare(dividend, divisor) < 0) {
return dividend; // dividend < divisor
} else {
return dividend - divisor; // dividend >= divisor
}
}

// Optimization - use signed modulus if dividend < 2^63
if (dividend >= 0) {
return dividend % divisor;
}

/*
* Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
* guaranteed to be either exact or one less than the correct value. This follows from fact
* that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not
* quite trivial.
*/
long quotient = ((dividend >>> 1) / divisor) << 1;
long rem = dividend - quotient * divisor;
if (compare(rem, divisor) >= 0) {
return rem - divisor;
} else {
return rem;
}
}

public static long reverseBytes(long l) {
int high = LongUtils.getHighBits(l);
int low = (int) l;
Expand Down Expand Up @@ -163,15 +233,15 @@ public static long sum(long a, long b) {
}

public static String toBinaryString(long value) {
return toPowerOfTwoUnsignedString(value, 1);
return toUnsignedString(value, 2);
}

public static String toHexString(long value) {
return toPowerOfTwoUnsignedString(value, 4);
return toUnsignedString(value, 16);
}

public static String toOctalString(long value) {
return toPowerOfTwoUnsignedString(value, 3);
return toUnsignedString(value, 8);
}

public static String toString(long value) {
Expand Down Expand Up @@ -219,17 +289,59 @@ public static String toString(long value, int intRadix) {

public static Long valueOf(long l) {
if (l > -129 && l < 128) {
return BoxedValues.get(l);
return BoxedValues.get(l);
}
return new Long(l);
}

public static Long valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
public static String toUnsignedString(long value) {
return toUnsignedString(value, 10);
}

public static Long valueOf(String s, int radix) throws NumberFormatException {
return valueOf(parseLong(s, radix));
public static String toUnsignedString(long value, int intRadix) {
if (fitsInUint(value)) {
return Integer.toUnsignedString((int) value, intRadix);
}

if (intRadix < Character.MIN_RADIX || intRadix > Character.MAX_RADIX) {
intRadix = 10;
}

if (isPowerOfTwo(intRadix)) {
return toPowerOfTwoUnsignedString(value, intRadix);
}

if (value >= 0) {
return toString(value, intRadix);
}

// Convert radix to long before hand to avoid costly conversion on each iteration.
long radix = intRadix;
if (intRadix == 10) {
long quotient = divideUnsigned(value, radix);
int rem = (int) (value - quotient * radix);
return toString(quotient) + rem;
}

int bufLen = intRadix < 8 ? 65 : 23; // Max chars in result (conservative)
char[] buf = new char[bufLen];
int cursor = bufLen;
if (value < 0) {
// Separate off the last digit using unsigned division. That will leave
// a number that is nonnegative as a signed integer.
long quotient = divideUnsigned(value, radix);
int rem = (int) (value - quotient * radix);
buf[--cursor] = Character.forDigit(rem, intRadix);
value = quotient;
}

// Simple modulo/division approach
while (value > 0) {
buf[--cursor] = Character.forDigit((int) (value % radix), intRadix);
value /= radix;
}

return new String(buf, cursor, buf.length - cursor);
}

private static String toPowerOfTwoUnsignedString(long value, int shift) {
Expand All @@ -252,6 +364,27 @@ private static String toPowerOfTwoUnsignedString(long value, int shift) {
return String.valueOf(buf, pos, bufSize - pos);
}

private static boolean isPowerOfTwo(int x) {
return (x & (x - 1)) == 0;
}

private static int log2(int x) {
return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(x);
}

static boolean fitsInUint(long value) {
int highBits = (int) (value >> 32);
return highBits == 0;
}

public static Long valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}

public static Long valueOf(String s, int radix) throws NumberFormatException {
return valueOf(parseLong(s, radix));
}

private final transient long value;

public Long(long value) {
Expand Down
Loading