src/java.base/share/classes/java/lang/Long.java

Print this page

        

@@ -28,10 +28,13 @@
 import java.lang.annotation.Native;
 import java.math.*;
 import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
+import static java.lang.String.COMPACT_STRINGS;
+import static java.lang.String.LATIN1;
+import static java.lang.String.UTF16;
 
 /**
  * The {@code Long} class wraps a value of the primitive type {@code
  * long} in an object. An object of type {@code Long} contains a
  * single field whose type is {@code long}.

@@ -122,29 +125,50 @@
     public static String toString(long i, int radix) {
         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
             radix = 10;
         if (radix == 10)
             return toString(i);
-        char[] buf = new char[65];
+
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[65];
         int charPos = 64;
         boolean negative = (i < 0);
 
         if (!negative) {
             i = -i;
         }
 
         while (i <= -radix) {
-            buf[charPos--] = Integer.digits[(int)(-(i % radix))];
+                buf[charPos--] = (byte)Integer.digits[(int)(-(i % radix))];
             i = i / radix;
         }
-        buf[charPos] = Integer.digits[(int)(-i)];
+            buf[charPos] = (byte)Integer.digits[(int)(-i)];
 
         if (negative) {
             buf[--charPos] = '-';
         }
+            return StringLatin1.newString(buf, charPos, (65 - charPos));
+        }
+        return toStringUTF16(i, radix);
+    }
 
-        return new String(buf, charPos, (65 - charPos));
+    private static String toStringUTF16(long i, int radix) {
+        byte[] buf = new byte[65 * 2];
+        int charPos = 64;
+        boolean negative = (i < 0);
+        if (!negative) {
+            i = -i;
+        }
+        while (i <= -radix) {
+            StringUTF16.putChar(buf, charPos--, Integer.digits[(int)(-(i % radix))]);
+            i = i / radix;
+        }
+        StringUTF16.putChar(buf, charPos, Integer.digits[(int)(-i)]);
+        if (negative) {
+            StringUTF16.putChar(buf, --charPos, '-');
+        }
+        return StringUTF16.newString(buf, charPos, (65 - charPos));
     }
 
     /**
      * Returns a string representation of the first argument as an
      * unsigned integer value in the radix specified by the second

@@ -353,14 +377,20 @@
      */
     static String toUnsignedString0(long val, int shift) {
         // assert shift > 0 && shift <=5 : "Illegal shift value";
         int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
         int chars = Math.max(((mag + (shift - 1)) / shift), 1);
-        char[] buf = new char[chars];
 
-        formatUnsignedLong(val, shift, buf, 0, chars);
-        return new String(buf, true);
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[chars];
+            formatUnsignedLong0(val, shift, buf, 0, chars);
+            return new String(buf, LATIN1);
+        } else {
+            byte[] buf = new byte[chars * 2];
+            formatUnsignedLong0UTF16(val, shift, buf, 0, chars);
+            return new String(buf, UTF16);
+        }
     }
 
     /**
      * Format a long (treated as unsigned) into a character buffer. If
      * {@code len} exceeds the formatted ASCII representation of {@code val},

@@ -383,10 +413,32 @@
             buf[--charPos] = Integer.digits[((int) val) & mask];
             val >>>= shift;
         } while (charPos > offset);
     }
 
+    /** byte[]/LATIN1 version    */
+    static void formatUnsignedLong0(long val, int shift, byte[] buf, int offset, int len) {
+        int charPos = offset + len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            buf[--charPos] = (byte)Integer.digits[((int) val) & mask];
+            val >>>= shift;
+        } while (charPos > offset);
+    }
+
+    /** byte[]/UTF16 version    */
+    static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) {
+        int charPos = offset + len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            StringUTF16.putChar(buf, --charPos, Integer.digits[((int) val) & mask]);
+            val >>>= shift;
+        } while (charPos > offset);
+    }
+
     /**
      * Returns a {@code String} object representing the specified
      * {@code long}.  The argument is converted to signed decimal
      * representation and returned as a string, exactly as if the
      * argument and the radix 10 were given as arguments to the {@link

@@ -397,13 +449,19 @@
      */
     public static String toString(long i) {
         if (i == Long.MIN_VALUE)
             return "-9223372036854775808";
         int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
-        char[] buf = new char[size];
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[size];
         getChars(i, size, buf);
-        return new String(buf, true);
+            return new String(buf, LATIN1);
+        } else {
+            byte[] buf = new byte[size * 2];
+            getCharsUTF16(i, size, buf);
+            return new String(buf, UTF16);
+        }
     }
 
     /**
      * Returns a string representation of the argument as an unsigned
      * decimal value.

@@ -429,11 +487,58 @@
      * digit at the specified index (exclusive), and working
      * backwards from there.
      *
      * Will fail if i == Long.MIN_VALUE
      */
