optimize toHexString

This commit is contained in:
Shaojin Wen 2025-01-07 13:56:26 +08:00
parent 91db7c0877
commit 79fe74eb8f
2 changed files with 81 additions and 2 deletions

View File

@ -286,7 +286,55 @@ public final class Integer extends Number
* @since 1.0.2
*/
public static String toHexString(int i) {
return toUnsignedString0(i, 4);
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(i);
int len = Math.max(((mag + 3) / 4), 1);
byte coder = COMPACT_STRINGS ? LATIN1 : UTF16;
byte[] chars = new byte[len << coder];
long x = hex8(i);
do {
--len;
byte b = (byte) x;
if (COMPACT_STRINGS) {
StringLatin1.putChar(chars, len, b);
} else {
StringUTF16.putChar(chars, len, b);
}
x >>>= 8;
} while (len > 0);
return new String(chars, coder);
}
/**
* Extract the least significant 8 bytes from the input integer i, convert each byte into its corresponding 2-digit
* hexadecimal representation, concatenate these hexadecimal strings into one continuous string, and then interpret
* this string as a hexadecimal number to form and return a long value.
*/
static long hex8(long i) {
long x = Long.expand(i, 0x0F0F_0F0F_0F0F_0F0FL);
/*
Use long to simulate vector operations and generate 8 hexadecimal characters at a time.
------------
0 = 0b0000_0000 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '0'
1 = 0b0000_0001 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '1'
2 = 0b0000_0010 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '2'
3 = 0b0000_0011 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '3'
4 = 0b0000_0100 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '4'
5 = 0b0000_0101 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '5'
6 = 0b0000_0110 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '6'
7 = 0b0000_0111 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '7'
8 = 0b0000_1000 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '8'
9 = 0b0000_1001 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 0 + 0x30 + (i & 0xF) => '9'
10 = 0b0000_1010 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (i & 0xF) => 'a'
11 = 0b0000_1011 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (i & 0xF) => 'b'
12 = 0b0000_1100 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (i & 0xF) => 'c'
13 = 0b0000_1101 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (i & 0xF) => 'd'
14 = 0b0000_1110 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (i & 0xF) => 'e'
15 = 0b0000_1111 => m = ((i + 6) & 0x10); (m << 1) + (m >> 1) - (m >> 4) => 39 + 0x30 + (i & 0xF) => 'f'
*/
long m = (x + 0x0606_0606_0606_0606L) & 0x1010_1010_1010_1010L;
return ((m << 1) + (m >> 1) - (m >> 4))
+ 0x3030_3030_3030_3030L
+ (x & 0x0F0F_0F0F_0F0F_0F0FL);
}
/**

View File

@ -34,6 +34,7 @@ import java.util.Objects;
import java.util.Optional;
import jdk.internal.misc.CDS;
import jdk.internal.misc.Unsafe;
import jdk.internal.util.DecimalDigits;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
@ -43,6 +44,7 @@ import static java.lang.Character.digit;
import static java.lang.String.COMPACT_STRINGS;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
/**
* The {@code Long} class is the {@linkplain
@ -311,7 +313,36 @@ public final class Long extends Number
* @since 1.0.2
*/
public static String toHexString(long i) {
return toUnsignedString0(i, 4);
int mag = Long.SIZE - Long.numberOfLeadingZeros(i);
int len = Math.max(((mag + 3) / 4), 1);
byte coder = COMPACT_STRINGS ? LATIN1 : UTF16;
byte[] chars = new byte[len << coder];
byte b;
long x = Integer.hex8(i);
if (len > 8) {
if (COMPACT_STRINGS) {
len -= 8;
Unsafe.getUnsafe().putLong(chars, ARRAY_BYTE_BASE_OFFSET + len, Long.reverseBytes(x));
} else {
for (int j = 0; j < 8; j++) {
b = (byte) x;
StringUTF16.putChar(chars, --len, b);
x >>>= 8;
}
}
x = Integer.hex8(i >>> 32);
}
do {
--len;
b = (byte) x;
if (COMPACT_STRINGS) {
chars[len] = b;
} else {
StringUTF16.putChar(chars, len, b);
}
x >>>= 8;
} while (len > 0);
return new String(chars, coder);
}
/**