diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index e58ded864f070..b41b5db37837a 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -832,7 +832,7 @@ public AbstractStringBuilder append(int i) { int spaceNeeded = count + Integer.stringSize(i); ensureCapacityInternal(spaceNeeded); if (isLatin1()) { - Integer.getChars(i, spaceNeeded, value); + StringLatin1.getChars(i, spaceNeeded, value); } else { StringUTF16.getChars(i, count, spaceNeeded, value); } @@ -857,7 +857,7 @@ public AbstractStringBuilder append(long l) { int spaceNeeded = count + Long.stringSize(l); ensureCapacityInternal(spaceNeeded); if (isLatin1()) { - Long.getChars(l, spaceNeeded, value); + StringLatin1.getChars(l, spaceNeeded, value); } else { StringUTF16.getChars(l, count, spaceNeeded, value); } diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 8c8bcb9226f4d..2b2377a889bbe 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -414,33 +414,6 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l } while (charPos > 0); } - static final byte[] DigitTens = { - '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 byte[] DigitOnes = { - '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', - } ; - - /** * Returns a {@code String} object representing the * specified integer. The argument is converted to signed decimal @@ -456,7 +429,7 @@ public static String toString(int i) { int size = stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; - getChars(i, size, buf); + StringLatin1.getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; @@ -483,53 +456,6 @@ public static String toUnsignedString(int i) { return Long.toString(toUnsignedLong(i)); } - /** - * 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) { - int q, r; - int charPos = index; - - boolean negative = i < 0; - if (!negative) { - i = -i; - } - - // Generate two digits per iteration - while (i <= -100) { - q = i / 100; - r = (q * 100) - i; - i = q; - buf[--charPos] = DigitOnes[r]; - buf[--charPos] = DigitTens[r]; - } - - // We know there are at most two digits left at this point. - buf[--charPos] = DigitOnes[-i]; - if (i < -9) { - buf[--charPos] = DigitTens[-i]; - } - - if (negative) { - buf[--charPos] = (byte)'-'; - } - return charPos; - } - /** * Returns the string representation size for a given int value. * diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 813837020fb8e..91583c26be106 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -459,7 +459,7 @@ public static String toString(long i) { int size = stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; - getChars(i, size, buf); + StringLatin1.getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; @@ -486,65 +486,6 @@ public static String toUnsignedString(long i) { return toUnsignedString(i, 10); } - /** - * 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) { - long q; - int r; - 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; - r = (int)((q * 100) - i); - i = q; - buf[--charPos] = Integer.DigitOnes[r]; - buf[--charPos] = Integer.DigitTens[r]; - } - - // Get 2 digits/iteration using ints - int q2; - int i2 = (int)i; - while (i2 <= -100) { - q2 = i2 / 100; - r = (q2 * 100) - i2; - i2 = q2; - buf[--charPos] = Integer.DigitOnes[r]; - buf[--charPos] = Integer.DigitTens[r]; - } - - // We know there are at most two digits left at this point. - buf[--charPos] = Integer.DigitOnes[-i2]; - if (i2 < -9) { - buf[--charPos] = Integer.DigitTens[-i2]; - } - - if (negative) { - buf[--charPos] = (byte)'-'; - } - return charPos; - } - /** * Returns the string representation size for a given long value. * diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 139181af0963e..eddfc7e649660 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,7 +250,7 @@ static long prepend(long indexCoder, byte[] buf, char value, String prefix) { */ private static long prepend(long indexCoder, byte[] buf, int value) { if (indexCoder < UTF16) { - return Integer.getChars(value, (int)indexCoder, buf); + return StringLatin1.getChars(value, (int)indexCoder, buf); } else { return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; } @@ -285,7 +285,7 @@ static long prepend(long indexCoder, byte[] buf, int value, String prefix) { */ private static long prepend(long indexCoder, byte[] buf, long value) { if (indexCoder < UTF16) { - return Long.getChars(value, (int)indexCoder, buf); + return StringLatin1.getChars(value, (int)indexCoder, buf); } else { return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; } diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 7c12e5711b397..f6e2acd2fe6c6 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -33,7 +33,9 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.util.ArraysSupport; +import jdk.internal.util.ByteArrayLittleEndian; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.Stable; import static java.lang.String.LATIN1; import static java.lang.String.UTF16; @@ -42,6 +44,40 @@ final class StringLatin1 { + /** + * Each element of the array represents the packaging of two ascii characters based on little endian:
+ *
+ * 00 -> '0' | ('0' << 8) -> 0x3030
+ * 01 -> '1' | ('0' << 8) -> 0x3130
+ * 02 -> '2' | ('0' << 8) -> 0x3230
+ *
+ * ...
+ *
+ * 10 -> '0' | ('1' << 8) -> 0x3031
+ * 11 -> '1' | ('1' << 8) -> 0x3131
+ * 12 -> '2' | ('1' << 8) -> 0x3231
+ *
+ * ...
+ *
+ * 97 -> '7' | ('9' << 8) -> 0x3739
+ * 98 -> '8' | ('9' << 8) -> 0x3839
+ * 99 -> '9' | ('9' << 8) -> 0x3939
+ *
+ */
+ @Stable
+ static final short[] PACKED_DIGITS = new short[] {
+ 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
+ 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
+ 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
+ 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933,
+ 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934,
+ 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935,
+ 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936,
+ 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
+ 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
+ 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939
+ };
+
public static char charAt(byte[] value, int index) {
checkIndex(index, value.length);
return (char)(value[index] & 0xff);
@@ -79,6 +115,115 @@ public static byte[] inflate(byte[] value, int off, int len) {
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, r;
+ int charPos = index;
+
+ boolean negative = i < 0;
+ if (!negative) {
+ i = -i;
+ }
+
+ // Generate two digits per iteration
+ while (i <= -100) {
+ q = i / 100;
+ r = (q * 100) - i;
+ i = q;
+ charPos -= 2;
+ ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[r]);
+ }
+
+ // We know there are at most two digits left at this point.
+ if (i < -9) {
+ charPos -= 2;
+ ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[-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;
+ ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[(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;
+ ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[(q2 * 100) - i2]);
+ i2 = q2;
+ }
+
+ // We know there are at most two digits left at this point.
+ if (i2 < -9) {
+ charPos -= 2;
+ ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[-i2]);
+ } else {
+ buf[--charPos] = (byte)('0' - i2);
+ }
+
+ if (negative) {
+ buf[--charPos] = (byte)'-';
+ }
+ return charPos;
+ }
+
public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) {
inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
index 73d8586399097..db9bdb11864b9 100644
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -33,6 +33,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.util.ArraysSupport;
+import jdk.internal.util.ByteArrayLittleEndian;
import jdk.internal.vm.annotation.DontInline;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
@@ -1519,7 +1520,7 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount,
// been done by the caller.
/**
- * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for
+ * This is a variant of {@link StringLatin1#getChars(int, int, byte[])}, but for
* UTF-16 coder.
*
* @param i value to convert
@@ -1528,6 +1529,7 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount,
* @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;
@@ -1541,14 +1543,23 @@ static int getChars(int i, int index, byte[] buf) {
q = i / 100;
r = (q * 100) - i;
i = q;
- putChar(buf, --charPos, Integer.DigitOnes[r]);
- putChar(buf, --charPos, Integer.DigitTens[r]);
+
+ int packed = (int) StringLatin1.PACKED_DIGITS[r];
+ int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF);
+
+ charPos -= 2;
+ ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated);
}
// We know there are at most two digits left at this point.
- putChar(buf, --charPos, Integer.DigitOnes[-i]);
if (i < -9) {
- putChar(buf, --charPos, Integer.DigitTens[-i]);
+ int packed = (int) StringLatin1.PACKED_DIGITS[-i];
+ int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF);
+
+ charPos -= 2;
+ ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated);
+ } else {
+ putChar(buf, --charPos, '0' - i);
}
if (negative) {
@@ -1558,7 +1569,7 @@ static int getChars(int i, int index, byte[] buf) {
}
/**
- * This is a variant of {@link Long#getChars(long, int, byte[])}, but for
+ * This is a variant of {@link StringLatin1#getChars(long, int, byte[])}, but for
* UTF-16 coder.
*
* @param i value to convert
@@ -1567,8 +1578,8 @@ static int getChars(int i, int index, byte[] buf) {
* @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 r;
int charPos = index;
boolean negative = (i < 0);
@@ -1579,10 +1590,13 @@ static int getChars(long i, int index, byte[] buf) {
// Get 2 digits/iteration using longs until quotient fits into an int
while (i <= Integer.MIN_VALUE) {
q = i / 100;
- r = (int)((q * 100) - i);
+
+ int packed = (int) StringLatin1.PACKED_DIGITS[(int)((q * 100) - i)];
+ int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF);
+
+ charPos -= 2;
+ ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated);
i = q;
- putChar(buf, --charPos, Integer.DigitOnes[r]);
- putChar(buf, --charPos, Integer.DigitTens[r]);
}
// Get 2 digits/iteration using ints
@@ -1590,16 +1604,25 @@ static int getChars(long i, int index, byte[] buf) {
int i2 = (int)i;
while (i2 <= -100) {
q2 = i2 / 100;
- r = (q2 * 100) - i2;
+
+ int packed = (int) StringLatin1.PACKED_DIGITS[(q2 * 100) - i2];
+ int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF);
+
+ charPos -= 2;
+ ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated);
i2 = q2;
- putChar(buf, --charPos, Integer.DigitOnes[r]);
- putChar(buf, --charPos, Integer.DigitTens[r]);
}
// We know there are at most two digits left at this point.
- putChar(buf, --charPos, Integer.DigitOnes[-i2]);
if (i2 < -9) {
- putChar(buf, --charPos, Integer.DigitTens[-i2]);
+ charPos -= 2;
+
+ int packed = (int) StringLatin1.PACKED_DIGITS[-i2];
+ int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF);
+
+ ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated);
+ } else {
+ putChar(buf, --charPos, '0' - i2);
}
if (negative) {
diff --git a/test/jdk/java/lang/Integer/ToString.java b/test/jdk/java/lang/Integer/ToString.java
index 060e0666eb928..0ada8bbf47ca0 100644
--- a/test/jdk/java/lang/Integer/ToString.java
+++ b/test/jdk/java/lang/Integer/ToString.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,13 +23,20 @@
/*
* @test
- * @bug 8136500
- * @summary Test Integer.toString method
+ * @bug 8136500 8310929
+ * @summary Test Integer.toString method for both compact and non-compact strings
+ * @run junit/othervm -XX:+CompactStrings ToString
+ * @run junit/othervm -XX:-CompactStrings ToString
*/
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
public class ToString {
- public static void main(String[] args) throws Exception {
+ @Test
+ public void testBase10() {
test("-2147483648", Integer.MIN_VALUE);
test("2147483647", Integer.MAX_VALUE);
test("0", 0);
@@ -77,9 +84,6 @@ private static void buildAndTest(int c) {
}
private static void test(String expected, int value) {
- String actual = Integer.toString(value);
- if (!expected.equals(actual)) {
- throw new RuntimeException("Expected " + expected + ", but got " + actual);
- }
+ assertEquals(expected, Integer.toString(value));
}
}
diff --git a/test/jdk/java/lang/Long/ToString.java b/test/jdk/java/lang/Long/ToString.java
index a420e3ed25e05..4dd457da2fd8e 100644
--- a/test/jdk/java/lang/Long/ToString.java
+++ b/test/jdk/java/lang/Long/ToString.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,13 +23,20 @@
/*
* @test
- * @bug 8136500
- * @summary Test Long.toString method
+ * @bug 8136500 8310929
+ * @summary Test Long.toString method for both compact and non-compact strings
+ * @run junit/othervm -XX:+CompactStrings ToString
+ * @run junit/othervm -XX:-CompactStrings ToString
*/
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
public class ToString {
- public static void main(String[] args) throws Exception {
+ @Test
+ public void testBase10() {
test("-9223372036854775808", Long.MIN_VALUE);
test("9223372036854775807", Long.MAX_VALUE);
test("0", 0);
@@ -77,9 +84,6 @@ private static void buildAndTest(long c) {
}
private static void test(String expected, long value) {
- String actual = Long.toString(value);
- if (!expected.equals(actual)) {
- throw new RuntimeException("Expected " + expected + ", but got " + actual);
- }
+ assertEquals(expected, Long.toString(value));
}
}