Merge "Revert "OpenJDK 11: Merging in java.lang.ref.Cleaner""
diff --git a/api/current.txt b/api/current.txt
index 6b3f9fa..92cb73a 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -3177,8 +3177,8 @@
}
public final class Integer extends java.lang.Number implements java.lang.Comparable<java.lang.Integer> {
- ctor public Integer(int);
- ctor public Integer(@NonNull String) throws java.lang.NumberFormatException;
+ ctor @Deprecated public Integer(int);
+ ctor @Deprecated public Integer(@NonNull String) throws java.lang.NumberFormatException;
method public static int bitCount(int);
method public static int compare(int, int);
method public int compareTo(@NonNull Integer);
@@ -3200,8 +3200,10 @@
method public static int numberOfLeadingZeros(int);
method public static int numberOfTrailingZeros(int);
method public static int parseInt(@NonNull String, int) throws java.lang.NumberFormatException;
+ method public static int parseInt(@NonNull CharSequence, int, int, int) throws java.lang.NumberFormatException;
method public static int parseInt(@NonNull String) throws java.lang.NumberFormatException;
method public static int parseUnsignedInt(@NonNull String, int) throws java.lang.NumberFormatException;
+ method public static int parseUnsignedInt(@NonNull CharSequence, int, int, int) throws java.lang.NumberFormatException;
method public static int parseUnsignedInt(@NonNull String) throws java.lang.NumberFormatException;
method public static int remainderUnsigned(int, int);
method public static int reverse(int);
@@ -3253,8 +3255,8 @@
}
public final class Long extends java.lang.Number implements java.lang.Comparable<java.lang.Long> {
- ctor public Long(long);
- ctor public Long(@NonNull String) throws java.lang.NumberFormatException;
+ ctor @Deprecated public Long(long);
+ ctor @Deprecated public Long(@NonNull String) throws java.lang.NumberFormatException;
method public static int bitCount(long);
method public static int compare(long, long);
method public int compareTo(@NonNull Long);
@@ -3276,8 +3278,10 @@
method public static int numberOfLeadingZeros(long);
method public static int numberOfTrailingZeros(long);
method public static long parseLong(@NonNull String, int) throws java.lang.NumberFormatException;
+ method public static long parseLong(@NonNull CharSequence, int, int, int) throws java.lang.NumberFormatException;
method public static long parseLong(@NonNull String) throws java.lang.NumberFormatException;
method public static long parseUnsignedLong(@NonNull String, int) throws java.lang.NumberFormatException;
+ method public static long parseUnsignedLong(@NonNull CharSequence, int, int, int) throws java.lang.NumberFormatException;
method public static long parseUnsignedLong(@NonNull String) throws java.lang.NumberFormatException;
method public static long remainderUnsigned(long, long);
method public static long reverse(long);
diff --git a/ojluni/annotations/sdk/nullability/java/lang/Integer.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/Integer.annotated.java
index d3f6753..f06aa0b 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/Integer.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/Integer.annotated.java
@@ -53,10 +53,14 @@
public static int parseInt(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+public static int parseInt(@libcore.util.NonNull java.lang.CharSequence s, int beginIndex, int endIndex, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
public static int parseUnsignedInt(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
public static int parseUnsignedInt(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+public static int parseUnsignedInt(@libcore.util.NonNull java.lang.CharSequence s, int beginIndex, int endIndex, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
@libcore.util.NonNull public static java.lang.Integer valueOf(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
@libcore.util.NonNull public static java.lang.Integer valueOf(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
diff --git a/ojluni/annotations/sdk/nullability/java/lang/Long.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/Long.annotated.java
index b077ef5..7e9e6f5 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/Long.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/Long.annotated.java
@@ -54,10 +54,14 @@
public static long parseLong(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+public static long parseLong(@libcore.util.NonNull java.lang.CharSequence s, int beginIndex, int endIndex, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
public static long parseUnsignedLong(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
public static long parseUnsignedLong(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+public static long parseUnsignedLong(@libcore.util.NonNull java.lang.CharSequence s, int beginIndex, int endIndex, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
@libcore.util.NonNull public static java.lang.Long valueOf(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
@libcore.util.NonNull public static java.lang.Long valueOf(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
index 08d1aa3..6739605 100644
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -45,6 +45,7 @@
* @since 1.5
*/
abstract class AbstractStringBuilder implements Appendable, CharSequence {
+ // TODO: remove java.lang.Integer.getChars(int, int, char[]) once updated to byte[] from 11.
/**
* The value is used for character storage.
*/
diff --git a/ojluni/src/main/java/java/lang/Integer.java b/ojluni/src/main/java/java/lang/Integer.java
index 93ae24c..3df8c28 100644
--- a/ojluni/src/main/java/java/lang/Integer.java
+++ b/ojluni/src/main/java/java/lang/Integer.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,9 @@
package java.lang;
import java.lang.annotation.Native;
+import java.util.Objects;
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.VM;
/**
* The {@code Integer} class wraps a value of the primitive type
@@ -48,7 +51,7 @@
* @author Arthur van Hoff
* @author Josh Bloch
* @author Joseph D. Darcy
- * @since JDK1.0
+ * @since 1.0
*/
public final class Integer extends Number implements Comparable<Integer> {
/**
@@ -67,7 +70,7 @@
* The {@code Class} instance representing the primitive type
* {@code int}.
*
- * @since JDK1.1
+ * @since 1.1
*/
@SuppressWarnings("unchecked")
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
@@ -75,7 +78,7 @@
/**
* All possible chars for representing a number as a String
*/
- final static char[] digits = {
+ static final char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
@@ -137,26 +140,59 @@
return toString(i);
}
- char buf[] = new char[33];
+ // BEGIN Android-changed: Use single-byte chars.
+ /*
+ if (COMPACT_STRINGS) {
+ */
+ byte[] buf = new byte[33];
+ boolean negative = (i < 0);
+ int charPos = 32;
+
+ if (!negative) {
+ i = -i;
+ }
+
+ while (i <= -radix) {
+ buf[charPos--] = (byte)digits[-(i % radix)];
+ i = i / radix;
+ }
+ buf[charPos] = (byte)digits[-i];
+
+ if (negative) {
+ buf[--charPos] = '-';
+ }
+
+ /*
+ return StringLatin1.newString(buf, charPos, (33 - charPos));
+ }
+ return toStringUTF16(i, radix);
+ */
+ return new String(buf, charPos, (33 - charPos));
+ // END Android-changed: Use single-byte chars.
+ }
+
+ // BEGIN Android-removed: UTF16 version of toString.
+ /*
+ private static String toStringUTF16(int i, int radix) {
+ byte[] buf = new byte[33 * 2];
boolean negative = (i < 0);
int charPos = 32;
-
if (!negative) {
i = -i;
}
-
while (i <= -radix) {
- buf[charPos--] = digits[-(i % radix)];
+ StringUTF16.putChar(buf, charPos--, digits[-(i % radix)]);
i = i / radix;
}
- buf[charPos] = digits[-i];
+ StringUTF16.putChar(buf, charPos, digits[-i]);
if (negative) {
- buf[--charPos] = '-';
+ StringUTF16.putChar(buf, --charPos, '-');
}
-
- return new String(buf, charPos, (33 - charPos));
+ return StringUTF16.newString(buf, charPos, (33 - charPos));
}
+ */
+ // END Android-removed: UTF16 version of toString.
/**
* Returns a string representation of the first argument as an
@@ -228,7 +264,7 @@
* represented by the argument in hexadecimal (base 16).
* @see #parseUnsignedInt(String, int)
* @see #toUnsignedString(int, int)
- * @since JDK1.0.2
+ * @since 1.0.2
*/
public static String toHexString(int i) {
return toUnsignedString0(i, 4);
@@ -266,7 +302,7 @@
* represented by the argument in octal (base 8).
* @see #parseUnsignedInt(String, int)
* @see #toUnsignedString(int, int)
- * @since JDK1.0.2
+ * @since 1.0.2
*/
public static String toOctalString(int i) {
return toUnsignedString0(i, 3);
@@ -298,7 +334,7 @@
* represented by the argument in binary (base 2).
* @see #parseUnsignedInt(String, int)
* @see #toUnsignedString(int, int)
- * @since JDK1.0.2
+ * @since 1.0.2
*/
public static String toBinaryString(int i) {
return toUnsignedString0(i, 1);
@@ -311,42 +347,82 @@
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
- char[] buf = new char[chars];
- formatUnsignedInt(val, shift, buf, 0, chars);
- // Android-changed: Use regular constructor instead of one which takes over "buf".
- // return new String(buf, true);
+ // BEGIN Android-changed: Use single-byte chars.
+ /*
+ if (COMPACT_STRINGS) {
+ */
+ byte[] buf = new byte[chars];
+ formatUnsignedInt(val, shift, buf, 0, chars);
+ /*
+ return new String(buf, LATIN1);
+ } else {
+ byte[] buf = new byte[chars * 2];
+ formatUnsignedIntUTF16(val, shift, buf, 0, chars);
+ return new String(buf, UTF16);
+ }
+ */
return new String(buf);
+ // END Android-changed: Use single-byte chars.
}
/**
- * Format a long (treated as unsigned) into a character buffer.
+ * Format an {@code int} (treated as unsigned) into a character buffer. If
+ * {@code len} exceeds the formatted ASCII representation of {@code val},
+ * {@code buf} will be padded with leading zeroes.
+ *
* @param val the unsigned int to format
* @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
* @param buf the character buffer to write to
* @param offset the offset in the destination buffer to start at
* @param len the number of characters to write
- * @return the lowest character location used
*/
- static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
- int charPos = len;
+ static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
+ // assert shift > 0 && shift <=5 : "Illegal shift value";
+ // assert offset >= 0 && offset < buf.length : "illegal offset";
+ // assert len > 0 && (offset + len) <= buf.length : "illegal length";
+ int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1;
do {
- buf[offset + --charPos] = Integer.digits[val & mask];
+ buf[--charPos] = Integer.digits[val & mask];
val >>>= shift;
- } while (val != 0 && charPos > 0);
-
- return charPos;
+ } while (charPos > offset);
}
+ /** byte[]/LATIN1 version */
+ static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {
+ int charPos = offset + len;
+ int radix = 1 << shift;
+ int mask = radix - 1;
+ do {
+ buf[--charPos] = (byte)Integer.digits[val & mask];
+ val >>>= shift;
+ } while (charPos > offset);
+ }
+
+ // BEGIN Android-removed: UTF16 version of formatUnsignedInt().
+ /*
+ /** byte[]/UTF16 version *
+ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
+ int charPos = offset + len;
+ int radix = 1 << shift;
+ int mask = radix - 1;
+ do {
+ StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);
+ val >>>= shift;
+ } while (charPos > offset);
+ }
+ */
+ // END Android-removed: UTF16 version of formatUnsignedInt().
+
// BEGIN Android-changed: Cache the toString() result for small values.
private static final String[] SMALL_NEG_VALUES = new String[100];
private static final String[] SMALL_NONNEG_VALUES = new String[100];
// END Android-changed: Cache the toString() result for small values.
- final static char [] DigitTens = {
+ static final byte[] DigitTens = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
@@ -359,7 +435,7 @@
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
} ;
- final static char [] DigitOnes = {
+ static final byte[] DigitOnes = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
@@ -372,24 +448,6 @@
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
} ;
- // I use the "invariant division by multiplication" trick to
- // accelerate Integer.toString. In particular we want to
- // avoid division by 10.
- //
- // The "trick" has roughly the same performance characteristics
- // as the "classic" Integer.toString code on a non-JIT VM.
- // The trick avoids .rem and .div calls but has a longer code
- // path and is thus dominated by dispatch overhead. In the
- // JIT case the dispatch overhead doesn't exist and the
- // "trick" is considerably faster than the classic code.
- //
- // TODO-FIXME: convert (x * 52429) into the equiv shift-add
- // sequence.
- //
- // RE: Division by Invariant Integers using Multiplication
- // T Gralund, P Montgomery
- // ACM PLDI 1994
- //
/**
* Returns a {@code String} object representing the
@@ -401,12 +459,9 @@
* @param i an integer to be converted.
* @return a string representation of the argument in base 10.
*/
+ @HotSpotIntrinsicCandidate
public static String toString(int i) {
- if (i == Integer.MIN_VALUE)
- return "-2147483648";
-
// BEGIN Android-changed: Cache the String for small values.
- // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
boolean negative = i < 0;
boolean small = negative ? i > -100 : i < 100;
if (small) {
@@ -416,25 +471,37 @@
i = -i;
if (smallValues[i] == null) {
smallValues[i] =
- i < 10 ? new String(new char[]{'-', DigitOnes[i]})
- : new String(new char[]{'-', DigitTens[i], DigitOnes[i]});
+ i < 10 ? new String(new byte[]{'-', DigitOnes[i]})
+ : new String(new byte[]{'-', DigitTens[i], DigitOnes[i]});
}
} else {
if (smallValues[i] == null) {
smallValues[i] =
- i < 10 ? new String(new char[]{DigitOnes[i]})
- : new String(new char[]{DigitTens[i], DigitOnes[i]});
+ i < 10 ? new String(new byte[]{DigitOnes[i]})
+ : new String(new byte[]{DigitTens[i], DigitOnes[i]});
}
}
return smallValues[i];
}
- int size = negative ? stringSize(-i) + 1 : stringSize(i);
// END Android-changed: Cache the String for small values.
- char[] buf = new char[size];
- getChars(i, size, buf);
- // Android-changed: Use regular constructor instead of one which takes over "buf".
- // return new String(buf, true);
+ int size = stringSize(i);
+
+ // BEGIN Android-changed: Use single-byte chars.
+ /*
+ if (COMPACT_STRINGS) {
+ */
+ byte[] buf = new byte[size];
+ getChars(i, size, buf);
+ /*
+ return new String(buf, LATIN1);
+ } else {
+ byte[] buf = new byte[size * 2];
+ StringUTF16.getChars(i, size, buf);
+ return new String(buf, UTF16);
+ }
+ */
return new String(buf);
+ // END Android-changed: Use single-byte chars.
}
/**
@@ -462,50 +529,115 @@
* digit at the specified index (exclusive), and working
* backwards from there.
*
- * Will fail if i == Integer.MIN_VALUE
+ * @implNote This method converts positive inputs into negative
+ * values, to cover the Integer.MIN_VALUE case. Converting otherwise
+ * (negative to positive) will expose -Integer.MIN_VALUE that overflows
+ * integer.
+ *
+ * @param i value to convert
+ * @param index next index, after the least significant digit
+ * @param buf target buffer, Latin1-encoded
+ * @return index of the most significant digit or minus sign, if present
*/
- static void getChars(int i, int index, char[] buf) {
+ static int getChars(int i, int index, byte[] buf) {
int q, r;
int charPos = index;
- char sign = 0;
- if (i < 0) {
- sign = '-';
+ boolean negative = i < 0;
+ if (!negative) {
i = -i;
}
// Generate two digits per iteration
- while (i >= 65536) {
+ while (i <= -100) {
q = i / 100;
- // really: r = i - (q * 100);
- r = i - ((q << 6) + (q << 5) + (q << 2));
+ r = (q * 100) - i;
i = q;
- buf [--charPos] = DigitOnes[r];
- buf [--charPos] = DigitTens[r];
+ buf[--charPos] = DigitOnes[r];
+ buf[--charPos] = DigitTens[r];
}
- // Fall thru to fast mode for smaller numbers
- // assert(i <= 65536, i);
- for (;;) {
- q = (i * 52429) >>> (16+3);
- r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
- buf [--charPos] = digits [r];
- i = q;
- if (i == 0) break;
+ // We know there are at most two digits left at this point.
+ q = i / 10;
+ r = (q * 10) - i;
+ buf[--charPos] = (byte)('0' + r);
+
+ // Whatever left is the remaining digit.
+ if (q < 0) {
+ buf[--charPos] = (byte)('0' - q);
}
- if (sign != 0) {
- buf [--charPos] = sign;
+
+ if (negative) {
+ buf[--charPos] = (byte)'-';
}
+ return charPos;
}
- final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
+ // BEGIN Android-added: char version of getChars(int i, int index, byte[] buf).
+ // for java.lang.AbstractStringBuilder#append(int).
+ static int getChars(int i, int index, char[] buf) {
+ int q, r;
+ int charPos = index;
+
+ boolean negative = i < 0;
+ if (!negative) {
+ i = -i;
+ }
+
+ // Generate two digits per iteration
+ while (i <= -100) {
+ q = i / 100;
+ r = (q * 100) - i;
+ i = q;
+ buf[--charPos] = (char)DigitOnes[r];
+ buf[--charPos] = (char)DigitTens[r];
+ }
+
+ // We know there are at most two digits left at this point.
+ q = i / 10;
+ r = (q * 10) - i;
+ buf[--charPos] = (char)('0' + r);
+
+ // Whatever left is the remaining digit.
+ if (q < 0) {
+ buf[--charPos] = (char)('0' - q);
+ }
+
+ if (negative) {
+ buf[--charPos] = (byte)'-';
+ }
+ return charPos;
+ }
+ // END Android-added: char version of getChars(int i, int index, byte[] buf).
+
+ // Left here for compatibility reasons, see JDK-8143900.
+ static final int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
- // Requires positive x
+ /**
+ * Returns the string representation size for a given int value.
+ *
+ * @param x int value
+ * @return string size
+ *
+ * @implNote There are other ways to compute this: e.g. binary search,
+ * but values are biased heavily towards zero, and therefore linear search
+ * wins. The iteration results are also routinely inlined in the generated
+ * code after loop unrolling.
+ */
static int stringSize(int x) {
- for (int i=0; ; i++)
- if (x <= sizeTable[i])
- return i+1;
+ int d = 1;
+ if (x >= 0) {
+ d = 0;
+ x = -x;
+ }
+ int p = -10;
+ for (int i = 1; i < 10; i++) {
+ if (x > p)
+ return i + d;
+ p = 10 * p;
+ }
+ return 10 + d;
}
/**
@@ -587,12 +719,9 @@
" greater than Character.MAX_RADIX");
}
- int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
- int multmin;
- int digit;
if (len > 0) {
char firstChar = s.charAt(0);
@@ -600,21 +729,21 @@
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
- } else if (firstChar != '+')
- throw NumberFormatException.forInputString(s);
-
- if (len == 1) // Cannot have lone "+" or "-"
- throw NumberFormatException.forInputString(s);
- i++;
- }
- multmin = limit / radix;
- while (i < len) {
- // Accumulating negatively avoids surprises near MAX_VALUE
- digit = Character.digit(s.charAt(i++),radix);
- if (digit < 0) {
+ } else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
}
- if (result < multmin) {
+
+ if (len == 1) { // Cannot have lone "+" or "-"
+ throw NumberFormatException.forInputString(s);
+ }
+ i++;
+ }
+ int multmin = limit / radix;
+ int result = 0;
+ while (i < len) {
+ // Accumulating negatively avoids surprises near MAX_VALUE
+ int digit = Character.digit(s.charAt(i++), radix);
+ if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
@@ -623,10 +752,96 @@
}
result -= digit;
}
+ return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s);
}
- return negative ? result : -result;
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as a signed {@code int} in the
+ * specified {@code radix}, beginning at the specified {@code beginIndex}
+ * and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the {@code int}
+ * representation to be parsed
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @param radix the radix to be used while parsing {@code s}.
+ * @return the signed {@code int} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 9
+ */
+ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (radix < Character.MIN_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " less than Character.MIN_RADIX");
+ }
+ if (radix > Character.MAX_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " greater than Character.MAX_RADIX");
+ }
+
+ boolean negative = false;
+ int i = beginIndex;
+ int limit = -Integer.MAX_VALUE;
+
+ if (i < endIndex) {
+ char firstChar = s.charAt(i);
+ if (firstChar < '0') { // Possible leading "+" or "-"
+ if (firstChar == '-') {
+ negative = true;
+ limit = Integer.MIN_VALUE;
+ } else if (firstChar != '+') {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ i++;
+ if (i == endIndex) { // Cannot have lone "+" or "-"
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ }
+ int multmin = limit / radix;
+ int result = 0;
+ while (i < endIndex) {
+ // Accumulating negatively avoids surprises near MAX_VALUE
+ int digit = Character.digit(s.charAt(i), radix);
+ if (digit < 0 || result < multmin) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ result *= radix;
+ if (result < limit + digit) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ i++;
+ result -= digit;
+ }
+ return negative ? result : -result;
+ } else {
+ throw NumberFormatException.forInputString("");
+ }
}
/**
@@ -727,9 +942,71 @@
}
/**
+ * Parses the {@link CharSequence} argument as an unsigned {@code int} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the unsigned
+ * {@code int} representation to be parsed
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @param radix the radix to be used while parsing {@code s}.
+ * @return the unsigned {@code int} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable unsigned {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 9
+ */
+ public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ int start = beginIndex, len = endIndex - beginIndex;
+
+ if (len > 0) {
+ char firstChar = s.charAt(start);
+ if (firstChar == '-') {
+ throw new
+ NumberFormatException(String.format("Illegal leading minus sign " +
+ "on unsigned string %s.", s));
+ } else {
+ if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
+ (radix == 10 && len <= 9)) { // Integer.MAX_VALUE in base 10 is 10 digits
+ return parseInt(s, start, start + len, radix);
+ } else {
+ long ell = Long.parseLong(s, start, start + len, radix);
+ if ((ell & 0xffff_ffff_0000_0000L) == 0) {
+ return (int) ell;
+ } else {
+ throw new
+ NumberFormatException(String.format("String value %s exceeds " +
+ "range of unsigned int.", s));
+ }
+ }
+ }
+ } else {
+ throw new NumberFormatException("");
+ }
+ }
+
+ /**
* Parses the string argument as an unsigned decimal integer. The
* characters in the string must all be decimal digits, except
- * that the first character may be an an ASCII plus sign {@code
+ * that the first character may be an ASCII plus sign {@code
* '+'} ({@code '\u005Cu002B'}). The resulting integer value
* is returned, exactly as if the argument and the radix 10 were
* given as arguments to the {@link
@@ -809,7 +1086,7 @@
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
- * sun.misc.VM class.
+ * jdk.internal.misc.VM class.
*/
private static class IntegerCache {
@@ -821,7 +1098,7 @@
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
- sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
+ VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
@@ -861,6 +1138,7 @@
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
@@ -880,7 +1158,13 @@
*
* @param value the value to be represented by the
* {@code Integer} object.
+ *
+ * @deprecated
+ * It is rarely appropriate to use this constructor. The static factory
+ * {@link #valueOf(int)} is generally a better choice, as it is
+ * likely to yield significantly better space and time performance.
*/
+ @Deprecated(since="9")
public Integer(int value) {
this.value = value;
}
@@ -892,12 +1176,17 @@
* {@code int} value in exactly the manner used by the
* {@code parseInt} method for radix 10.
*
- * @param s the {@code String} to be converted to an
- * {@code Integer}.
- * @exception NumberFormatException if the {@code String} does not
- * contain a parsable integer.
- * @see java.lang.Integer#parseInt(java.lang.String, int)
+ * @param s the {@code String} to be converted to an {@code Integer}.
+ * @throws NumberFormatException if the {@code String} does not
+ * contain a parsable integer.
+ *
+ * @deprecated
+ * It is rarely appropriate to use this constructor.
+ * Use {@link #parseInt(String)} to convert a string to a
+ * {@code int} primitive, or use {@link #valueOf(String)}
+ * to convert a string to an {@code Integer} object.
*/
+ @Deprecated(since="9")
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
@@ -924,6 +1213,7 @@
* Returns the value of this {@code Integer} as an
* {@code int}.
*/
+ @HotSpotIntrinsicCandidate
public int intValue() {
return value;
}
@@ -983,13 +1273,13 @@
}
/**
- * Returns a hash code for a {@code int} value; compatible with
+ * Returns a hash code for an {@code int} value; compatible with
* {@code Integer.hashCode()}.
*
* @param value the value to hash
* @since 1.8
*
- * @return a hash code value for a {@code int} value.
+ * @return a hash code value for an {@code int} value.
*/
public static int hashCode(int value) {
return value;
@@ -1358,7 +1648,7 @@
@Native public static final int SIZE = 32;
/**
- * The number of bytes used to represent a {@code int} value in two's
+ * The number of bytes used to represent an {@code int} value in two's
* complement binary form.
*
* @since 1.8
@@ -1379,13 +1669,7 @@
* @since 1.5
*/
public static int highestOneBit(int i) {
- // HD, Figure 3-1
- i |= (i >> 1);
- i |= (i >> 2);
- i |= (i >> 4);
- i |= (i >> 8);
- i |= (i >> 16);
- return i - (i >>> 1);
+ return i & (MIN_VALUE >>> numberOfLeadingZeros(i));
}
/**
@@ -1427,17 +1711,17 @@
* is equal to zero.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static int numberOfLeadingZeros(int i) {
- // HD, Figure 5-6
- if (i == 0)
- return 32;
- int n = 1;
- if (i >>> 16 == 0) { n += 16; i <<= 16; }
- if (i >>> 24 == 0) { n += 8; i <<= 8; }
- if (i >>> 28 == 0) { n += 4; i <<= 4; }
- if (i >>> 30 == 0) { n += 2; i <<= 2; }
- n -= i >>> 31;
- return n;
+ // HD, Count leading 0's
+ if (i <= 0)
+ return i == 0 ? 32 : 0;
+ int n = 31;
+ if (i >= 1 << 16) { n -= 16; i >>>= 16; }
+ if (i >= 1 << 8) { n -= 8; i >>>= 8; }
+ if (i >= 1 << 4) { n -= 4; i >>>= 4; }
+ if (i >= 1 << 2) { n -= 2; i >>>= 2; }
+ return n - (i >>> 1);
}
/**
@@ -1454,6 +1738,7 @@
* to zero.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static int numberOfTrailingZeros(int i) {
// HD, Figure 5-14
int y;
@@ -1476,6 +1761,7 @@
* representation of the specified {@code int} value.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
@@ -1549,9 +1835,8 @@
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
- i = (i << 24) | ((i & 0xff00) << 8) |
- ((i >>> 8) & 0xff00) | (i >>> 24);
- return i;
+
+ return reverseBytes(i);
}
/**
@@ -1577,11 +1862,12 @@
* {@code int} value.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static int reverseBytes(int i) {
- return ((i >>> 24) ) |
- ((i >> 8) & 0xFF00) |
- ((i << 8) & 0xFF0000) |
- ((i << 24));
+ return (i << 24) |
+ ((i & 0xff00) << 8) |
+ ((i >>> 8) & 0xff00) |
+ (i >>> 24);
}
/**
diff --git a/ojluni/src/main/java/java/lang/Long.java b/ojluni/src/main/java/java/lang/Long.java
index 0047125..c5f5edd 100644
--- a/ojluni/src/main/java/java/lang/Long.java
+++ b/ojluni/src/main/java/java/lang/Long.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
import java.lang.annotation.Native;
import java.math.*;
+import java.util.Objects;
+import jdk.internal.HotSpotIntrinsicCandidate;
/**
@@ -50,7 +52,7 @@
* @author Arthur van Hoff
* @author Josh Bloch
* @author Joseph D. Darcy
- * @since JDK1.0
+ * @since 1.0
*/
public final class Long extends Number implements Comparable<Long> {
/**
@@ -69,7 +71,7 @@
* The {@code Class} instance representing the primitive type
* {@code long}.
*
- * @since JDK1.1
+ * @since 1.1
*/
@SuppressWarnings("unchecked")
public static final Class<Long> TYPE = (Class<Long>) Class.getPrimitiveClass("long");
@@ -123,26 +125,58 @@
radix = 10;
if (radix == 10)
return toString(i);
- char[] buf = new char[65];
+
+ // BEGIN Android-changed: Use single-byte chars.
+ /*
+ if (COMPACT_STRINGS) {
+ */
+ byte[] buf = new byte[65];
+ int charPos = 64;
+ boolean negative = (i < 0);
+
+ if (!negative) {
+ i = -i;
+ }
+
+ while (i <= -radix) {
+ buf[charPos--] = (byte)Integer.digits[(int)(-(i % radix))];
+ i = i / radix;
+ }
+ buf[charPos] = (byte)Integer.digits[(int)(-i)];
+
+ if (negative) {
+ buf[--charPos] = '-';
+ }
+ /*
+ return StringLatin1.newString(buf, charPos, (65 - charPos));
+ }
+ return toStringUTF16(i, radix);
+ */
+ return new String(buf, charPos, (65 - charPos));
+ // END Android-changed: Use single-byte chars.
+ }
+
+ // BEGIN Android-removed: UTF16 version of toString(long i, int radix).
+ /*
+ private static String toStringUTF16(long i, int radix) {
+ byte[] buf = new byte[65 * 2];
int charPos = 64;
boolean negative = (i < 0);
-
if (!negative) {
i = -i;
}
-
while (i <= -radix) {
- buf[charPos--] = Integer.digits[(int)(-(i % radix))];
+ StringUTF16.putChar(buf, charPos--, Integer.digits[(int)(-(i % radix))]);
i = i / radix;
}
- buf[charPos] = Integer.digits[(int)(-i)];
-
+ StringUTF16.putChar(buf, charPos, Integer.digits[(int)(-i)]);
if (negative) {
- buf[--charPos] = '-';
+ StringUTF16.putChar(buf, --charPos, '-');
}
-
- return new String(buf, charPos, (65 - charPos));
+ return StringUTF16.newString(buf, charPos, (65 - charPos));
}
+ */
+ // END Android-removed: UTF16 version of toString(long i, int radix).
/**
* Returns a string representation of the first argument as an
@@ -267,7 +301,7 @@
* (base 16).
* @see #parseUnsignedLong(String, int)
* @see #toUnsignedString(long, int)
- * @since JDK 1.0.2
+ * @since 1.0.2
*/
public static String toHexString(long i) {
return toUnsignedString0(i, 4);
@@ -306,7 +340,7 @@
* value represented by the argument in octal (base 8).
* @see #parseUnsignedLong(String, int)
* @see #toUnsignedString(long, int)
- * @since JDK 1.0.2
+ * @since 1.0.2
*/
public static String toOctalString(long i) {
return toUnsignedString0(i, 3);
@@ -339,7 +373,7 @@
* value represented by the argument in binary (base 2).
* @see #parseUnsignedLong(String, int)
* @see #toUnsignedString(long, int)
- * @since JDK 1.0.2
+ * @since 1.0.2
*/
public static String toBinaryString(long i) {
return toUnsignedString0(i, 1);
@@ -354,35 +388,63 @@
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
- char[] buf = new char[chars];
- formatUnsignedLong(val, shift, buf, 0, chars);
- // Android-changed: Use regular constructor instead of one which takes over "buf".
- // return new String(buf, true);
+ // BEGIN Android-changed: Use single-byte chars.
+ /*
+ if (COMPACT_STRINGS) {
+ */
+ byte[] buf = new byte[chars];
+ formatUnsignedLong0(val, shift, buf, 0, chars);
+ /*
+ return new String(buf, LATIN1);
+ } else {
+ byte[] buf = new byte[chars * 2];
+ formatUnsignedLong0UTF16(val, shift, buf, 0, chars);
+ return new String(buf, UTF16);
+ }
+ */
return new String(buf);
+ // END Android-changed: Use single-byte chars.
}
/**
- * Format a long (treated as unsigned) into a character buffer.
+ * Format a long (treated as unsigned) into a character buffer. If
+ * {@code len} exceeds the formatted ASCII representation of {@code val},
+ * {@code buf} will be padded with leading zeroes.
+ *
* @param val the unsigned long to format
* @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
* @param buf the character buffer to write to
* @param offset the offset in the destination buffer to start at
* @param len the number of characters to write
- * @return the lowest character location used
*/
- static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
- int charPos = len;
+
+ /** byte[]/LATIN1 version */
+ static void formatUnsignedLong0(long val, int shift, byte[] buf, int offset, int len) {
+ int charPos = offset + len;
int radix = 1 << shift;
int mask = radix - 1;
do {
- buf[offset + --charPos] = Integer.digits[((int) val) & mask];
+ buf[--charPos] = (byte)Integer.digits[((int) val) & mask];
val >>>= shift;
- } while (val != 0 && charPos > 0);
-
- return charPos;
+ } while (charPos > offset);
}
+ // BEGIN Android-removed: UTF16 version of formatUnsignedLong0().
+ /*
+ /** byte[]/UTF16 version *
+ private static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) {
+ int charPos = offset + len;
+ int radix = 1 << shift;
+ int mask = radix - 1;
+ do {
+ StringUTF16.putChar(buf, --charPos, Integer.digits[((int) val) & mask]);
+ val >>>= shift;
+ } while (charPos > offset);
+ }
+ */
+ // END Android-removed: UTF16 version of formatUnsignedLong0().
+
/**
* Returns a {@code String} object representing the specified
* {@code long}. The argument is converted to signed decimal
@@ -394,14 +456,23 @@
* @return a string representation of the argument in base 10.
*/
public static String toString(long i) {
- if (i == Long.MIN_VALUE)
- return "-9223372036854775808";
- int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
- char[] buf = new char[size];
- getChars(i, size, buf);
- // Android-changed: Use regular constructor instead of one which takes over "buf".
- // return new String(buf, true);
+ int size = stringSize(i);
+ // BEGIN Android-changed: Always use single-byte buffer.
+ /*
+ if (COMPACT_STRINGS) {
+ */
+ byte[] buf = new byte[size];
+ getChars(i, size, buf);
+ /*
+ return new String(buf, LATIN1);
+ } else {
+ byte[] buf = new byte[size * 2];
+ StringUTF16.getChars(i, size, buf);
+ return new String(buf, UTF16);
+ }
+ */
return new String(buf);
+ // END Android-changed: Always use single-byte buffer.
}
/**
@@ -423,30 +494,36 @@
}
/**
- * Places characters representing the integer i into the
+ * Places characters representing the long i into the
* character array buf. The characters are placed into
* the buffer backwards starting with the least significant
* digit at the specified index (exclusive), and working
* backwards from there.
*
- * Will fail if i == Long.MIN_VALUE
+ * @implNote This method converts positive inputs into negative
+ * values, to cover the Long.MIN_VALUE case. Converting otherwise
+ * (negative to positive) will expose -Long.MIN_VALUE that overflows
+ * long.
+ *
+ * @param i value to convert
+ * @param index next index, after the least significant digit
+ * @param buf target buffer, Latin1-encoded
+ * @return index of the most significant digit or minus sign, if present
*/
- static void getChars(long i, int index, char[] buf) {
+ static int getChars(long i, int index, byte[] buf) {
long q;
int r;
int charPos = index;
- char sign = 0;
- if (i < 0) {
- sign = '-';
+ boolean negative = (i < 0);
+ if (!negative) {
i = -i;
}
// Get 2 digits/iteration using longs until quotient fits into an int
- while (i > Integer.MAX_VALUE) {
+ while (i <= Integer.MIN_VALUE) {
q = i / 100;
- // really: r = i - (q * 100);
- r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
+ r = (int)((q * 100) - i);
i = q;
buf[--charPos] = Integer.DigitOnes[r];
buf[--charPos] = Integer.DigitTens[r];
@@ -455,38 +532,103 @@
// Get 2 digits/iteration using ints
int q2;
int i2 = (int)i;
- while (i2 >= 65536) {
+ while (i2 <= -100) {
q2 = i2 / 100;
- // really: r = i2 - (q * 100);
- r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
+ r = (q2 * 100) - i2;
i2 = q2;
buf[--charPos] = Integer.DigitOnes[r];
buf[--charPos] = Integer.DigitTens[r];
}
- // Fall thru to fast mode for smaller numbers
- // assert(i2 <= 65536, i2);
- for (;;) {
- q2 = (i2 * 52429) >>> (16+3);
- r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
- buf[--charPos] = Integer.digits[r];
- i2 = q2;
- if (i2 == 0) break;
+ // We know there are at most two digits left at this point.
+ q2 = i2 / 10;
+ r = (q2 * 10) - i2;
+ buf[--charPos] = (byte)('0' + r);
+
+ // Whatever left is the remaining digit.
+ if (q2 < 0) {
+ buf[--charPos] = (byte)('0' - q2);
}
- if (sign != 0) {
- buf[--charPos] = sign;
+
+ if (negative) {
+ buf[--charPos] = (byte)'-';
}
+ return charPos;
}
- // Requires positive x
- static int stringSize(long x) {
- long p = 10;
- for (int i=1; i<19; i++) {
- if (x < p)
- return i;
- p = 10*p;
+ // BEGIN Android-added: char version of getChars(long i, int index, byte[] buf).
+ // for java.lang.AbstractStringBuilder#append(int).
+ static int getChars(long i, int index, char[] buf) {
+ long q;
+ int r;
+ int charPos = index;
+
+ boolean negative = (i < 0);
+ if (!negative) {
+ i = -i;
}
- return 19;
+
+ // Get 2 digits/iteration using longs until quotient fits into an int
+ while (i <= Integer.MIN_VALUE) {
+ q = i / 100;
+ r = (int)((q * 100) - i);
+ i = q;
+ buf[--charPos] = (char)Integer.DigitOnes[r];
+ buf[--charPos] = (char)Integer.DigitTens[r];
+ }
+
+ // Get 2 digits/iteration using ints
+ int q2;
+ int i2 = (int)i;
+ while (i2 <= -100) {
+ q2 = i2 / 100;
+ r = (q2 * 100) - i2;
+ i2 = q2;
+ buf[--charPos] = (char)Integer.DigitOnes[r];
+ buf[--charPos] = (char)Integer.DigitTens[r];
+ }
+
+ // We know there are at most two digits left at this point.
+ q2 = i2 / 10;
+ r = (q2 * 10) - i2;
+ buf[--charPos] = (char)('0' + r);
+
+ // Whatever left is the remaining digit.
+ if (q2 < 0) {
+ buf[--charPos] = (char)('0' - q2);
+ }
+
+ if (negative) {
+ buf[--charPos] = (byte)'-';
+ }
+ return charPos;
+ }
+ // END Android-added: char version of getChars(long i, int index, byte[] buf).
+
+ /**
+ * Returns the string representation size for a given long value.
+ *
+ * @param x long value
+ * @return string size
+ *
+ * @implNote There are other ways to compute this: e.g. binary search,
+ * but values are biased heavily towards zero, and therefore linear search
+ * wins. The iteration results are also routinely inlined in the generated
+ * code after loop unrolling.
+ */
+ static int stringSize(long x) {
+ int d = 1;
+ if (x >= 0) {
+ d = 0;
+ x = -x;
+ }
+ long p = -10;
+ for (int i = 1; i < 19; i++) {
+ if (x > p)
+ return i + d;
+ p = 10 * p;
+ }
+ return 19 + d;
}
/**
@@ -566,12 +708,9 @@
" greater than Character.MAX_RADIX");
}
- long result = 0;
boolean negative = false;
int i = 0, len = s.length();
long limit = -Long.MAX_VALUE;
- long multmin;
- int digit;
if (len > 0) {
char firstChar = s.charAt(0);
@@ -579,21 +718,21 @@
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
- } else if (firstChar != '+')
- throw NumberFormatException.forInputString(s);
-
- if (len == 1) // Cannot have lone "+" or "-"
- throw NumberFormatException.forInputString(s);
- i++;
- }
- multmin = limit / radix;
- while (i < len) {
- // Accumulating negatively avoids surprises near MAX_VALUE
- digit = Character.digit(s.charAt(i++),radix);
- if (digit < 0) {
+ } else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
}
- if (result < multmin) {
+
+ if (len == 1) { // Cannot have lone "+" or "-"
+ throw NumberFormatException.forInputString(s);
+ }
+ i++;
+ }
+ long multmin = limit / radix;
+ long result = 0;
+ while (i < len) {
+ // Accumulating negatively avoids surprises near MAX_VALUE
+ int digit = Character.digit(s.charAt(i++),radix);
+ if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
@@ -602,10 +741,96 @@
}
result -= digit;
}
+ return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s);
}
- return negative ? result : -result;
+ }
+
+ /**
+ * Parses the {@link CharSequence} argument as a signed {@code long} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the {@code long}
+ * representation to be parsed
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @param radix the radix to be used while parsing {@code s}.
+ * @return the signed {@code long} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable {@code int} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 9
+ */
+ public static long parseLong(CharSequence s, int beginIndex, int endIndex, int radix)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (radix < Character.MIN_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " less than Character.MIN_RADIX");
+ }
+ if (radix > Character.MAX_RADIX) {
+ throw new NumberFormatException("radix " + radix +
+ " greater than Character.MAX_RADIX");
+ }
+
+ boolean negative = false;
+ int i = beginIndex;
+ long limit = -Long.MAX_VALUE;
+
+ if (i < endIndex) {
+ char firstChar = s.charAt(i);
+ if (firstChar < '0') { // Possible leading "+" or "-"
+ if (firstChar == '-') {
+ negative = true;
+ limit = Long.MIN_VALUE;
+ } else if (firstChar != '+') {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ i++;
+ }
+ if (i >= endIndex) { // Cannot have lone "+", "-" or ""
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ long multmin = limit / radix;
+ long result = 0;
+ while (i < endIndex) {
+ // Accumulating negatively avoids surprises near MAX_VALUE
+ int digit = Character.digit(s.charAt(i), radix);
+ if (digit < 0 || result < multmin) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ result *= radix;
+ if (result < limit + digit) {
+ throw NumberFormatException.forCharSequence(s, beginIndex,
+ endIndex, i);
+ }
+ i++;
+ result -= digit;
+ }
+ return negative ? result : -result;
+ } else {
+ throw new NumberFormatException("");
+ }
}
/**
@@ -699,27 +924,64 @@
}
// No need for range checks on len due to testing above.
- long first = parseLong(s.substring(0, len - 1), radix);
+ long first = parseLong(s, 0, len - 1, radix);
int second = Character.digit(s.charAt(len - 1), radix);
if (second < 0) {
throw new NumberFormatException("Bad digit at end of " + s);
}
long result = first * radix + second;
- if (compareUnsigned(result, first) < 0) {
+
+ /*
+ * Test leftmost bits of multiprecision extension of first*radix
+ * for overflow. The number of bits needed is defined by
+ * GUARD_BIT = ceil(log2(Character.MAX_RADIX)) + 1 = 7. Then
+ * int guard = radix*(int)(first >>> (64 - GUARD_BIT)) and
+ * overflow is tested by splitting guard in the ranges
+ * guard < 92, 92 <= guard < 128, and 128 <= guard, where
+ * 92 = 128 - Character.MAX_RADIX. Note that guard cannot take
+ * on a value which does not include a prime factor in the legal
+ * radix range.
+ */
+ int guard = radix * (int) (first >>> 57);
+ if (guard >= 128 ||
+ (result >= 0 && guard >= 128 - Character.MAX_RADIX)) {
/*
- * The maximum unsigned value, (2^64)-1, takes at
- * most one more digit to represent than the
- * maximum signed value, (2^63)-1. Therefore,
- * parsing (len - 1) digits will be appropriately
- * in-range of the signed parsing. In other
- * words, if parsing (len -1) digits overflows
- * signed parsing, parsing len digits will
- * certainly overflow unsigned parsing.
+ * For purposes of exposition, the programmatic statements
+ * below should be taken to be multi-precision, i.e., not
+ * subject to overflow.
*
- * The compareUnsigned check above catches
- * situations where an unsigned overflow occurs
- * incorporating the contribution of the final
- * digit.
+ * A) Condition guard >= 128:
+ * If guard >= 128 then first*radix >= 2^7 * 2^57 = 2^64
+ * hence always overflow.
+ *
+ * B) Condition guard < 92:
+ * Define left7 = first >>> 57.
+ * Given first = (left7 * 2^57) + (first & (2^57 - 1)) then
+ * result <= (radix*left7)*2^57 + radix*(2^57 - 1) + second.
+ * Thus if radix*left7 < 92, radix <= 36, and second < 36,
+ * then result < 92*2^57 + 36*(2^57 - 1) + 36 = 2^64 hence
+ * never overflow.
+ *
+ * C) Condition 92 <= guard < 128:
+ * first*radix + second >= radix*left7*2^57 + second
+ * so that first*radix + second >= 92*2^57 + 0 > 2^63
+ *
+ * D) Condition guard < 128:
+ * radix*first <= (radix*left7) * 2^57 + radix*(2^57 - 1)
+ * so
+ * radix*first + second <= (radix*left7) * 2^57 + radix*(2^57 - 1) + 36
+ * thus
+ * radix*first + second < 128 * 2^57 + 36*2^57 - radix + 36
+ * whence
+ * radix*first + second < 2^64 + 2^6*2^57 = 2^64 + 2^63
+ *
+ * E) Conditions C, D, and result >= 0:
+ * C and D combined imply the mathematical result
+ * 2^63 < first*radix + second < 2^64 + 2^63. The lower
+ * bound is therefore negative as a signed long, but the
+ * upper bound is too small to overflow again after the
+ * signed long overflows to positive above 2^64 - 1. Hence
+ * result >= 0 implies overflow given C and D.
*/
throw new NumberFormatException(String.format("String value %s exceeds " +
"range of unsigned long.", s));
@@ -732,9 +994,127 @@
}
/**
+ * Parses the {@link CharSequence} argument as an unsigned {@code long} in
+ * the specified {@code radix}, beginning at the specified
+ * {@code beginIndex} and extending to {@code endIndex - 1}.
+ *
+ * <p>The method does not take steps to guard against the
+ * {@code CharSequence} being mutated while parsing.
+ *
+ * @param s the {@code CharSequence} containing the unsigned
+ * {@code long} representation to be parsed
+ * @param beginIndex the beginning index, inclusive.
+ * @param endIndex the ending index, exclusive.
+ * @param radix the radix to be used while parsing {@code s}.
+ * @return the unsigned {@code long} represented by the subsequence in
+ * the specified radix.
+ * @throws NullPointerException if {@code s} is null.
+ * @throws IndexOutOfBoundsException if {@code beginIndex} is
+ * negative, or if {@code beginIndex} is greater than
+ * {@code endIndex} or if {@code endIndex} is greater than
+ * {@code s.length()}.
+ * @throws NumberFormatException if the {@code CharSequence} does not
+ * contain a parsable unsigned {@code long} in the specified
+ * {@code radix}, or if {@code radix} is either smaller than
+ * {@link java.lang.Character#MIN_RADIX} or larger than
+ * {@link java.lang.Character#MAX_RADIX}.
+ * @since 9
+ */
+ public static long parseUnsignedLong(CharSequence s, int beginIndex, int endIndex, int radix)
+ throws NumberFormatException {
+ s = Objects.requireNonNull(s);
+
+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ int start = beginIndex, len = endIndex - beginIndex;
+
+ if (len > 0) {
+ char firstChar = s.charAt(start);
+ if (firstChar == '-') {
+ throw new NumberFormatException(String.format("Illegal leading minus sign " +
+ "on unsigned string %s.", s.subSequence(start, start + len)));
+ } else {
+ if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
+ (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
+ return parseLong(s, start, start + len, radix);
+ }
+
+ // No need for range checks on end due to testing above.
+ long first = parseLong(s, start, start + len - 1, radix);
+ int second = Character.digit(s.charAt(start + len - 1), radix);
+ if (second < 0) {
+ throw new NumberFormatException("Bad digit at end of " +
+ s.subSequence(start, start + len));
+ }
+ long result = first * radix + second;
+
+ /*
+ * Test leftmost bits of multiprecision extension of first*radix
+ * for overflow. The number of bits needed is defined by
+ * GUARD_BIT = ceil(log2(Character.MAX_RADIX)) + 1 = 7. Then
+ * int guard = radix*(int)(first >>> (64 - GUARD_BIT)) and
+ * overflow is tested by splitting guard in the ranges
+ * guard < 92, 92 <= guard < 128, and 128 <= guard, where
+ * 92 = 128 - Character.MAX_RADIX. Note that guard cannot take
+ * on a value which does not include a prime factor in the legal
+ * radix range.
+ */
+ int guard = radix * (int) (first >>> 57);
+ if (guard >= 128 ||
+ (result >= 0 && guard >= 128 - Character.MAX_RADIX)) {
+ /*
+ * For purposes of exposition, the programmatic statements
+ * below should be taken to be multi-precision, i.e., not
+ * subject to overflow.
+ *
+ * A) Condition guard >= 128:
+ * If guard >= 128 then first*radix >= 2^7 * 2^57 = 2^64
+ * hence always overflow.
+ *
+ * B) Condition guard < 92:
+ * Define left7 = first >>> 57.
+ * Given first = (left7 * 2^57) + (first & (2^57 - 1)) then
+ * result <= (radix*left7)*2^57 + radix*(2^57 - 1) + second.
+ * Thus if radix*left7 < 92, radix <= 36, and second < 36,
+ * then result < 92*2^57 + 36*(2^57 - 1) + 36 = 2^64 hence
+ * never overflow.
+ *
+ * C) Condition 92 <= guard < 128:
+ * first*radix + second >= radix*left7*2^57 + second
+ * so that first*radix + second >= 92*2^57 + 0 > 2^63
+ *
+ * D) Condition guard < 128:
+ * radix*first <= (radix*left7) * 2^57 + radix*(2^57 - 1)
+ * so
+ * radix*first + second <= (radix*left7) * 2^57 + radix*(2^57 - 1) + 36
+ * thus
+ * radix*first + second < 128 * 2^57 + 36*2^57 - radix + 36
+ * whence
+ * radix*first + second < 2^64 + 2^6*2^57 = 2^64 + 2^63
+ *
+ * E) Conditions C, D, and result >= 0:
+ * C and D combined imply the mathematical result
+ * 2^63 < first*radix + second < 2^64 + 2^63. The lower
+ * bound is therefore negative as a signed long, but the
+ * upper bound is too small to overflow again after the
+ * signed long overflows to positive above 2^64 - 1. Hence
+ * result >= 0 implies overflow given C and D.
+ */
+ throw new NumberFormatException(String.format("String value %s exceeds " +
+ "range of unsigned long.", s.subSequence(start, start + len)));
+ }
+ return result;
+ }
+ } else {
+ throw NumberFormatException.forInputString("");
+ }
+ }
+
+ /**
* Parses the string argument as an unsigned decimal {@code long}. The
* characters in the string must all be decimal digits, except
- * that the first character may be an an ASCII plus sign {@code
+ * that the first character may be an ASCII plus sign {@code
* '+'} ({@code '\u005Cu002B'}). The resulting integer value
* is returned, exactly as if the argument and the radix 10 were
* given as arguments to the {@link
@@ -828,15 +1208,14 @@
* significantly better space and time performance by caching
* frequently requested values.
*
- * Note that unlike the {@linkplain Integer#valueOf(int)
- * corresponding method} in the {@code Integer} class, this method
- * is <em>not</em> required to cache values within a particular
- * range.
+ * This method will always cache values in the range -128 to 127,
+ * inclusive, and may cache other values outside of this range.
*
* @param l a long value.
* @return a {@code Long} instance representing {@code l}.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
@@ -948,7 +1327,13 @@
*
* @param value the value to be represented by the
* {@code Long} object.
+ *
+ * @deprecated
+ * It is rarely appropriate to use this constructor. The static factory
+ * {@link #valueOf(long)} is generally a better choice, as it is
+ * likely to yield significantly better space and time performance.
*/
+ @Deprecated(since="9")
public Long(long value) {
this.value = value;
}
@@ -964,8 +1349,14 @@
* {@code Long}.
* @throws NumberFormatException if the {@code String} does not
* contain a parsable {@code long}.
- * @see java.lang.Long#parseLong(java.lang.String, int)
+ *
+ * @deprecated
+ * It is rarely appropriate to use this constructor.
+ * Use {@link #parseLong(String)} to convert a string to a
+ * {@code long} primitive, or use {@link #valueOf(String)}
+ * to convert a string to a {@code Long} object.
*/
+ @Deprecated(since="9")
public Long(String s) throws NumberFormatException {
this.value = parseLong(s, 10);
}
@@ -1001,6 +1392,7 @@
* Returns the value of this {@code Long} as a
* {@code long} value.
*/
+ @HotSpotIntrinsicCandidate
public long longValue() {
return value;
}
@@ -1369,14 +1761,7 @@
* @since 1.5
*/
public static long highestOneBit(long i) {
- // HD, Figure 3-1
- i |= (i >> 1);
- i |= (i >> 2);
- i |= (i >> 4);
- i |= (i >> 8);
- i |= (i >> 16);
- i |= (i >> 32);
- return i - (i >>> 1);
+ return i & (MIN_VALUE >>> numberOfLeadingZeros(i));
}
/**
@@ -1418,19 +1803,11 @@
* is equal to zero.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static int numberOfLeadingZeros(long i) {
- // HD, Figure 5-6
- if (i == 0)
- return 64;
- int n = 1;
int x = (int)(i >>> 32);
- if (x == 0) { n += 32; x = (int)i; }
- if (x >>> 16 == 0) { n += 16; x <<= 16; }
- if (x >>> 24 == 0) { n += 8; x <<= 8; }
- if (x >>> 28 == 0) { n += 4; x <<= 4; }
- if (x >>> 30 == 0) { n += 2; x <<= 2; }
- n -= x >>> 31;
- return n;
+ return x == 0 ? 32 + Integer.numberOfLeadingZeros((int)i)
+ : Integer.numberOfLeadingZeros(x);
}
/**
@@ -1447,6 +1824,7 @@
* to zero.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static int numberOfTrailingZeros(long i) {
// HD, Figure 5-14
int x, y;
@@ -1470,8 +1848,9 @@
* representation of the specified {@code long} value.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static int bitCount(long i) {
- // HD, Figure 5-14
+ // HD, Figure 5-2
i = i - ((i >>> 1) & 0x5555555555555555L);
i = (i & 0x3333333333333333L) + ((i >>> 2) & 0x3333333333333333L);
i = (i + (i >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
@@ -1544,10 +1923,8 @@
i = (i & 0x5555555555555555L) << 1 | (i >>> 1) & 0x5555555555555555L;
i = (i & 0x3333333333333333L) << 2 | (i >>> 2) & 0x3333333333333333L;
i = (i & 0x0f0f0f0f0f0f0f0fL) << 4 | (i >>> 4) & 0x0f0f0f0f0f0f0f0fL;
- i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
- i = (i << 48) | ((i & 0xffff0000L) << 16) |
- ((i >>> 16) & 0xffff0000L) | (i >>> 48);
- return i;
+
+ return reverseBytes(i);
}
/**
@@ -1573,6 +1950,7 @@
* {@code long} value.
* @since 1.5
*/
+ @HotSpotIntrinsicCandidate
public static long reverseBytes(long i) {
i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
return (i << 48) | ((i & 0xffff0000L) << 16) |
diff --git a/ojluni/src/test/java/lang/Integer/ParsingTest.java b/ojluni/src/test/java/lang/Integer/ParsingTest.java
new file mode 100644
index 0000000..e24ba15
--- /dev/null
+++ b/ojluni/src/test/java/lang/Integer/ParsingTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 5017980 6576055 8041972 8055251
+ * @summary Test parsing methods
+ * @author Joseph D. Darcy
+ */
+package test.java.lang.Integer;
+
+import java.lang.IndexOutOfBoundsException;
+import java.lang.NullPointerException;
+import java.lang.RuntimeException;
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+/**
+ * There are seven methods in java.lang.Integer which transform strings
+ * into an int or Integer value:
+ *
+ * public Integer(String s)
+ * public static Integer decode(String nm)
+ * public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
+ * public static int parseInt(String s, int radix)
+ * public static int parseInt(String s)
+ * public static Integer valueOf(String s, int radix)
+ * public static Integer valueOf(String s)
+ *
+ * Besides decode, all the methods and constructor call down into
+ * parseInt(CharSequence, int, int, int) to do the actual work. Therefore, the
+ * behavior of parseInt(CharSequence, int, int, int) will be tested here.
+ *
+ */
+
+public class ParsingTest {
+
+ @Test
+ public void main() {
+ check(+100, "+100");
+ check(-100, "-100");
+
+ check(0, "+0");
+ check(0, "-0");
+ check(0, "+00000");
+ check(0, "-00000");
+
+ check(0, "0");
+ check(1, "1");
+ check(9, "9");
+
+ checkFailure("");
+ checkFailure("\u0000");
+ checkFailure("\u002f");
+ checkFailure("+");
+ checkFailure("-");
+ checkFailure("++");
+ checkFailure("+-");
+ checkFailure("-+");
+ checkFailure("--");
+ checkFailure("++100");
+ checkFailure("--100");
+ checkFailure("+-6");
+ checkFailure("-+6");
+ checkFailure("*100");
+
+ // check offset based methods
+ check(0, "+00000", 0, 6, 10);
+ check(0, "-00000", 0, 6, 10);
+ check(0, "test-00000", 4, 10, 10);
+ check(-12345, "test-12345", 4, 10, 10);
+ check(12345, "xx12345yy", 2, 7, 10);
+ check(15, "xxFyy", 2, 3, 16);
+
+ checkNumberFormatException("", 0, 0, 10);
+ checkNumberFormatException("+-6", 0, 3, 10);
+ checkNumberFormatException("1000000", 7, 7, 10);
+ checkNumberFormatException("1000000", 0, 2, Character.MAX_RADIX + 1);
+ checkNumberFormatException("1000000", 0, 2, Character.MIN_RADIX - 1);
+
+ checkIndexOutOfBoundsException("1000000", 10, 4, 10);
+ checkIndexOutOfBoundsException("1000000", -1, 2, Character.MAX_RADIX + 1);
+ checkIndexOutOfBoundsException("1000000", -1, 2, Character.MIN_RADIX - 1);
+ checkIndexOutOfBoundsException("1000000", 10, 2, Character.MAX_RADIX + 1);
+ checkIndexOutOfBoundsException("1000000", 10, 2, Character.MIN_RADIX - 1);
+ checkIndexOutOfBoundsException("-1", 0, 3, 10);
+ checkIndexOutOfBoundsException("-1", 2, 3, 10);
+ checkIndexOutOfBoundsException("-1", -1, 2, 10);
+
+ checkNull(0, 1, 10);
+ checkNull(-1, 0, 10);
+ checkNull(0, 0, 10);
+ checkNull(0, -1, 10);
+ checkNull(-1, -1, -1);
+ }
+
+ private static void check(int expected, String val) {
+ int n = Integer.parseInt(val);
+ if (n != expected)
+ throw new RuntimeException("Integer.parseInt failed. String:" +
+ val + " Result:" + n);
+ }
+
+ private static void checkFailure(String val) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val);
+ System.err.println("parseInt(" + val + ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNumberFormatException(String val, int start, int end, int radix) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, start, end, radix);
+ System.err.println("parseInt(" + val + ", " + start + ", " + end + ", " + radix +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkIndexOutOfBoundsException(String val, int start, int end, int radix) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(val, start, end, radix);
+ System.err.println("parseInt(" + val + ", " + start + ", " + end + ", " + radix +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (IndexOutOfBoundsException ioob) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNull(int start, int end, int radix) {
+ int n = 0;
+ try {
+ n = Integer.parseInt(null, start, end, radix);
+ System.err.println("parseInt(null, " + start + ", " + end + ", " + radix +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+ }
+
+ private static void check(int expected, String val, int start, int end, int radix) {
+ int n = Integer.parseInt(val, start, end, radix);
+ if (n != expected)
+ throw new RuntimeException("Integer.parsedInt failed. Expected: " + expected + " String: \"" +
+ val + "\", start: " + start + ", end: " + end + ", radix: " + radix + " Result:" + n);
+ }
+}
diff --git a/ojluni/src/test/java/lang/Integer/Unsigned.java b/ojluni/src/test/java/lang/Integer/Unsigned.java
new file mode 100644
index 0000000..36cce16
--- /dev/null
+++ b/ojluni/src/test/java/lang/Integer/Unsigned.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.lang.Integer;
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+/*
+ * @test
+ * @bug 4504839 4215269 6322074
+ * @summary Basic tests for unsigned operations.
+ * @author Joseph D. Darcy
+ */
+public class Unsigned {
+
+ @Test
+ public void testRoundtrip() {
+ int[] data = {-1, 0, 1};
+
+ for(int datum : data) {
+ Assert.assertEquals(
+ Integer.parseUnsignedInt(Integer.toBinaryString(datum), 2),
+ datum,
+ "Bad binary roundtrip conversion of " + datum);
+
+ Assert.assertEquals(Integer.parseUnsignedInt(Integer.toOctalString(datum), 8),
+ datum,
+ "Bad octal roundtrip conversion of " + datum);
+
+ Assert.assertEquals(Integer.parseUnsignedInt(Integer.toHexString(datum), 16),
+ datum,
+ "Bad hex roundtrip conversion of " + datum);
+ }
+ }
+
+ @Test
+ public void testByteToUnsignedInt() {
+ for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ byte datum = (byte) i;
+ int ui = Byte.toUnsignedInt(datum);
+
+ if ( (ui & (~0xff)) != 0 || ((byte)ui != datum )) {
+ Assert.fail(
+ String.format("Bad conversion of byte %d to unsigned int %d%n", datum, ui));
+ }
+ }
+ }
+
+ @Test
+ public void testShortToUnsignedInt() {
+ for(int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) {
+ short datum = (short) i;
+ int ui = Short.toUnsignedInt(datum);
+
+ if ( (ui & (~0xffff)) != 0 || ((short)ui != datum )) {
+ Assert.fail(
+ String.format("Bad conversion of short %d to unsigned int %d%n", datum, ui));
+ }
+ }
+ }
+
+ @Test
+ public void testUnsignedCompare() {
+ int[] data = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 0x8000_0000,
+ 0x8000_0001,
+ 0x8000_0002,
+ 0x8000_0003,
+ 0xFFFF_FFFE,
+ 0xFFFF_FFFF,
+ };
+
+ for(int i : data) {
+ for(int j : data) {
+ int libraryResult = Integer.compareUnsigned(i, j);
+ int libraryResultRev = Integer.compareUnsigned(j, i);
+ int localResult = compUnsigned(i, j);
+
+ if (i == j) {
+ Assert.assertEquals(libraryResult, 0,
+ String.format("Value 0x%x did not compare as " +
+ "an unsigned value equal to itself; got %d%n",
+ i, libraryResult));
+ }
+
+ Assert.assertEquals(Integer.signum(libraryResult),
+ Integer.signum(localResult),
+ String.format("Unsigned compare of 0x%x to 0x%x%n:" +
+ "\texpected sign of %d, got %d%n",
+ i, j, localResult, libraryResult));
+
+ Assert.assertEquals(Integer.signum(libraryResult),
+ -Integer.signum(libraryResultRev),
+ String.format("signum(compareUnsigned(x, y)) != -signum(compareUnsigned(y,x))" +
+ " for \t0x%x and 0x%x, computed %d and %d%n",
+ i, j, libraryResult, libraryResultRev));
+ }
+ }
+ }
+
+ /**
+ * Straightforward compare unsigned algorithm.
+ */
+ private static int compUnsigned(int x, int y) {
+ int sign_x = x & Integer.MIN_VALUE;
+ int sign_y = y & Integer.MIN_VALUE;
+
+ int mant_x = x & (~Integer.MIN_VALUE);
+ int mant_y = y & (~Integer.MIN_VALUE);
+
+ if (sign_x == sign_y)
+ return Integer.compare(mant_x, mant_y);
+ else {
+ if (sign_x == 0)
+ return -1; // sign x is 0, sign y is 1 => (x < y)
+ else
+ return 1; // sign x is 1, sign y is 0 => (x > y)
+ }
+ }
+
+ @Test
+ public void testToUnsignedLong() {
+ int[] data = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 0x1234_5678,
+ 0x8000_0000,
+ 0x8000_0001,
+ 0x8000_0002,
+ 0x8000_0003,
+ 0x8765_4321,
+ 0xFFFF_FFFE,
+ 0xFFFF_FFFF,
+ };
+
+ for(int datum : data) {
+ long result = Integer.toUnsignedLong(datum);
+
+ // High-order bits should be zero
+ Assert.assertEquals(
+ (result & 0xffff_ffff_0000_0000L),
+ 0L,
+ String.format("High bits set converting 0x%x to 0x%x%n", datum, result));
+
+ // Lower-order bits should be equal to datum.
+ int lowOrder = (int)(result & 0x0000_0000_ffff_ffffL);
+ Assert.assertEquals(lowOrder, datum,
+ String.format("Low bits not preserved converting 0x%x to 0x%x%n", datum, result));
+ }
+ }
+
+ @Test
+ public void testToStringUnsigned() {
+ int[] data = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 99999,
+ 100000,
+ 999999,
+ 100000,
+ 999999999,
+ 1000000000,
+ 0x1234_5678,
+ 0x8000_0000,
+ 0x8000_0001,
+ 0x8000_0002,
+ 0x8000_0003,
+ 0x8765_4321,
+ 0xFFFF_FFFE,
+ 0xFFFF_FFFF,
+ };
+
+ for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+ for(int datum : data) {
+ String result1 = Integer.toUnsignedString(datum, radix);
+ String result2 = Long.toString(Integer.toUnsignedLong(datum), radix);
+
+ if (!result1.equals(result2)) {
+ Assert.fail(String.format("Unexpected string difference converting 0x%x:" +
+ "\t%s %s%n",
+ datum, result1, result2));
+ }
+
+ if (radix == 10) {
+ String result3 = Integer.toUnsignedString(datum);
+ if (!result2.equals(result3)) {
+ Assert.fail(String.format("Unexpected string difference converting 0x%x:" +
+ "\t%s %s%n",
+ datum, result3, result2));
+ }
+ }
+
+ int parseResult = Integer.parseUnsignedInt(result1, radix);
+
+ if (parseResult != datum) {
+ Assert.fail(String.format("Bad roundtrip conversion of %d in base %d" +
+ "\tconverting back ''%s'' resulted in %d%n",
+ datum, radix, result1, parseResult));
+ }
+ }
+ }
+ }
+
+ private static final long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
+
+ @Test
+ public void testParseUnsignedInt() {
+ // Values include those between signed Integer.MAX_VALUE and
+ // unsignted int MAX_VALUE.
+ long[] inRange = {
+ 0L,
+ 1L,
+ 10L,
+ 2147483646L, // MAX_VALUE - 1
+ 2147483647L, // MAX_VALUE
+ 2147483648L, // MAX_VALUE + 1
+
+ MAX_UNSIGNED_INT - 1L,
+ MAX_UNSIGNED_INT,
+ };
+
+ for(long value : inRange) {
+ for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+ String longString = Long.toString(value, radix);
+ int intResult = Integer.parseUnsignedInt(longString, radix);
+
+ if (Integer.toUnsignedLong(intResult) != value) {
+ Assert.fail(String.format("Bad roundtrip conversion of %d in base %d" +
+ "\tconverting back ''%s'' resulted in %d%n",
+ value, radix, longString, intResult));
+ }
+
+ // test offset based parse method
+ intResult = Integer.parseUnsignedInt("prefix" + longString + "suffix",
+ "prefix".length(), "prefix".length() + longString.length(), radix);
+
+ if (Integer.toUnsignedLong(intResult) != value) {
+ Assert.fail(String.format("Bad roundtrip conversion of %d in base %d" +
+ "\tconverting back ''%s'' resulted in %d%n",
+ value, radix, longString, intResult));
+ }
+ }
+ }
+
+ String[] outOfRange = {
+ null,
+ "",
+ "-1",
+ Long.toString(MAX_UNSIGNED_INT + 1L),
+ Long.toString(Long.MAX_VALUE)
+ };
+
+ for(String s : outOfRange) {
+ try {
+ int result = Integer.parseUnsignedInt(s);
+ Assert.fail(
+ String.format("Unexpected got %d from an unsigned conversion of %s", result, s));
+ } catch(NumberFormatException nfe) {
+ ; // Correct result
+ }
+ }
+ }
+
+ @Test
+ public void testDivideAndRemainder() {
+ long[] inRange = {
+ 0L,
+ 1L,
+ 2L,
+ 2147483646L, // MAX_VALUE - 1
+ 2147483647L, // MAX_VALUE
+ 2147483648L, // MAX_VALUE + 1
+
+ MAX_UNSIGNED_INT - 1L,
+ MAX_UNSIGNED_INT,
+ };
+
+ for(long dividend : inRange) {
+ for(long divisor : inRange) {
+ int quotient;
+ long longQuotient;
+
+ int remainder;
+ long longRemainder;
+
+ if (divisor == 0) {
+ try {
+ quotient = Integer.divideUnsigned((int) dividend, (int) divisor);
+ Assert.fail("Unexpectedly did not throw");
+ } catch(ArithmeticException ea) {
+ ; // Expected
+ }
+
+ try {
+ remainder = Integer.remainderUnsigned((int) dividend, (int) divisor);
+ Assert.fail("Unexpectedly did not throw");
+ } catch(ArithmeticException ea) {
+ ; // Expected
+ }
+ } else {
+ quotient = Integer.divideUnsigned((int) dividend, (int) divisor);
+ longQuotient = dividend / divisor;
+
+ if (quotient != (int)longQuotient) {
+ Assert.fail(String.format("Unexpected unsigned divide result %s on %s/%s%n",
+ Integer.toUnsignedString(quotient),
+ Integer.toUnsignedString((int) dividend),
+ Integer.toUnsignedString((int) divisor)));
+ }
+
+ remainder = Integer.remainderUnsigned((int) dividend, (int) divisor);
+ longRemainder = dividend % divisor;
+
+ if (remainder != (int)longRemainder) {
+ Assert.fail(String.format("Unexpected unsigned remainder result %s on %s%%%s%n",
+ Integer.toUnsignedString(remainder),
+ Integer.toUnsignedString((int) dividend),
+ Integer.toUnsignedString((int) divisor)));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ojluni/src/test/java/lang/Long/ParsingTest.java b/ojluni/src/test/java/lang/Long/ParsingTest.java
new file mode 100644
index 0000000..f369ea9
--- /dev/null
+++ b/ojluni/src/test/java/lang/Long/ParsingTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 5017980 6576055 8041972 8055251
+ * @summary Test parsing methods
+ * @author Joseph D. Darcy
+ */
+
+/**
+ * There are seven methods in java.lang.Long which transform strings
+ * into a long or Long value:
+ *
+ * public Long(String s)
+ * public static Long decode(String nm)
+ * public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex)
+ * public static long parseLong(String s, int radix)
+ * public static long parseLong(String s)
+ * public static Long valueOf(String s, int radix)
+ * public static Long valueOf(String s)
+ *
+ * Besides decode, all the methods and constructor call down into
+ * parseLong(CharSequence, int, int, int) to do the actual work. Therefore, the
+ * behavior of parseLong(CharSequence, int, int, int) will be tested here.
+ */
+package test.java.lang.Long;
+
+import org.testng.annotations.Test;
+
+public class ParsingTest {
+
+ @Test
+ public void testParsing() {
+ check(+100L, "+100");
+ check(-100L, "-100");
+
+ check(0L, "+0");
+ check(0L, "-0");
+ check(0L, "+00000");
+ check(0L, "-00000");
+
+ check(0L, "0");
+ check(1L, "1");
+ check(9L, "9");
+
+ checkFailure("");
+ checkFailure("\u0000");
+ checkFailure("\u002f");
+ checkFailure("+");
+ checkFailure("-");
+ checkFailure("++");
+ checkFailure("+-");
+ checkFailure("-+");
+ checkFailure("--");
+ checkFailure("++100");
+ checkFailure("--100");
+ checkFailure("+-6");
+ checkFailure("-+6");
+ checkFailure("*100");
+
+ check(0L, "test-00000", 4, 10, 10);
+ check(-12345L, "test-12345", 4, 10, 10);
+ check(12345L, "xx12345yy", 2, 7, 10);
+ check(123456789012345L, "xx123456789012345yy", 2, 17, 10);
+ check(15L, "xxFyy", 2, 3, 16);
+
+ checkNumberFormatException("", 0, 0, 10);
+ checkNumberFormatException("+-6", 0, 3, 10);
+ checkNumberFormatException("1000000", 7, 7, 10);
+ checkNumberFormatException("1000000", 0, 2, Character.MAX_RADIX + 1);
+ checkNumberFormatException("1000000", 0, 2, Character.MIN_RADIX - 1);
+
+ checkIndexOutOfBoundsException("", 1, 1, 10);
+ checkIndexOutOfBoundsException("1000000", 10, 4, 10);
+ checkIndexOutOfBoundsException("1000000", 10, 2, Character.MAX_RADIX + 1);
+ checkIndexOutOfBoundsException("1000000", 10, 2, Character.MIN_RADIX - 1);
+ checkIndexOutOfBoundsException("1000000", -1, 2, Character.MAX_RADIX + 1);
+ checkIndexOutOfBoundsException("1000000", -1, 2, Character.MIN_RADIX - 1);
+ checkIndexOutOfBoundsException("-1", 0, 3, 10);
+ checkIndexOutOfBoundsException("-1", 2, 3, 10);
+ checkIndexOutOfBoundsException("-1", -1, 2, 10);
+
+ checkNull(0, 1, 10);
+ checkNull(-1, 0, 10);
+ checkNull(0, 0, 10);
+ checkNull(0, -1, 10);
+ checkNull(-1, -1, -1);
+ }
+
+ private static void check(long expected, String val) {
+ long n = Long.parseLong(val);
+ if (n != expected)
+ throw new RuntimeException("Long.parseLong failed. String:" +
+ val + " Result:" + n);
+ }
+
+ private static void checkFailure(String val) {
+ long n = 0L;
+ try {
+ n = Long.parseLong(val);
+ System.err.println("parseLong(" + val + ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNumberFormatException(String val, int start, int end, int radix) {
+ long n = 0;
+ try {
+ n = Long.parseLong(val, start, end, radix);
+ System.err.println("parseLong(" + val + ", " + start + ", " + end + ", " + radix +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NumberFormatException nfe) {
+ ; // Expected
+ }
+ }
+
+ private static void checkIndexOutOfBoundsException(String val, int start, int end, int radix) {
+ long n = 0;
+ try {
+ n = Long.parseLong(val, start, end, radix);
+ System.err.println("parseLong(" + val + ", " + start + ", " + end + ", " + radix +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (IndexOutOfBoundsException ioob) {
+ ; // Expected
+ }
+ }
+
+ private static void checkNull(int start, int end, int radix) {
+ long n = 0;
+ try {
+ n = Long.parseLong(null, start, end, radix);
+ System.err.println("parseLong(null, " + start + ", " + end + ", " + radix +
+ ") incorrectly returned " + n);
+ throw new RuntimeException();
+ } catch (NullPointerException npe) {
+ ; // Expected
+ }
+ }
+
+ private static void check(long expected, String val, int start, int end, int radix) {
+ long n = Long.parseLong(val, start, end, radix);
+ if (n != expected)
+ throw new RuntimeException("Long.parseLong failed. Expexted: " + expected + " String: \"" +
+ val + "\", start: " + start + ", end: " + end + " radix: " + radix + " Result: " + n);
+ }
+}
diff --git a/ojluni/src/test/java/lang/Long/Unsigned.java b/ojluni/src/test/java/lang/Long/Unsigned.java
new file mode 100644
index 0000000..8b4a62b
--- /dev/null
+++ b/ojluni/src/test/java/lang/Long/Unsigned.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4504839 4215269 6322074 8030814
+ * @summary Basic tests for unsigned operations
+ * @author Joseph D. Darcy
+ */
+package test.java.lang.Long;
+
+import java.math.*;
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+public class Unsigned {
+ private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+ @Test
+ public void testRoundtrip() {
+ long[] data = {-1L, 0L, 1L};
+
+ for(long datum : data) {
+ Assert.assertEquals(
+ Long.parseUnsignedLong(Long.toBinaryString(datum), 2),
+ datum,
+ "Bad binary roundtrip conversion of " + datum);
+
+ Assert.assertEquals(
+ Long.parseUnsignedLong(Long.toOctalString(datum), 8),
+ datum,
+ "Bad octal roundtrip conversion of " + datum);
+
+ Assert.assertEquals(
+ Long.parseUnsignedLong(Long.toHexString(datum), 16),
+ datum,
+ "Bad hex roundtrip conversion of " + datum);
+ }
+ }
+
+ @Test
+ public void testByteToUnsignedLong() {
+ for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ byte datum = (byte) i;
+ long ui = Byte.toUnsignedLong(datum);
+
+ if ( (ui & (~0xffL)) != 0L || ((byte)ui != datum )) {
+ Assert.fail(
+ String.format("Bad conversion of byte %d to unsigned long %d%n", datum, ui));
+ }
+ }
+ }
+
+ @Test
+ public void testShortToUnsignedLong() {
+ for(int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) {
+ short datum = (short) i;
+ long ui = Short.toUnsignedLong(datum);
+
+ if ( (ui & (~0xffffL)) != 0L || ((short)ui != datum )) {
+ Assert.fail(
+ String.format("Bad conversion of short %d to unsigned long %d%n", datum, ui));
+ }
+ }
+ }
+
+ @Test
+ public void testUnsignedCompare() {
+ long[] data = {
+ 0L,
+ 1L,
+ 2L,
+ 3L,
+ 0x00000000_80000000L,
+ 0x00000000_FFFFFFFFL,
+ 0x00000001_00000000L,
+ 0x80000000_00000000L,
+ 0x80000000_00000001L,
+ 0x80000000_00000002L,
+ 0x80000000_00000003L,
+ 0x80000000_80000000L,
+ 0xFFFFFFFF_FFFFFFFEL,
+ 0xFFFFFFFF_FFFFFFFFL,
+ };
+
+ for(long i : data) {
+ for(long j : data) {
+ long libraryResult = Long.compareUnsigned(i, j);
+ long libraryResultRev = Long.compareUnsigned(j, i);
+ long localResult = compUnsigned(i, j);
+
+ if (i == j) {
+ Assert.assertEquals(
+ libraryResult,
+ 0,
+ String.format("Value 0x%x did not compare as " +
+ "an unsigned equal to itself; got %d%n",
+ i, libraryResult));
+ }
+
+ Assert.assertEquals(
+ Long.signum(libraryResult),
+ Long.signum(localResult),
+ String.format("Unsigned compare of 0x%x to 0x%x%n:" +
+ "\texpected sign of %d, got %d%n",
+ i, j, localResult, libraryResult));
+
+ Assert.assertEquals(
+ Long.signum(libraryResult),
+ -Long.signum(libraryResultRev),
+ String.format("signum(compareUnsigned(x, y)) != -signum(compareUnsigned(y,x))" +
+ " for \t0x%x and 0x%x, computed %d and %d%n",
+ i, j, libraryResult, libraryResultRev));
+ }
+ }
+ }
+
+ private static int compUnsigned(long x, long y) {
+ BigInteger big_x = toUnsignedBigInt(x);
+ BigInteger big_y = toUnsignedBigInt(y);
+
+ return big_x.compareTo(big_y);
+ }
+
+ private static BigInteger toUnsignedBigInt(long x) {
+ if (x >= 0)
+ return BigInteger.valueOf(x);
+ else {
+ int upper = (int)(((long)x) >> 32);
+ int lower = (int) x;
+
+ BigInteger bi = // (upper << 32) + lower
+ (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
+ add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
+
+ // System.out.printf("%n\t%d%n\t%s%n", x, bi.toString());
+ return bi;
+ }
+ }
+
+ @Test
+ public void testToStringUnsigned() {
+ long[] data = {
+ 0L,
+ 1L,
+ 2L,
+ 3L,
+ 99999L,
+ 100000L,
+ 999999L,
+ 100000L,
+ 999999999L,
+ 1000000000L,
+ 0x1234_5678L,
+ 0x8000_0000L,
+ 0x8000_0001L,
+ 0x8000_0002L,
+ 0x8000_0003L,
+ 0x8765_4321L,
+ 0xFFFF_FFFEL,
+ 0xFFFF_FFFFL,
+
+ // Long-range values
+ 999_999_999_999L,
+ 1_000_000_000_000L,
+
+ 999_999_999_999_999_999L,
+ 1_000_000_000_000_000_000L,
+
+ 0xFFFF_FFFF_FFFF_FFFEL,
+ 0xFFFF_FFFF_FFFF_FFFFL,
+ };
+
+ for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+ for(long datum : data) {
+ String result1 = Long.toUnsignedString(datum, radix);
+ String result2 = toUnsignedBigInt(datum).toString(radix);
+
+ Assert.assertEquals(
+ result1,
+ result2,
+ String.format("Unexpected string difference converting 0x%x:" +
+ "\t%s %s%n", datum, result1, result2));
+
+ if (radix == 10) {
+ String result3 = Long.toUnsignedString(datum);
+ Assert.assertEquals(
+ result2,
+ result3,
+ String.format("Unexpected string difference converting 0x%x:" +
+ "\t%s %s%n", datum, result3, result2));
+ }
+
+ long parseResult = Long.parseUnsignedLong(result1, radix);
+
+ Assert.assertEquals(
+ parseResult,
+ datum,
+ String.format("Bad roundtrip conversion of %d in base %d" +
+ "\tconverting back ''%s'' resulted in %d%n",
+ datum, radix, result1, parseResult));
+ }
+ }
+ }
+
+ @Test
+ public void testParseUnsignedLong() {
+ long maxUnsignedInt = Integer.toUnsignedLong(0xffff_ffff);
+
+ // Values include those between signed Long.MAX_VALUE and
+ // unsignted Long MAX_VALUE.
+ BigInteger[] inRange = {
+ BigInteger.valueOf(0L),
+ BigInteger.valueOf(1L),
+ BigInteger.valueOf(10L),
+ BigInteger.valueOf(2147483646L), // Integer.MAX_VALUE - 1
+ BigInteger.valueOf(2147483647L), // Integer.MAX_VALUE
+ BigInteger.valueOf(2147483648L), // Integer.MAX_VALUE + 1
+
+ BigInteger.valueOf(maxUnsignedInt - 1L),
+ BigInteger.valueOf(maxUnsignedInt),
+
+ BigInteger.valueOf(Long.MAX_VALUE - 1L),
+ BigInteger.valueOf(Long.MAX_VALUE),
+ BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
+
+ TWO.pow(64).subtract(BigInteger.ONE)
+ };
+
+ for(BigInteger value : inRange) {
+ for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+ String bigString = value.toString(radix);
+ long longResult = Long.parseUnsignedLong(bigString, radix);
+
+ Assert.assertEquals(
+ toUnsignedBigInt(longResult),
+ value,
+ String.format("Bad roundtrip conversion of %d in base %d" +
+ "\tconverting back ''%s'' resulted in %d%n",
+ value, radix, bigString, longResult));
+
+ // test offset based parse method
+ longResult = Long.parseUnsignedLong("prefix" + bigString + "suffix", "prefix".length(),
+ "prefix".length() + bigString.length(), radix);
+
+ Assert.assertEquals(
+ toUnsignedBigInt(longResult),
+ value,
+ String.format("Bad roundtrip conversion of %d in base %d" +
+ "\tconverting back ''%s'' resulted in %d%n",
+ value, radix, bigString, longResult));
+ }
+ }
+
+ String[] outOfRange = {
+ null,
+ "",
+ "-1",
+ TWO.pow(64).toString(),
+ };
+
+ for(String s : outOfRange) {
+ try {
+ long result = Long.parseUnsignedLong(s);
+ Assert.fail(String.format("Unexpected got %d from an unsigned conversion of %s",
+ result, s));
+ } catch(NumberFormatException nfe) {
+ ; // Correct result
+ }
+ }
+
+ // test case known at one time to fail
+ testUnsignedOverflow("1234567890abcdef1", 16, true);
+
+ // largest value with guard = 91 = 13*7; radix = 13
+ testUnsignedOverflow("196a78a44c3bba320c", 13, false);
+
+ // smallest value with guard = 92 = 23*2*2; radix = 23
+ testUnsignedOverflow("137060c6g1c1dg0", 23, false);
+
+ // guard in [92,98]: no overflow
+
+ // one less than smallest guard value to overflow: guard = 99 = 11*3*3, radix = 33
+ testUnsignedOverflow("b1w8p7j5q9r6f", 33, false);
+
+ // smallest guard value to overflow: guard = 99 = 11*3*3, radix = 33
+ testUnsignedOverflow("b1w8p7j5q9r6g", 33, true);
+
+ // test overflow of overflow
+ BigInteger maxUnsignedLong =
+ BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE);
+ for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+ BigInteger quotient = maxUnsignedLong.divide(BigInteger.valueOf(radix));
+ for (int addend = 2; addend <= radix; addend++) {
+ BigInteger b = quotient.multiply(BigInteger.valueOf(radix + addend));
+ testUnsignedOverflow(b.toString(radix), radix, b.compareTo(maxUnsignedLong) > 0);
+ }
+ }
+ }
+
+ // test for missing or unexpected unsigned overflow exception
+ private static void testUnsignedOverflow(String s, int radix, boolean exception) {
+ long result;
+ try {
+ result = Long.parseUnsignedLong(s, radix);
+ if (exception) {
+ Assert.fail(String.format("Unexpected result %d for Long.parseUnsignedLong(%s,%d)\n",
+ result, s, radix));
+ }
+ } catch (NumberFormatException nfe) {
+ if (!exception) {
+ Assert.fail(
+ String.format("Unexpected exception %s for Long.parseUnsignedLong(%s,%d)\n",
+ nfe.toString(), s, radix));
+ }
+ }
+ }
+
+ @Test
+ public void testDivideAndRemainder() {
+ long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
+
+ BigInteger[] inRange = {
+ BigInteger.valueOf(0L),
+ BigInteger.valueOf(1L),
+ BigInteger.valueOf(10L),
+ BigInteger.valueOf(2147483646L), // Integer.MAX_VALUE - 1
+ BigInteger.valueOf(2147483647L), // Integer.MAX_VALUE
+ BigInteger.valueOf(2147483648L), // Integer.MAX_VALUE + 1
+
+ BigInteger.valueOf(MAX_UNSIGNED_INT - 1L),
+ BigInteger.valueOf(MAX_UNSIGNED_INT),
+
+ BigInteger.valueOf(Long.MAX_VALUE - 1L),
+ BigInteger.valueOf(Long.MAX_VALUE),
+ BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
+
+ TWO.pow(64).subtract(BigInteger.ONE)
+ };
+
+ for(BigInteger dividend : inRange) {
+ for(BigInteger divisor : inRange) {
+ long quotient;
+ BigInteger longQuotient;
+
+ long remainder;
+ BigInteger longRemainder;
+
+ if (divisor.equals(BigInteger.ZERO)) {
+ try {
+ quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
+ Assert.fail("Unexpectedly did not throw while dividing by zero");
+ } catch(ArithmeticException ea) {
+ ; // Expected
+ }
+
+ try {
+ remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
+ Assert.fail("Unexpectedly did not throw while dividing by zero");
+ } catch(ArithmeticException ea) {
+ ; // Expected
+ }
+ } else {
+ quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
+ longQuotient = dividend.divide(divisor);
+
+ Assert.assertEquals(
+ quotient,
+ longQuotient.longValue(),
+ String.format("Unexpected unsigned divide result %s on %s/%s%n",
+ Long.toUnsignedString(quotient),
+ Long.toUnsignedString(dividend.longValue()),
+ Long.toUnsignedString(divisor.longValue())));
+
+ remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
+ longRemainder = dividend.remainder(divisor);
+
+ Assert.assertEquals(
+ remainder,
+ longRemainder.longValue(),
+ String.format("Unexpected unsigned remainder result %s on %s%%%s%n",
+ Long.toUnsignedString(remainder),
+ Long.toUnsignedString(dividend.longValue()),
+ Long.toUnsignedString(divisor.longValue())));
+ }
+ }
+ }
+ }
+}