Skip to content

Commit

Permalink
Move UnsignedLongs static constants to a static class, to allow other…
Browse files Browse the repository at this point in the history
… UnsignedLongs methods to get inlined.

Effects on IntMathProGuard:
55843 bytes => 55068 bytes
8 classes => 7 classes
51 methods => 50 methods

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=157039263
  • Loading branch information
lowasser authored and cpovirk committed May 25, 2017
1 parent 2a6752b commit 5117309
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 66 deletions.
74 changes: 41 additions & 33 deletions android/guava/src/com/google/common/primitives/UnsignedLongs.java
Expand Up @@ -305,42 +305,64 @@ public static long parseUnsignedLong(String string, int radix) {
throw new NumberFormatException("illegal radix: " + radix);
}

int maxSafePos = maxSafeDigits[radix] - 1;
int maxSafePos = ParseOverflowDetection.maxSafeDigits[radix] - 1;
long value = 0;
for (int pos = 0; pos < string.length(); pos++) {
int digit = Character.digit(string.charAt(pos), radix);
if (digit == -1) {
throw new NumberFormatException(string);
}
if (pos > maxSafePos && overflowInParse(value, digit, radix)) {
if (pos > maxSafePos && ParseOverflowDetection.overflowInParse(value, digit, radix)) {
throw new NumberFormatException("Too large for unsigned long: " + string);
}
value = (value * radix) + digit;
}

return value;
}

