8357063: Document preconditions for DecimalDigits methods

Reviewed-by: vyazici, liach, rriggs
This commit is contained in:
Shaojin Wen 2025-05-21 22:39:11 +00:00
parent f687cac889
commit 07871cd78a
7 changed files with 69 additions and 58 deletions

View File

@ -924,9 +924,9 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
int spaceNeeded = count + DecimalDigits.stringSize(i);
byte[] value = ensureCapacitySameCoder(this.value, coder, spaceNeeded);
if (isLatin1(coder)) {
DecimalDigits.getCharsLatin1(i, spaceNeeded, value);
DecimalDigits.uncheckedGetCharsLatin1(i, spaceNeeded, value);
} else {
DecimalDigits.getCharsUTF16(i, spaceNeeded, value);
DecimalDigits.uncheckedGetCharsUTF16(i, spaceNeeded, value);
}
this.value = value;
this.count = spaceNeeded;
@ -951,9 +951,9 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
int spaceNeeded = count + DecimalDigits.stringSize(l);
byte[] value = ensureCapacitySameCoder(this.value, coder, spaceNeeded);
if (isLatin1(coder)) {
DecimalDigits.getCharsLatin1(l, spaceNeeded, value);
DecimalDigits.uncheckedGetCharsLatin1(l, spaceNeeded, value);
} else {
DecimalDigits.getCharsUTF16(l, spaceNeeded, value);
DecimalDigits.uncheckedGetCharsUTF16(l, spaceNeeded, value);
}
this.value = value;
this.count = spaceNeeded;

View File

@ -432,11 +432,11 @@ public final class Integer extends Number
int size = DecimalDigits.stringSize(i);
if (COMPACT_STRINGS) {
byte[] buf = new byte[size];
DecimalDigits.getCharsLatin1(i, size, buf);
DecimalDigits.uncheckedGetCharsLatin1(i, size, buf);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
DecimalDigits.getCharsUTF16(i, size, buf);
DecimalDigits.uncheckedGetCharsUTF16(i, size, buf);
return new String(buf, UTF16);
}
}

View File

@ -462,11 +462,11 @@ public final class Long extends Number
int size = DecimalDigits.stringSize(i);
if (COMPACT_STRINGS) {
byte[] buf = new byte[size];
DecimalDigits.getCharsLatin1(i, size, buf);
DecimalDigits.uncheckedGetCharsLatin1(i, size, buf);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
DecimalDigits.getCharsUTF16(i, size, buf);
DecimalDigits.uncheckedGetCharsUTF16(i, size, buf);
return new String(buf, UTF16);
}
}

View File