-    static void getChars(long i, int index, char[] buf) {
+    static void getChars(long i, int index, byte[] buf) {
+        long q;
+        int r;
+        int charPos = index;
+        char sign = 0;
+
+        if (i < 0) {
+            sign = '-';
+            i = -i;
+        }
+
+        // Get 2 digits/iteration using longs until quotient fits into an int
+        while (i > Integer.MAX_VALUE) {
+            q = i / 100;
+            // really: r = i - (q * 100);
+            r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
+            i = q;
+            buf[--charPos] = (byte)Integer.DigitOnes[r];
+            buf[--charPos] = (byte)Integer.DigitTens[r];
+        }
+
+        // Get 2 digits/iteration using ints
+        int q2;
+        int i2 = (int)i;
+        while (i2 >= 65536) {
+            q2 = i2 / 100;
+            // really: r = i2 - (q * 100);
+            r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
+            i2 = q2;
+            buf[--charPos] = (byte)Integer.DigitOnes[r];
+            buf[--charPos] = (byte)Integer.DigitTens[r];
+        }
+
+        // Fall thru to fast mode for smaller numbers
+        // assert(i2 <= 65536, i2);
+        for (;;) {
+            q2 = (i2 * 52429) >>> (16+3);
+            r = i2 - ((q2 << 3) + (q2 << 1));  // r = i2-(q2*10) ...
+            buf[--charPos] = (byte)Integer.digits[r];
+            i2 = q2;
+            if (i2 == 0) break;
+        }
+        if (sign != 0) {
+            buf[--charPos] = (byte)sign;
+        }
+    }
+
+    static void getCharsUTF16(long i, int index, byte[] buf) {
         long q;
         int r;
         int charPos = index;
         char sign = 0;
 

@@ -446,37 +551,37 @@
         while (i > Integer.MAX_VALUE) {
             q = i / 100;
             // really: r = i - (q * 100);
             r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
             i = q;
-            buf[--charPos] = Integer.DigitOnes[r];
-            buf[--charPos] = Integer.DigitTens[r];
+            StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
+            StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
         }
 
         // Get 2 digits/iteration using ints
         int q2;
         int i2 = (int)i;
         while (i2 >= 65536) {
             q2 = i2 / 100;
             // really: r = i2 - (q * 100);
             r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
             i2 = q2;
-            buf[--charPos] = Integer.DigitOnes[r];
-            buf[--charPos] = Integer.DigitTens[r];
+            StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
+            StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
         }
 
         // Fall thru to fast mode for smaller numbers
         // assert(i2 <= 65536, i2);
         for (;;) {
             q2 = (i2 * 52429) >>> (16+3);
             r = i2 - ((q2 << 3) + (q2 << 1));  // r = i2-(q2*10) ...
-            buf[--charPos] = Integer.digits[r];
+            StringUTF16.putChar(buf, --charPos, Integer.digits[r]);
             i2 = q2;
             if (i2 == 0) break;
         }
         if (sign != 0) {
-            buf[--charPos] = sign;
+            StringUTF16.putChar(buf, --charPos, sign);
         }
     }
 
     // Requires positive x
     static int stringSize(long x) {