8342650: Move getChars to DecimalDigits
Reviewed-by: liach
This commit is contained in:
parent
ca69a53b76
commit
e1d684c645
@ -830,9 +830,9 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
|
||||
int spaceNeeded = count + DecimalDigits.stringSize(i);
|
||||
ensureCapacityInternal(spaceNeeded);
|
||||
if (isLatin1()) {
|
||||
StringLatin1.getChars(i, spaceNeeded, value);
|
||||
DecimalDigits.getCharsLatin1(i, spaceNeeded, value);
|
||||
} else {
|
||||
StringUTF16.getChars(i, count, spaceNeeded, value);
|
||||
DecimalDigits.getCharsUTF16(i, spaceNeeded, value);
|
||||
}
|
||||
this.count = spaceNeeded;
|
||||
return this;
|
||||
@ -855,9 +855,9 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
|
||||
int spaceNeeded = count + DecimalDigits.stringSize(l);
|
||||
ensureCapacityInternal(spaceNeeded);
|
||||
if (isLatin1()) {
|
||||
StringLatin1.getChars(l, spaceNeeded, value);
|
||||
DecimalDigits.getCharsLatin1(l, spaceNeeded, value);
|
||||
} else {
|
||||
StringUTF16.getChars(l, count, spaceNeeded, value);
|
||||
DecimalDigits.getCharsUTF16(l, spaceNeeded, value);
|
||||
}
|
||||
this.count = spaceNeeded;
|
||||
return this;
|
||||
|
@ -432,11 +432,11 @@ public final class Integer extends Number
|
||||
int size = DecimalDigits.stringSize(i);
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[size];
|
||||
StringLatin1.getChars(i, size, buf);
|
||||
DecimalDigits.getCharsLatin1(i, size, buf);
|
||||
return new String(buf, LATIN1);
|
||||
} else {
|
||||
byte[] buf = new byte[size * 2];
|
||||
StringUTF16.getChars(i, size, buf);
|
||||
DecimalDigits.getCharsUTF16(i, size, buf);
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
}
|
||||
|
@ -462,11 +462,11 @@ public final class Long extends Number
|
||||
int size = DecimalDigits.stringSize(i);
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[size];
|
||||
StringLatin1.getChars(i, size, buf);
|
||||
DecimalDigits.getCharsLatin1(i, size, buf);
|
||||
return new String(buf, LATIN1);
|
||||
} else {
|
||||
byte[] buf = new byte[size * 2];
|
||||
StringUTF16.getChars(i, size, buf);
|
||||
DecimalDigits.getCharsUTF16(i, size, buf);
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
}
|
||||
|
@ -298,12 +298,12 @@ final class StringConcatHelper {
|
||||
static long prepend(long indexCoder, byte[] buf, int value, String prefix) {
|
||||
int index = (int)indexCoder;
|
||||
if (indexCoder < UTF16) {
|
||||
index = StringLatin1.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsLatin1(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.LATIN1);
|
||||
return index;
|
||||
} else {
|
||||
index = StringUTF16.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsUTF16(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.UTF16);
|
||||
return index | UTF16;
|
||||
@ -324,12 +324,12 @@ final class StringConcatHelper {
|
||||
static long prepend(long indexCoder, byte[] buf, long value, String prefix) {
|
||||
int index = (int)indexCoder;
|
||||
if (indexCoder < UTF16) {
|
||||
index = StringLatin1.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsLatin1(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.LATIN1);
|
||||
return index;
|
||||
} else {
|
||||
index = StringUTF16.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsUTF16(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.UTF16);
|
||||
return index | UTF16;
|
||||
@ -682,11 +682,11 @@ final class StringConcatHelper {
|
||||
*/
|
||||
static int prepend(int index, byte coder, byte[] buf, int value, String prefix) {
|
||||
if (coder == String.LATIN1) {
|
||||
index = StringLatin1.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsLatin1(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.LATIN1);
|
||||
} else {
|
||||
index = StringUTF16.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsUTF16(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.UTF16);
|
||||
}
|
||||
@ -706,11 +706,11 @@ final class StringConcatHelper {
|
||||
*/
|
||||
static int prepend(int index, byte coder, byte[] buf, long value, String prefix) {
|
||||
if (coder == String.LATIN1) {
|
||||
index = StringLatin1.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsLatin1(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.LATIN1);
|
||||
} else {
|
||||
index = StringUTF16.getChars(value, index, buf);
|
||||
index = DecimalDigits.getCharsUTF16(value, index, buf);
|
||||
index -= prefix.length();
|
||||
prefix.getBytes(buf, index, String.UTF16);
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.util.DecimalDigits;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
|
||||
import static java.lang.String.LATIN1;
|
||||
@ -86,120 +85,6 @@ final class StringLatin1 {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places characters representing the integer i into the
|
||||
* character array buf. The characters are placed into
|
||||
* the buffer backwards starting with the least significant
|
||||
* digit at the specified index (exclusive), and working
|
||||
* backwards from there.
|
||||
*
|
||||
* @implNote This method converts positive inputs into negative
|
||||
* values, to cover the Integer.MIN_VALUE case. Converting otherwise
|
||||
* (negative to positive) will expose -Integer.MIN_VALUE that overflows
|
||||
* integer.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, Latin1-encoded
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
static int getChars(int i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
int q;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = i < 0;
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Generate two digits per iteration
|
||||
while (i <= -100) {
|
||||
q = i / 100;
|
||||
charPos -= 2;
|
||||
writeDigitPair(buf, charPos, (q * 100) - i);
|
||||
i = q;
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i < -9) {
|
||||
charPos -= 2;
|
||||
writeDigitPair(buf, charPos, -i);
|
||||
} else {
|
||||
buf[--charPos] = (byte)('0' - i);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
buf[--charPos] = (byte)'-';
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places characters representing the long i into the
|
||||
* character array buf. The characters are placed into
|
||||
* the buffer backwards starting with the least significant
|
||||
* digit at the specified index (exclusive), and working
|
||||
* backwards from there.
|
||||
*
|
||||
* @implNote This method converts positive inputs into negative
|
||||
* values, to cover the Long.MIN_VALUE case. Converting otherwise
|
||||
* (negative to positive) will expose -Long.MIN_VALUE that overflows
|
||||
* long.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, Latin1-encoded
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
static int getChars(long i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
long q;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = (i < 0);
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using longs until quotient fits into an int
|
||||
while (i <= Integer.MIN_VALUE) {
|
||||
q = i / 100;
|
||||
charPos -= 2;
|
||||
writeDigitPair(buf, charPos, (int)((q * 100) - i));
|
||||
i = q;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
int q2;
|
||||
int i2 = (int)i;
|
||||
while (i2 <= -100) {
|
||||
q2 = i2 / 100;
|
||||
charPos -= 2;
|
||||
writeDigitPair(buf, charPos, (q2 * 100) - i2);
|
||||
i2 = q2;
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i2 < -9) {
|
||||
charPos -= 2;
|
||||
writeDigitPair(buf, charPos, -i2);
|
||||
} else {
|
||||
buf[--charPos] = (byte)('0' - i2);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
buf[--charPos] = (byte)'-';
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
private static void writeDigitPair(byte[] buf, int charPos, int value) {
|
||||
short pair = DecimalDigits.digitPair(value);
|
||||
buf[charPos] = (byte)(pair);
|
||||
buf[charPos + 1] = (byte)(pair >> 8);
|
||||
}
|
||||
|
||||
public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) {
|
||||
inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ import java.util.stream.StreamSupport;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.util.DecimalDigits;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
|
||||
@ -1513,20 +1512,6 @@ final class StringUTF16 {
|
||||
return codePointCount(val, beginIndex, endIndex, true /* checked */);
|
||||
}
|
||||
|
||||
public static int getChars(int i, int begin, int end, byte[] value) {
|
||||
checkBoundsBeginEnd(begin, end, value);
|
||||
int pos = getChars(i, end, value);
|
||||
assert begin == pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static int getChars(long l, int begin, int end, byte[] value) {
|
||||
checkBoundsBeginEnd(begin, end, value);
|
||||
int pos = getChars(l, end, value);
|
||||
assert begin == pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static boolean contentEquals(byte[] v1, byte[] v2, int len) {
|
||||
checkBoundsOffCount(0, len, v2);
|
||||
for (int i = 0; i < len; i++) {
|
||||
@ -1662,109 +1647,6 @@ final class StringUTF16 {
|
||||
|
||||
static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
|
||||
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have
|
||||
// been done by the caller.
|
||||
|
||||
/**
|
||||
* This is a variant of {@link StringLatin1#getChars(int, int, byte[])}, but for
|
||||
* UTF-16 coder.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, UTF16-coded.
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
static int getChars(int i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
int q, r;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = (i < 0);
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
while (i <= -100) {
|
||||
q = i / 100;
|
||||
r = (q * 100) - i;
|
||||
i = q;
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, r);
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i < -9) {
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, -i);
|
||||
} else {
|
||||
putChar(buf, --charPos, '0' - i);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
putChar(buf, --charPos, '-');
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a variant of {@link StringLatin1#getChars(long, int, byte[])}, but for
|
||||
* UTF-16 coder.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, UTF16-coded.
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
static int getChars(long i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
long q;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = (i < 0);
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using longs until quotient fits into an int
|
||||
while (i <= Integer.MIN_VALUE) {
|
||||
q = i / 100;
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, (int)((q * 100) - i));
|
||||
i = q;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
int q2;
|
||||
int i2 = (int)i;
|
||||
while (i2 <= -100) {
|
||||
q2 = i2 / 100;
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, (q2 * 100) - i2);
|
||||
i2 = q2;
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i2 < -9) {
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, -i2);
|
||||
} else {
|
||||
putChar(buf, --charPos, '0' - i2);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
putChar(buf, --charPos, '-');
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
private static void putPair(byte[] buf, int charPos, int v) {
|
||||
int packed = (int) DecimalDigits.digitPair(v);
|
||||
putChar(buf, charPos, packed & 0xFF);
|
||||
putChar(buf, charPos + 1, packed >> 8);
|
||||
}
|
||||
// End of trusted methods.
|
||||
|
||||
public static void checkIndex(int off, byte[] val) {
|
||||
String.checkIndex(off, length(val));
|
||||
}
|
||||
|
@ -2648,14 +2648,6 @@ public final class System {
|
||||
return str.coder();
|
||||
}
|
||||
|
||||
public int getCharsLatin1(long i, int index, byte[] buf) {
|
||||
return StringLatin1.getChars(i, index, buf);
|
||||
}
|
||||
|
||||
public int getCharsUTF16(long i, int index, byte[] buf) {
|
||||
return StringUTF16.getChars(i, index, buf);
|
||||
}
|
||||
|
||||
public String join(String prefix, String suffix, String delimiter, String[] elements, int size) {
|
||||
return String.join(prefix, suffix, delimiter, elements, size);
|
||||
}
|
||||
|
@ -35,9 +35,15 @@ import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.StreamCorruptedException;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.access.JavaLangAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.util.DecimalDigits;
|
||||
|
||||
/**
|
||||
* Immutable, arbitrary-precision signed decimal numbers. A {@code
|
||||
* BigDecimal} consists of an arbitrary precision integer
|
||||
@ -328,6 +334,8 @@ import java.util.Objects;
|
||||
* @since 1.1
|
||||
*/
|
||||
public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
|
||||
|
||||
/*
|
||||
* Let l = log_2(10).
|
||||
* Then, L < l < L + ulp(L) / 2, that is, L = roundTiesToEven(l).
|
||||
@ -4164,103 +4172,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
return BigDecimal.valueOf(1, this.scale(), 1);
|
||||
}
|
||||
|
||||
// Private class to build a string representation for BigDecimal object. The
|
||||
// StringBuilder field acts as a buffer to hold the temporary representation
|
||||
// of BigDecimal. The cmpCharArray holds all the characters for the compact
|
||||
// representation of BigDecimal (except for '-' sign' if it is negative) if
|
||||
// its intCompact field is not INFLATED.
|
||||
static class StringBuilderHelper {
|
||||
final StringBuilder sb; // Placeholder for BigDecimal string
|
||||
final char[] cmpCharArray; // character array to place the intCompact
|
||||
|
||||
StringBuilderHelper() {
|
||||
sb = new StringBuilder(32);
|
||||
// All non negative longs can be made to fit into 19 character array.
|
||||
cmpCharArray = new char[19];
|
||||
}
|
||||
|
||||
// Accessors.
|
||||
StringBuilder getStringBuilder() {
|
||||
sb.setLength(0);
|
||||
return sb;
|
||||
}
|
||||
|
||||
char[] getCompactCharArray() {
|
||||
return cmpCharArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places characters representing the intCompact in {@code long} into
|
||||
* cmpCharArray and returns the offset to the array where the
|
||||
* representation starts.
|
||||
*
|
||||
* @param intCompact the number to put into the cmpCharArray.
|
||||
* @return offset to the array where the representation starts.
|
||||
* Note: intCompact must be greater or equal to zero.
|
||||
*/
|
||||
int putIntCompact(long intCompact) {
|
||||
assert intCompact >= 0;
|
||||
|
||||
long q;
|
||||
int r;
|
||||
// since we start from the least significant digit, charPos points to
|
||||
// the last character in cmpCharArray.
|
||||
int charPos = cmpCharArray.length;
|
||||
|
||||
// Get 2 digits/iteration using longs until quotient fits into an int
|
||||
while (intCompact > Integer.MAX_VALUE) {
|
||||
q = intCompact / 100;
|
||||
r = (int)(intCompact - q * 100);
|
||||
intCompact = q;
|
||||
cmpCharArray[--charPos] = DIGIT_ONES[r];
|
||||
cmpCharArray[--charPos] = DIGIT_TENS[r];
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints when i2 >= 100
|
||||
int q2;
|
||||
int i2 = (int)intCompact;
|
||||
while (i2 >= 100) {
|
||||
q2 = i2 / 100;
|
||||
r = i2 - q2 * 100;
|
||||
i2 = q2;
|
||||
cmpCharArray[--charPos] = DIGIT_ONES[r];
|
||||
cmpCharArray[--charPos] = DIGIT_TENS[r];
|
||||
}
|
||||
|
||||
cmpCharArray[--charPos] = DIGIT_ONES[i2];
|
||||
if (i2 >= 10)
|
||||
cmpCharArray[--charPos] = DIGIT_TENS[i2];
|
||||
|
||||
return charPos;
|
||||
}
|
||||
|
||||
static final char[] DIGIT_TENS = {
|
||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
|
||||
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
|
||||
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
|
||||
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
|
||||
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
|
||||
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
|
||||
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
|
||||
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
|
||||
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
|
||||
};
|
||||
|
||||
static final char[] DIGIT_ONES = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Lay out this {@code BigDecimal} into a {@code char[]} array.
|
||||
* The Java 1.2 equivalent to this was called {@code getValueString}.
|
||||
@ -4271,6 +4182,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* {@code BigDecimal}
|
||||
*/
|
||||
private String layoutChars(boolean sci) {
|
||||
long intCompact = this.intCompact;
|
||||
int scale = this.scale;
|
||||
if (scale == 0) // zero scale is trivial
|
||||
return (intCompact != INFLATED) ?
|
||||
Long.toString(intCompact):
|
||||
@ -4280,18 +4193,24 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
// currency fast path
|
||||
int lowInt = (int)intCompact % 100;
|
||||
int highInt = (int)intCompact / 100;
|
||||
return (Integer.toString(highInt) + '.' +
|
||||
StringBuilderHelper.DIGIT_TENS[lowInt] +
|
||||
StringBuilderHelper.DIGIT_ONES[lowInt]) ;
|
||||
int highIntSize = DecimalDigits.stringSize(highInt);
|
||||
byte[] buf = new byte[highIntSize + 3];
|
||||
DecimalDigits.putPairLatin1(buf, highIntSize + 1, lowInt);
|
||||
buf[highIntSize] = '.';
|
||||
DecimalDigits.getCharsLatin1(highInt, highIntSize, buf);
|
||||
try {
|
||||
return JLA.newStringNoRepl(buf, StandardCharsets.ISO_8859_1);
|
||||
} catch (CharacterCodingException cce) {
|
||||
throw new AssertionError(cce);
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilderHelper sbHelper = new StringBuilderHelper();
|
||||
char[] coeff;
|
||||
int offset; // offset is the starting index for coeff array
|
||||
// Get the significand as an absolute value
|
||||
if (intCompact != INFLATED) {
|
||||
offset = sbHelper.putIntCompact(Math.abs(intCompact));
|
||||
coeff = sbHelper.getCompactCharArray();
|
||||
coeff = new char[19];
|
||||
offset = DecimalDigits.getChars(Math.abs(intCompact), coeff.length, coeff);
|
||||
} else {
|
||||
offset = 0;
|
||||
coeff = intVal.abs().toString().toCharArray();
|
||||
@ -4301,7 +4220,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
// If E-notation is needed, length will be: +1 if negative, +1
|
||||
// if '.' needed, +2 for "E+", + up to 10 for adjusted exponent.
|
||||
// Otherwise it could have +1 if negative, plus leading "0.00000"
|
||||
StringBuilder buf = sbHelper.getStringBuilder();
|
||||
StringBuilder buf = new StringBuilder(32);;
|
||||
if (signum() < 0) // prefix '-' if negative
|
||||
buf.append('-');
|
||||
int coeffLen = coeff.length - offset;
|
||||
|
@ -487,10 +487,6 @@ public interface JavaLangAccess {
|
||||
*/
|
||||
Object classData(Class<?> c);
|
||||
|
||||
int getCharsLatin1(long i, int index, byte[] buf);
|
||||
|
||||
int getCharsUTF16(long i, int index, byte[] buf);
|
||||
|
||||
/**
|
||||
* Returns the {@link NativeLibraries} object associated with the provided class loader.
|
||||
* This is used by {@link SymbolLookup#loaderLookup()}.
|
||||
|
@ -25,14 +25,18 @@
|
||||
|
||||
package jdk.internal.util;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
|
||||
/**
|
||||
* Digits class for decimal digits.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public final class DecimalDigits {
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
/**
|
||||
* Each element of the array represents the packaging of two ascii characters based on little endian:<p>
|
||||
@ -76,15 +80,6 @@ public final class DecimalDigits {
|
||||
private DecimalDigits() {
|
||||
}
|
||||
|
||||
/**
|
||||
* For values from 0 to 99 return a short encoding a pair of ASCII-encoded digit characters in little-endian
|
||||
* @param i value to convert
|
||||
* @return a short encoding a pair of ASCII-encoded digit characters
|
||||
*/
|
||||
public static short digitPair(int i) {
|
||||
return DIGITS[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation size for a given int value.
|
||||
*
|
||||
@ -136,4 +131,306 @@ public final class DecimalDigits {
|
||||
}
|
||||
return 19 + d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places characters representing the integer i into the
|
||||
* character array buf. The characters are placed into
|
||||
* the buffer backwards starting with the least significant
|
||||
* digit at the specified index (exclusive), and working
|
||||
* backwards from there.
|
||||
*
|
||||
* @implNote This method converts positive inputs into negative
|
||||
* values, to cover the Integer.MIN_VALUE case. Converting otherwise
|
||||
* (negative to positive) will expose -Integer.MIN_VALUE that overflows
|
||||
* integer.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, Latin1-encoded
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
public static int getCharsLatin1(int i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
int q;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = i < 0;
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Generate two digits per iteration
|
||||
while (i <= -100) {
|
||||
q = i / 100;
|
||||
charPos -= 2;
|
||||
putPairLatin1(buf, charPos, (q * 100) - i);
|
||||
i = q;
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i < -9) {
|
||||
charPos -= 2;
|
||||
putPairLatin1(buf, charPos, -i);
|
||||
} else {
|
||||
putCharLatin1(buf, --charPos, '0' - i);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
putCharLatin1(buf, --charPos, '-');
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Places characters representing the long i into the
|
||||
* character array buf. The characters are placed into
|
||||
* the buffer backwards starting with the least significant
|
||||
* digit at the specified index (exclusive), and working
|
||||
* backwards from there.
|
||||
*
|
||||
* @implNote This method converts positive inputs into negative
|
||||
* values, to cover the Long.MIN_VALUE case. Converting otherwise
|
||||
* (negative to positive) will expose -Long.MIN_VALUE that overflows
|
||||
* long.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, Latin1-encoded
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
public static int getCharsLatin1(long i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
long q;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = (i < 0);
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using longs until quotient fits into an int
|
||||
while (i <= Integer.MIN_VALUE) {
|
||||
q = i / 100;
|
||||
charPos -= 2;
|
||||
putPairLatin1(buf, charPos, (int)((q * 100) - i));
|
||||
i = q;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
int q2;
|
||||
int i2 = (int)i;
|
||||
while (i2 <= -100) {
|
||||
q2 = i2 / 100;
|
||||
charPos -= 2;
|
||||
putPairLatin1(buf, charPos, (q2 * 100) - i2);
|
||||
i2 = q2;
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i2 < -9) {
|
||||
charPos -= 2;
|
||||
putPairLatin1(buf, charPos, -i2);
|
||||
} else {
|
||||
putCharLatin1(buf, --charPos, '0' - i2);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
putCharLatin1(buf, --charPos, '-');
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is a variant of {@link DecimalDigits#getCharsLatin1(int, int, byte[])}, but for
|
||||
* UTF-16 coder.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, UTF16-coded.
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
public static int getCharsUTF16(int i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
int q, r;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = (i < 0);
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
while (i <= -100) {
|
||||
q = i / 100;
|
||||
r = (q * 100) - i;
|
||||
i = q;
|
||||
charPos -= 2;
|
||||
putPairUTF16(buf, charPos, r);
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i < -9) {
|
||||
charPos -= 2;
|
||||
putPairUTF16(buf, charPos, -i);
|
||||
} else {
|
||||
putCharUTF16(buf, --charPos, '0' - i);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
putCharUTF16(buf, --charPos, '-');
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is a variant of {@link DecimalDigits#getCharsLatin1(long, int, byte[])}, but for
|
||||
* UTF-16 coder.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, UTF16-coded.
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
public static int getCharsUTF16(long i, int index, byte[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
long q;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = (i < 0);
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using longs until quotient fits into an int
|
||||
while (i <= Integer.MIN_VALUE) {
|
||||
q = i / 100;
|
||||
charPos -= 2;
|
||||
putPairUTF16(buf, charPos, (int)((q * 100) - i));
|
||||
i = q;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
int q2;
|
||||
int i2 = (int)i;
|
||||
while (i2 <= -100) {
|
||||
q2 = i2 / 100;
|
||||
charPos -= 2;
|
||||
putPairUTF16(buf, charPos, (q2 * 100) - i2);
|
||||
i2 = q2;
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i2 < -9) {
|
||||
charPos -= 2;
|
||||
putPairUTF16(buf, charPos, -i2);
|
||||
} else {
|
||||
putCharUTF16(buf, --charPos, '0' - i2);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
putCharUTF16(buf, --charPos, '-');
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a variant of {@link DecimalDigits#getCharsUTF16(long, int, byte[])}, but for
|
||||
* UTF-16 coder.
|
||||
*
|
||||
* @param i value to convert
|
||||
* @param index next index, after the least significant digit
|
||||
* @param buf target buffer, UTF16-coded.
|
||||
* @return index of the most significant digit or minus sign, if present
|
||||
*/
|
||||
public static int getChars(long i, int index, char[] buf) {
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have been done by the caller.
|
||||
long q;
|
||||
int charPos = index;
|
||||
|
||||
boolean negative = (i < 0);
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using longs until quotient fits into an int
|
||||
while (i <= Integer.MIN_VALUE) {
|
||||
q = i / 100;
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, (int)((q * 100) - i));
|
||||
i = q;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
int q2;
|
||||
int i2 = (int)i;
|
||||
while (i2 <= -100) {
|
||||
q2 = i2 / 100;
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, (q2 * 100) - i2);
|
||||
i2 = q2;
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
if (i2 < -9) {
|
||||
charPos -= 2;
|
||||
putPair(buf, charPos, -i2);
|
||||
} else {
|
||||
buf[--charPos] = (char) ('0' - i2);
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
buf[--charPos] = '-';
|
||||
}
|
||||
return charPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the 2-chars integer into the buf as 2 decimal digit ASCII chars,
|
||||
* only least significant 16 bits of {@code v} are used.
|
||||
* @param buf byte buffer to copy into
|
||||
* @param charPos insert point
|
||||
* @param v to convert
|
||||
*/
|
||||
public static void putPair(char[] buf, int charPos, int v) {
|
||||
int packed = DIGITS[v];
|
||||
buf[charPos ] = (char) (packed & 0xFF);
|
||||
buf[charPos + 1] = (char) (packed >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the 2-bytes integer into the buf as 2 decimal digit ASCII bytes,
|
||||
* only least significant 16 bits of {@code v} are used.
|
||||
* @param buf byte buffer to copy into
|
||||
* @param charPos insert point
|
||||
* @param v to convert
|
||||
*/
|
||||
public static void putPairLatin1(byte[] buf, int charPos, int v) {
|
||||
int packed = DIGITS[v];
|
||||
putCharLatin1(buf, charPos, packed & 0xFF);
|
||||
putCharLatin1(buf, charPos + 1, packed >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the 2-chars integer into the buf as 2 decimal digit UTF16 bytes,
|
||||
* only least significant 16 bits of {@code v} are used.
|
||||
* @param buf byte buffer to copy into
|
||||
* @param charPos insert point
|
||||
* @param v to convert
|
||||
*/
|
||||
public static void putPairUTF16(byte[] buf, int charPos, int v) {
|
||||
int packed = DIGITS[v];
|
||||
putCharUTF16(buf, charPos, packed & 0xFF);
|
||||
putCharUTF16(buf, charPos + 1, packed >> 8);
|
||||
}
|
||||
|
||||
private static void putCharLatin1(byte[] buf, int charPos, int c) {
|
||||
UNSAFE.putByte(buf, ARRAY_BYTE_BASE_OFFSET + charPos, (byte) c);
|
||||
}
|
||||
|
||||
private static void putCharUTF16(byte[] buf, int charPos, int c) {
|
||||
UNSAFE.putChar(buf, ARRAY_BYTE_BASE_OFFSET + (charPos << 1), (char) c);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
import jdk.internal.util.DecimalDigits;
|
||||
|
||||
/**
|
||||
* A helper class to get access to package-private members
|
||||
*/
|
||||
@ -117,11 +119,17 @@ public class Helper {
|
||||
}
|
||||
|
||||
public static int getChars(int i, int begin, int end, byte[] value) {
|
||||
return StringUTF16.getChars(i, begin, end, value);
|
||||
StringUTF16.checkBoundsBeginEnd(begin, end, value);
|
||||
int pos = DecimalDigits.getCharsUTF16(i, end, value);
|
||||
assert begin == pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static int getChars(long l, int begin, int end, byte[] value) {
|
||||
return StringUTF16.getChars(l, begin, end, value);
|
||||
StringUTF16.checkBoundsBeginEnd(begin, end, value);
|
||||
int pos = DecimalDigits.getCharsUTF16(l, end, value);
|
||||
assert begin == pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static boolean contentEquals(byte[] v1, byte[] v2, int len) {
|
||||
|
@ -54,6 +54,8 @@ public class StringBuilders {
|
||||
private StringBuilder sbLatin2;
|
||||
private StringBuilder sbUtf16;
|
||||
private StringBuilder sbUtf17;
|
||||
private int[] intsArray;
|
||||
private long[] longArray;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
@ -69,6 +71,13 @@ public class StringBuilders {
|
||||
sbLatin2 = new StringBuilder("Latin1 string");
|
||||
sbUtf16 = new StringBuilder("UTF-\uFF11\uFF16 string");
|
||||
sbUtf17 = new StringBuilder("UTF-\uFF11\uFF16 string");
|
||||
int size = 16;
|
||||
intsArray = new int[size];
|
||||
longArray = new long[size];
|
||||
for (int i = 0; i < longArray.length; i++) {
|
||||
intsArray[i] = ((100 * i + i) << 24) + 4543 + i * 4;
|
||||
longArray[i] = ((100L * i + i) << 32) + 4543 + i * 4L;
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@ -224,6 +233,47 @@ public class StringBuilders {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int appendWithIntLatin1() {
|
||||
StringBuilder buf = sbLatin1;
|
||||
buf.setLength(0);
|
||||
for (long l : longArray) {
|
||||
buf.append(l);
|
||||
}
|
||||
return buf.length();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int appendWithIntUtf16() {
|
||||
StringBuilder buf = sbUtf16;
|
||||
buf.setLength(0);
|
||||
buf.setLength(0);
|
||||
for (long l : longArray) {
|
||||
buf.append(l);
|
||||
}
|
||||
return buf.length();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int appendWithLongLatin1() {
|
||||
StringBuilder buf = sbLatin1;
|
||||
buf.setLength(0);
|
||||
for (long l : longArray) {
|
||||
buf.append(l);
|
||||
}
|
||||
return buf.length();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int appendWithLongUtf16() {
|
||||
StringBuilder buf = sbUtf16;
|
||||
buf.setLength(0);
|
||||
buf.setLength(0);
|
||||
for (long l : longArray) {
|
||||
buf.append(l);
|
||||
}
|
||||
return buf.length();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int appendWithBool8Latin1() {
|
||||
|
Loading…
Reference in New Issue
Block a user