< prev index next >

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

Print this page

        

@@ -68,10 +68,15 @@
      * The count is the number of characters used.
      */
     int count;
 
     /**
+     * Whether value array is shared with a String.
+     */
+    transient boolean shared;
+
+    /**
      * This no-arg constructor is necessary for serialization of subclasses.
      */
     AbstractStringBuilder() {
     }
 

@@ -86,10 +91,19 @@
             value = StringUTF16.newBytesFor(capacity);
             coder = UTF16;
         }
     }
 
+    byte[] unshareValue() {
+        if (shared) {
+            // assert (count << coder) == value.length
+            value = Arrays.copyOf(value, value.length);
+            shared = false;
+        }
+        return value;
+    }
+
     /**
      * Returns the length (character count).
      *
      * @return  the length of the sequence of characters currently
      *          represented by this object

@@ -164,10 +178,11 @@
                 throw new OutOfMemoryError();
             }
             newCapacity = StringUTF16.MAX_LENGTH;
         }
         this.value = Arrays.copyOf(value, newCapacity << coder);
+        this.shared = false;
     }
 
     /**
      * If the coder is "isLatin1", this inflates the internal 8-bit storage
      * to 16-bit <hi=0, low> pair storage.

@@ -178,10 +193,11 @@
         }
         byte[] buf = StringUTF16.newBytesFor(value.length);
         StringLatin1.inflateSB(value, buf, 0, count);
         this.value = buf;
         this.coder = UTF16;
+        this.shared = false;
     }
 
     /**
      * Attempts to reduce storage used for the character sequence.
      * If the buffer is larger than necessary to hold its current sequence of

@@ -223,17 +239,19 @@
      */
     public void setLength(int newLength) {
         if (newLength < 0) {
             throw new StringIndexOutOfBoundsException(newLength);
         }
-        ensureCapacityInternal(newLength);
         if (count < newLength) {
+            ensureCapacityInternal(newLength);
             if (isLatin1()) {
                 StringLatin1.fillNull(value, count, newLength);
             } else {
                 StringUTF16.fillNull(value, count, newLength);
             }
+        } else if (newLength < count) {
+            unshareValue();
         }
         count = newLength;
     }
 
     /**

@@ -435,14 +453,17 @@
      *             negative or greater than or equal to {@code length()}.
      */
     public void setCharAt(int index, char ch) {
         checkIndex(index, count);
         if (isLatin1() && StringLatin1.canEncode(ch)) {
+            final byte[] value = unshareValue();
             value[index] = (byte)ch;
         } else {
             if (isLatin1()) {
                 inflate();
+            } else {
+                unshareValue();
             }
             StringUTF16.putCharSB(value, index, ch);
         }
     }
 

@@ -824,10 +845,11 @@
             end = count;
         }
         checkRangeSIOOBE(start, end, count);
         int len = end - start;
         if (len > 0) {
+            unshareValue();
             shift(end, -len);
             count -= len;
         }
         return this;
     }

@@ -875,10 +897,11 @@
      *              is negative or greater than or equal to
      *              {@code length()}.
      */
     public AbstractStringBuilder deleteCharAt(int index) {
         checkIndex(index, count);
+        unshareValue();
         shift(index + 1, -1);
         count--;
         return this;
     }
 

@@ -907,10 +930,11 @@
         }
         checkRangeSIOOBE(start, end, count);
         int len = str.length();
         int newCount = count + len - (end - start);
         ensureCapacityInternal(newCount);
+        unshareValue();
         shift(end, newCount - count);
         count = newCount;
         putStringAt(start, str);
         return this;
     }

@@ -1463,11 +1487,11 @@
      * a valid surrogate pair.
      *
      * @return  a reference to this object.
      */
     public AbstractStringBuilder reverse() {
-        byte[] val = this.value;
+        byte[] val = unshareValue();
         int count = this.count;
         int coder = this.coder;
         int n = count - 1;
         if (COMPACT_STRINGS && coder == LATIN1) {
             for (int j = (n-1) >> 1; j >= 0; j--) {

@@ -1573,11 +1597,11 @@
      * @param coder     the coder of dst[]
      */
     void getBytes(byte dst[], int dstBegin, byte coder) {
         if (this.coder == coder) {
             System.arraycopy(value, 0, dst, dstBegin << coder, count << coder);
-        } else {        // this.coder == LATIN && coder == UTF16
+        } else {        // this.coder == LATIN1 && coder == UTF16
             StringLatin1.inflateSB(value, dst, dstBegin, count);
         }
     }
 
     /* for readObject() */
< prev index next >