@ -315,12 +315,12 @@ final class StringConcatHelper {
static long prepend(long indexCoder, byte[] buf, int value, String prefix) {
int index = (int)indexCoder;
if (indexCoder < UTF16) {
index = DecimalDigits.getCharsLatin1(value, index, buf);
index = DecimalDigits.uncheckedGetCharsLatin1(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.LATIN1);
return index;
} else {
index = DecimalDigits.getCharsUTF16(value, index, buf);
index = DecimalDigits.uncheckedGetCharsUTF16(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.UTF16);
return index | UTF16;
@ -341,12 +341,12 @@ final class StringConcatHelper {
static long prepend(long indexCoder, byte[] buf, long value, String prefix) {
int index = (int)indexCoder;
if (indexCoder < UTF16) {
index = DecimalDigits.getCharsLatin1(value, index, buf);
index = DecimalDigits.uncheckedGetCharsLatin1(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.LATIN1);
return index;
} else {
index = DecimalDigits.getCharsUTF16(value, index, buf);
index = DecimalDigits.uncheckedGetCharsUTF16(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.UTF16);
return index | UTF16;
@ -713,11 +713,11 @@ final class StringConcatHelper {
*/
static int prepend(int index, byte coder, byte[] buf, int value, String prefix) {
if (coder == String.LATIN1) {
index = DecimalDigits.getCharsLatin1(value, index, buf);
index = DecimalDigits.uncheckedGetCharsLatin1(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.LATIN1);
} else {
index = DecimalDigits.getCharsUTF16(value, index, buf);
index = DecimalDigits.uncheckedGetCharsUTF16(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.UTF16);
}
@ -737,11 +737,11 @@ final class StringConcatHelper {
*/
static int prepend(int index, byte coder, byte[] buf, long value, String prefix) {
if (coder == String.LATIN1) {
index = DecimalDigits.getCharsLatin1(value, index, buf);
index = DecimalDigits.uncheckedGetCharsLatin1(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.LATIN1);
} else {
index = DecimalDigits.getCharsUTF16(value, index, buf);
index = DecimalDigits.uncheckedGetCharsUTF16(value, index, buf);
index -= prefix.length();
prefix.getBytes(buf, index, String.UTF16);
}

View File

@ -4146,9 +4146,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
int highInt = (int)intCompact / 100;
int highIntSize = DecimalDigits.stringSize(highInt);
byte[] buf = new byte[highIntSize + 3];
DecimalDigits.getCharsLatin1(highInt, highIntSize, buf);
DecimalDigits.uncheckedGetCharsLatin1(highInt, highIntSize, buf);
buf[highIntSize] = '.';
DecimalDigits.putPairLatin1(buf, highIntSize + 1, lowInt);
DecimalDigits.uncheckedPutPairLatin1(buf, highIntSize + 1, lowInt);
try {
return JLA.uncheckedNewStringNoRepl(buf, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {

View File

@ -143,14 +143,15 @@ public final class DecimalDigits {
* values, to cover the Integer.MIN_VALUE case. Converting otherwise
* (negative to positive) will expose -Integer.MIN_VALUE that overflows
* integer.
* <p>
* <b>WARNING: This method does not perform any bound checks. </b>
*
* @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.
public static int uncheckedGetCharsLatin1(int i, int index, byte[] buf) {
int q;
int charPos = index;
@ -163,20 +164,20 @@ public final class DecimalDigits {
while (i <= -100) {
q = i / 100;
charPos -= 2;
putPairLatin1(buf, charPos, (q * 100) - i);
uncheckedPutPairLatin1(buf, charPos, (q * 100) - i);
i = q;
}
// We know there are at most two digits left at this point.
if (i <= -10) {
charPos -= 2;
putPairLatin1(buf, charPos, -i);
uncheckedPutPairLatin1(buf, charPos, -i);
} else {
putCharLatin1(buf, --charPos, '0' - i);
uncheckedPutCharLatin1(buf, --charPos, '0' - i);
}
if (negative) {
putCharLatin1(buf, --charPos, '-');
uncheckedPutCharLatin1(buf, --charPos, '-');
}
return charPos;
}
@ -193,14 +194,15 @@ public final class DecimalDigits {
* values, to cover the Long.MIN_VALUE case. Converting otherwise
* (negative to positive) will expose -Long.MIN_VALUE that overflows
* long.
* <p>
* <b>WARNING: This method does not perform any bound checks. </b>
*
* @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.
public static int uncheckedGetCharsLatin1(long i, int index, byte[] buf) {
long q;
int charPos = index;
@ -213,7 +215,7 @@ public final class DecimalDigits {
while (i < Integer.MIN_VALUE) {
q = i / 100;
charPos -= 2;
putPairLatin1(buf, charPos, (int)((q * 100) - i));
uncheckedPutPairLatin1(buf, charPos, (int)((q * 100) - i));
i = q;
}
@ -223,36 +225,37 @@ public final class DecimalDigits {
while (i2 <= -100) {
q2 = i2 / 100;
charPos -= 2;
putPairLatin1(buf, charPos, (q2 * 100) - i2);
uncheckedPutPairLatin1(buf, charPos, (q2 * 100) - i2);
i2 = q2;
}
// We know there are at most two digits left at this point.
if (i2 <= -10) {
charPos -= 2;
putPairLatin1(buf, charPos, -i2);
uncheckedPutPairLatin1(buf, charPos, -i2);
} else {
putCharLatin1(buf, --charPos, '0' - i2);
uncheckedPutCharLatin1(buf, --charPos, '0' - i2);
}
if (negative) {
putCharLatin1(buf, --charPos, '-');
uncheckedPutCharLatin1(buf, --charPos, '-');
}
return charPos;
}
/**
* This is a variant of {@link DecimalDigits#getCharsLatin1(int, int, byte[])}, but for
* This is a variant of {@link DecimalDigits#uncheckedGetCharsLatin1(int, int, byte[])}, but for
* UTF-16 coder.
* <p>
* <b>WARNING: This method does not perform any bound checks.</b>
*
* @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.
public static int uncheckedGetCharsUTF16(int i, int index, byte[] buf) {
int q;
int charPos = index;
@ -265,36 +268,37 @@ public final class DecimalDigits {
while (i <= -100) {
q = i / 100;
charPos -= 2;
putPairUTF16(buf, charPos, (q * 100) - i);
uncheckedPutPairUTF16(buf, charPos, (q * 100) - i);
i = q;
}
// We know there are at most two digits left at this point.
if (i <= -10) {
charPos -= 2;
putPairUTF16(buf, charPos, -i);
uncheckedPutPairUTF16(buf, charPos, -i);
} else {
putCharUTF16(buf, --charPos, '0' - i);
uncheckedPutCharUTF16(buf, --charPos, '0' - i);
}
if (negative) {
putCharUTF16(buf, --charPos, '-');
uncheckedPutCharUTF16(buf, --charPos, '-');
}
return charPos;
}
/**
* This is a variant of {@link DecimalDigits#getCharsLatin1(long, int, byte[])}, but for
* This is a variant of {@link DecimalDigits#uncheckedGetCharsLatin1(long, int, byte[])}, but for
* UTF-16 coder.
* <p>
* <b>WARNING: This method does not perform any bound checks.</b>
*
* @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.
public static int uncheckedGetCharsUTF16(long i, int index, byte[] buf) {
long q;
int charPos = index;
@ -307,7 +311,7 @@ public final class DecimalDigits {
while (i < Integer.MIN_VALUE) {
q = i / 100;
charPos -= 2;
putPairUTF16(buf, charPos, (int)((q * 100) - i));
uncheckedPutPairUTF16(buf, charPos, (int)((q * 100) - i));
i = q;
}
@ -317,26 +321,26 @@ public final class DecimalDigits {
while (i2 <= -100) {
q2 = i2 / 100;
charPos -= 2;
putPairUTF16(buf, charPos, (q2 * 100) - i2);
uncheckedPutPairUTF16(buf, charPos, (q2 * 100) - i2);
i2 = q2;
}
// We know there are at most two digits left at this point.
if (i2 <= -10) {
charPos -= 2;
putPairUTF16(buf, charPos, -i2);
uncheckedPutPairUTF16(buf, charPos, -i2);
} else {
putCharUTF16(buf, --charPos, '0' - i2);
uncheckedPutCharUTF16(buf, --charPos, '0' - i2);
}
if (negative) {
putCharUTF16(buf, --charPos, '-');
uncheckedPutCharUTF16(buf, --charPos, '-');
}
return charPos;
}
/**
* This is a variant of {@link DecimalDigits#getCharsUTF16(long, int, byte[])}, but for
* This is a variant of {@link DecimalDigits#uncheckedGetCharsUTF16(long, int, byte[])}, but for
* UTF-16 coder.
*
* @param i value to convert
@ -345,7 +349,6 @@ public final class DecimalDigits {
* @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;
@ -402,34 +405,42 @@ public final class DecimalDigits {
/**
* Insert the 2-bytes integer into the buf as 2 decimal digit ASCII bytes,
* only least significant 16 bits of {@code v} are used.
* <p>
* <b>WARNING: This method does not perform any bound checks.</b>
*
* @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) {
public static void uncheckedPutPairLatin1(byte[] buf, int charPos, int v) {
int packed = DIGITS[v & 0x7f];
putCharLatin1(buf, charPos, packed & 0xFF);
putCharLatin1(buf, charPos + 1, packed >> 8);
uncheckedPutCharLatin1(buf, charPos, packed & 0xFF);
uncheckedPutCharLatin1(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.
* <p>
* <b>WARNING: This method does not perform any bound checks.</b>
*
* @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) {
public static void uncheckedPutPairUTF16(byte[] buf, int charPos, int v) {
int packed = DIGITS[v & 0x7f];
putCharUTF16(buf, charPos, packed & 0xFF);
putCharUTF16(buf, charPos + 1, packed >> 8);
uncheckedPutCharUTF16(buf, charPos, packed & 0xFF);
uncheckedPutCharUTF16(buf, charPos + 1, packed >> 8);
}
private static void putCharLatin1(byte[] buf, int charPos, int c) {
private static void uncheckedPutCharLatin1(byte[] buf, int charPos, int c) {
assert charPos >= 0 && charPos < buf.length;
UNSAFE.putByte(buf, ARRAY_BYTE_BASE_OFFSET + charPos, (byte) c);
}
private static void putCharUTF16(byte[] buf, int charPos, int c) {
private static void uncheckedPutCharUTF16(byte[] buf, int charPos, int c) {
assert charPos >= 0 && charPos < (buf.length >> 1);
UNSAFE.putCharUnaligned(buf, ARRAY_BYTE_BASE_OFFSET + ((long) charPos << 1), (char) c);
}
}

View File

@ -120,14 +120,14 @@ public class Helper {
public static int getChars(int i, int begin, int end, byte[] value) {
StringUTF16.checkBoundsBeginEnd(begin, end, value);
int pos = DecimalDigits.getCharsUTF16(i, end, value);
int pos = DecimalDigits.uncheckedGetCharsUTF16(i, end, value);
assert begin == pos;
return pos;
}
public static int getChars(long l, int begin, int end, byte[] value) {
StringUTF16.checkBoundsBeginEnd(begin, end, value);
int pos = DecimalDigits.getCharsUTF16(l, end, value);
int pos = DecimalDigits.uncheckedGetCharsUTF16(l, end, value);
assert begin == pos;
return pos;
}