Path: blob/master/jcl/src/java.base/share/classes/java/lang/StringBuilder.java
12513 views
/*[INCLUDE-IF JAVA_SPEC_VERSION == 8]*/1/*******************************************************************************2* Copyright (c) 2005, 2022 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* distribution and is available at https://www.eclipse.org/legal/epl-2.0/7* or the Apache License, Version 2.0 which accompanies this distribution and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*20* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception21*******************************************************************************/22package java.lang;2324import java.io.IOException;25import java.io.ObjectInputStream;26import java.io.ObjectOutputStream;27import java.io.Serializable;28import java.io.StreamCorruptedException;29import java.util.Arrays;30import java.util.Properties;3132/**33* StringBuilder is not thread safe. For a synchronized implementation, use34* StringBuffer.35*36* StringBuilder is a variable size contiguous indexable array of characters.37* The length of the StringBuilder is the number of characters it contains.38* The capacity of the StringBuilder is the number of characters it can hold.39* <p>40* Characters may be inserted at any position up to the length of the41* StringBuilder, increasing the length of the StringBuilder. Characters at any42* position in the StringBuilder may be replaced, which does not affect the43* StringBuilder length.44* <p>45* The capacity of a StringBuilder may be specified when the StringBuilder is46* created. If the capacity of the StringBuilder is exceeded, the capacity47* is increased.48*49* @author OTI50* @version initial51*52* @see StringBuffer53*54* @since 1.555*/56public final class StringBuilder extends AbstractStringBuilder implements Serializable, CharSequence, Appendable {57private static final long serialVersionUID = 4383685877147921099L;5859private static final int INITIAL_SIZE = 16;6061private static boolean TOSTRING_COPY_BUFFER_ENABLED = false;62private static boolean growAggressively = false;6364// Used to access compression related helper methods65private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();6667// Represents the bit in count field to test for whether this StringBuilder backing array is not compressed68// under String compression mode. This bit is not used when String compression is disabled.69private static final int uncompressedBit = 0x80000000;7071// Represents the bit in capacity field to test for whether this StringBuilder backing array is shared.72private static final int sharedBit = 0x80000000;7374private transient int count;75private transient char[] value;76private transient int capacity;7778private int decompress(int min) {79int currentLength = lengthInternal();80int currentCapacity = capacityInternal();81char[] newValue;8283if (min > currentCapacity) {84/* twice may be negative, in which case we'll use min */85int twice = (currentCapacity << 1) + 2;8687newValue = new char[min > twice ? min : twice];88} else {89newValue = new char[currentCapacity];90}9192String.decompress(value, 0, newValue, 0, currentLength);9394count = count | uncompressedBit;95value = newValue;96capacity = newValue.length;9798String.initCompressionFlag();99return capacity;100}101102/**103* Constructs a new StringBuffer using the default capacity.104*/105public StringBuilder() {106this(INITIAL_SIZE);107}108109/**110* Constructs a new StringBuilder using the specified capacity.111*112* @param capacity the initial capacity113*/114public StringBuilder(int capacity) {115/* capacity argument is used to determine the byte/char array size. If116* capacity argument is Integer.MIN_VALUE (-2147483648), then capacity *= 2117* will yield a non-negative number due to overflow. We will fail to throw118* NegativeArraySizeException. The check below will assure that119* NegativeArraySizeException is thrown if capacity argument is less than 0.120*/121if (capacity < 0) {122throw new NegativeArraySizeException(String.valueOf(capacity));123}124int arraySize = capacity;125126if (String.COMPACT_STRINGS) {127arraySize = (capacity + 1) >>> 1;128}129value = new char[arraySize];130131this.capacity = capacity;132}133134/**135* Constructs a new StringBuilder containing the characters in136* the specified string and the default capacity.137*138* @param string the initial contents of this StringBuilder139* @exception NullPointerException when string is null140*/141public StringBuilder (String string) {142int stringLength = string.lengthInternal();143144int newLength = stringLength + INITIAL_SIZE;145if (newLength < stringLength) {146newLength = stringLength;147}148149if (String.COMPACT_STRINGS) {150if (string.isCompressed ()) {151value = new char[(newLength + 1) >>> 1];152153capacity = newLength;154155string.getBytes(0, stringLength, value, 0);156157count = stringLength;158} else {159value = new char[newLength];160161string.getCharsNoBoundChecks(0, stringLength, value, 0);162163capacity = newLength;164165count = stringLength | uncompressedBit;166167String.initCompressionFlag();168}169} else {170value = new char[newLength];171172string.getCharsNoBoundChecks(0, stringLength, value, 0);173174capacity = newLength;175176count = stringLength;177}178}179180/**181* Adds the character array to the end of this StringBuilder.182*183* @param chars the character array184* @return this StringBuilder185*186* @exception NullPointerException when chars is null187*/188public StringBuilder append (char[] chars) {189int currentLength = lengthInternal();190int currentCapacity = capacityInternal();191192int newLength = currentLength + chars.length;193if (newLength < 0) {194/*[MSG "K0D01", "Array capacity exceeded"]*/195throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$196}197198if (String.COMPACT_STRINGS) {199// Check if the StringBuilder is compressed200if (count >= 0 && String.canEncodeAsLatin1(chars, 0, chars.length)) {201if (newLength > currentCapacity) {202ensureCapacityImpl(newLength);203}204205String.compress(chars, 0, value, currentLength, chars.length);206207count = newLength;208} else {209// Check if the StringBuilder is compressed210if (count >= 0) {211currentCapacity = decompress(newLength);212}213214if (newLength > currentCapacity) {215ensureCapacityImpl(newLength);216}217218String.decompressedArrayCopy(chars, 0, value, currentLength, chars.length);219220count = newLength | uncompressedBit;221}222} else {223if (newLength > currentCapacity) {224ensureCapacityImpl(newLength);225}226227String.decompressedArrayCopy(chars, 0, value, currentLength, chars.length);228229count = newLength;230}231232return this;233}234235/**236* Adds the specified sequence of characters to the end of237* this StringBuilder.238*239* @param chars a character array240* @param start the starting offset241* @param length the number of characters242* @return this StringBuilder243*244* @exception IndexOutOfBoundsException when {@code length < 0, start < 0} or245* {@code start + length > chars.length}246* @exception NullPointerException when chars is null247*/248public StringBuilder append (char chars[], int start, int length) {249if (start >= 0 && 0 <= length && length <= chars.length - start) {250int currentLength = lengthInternal();251int currentCapacity = capacityInternal();252253int newLength = currentLength + length;254if (newLength < 0) {255/*[MSG "K0D01", "Array capacity exceeded"]*/256throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$257}258259if (String.COMPACT_STRINGS) {260// Check if the StringBuilder is compressed261if (count >= 0 && String.canEncodeAsLatin1(chars, start, length)) {262if (newLength > currentCapacity) {263ensureCapacityImpl(newLength);264}265266String.compress(chars, start, value, currentLength, length);267268count = newLength;269} else {270// Check if the StringBuilder is compressed271if (count >= 0) {272currentCapacity = decompress(newLength);273}274275if (newLength > currentCapacity) {276ensureCapacityImpl(newLength);277}278279String.decompressedArrayCopy(chars, start, value, currentLength, length);280281count = newLength | uncompressedBit;282}283} else {284if (newLength > currentCapacity) {285ensureCapacityImpl(newLength);286}287288String.decompressedArrayCopy(chars, start, value, currentLength, length);289290count = newLength;291}292293return this;294} else {295throw new StringIndexOutOfBoundsException();296}297}298299StringBuilder append (char[] chars, int start, int length, boolean compressed) {300int currentLength = lengthInternal();301int currentCapacity = capacityInternal();302303int newLength = currentLength + length;304if (newLength < 0) {305/*[MSG "K0D01", "Array capacity exceeded"]*/306throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$307}308309if (String.COMPACT_STRINGS) {310// Check if the StringBuilder is compressed311if (count >= 0 && compressed) {312if (newLength > currentCapacity) {313ensureCapacityImpl(newLength);314}315316String.compressedArrayCopy(chars, start, value, currentLength, length);317318count = newLength;319} else {320// Check if the StringBuilder is compressed321if (count >= 0) {322currentCapacity = decompress(newLength);323}324325if (newLength > currentCapacity) {326ensureCapacityImpl(newLength);327}328329if (compressed) {330String.decompress(chars, start, value, currentLength, length);331} else {332String.decompressedArrayCopy(chars, start, value, currentLength, length);333}334335count = newLength | uncompressedBit;336}337} else {338if (newLength > currentCapacity) {339ensureCapacityImpl(newLength);340}341342if (compressed) {343String.decompress(chars, start, value, currentLength, length);344} else {345String.decompressedArrayCopy(chars, start, value, currentLength, length);346}347348count = newLength;349}350351return this;352}353354/**355* Adds the specified character to the end of356* this StringBuilder.357*358* @param ch a character359* @return this StringBuilder360*/361@Override362public StringBuilder append(char ch) {363int currentLength = lengthInternal();364int currentCapacity = capacityInternal();365366int newLength = currentLength + 1;367if (newLength < 0) {368/*[MSG "K0D01", "Array capacity exceeded"]*/369throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$370}371372if (String.COMPACT_STRINGS) {373// Check if the StringBuilder is compressed374if (count >= 0 && ch <= 255) {375if (newLength > currentCapacity) {376ensureCapacityImpl(newLength);377}378379helpers.putByteInArrayByIndex(value, currentLength, (byte) ch);380381count = newLength;382} else {383// Check if the StringBuilder is compressed384if (count >= 0) {385currentCapacity = decompress(newLength);386}387388if (newLength > currentCapacity) {389ensureCapacityImpl(newLength);390}391392value[currentLength] = ch;393394count = newLength | uncompressedBit;395}396} else {397if (newLength > currentCapacity) {398ensureCapacityImpl(newLength);399}400401value[currentLength] = ch;402403count = newLength;404}405406return this;407}408409/**410* Adds the string representation of the specified double to the411* end of this StringBuilder.412*413* @param value the double414* @return this StringBuilder415*/416public StringBuilder append (double value) {417return append (String.valueOf (value));418}419420/**421* Adds the string representation of the specified float to the422* end of this StringBuilder.423*424* @param value the float425* @return this StringBuilder426*/427public StringBuilder append (float value) {428return append (String.valueOf (value));429}430431/**432* Adds the string representation of the specified integer to the433* end of this StringBuilder.434*435* @param value the integer436* @return this StringBuilder437*/438public StringBuilder append(int value) {439if (value != Integer.MIN_VALUE) {440if (String.COMPACT_STRINGS && count >= 0) {441return append(Integer.toString(value));442} else {443int currentLength = lengthInternal();444int currentCapacity = capacityInternal();445446int valueLength;447if (value < 0) {448/* stringSize can't handle negative numbers in Java 8 */449valueLength = Integer.stringSize(-value) + 1;450} else {451valueLength = Integer.stringSize(value);452}453454int newLength = currentLength + valueLength;455if (newLength < 0) {456/*[MSG "K0D01", "Array capacity exceeded"]*/457throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$458}459460if (newLength > currentCapacity) {461ensureCapacityImpl(newLength);462}463464Integer.getChars(value, newLength, this.value);465466if (String.COMPACT_STRINGS) {467count = newLength | uncompressedBit;468} else {469count = newLength;470}471472return this;473}474} else {475// Append Integer.MIN_VALUE as a String476return append("-2147483648"); //$NON-NLS-1$477}478}479480/**481* Adds the string representation of the specified long to the482* end of this StringBuilder.483*484* @param value the long485* @return this StringBuilder486*/487public StringBuilder append(long value) {488if (value != Long.MIN_VALUE) {489if (String.COMPACT_STRINGS && count >= 0) {490return append(Long.toString(value));491} else {492int currentLength = lengthInternal();493int currentCapacity = capacityInternal();494495int valueLength;496if (value < 0) {497/* stringSize can't handle negative numbers in Java 8 */498valueLength = Long.stringSize(-value) + 1;499} else {500valueLength = Long.stringSize(value);501}502503int newLength = currentLength + valueLength;504if (newLength < 0) {505/*[MSG "K0D01", "Array capacity exceeded"]*/506throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$507}508509if (newLength > currentCapacity) {510ensureCapacityImpl(newLength);511}512513Long.getChars(value, newLength, this.value);514515if (String.COMPACT_STRINGS) {516count = newLength | uncompressedBit;517} else {518count = newLength;519}520521return this;522}523} else {524// Append Long.MIN_VALUE as a String525return append("-9223372036854775808"); //$NON-NLS-1$526}527}528529/**530* Adds the string representation of the specified object to the531* end of this StringBuilder.532*533* @param value the object534* @return this StringBuilder535*/536public StringBuilder append (Object value) {537return append (String.valueOf (value));538}539540/**541* Adds the specified string to the end of this StringBuilder.542*543* @param string the string544* @return this StringBuilder545*/546public StringBuilder append (String string) {547if (string == null) {548string = "null"; //$NON-NLS-1$549}550551int currentLength = lengthInternal();552int currentCapacity = capacityInternal();553554int stringLength = string.lengthInternal();555556int newLength = currentLength + stringLength;557if (newLength < 0) {558/*[MSG "K0D01", "Array capacity exceeded"]*/559throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$560}561562if (String.COMPACT_STRINGS) {563// Check if the StringBuilder is compressed564if (count >= 0 && string.isCompressed ()) {565if (newLength > currentCapacity) {566ensureCapacityImpl(newLength);567}568569string.getBytes(0, stringLength, value, currentLength);570571count = newLength;572} else {573// Check if the StringBuilder is compressed574if (count >= 0) {575currentCapacity = decompress(newLength);576}577578if (newLength > currentCapacity) {579ensureCapacityImpl(newLength);580}581582string.getCharsNoBoundChecks(0, stringLength, value, currentLength);583584count = newLength | uncompressedBit;585}586} else {587if (newLength > currentCapacity) {588ensureCapacityImpl(newLength);589}590591string.getCharsNoBoundChecks(0, stringLength, value, currentLength);592593count = newLength;594}595596return this;597}598599/**600* Adds the string representation of the specified boolean to the601* end of this StringBuilder.602*603* @param value the boolean604* @return this StringBuilder605*/606public StringBuilder append (boolean value) {607return append (String.valueOf (value));608}609610/**611* Answers the number of characters this StringBuilder can hold without612* growing.613*614* @return the capacity of this StringBuilder615*616* @see #ensureCapacity617* @see #length618*/619public int capacity() {620return capacityInternal();621}622623/**624* Answers the number of characters this StringBuilder can hold without growing. This method is to be used internally625* within the current package whenever possible as the JIT compiler will take special precaution to avoid generating626* HCR guards for calls to this method.627*628* @return the capacity of this StringBuilder629*630* @see #ensureCapacity631* @see #length632*/633int capacityInternal() {634return capacity & ~sharedBit;635}636637/**638* Answers the character at the specified offset in this StringBuilder.639*640* @param index the zero-based index in this StringBuilder641* @return the character at the index642*643* @exception IndexOutOfBoundsException when {@code index < 0} or644* {@code index >= length()}645*/646@Override647public char charAt(int index) {648int currentLength = lengthInternal();649650if (index >= 0 && index < currentLength) {651// Check if the StringBuilder is compressed652if (String.COMPACT_STRINGS && count >= 0) {653return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));654} else {655return value[index];656}657}658659throw new StringIndexOutOfBoundsException(index);660}661662/**663* Deletes a range of characters.664*665* @param start the offset of the first character666* @param end the offset one past the last character667* @return this StringBuilder668*669* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or670* {@code end > length()}671*/672public StringBuilder delete(int start, int end) {673int currentLength = lengthInternal();674675if (start >= 0) {676if (end > currentLength) {677end = currentLength;678}679680if (end > start) {681int numberOfTailChars = currentLength - end;682683try {684// Check if the StringBuilder is not shared685if (capacity >= 0) {686if (numberOfTailChars > 0) {687// Check if the StringBuilder is compressed688if (String.COMPACT_STRINGS && count >= 0) {689String.compressedArrayCopy(value, end, value, start, numberOfTailChars);690} else {691String.decompressedArrayCopy(value, end, value, start, numberOfTailChars);692}693}694} else {695char[] newData = new char[value.length];696697// Check if the StringBuilder is compressed698if (String.COMPACT_STRINGS && count >= 0) {699if (start > 0) {700String.compressedArrayCopy(value, 0, newData, 0, start);701}702703if (numberOfTailChars > 0) {704String.compressedArrayCopy(value, end, newData, start, numberOfTailChars);705}706} else {707if (start > 0) {708String.decompressedArrayCopy(value, 0, newData, 0, start);709}710711if (numberOfTailChars > 0) {712String.decompressedArrayCopy(value, end, newData, start, numberOfTailChars);713}714}715716value = newData;717718capacity = capacity & ~sharedBit;719}720} catch (IndexOutOfBoundsException e) {721throw new StringIndexOutOfBoundsException();722}723724if (String.COMPACT_STRINGS) {725// Check if the StringBuilder is compressed726if (count >= 0) {727count = currentLength - (end - start);728} else {729count = (currentLength - (end - start)) | uncompressedBit;730731String.initCompressionFlag();732}733} else {734count = currentLength - (end - start);735}736737return this;738}739740if (start == end) {741return this;742}743}744745throw new StringIndexOutOfBoundsException();746}747748/**749* Deletes a single character750*751* @param location the offset of the character to delete752* @return this StringBuilder753*754* @exception StringIndexOutOfBoundsException when {@code location < 0} or755* {@code location >= length()}756*/757public StringBuilder deleteCharAt(int location) {758int currentLength = lengthInternal();759760if (currentLength != 0) {761return delete (location, location + 1);762} else {763throw new StringIndexOutOfBoundsException ();764}765}766767/**768* Ensures that this StringBuilder can hold the specified number of characters769* without growing.770*771* @param min the minimum number of elements that this772* StringBuilder will hold before growing773*/774public void ensureCapacity(int min) {775int currentCapacity = capacityInternal();776777if (min > currentCapacity) {778ensureCapacityImpl(min);779}780}781782private void ensureCapacityImpl(int min) {783int currentLength = lengthInternal();784int currentCapacity = capacityInternal();785786int newCapacity = (currentCapacity << 1) + 2;787788if (growAggressively && (newCapacity < currentCapacity)) {789newCapacity = Integer.MAX_VALUE;790}791792int newLength = min > newCapacity ? min : newCapacity;793794// Check if the StringBuilder is compressed795if (String.COMPACT_STRINGS && count >= 0) {796char[] newData = new char[(newLength + 1) >>> 1];797798String.compressedArrayCopy(value, 0, newData, 0, currentLength);799800value = newData;801} else {802char[] newData = new char[newLength];803804String.decompressedArrayCopy(value, 0, newData, 0, currentLength);805value = newData;806}807808capacity = newLength;809}810811/**812* Copies the specified characters in this StringBuilder to the character array813* starting at the specified offset in the character array.814*815* @param start the starting offset of characters to copy816* @param end the ending offset of characters to copy817* @param buffer the destination character array818* @param index the starting offset in the character array819*820* @exception IndexOutOfBoundsException when {@code start < 0, end > length(),821* start > end, index < 0, end - start > buffer.length - index}822* @exception NullPointerException when buffer is null823*/824public void getChars(int start, int end, char[] buffer, int index) {825try {826int currentLength = lengthInternal();827828if (start <= currentLength && end <= currentLength) {829// Note that we must explicitly check all the conditions because we are not using System.arraycopy which would830// have implicitly checked these conditions831if (start >= 0 && start <= end && index >= 0 && end - start <= buffer.length - index) {832// Check if the StringBuilder is compressed833if (String.COMPACT_STRINGS && count >= 0) {834String.decompress(value, start, buffer, index, end - start);835836return;837} else {838System.arraycopy(value, start, buffer, index, end - start);839840return;841}842}843}844} catch(IndexOutOfBoundsException e) {845// Void846}847848throw new StringIndexOutOfBoundsException ();849}850851/**852* Inserts the character array at the specified offset in this StringBuilder.853*854* @param index the index at which to insert855* @param chars the character array to insert856* @return this StringBuilder857*858* @exception StringIndexOutOfBoundsException when {@code index < 0} or859* {@code index > length()}860* @exception NullPointerException when chars is null861*/862public StringBuilder insert(int index, char[] chars) {863int currentLength = lengthInternal();864865if (0 <= index && index <= currentLength) {866move(chars.length, index);867868if (String.COMPACT_STRINGS) {869// Check if the StringBuilder is compressed870if (count >= 0 && String.canEncodeAsLatin1(chars, 0, chars.length)) {871String.compress(chars, 0, value, index, chars.length);872873count = currentLength + chars.length;874875return this;876} else {877// Check if the StringBuilder is compressed878if (count >= 0) {879decompress(value.length);880}881882String.decompressedArrayCopy(chars, 0, value, index, chars.length);883884count = (currentLength + chars.length) | uncompressedBit;885886return this;887}888} else {889String.decompressedArrayCopy(chars, 0, value, index, chars.length);890891count = currentLength + chars.length;892893return this;894}895} else {896throw new StringIndexOutOfBoundsException(index);897}898}899900/**901* Inserts the specified sequence of characters at the902* specified offset in this StringBuilder.903*904* @param index the index at which to insert905* @param chars a character array906* @param start the starting offset907* @param length the number of characters908* @return this StringBuilder909*910* @exception StringIndexOutOfBoundsException when {@code length < 0, start < 0,911* start + length > chars.length, index < 0} or912* {@code index > length()}913* @exception NullPointerException when chars is null914*/915public StringBuilder insert(int index, char[] chars, int start, int length) {916int currentLength = lengthInternal();917918if (0 <= index && index <= currentLength) {919if (start >= 0 && 0 <= length && length <= chars.length - start) {920move(length, index);921922if (String.COMPACT_STRINGS) {923// Check if the StringBuilder is compressed924if (count >= 0 && String.canEncodeAsLatin1(chars, start, length)) {925String.compress(chars, start, value, index, length);926927count = currentLength + length;928929return this;930} else {931// Check if the StringBuilder is compressed932if (count >= 0) {933decompress(value.length);934}935936String.decompressedArrayCopy(chars, start, value, index, length);937938count = (currentLength + length) | uncompressedBit;939940return this;941}942} else {943String.decompressedArrayCopy(chars, start, value, index, length);944945count = currentLength + length;946947return this;948}949} else {950throw new StringIndexOutOfBoundsException();951}952} else {953throw new StringIndexOutOfBoundsException(index);954}955}956957StringBuilder insert(int index, char[] chars, int start, int length, boolean compressed) {958int currentLength = lengthInternal();959960move(length, index);961962if (String.COMPACT_STRINGS) {963// Check if the StringBuilder is compressed964if (count >= 0 && compressed) {965String.compressedArrayCopy(chars, start, value, index, length);966967count = currentLength + length;968969return this;970} else {971if (count >= 0) {972decompress(value.length);973}974975String.decompressedArrayCopy(chars, start, value, index, length);976977count = (currentLength + length) | uncompressedBit;978979return this;980}981} else {982String.decompressedArrayCopy(chars, start, value, index, length);983984count = currentLength + length;985986return this;987}988}989990/**991* Inserts the character at the specified offset in this StringBuilder.992*993* @param index the index at which to insert994* @param ch the character to insert995* @return this StringBuilder996*997* @exception IndexOutOfBoundsException when {@code index < 0} or998* {@code index > length()}999*/1000public StringBuilder insert(int index, char ch) {1001int currentLength = lengthInternal();10021003if (0 <= index && index <= currentLength) {1004move(1, index);10051006if (String.COMPACT_STRINGS ) {1007// Check if the StringBuilder is compressed1008if (count >= 0 && ch <= 255) {1009helpers.putByteInArrayByIndex(value, index, (byte) ch);10101011count = currentLength + 1;10121013return this;1014} else {1015// Check if the StringBuilder is compressed1016if (count >= 0) {1017decompress(value.length);1018}10191020value[index] = ch;10211022count = (currentLength + 1) | uncompressedBit;10231024return this;1025}1026} else {1027value[index] = ch;10281029count = currentLength + 1;10301031return this;1032}1033} else {1034throw new StringIndexOutOfBoundsException(index);1035}1036}10371038/**1039* Inserts the string representation of the specified double at the specified1040* offset in this StringBuilder.1041*1042* @param index the index at which to insert1043* @param value the double to insert1044* @return this StringBuilder1045*1046* @exception StringIndexOutOfBoundsException when {@code index < 0} or1047* {@code index > length()}1048*/1049public StringBuilder insert(int index, double value) {1050return insert(index, String.valueOf(value));1051}10521053/**1054* Inserts the string representation of the specified float at the specified1055* offset in this StringBuilder.1056*1057* @param index the index at which to insert1058* @param value the float to insert1059* @return this StringBuilder1060*1061* @exception StringIndexOutOfBoundsException when {@code index < 0} or1062* {@code index > length()}1063*/1064public StringBuilder insert(int index, float value) {1065return insert(index, String.valueOf(value));1066}10671068/**1069* Inserts the string representation of the specified integer at the specified1070* offset in this StringBuilder.1071*1072* @param index the index at which to insert1073* @param value the integer to insert1074* @return this StringBuilder1075*1076* @exception StringIndexOutOfBoundsException when {@code index < 0} or1077* {@code index > length()}1078*/1079public StringBuilder insert(int index, int value) {1080return insert(index, Integer.toString(value));1081}10821083/**1084* Inserts the string representation of the specified long at the specified1085* offset in this StringBuilder.1086*1087* @param index the index at which to insert1088* @param value the long to insert1089* @return this StringBuilder1090*1091* @exception StringIndexOutOfBoundsException when {@code index < 0} or1092* {@code index > length()}1093*/1094public StringBuilder insert(int index, long value) {1095return insert(index, Long.toString(value));1096}10971098/**1099* Inserts the string representation of the specified object at the specified1100* offset in this StringBuilder.1101*1102* @param index the index at which to insert1103* @param value the object to insert1104* @return this StringBuilder1105*1106* @exception StringIndexOutOfBoundsException when {@code index < 0} or1107* {@code index > length()}1108*/1109public StringBuilder insert(int index, Object value) {1110return insert(index, String.valueOf(value));1111}11121113/**1114* Inserts the string at the specified offset in this StringBuilder.1115*1116* @param index the index at which to insert1117* @param string the string to insert1118* @return this StringBuilder1119*1120* @exception StringIndexOutOfBoundsException when {@code index < 0} or1121* {@code index > length()}1122*/1123public StringBuilder insert(int index, String string) {1124int currentLength = lengthInternal();11251126if (0 <= index && index <= currentLength) {1127if (string == null) {1128string = "null"; //$NON-NLS-1$1129}11301131int stringLength = string.lengthInternal();11321133move(stringLength, index);11341135if (String.COMPACT_STRINGS) {1136// Check if the StringBuilder is compressed1137if (count >= 0 && string.isCompressed()) {1138string.getBytes(0, stringLength, value, index);11391140count = currentLength + stringLength;11411142return this;1143} else {1144// Check if the StringBuilder is compressed1145if (count >= 0) {1146decompress(value.length);1147}11481149string.getCharsNoBoundChecks(0, stringLength, value, index);11501151count = (currentLength + stringLength) | uncompressedBit;11521153return this;1154}1155} else {1156string.getCharsNoBoundChecks(0, stringLength, value, index);11571158count = currentLength + stringLength;11591160return this;1161}1162} else {1163throw new StringIndexOutOfBoundsException(index);1164}1165}11661167/**1168* Inserts the string representation of the specified boolean at the specified1169* offset in this StringBuilder.1170*1171* @param index the index at which to insert1172* @param value the boolean to insert1173* @return this StringBuilder1174*1175* @exception StringIndexOutOfBoundsException when {@code index < 0} or1176* {@code index > length()}1177*/1178public StringBuilder insert(int index, boolean value) {1179return insert(index, String.valueOf(value));1180}11811182/**1183* Answers the size of this StringBuilder.1184*1185* @return the number of characters in this StringBuilder1186*/1187@Override1188public int length() {1189return lengthInternal();1190}11911192/**1193* Answers the size of this StringBuilder. This method is to be used internally within the current package whenever1194* possible as the JIT compiler will take special precaution to avoid generating HCR guards for calls to this1195* method.1196*1197* @return the number of characters in this StringBuilder1198*/1199int lengthInternal() {1200if (String.COMPACT_STRINGS) {1201// Check if the StringBuilder is compressed1202if (count >= 0) {1203return count;1204} else {1205return count & ~uncompressedBit;1206}1207} else {1208return count;1209}1210}12111212private void move(int size, int index) {1213int currentLength = lengthInternal();1214int currentCapacity = capacityInternal();12151216// Check if the StringBuilder is compressed1217if (String.COMPACT_STRINGS && count >= 0) {1218int newLength;12191220if (currentCapacity - currentLength >= size) {1221// Check if the StringBuilder is not shared1222if (capacity >= 0) {1223String.compressedArrayCopy(value, index, value, index + size, currentLength - index);12241225return;1226}12271228newLength = currentCapacity;1229} else {1230newLength = Integer.max(currentLength + size, (currentCapacity << 1) + 2);1231if (newLength < 0) {1232/*[MSG "K0D01", "Array capacity exceeded"]*/1233throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1234}1235}12361237char[] newData = new char[(newLength + 1) >>> 1];12381239String.compressedArrayCopy(value, 0, newData, 0, index);1240String.compressedArrayCopy(value, index, newData, index + size, currentLength - index);12411242value = newData;12431244capacity = newLength;1245} else {1246int newLength;12471248if (currentCapacity - currentLength >= size) {1249// Check if the StringBuilder is not shared1250if (capacity >= 0) {1251String.decompressedArrayCopy(value, index, value, index + size, currentLength - index);12521253return;1254}12551256newLength = currentCapacity;1257} else {1258newLength = Integer.max(currentLength + size, (currentCapacity << 1) + 2);1259if (newLength < 0) {1260/*[MSG "K0D01", "Array capacity exceeded"]*/1261throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1262}1263}12641265char[] newData = new char[newLength];12661267String.decompressedArrayCopy(value, 0, newData, 0, index);1268String.decompressedArrayCopy(value, index, newData, index + size, currentLength - index);12691270value = newData;12711272capacity = newLength;1273}1274}12751276/**1277* Replace a range of characters with the characters in the specified String.1278*1279* @param start the offset of the first character1280* @param end the offset one past the last character1281* @param string a String1282* @return this StringBuilder1283*1284* @exception StringIndexOutOfBoundsException when {@code start < 0} or1285* {@code start > end}1286*/1287public StringBuilder replace(int start, int end, String string) {1288int currentLength = lengthInternal();12891290if (String.COMPACT_STRINGS) {1291// Check if the StringBuilder is compressed1292if (count >= 0 && string.isCompressed()) {1293if (start >= 0) {1294if (end > currentLength) {1295end = currentLength;1296}12971298if (end > start) {1299int size = string.lengthInternal();13001301// Difference between the substring we wish to replace and the size of the string parameter1302int difference = end - start - size;13031304if (difference > 0) {1305// Check if the StringBuilder is not shared1306if (capacity >= 0) {1307String.compressedArrayCopy(value, end, value, start + size, currentLength - end);1308} else {1309char[] newData = new char[value.length];13101311String.compressedArrayCopy(value, 0, newData, 0, start);1312String.compressedArrayCopy(value, end, newData, start + size, currentLength - end);13131314value = newData;13151316capacity = capacity & ~sharedBit;1317}1318} else if (difference < 0) {1319move(-difference, end);1320} else if (capacity < 0) {1321value = value.clone();13221323capacity = capacity & ~sharedBit;1324}13251326string.getBytes(0, size, value, start);13271328count = currentLength - difference;13291330return this;1331}13321333if (start == end) {1334return insert(start, string);1335}1336}1337} else {1338// Check if the StringBuilder is compressed1339if (count >= 0) {1340decompress(value.length);1341}13421343if (start >= 0) {1344if (end > currentLength) {1345end = currentLength;1346}13471348if (end > start) {1349int size = string.lengthInternal();13501351// Difference between the substring we wish to replace and the size of the string parameter1352int difference = end - start - size;13531354if (difference > 0) {1355// Check if the StringBuilder is not shared1356if (capacity >= 0) {1357String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);1358} else {1359char[] newData = new char[value.length];13601361String.decompressedArrayCopy(value, 0, newData, 0, start);1362String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);13631364value = newData;13651366capacity = capacity & ~sharedBit;1367}1368} else if (difference < 0) {1369move(-difference, end);1370} else if (capacity < 0) {1371value = value.clone();13721373capacity = capacity & ~sharedBit;1374}13751376string.getCharsNoBoundChecks(0, size, value, start);13771378count = (currentLength - difference) | uncompressedBit;13791380return this;1381}13821383if (start == end) {1384string.getClass(); // Implicit null check13851386return insert(start, string);1387}1388}1389}1390} else {1391if (start >= 0) {1392if (end > currentLength) {1393end = currentLength;1394}13951396if (end > start) {1397int size = string.lengthInternal();13981399// Difference between the substring we wish to replace and the size of the string parameter1400int difference = end - start - size;14011402if (difference > 0) {1403// Check if the StringBuilder is not shared1404if (capacity >= 0) {1405String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);1406} else {1407char[] newData = new char[value.length];14081409String.decompressedArrayCopy(value, 0, newData, 0, start);1410String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);14111412value = newData;14131414capacity = capacity & ~sharedBit;1415}1416} else if (difference < 0) {1417move(-difference, end);1418} else if (capacity < 0) {1419value = value.clone();14201421capacity = capacity & ~sharedBit;1422}14231424string.getCharsNoBoundChecks(0, size, value, start);14251426count = currentLength - difference;14271428return this;1429}14301431if (start == end) {1432string.getClass(); // Implicit null check14331434return insert(start, string);1435}1436}1437}14381439throw new StringIndexOutOfBoundsException();1440}14411442/**1443* Reverses the order of characters in this StringBuilder.1444*1445* @return this StringBuilder1446*/1447public StringBuilder reverse() {1448int currentLength = lengthInternal();14491450if (currentLength < 2) {1451return this;1452}14531454// Check if the StringBuilder is compressed1455if (String.COMPACT_STRINGS && count >= 0) {1456// Check if the StringBuilder is not shared1457if (capacity >= 0) {1458for (int i = 0, mid = currentLength / 2, j = currentLength - 1; i < mid; ++i, --j) {1459byte a = helpers.getByteFromArrayByIndex(value, i);1460byte b = helpers.getByteFromArrayByIndex(value, j);14611462helpers.putByteInArrayByIndex(value, i, b);1463helpers.putByteInArrayByIndex(value, j, a);1464}14651466return this;1467} else {1468char[] newData = new char[value.length];14691470for (int i = 0, j = currentLength - 1; i < currentLength; ++i, --j) {1471helpers.putByteInArrayByIndex(newData, j, helpers.getByteFromArrayByIndex(value, i));1472}14731474value = newData;14751476capacity = capacity & ~sharedBit;14771478return this;1479}1480} else {1481// Check if the StringBuilder is not shared1482if (capacity >= 0) {1483int end = currentLength - 1;14841485char frontHigh = value[0];1486char endLow = value[end];1487boolean allowFrontSur = true, allowEndSur = true;1488for (int i = 0, mid = currentLength / 2; i < mid; i++, --end) {1489char frontLow = value[i + 1];1490char endHigh = value[end - 1];1491boolean surAtFront = false, surAtEnd = false;1492if (allowFrontSur && frontLow >= Character.MIN_LOW_SURROGATE && frontLow <= Character.MAX_LOW_SURROGATE && frontHigh >= Character.MIN_HIGH_SURROGATE && frontHigh <= Character.MAX_HIGH_SURROGATE) {1493surAtFront = true;1494if (currentLength < 3) return this;1495}1496if (allowEndSur && endHigh >= Character.MIN_HIGH_SURROGATE && endHigh <= Character.MAX_HIGH_SURROGATE && endLow >= Character.MIN_LOW_SURROGATE && endLow <= Character.MAX_LOW_SURROGATE) {1497surAtEnd = true;1498}1499allowFrontSur = true;1500allowEndSur = true;1501if (surAtFront == surAtEnd) {1502if (surAtFront) {1503// both surrogates1504value[end] = frontLow;1505value[end - 1] = frontHigh;1506value[i] = endHigh;1507value[i + 1] = endLow;1508frontHigh = value[i + 2];1509endLow = value[end - 2];1510i++;1511--end;1512} else {1513// neither surrogates1514value[end] = frontHigh;1515value[i] = endLow;1516frontHigh = frontLow;1517endLow = endHigh;1518}1519} else {1520if (surAtFront) {1521// surrogate only at the front1522value[end] = frontLow;1523value[i] = endLow;1524endLow = endHigh;1525allowFrontSur = false;1526} else {1527// surrogate only at the end1528value[end] = frontHigh;1529value[i] = endHigh;1530frontHigh = frontLow;1531allowEndSur = false;1532}1533}1534}1535if ((currentLength & 1) == 1 && (!allowFrontSur || !allowEndSur)) {1536value[end] = allowFrontSur ? endLow : frontHigh;1537}1538} else {1539char[] newData = new char[value.length];15401541for (int i = 0, end = currentLength; i < currentLength; i++) {1542char high = value[i];15431544if ((i + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {1545char low = value[i + 1];15461547if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {1548newData[--end] = low;1549i++;1550}1551}1552newData[--end] = high;1553}15541555value = newData;15561557capacity = capacity & ~sharedBit;1558}15591560return this;1561}1562}15631564/**1565* Sets the character at the specified offset in this StringBuilder.1566*1567* @param index the zero-based index in this StringBuilder1568* @param ch the character1569*1570* @exception IndexOutOfBoundsException when {@code index < 0} or1571* {@code index >= length()}1572*/1573public void setCharAt(int index, char ch) {1574int currentLength = lengthInternal();15751576if (0 <= index && index < currentLength) {1577if (String.COMPACT_STRINGS) {1578// Check if the StringBuilder is compressed1579if (count >= 0 && ch <= 255) {1580if (capacity < 0) {1581value = value.clone();15821583capacity = capacity & ~sharedBit;1584}15851586helpers.putByteInArrayByIndex(value, index, (byte) ch);1587} else {1588// Check if the StringBuilder is compressed1589if (count >= 0) {1590decompress(value.length);1591}15921593if (capacity < 0) {1594value = value.clone();15951596capacity = capacity & ~sharedBit;1597}15981599value[index] = ch;1600}1601} else {1602if (capacity < 0) {1603value = value.clone();16041605capacity = capacity & ~sharedBit;1606}16071608value[index] = ch;1609}1610} else {1611throw new StringIndexOutOfBoundsException(index);1612}1613}16141615/**1616* Sets the length of this StringBuilder to the specified length. If there1617* are more than length characters in this StringBuilder, the characters1618* at end are lost. If there are less than length characters in the1619* StringBuilder, the additional characters are set to {@code \\u0000}.1620*1621* @param length the new length of this StringBuilder1622*1623* @exception IndexOutOfBoundsException when {@code length < 0}1624*1625* @see #length1626*/1627public void setLength(int length) {1628int currentLength = lengthInternal();1629int currentCapacity = capacityInternal();16301631// Check if the StringBuilder is compressed1632if (String.COMPACT_STRINGS && count >= 0) {1633if (length > currentCapacity) {1634ensureCapacityImpl(length);1635} else if (length > currentLength) {1636for (int i = currentLength; i < length; ++i) {1637helpers.putByteInArrayByIndex(value, i, (byte) 0);1638}1639} else if (capacity < 0) {1640if (length < 0) {1641throw new IndexOutOfBoundsException();1642}16431644char[] newData = new char[value.length];16451646if (length > 0) {1647String.compressedArrayCopy(value, 0, newData, 0, length);1648}16491650value = newData;16511652capacity = capacity & ~sharedBit;1653} else if (length < 0) {1654throw new IndexOutOfBoundsException();1655}1656} else {1657if (length > currentCapacity) {1658ensureCapacityImpl(length);1659} else if (length > currentLength) {1660Arrays.fill(value, currentLength, length, (char) 0);1661} else if (capacity < 0) {1662if (length < 0) {1663throw new IndexOutOfBoundsException();1664}16651666char[] newData = new char[value.length];16671668if (length > 0) {1669String.decompressedArrayCopy(value, 0, newData, 0, length);1670}16711672value = newData;16731674capacity = capacity & ~sharedBit;1675} else if (length < 0) {1676throw new IndexOutOfBoundsException();1677}1678}16791680if (String.COMPACT_STRINGS) {1681// Check if the StringBuilder is compressed1682if (count >= 0) {1683count = length;1684} else {1685count = length | uncompressedBit;1686}1687} else {1688count = length;1689}1690}16911692/**1693* Copies a range of characters into a new String.1694*1695* @param start the offset of the first character1696* @return a new String containing the characters from start to the end1697* of the string1698*1699* @exception StringIndexOutOfBoundsException when {@code start < 0} or1700* {@code start > length()}1701*/1702public String substring(int start) {1703int currentLength = lengthInternal();17041705// Check if the StringBuilder is compressed1706if (String.COMPACT_STRINGS && count >= 0) {1707if (0 <= start && start <= currentLength) {1708return new String(value, start, currentLength - start, true, false);1709}1710} else {1711if (0 <= start && start <= currentLength) {1712return new String(value, start, currentLength - start, false, false);1713}1714}17151716throw new StringIndexOutOfBoundsException(start);1717}17181719/**1720* Copies a range of characters into a new String.1721*1722* @param start the offset of the first character1723* @param end the offset one past the last character1724* @return a new String containing the characters from start to end - 11725*1726* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or1727* {@code end > length()}1728*/1729public String substring(int start, int end) {1730int currentLength = lengthInternal();17311732// Check if the StringBuilder is compressed1733if (String.COMPACT_STRINGS && count >= 0) {1734if (0 <= start && start <= end && end <= currentLength) {1735return new String(value, start, end - start, true, false);1736}1737} else {1738if (0 <= start && start <= end && end <= currentLength) {1739return new String(value, start, end - start, false, false);1740}1741}17421743throw new StringIndexOutOfBoundsException();1744}17451746static void initFromSystemProperties(Properties props) {1747String prop = props.getProperty("java.lang.string.create.unique"); //$NON-NLS-1$1748TOSTRING_COPY_BUFFER_ENABLED = "true".equals(prop) || "StringBuilder".equals(prop); //$NON-NLS-1$ //$NON-NLS-2$17491750// growAggressively by default1751String growAggressivelyProperty = props.getProperty("java.lang.stringBuffer.growAggressively", ""); //$NON-NLS-1$ //$NON-NLS-2$1752growAggressively = "".equals(growAggressivelyProperty) || Boolean.parseBoolean(growAggressivelyProperty); //$NON-NLS-1$1753}17541755/**1756* Answers the contents of this StringBuilder.1757*1758* @return a String containing the characters in this StringBuilder1759*/1760@Override1761public String toString () {1762int currentLength = lengthInternal();1763int currentCapacity = capacityInternal();17641765if (false == TOSTRING_COPY_BUFFER_ENABLED) {1766int wasted = currentCapacity - currentLength;1767if (wasted >= 768 || (wasted >= INITIAL_SIZE && wasted >= (currentCapacity >> 1))) {1768// Check if the StringBuffer is compressed1769if (String.COMPACT_STRINGS && count >= 0) {1770return new String (value, 0, currentLength, true, false);1771} else {1772return new String (value, 0, currentLength, false, false);1773}1774}1775} else {1776// Do not copy the char[] if it will not get smaller because of object alignment1777int roundedCount = (currentLength + 3) & ~3;1778if (roundedCount < currentCapacity) {1779// Check if the StringBuffer is compressed1780if (String.COMPACT_STRINGS && count >= 0) {1781return new String (value, 0, currentLength, true, false);1782} else {1783return new String (value, 0, currentLength, false, false);1784}1785}1786}17871788capacity = capacity | sharedBit;17891790// Check if the StringBuffer is compressed1791if (String.COMPACT_STRINGS && count >= 0) {1792return new String (value, 0, currentLength, true);1793} else {1794return new String (value, 0, currentLength, false);1795}1796}17971798private void writeObject(ObjectOutputStream stream) throws IOException {1799int currentLength = lengthInternal();18001801stream.defaultWriteObject();1802stream.writeInt(currentLength);18031804// Check if the StringBuilder is compressed1805if (String.COMPACT_STRINGS && count >= 0) {1806char[] newData = new char[currentLength];18071808String.decompress(value, 0, newData, 0, currentLength);18091810stream.writeObject(newData);1811} else {1812stream.writeObject(value);1813}1814}18151816private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {1817stream.defaultReadObject();1818int streamCount = stream.readInt();1819char[] streamValue = (char[])stream.readObject();18201821if ((streamCount < 0) || (streamCount > streamValue.length)) {1822/*[MSG "K0199", "count value invalid"]*/1823throw new StreamCorruptedException(com.ibm.oti.util.Msg.getString("K0199")); //$NON-NLS-1$1824}1825if (String.COMPACT_STRINGS) {1826if (String.canEncodeAsLatin1(streamValue, 0, streamValue.length)) {1827value = new char[(streamValue.length + 1) >>> 1];1828String.compress(streamValue, 0, value, 0, streamValue.length);1829count = streamCount;1830capacity = streamValue.length;1831} else {1832value = new char[streamValue.length];1833System.arraycopy(streamValue, 0, value, 0, streamValue.length);1834count = streamCount | uncompressedBit;1835capacity = streamValue.length;1836String.initCompressionFlag();1837}1838} else {1839value = new char[streamValue.length];1840System.arraycopy(streamValue, 0, value, 0, streamValue.length);1841count = streamCount;1842capacity = streamValue.length;1843}1844}18451846/**1847* Adds the specified StringBuffer to the end of this StringBuilder.1848*1849* @param buffer the StringBuffer1850* @return this StringBuilder1851*/1852public StringBuilder append(StringBuffer buffer) {1853if (buffer == null) {1854return append((String)null);1855}18561857synchronized (buffer) {1858if (String.COMPACT_STRINGS && buffer.isCompressed()) {1859return append(buffer.getValue(), 0, buffer.length(), true);1860} else {1861return append(buffer.getValue(), 0, buffer.length(), false);1862}1863}1864}18651866/**1867* Copies a range of characters into a new String.1868*1869* @param start the offset of the first character1870* @param end the offset one past the last character1871* @return a new String containing the characters from start to end - 11872*1873* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or1874* {@code end > length()}1875*/1876@Override1877public CharSequence subSequence(int start, int end) {1878return substring(start, end);1879}18801881/**1882* Searches in this StringBuilder for the first index of the specified character. The1883* search for the character starts at the beginning and moves towards the1884* end.1885*1886* @param string the string to find1887* @return the index in this StringBuilder of the specified character, -1 if the1888* character isn't found1889*1890* @see #lastIndexOf(String)1891*/1892public int indexOf(String string) {1893return indexOf(string, 0);1894}18951896/**1897* Searches in this StringBuilder for the index of the specified character. The1898* search for the character starts at the specified offset and moves towards1899* the end.1900*1901* @param subString the string to find1902* @param start the starting offset1903* @return the index in this StringBuilder of the specified character, -1 if the1904* character isn't found1905*1906* @see #lastIndexOf(String,int)1907*/1908public int indexOf(String subString, int start) {1909int currentLength = lengthInternal();19101911if (start < 0) {1912start = 0;1913}19141915int subStringLength = subString.lengthInternal();19161917if (subStringLength > 0) {1918if (subStringLength + start > currentLength) {1919return -1;1920}19211922char firstChar = subString.charAtInternal(0);19231924// Check if the StringBuilder is compressed1925if (String.COMPACT_STRINGS && count >= 0) {1926if (!subString.isCompressed()) {1927return -1;1928}19291930while (true) {1931int i = start;19321933boolean found = false;19341935for (; i < currentLength; ++i) {1936if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {1937found = true;1938break;1939}1940}19411942// Handles subStringLength > currentLength || start >= currentLength1943if (!found || subStringLength + i > currentLength) {1944return -1;1945}19461947int o1 = i;1948int o2 = 0;19491950while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))1951;19521953if (o2 == subStringLength) {1954return i;1955}19561957start = i + 1;1958}1959} else {1960while (true) {1961int i = start;19621963boolean found = false;19641965for (; i < currentLength; ++i) {1966if (value[i] == firstChar) {1967found = true;1968break;1969}1970}19711972// Handles subStringLength > currentLength || start >= currentLength1973if (!found || subStringLength + i > currentLength) {1974return -1;1975}19761977int o1 = i;1978int o2 = 0;19791980while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))1981;19821983if (o2 == subStringLength) {1984return i;1985}19861987start = i + 1;1988}1989}19901991} else {1992return (start < currentLength || start == 0) ? start : currentLength;1993}1994}19951996/**1997* Searches in this StringBuilder for the last index of the specified character. The1998* search for the character starts at the end and moves towards the beginning.1999*2000* @param string the string to find2001* @return the index in this StringBuilder of the specified character, -1 if the2002* character isn't found2003*2004* @see #indexOf(String)2005*/2006public int lastIndexOf(String string) {2007int currentLength = lengthInternal();20082009return lastIndexOf(string, currentLength);2010}20112012/**2013* Searches in this StringBuilder for the index of the specified character. The2014* search for the character starts at the specified offset and moves towards2015* the beginning.2016*2017* @param subString the string to find2018* @param start the starting offset2019* @return the index in this StringBuilder of the specified character, -1 if the2020* character isn't found2021*2022* @see #indexOf(String,int)2023*/2024public int lastIndexOf(String subString, int start) {2025int currentLength = lengthInternal();20262027int subStringLength = subString.lengthInternal();20282029if (subStringLength <= currentLength && start >= 0) {2030if (subStringLength > 0) {2031if (start > currentLength - subStringLength) {2032start = currentLength - subStringLength;2033}20342035char firstChar = subString.charAtInternal(0);20362037// Check if the StringBuilder is compressed2038if (String.COMPACT_STRINGS && count >= 0) {2039if (!subString.isCompressed()) {2040return -1;2041}20422043while (true) {2044int i = start;20452046boolean found = false;20472048for (; i >= 0; --i) {2049if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {2050found = true;2051break;2052}2053}20542055if (!found) {2056return -1;2057}20582059int o1 = i;2060int o2 = 0;20612062while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))2063;20642065if (o2 == subStringLength) {2066return i;2067}20682069start = i - 1;2070}2071} else {2072while (true) {2073int i = start;20742075boolean found = false;20762077for (; i >= 0; --i) {2078if (value[i] == firstChar) {2079found = true;2080break;2081}2082}20832084if (!found) {2085return -1;2086}20872088int o1 = i;2089int o2 = 0;20902091while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))2092;20932094if (o2 == subStringLength) {2095return i;2096}20972098start = i - 1;2099}2100}2101} else {2102return start < currentLength ? start : currentLength;2103}2104} else {2105return -1;2106}2107}21082109/**2110* Return the underlying buffer and set the shared flag.2111*2112*/2113char[] shareValue() {2114capacity = capacity | sharedBit;21152116return value;2117}21182119boolean isCompressed() {2120// Check if the StringBuilder is compressed2121if (String.COMPACT_STRINGS && count >= 0) {2122return true;2123} else {2124return false;2125}2126}21272128/**2129* Constructs a new StringBuilder containing the characters in2130* the specified CharSequence and the default capacity.2131*2132* @param sequence the initial contents of this StringBuilder2133* @exception NullPointerException when sequence is null2134*/2135public StringBuilder(CharSequence sequence) {2136int size = sequence.length();21372138if (size < 0) {2139size = 0;2140}21412142int newLength = INITIAL_SIZE + size;2143if (newLength < size) {2144newLength = size;2145}21462147if (String.COMPACT_STRINGS) {2148value = new char[(newLength + 1) >>> 1];2149} else {2150value = new char[newLength];2151}21522153capacity = newLength;21542155if (sequence instanceof String) {2156append((String)sequence);2157} else if (sequence instanceof StringBuffer) {2158append((StringBuffer)sequence);2159} else {2160if (String.COMPACT_STRINGS) {2161boolean isCompressed = true;21622163for (int i = 0; i < size; ++i) {2164if (sequence.charAt(i) > 255) {2165isCompressed = false;21662167break;2168}2169}21702171if (isCompressed) {2172count = size;21732174for (int i = 0; i < size; ++i) {2175helpers.putByteInArrayByIndex(value, i, (byte) sequence.charAt(i));2176}2177} else {2178value = new char[newLength];21792180count = size | uncompressedBit;21812182for (int i = 0; i < size; ++i) {2183value[i] = sequence.charAt(i);2184}21852186String.initCompressionFlag();2187}2188} else {2189count = size;21902191for (int i = 0; i < size; ++i) {2192value[i] = sequence.charAt(i);2193}2194}2195}2196}21972198/**2199* Adds the specified CharSequence to the end of this StringBuilder.2200*2201* @param sequence the CharSequence2202* @return this StringBuilder2203*/2204@Override2205public StringBuilder append(CharSequence sequence) {2206if (sequence == null) {2207return append(String.valueOf(sequence));2208} else if (sequence instanceof String) {2209return append((String)sequence);2210} else if (sequence instanceof StringBuffer) {2211return append((StringBuffer)sequence);2212} else if (sequence instanceof StringBuilder) {2213StringBuilder builder = (StringBuilder) sequence;22142215// Check if the StringBuilder is compressed2216if (String.COMPACT_STRINGS && builder.count >= 0) {2217return append(builder.value, 0, builder.lengthInternal(), true);2218} else {2219return append(builder.value, 0, builder.lengthInternal(), false);2220}2221} else {2222int currentLength = lengthInternal();2223int currentCapacity = capacityInternal();22242225int sequenceLength = sequence.length();22262227int newLength = currentLength + sequenceLength;2228if (newLength < 0) {2229/*[MSG "K0D01", "Array capacity exceeded"]*/2230throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$2231}22322233if (String.COMPACT_STRINGS) {2234boolean isCompressed = true;22352236if (count >= 0) {2237for (int i = 0; i < sequence.length(); ++i) {2238if (sequence.charAt(i) > 255) {2239isCompressed = false;22402241break;2242}2243}2244}22452246// Check if the StringBuilder is compressed2247if (count >= 0 && isCompressed) {2248if (newLength > currentCapacity) {2249ensureCapacityImpl(newLength);2250}22512252for (int i = 0; i < sequence.length(); ++i) {2253helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(i));2254}22552256count = newLength;2257} else {2258// Check if the StringBuilder is compressed2259if (count >= 0) {2260currentCapacity = decompress(newLength);2261}22622263if (newLength > currentCapacity) {2264ensureCapacityImpl(newLength);2265}22662267for (int i = 0; i < sequence.length(); ++i) {2268value[currentLength + i] = sequence.charAt(i);2269}22702271count = newLength | uncompressedBit;2272}2273} else {2274if (newLength > currentCapacity) {2275ensureCapacityImpl(newLength);2276}22772278for (int i = 0; i < sequence.length(); ++i) {2279value[currentLength + i] = sequence.charAt(i);2280}22812282count = newLength;2283}22842285return this;2286}2287}22882289/**2290* Adds the specified CharSequence to the end of this StringBuilder.2291*2292* @param sequence the CharSequence2293* @param start the offset of the first character2294* @param end the offset one past the last character2295* @return this StringBuilder2296*2297* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or2298* {@code end > length()}2299*/2300@Override2301public StringBuilder append(CharSequence sequence, int start, int end) {2302if (sequence == null) {2303return append(String.valueOf(sequence), start, end);2304} else if (sequence instanceof String) {2305String sequenceString = (String) sequence;2306if (start >= 0 && start <= end && end <= sequenceString.lengthInternal()) {23072308int currentLength = lengthInternal();2309int currentCapacity = capacityInternal();2310int newLength = currentLength + end - start;2311if (newLength < 0) {2312/*[MSG "K0D01", "Array capacity exceeded"]*/2313throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$2314}23152316if (String.COMPACT_STRINGS) {23172318// Check if the StringBuilder is compressed2319if (count >= 0 && sequenceString.isCompressed()) {2320if (newLength > currentCapacity) {2321ensureCapacityImpl(newLength);2322}23232324sequenceString.getBytes(start, end, value, currentLength);2325count = newLength;2326} else {2327// Check if the StringBuilder is compressed2328if (count >= 0) {2329currentCapacity = decompress(newLength);2330}23312332if (newLength > currentCapacity) {2333ensureCapacityImpl(newLength);2334}23352336sequenceString.getCharsNoBoundChecks(start, end, value, currentLength);2337count = newLength | uncompressedBit;2338}2339} else {2340if (newLength > currentCapacity) {2341ensureCapacityImpl(newLength);2342}23432344sequenceString.getCharsNoBoundChecks(start, end, value, currentLength);2345count = newLength;2346}2347return this;2348} else {2349throw new IndexOutOfBoundsException();2350}2351} else if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {2352if (sequence instanceof StringBuffer) {2353synchronized (sequence) {2354StringBuffer buffer = (StringBuffer) sequence;23552356if (String.COMPACT_STRINGS && buffer.isCompressed()) {2357return append(buffer.getValue(), start, end - start, true);2358} else {2359return append(buffer.getValue(), start, end - start, false);2360}2361}2362} else if (sequence instanceof StringBuilder) {2363synchronized (sequence) {2364StringBuilder builder = (StringBuilder) sequence;23652366// Check if the StringBuilder is compressed2367if (String.COMPACT_STRINGS && builder.count >= 0) {2368return append(builder.value, start, end - start, true);2369} else {2370return append(builder.value, start, end - start, false);2371}2372}2373} else {2374int currentLength = lengthInternal();2375int currentCapacity = capacityInternal();23762377int newLength = currentLength + end - start;2378if (newLength < 0) {2379/*[MSG "K0D01", "Array capacity exceeded"]*/2380throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$2381}23822383if (String.COMPACT_STRINGS) {2384boolean isCompressed = true;23852386if (count >= 0) {2387for (int i = 0; i < sequence.length(); ++i) {2388if (sequence.charAt(i) > 255) {2389isCompressed = false;23902391break;2392}2393}2394}23952396// Check if the StringBuilder is compressed2397if (count >= 0 && isCompressed) {2398if (newLength > currentCapacity) {2399ensureCapacityImpl(newLength);2400}24012402for (int i = 0; i < end - start; ++i) {2403helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(start + i));2404}24052406count = newLength;2407} else {2408// Check if the StringBuilder is compressed2409if (count >= 0) {2410currentCapacity = decompress(newLength);2411}24122413if (newLength > currentCapacity) {2414ensureCapacityImpl(newLength);2415}24162417for (int i = 0; i < end - start; ++i) {2418value[currentLength + i] = sequence.charAt(start + i);2419}24202421count = newLength | uncompressedBit;2422}2423} else {2424if (newLength > currentCapacity) {2425ensureCapacityImpl(newLength);2426}24272428for (int i = 0; i < end - start; ++i) {2429value[currentLength + i] = sequence.charAt(start + i);2430}24312432count = newLength;2433}24342435return this;2436}2437} else {2438throw new IndexOutOfBoundsException();2439}2440}24412442/**2443* Inserts the CharSequence at the specified offset in this StringBuilder.2444*2445* @param index the index at which to insert2446* @param sequence the CharSequence to insert2447* @return this StringBuilder2448*2449* @exception IndexOutOfBoundsException when {@code index < 0} or2450* {@code index > length()}2451*/2452public StringBuilder insert(int index, CharSequence sequence) {2453int currentLength = lengthInternal();24542455if (index >= 0 && index <= currentLength) {2456if (sequence == null) {2457return insert(index, String.valueOf(sequence));2458} else if (sequence instanceof String) {2459return insert(index, (String) sequence);2460} else if (sequence instanceof StringBuffer) {2461synchronized(sequence) {2462StringBuffer buffer = (StringBuffer) sequence;24632464if (String.COMPACT_STRINGS && buffer.isCompressed()) {2465return insert(index, buffer.getValue(), 0, buffer.length(), true);2466} else {2467return insert(index, buffer.getValue(), 0, buffer.length(), false);2468}2469}2470} else if (sequence instanceof StringBuilder) {2471synchronized (sequence) {2472StringBuilder builder = (StringBuilder) sequence;24732474// Check if the StringBuilder is compressed2475if (String.COMPACT_STRINGS && builder.count >= 0) {2476return insert(index, builder.value, 0, builder.lengthInternal(), true);2477} else {2478return insert(index, builder.value, 0, builder.lengthInternal(), false);2479}2480}2481} else {2482int sequneceLength = sequence.length();24832484if (sequneceLength > 0) {2485move(sequneceLength, index);24862487int newLength = currentLength + sequneceLength;24882489if (String.COMPACT_STRINGS) {2490boolean isCompressed = true;24912492for (int i = 0; i < sequneceLength; ++i) {2493if (sequence.charAt(i) > 255) {2494isCompressed = false;24952496break;2497}2498}24992500// Check if the StringBuilder is compressed2501if (count >= 0 && isCompressed) {2502for (int i = 0; i < sequneceLength; ++i) {2503helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(i));2504}25052506count = newLength;25072508return this;2509} else {2510// Check if the StringBuilder is compressed2511if (count >= 0) {2512decompress(value.length);2513}25142515for (int i = 0; i < sequneceLength; ++i) {2516value[index + i] = sequence.charAt(i);2517}25182519count = newLength | uncompressedBit;2520}2521} else {2522for (int i = 0; i < sequneceLength; ++i) {2523value[index + i] = sequence.charAt(i);2524}25252526count = newLength;2527}2528}25292530return this;2531}2532} else {2533throw new IndexOutOfBoundsException();2534}2535}25362537/**2538* Inserts the CharSequence at the specified offset in this StringBuilder.2539*2540* @param index the index at which to insert2541* @param sequence the CharSequence to insert2542* @param start the offset of the first character2543* @param end the offset one past the last character2544* @return this StringBuilder2545*2546* @exception IndexOutOfBoundsException when {@code index < 0} or2547* {@code index > length()}, or when {@code start < 0, start > end} or2548* {@code end > length()}2549*/2550public StringBuilder insert(int index, CharSequence sequence, int start, int end) {2551int currentLength = lengthInternal();25522553if (index >= 0 && index <= currentLength) {2554if (sequence == null)2555return insert(index, String.valueOf(sequence), start, end);2556if (sequence instanceof String) {2557return insert(index, ((String) sequence).substring(start, end));2558}2559if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {2560if (sequence instanceof StringBuffer) {2561synchronized(sequence) {2562StringBuffer buffer = (StringBuffer) sequence;25632564if (String.COMPACT_STRINGS && buffer.isCompressed()) {2565return insert(index, buffer.getValue(), start, end - start, true);2566} else {2567return insert(index, buffer.getValue(), start, end - start, false);2568}2569}2570} else if (sequence instanceof StringBuilder) {2571synchronized(sequence) {2572StringBuilder builder = (StringBuilder) sequence;25732574// Check if the StringBuilder is compressed2575if (String.COMPACT_STRINGS && builder.count >= 0) {2576return insert(index, builder.value, start, end - start, true);2577} else {2578return insert(index, builder.value, start, end - start, false);2579}2580}2581} else {2582int sequenceLength = end - start;25832584if (sequenceLength > 0) {2585move(sequenceLength, index);25862587int newLength = currentLength + sequenceLength;25882589if (String.COMPACT_STRINGS) {2590boolean isCompressed = true;25912592for (int i = 0; i < sequenceLength; ++i) {2593if (sequence.charAt(start + i) > 255) {2594isCompressed = false;25952596break;2597}2598}25992600// Check if the StringBuilder is compressed2601if (count >= 0 && isCompressed) {2602for (int i = 0; i < sequenceLength; ++i) {2603helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(start + i));2604}26052606count = newLength;26072608return this;2609} else {2610// Check if the StringBuilder is compressed2611if (count >= 0) {2612decompress(value.length);2613}26142615for (int i = 0; i < sequenceLength; ++i) {2616value[index + i] = sequence.charAt(start + i);2617}26182619count = newLength | uncompressedBit;2620}2621} else {2622for (int i = 0; i < sequenceLength; ++i) {2623value[index + i] = sequence.charAt(start + i);2624}26252626count = newLength;2627}2628}26292630return this;2631}2632} else {2633throw new IndexOutOfBoundsException();2634}2635} else {2636throw new IndexOutOfBoundsException();2637}2638}26392640/**2641* Optionally modify the underlying char array to only2642* be large enough to hold the characters in this StringBuffer.2643*/2644public void trimToSize() {2645int currentLength = lengthInternal();2646int currentCapacity = capacityInternal();26472648// Check if the StringBuilder is compressed2649if (String.COMPACT_STRINGS && count >= 0) {2650// Check if the StringBuilder is not shared2651if (capacity >= 0 && currentCapacity != currentLength) {2652char[] newData = new char[(currentLength + 1) / 2];26532654String.compressedArrayCopy(value, 0, newData, 0, currentLength);26552656value = newData;26572658capacity = currentLength;2659}2660} else {2661// Check if the StringBuilder is not shared2662if (capacity >= 0 && currentCapacity != currentLength) {2663char[] newData = new char[currentLength];26642665String.decompressedArrayCopy(value, 0, newData, 0, currentLength);26662667value = newData;26682669capacity = currentLength;2670}2671}2672}26732674/**2675* Returns the Unicode character at the given point.2676*2677* @param index the character index2678* @return the Unicode character value at the index2679*/2680public int codePointAt(int index) {2681int currentLength = lengthInternal();26822683if (index >= 0 && index < currentLength) {2684// Check if the StringBuilder is compressed2685if (String.COMPACT_STRINGS && count >= 0) {2686return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));2687} else {2688int high = value[index];26892690if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2691int low = value[index + 1];26922693if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2694return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);2695}2696}26972698return high;2699}2700} else {2701throw new StringIndexOutOfBoundsException(index);2702}2703}27042705/**2706* Returns the Unicode character before the given point.2707*2708* @param index the character index2709* @return the Unicode character value before the index2710*/2711public int codePointBefore(int index) {2712int currentLength = lengthInternal();27132714if (index > 0 && index <= currentLength) {2715// Check if the StringBuilder is compressed2716if (String.COMPACT_STRINGS && count >= 0) {2717return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));2718} else {2719int low = value[index - 1];27202721if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2722int high = value[index - 2];27232724if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2725return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);2726}2727}27282729return low;2730}2731} else {2732throw new StringIndexOutOfBoundsException(index);2733}2734}27352736/**2737* Returns the total Unicode values in the specified range.2738*2739* @param start first index2740* @param end last index2741* @return the total Unicode values2742*/2743public int codePointCount(int start, int end) {2744int currentLength = lengthInternal();27452746if (start >= 0 && start <= end && end <= currentLength) {2747// Check if the StringBuilder is compressed2748if (String.COMPACT_STRINGS && count >= 0) {2749return end - start;2750} else {2751int count = 0;27522753for (int i = start; i < end; ++i) {2754int high = value[i];27552756if (i + 1 < end && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2757int low = value[i + 1];27582759if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2760++i;2761}2762}27632764++count;2765}27662767return count;2768}2769} else {2770throw new IndexOutOfBoundsException();2771}2772}27732774/**2775* Returns the index of the code point that was offset by {@code codePointCount}.2776*2777* @param start the position to offset2778* @param codePointCount the code point count2779* @return the offset index2780*/2781public int offsetByCodePoints(int start, int codePointCount) {2782int currentLength = lengthInternal();27832784if (start >= 0 && start <= currentLength) {2785// Check if the StringBuilder is compressed2786if (String.COMPACT_STRINGS && count >= 0) {2787int index = start + codePointCount;27882789if (index >= currentLength) {2790throw new IndexOutOfBoundsException();2791} else {2792return index;2793}2794} else {2795int index = start;27962797if (codePointCount == 0) {2798return start;2799} else if (codePointCount > 0) {2800for (int i = 0; i < codePointCount; ++i) {2801if (index == currentLength) {2802throw new IndexOutOfBoundsException();2803}28042805int high = value[index];28062807if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2808int low = value[index + 1];28092810if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2811index++;2812}2813}28142815index++;2816}2817} else {2818for (int i = codePointCount; i < 0; ++i) {2819if (index < 1) {2820throw new IndexOutOfBoundsException();2821}28222823int low = value[index - 1];28242825if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {2826int high = value[index - 2];28272828if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {2829index--;2830}2831}28322833index--;2834}2835}28362837return index;2838}2839} else {2840throw new IndexOutOfBoundsException();2841}2842}28432844/**2845* Adds the specified code point to the end of this StringBuffer.2846*2847* @param codePoint the code point2848* @return this StringBuffer2849*/2850public StringBuilder appendCodePoint(int codePoint) {2851if (codePoint >= 0) {2852if (codePoint < 0x10000) {2853return append((char)codePoint);2854} else if (codePoint < 0x110000) {2855// Check if the StringBuilder is compressed2856if (String.COMPACT_STRINGS && count >= 0) {2857decompress(value.length);2858}28592860int currentLength = lengthInternal();2861int currentCapacity = capacityInternal();28622863int newLength = currentLength + 2;2864if (newLength < 0) {2865/*[MSG "K0D01", "Array capacity exceeded"]*/2866throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$2867}28682869if (newLength > currentCapacity) {2870ensureCapacityImpl(newLength);2871}28722873codePoint -= 0x10000;28742875value[currentLength] = (char) (Character.MIN_HIGH_SURROGATE + (codePoint >> 10));2876value[currentLength + 1] = (char) (Character.MIN_LOW_SURROGATE + (codePoint & 0x3ff));28772878if (String.COMPACT_STRINGS) {2879count = newLength | uncompressedBit;2880} else {2881count = newLength;2882}28832884return this;2885}2886}28872888throw new IllegalArgumentException();2889}28902891/*2892* Returns the character array for this StringBuilder.2893*/2894char[] getValue() {2895return value;2896}28972898}289929002901