8264514: HexFormat implementation tweaks

Reviewed-by: rriggs
This commit is contained in:
Raffaello Giulietti 2021-04-22 13:54:41 +00:00 committed by Roger Riggs
parent e16d568c1f
commit fa82d47591

View File

@ -150,20 +150,24 @@ public final class HexFormat {
};
// Analysis has shown that generating the whole array allows the JIT to generate
// better code compared to a slimmed down array, such as one cutting off after 'f'
private static final byte[] DIGITS = new byte[] {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1,
-1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12,
13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
private static final byte[] DIGITS = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
/**
* Format each byte of an array as a pair of hexadecimal digits.
* The hexadecimal characters are from lowercase alpha digits.
@ -171,7 +175,7 @@ public final class HexFormat {
private static final HexFormat HEX_FORMAT =
new HexFormat("", "", "", LOWERCASE_DIGITS);
private static final byte[] EMPTY_BYTES = new byte[0];
private static final byte[] EMPTY_BYTES = {};
private final String delimiter;
private final String prefix;
@ -191,7 +195,7 @@ public final class HexFormat {
this.delimiter = Objects.requireNonNull(delimiter, "delimiter");
this.prefix = Objects.requireNonNull(prefix, "prefix");
this.suffix = Objects.requireNonNull(suffix, "suffix");
this.digits = Objects.requireNonNull(digits, "digits");
this.digits = digits;
}
/**
@ -468,7 +472,8 @@ public final class HexFormat {
}
/**
* Checked that the requested size for the result string is less than the max array size.
* Checked that the requested size for the result string is
* less than or equal to the max array size.
*
* @param length the requested size of a byte array.
* @return the length
@ -526,7 +531,7 @@ public final class HexFormat {
string = string.subSequence(fromIndex, toIndex);
}
if (string.length() == 0)
if (string.isEmpty())
return EMPTY_BYTES;
if (delimiter.isEmpty() && prefix.isEmpty() && suffix.isEmpty())
return parseNoDelimiter(string);
@ -534,7 +539,7 @@ public final class HexFormat {
// avoid overflow for max length prefix or suffix
long valueChars = prefix.length() + 2L + suffix.length();
long stride = valueChars + delimiter.length();
if (string.length() < valueChars || (string.length() - valueChars) % stride != 0)
if ((string.length() - valueChars) % stride != 0)
throw new IllegalArgumentException("extra or missing delimiters " +
"or values consisting of prefix, two hexadecimal digits, and suffix");
@ -545,16 +550,10 @@ public final class HexFormat {
byte[] bytes = new byte[len];
int i, offset;
for (i = 0, offset = prefix.length(); i < len - 1; i++, offset += 2 + between.length()) {
int v = fromHexDigits(string, offset);
if (v < 0)
throw new IllegalArgumentException("input contains non-hexadecimal characters");
bytes[i] = (byte) v;
bytes[i] = (byte) fromHexDigits(string, offset);
checkLiteral(string, offset + 2, between);
}
int v = fromHexDigits(string, offset);
if (v < 0)
throw new IllegalArgumentException("input contains non-hexadecimal characters");
bytes[i] = (byte) v;
bytes[i] = (byte) fromHexDigits(string, offset);
return bytes;
}
@ -830,21 +829,15 @@ public final class HexFormat {
* @throws IllegalArgumentException if the string length is not valid or
* the string contains non-hexadecimal characters
*/
private byte[] parseNoDelimiter(CharSequence string) {
private static byte[] parseNoDelimiter(CharSequence string) {
if ((string.length() & 1) != 0)
throw new IllegalArgumentException("string length not even: " +
string.length());
byte[] bytes = new byte[string.length() / 2];
int illegal = 0; // Accumulate logical-or of all bytes
for (int i = 0; i < bytes.length; i++) {
int v = fromHexDigits(string, i * 2);
bytes[i] = (byte) v;
illegal |= v;
bytes[i] = (byte) fromHexDigits(string, i * 2);
}
// check if any character was an illegal character
if (illegal < 0)
throw new IllegalArgumentException("input contains non-hexadecimal characters");
return bytes;
}
@ -916,7 +909,6 @@ public final class HexFormat {
* for the {@code CharSequence}
*/
private static int fromHexDigits(CharSequence string, int index) {
Objects.requireNonNull(string, "string");
int high = fromHexDigit(string.charAt(index));
int low = fromHexDigit(string.charAt(index + 1));
return (high << 4) | low;
@ -933,7 +925,8 @@ public final class HexFormat {
* {@link Integer#parseUnsignedInt(String, int) Integer.parseUnsignedInt(s, 16)}
* are similar but allow all Unicode hexadecimal digits defined by
* {@link Character#digit(char, int) Character.digit(ch, 16)}.
* {@code HexFormat} uses only hexadecimal characters "0-9, "A-F", and "a-f".
* {@code HexFormat} uses only hexadecimal characters
* {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
* Signed hexadecimal strings can be parsed with {@link Integer#parseInt(String, int)}.
*
* @param string a CharSequence containing up to eight hexadecimal characters
@ -942,13 +935,7 @@ public final class HexFormat {
* if any of the characters is not a hexadecimal character
*/
public static int fromHexDigits(CharSequence string) {
Objects.requireNonNull(string, "string");
int length = checkDigitCount(0, string.length(), 8);
int value = 0;
for (int i = 0; i < length; i++) {
value = (value << 4) + fromHexDigit(string.charAt(i));
}
return value;
return fromHexDigits(string, 0, string.length());
}
/**
@ -964,7 +951,8 @@ public final class HexFormat {
* {@link Integer#parseUnsignedInt(String, int) Integer.parseUnsignedInt(s, 16)}
* are similar but allow all Unicode hexadecimal digits defined by
* {@link Character#digit(char, int) Character.digit(ch, 16)}.
* {@code HexFormat} uses only hexadecimal characters "0-9, "A-F", and "a-f".
* {@code HexFormat} uses only hexadecimal characters
* {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
* Signed hexadecimal strings can be parsed with {@link Integer#parseInt(String, int)}.
*
* @param string a CharSequence containing the characters
@ -998,7 +986,8 @@ public final class HexFormat {
* {@link Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s, 16)}
* are similar but allow all Unicode hexadecimal digits defined by
* {@link Character#digit(char, int) Character.digit(ch, 16)}.
* {@code HexFormat} uses only hexadecimal characters "0-9, "A-F", and "a-f".
* {@code HexFormat} uses only hexadecimal characters
* {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
* Signed hexadecimal strings can be parsed with {@link Long#parseLong(String, int)}.
*
* @param string a CharSequence containing up to sixteen hexadecimal characters
@ -1007,13 +996,7 @@ public final class HexFormat {
* if any of the characters is not a hexadecimal character
*/
public static long fromHexDigitsToLong(CharSequence string) {
Objects.requireNonNull(string, "string");
int length = checkDigitCount(0, string.length(), 16);
long value = 0L;
for (int i = 0; i < length; i++) {
value = (value << 4) + fromHexDigit(string.charAt(i));
}
return value;
return fromHexDigitsToLong(string, 0, string.length());
}
/**
@ -1029,7 +1012,8 @@ public final class HexFormat {
* {@link Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s, 16)}
* are similar but allow all Unicode hexadecimal digits defined by
* {@link Character#digit(char, int) Character.digit(ch, 16)}.
* {@code HexFormat} uses only hexadecimal characters "0-9, "A-F", and "a-f".
* {@code HexFormat} uses only hexadecimal characters
* {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
* Signed hexadecimal strings can be parsed with {@link Long#parseLong(String, int)}.
*
* @param string a CharSequence containing the characters
@ -1068,10 +1052,10 @@ public final class HexFormat {
if (o == null || getClass() != o.getClass())
return false;
HexFormat otherHex = (HexFormat) o;
return delimiter.equals(otherHex.delimiter) &&
return Arrays.equals(digits, otherHex.digits) &&
delimiter.equals(otherHex.delimiter) &&
prefix.equals(otherHex.prefix) &&
suffix.equals(otherHex.suffix) &&
Arrays.equals(digits, otherHex.digits);
suffix.equals(otherHex.suffix);
}
/**