|
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