/**
* Returns true if (current * radix) + digit is a number too large to be represented by an
* unsigned long. This is useful for detecting overflow while parsing a string representation of a
* number. Does not verify whether supplied radix is valid, passing an invalid radix will give
* undefined results or an ArrayIndexOutOfBoundsException.

/*
* We move the static constants into this class so ProGuard can inline UnsignedLongs entirely
* unless the user is actually calling a parse method.
*/
private static boolean overflowInParse(long current, int digit, int radix) {
if (current >= 0) {
if (current < maxValueDivs[radix]) {
return false;
}
if (current > maxValueDivs[radix]) {
return true;
private static final class ParseOverflowDetection {
private ParseOverflowDetection() {}

// calculated as 0xffffffffffffffff / radix
static final long[] maxValueDivs = new long[Character.MAX_RADIX + 1];
static final int[] maxValueMods = new int[Character.MAX_RADIX + 1];
static final int[] maxSafeDigits = new int[Character.MAX_RADIX + 1];

static {
BigInteger overflow = new BigInteger("10000000000000000", 16);
for (int i = Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) {
maxValueDivs[i] = divide(MAX_VALUE, i);
maxValueMods[i] = (int) remainder(MAX_VALUE, i);
maxSafeDigits[i] = overflow.toString(i).length() - 1;
}
// current == maxValueDivs[radix]
return (digit > maxValueMods[radix]);
}

// current < 0: high bit is set
return true;
/**
* Returns true if (current * radix) + digit is a number too large to be represented by an
* unsigned long. This is useful for detecting overflow while parsing a string representation of
* a number. Does not verify whether supplied radix is valid, passing an invalid radix will give
* undefined results or an ArrayIndexOutOfBoundsException.
*/
static boolean overflowInParse(long current, int digit, int radix) {
if (current >= 0) {
if (current < maxValueDivs[radix]) {
return false;
}
if (current > maxValueDivs[radix]) {
return true;
}
// current == maxValueDivs[radix]
return (digit > maxValueMods[radix]);
}

// current < 0: high bit is set
return true;
}
}

/**
Expand Down Expand Up @@ -403,18 +425,4 @@ public static String toString(long x, int radix) {
return new String(buf, i, buf.length - i);
}
}

// calculated as 0xffffffffffffffff / radix
private static final long[] maxValueDivs = new long[Character.MAX_RADIX + 1];
private static final int[] maxValueMods = new int[Character.MAX_RADIX + 1];
private static final int[] maxSafeDigits = new int[Character.MAX_RADIX + 1];

static {
BigInteger overflow = new BigInteger("10000000000000000", 16);
for (int i = Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) {
maxValueDivs[i] = divide(MAX_VALUE, i);
maxValueMods[i] = (int) remainder(MAX_VALUE, i);
maxSafeDigits[i] = overflow.toString(i).length() - 1;
}
}
}
74 changes: 41 additions & 33 deletions guava/src/com/google/common/primitives/UnsignedLongs.java
Expand Up @@ -305,42 +305,64 @@ public static long parseUnsignedLong(String string, int radix) {
throw new NumberFormatException("illegal radix: " + radix);
}

int maxSafePos = maxSafeDigits[radix] - 1;
int maxSafePos = ParseOverflowDetection.maxSafeDigits[radix] - 1;
long value = 0;
for (int pos = 0; pos < string.length(); pos++) {
int digit = Character.digit(string.charAt(pos), radix);
if (digit == -1) {
throw new NumberFormatException(string);
}
if (pos > maxSafePos && overflowInParse(value, digit, radix)) {
if (pos > maxSafePos && ParseOverflowDetection.overflowInParse(value, digit, radix)) {
throw new NumberFormatException("Too large for unsigned long: " + string);
}
value = (value * radix) + digit;
}

return value;
}

/**
* Returns true if (current * radix) + digit is a number too large to be represented by an
* unsigned long. This is useful for detecting overflow while parsing a string representation of a
* number. Does not verify whether supplied radix is valid, passing an invalid radix will give
* undefined results or an ArrayIndexOutOfBoundsException.

/*
* We move the static constants into this class so ProGuard can inline UnsignedLongs entirely
* unless the user is actually calling a parse method.
*/
private static boolean overflowInParse(long current, int digit, int radix) {
if (current >= 0) {
if (current < maxValueDivs[radix]) {
return false;
}
if (current > maxValueDivs[radix]) {
return true;
private static final class ParseOverflowDetection {
private ParseOverflowDetection() {}

// calculated as 0xffffffffffffffff / radix
static final long[] maxValueDivs = new long[Character.MAX_RADIX + 1];
static final int[] maxValueMods = new int[Character.MAX_RADIX + 1];
static final int[] maxSafeDigits = new int[Character.MAX_RADIX + 1];

static {
BigInteger overflow = new BigInteger("10000000000000000", 16);
for (int i = Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) {
maxValueDivs[i] = divide(MAX_VALUE, i);
maxValueMods[i] = (int) remainder(MAX_VALUE, i);
maxSafeDigits[i] = overflow.toString(i).length() - 1;
}
// current == maxValueDivs[radix]
return (digit > maxValueMods[radix]);
}

// current < 0: high bit is set
return true;
/**
* Returns true if (current * radix) + digit is a number too large to be represented by an
* unsigned long. This is useful for detecting overflow while parsing a string representation of
* a number. Does not verify whether supplied radix is valid, passing an invalid radix will give
* undefined results or an ArrayIndexOutOfBoundsException.
*/
static boolean overflowInParse(long current, int digit, int radix) {
if (current >= 0) {
if (current < maxValueDivs[radix]) {
return false;
}
if (current > maxValueDivs[radix]) {
return true;
}
// current == maxValueDivs[radix]
return (digit > maxValueMods[radix]);
}

// current < 0: high bit is set
return true;
}
}

/**
Expand Down Expand Up @@ -403,18 +425,4 @@ public static String toString(long x, int radix) {
return new String(buf, i, buf.length - i);
}
}

// calculated as 0xffffffffffffffff / radix
private static final long[] maxValueDivs = new long[Character.MAX_RADIX + 1];
private static final int[] maxValueMods = new int[Character.MAX_RADIX + 1];
private static final int[] maxSafeDigits = new int[Character.MAX_RADIX + 1];

static {
BigInteger overflow = new BigInteger("10000000000000000", 16);
for (int i = Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) {
maxValueDivs[i] = divide(MAX_VALUE, i);
maxValueMods[i] = (int) remainder(MAX_VALUE, i);
maxSafeDigits[i] = overflow.toString(i).length() - 1;
}
}
}

0 comments on commit 5117309

Please sign in to comment.