|
54 | 54 | * methods include {@link #fromHexDigits(CharSequence) fromHexDigits(string)},
|
55 | 55 | * {@link #fromHexDigitsToLong(CharSequence) fromHexDigitsToLong(string)}, and
|
56 | 56 | * {@link #fromHexDigit(int) fromHexDigit(int)} converts a single character or codepoint.
|
57 |
| - * |
| 57 | + * For conversions from hexadecimal characters the digits and uppercase and lowercase |
| 58 | + * characters in {@code "0-9", "a-f", and "A-F"} are converted to corresponding values |
| 59 | + * {@code 0-15}. |
58 | 60 | * <p>
|
59 | 61 | * For byte array to formatted hexadecimal string conversions
|
60 | 62 | * the {@code formatHex} methods include {@link #formatHex(byte[]) formatHex(byte[])}
|
@@ -143,7 +145,22 @@ public final class HexFormat {
|
143 | 145 | '0', '1', '2', '3', '4', '5', '6', '7',
|
144 | 146 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
|
145 | 147 | };
|
146 |
| - |
| 148 | + // Analysis has shown that generating the whole array allows the JIT to generate |
| 149 | + // better code compared to a slimmed down array, such as one cutting off after 'f' |
| 150 | + private static final byte[] DIGITS = new byte[] { |
| 151 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 152 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 153 | + -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, |
| 154 | + -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 155 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, |
| 156 | + 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 157 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 158 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 159 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 160 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 161 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 162 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 163 | + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; |
147 | 164 | /**
|
148 | 165 | * Format each byte of an array as a pair of hexadecimal digits.
|
149 | 166 | * The hexadecimal characters are from lowercase alpha digits.
|
@@ -829,32 +846,38 @@ private static int checkDigitCount(int fromIndex, int toIndex, int limit) {
|
829 | 846 |
|
830 | 847 | /**
|
831 | 848 | * Returns {@code true} if the character is a valid hexadecimal character or codepoint.
|
832 |
| - * A character is a valid hexadecimal character if |
833 |
| - * {@link Character#digit(int, int) Character.digit(int, 16)} returns |
834 |
| - * a positive value. |
835 |
| - * |
| 849 | + * The valid hexadecimal characters are: |
| 850 | + * <ul> |
| 851 | + * <li>{@code '0' ('\u005Cu0030')} through {@code '9' ('\u005Cu0039')} inclusive, |
| 852 | + * <li>{@code 'A' ('\u005Cu0041')} through {@code 'F' ('\u005Cu0046')} inclusive, and |
| 853 | + * <li>{@code 'a' ('\u005Cu0061')} through {@code 'f' ('\u005Cu0066')} inclusive. |
| 854 | + * </ul> |
836 | 855 | * @param ch a codepoint
|
837 | 856 | * @return {@code true} if the character is valid a hexadecimal character,
|
838 | 857 | * otherwise {@code false}
|
839 | 858 | */
|
840 | 859 | public boolean isHexDigit(int ch) {
|
841 |
| - return Character.digit(ch, 16) >= 0; |
| 860 | + return ((ch >>> 8) == 0 && DIGITS[ch] >= 0); |
842 | 861 | }
|
843 | 862 |
|
844 | 863 | /**
|
845 | 864 | * Returns the value for the hexadecimal character or codepoint.
|
846 |
| - * The characters {@code "0-9", "A-F", "a-f"} are parsed |
847 |
| - * using {@link Character#digit(int, int) Character.digit(int, 16)}. |
848 |
| - * |
| 865 | + * The value is: |
| 866 | + * <ul> |
| 867 | + * <li>{@code (ch - '0')} for {@code '0'} through {@code '9'} inclusive, |
| 868 | + * <li>{@code (ch - 'A' + 10)} for {@code 'A'} through {@code 'F'} inclusive, and |
| 869 | + * <li>{@code (ch - 'a' + 10)} for {@code 'a'} through {@code 'f'} inclusive. |
| 870 | + * </ul> |
849 | 871 | * @param ch a character or codepoint
|
850 |
| - * @return the value {@code 0..15} |
| 872 | + * @return the value {@code 0-15} |
851 | 873 | * @throws NumberFormatException if the codepoint is not a hexadecimal character
|
852 | 874 | */
|
853 | 875 | public int fromHexDigit(int ch) {
|
854 |
| - int value = Character.digit(ch, 16); |
855 |
| - if (value < 0) |
856 |
| - throw new NumberFormatException("not a hexadecimal digit: \"" + (char)ch + "\" + " + ch); |
857 |
| - return value; |
| 876 | + int value; |
| 877 | + if ((ch >>> 8) == 0 && (value = DIGITS[ch]) >= 0) { |
| 878 | + return value; |
| 879 | + } |
| 880 | + throw new NumberFormatException("not a hexadecimal digit: \"" + (char) ch + "\" = " + ch); |
858 | 881 | }
|
859 | 882 |
|
860 | 883 | /**
|
|
0 commit comments