Path: blob/master/jcl/src/java.base/share/classes/java/lang/String.java
12513 views
/*[INCLUDE-IF JAVA_SPEC_VERSION < 17]*/1/*******************************************************************************2* Copyright (c) 1998, 2021 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.Serializable;2526import java.util.Locale;27import java.util.Comparator;28import java.io.UnsupportedEncodingException;29import java.util.regex.Pattern;30import java.util.regex.PatternSyntaxException;31import java.util.Formatter;32import java.util.StringJoiner;33import java.util.Iterator;34import java.nio.charset.Charset;35/*[IF JAVA_SPEC_VERSION >= 12]*/36import java.util.function.Function;37import java.util.Optional;38/*[ENDIF] JAVA_SPEC_VERSION >= 12 */39/*[IF Sidecar19-SE]*/40import java.util.Spliterator;41import java.util.stream.StreamSupport;4243import jdk.internal.misc.Unsafe;44import java.util.stream.IntStream;45/*[ELSE] Sidecar19-SE*/46import sun.misc.Unsafe;47/*[ENDIF] Sidecar19-SE*/4849/*[IF JAVA_SPEC_VERSION >= 11]*/50import java.util.stream.Stream;51/*[ENDIF] JAVA_SPEC_VERSION >= 11 */5253/*[IF JAVA_SPEC_VERSION >= 12]*/54import java.lang.constant.Constable;55import java.lang.constant.ConstantDesc;56import java.lang.invoke.MethodHandles;57import java.lang.invoke.MethodHandles.Lookup;58/*[ENDIF] JAVA_SPEC_VERSION >= 12 */5960/**61* Strings are objects which represent immutable arrays of characters.62*63* @author OTI64* @version initial65*66* @see StringBuffer67*/68public final class String implements Serializable, Comparable<String>, CharSequence69/*[IF JAVA_SPEC_VERSION >= 12]*/70, Constable, ConstantDesc71/*[ENDIF] JAVA_SPEC_VERSION >= 12 */72{7374/*75* Last character of String substitute in String.replaceAll(regex, substitute) can't be \ or $.76* The backslash (\) is used to escape literal characters, and the dollar sign ($) is treated as77* references to captured subsequences.78*/79private void checkLastChar(char lastChar) {80if (lastChar == '\\') {81/*[MSG "K0801", "Last character in replacement string can't be \, character to be escaped is required."]*/82throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0801")); //$NON-NLS-1$83} else if (lastChar == '$') {84/*[MSG "K0802", "Last character in replacement string can't be $, group index is required."]*/85throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0802")); //$NON-NLS-1$86}87}8889/*[IF Sidecar19-SE]*/90// DO NOT CHANGE OR MOVE THIS LINE91// IT MUST BE THE FIRST THING IN THE INITIALIZATION92private static final long serialVersionUID = -6849794470754667710L;9394/**95* Determines whether String compression is enabled.96*/97static final boolean COMPACT_STRINGS = com.ibm.oti.vm.VM.J9_STRING_COMPRESSION_ENABLED;9899static final byte LATIN1 = 0;100static final byte UTF16 = 1;101102// returns UTF16 when COMPACT_STRINGS is false103byte coder() {104if (COMPACT_STRINGS) {105return coder;106} else {107return UTF16;108}109}110111/*[IF JAVA_SPEC_VERSION >= 16]*/112/**113* Copy bytes from value starting at srcIndex into the bytes array starting at114* destIndex. No range checking is needed. Caller ensures bytes is in UTF16.115*116* @param bytes copy destination117* @param srcIndex index into value118* @param destIndex index into bytes119* @param coder LATIN1 or UTF16120* @param length the number of elements to copy121*/122void getBytes(byte[] bytes, int srcIndex, int destIndex, byte coder, int length) {123// Check if the String is compressed124if (COMPACT_STRINGS && (null == compressionFlag || this.coder == LATIN1)) {125if (String.LATIN1 == coder) {126compressedArrayCopy(value, srcIndex, bytes, destIndex, length);127} else {128StringLatin1.inflate(value, srcIndex, bytes, destIndex, length);129}130} else {131decompressedArrayCopy(value, srcIndex, bytes, destIndex, length);132}133}134/*[ENDIF] JAVA_SPEC_VERSION >= 16 */135136// no range checking, caller ensures bytes is in UTF16137// coder is one of LATIN1 or UTF16138void getBytes(byte[] bytes, int offset, byte coder) {139int currentLength = lengthInternal();140141// Check if the String is compressed142if (COMPACT_STRINGS && (null == compressionFlag || this.coder == LATIN1)) {143if (String.LATIN1 == coder) {144compressedArrayCopy(value, 0, bytes, offset, currentLength);145} else {146StringLatin1.inflate(value, 0, bytes, offset, currentLength);147}148} else {149decompressedArrayCopy(value, 0, bytes, offset, currentLength);150}151}152153static void checkIndex(int index, int length) {154if ((0 <= index) && (index < length)) {155return;156}157throw new StringIndexOutOfBoundsException("index="+index + " length="+length); //$NON-NLS-1$ //$NON-NLS-2$158}159160static void checkOffset(int offset, int length) {161if ((0 <= offset) && (offset <= length)) {162return;163}164throw new StringIndexOutOfBoundsException("offset="+offset + " length="+length); //$NON-NLS-1$ //$NON-NLS-2$165}166167/**168* CaseInsensitiveComparator compares Strings ignoring the case of the characters.169*/170private static final class CaseInsensitiveComparator implements Comparator<String>, Serializable {171static final long serialVersionUID = 8575799808933029326L;172173/**174* Compare the two objects to determine the relative ordering.175*176* @param o1177* an Object to compare178* @param o2179* an Object to compare180* @return {@code < 0} if o1 is less than o2, {@code 0} if they are equal, and {@code > 0} if o1 is greater181*182* @exception ClassCastException183* when objects are not the correct type184*/185public int compare(String o1, String o2) {186return o1.compareToIgnoreCase(o2);187}188};189190/**191* A Comparator which compares Strings ignoring the case of the characters.192*/193public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();194195// Used to represent the value of an empty String196private static final byte[] emptyValue = new byte[0];197198// Used to extract the value of a single ASCII character String by the integral value of the respective character as199// an index into this table200private static final byte[][] compressedAsciiTable;201202private static final byte[][] decompressedAsciiTable;203204// Used to access compression related helper methods205private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();206207static class StringCompressionFlag implements Serializable {208private static final long serialVersionUID = 1346155847239551492L;209}210211// Singleton used by all String instances to indicate a non-compressed string has been212// allocated. JIT attempts to fold away the null check involving this static if the213// StringCompressionFlag class has not been initialized and patches the code to bring back214// the null check if a non-compressed String is constructed.215private static StringCompressionFlag compressionFlag;216217// Represents the bit in count field to test for whether this String backing array is not compressed218// under String compression mode. This bit is not used when String compression is disabled.219private static final int uncompressedBit = 0x80000000;220221private static String[] stringArray;222private static final int stringArraySize = 10;223224private static class UnsafeHelpers {225public final static long valueFieldOffset = getValueFieldOffset();226227static long getValueFieldOffset() {228try {229return Unsafe.getUnsafe().objectFieldOffset(String.class.getDeclaredField("value")); //$NON-NLS-1$230} catch (NoSuchFieldException e) {231throw new RuntimeException(e);232}233}234}235236/**237* This is a System property to enable sharing of the underlying value array in {@link #String.substring(int)} and238* {@link #String.substring(int, int)} if the offset is zero.239*/240static boolean enableSharingInSubstringWhenOffsetIsZero;241242private final byte[] value;243private final byte coder;244private int hash;245246static {247stringArray = new String[stringArraySize];248249compressedAsciiTable = new byte[256][];250251for (int i = 0; i < compressedAsciiTable.length; ++i) {252byte[] asciiValue = new byte[1];253254helpers.putByteInArrayByIndex(asciiValue, 0, (byte) i);255256compressedAsciiTable[i] = asciiValue;257}258259decompressedAsciiTable = new byte[256][];260261for (int i = 0; i < decompressedAsciiTable.length; ++i) {262byte[] asciiValue = new byte[2];263264helpers.putCharInArrayByIndex(asciiValue, 0, (char) i);265266decompressedAsciiTable[i] = asciiValue;267}268}269270static void initCompressionFlag() {271if (compressionFlag == null) {272compressionFlag = new StringCompressionFlag();273}274}275276/**277* Determines whether the input character array can be encoded as a compact278* Latin1 string.279*280* <p>This API implicitly assumes the following:281* <blockquote><pre>282* - {@code length >= 0}283* - {@code start >= 0}284* - {@code start + length <= data.length}285* <blockquote><pre>286*287* @param c the array of characters to check288* @param start the starting offset in the character array289* @param length the number of characters to check starting at {@code start}290* @return {@code true} if the input character array can be encoded291* using the Latin1 encoding; {@code false} otherwise292*/293static boolean canEncodeAsLatin1(char[] c, int start, int length) {294for (int i = start; i < start + length; ++i) {295if (c[i] > 255) {296return false;297}298}299300return true;301}302303static void compress(byte[] array1, int start1, byte[] array2, int start2, int length) {304for (int i = 0; i < length; ++i) {305helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));306}307}308309static void compress(char[] array1, int start1, byte[] array2, int start2, int length) {310for (int i = 0; i < length; ++i) {311helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));312}313}314315static void compress(byte[] array1, int start1, char[] array2, int start2, int length) {316for (int i = 0; i < length; ++i) {317helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));318}319}320321static void compress(char[] array1, int start1, char[] array2, int start2, int length) {322for (int i = 0; i < length; ++i) {323helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));324}325}326327static void decompress(byte[] array1, int start1, byte[] array2, int start2, int length) {328for (int i = 0; i < length; ++i) {329helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));330}331}332333static void decompress(char[] array1, int start1, byte[] array2, int start2, int length) {334for (int i = 0; i < length; ++i) {335helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));336}337}338339static void decompress(byte[] array1, int start1, char[] array2, int start2, int length) {340for (int i = 0; i < length; ++i) {341helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));342}343}344345static void decompress(char[] array1, int start1, char[] array2, int start2, int length) {346for (int i = 0; i < length; ++i) {347helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));348}349}350351static void compressedArrayCopy(byte[] array1, int start1, byte[] array2, int start2, int length) {352if (array1 == array2 && start1 < start2) {353for (int i = length - 1; i >= 0; --i) {354helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));355}356} else {357for (int i = 0; i < length; ++i) {358helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));359}360}361}362363static void compressedArrayCopy(byte[] array1, int start1, char[] array2, int start2, int length) {364for (int i = 0; i < length; ++i) {365helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));366}367}368369static void compressedArrayCopy(char[] array1, int start1, byte[] array2, int start2, int length) {370for (int i = 0; i < length; ++i) {371helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));372}373}374375static void compressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {376if (array1 == array2 && start1 < start2) {377for (int i = length - 1; i >= 0; --i) {378helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));379}380} else {381for (int i = 0; i < length; ++i) {382helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));383}384}385}386387static void decompressedArrayCopy(byte[] array1, int start1, byte[] array2, int start2, int length) {388if (array1 == array2 && start1 < start2) {389for (int i = length - 1; i >= 0; --i) {390helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));391}392} else {393for (int i = 0; i < length; ++i) {394helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));395}396}397}398399static void decompressedArrayCopy(byte[] array1, int start1, char[] array2, int start2, int length) {400for (int i = 0; i < length; ++i) {401helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));402}403}404405static void decompressedArrayCopy(char[] array1, int start1, byte[] array2, int start2, int length) {406for (int i = 0; i < length; ++i) {407helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));408}409}410411static void decompressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {412System.arraycopy(array1, start1, array2, start2, length);413}414415boolean isCompressed() {416// Check if the String is compressed417if (COMPACT_STRINGS) {418if (null == compressionFlag) {419return true;420} else {421return coder == String.LATIN1;422}423} else {424return false;425}426}427428String(byte[] byteArray, byte coder) {429if (COMPACT_STRINGS) {430if (String.LATIN1 == coder) {431value = byteArray;432} else {433value = byteArray;434435initCompressionFlag();436}437} else {438value = byteArray;439}440this.coder = coder;441}442443static void checkBoundsOffCount(int offset, int count, int length) {444if (offset >= 0 && count >= 0 && offset <= length - count) {445return;446}447448throw newStringIndexOutOfBoundsException(offset, count, length);449}450451static private StringIndexOutOfBoundsException newStringIndexOutOfBoundsException(int offset, int count, int length) {452return new StringIndexOutOfBoundsException("offset = " + offset + " count = " + count + " length = " + length); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$453}454455/**456* Answers an empty string.457*/458public String() {459value = emptyValue;460461if (COMPACT_STRINGS) {462coder = LATIN1;463} else {464coder = UTF16;465}466}467468/**469* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not470* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.471*472* @param data473* the byte array to convert to a String474*475* @throws NullPointerException476* when data is null477*478* @see #getBytes()479* @see #getBytes(int, int, byte[], int)480* @see #getBytes(String)481* @see #valueOf(boolean)482* @see #valueOf(char)483* @see #valueOf(char[])484* @see #valueOf(char[], int, int)485* @see #valueOf(double)486* @see #valueOf(float)487* @see #valueOf(int)488* @see #valueOf(long)489* @see #valueOf(Object)490*491*/492public String(byte[] data) {493this(data, 0, data.length);494}495496/**497* Converts the byte array to a String, setting the high byte of every character to the specified value.498*499* @param data500* the byte array to convert to a String501* @param high502* the high byte to use503*504* @throws NullPointerException505* when data is null506*507* @deprecated Use String(byte[]) or String(byte[], String) instead508*/509@Deprecated(forRemoval=false, since="1.1")510public String(byte[] data, int high) {511this(data, high, 0, data.length);512}513514/**515* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not516* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.517*518* @param data519* the byte array to convert to a String520* @param start521* the starting offset in the byte array522* @param length523* the number of bytes to convert524*525* @throws IndexOutOfBoundsException526* when {@code length < 0, start < 0} or {@code start + length > data.length}527* @throws NullPointerException528* when data is null529*530* @see #getBytes()531* @see #getBytes(int, int, byte[], int)532* @see #getBytes(String)533* @see #valueOf(boolean)534* @see #valueOf(char)535* @see #valueOf(char[])536* @see #valueOf(char[], int, int)537* @see #valueOf(double)538* @see #valueOf(float)539* @see #valueOf(int)540* @see #valueOf(long)541* @see #valueOf(Object)542*543*/544public String(byte[] data, int start, int length) {545data.getClass(); // Implicit null check546547if (start >= 0 && 0 <= length && length <= data.length - start) {548StringCoding.Result scResult = StringCoding.decode(data, start, length);549550value = scResult.value;551coder = scResult.coder;552553if (COMPACT_STRINGS && scResult.coder == UTF16) {554initCompressionFlag();555}556} else {557throw new StringIndexOutOfBoundsException();558}559}560561/**562* Converts the byte array to a String, setting the high byte of every character to the specified value.563*564* @param data565* the byte array to convert to a String566* @param high567* the high byte to use568* @param start569* the starting offset in the byte array570* @param length571* the number of bytes to convert572*573* @throws IndexOutOfBoundsException574* when {@code length < 0, start < 0} or {@code start + length > data.length}575* @throws NullPointerException576* when data is null577*578* @deprecated Use String(byte[], int, int) instead579*/580@Deprecated(forRemoval=false, since="1.1")581public String(byte[] data, int high, int start, int length) {582data.getClass(); // Implicit null check583584if (start >= 0 && 0 <= length && length <= data.length - start) {585if (COMPACT_STRINGS && high == 0) {586value = new byte[length];587coder = LATIN1;588589compressedArrayCopy(data, start, value, 0, length);590} else {591value = StringUTF16.newBytesFor(length);592coder = UTF16;593594high <<= 8;595596for (int i = 0; i < length; ++i) {597helpers.putCharInArrayByIndex(value, i, (char) (high + (data[start++] & 0xff)));598}599600if (COMPACT_STRINGS) {601initCompressionFlag();602}603}604} else {605throw new StringIndexOutOfBoundsException();606}607}608609/**610* Converts the byte array to a String using the specified encoding.611*612* @param data613* the byte array to convert to a String614* @param start615* the starting offset in the byte array616* @param length617* the number of bytes to convert618* @param encoding619* the encoding620*621* @throws IndexOutOfBoundsException622* when {@code length < 0, start < 0} or {@code start + length > data.length}623* @throws UnsupportedEncodingException624* when encoding is not supported625* @throws NullPointerException626* when data is null627*628* @see #getBytes()629* @see #getBytes(int, int, byte[], int)630* @see #getBytes(String)631* @see #valueOf(boolean)632* @see #valueOf(char)633* @see #valueOf(char[])634* @see #valueOf(char[], int, int)635* @see #valueOf(double)636* @see #valueOf(float)637* @see #valueOf(int)638* @see #valueOf(long)639* @see #valueOf(Object)640* @see UnsupportedEncodingException641*/642public String(byte[] data, int start, int length, final String encoding) throws UnsupportedEncodingException {643data.getClass(); // Implicit null check644encoding.getClass(); // Implicit null check645646if (start >= 0 && 0 <= length && length <= data.length - start) {647StringCoding.Result scResult = StringCoding.decode(encoding, data, start, length);648649value = scResult.value;650coder = scResult.coder;651652if (COMPACT_STRINGS && scResult.coder == UTF16) {653initCompressionFlag();654}655} else {656throw new StringIndexOutOfBoundsException();657}658}659660/**661* Converts the byte array to a String using the specified encoding.662*663* @param data664* the byte array to convert to a String665* @param encoding666* the encoding667*668* @throws UnsupportedEncodingException669* when encoding is not supported670* @throws NullPointerException671* when data is null672*673* @see #getBytes()674* @see #getBytes(int, int, byte[], int)675* @see #getBytes(String)676* @see #valueOf(boolean)677* @see #valueOf(char)678* @see #valueOf(char[])679* @see #valueOf(char[], int, int)680* @see #valueOf(double)681* @see #valueOf(float)682* @see #valueOf(int)683* @see #valueOf(long)684* @see #valueOf(Object)685* @see UnsupportedEncodingException686*/687public String(byte[] data, String encoding) throws UnsupportedEncodingException {688this(data, 0, data.length, encoding);689}690691private String(String s, char c) {692if (s == null) {693s = "null"; //$NON-NLS-1$694}695696int slen = s.lengthInternal();697698int concatlen = slen + 1;699if (concatlen < 0) {700/*[MSG "K0D01", "Array capacity exceeded"]*/701throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$702}703704// Check if the String is compressed705if (COMPACT_STRINGS && (null == compressionFlag || s.coder == LATIN1) && c <= 255) {706value = new byte[concatlen];707coder = LATIN1;708709compressedArrayCopy(s.value, 0, value, 0, slen);710711helpers.putByteInArrayByIndex(value, slen, (byte) c);712} else {713value = StringUTF16.newBytesFor(concatlen);714coder = UTF16;715716// Check if the String is compressed717if (COMPACT_STRINGS && s.coder == LATIN1) {718StringLatin1.inflate(s.value, 0, value, 0, slen);719} else {720decompressedArrayCopy(s.value, 0, value, 0, slen);721}722723helpers.putCharInArrayByIndex(value, slen, c);724725if (COMPACT_STRINGS) {726initCompressionFlag();727}728}729}730731/**732* Initializes this String to contain the characters in the specified character array. Modifying the character array after creating the String has733* no effect on the String.734*735* @param data736* the array of characters737*738* @throws NullPointerException739* when data is null740*/741public String(char[] data) {742this(data, 0, data.length);743}744745/**746* Initializes this String to use the specified character array. The character array should not be modified after the String is created.747*748* @param data749* a non-null array of characters750*/751String(char[] data, boolean ignore) {752if (COMPACT_STRINGS && canEncodeAsLatin1(data, 0, data.length)) {753value = new byte[data.length];754coder = LATIN1;755756compress(data, 0, value, 0, data.length);757} else {758value = StringUTF16.newBytesFor(data.length);759coder = UTF16;760761decompressedArrayCopy(data, 0, value, 0, data.length);762763if (COMPACT_STRINGS) {764initCompressionFlag();765}766}767}768769/**770* Initializes this String to contain the specified characters in the character array. Modifying the character array after creating the String has771* no effect on the String.772*773* @param data774* the array of characters775* @param start776* the starting offset in the character array777* @param length778* the number of characters to use779*780* @throws IndexOutOfBoundsException781* when {@code length < 0, start < 0} or {@code start + length > data.length}782* @throws NullPointerException783* when data is null784*/785public String(char[] data, int start, int length) {786if (start >= 0 && 0 <= length && length <= data.length - start) {787if (COMPACT_STRINGS && canEncodeAsLatin1(data, start, length)) {788value = new byte[length];789coder = LATIN1;790791compress(data, start, value, 0, length);792} else {793value = StringUTF16.newBytesFor(length);794coder = UTF16;795796decompressedArrayCopy(data, start, value, 0, length);797798if (COMPACT_STRINGS) {799initCompressionFlag();800}801}802} else {803throw new StringIndexOutOfBoundsException();804}805}806807String(byte[] data, int start, int length, boolean compressed) {808if (length == 0) {809value = emptyValue;810811if (COMPACT_STRINGS) {812coder = LATIN1;813} else {814coder = UTF16;815}816} else if (length == 1) {817if (COMPACT_STRINGS && compressed) {818char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));819820value = compressedAsciiTable[theChar];821coder = LATIN1;822hash = theChar;823} else {824char theChar = helpers.getCharFromArrayByIndex(data, start);825826if (theChar <= 255) {827value = decompressedAsciiTable[theChar];828} else {829value = new byte[2];830831helpers.putCharInArrayByIndex(value, 0, theChar);832}833834coder = UTF16;835hash = theChar;836837if (COMPACT_STRINGS) {838initCompressionFlag();839}840}841} else {842if (COMPACT_STRINGS && compressed) {843if (start == 0 && data.length == length) {844value = data;845} else {846value = new byte[length];847848compressedArrayCopy(data, start, value, 0, length);849}850851coder = LATIN1;852} else {853if (start == 0 && data.length == length * 2) {854value = data;855} else {856value = StringUTF16.newBytesFor(length);857858decompressedArrayCopy(data, start, value, 0, length);859}860861coder = UTF16;862863if (COMPACT_STRINGS) {864initCompressionFlag();865}866}867}868}869870String(byte[] data, int start, int length, boolean compressed, boolean sharingIsAllowed) {871if (length == 0) {872value = emptyValue;873874if (COMPACT_STRINGS) {875coder = LATIN1;876} else {877coder = UTF16;878}879} else if (length == 1) {880if (COMPACT_STRINGS && compressed) {881char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));882883value = compressedAsciiTable[theChar];884coder = LATIN1;885hash = theChar;886} else {887char theChar = helpers.getCharFromArrayByIndex(data, start);888889if (theChar <= 255) {890value = decompressedAsciiTable[theChar];891} else {892value = new byte[2];893894helpers.putCharInArrayByIndex(value, 0, theChar);895}896897coder = UTF16;898hash = theChar;899900if (COMPACT_STRINGS) {901initCompressionFlag();902}903}904} else {905if (COMPACT_STRINGS && compressed) {906if (sharingIsAllowed && start == 0 && data.length == length) {907value = data;908} else {909value = new byte[length];910911compressedArrayCopy(data, start, value, 0, length);912}913914coder = LATIN1;915} else {916if (sharingIsAllowed && start == 0 && data.length == length * 2) {917value = data;918} else {919value = StringUTF16.newBytesFor(length);920921decompressedArrayCopy(data, start, value, 0, length);922}923924coder = UTF16;925926if (COMPACT_STRINGS) {927initCompressionFlag();928}929}930}931}932933/**934* Creates a string that is a copy of another string935*936* @param string937* the String to copy938*/939public String(String string) {940value = string.value;941coder = string.coder;942hash = string.hash;943}944945/**946* Creates a string from the contents of a StringBuffer.947*948* @param buffer949* the StringBuffer950*/951public String(StringBuffer buffer) {952this(buffer.toString());953}954955/*956* Creates a string that is s1 + s2.957*/958private String(String s1, String s2) {959if (s1 == null) {960s1 = "null"; //$NON-NLS-1$961}962963if (s2 == null) {964s2 = "null"; //$NON-NLS-1$965}966967int s1len = s1.lengthInternal();968int s2len = s2.lengthInternal();969970int concatlen = s1len + s2len;971if (concatlen < 0) {972/*[MSG "K0D01", "Array capacity exceeded"]*/973throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$974}975976if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {977value = new byte[concatlen];978coder = LATIN1;979980compressedArrayCopy(s1.value, 0, value, 0, s1len);981compressedArrayCopy(s2.value, 0, value, s1len, s2len);982} else {983value = StringUTF16.newBytesFor(concatlen);984coder = UTF16;985986// Check if the String is compressed987if (COMPACT_STRINGS && s1.coder == LATIN1) {988StringLatin1.inflate(s1.value, 0, value, 0, s1len);989} else {990decompressedArrayCopy(s1.value, 0, value, 0, s1len);991}992993// Check if the String is compressed994if (COMPACT_STRINGS && s2.coder == LATIN1) {995StringLatin1.inflate(s2.value, 0, value, s1len, s2len);996} else {997decompressedArrayCopy(s2.value, 0, value, s1len, s2len);998}9991000if (COMPACT_STRINGS) {1001initCompressionFlag();1002}1003}1004}10051006/*1007* Creates a string that is s1 + s2 + s3.1008*/1009private String(String s1, String s2, String s3) {1010if (s1 == null) {1011s1 = "null"; //$NON-NLS-1$1012}10131014if (s2 == null) {1015s2 = "null"; //$NON-NLS-1$1016}10171018if (s3 == null) {1019s3 = "null"; //$NON-NLS-1$1020}10211022int s1len = s1.lengthInternal();1023int s2len = s2.lengthInternal();1024int s3len = s3.lengthInternal();10251026long totalLen = (long) s1len + (long) s2len + (long) s3len;1027if (totalLen > Integer.MAX_VALUE) {1028/*[MSG "K0D01", "Array capacity exceeded"]*/1029throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1030}1031int concatlen = (int) totalLen;10321033if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder | s3.coder) == LATIN1)) {1034value = new byte[concatlen];1035coder = LATIN1;10361037compressedArrayCopy(s1.value, 0, value, 0, s1len);1038compressedArrayCopy(s2.value, 0, value, s1len, s2len);1039compressedArrayCopy(s3.value, 0, value, s1len + s2len, s3len);1040} else {1041value = StringUTF16.newBytesFor(concatlen);1042coder = UTF16;10431044// Check if the String is compressed1045if (COMPACT_STRINGS && s1.coder == LATIN1) {1046StringLatin1.inflate(s1.value, 0, value, 0, s1len);1047} else {1048decompressedArrayCopy(s1.value, 0, value, 0, s1len);1049}10501051// Check if the String is compressed1052if (COMPACT_STRINGS && s2.coder == LATIN1) {1053StringLatin1.inflate(s2.value, 0, value, s1len, s2len);1054} else {1055decompressedArrayCopy(s2.value, 0, value, s1len, s2len);1056}10571058// Check if the String is compressed1059if (COMPACT_STRINGS && s3.coder == LATIN1) {1060StringLatin1.inflate(s3.value, 0, value, s1len + s2len, s3len);1061} else {1062decompressedArrayCopy(s3.value, 0, value, (s1len + s2len), s3len);1063}10641065if (COMPACT_STRINGS) {1066initCompressionFlag();1067}1068}1069}10701071/*1072* Creates a string that is s1 + v1.1073*/1074private String(String s1, int v1) {1075if (s1 == null) {1076s1 = "null"; //$NON-NLS-1$1077}10781079// Char length of all the parameters respectively1080int s1len = s1.lengthInternal();1081int v1len = 1;10821083int quot;1084int i = v1;1085while ((i /= 10) != 0)1086v1len++;1087if (v1 >= 0) {1088quot = -v1;1089} else {1090// Leave room for '-'1091v1len++;1092quot = v1;1093}10941095// Char length of the final String1096int len = s1len + v1len;1097if (len < 0) {1098/*[MSG "K0D01", "Array capacity exceeded"]*/1099throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1100}11011102if (COMPACT_STRINGS && (null == compressionFlag || s1.coder == LATIN1)) {1103value = new byte[len];1104coder = LATIN1;11051106// Copy in v11107int index = len - 1;11081109do {1110int res = quot / 10;1111int rem = quot - (res * 10);11121113quot = res;11141115// Write the digit into the correct position1116helpers.putByteInArrayByIndex(value, index--, (byte) ('0' - rem));1117} while (quot != 0);11181119if (v1 < 0) {1120helpers.putByteInArrayByIndex(value, index, (byte) '-');1121}11221123// Copy in s1 contents1124compressedArrayCopy(s1.value, 0, value, 0, s1len);1125} else {1126value = StringUTF16.newBytesFor(len);1127coder = UTF16;11281129// Copy in v11130int index = len - 1;11311132do {1133int res = quot / 10;1134int rem = quot - (res * 10);11351136quot = res;11371138// Write the digit into the correct position1139helpers.putCharInArrayByIndex(value, index--, (char) ('0' - rem));1140} while (quot != 0);11411142if (v1 < 0) {1143helpers.putCharInArrayByIndex(value, index, (char) '-');1144}11451146// Copy in s1 contents1147decompressedArrayCopy(s1.value, 0, value, 0, s1len);11481149if (COMPACT_STRINGS) {1150initCompressionFlag();1151}1152}1153}11541155/*1156* Creates a string that is v1 + s1 + v2 + s2 + s3.1157*/1158private String(int v1, String s1, int v2, String s2, String s3) {1159if (s1 == null) {1160s1 = "null"; //$NON-NLS-1$1161}11621163if (s2 == null) {1164s2 = "null"; //$NON-NLS-1$1165}11661167if (s3 == null) {1168s3 = "null"; //$NON-NLS-1$1169}11701171// Char length of all the parameters respectively1172int s1len = s1.lengthInternal();1173int s2len = s2.lengthInternal();1174int s3len = s3.lengthInternal();11751176int v1len = 1;1177int v2len = 1;11781179int quot1;1180int i1 = v1;1181while ((i1 /= 10) != 0)1182v1len++;1183if (v1 >= 0) {1184quot1 = -v1;1185} else {1186// Leave room for '-'1187v1len++;1188quot1 = v1;1189}11901191int quot2;1192int i2 = v2;1193while ((i2 /= 10) != 0)1194v2len++;1195if (v2 >= 0) {1196quot2 = -v2;1197} else {1198// Leave room for '-'1199v2len++;1200quot2 = v2;1201}12021203// Char length of the final String1204long totalLen = (long) s1len + (long) v1len + (long) v2len + (long) s2len + (long) s3len;1205if (totalLen > Integer.MAX_VALUE) {1206/*[MSG "K0D01", "Array capacity exceeded"]*/1207throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1208}1209int len = (int) totalLen;12101211if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder | s3.coder) == LATIN1)) {1212value = new byte[len];1213coder = LATIN1;12141215int start = len;12161217// Copy in s3 contents1218start = start - s3len;1219compressedArrayCopy(s3.value, 0, value, start, s3len);12201221// Copy in s2 contents1222start = start - s2len;1223compressedArrayCopy(s2.value, 0, value, start, s2len);12241225// Copy in v21226int index2 = start - 1;12271228do {1229int res = quot2 / 10;1230int rem = quot2 - (res * 10);12311232quot2 = res;12331234// Write the digit into the correct position1235helpers.putByteInArrayByIndex(value, index2--, (byte) ('0' - rem));1236} while (quot2 != 0);12371238if (v2 < 0) {1239helpers.putByteInArrayByIndex(value, index2--, (byte) '-');1240}12411242// Copy in s1 contents1243start = index2 + 1 - s1len;1244compressedArrayCopy(s1.value, 0, value, start, s1len);12451246// Copy in v11247int index1 = start - 1;12481249do {1250int res = quot1 / 10;1251int rem = quot1 - (res * 10);12521253quot1 = res;12541255// Write the digit into the correct position1256helpers.putByteInArrayByIndex(value, index1--, (byte) ('0' - rem));1257} while (quot1 != 0);12581259if (v1 < 0) {1260helpers.putByteInArrayByIndex(value, index1--, (byte) '-');1261}1262} else {1263value = StringUTF16.newBytesFor(len);1264coder = UTF16;12651266int start = len;12671268// Copy in s3 contents1269start = start - s3len;12701271// Check if the String is compressed1272if (COMPACT_STRINGS && s3.coder == LATIN1) {1273StringLatin1.inflate(s3.value, 0, value, start, s3len);1274} else {1275decompressedArrayCopy(s3.value, 0, value, start, s3len);1276}12771278// Copy in s2 contents1279start = start - s2len;12801281// Check if the String is compressed1282if (COMPACT_STRINGS && s2.coder == LATIN1) {1283StringLatin1.inflate(s2.value, 0, value, start, s2len);1284} else {1285decompressedArrayCopy(s2.value, 0, value, start, s2len);1286}12871288// Copy in v21289int index2 = start - 1;12901291do {1292int res = quot2 / 10;1293int rem = quot2 - (res * 10);12941295quot2 = res;12961297// Write the digit into the correct position1298helpers.putCharInArrayByIndex(value, index2--, (char) ('0' - rem));1299} while (quot2 != 0);13001301if (v2 < 0) {1302helpers.putCharInArrayByIndex(value, index2--, (char) '-');1303}13041305// Copy in s1 contents1306start = index2 + 1 - s1len;13071308// Check if the String is compressed1309if (COMPACT_STRINGS && s1.coder == LATIN1) {1310StringLatin1.inflate(s1.value, 0, value, start, s1len);1311} else {1312decompressedArrayCopy(s1.value, 0, value, start, s1len);1313}13141315// Copy in v11316int index1 = start - 1;13171318do {1319int res = quot1 / 10;1320int rem = quot1 - (res * 10);13211322quot1 = res;13231324// Write the digit into the correct position1325helpers.putCharInArrayByIndex(value, index1--, (char) ('0' - rem));1326} while (quot1 != 0);13271328if (v1 < 0) {1329helpers.putCharInArrayByIndex(value, index1--, (char) '-');1330}13311332if (COMPACT_STRINGS) {1333initCompressionFlag();1334}1335}1336}13371338/*1339* Loads from the stringArray if concatenated result is found else it creates a string that is s1 + s2 which is stored in stringArray and then1340* returned.1341*/1342static private String cachedConstantString(String s1, String s2, int index) {1343if (index < stringArraySize) {1344if (stringArray[index] == null) {1345stringArray[index] = new String(s1, s2);1346}1347} else {1348return new String(s1, s2);1349}1350return stringArray[index];1351}13521353/**1354* Answers the character at the specified offset in this String.1355*1356* @param index1357* the zero-based index in this string1358* @return the character at the index1359*1360* @throws IndexOutOfBoundsException1361* when {@code index < 0} or {@code index >= length()}1362*/1363public char charAt(int index) {1364if (0 <= index && index < lengthInternal()) {1365// Check if the String is compressed1366if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {1367return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));1368} else {1369return helpers.getCharFromArrayByIndex(value, index);1370}1371} else {1372throw new StringIndexOutOfBoundsException();1373}1374}13751376// Internal version of charAt used for extracting a char from a String in compression related code.1377char charAtInternal(int index) {1378// Check if the String is compressed1379if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {1380return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));1381} else {1382return helpers.getCharFromArrayByIndex(value, index);1383}1384}13851386// This method is needed so idiom recognition properly recognizes idiomatic loops where we are doing an operation on1387// the byte[] value of two Strings. In such cases we extract the String.value fields before entering the operation loop.1388// However if chatAt is used inside the loop then the JIT will anchor the load of the value byte[] inside of the loop thus1389// causing us to load the String.value on every iteration. This is very suboptimal and breaks some of the common idioms1390// that we recognize. The most prominent one is the regionMatches arraycmp idiom that is not recognized unless this method1391// is being used.1392char charAtInternal(int index, byte[] value) {1393// Check if the String is compressed1394if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {1395return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));1396} else {1397return helpers.getCharFromArrayByIndex(value, index);1398}1399}14001401/**1402* Compares the specified String to this String using the Unicode values of the characters. Answer 0 if the strings contain the same characters in1403* the same order. Answer a negative integer if the first non-equal character in this String has a Unicode value which is less than the Unicode1404* value of the character at the same position in the specified string, or if this String is a prefix of the specified string. Answer a positive1405* integer if the first non-equal character in this String has a Unicode value which is greater than the Unicode value of the character at the same1406* position in the specified string, or if the specified String is a prefix of the this String.1407*1408* @param string1409* the string to compare1410* @return 0 if the strings are equal, a negative integer if this String is before the specified String, or a positive integer if this String is1411* after the specified String1412*1413* @throws NullPointerException1414* when string is null1415*/1416public int compareTo(String string) {1417String s1 = this;1418String s2 = string;14191420int s1len = s1.lengthInternal();1421int s2len = s2.lengthInternal();14221423// Upper bound index on the last char to compare1424int end = s1len < s2len ? s1len : s2len;14251426int o1 = 0;1427int o2 = 0;14281429byte[] s1Value = s1.value;1430byte[] s2Value = s2.value;14311432if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {1433while (o1 < end) {1434int result =1435helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s1Value, o1++)) -1436helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s2Value, o2++));14371438if (result != 0) {1439return result;1440}1441}1442} else {1443while (o1 < end) {1444int result =1445s1.charAtInternal(o1++, s1Value) -1446s2.charAtInternal(o2++, s2Value);14471448if (result != 0) {1449return result;1450}1451}1452}14531454return s1len - s2len;1455}14561457private static int compareValue(int codepoint) {1458if ('A' <= codepoint && codepoint <= 'Z') {1459return codepoint + ('a' - 'A');1460}14611462return Character.toLowerCase(Character.toUpperCase(codepoint));1463}14641465private static char compareValue(char c) {1466if ('A' <= c && c <= 'Z') {1467return (char) (c + ('a' - 'A'));1468}14691470return Character.toLowerCase(Character.toUpperCase(c));1471}14721473private static char compareValue(byte b) {1474if ('A' <= b && b <= 'Z') {1475return (char)(helpers.byteToCharUnsigned(b) + ('a' - 'A'));1476}1477return Character.toLowerCase(Character.toUpperCase(helpers.byteToCharUnsigned(b)));1478}14791480private static boolean charValuesEqualIgnoreCase(char c1, char c2) {1481boolean charValuesEqual = false;1482char c1upper = (char) toUpperCase(c1);1483char c2upper = (char) toUpperCase(c2);14841485// If at least one char is ASCII, converting to upper cases then compare should be sufficient.1486// If both chars are not in ASCII char set, need to convert to lower case and compare as well.1487if (((c1 <= 255 || c2 <= 255) && (c1upper == c2upper))1488|| (toLowerCase(c1upper) == toLowerCase(c2upper))1489) {1490charValuesEqual = true;1491}14921493return charValuesEqual;1494}14951496/**1497* Compare the receiver to the specified String to determine the relative ordering when the case of the characters is ignored.1498*1499* @param string1500* a String1501* @return an {@code int < 0} if this String is less than the specified String, 0 if they are equal, and {@code > 0} if this String is greater1502*/1503public int compareToIgnoreCase(String string) {1504String s1 = this;1505String s2 = string;15061507int s1len = s1.lengthInternal();1508int s2len = s2.lengthInternal();15091510// Upper bound index on the last char to compare1511int end = s1len < s2len ? s1len : s2len;15121513int o1 = 0;1514int o2 = 0;15151516byte[] s1Value = s1.value;1517byte[] s2Value = s2.value;15181519if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {1520while (o1 < end) {1521byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);1522byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);15231524if (byteAtO1 == byteAtO2) {1525continue;1526}15271528int result = compareValue(byteAtO1) - compareValue(byteAtO2);15291530if (result != 0) {1531return result;1532}1533}1534} else {1535while (o1 < end) {1536char charAtO1 = s1.charAtInternal(o1++, s1Value);1537char charAtO2 = s2.charAtInternal(o2++, s2Value);1538int codepointAtO1 = charAtO1;1539int codepointAtO2 = charAtO2;15401541if (charAtO1 == charAtO2) {1542/*[IF JAVA_SPEC_VERSION >= 16]*/1543if (Character.isHighSurrogate(charAtO1) && (o1 < end)) {1544codepointAtO1 = Character.toCodePoint(charAtO1, s1.charAtInternal(o1++, s1Value));1545codepointAtO2 = Character.toCodePoint(charAtO2, s2.charAtInternal(o2++, s2Value));1546if (codepointAtO1 == codepointAtO2) {1547continue;1548}1549} else {1550continue;1551}1552/*[ELSE]*/1553continue;1554/*[ENDIF] JAVA_SPEC_VERSION >= 16 */1555}15561557int result = compareValue(codepointAtO1) - compareValue(codepointAtO2);15581559if (result != 0) {1560return result;1561}1562}1563}15641565return s1len - s2len;1566}15671568/**1569* Concatenates this String and the specified string.1570*1571* @param string1572* the string to concatenate1573* @return a String which is the concatenation of this String and the specified String1574*1575* @throws NullPointerException1576* if string is null1577*/1578public String concat(String string) {1579String s1 = this;1580String s2 = string;15811582int s1len = s1.lengthInternal();1583int s2len = s2.lengthInternal();15841585if (s2len == 0) {1586return s1;1587}15881589int concatlen = s1len + s2len;1590if (concatlen < 0) {1591/*[MSG "K0D01", "Array capacity exceeded"]*/1592throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$1593}15941595if (COMPACT_STRINGS && ((null == compressionFlag) || ((s1.coder | s2.coder) == LATIN1))) {1596byte[] buffer = new byte[concatlen];15971598compressedArrayCopy(s1.value, 0, buffer, 0, s1len);1599compressedArrayCopy(s2.value, 0, buffer, s1len, s2len);16001601return new String(buffer, LATIN1);1602} else {1603byte[] buffer = StringUTF16.newBytesFor(concatlen);16041605// Check if the String is compressed1606if (COMPACT_STRINGS && s1.coder == LATIN1) {1607StringLatin1.inflate(s1.value, 0, buffer, 0, s1len);1608} else {1609decompressedArrayCopy(s1.value, 0, buffer, 0, s1len);1610}16111612// Check if the String is compressed1613if (COMPACT_STRINGS && s2.coder == LATIN1) {1614StringLatin1.inflate(s2.value, 0, buffer, s1len, s2len);1615} else {1616decompressedArrayCopy(s2.value, 0, buffer, s1len, s2len);1617}16181619return new String(buffer, UTF16);1620}1621}16221623/**1624* Creates a new String containing the characters in the specified character array. Modifying the character array after creating the String has no1625* effect on the String.1626*1627* @param data1628* the array of characters1629* @return the new String1630*1631* @throws NullPointerException1632* if data is null1633*/1634public static String copyValueOf(char[] data) {1635return new String(data, 0, data.length);1636}16371638/**1639* Creates a new String containing the specified characters in the character array. Modifying the character array after creating the String has no1640* effect on the String.1641*1642* @param data1643* the array of characters1644* @param start1645* the starting offset in the character array1646* @param length1647* the number of characters to use1648* @return the new String1649*1650* @throws IndexOutOfBoundsException1651* when {@code length < 0, start < 0} or {@code start + length > data.length}1652* @throws NullPointerException1653* if data is null1654*/1655public static String copyValueOf(char[] data, int start, int length) {1656return new String(data, start, length);1657}16581659/**1660* Compares the specified string to this String to determine if the specified string is a suffix.1661*1662* @param suffix1663* the string to look for1664* @return true when the specified string is a suffix of this String, false otherwise1665*1666* @throws NullPointerException1667* if suffix is null1668*/1669public boolean endsWith(String suffix) {1670return regionMatches(lengthInternal() - suffix.lengthInternal(), suffix, 0, suffix.lengthInternal());1671}16721673/**1674* Compares the specified object to this String and answer if they are equal. The object must be an instance of String with the same characters in1675* the same order.1676*1677* @param object1678* the object to compare1679* @return true if the specified object is equal to this String, false otherwise1680*1681* @see #hashCode()1682*/1683public boolean equals(Object object) {1684if (object == this) {1685return true;1686} else {1687if (object instanceof String) {1688String s1 = this;1689String s2 = (String) object;16901691int s1len = s1.lengthInternal();1692int s2len = s2.lengthInternal();16931694if (s1len != s2len) {1695return false;1696}16971698byte[] s1Value = s1.value;1699byte[] s2Value = s2.value;17001701if (s1Value == s2Value) {1702return true;1703} else {1704// There was a time hole between first read of s.hash and second read if another thread does hashcode1705// computing for incoming string object1706int s1hash = s1.hash;1707int s2hash = s2.hash;17081709if (s1hash != 0 && s2hash != 0 && s1hash != s2hash) {1710return false;1711}17121713if (!regionMatchesInternal(s1, s2, s1Value, s2Value, 0, 0, s1len)) {1714return false;1715}17161717if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY != com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_DISABLED) {1718deduplicateStrings(s1, s1Value, s2, s2Value);1719}17201721return true;1722}1723}17241725return false;1726}1727}17281729/**1730* Deduplicate the backing buffers of the given strings.1731*1732* This updates the {@link #value} of one of the two given strings so that1733* they both share a single backing buffer. The strings must have identical1734* contents.1735*1736* Deduplication helps save space, and lets {@link #equals(Object)} exit1737* early more often.1738*1739* The strings' corresponding backing buffers are accepted as parameters1740* because the caller likely already has them.1741*1742* @param s1 The first string1743* @param value1 {@code s1.value}1744* @param s2 The second string1745* @param value2 {@code s2.value}1746*/1747private static final void deduplicateStrings(String s1, Object value1, String s2, Object value2) {1748if (s1.coder == s2.coder) {1749long valueFieldOffset = UnsafeHelpers.valueFieldOffset;17501751if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY == com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_FAVOUR_LOWER) {1752if (helpers.acmplt(value1, value2)) {1753helpers.putObjectInObject(s2, valueFieldOffset, value1);1754} else {1755helpers.putObjectInObject(s1, valueFieldOffset, value2);1756}1757} else {1758if (helpers.acmplt(value2, value1)) {1759helpers.putObjectInObject(s2, valueFieldOffset, value1);1760} else {1761helpers.putObjectInObject(s1, valueFieldOffset, value2);1762}1763}1764}1765}17661767/**1768* Compares the specified String to this String ignoring the case of the characters and answer if they are equal.1769*1770* @param string1771* the string to compare1772* @return true if the specified string is equal to this String, false otherwise1773*/1774public boolean equalsIgnoreCase(String string) {1775String s1 = this;1776String s2 = string;17771778if (s1 == s2) {1779return true;1780}17811782if (s2 == null) {1783return false;1784}17851786int s1len = s1.lengthInternal();1787int s2len = s2.lengthInternal();17881789if (s1len != s2len) {1790return false;1791}17921793// Zero length strings are equal1794if (s1len == 0) {1795return true;1796}17971798int o1 = 0;1799int o2 = 0;18001801// Upper bound index on the last char to compare1802int end = s1len;18031804byte[] s1Value = s1.value;1805byte[] s2Value = s2.value;18061807if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {1808// Compare the last chars.1809// In order to tell 2 chars are different:1810// Under string compression, the compressible char set obeys 1-1 mapping for upper/lower case,1811// converting to upper cases then compare should be sufficient.1812byte byteAtO1Last = helpers.getByteFromArrayByIndex(s1Value, s1len - 1);1813byte byteAtO2Last = helpers.getByteFromArrayByIndex(s2Value, s1len - 1);18141815if ((byteAtO1Last != byteAtO2Last)1816&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1Last)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2Last)))1817) {1818return false;1819}18201821while (o1 < end - 1) {1822byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);1823byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);18241825if ((byteAtO1 != byteAtO2)1826&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2)))1827) {1828return false;1829}1830}1831} else {1832// Compare the last chars.1833// In order to tell 2 chars are different:1834// If at least one char is ASCII, converting to upper cases then compare should be sufficient.1835// If both chars are not in ASCII char set, need to convert to lower case and compare as well.1836char charAtO1Last = s1.charAtInternal(s1len - 1, s1Value);1837char charAtO2Last = s2.charAtInternal(s1len - 1, s2Value);18381839if ((charAtO1Last != charAtO2Last)1840&& !charValuesEqualIgnoreCase(charAtO1Last, charAtO2Last)1841/*[IF JAVA_SPEC_VERSION >= 16]*/1842&& (!Character.isLowSurrogate(charAtO1Last) || !Character.isLowSurrogate(charAtO2Last))1843/*[ENDIF] JAVA_SPEC_VERSION >= 16 */1844) {1845return false;1846}18471848/*[IF JAVA_SPEC_VERSION >= 16]*/1849while (o1 < end) {1850/*[ELSE]*/1851while (o1 < end - 1) {1852/*[ENDIF] JAVA_SPEC_VERSION >= 16 */1853char charAtO1 = s1.charAtInternal(o1++, s1Value);1854char charAtO2 = s2.charAtInternal(o2++, s2Value);18551856/*[IF JAVA_SPEC_VERSION >= 16]*/1857if (Character.isHighSurrogate(charAtO1) && Character.isHighSurrogate(charAtO2) && (o1 < end)) {1858int codepointAtO1 = Character.toCodePoint(charAtO1, s1.charAtInternal(o1++, s1Value));1859int codepointAtO2 = Character.toCodePoint(charAtO2, s2.charAtInternal(o2++, s2Value));1860if ((codepointAtO1 != codepointAtO2)1861&& (compareValue(codepointAtO1) != compareValue(codepointAtO2))1862) {1863return false;1864} else {1865continue;1866}1867}1868/*[ENDIF] JAVA_SPEC_VERSION >= 16 */18691870if ((charAtO1 != charAtO2)1871&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))1872) {1873return false;1874}1875}1876}18771878return true;1879}18801881/**1882* Converts this String to a byte encoding using the default encoding as specified by the file.encoding system property. If the system property is1883* not defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.1884*1885* @return the byte array encoding of this String1886*1887* @see String1888*/1889public byte[] getBytes() {1890return StringCoding.encode(coder, value);1891}18921893/**1894* Converts this String to a byte array, ignoring the high order bits of each character.1895*1896* @param start1897* the starting offset of characters to copy1898* @param end1899* the ending offset of characters to copy1900* @param data1901* the destination byte array1902* @param index1903* the starting offset in the byte array1904*1905* @throws NullPointerException1906* when data is null1907* @throws IndexOutOfBoundsException1908* when {@code start < 0, end > length(), index < 0, end - start > data.length - index}1909*1910* @deprecated Use getBytes() or getBytes(String)1911*/1912@Deprecated(forRemoval=false, since="1.1")1913public void getBytes(int start, int end, byte[] data, int index) {1914if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {1915// Check if the String is compressed1916if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {1917compressedArrayCopy(value, start, data, index, end - start);1918} else {1919compress(value, start, data, index, end - start);1920}1921} else {1922throw new StringIndexOutOfBoundsException();1923}1924}19251926/**1927* Converts this String to a byte encoding using the specified encoding.1928*1929* @param encoding1930* the encoding1931* @return the byte array encoding of this String1932*1933* @throws UnsupportedEncodingException1934* when the encoding is not supported1935*1936* @see String1937* @see UnsupportedEncodingException1938*/1939public byte[] getBytes(String encoding) throws UnsupportedEncodingException {1940encoding.getClass(); // Implicit null check1941return StringCoding.encode(encoding, coder, value);1942}19431944/**1945* Copies the specified characters in this String to the character array starting at the specified offset in the character array.1946*1947* @param start1948* the starting offset of characters to copy1949* @param end1950* the ending offset of characters to copy1951* @param data1952* the destination character array1953* @param index1954* the starting offset in the character array1955*1956* @throws IndexOutOfBoundsException1957* when {@code start < 0, end > length(), start > end, index < 0, end - start > buffer.length - index}1958* @throws NullPointerException1959* when buffer is null1960*/1961public void getChars(int start, int end, char[] data, int index) {1962if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {1963getCharsNoBoundChecks(start, end, data, index);1964} else {1965throw new StringIndexOutOfBoundsException();1966}1967}19681969// This is a package protected method that performs the getChars operation without explicit bound checks.1970// Caller of this method must validate bound safety for String indexing and array copying.1971void getCharsNoBoundChecks(int start, int end, char[] data, int index) {1972// Check if the String is compressed1973if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {1974StringLatin1.inflate(value, start, data, index, end - start);1975} else {1976decompressedArrayCopy(value, start, data, index, end - start);1977}1978}19791980// This is a package protected method that performs the getChars operation without explicit bound checks.1981// Caller of this method must validate bound safety for String indexing and array copying.1982void getCharsNoBoundChecks(int start, int end, byte[] data, int index) {1983// Check if the String is compressed1984if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {1985StringLatin1.inflate(value, start, data, index, end - start);1986} else {1987decompressedArrayCopy(value, start, data, index, end - start);1988}1989}19901991/**1992* Answers an integer hash code for the receiver. Objects which are equal answer the same value for this method.1993*1994* @return the receiver's hash1995*1996* @see #equals1997*/1998public int hashCode() {1999if (hash == 0 && value.length > 0) {2000// Check if the String is compressed2001if (COMPACT_STRINGS && (compressionFlag == null || coder == LATIN1)) {2002hash = hashCodeImplCompressed(value, 0, lengthInternal());2003} else {2004hash = hashCodeImplDecompressed(value, 0, lengthInternal());2005}2006}20072008return hash;2009}20102011private static int hashCodeImplCompressed(byte[] value, int offset, int count) {2012int hash = 0, end = offset + count;20132014for (int i = offset; i < end; ++i) {2015hash = (hash << 5) - hash + helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i));2016}20172018return hash;2019}20202021private static int hashCodeImplDecompressed(byte[] value, int offset, int count) {2022int hash = 0, end = offset + count;20232024for (int i = offset; i < end; ++i) {2025hash = (hash << 5) - hash + helpers.getCharFromArrayByIndex(value, i);2026}20272028return hash;2029}20302031/**2032* Searches in this String for the first index of the specified character. The search for the character starts at the beginning and moves towards2033* the end of this String.2034*2035* @param c2036* the character to find2037* @return the index in this String of the specified character, -1 if the character isn't found2038*2039* @see #lastIndexOf(int)2040* @see #lastIndexOf(int, int)2041* @see #lastIndexOf(String)2042* @see #lastIndexOf(String, int)2043*/2044public int indexOf(int c) {2045return indexOf(c, 0);2046}20472048/**2049* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards2050* the end of this String.2051*2052* @param c2053* the character to find2054* @param start2055* the starting offset2056* @return the index in this String of the specified character, -1 if the character isn't found2057*2058* @see #lastIndexOf(int)2059* @see #lastIndexOf(int, int)2060* @see #lastIndexOf(String)2061* @see #lastIndexOf(String, int)2062*/2063public int indexOf(int c, int start) {2064int len = lengthInternal();20652066if (start < len) {2067if (start < 0) {2068start = 0;2069}20702071if (c >= 0 && c <= Character.MAX_VALUE) {2072byte[] array = value;20732074// Check if the String is compressed2075if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2076if (c <= 255) {2077return helpers.intrinsicIndexOfLatin1(array, (byte)c, start, len);2078}2079} else {2080return helpers.intrinsicIndexOfUTF16(array, (char)c, start, len);2081}2082} else if (c <= Character.MAX_CODE_POINT) {2083for (int i = start; i < len; ++i) {2084int codePoint = codePointAt(i);20852086if (codePoint == c) {2087return i;2088}20892090if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {2091++i;2092}2093}2094}2095}20962097return -1;2098}20992100/**2101* Searches in this String for the first index of the specified string. The search for the string starts at the beginning and moves towards the end2102* of this String.2103*2104* @param string2105* the string to find2106* @return the index in this String of the specified string, -1 if the string isn't found2107*2108* @throws NullPointerException2109* when string is null2110*2111* @see #lastIndexOf(int)2112* @see #lastIndexOf(int, int)2113* @see #lastIndexOf(String)2114* @see #lastIndexOf(String, int)2115*2116*/2117public int indexOf(String string) {2118return indexOf(string, 0);2119}21202121/**2122* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the2123* end of this String.2124*2125* @param subString2126* the string to find2127* @param start2128* the starting offset2129* @return the index in this String of the specified string, -1 if the string isn't found2130*2131* @throws NullPointerException2132* when string is null2133*2134* @see #lastIndexOf(int)2135* @see #lastIndexOf(int, int)2136* @see #lastIndexOf(String)2137* @see #lastIndexOf(String, int)2138*/2139public int indexOf(String subString, int start) {2140if (subString.length() == 1) {2141return indexOf(subString.charAtInternal(0), start);2142}21432144return indexOf(value, coder, lengthInternal(), subString, start);2145}21462147static int indexOf(byte[] value, byte coder, int count, String str, int fromIndex) {2148int s1Length = count;2149int s2Length = str.lengthInternal();21502151if (fromIndex < 0) {2152fromIndex = 0;2153} else if (fromIndex >= s1Length) {2154// Handle the case where the substring is of zero length, in which case we have an indexOf hit at the end2155// of this string2156return s2Length == 0 ? s1Length : -1;2157}21582159if (s2Length == 0) {2160// At this point we know fromIndex < s1Length so there is a hit at fromIndex2161return fromIndex;2162}21632164byte[] s1Value = value;2165byte[] s2Value = str.value;21662167if (coder == str.coder) {2168if (coder == LATIN1) {2169return StringLatin1.indexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);2170} else {2171return StringUTF16.indexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);2172}2173}21742175if (coder == UTF16) {2176return StringUTF16.indexOfLatin1(s1Value, s1Length, s2Value, s2Length, fromIndex);2177}21782179return -1;2180}21812182/**2183* Searches an internal table of strings for a string equal to this String. If the string is not in the table, it is added. Answers the string2184* contained in the table which is equal to this String. The same string object is always answered for strings which are equal.2185*2186* @return the interned string equal to this String2187*/2188public native String intern();21892190/**2191* Searches in this String for the last index of the specified character. The search for the character starts at the end and moves towards the2192* beginning of this String.2193*2194* @param c2195* the character to find2196* @return the index in this String of the specified character, -1 if the character isn't found2197*2198* @see #lastIndexOf(int)2199* @see #lastIndexOf(int, int)2200* @see #lastIndexOf(String)2201* @see #lastIndexOf(String, int)2202*/2203public int lastIndexOf(int c) {2204return lastIndexOf(c, lengthInternal() - 1);2205}22062207/**2208* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards2209* the beginning of this String.2210*2211* @param c2212* the character to find2213* @param start2214* the starting offset2215* @return the index in this String of the specified character, -1 if the character isn't found2216*2217* @see #lastIndexOf(int)2218* @see #lastIndexOf(int, int)2219* @see #lastIndexOf(String)2220* @see #lastIndexOf(String, int)2221*/2222public int lastIndexOf(int c, int start) {2223if (start >= 0) {2224int len = lengthInternal();22252226if (start >= len) {2227start = len - 1;2228}22292230if (c >= 0 && c <= Character.MAX_VALUE) {2231byte[] array = value;22322233// Check if the String is compressed2234if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2235if (c <= 255) {2236byte b = (byte) c;22372238for (int i = start; i >= 0; --i) {2239if (helpers.getByteFromArrayByIndex(array, i) == b) {2240return i;2241}2242}2243}2244} else {2245for (int i = start; i >= 0; --i) {2246if (helpers.getCharFromArrayByIndex(array, i) == c) {2247return i;2248}2249}2250}2251} else if (c <= Character.MAX_CODE_POINT) {2252for (int i = start; i >= 0; --i) {2253int codePoint = codePointAt(i);22542255if (codePoint == c) {2256return i;2257}22582259if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {2260--i;2261}2262}2263}2264}22652266return -1;2267}22682269/**2270* Searches in this String for the last index of the specified string. The search for the string starts at the end and moves towards the beginning2271* of this String.2272*2273* @param string2274* the string to find2275* @return the index in this String of the specified string, -1 if the string isn't found2276*2277* @throws NullPointerException2278* when string is null2279*2280* @see #lastIndexOf(int)2281* @see #lastIndexOf(int, int)2282* @see #lastIndexOf(String)2283* @see #lastIndexOf(String, int)2284*/2285public int lastIndexOf(String string) {2286return lastIndexOf(string, lengthInternal());2287}22882289/**2290* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the2291* beginning of this String.2292*2293* @param subString2294* the string to find2295* @param start2296* the starting offset2297* @return the index in this String of the specified string, -1 if the string isn't found2298*2299* @throws NullPointerException2300* when string is null2301*2302* @see #lastIndexOf(int)2303* @see #lastIndexOf(int, int)2304* @see #lastIndexOf(String)2305* @see #lastIndexOf(String, int)2306*/2307public int lastIndexOf(String subString, int start) {2308return lastIndexOf(value, coder, lengthInternal(), subString, start);2309}23102311static int lastIndexOf(byte[] value, byte coder, int count, String str, int fromIndex) {2312int s1Length = count;2313int s2Length = str.lengthInternal();23142315if (fromIndex > s1Length - s2Length) {2316fromIndex = s1Length - s2Length;2317}23182319if (fromIndex < 0) {2320return -1;2321}23222323if (s2Length == 0) {2324return fromIndex;2325}23262327byte[] s1Value = value;2328byte[] s2Value = str.value;23292330if (coder == str.coder) {2331if (coder == LATIN1) {2332return StringLatin1.lastIndexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);2333} else {2334return StringUTF16.lastIndexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);2335}2336}23372338if (coder == UTF16) {2339return StringUTF16.lastIndexOfLatin1(s1Value, s1Length, s2Value, s2Length, fromIndex);2340}23412342return -1;2343}23442345/**2346* Answers the size of this String.2347*2348* @return the number of characters in this String2349*/2350public int length() {2351return lengthInternal();2352}23532354/**2355* Answers the size of this String. This method is to be used internally within the current package whenever2356* possible as the JIT compiler will take special precaution to avoid generating HCR guards for calls to this2357* method.2358*2359* @return the number of characters in this String2360*/2361int lengthInternal() {2362if (COMPACT_STRINGS) {2363return value.length >> coder;2364} else {2365return value.length >> 1;2366}2367}23682369/**2370* Compares the specified string to this String and compares the specified range of characters to determine if they are the same.2371*2372* @param thisStart2373* the starting offset in this String2374* @param string2375* the string to compare2376* @param start2377* the starting offset in string2378* @param length2379* the number of characters to compare2380* @return true if the ranges of characters is equal, false otherwise2381*2382* @throws NullPointerException2383* when string is null2384*/2385public boolean regionMatches(int thisStart, String string, int start, int length) {2386string.getClass(); // Implicit null check23872388String s1 = this;2389String s2 = string;23902391int s1len = s1.lengthInternal();2392int s2len = s2.lengthInternal();23932394if (start < 0 || s2len - start < length) {2395return false;2396}23972398if (thisStart < 0 || s1len - thisStart < length) {2399return false;2400}24012402return regionMatchesInternal(s1, s2, s1.value, s2.value, thisStart, start, length);2403}24042405private static boolean regionMatchesInternal(String s1, String s2, byte[] s1Value, byte[] s2Value, int s1Start, int s2Start, int length)2406{2407if (length <= 0) {2408return true;2409}24102411// Index of the last char to compare2412int end = length - 1;24132414if (COMPACT_STRINGS && ((compressionFlag == null) || ((s1.coder | s2.coder) == LATIN1))) {2415if (helpers.getByteFromArrayByIndex(s1Value, s1Start + end) != helpers.getByteFromArrayByIndex(s2Value, s2Start + end)) {2416return false;2417} else {2418for (int i = 0; i < end; ++i) {2419if (helpers.getByteFromArrayByIndex(s1Value, s1Start + i) != helpers.getByteFromArrayByIndex(s2Value, s2Start + i)) {2420return false;2421}2422}2423}2424} else {2425if (s1.charAtInternal(s1Start + end, s1Value) != s2.charAtInternal(s2Start + end, s2Value)) {2426return false;2427} else {2428for (int i = 0; i < end; ++i) {2429if (s1.charAtInternal(s1Start + i, s1Value) != s2.charAtInternal(s2Start + i, s2Value)) {2430return false;2431}2432}2433}2434}2435return true;2436}24372438/**2439* Compares the specified string to this String and compares the specified range of characters to determine if they are the same. When ignoreCase2440* is true, the case of the characters is ignored during the comparison.2441*2442* @param ignoreCase2443* specifies if case should be ignored2444* @param thisStart2445* the starting offset in this String2446* @param string2447* the string to compare2448* @param start2449* the starting offset in string2450* @param length2451* the number of characters to compare2452* @return true if the ranges of characters is equal, false otherwise2453*2454* @throws NullPointerException2455* when string is null2456*/2457public boolean regionMatches(boolean ignoreCase, int thisStart, String string, int start, int length) {2458if (!ignoreCase) {2459return regionMatches(thisStart, string, start, length);2460}24612462string.getClass(); // Implicit null check24632464String s1 = this;2465String s2 = string;24662467int s1len = s1.lengthInternal();2468int s2len = s2.lengthInternal();24692470if (thisStart < 0 || length > s1len - thisStart) {2471return false;2472}24732474if (start < 0 || length > s2len - start) {2475return false;2476}24772478if (length <= 0) {2479return true;2480}24812482int o1 = thisStart;2483int o2 = start;24842485// Upper bound index on the last char to compare2486int end = thisStart + length;24872488byte[] s1Value = s1.value;2489byte[] s2Value = s2.value;24902491if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {2492while (o1 < end) {2493byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);2494byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);24952496if ((byteAtO1 != byteAtO2)2497&& (!charValuesEqualIgnoreCase(helpers.byteToCharUnsigned(byteAtO1), helpers.byteToCharUnsigned(byteAtO2)))2498) {2499return false;2500}2501}2502} else {2503while (o1 < end) {2504char charAtO1 = s1.charAtInternal(o1++, s1Value);2505char charAtO2 = s2.charAtInternal(o2++, s2Value);25062507/*[IF JAVA_SPEC_VERSION >= 16]*/2508if (Character.isHighSurrogate(charAtO1) && Character.isHighSurrogate(charAtO2) && (o1 < end)) {2509int codepointAtO1 = Character.toCodePoint(charAtO1, s1.charAtInternal(o1++, s1Value));2510int codepointAtO2 = Character.toCodePoint(charAtO2, s2.charAtInternal(o2++, s2Value));2511if ((codepointAtO1 != codepointAtO2)2512&& (compareValue(codepointAtO1) != compareValue(codepointAtO2))2513) {2514return false;2515}2516}2517/*[ENDIF] JAVA_SPEC_VERSION >= 16 */25182519if ((charAtO1 != charAtO2)2520&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))2521) {2522return false;2523}2524}2525}25262527return true;2528}25292530/**2531* Replaces occurrences of the specified character with another character.2532*2533* @param oldChar2534* the character to replace2535* @param newChar2536* the replacement character2537* @return a String with occurrences of oldChar replaced by newChar2538*/2539public String replace(char oldChar, char newChar) {2540int index = indexOf(oldChar, 0);25412542if (index == -1) {2543return this;2544}25452546int len = lengthInternal();25472548// Check if the String is compressed2549if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2550if (newChar <= 255) {2551byte[] buffer = new byte[len];25522553compressedArrayCopy(value, 0, buffer, 0, len);25542555do {2556helpers.putByteInArrayByIndex(buffer, index++, (byte) newChar);2557} while ((index = indexOf(oldChar, index)) != -1);25582559return new String(buffer, LATIN1);2560} else {2561byte[] buffer = StringUTF16.newBytesFor(len);25622563StringLatin1.inflate(value, 0, buffer, 0, len);25642565do {2566helpers.putCharInArrayByIndex(buffer, index++, (char) newChar);2567} while ((index = indexOf(oldChar, index)) != -1);25682569return new String(buffer, UTF16);2570}2571} else {2572byte[] buffer = StringUTF16.newBytesFor(len);25732574decompressedArrayCopy(value, 0, buffer, 0, len);25752576do {2577helpers.putCharInArrayByIndex(buffer, index++, (char) newChar);2578} while ((index = indexOf(oldChar, index)) != -1);25792580return new String(buffer, UTF16);2581}2582}25832584/**2585* Compares the specified string to this String to determine if the specified string is a prefix.2586*2587* @param prefix2588* the string to look for2589* @return true when the specified string is a prefix of this String, false otherwise2590*2591* @throws NullPointerException2592* when prefix is null2593*/2594public boolean startsWith(String prefix) {2595return startsWith(prefix, 0);2596}25972598/**2599* Compares the specified string to this String, starting at the specified offset, to determine if the specified string is a prefix.2600*2601* @param prefix2602* the string to look for2603* @param start2604* the starting offset2605* @return true when the specified string occurs in this String at the specified offset, false otherwise2606*2607* @throws NullPointerException2608* when prefix is null2609*/2610public boolean startsWith(String prefix, int start) {2611if (prefix.length() == 1) {2612if (start < 0 || start >= this.length()) {2613return false;2614}2615return charAtInternal(start) == prefix.charAtInternal(0);2616}2617return regionMatches(start, prefix, 0, prefix.lengthInternal());2618}26192620/*[IF JAVA_SPEC_VERSION >= 11]*/2621/**2622* Strip leading and trailing white space from a string.2623*2624* @return a substring of the original containing no leading2625* or trailing white space2626*2627* @since 112628*/2629public String strip() {2630String result;26312632if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2633result = StringLatin1.strip(value);2634} else {2635result = StringUTF16.strip(value);2636}26372638return (result == null) ? this : result;2639}26402641/**2642* Strip leading white space from a string.2643*2644* @return a substring of the original containing no leading2645* white space2646*2647* @since 112648*/2649public String stripLeading() {2650String result;26512652if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2653result = StringLatin1.stripLeading(value);2654} else {2655result = StringUTF16.stripLeading(value);2656}26572658return (result == null) ? this : result;2659}26602661/**2662* Strip trailing white space from a string.2663*2664* @return a substring of the original containing no trailing2665* white space2666*2667* @since 112668*/2669public String stripTrailing() {2670String result;26712672if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2673result = StringLatin1.stripTrailing(value);2674} else {2675result = StringUTF16.stripTrailing(value);2676}26772678return (result == null) ? this : result;2679}26802681/**2682* Determine if the string contains only white space characters.2683*2684* @return true if the string is empty or contains only white space2685* characters, otherwise false.2686*2687* @since 112688*/2689public boolean isBlank() {2690int index;26912692if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2693index = StringLatin1.indexOfNonWhitespace(value);2694} else {2695index = StringUTF16.indexOfNonWhitespace(value);2696}26972698return index >= lengthInternal();2699}27002701/**2702* Returns a stream of substrings extracted from this string partitioned by line terminators.2703*2704* Line terminators recognized are line feed "\n", carriage return "\r", and carriage return2705* followed by line feed "\r\n".2706*2707* @return the stream of this string's substrings partitioned by line terminators2708*2709* @since 112710*/2711public Stream<String> lines() {2712if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2713return StringLatin1.lines(value);2714} else {2715return StringUTF16.lines(value);2716}2717}2718/*[ENDIF] JAVA_SPEC_VERSION >= 11 */27192720/**2721* Copies a range of characters into a new String.2722*2723* @param start2724* the offset of the first character2725* @return a new String containing the characters from start to the end of the string2726*2727* @throws IndexOutOfBoundsException2728* when {@code start < 0} or {@code start > length()}2729*/2730public String substring(int start) {2731if (start == 0) {2732return this;2733}2734if (start < 0) {2735throw new StringIndexOutOfBoundsException(start);2736}2737int len = lengthInternal();2738if (start <= len) {2739boolean isCompressed = false;2740// Check if the String is compressed2741if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2742isCompressed = true;2743}2744return new String(value, start, len - start, isCompressed, enableSharingInSubstringWhenOffsetIsZero);2745}2746throw new StringIndexOutOfBoundsException("begin " + start + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$2747}27482749/**2750* Copies a range of characters.2751*2752* @param start2753* the offset of the first character2754* @param end2755* the offset one past the last character2756* @return a String containing the characters from start to end - 12757*2758* @throws IndexOutOfBoundsException2759* when {@code start < 0, start > end} or {@code end > length()}2760*/2761public String substring(int start, int end) {2762int len = lengthInternal();2763if (start == 0 && end == len) {2764return this;2765}2766if ((start >= 0) && (start <= end) && (end <= len)) {2767boolean isCompressed = false;2768// Check if the String is compressed2769if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2770isCompressed = true;2771}2772return new String(value, start, end - start, isCompressed, enableSharingInSubstringWhenOffsetIsZero);2773}2774throw new StringIndexOutOfBoundsException("begin " + start + ", end " + end + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$2775}27762777/**2778* Copies the characters in this String to a character array.2779*2780* @return a character array containing the characters of this String2781*/2782public char[] toCharArray() {2783int len = lengthInternal();27842785char[] buffer = new char[len];27862787// Check if the String is compressed2788if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2789StringLatin1.inflate(value, 0, buffer, 0, len);2790} else {2791decompressedArrayCopy(value, 0, buffer, 0, len);2792}27932794return buffer;2795}27962797/**2798* Converts the characters in this String to lowercase, using the default Locale. To convert to lower case independent of any locale, use2799* toLowerCase(Locale.ROOT).2800*2801* @return a new String containing the lowercase characters equivalent to the characters in this String2802*/2803public String toLowerCase() {2804return toLowerCase(Locale.getDefault());2805}28062807private static int toLowerCase(int codePoint) {2808if (codePoint < 128) {2809if ('A' <= codePoint && codePoint <= 'Z') {2810return codePoint + ('a' - 'A');2811} else {2812return codePoint;2813}2814} else {2815return Character.toLowerCase(codePoint);2816}2817}28182819private static int toUpperCase(int codePoint) {2820if (codePoint < 128) {2821if ('a' <= codePoint && codePoint <= 'z') {2822return codePoint - ('a' - 'A');2823} else {2824return codePoint;2825}2826} else {2827return Character.toUpperCase(codePoint);2828}2829}28302831/**2832* Converts the characters in this String to lowercase, using the specified Locale.2833*2834* @param locale2835* the Locale2836* @return a String containing the lowercase characters equivalent to the characters in this String2837*/2838public String toLowerCase(Locale locale) {2839// check locale for null2840String language = locale.getLanguage();2841int sLength = lengthInternal();28422843if (sLength == 0) {2844return this;2845}28462847boolean useIntrinsic = helpers.supportsIntrinsicCaseConversion()2848&& (language == "en") //$NON-NLS-1$2849&& (sLength <= (Integer.MAX_VALUE / 2));28502851if (COMPACT_STRINGS && ((null == compressionFlag) || (coder == LATIN1))) {2852if (useIntrinsic) {2853byte[] output = new byte[sLength << coder];28542855if (helpers.toLowerIntrinsicLatin1(value, output, sLength)) {2856return new String(output, LATIN1);2857}2858}2859return StringLatin1.toLowerCase(this, value, locale);2860} else {2861if (useIntrinsic) {2862byte[] output = new byte[sLength << coder];28632864if (helpers.toLowerIntrinsicUTF16(value, output, sLength * 2)) {2865return new String(output, UTF16);2866}2867}2868return StringUTF16.toLowerCase(this, value, locale);2869}2870}28712872/**2873* Answers a string containing a concise, human-readable description of the receiver.2874*2875* @return this String2876*/2877public String toString() {2878return this;2879}28802881/**2882* Converts the characters in this String to uppercase, using the default Locale. To convert to upper case independent of any locale, use2883* toUpperCase(Locale.ROOT).2884*2885* @return a String containing the uppercase characters equivalent to the characters in this String2886*/2887public String toUpperCase() {2888return toUpperCase(Locale.getDefault());2889}28902891/**2892* Converts the characters in this String to uppercase, using the specified Locale.2893*2894* @param locale2895* the Locale2896* @return a String containing the uppercase characters equivalent to the characters in this String2897*/2898public String toUpperCase(Locale locale) {2899String language = locale.getLanguage();2900int sLength = lengthInternal();29012902if (sLength == 0) {2903return this;2904}29052906boolean useIntrinsic = helpers.supportsIntrinsicCaseConversion()2907&& (language == "en") //$NON-NLS-1$2908&& (sLength <= (Integer.MAX_VALUE / 2));29092910if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2911if (useIntrinsic) {2912byte[] output = new byte[sLength << coder];29132914if (helpers.toUpperIntrinsicLatin1(value, output, sLength)) {2915return new String(output, LATIN1);2916}2917}2918return StringLatin1.toUpperCase(this, value, locale);2919} else {2920if (useIntrinsic) {2921byte[] output = new byte[sLength << coder];29222923if (helpers.toUpperIntrinsicUTF16(value, output, sLength * 2)) {2924return new String(output, UTF16);2925}2926}2927return StringUTF16.toUpperCase(this, value, locale);2928}2929}29302931/**2932* Removes white space characters from the beginning and end of the string.2933*2934* @return a String with characters {@code <= \\u0020} removed from the beginning and the end2935*/2936public String trim() {2937int start = 0;2938int last = lengthInternal() - 1;2939int end = last;29402941// Check if the String is compressed2942if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {2943while ((start <= end) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, start)) <= ' ')) {2944start++;2945}29462947while ((end >= start) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, end)) <= ' ')) {2948end--;2949}29502951if (start == 0 && end == last) {2952return this;2953} else {2954return new String(value, start, end - start + 1, true);2955}2956} else {2957while ((start <= end) && (charAtInternal(start) <= ' ')) {2958start++;2959}29602961while ((end >= start) && (charAtInternal(end) <= ' ')) {2962end--;2963}29642965if (start == 0 && end == last) {2966return this;2967} else {2968return new String(value, start, end - start + 1, false);2969}2970}2971}29722973/**2974* Returns a String containing the characters in the specified character array. Modifying the character array after creating the String has no2975* effect on the String.2976*2977* @param data2978* the array of characters2979* @return the String2980*2981* @throws NullPointerException2982* when data is null2983*/2984public static String valueOf(char[] data) {2985return new String(data, 0, data.length);2986}29872988/**2989* Returns a String containing the specified characters in the character array. Modifying the character array after creating the String has no2990* effect on the String.2991*2992* @param data2993* the array of characters2994* @param start2995* the starting offset in the character array2996* @param length2997* the number of characters to use2998* @return the String2999*3000* @throws IndexOutOfBoundsException3001* when {@code length < 0, start < 0} or {@code start + length > data.length}3002* @throws NullPointerException3003* when data is null3004*/3005public static String valueOf(char[] data, int start, int length) {3006return new String(data, start, length);3007}30083009/**3010* Converts the specified character to its string representation.3011*3012* @param value3013* the character3014* @return the character converted to a string3015*/3016public static String valueOf(char value) {3017String string;30183019if (value <= 255) {3020if (COMPACT_STRINGS) {3021string = new String(compressedAsciiTable[value], 0, 1, true);3022} else {3023string = new String(decompressedAsciiTable[value], 0, 1, false);3024}3025} else {3026byte[] buffer = new byte[2];30273028helpers.putCharInArrayByIndex(buffer, 0, value);30293030string = new String(buffer, 0, 1, false);3031}30323033return string;3034}30353036/**3037* Converts the specified double to its string representation.3038*3039* @param value3040* the double3041* @return the double converted to a string3042*/3043public static String valueOf(double value) {3044return Double.toString(value);3045}30463047/**3048* Converts the specified float to its string representation.3049*3050* @param value3051* the float3052* @return the float converted to a string3053*/3054public static String valueOf(float value) {3055return Float.toString(value);3056}30573058/**3059* Converts the specified integer to its string representation.3060*3061* @param value3062* the integer3063* @return the integer converted to a string3064*/3065public static String valueOf(int value) {3066return Integer.toString(value);3067}30683069/**3070* Converts the specified long to its string representation.3071*3072* @param value3073* the long3074* @return the long converted to a string3075*/3076public static String valueOf(long value) {3077return Long.toString(value);3078}30793080/**3081* Converts the specified object to its string representation. If the object is null answer the string {@code "null"}, otherwise use3082* {@code toString()} to get the string representation.3083*3084* @param value3085* the object3086* @return the object converted to a string3087*/3088public static String valueOf(Object value) {3089return value != null ? value.toString() : "null"; //$NON-NLS-1$3090}30913092/**3093* Converts the specified boolean to its string representation. When the boolean is true answer {@code "true"}, otherwise answer3094* {@code "false"}.3095*3096* @param value3097* the boolean3098* @return the boolean converted to a string3099*/3100public static String valueOf(boolean value) {3101return value ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$3102}31033104/**3105* Answers whether the characters in the StringBuffer buffer are the same as those in this String.3106*3107* @param buffer3108* the StringBuffer to compare this String to3109* @return true when the characters in buffer are identical to those in this String. If they are not, false will be returned.3110*3111* @throws NullPointerException3112* when buffer is null3113*3114* @since 1.43115*/3116public boolean contentEquals(StringBuffer buffer) {3117synchronized (buffer) {3118int s1Length = lengthInternal();3119int sbLength = buffer.length();31203121if (s1Length != sbLength) {3122return false;3123}31243125byte[] s1Value = value;3126byte[] sbValue = buffer.getValue();31273128if (coder == buffer.getCoder()) {3129for (int i = 0; i < s1Value.length; ++i) {3130if (s1Value[i] != sbValue[i]) {3131return false;3132}3133}31343135return true;3136}31373138// String objects are always compressed if compression is possible, thus if the buffer is compressed and the3139// String object is not it is impossible for their contents to equal3140if (coder == UTF16) {3141return false;3142}31433144// Otherwise we have a LATIN1 String and a UTF16 StringBuffer3145return StringUTF16.contentEquals(s1Value, sbValue, s1Length);3146}3147}31483149/**3150* Determines whether a this String matches a given regular expression.3151*3152* @param expr3153* the regular expression to be matched3154* @return true if the expression matches, otherwise false3155*3156* @throws PatternSyntaxException3157* if the syntax of the supplied regular expression is not valid3158* @throws NullPointerException3159* if expr is null3160*3161* @since 1.43162*/3163public boolean matches(String expr) {3164return Pattern.matches(expr, this);3165}31663167/**3168* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.3169*3170* @param regex3171* the regular expression to match3172* @param substitute3173* the string to replace the matching substring with3174* @return the new string3175*3176* @throws NullPointerException3177* if expr is null3178*3179* @since 1.43180*/3181public String replaceAll(String regex, String substitute) {3182// this is a fast path to handle replacements of 1 character with another or the deletion of3183// a single character (common operations when dealing with things like package names, file3184// system paths etc). In these simple cases a linear scan of the string is all that is necessary3185// and we can avoid the cost of building a full regex pattern matcher3186if (regex != null && substitute != null && regex.lengthInternal() == 1 && !hasMetaChars(regex)) {3187int substituteLength = substitute.lengthInternal();3188int length = lengthInternal();3189if (substituteLength < 2) {3190if (COMPACT_STRINGS && isCompressed() && (substituteLength == 0 || substitute.isCompressed())) {3191byte[] newChars = new byte[length];3192byte toReplace = helpers.getByteFromArrayByIndex(regex.value, 0);3193byte replacement = (byte)-1; // assign dummy value that will never be used3194if (substituteLength == 1) {3195replacement = helpers.getByteFromArrayByIndex(substitute.value, 0);3196checkLastChar((char)replacement);3197}3198int newCharIndex = 0;3199for (int i = 0; i < length; ++i) {3200byte current = helpers.getByteFromArrayByIndex(value, i);3201if (current != toReplace) {3202helpers.putByteInArrayByIndex(newChars, newCharIndex++, current);3203} else if (substituteLength == 1) {3204helpers.putByteInArrayByIndex(newChars, newCharIndex++, replacement);3205}3206}3207return new String(newChars, 0, newCharIndex, true);3208} else if (!COMPACT_STRINGS || !isCompressed()) {3209byte[] newChars = StringUTF16.newBytesFor(length);3210char toReplace = regex.charAtInternal(0);3211char replacement = (char)-1; // assign dummy value that will never be used3212if (substituteLength == 1) {3213replacement = substitute.charAtInternal(0);3214checkLastChar(replacement);3215}3216int newCharIndex = 0;3217for (int i = 0; i < length; ++i) {3218char current = helpers.getCharFromArrayByIndex(value, i);3219if (current != toReplace) {3220helpers.putCharInArrayByIndex(newChars, newCharIndex++, current);3221} else if (substituteLength == 1) {3222helpers.putCharInArrayByIndex(newChars, newCharIndex++, replacement);3223}3224}3225return new String(newChars, 0, newCharIndex, false);3226}3227}3228}3229return Pattern.compile(regex).matcher(this).replaceAll(substitute);3230}32313232/**3233* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.3234*3235* @param expr3236* the regular expression to match3237* @param substitute3238* the string to replace the matching substring with3239* @return the new string3240*3241* @throws NullPointerException3242* if expr is null3243*3244* @since 1.43245*/3246public String replaceFirst(String expr, String substitute) {3247return Pattern.compile(expr).matcher(this).replaceFirst(substitute);3248}32493250/**3251* Splits this string around matches of the given regular expression. Calling this method is same as calling split(regex,0). Therefore, empty3252* string(s) at the end of the returned array will be discarded.3253*3254*3255* @param regex3256* Regular expression that is used as a delimiter3257* @return The array of strings which are split around the regex3258*3259* @throws PatternSyntaxException3260* if the syntax of regex is invalid3261*3262* @since 1.43263*/3264public String[] split(String regex) {3265return split(regex, 0);3266}32673268private static final char[] regexMetaChars = new char[]3269{ '.', '$', '|', '(', ')', '[', ']', '{', '}', '^', '?', '*', '+', '\\' };32703271private static final boolean hasMetaChars(String s) {3272for (int i = 0; i < s.lengthInternal(); ++i) {3273char ch = s.charAtInternal(i);32743275// Note the surrogate ranges are HIGH: \uD800-\uDBFF; LOW: \uDC00-\uDFFF3276// this check is, therefore, equivalent to returning true if the character3277// falls anywhere in this range including the range between MAX_LOW_SURROGATE3278// and MIN_HIGH_SURROGATE which happen to be adjacent3279if (ch >= Character.MIN_HIGH_SURROGATE3280&& ch <= Character.MAX_LOW_SURROGATE) { return true; }32813282for (int j = 0; j < regexMetaChars.length; ++j) {3283if (ch == regexMetaChars[j]) { return true; }3284}3285}3286return false;3287}32883289private static final boolean isSingleEscapeLiteral(String s) {3290if ((s != null) && (s.lengthInternal() == 2) && (s.charAtInternal(0) == '\\')) {3291char literal = s.charAtInternal(1);3292for (int j = 0; j < regexMetaChars.length; ++j) {3293if (literal == regexMetaChars[j]) return true;3294}3295}3296return false;3297}32983299/**3300* Splits this String using the given regular expression.3301*3302* max controls the number of times the regex is applied to this string.3303* If max is positive, then regex can be applied to this String max-1 times.3304* The returned array size can not be bigger than max, and the last element of3305* the returned array contains all input after the last match of the regex.3306* If max is negative or zero, then regex can be applied to this string as many times as3307* possible and there is no size limit in the returned array.3308* If max is 0, all the empty string(s) at the end of the returned array will be discarded.3309*3310* @param regex Regular expression that is used as a delimiter3311* @param max The threshold of the returned array3312* @return The array of strings which are split around the regex3313*3314* @throws PatternSyntaxException if the syntax of regex is invalid3315*3316* @since 1.43317*/3318public String[] split(String regex, int max) {3319// it is faster to handle simple splits inline (i.e. no fancy regex matching),3320// including single escaped literal character (e.g. \. \{),3321// so we test for a suitable string and handle this here if we can3322boolean singleEscapeLiteral = isSingleEscapeLiteral(regex);3323if ((regex != null) && (regex.lengthInternal() > 0) && (!hasMetaChars(regex) || singleEscapeLiteral)) {3324if (max == 1) {3325return new String[] { this };3326}3327java.util.ArrayList<String> parts = new java.util.ArrayList<String>((max > 0 && max < 100) ? max : 10);33283329byte[] chars = this.value;33303331final boolean compressed = COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1);33323333int start = 0, current = 0, end = lengthInternal();3334if (regex.lengthInternal() == 1 || singleEscapeLiteral) {3335// if matching single escaped character, use the second char.3336char splitChar = regex.charAtInternal(singleEscapeLiteral ? 1 : 0);3337while (current < end) {3338if (charAtInternal(current, chars) == splitChar) {3339parts.add(new String(chars, start, current - start, compressed));3340start = current + 1;3341if (max > 0 && parts.size() == max - 1) {3342parts.add(new String(chars, start, end - start, compressed));3343break;3344}3345}3346current = current + 1;3347}3348} else {3349int rLength = regex.lengthInternal();33503351byte[] splitChars = regex.value;33523353char firstChar = charAtInternal(0, regex.value);3354while (current < end) {3355if (charAtInternal(current, chars) == firstChar) {3356int idx = current + 1;3357int matchIdx = 1;3358while (matchIdx < rLength && idx < end) {3359if (charAtInternal(idx, chars) != charAtInternal(matchIdx, splitChars)) {3360break;3361}3362matchIdx++;3363idx++;3364}3365if (matchIdx == rLength) {3366parts.add(new String(chars, start, current - start, compressed));3367start = current + rLength;3368if (max > 0 && parts.size() == max - 1) {3369parts.add(new String(chars, start, end - start, compressed));3370break;3371}3372current = current + rLength;3373continue;3374}3375}3376current = current + 1;3377}3378}3379if (parts.size() == 0) {3380return new String[] { this };3381} else if (start <= current && parts.size() != max) {3382parts.add(new String(chars, start, current - start, compressed));3383}3384if (max == 0) {3385end = parts.size();3386while (end > 0 && parts.get(end - 1).lengthInternal() == 0) {3387end -= 1;3388parts.remove(end);3389}3390}3391return parts.toArray(new String[parts.size()]);3392}3393return Pattern.compile(regex).split(this, max);3394}33953396/**3397* Has the same result as the substring function, but is present so that String may implement the CharSequence interface.3398*3399* @param start3400* the offset the first character3401* @param end3402* the offset of one past the last character to include3403*3404* @return the subsequence requested3405*3406* @throws IndexOutOfBoundsException3407* when start or end is less than zero, start is greater than end, or end is greater than the length of the String.3408*3409* @see java.lang.CharSequence#subSequence(int, int)3410*3411* @since 1.43412*/3413public CharSequence subSequence(int start, int end) {3414return substring(start, end);3415}34163417/**3418* @param data3419* the byte array to convert to a String3420* @param start3421* the starting offset in the byte array3422* @param length3423* the number of bytes to convert3424*3425* @since 1.53426*/3427public String(int[] data, int start, int length) {3428if (start >= 0 && 0 <= length && length <= data.length - start) {3429if (COMPACT_STRINGS) {3430byte[] bytes = StringLatin1.toBytes(data, start, length);34313432if (bytes != null) {3433value = bytes;3434coder = LATIN1;3435} else {3436bytes = StringUTF16.toBytes(data, start, length);34373438value = bytes;3439coder = UTF16;34403441initCompressionFlag();3442}3443} else {3444byte[] bytes = StringUTF16.toBytes(data, start, length);34453446value = bytes;3447coder = UTF16;3448}3449} else {3450throw new StringIndexOutOfBoundsException();3451}3452}34533454/**3455* Creates a string from the contents of a StringBuilder.3456*3457* @param builder3458* the StringBuilder3459*3460* @since 1.53461*/3462public String(StringBuilder builder) {3463this(builder.toString());3464}34653466/**3467* Returns the Unicode character at the given point.3468*3469* @param index3470* the character index3471* @return the Unicode character value at the index3472*3473* @since 1.53474*/3475public int codePointAt(int index) {3476int len = lengthInternal();34773478if (index >= 0 && index < len) {3479// Check if the String is compressed3480if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {3481return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));3482} else {3483char high = charAtInternal(index);34843485if ((index < (len - 1)) && Character.isHighSurrogate(high)) {3486char low = charAtInternal(index + 1);34873488if (Character.isLowSurrogate(low)) {3489return Character.toCodePoint(high, low);3490}3491}34923493return high;3494}3495} else {3496throw new StringIndexOutOfBoundsException(index);3497}3498}34993500/**3501* Returns the Unicode character before the given point.3502*3503* @param index3504* the character index3505* @return the Unicode character value before the index3506*3507* @since 1.53508*/3509public int codePointBefore(int index) {3510int len = lengthInternal();35113512if (index > 0 && index <= len) {3513// Check if the String is compressed3514if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {3515return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));3516} else {3517char low = charAtInternal(index - 1);35183519if ((index > 1) && Character.isLowSurrogate(low)) {3520char high = charAtInternal(index - 2);35213522if (Character.isHighSurrogate(high)) {3523return Character.toCodePoint(high, low);3524}3525}35263527return low;3528}3529} else {3530throw new StringIndexOutOfBoundsException(index);3531}3532}35333534/**3535* Returns the total Unicode values in the specified range.3536*3537* @param start3538* first index3539* @param end3540* last index3541* @return the total Unicode values3542*3543* @since 1.53544*/3545public int codePointCount(int start, int end) {3546int len = lengthInternal();35473548if (start >= 0 && start <= end && end <= len) {3549// Check if the String is compressed3550if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {3551return end - start;3552} else {3553int count = 0;35543555for (int i = start; i < end; ++i) {3556if ((i < (end - 1))3557&& Character.isHighSurrogate(charAtInternal(i))3558&& Character.isLowSurrogate(charAtInternal(i + 1))) {3559++i;3560}35613562++count;3563}35643565return count;3566}3567} else {3568throw new IndexOutOfBoundsException();3569}3570}35713572/**3573* Returns the index of the code point that was offset by codePointCount.3574*3575* @param start3576* the position to offset3577* @param codePointCount3578* the code point count3579* @return the offset index3580*3581* @since 1.53582*/3583public int offsetByCodePoints(int start, int codePointCount) {3584int len = lengthInternal();35853586if (start >= 0 && start <= len) {3587// Check if the String is compressed3588if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {3589int index = start + codePointCount;35903591if (index > len) {3592throw new IndexOutOfBoundsException();3593} else {3594return index;3595}3596} else {3597int index = start;35983599if (codePointCount == 0) {3600return start;3601} else if (codePointCount > 0) {3602for (int i = 0; i < codePointCount; ++i) {3603if (index == len) {3604throw new IndexOutOfBoundsException();3605}36063607if ((index < (len - 1))3608&& Character.isHighSurrogate(charAtInternal(index))3609&& Character.isLowSurrogate(charAtInternal(index + 1))) {3610index++;3611}36123613index++;3614}3615} else {3616for (int i = codePointCount; i < 0; ++i) {3617if (index < 1) {3618throw new IndexOutOfBoundsException();3619}36203621if ((index > 1)3622&& Character.isLowSurrogate(charAtInternal(index - 1))3623&& Character.isHighSurrogate(charAtInternal(index - 2))) {3624index--;3625}36263627index--;3628}3629}36303631return index;3632}3633} else {3634throw new IndexOutOfBoundsException();3635}3636}36373638/**3639* Compares the content of the character sequence to this String3640*3641* @param sequence3642* the character sequence3643* @return {@code true} if the content of this String is equal to the character sequence, {@code false} otherwise.3644*3645* @since 1.53646*/3647public boolean contentEquals(CharSequence sequence) {3648int len = lengthInternal();36493650if (len != sequence.length()) {3651return false;3652}36533654for (int i = 0; i < len; ++i) {3655if (charAtInternal(i) != sequence.charAt(i)) {3656return false;3657}3658}36593660return true;3661}36623663/**3664* @param sequence3665* the sequence to compare to3666* @return {@code true} if this String contains the sequence, {@code false} otherwise.3667*3668* @since 1.53669*/3670public boolean contains(CharSequence sequence) {3671int len = lengthInternal();36723673int sequencelen = sequence.length();36743675if (sequencelen > len) {3676return false;3677}36783679int start = 0;36803681if (sequencelen > 0) {3682if (sequencelen + start > len) {3683return false;3684}36853686char charAt0 = sequence.charAt(0);36873688while (true) {3689int i = indexOf(charAt0, start);36903691if (i == -1 || sequencelen + i > len) {3692return false;3693}36943695int o1 = i;3696int o2 = 0;36973698while (++o2 < sequencelen && charAtInternal(++o1) == sequence.charAt(o2))3699;37003701if (o2 == sequencelen) {3702return true;3703}37043705start = i + 1;3706}3707} else {3708return true;3709}3710}37113712/**3713* @param sequence13714* the old character sequence3715* @param sequence23716* the new character sequence3717* @return the new String3718*3719* @since 1.53720*/3721public String replace(CharSequence sequence1, CharSequence sequence2) {3722if (sequence2 == null) {3723throw new NullPointerException();3724}37253726int len = lengthInternal();37273728int sequence1len = sequence1.length();37293730if (sequence1len == 0) {3731int sequence2len = sequence2.length();37323733if ((sequence2len != 0) && (len >= ((Integer.MAX_VALUE - len) / sequence2len))) {3734/*[MSG "K0D01", "Array capacity exceeded"]*/3735throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$3736}37373738StringBuilder builder = new StringBuilder(len + ((len + 1) * sequence2len));37393740builder.append(sequence2);37413742for (int i = 0; i < len; ++i) {3743builder.append(charAt(i)).append(sequence2);3744}37453746return builder.toString();3747} else {3748StringBuilder builder = new StringBuilder();37493750int start = 0;3751int copyStart = 0;37523753char charAt0 = sequence1.charAt(0);37543755while (start < len) {3756int firstIndex = indexOf(charAt0, start);37573758if (firstIndex == -1) {3759break;3760}37613762boolean found = true;37633764if (sequence1len > 1) {3765if (sequence1len > len - firstIndex) {3766/* the tail of this string is too short to find sequence1 */3767break;3768}37693770for (int i = 1; i < sequence1len; i++) {3771if (charAt(firstIndex + i) != sequence1.charAt(i)) {3772found = false;3773break;3774}3775}3776}37773778if (found) {3779builder.append(substring(copyStart, firstIndex)).append(sequence2);37803781copyStart = start = firstIndex + sequence1len;3782} else {3783start = firstIndex + 1;3784}3785}37863787if (builder.length() == 0 && copyStart == 0) {3788return this;3789}37903791builder.append(substring(copyStart));37923793return builder.toString();3794}3795}37963797/**3798* Format the receiver using the specified format and args.3799*3800* @param format3801* the format to use3802* @param args3803* the format arguments to use3804*3805* @return the formatted result3806*3807* @see java.util.Formatter#format(String, Object...)3808*/3809public static String format(String format, Object... args) {3810return new Formatter().format(format, args).toString();3811}38123813/**3814* Format the receiver using the specified local, format and args.3815*3816* @param locale3817* the locale used to create the Formatter, may be null3818* @param format3819* the format to use3820* @param args3821* the format arguments to use3822*3823* @return the formatted result3824*3825* @see java.util.Formatter#format(String, Object...)3826*/3827public static String format(Locale locale, String format, Object... args) {3828return new Formatter(locale).format(format, args).toString();3829}38303831private static final java.io.ObjectStreamField[] serialPersistentFields = {};38323833/**3834* Answers if this String has no characters, a length of zero.3835*3836* @return true if this String has no characters, false otherwise3837*3838* @since 1.63839*3840* @see #length3841*/3842public boolean isEmpty() {3843return lengthInternal() == 0;3844}38453846/**3847* Converts the byte array to a String using the specified Charset.3848*3849* @param data3850* the byte array to convert to a String3851* @param charset3852* the Charset to use3853*3854* @throws NullPointerException3855* when data is null3856*3857* @since 1.63858*3859* @see #String(byte[], int, int, Charset)3860* @see #getBytes(Charset)3861*/3862public String(byte[] data, Charset charset) {3863this(data, 0, data.length, charset);3864}38653866/**3867* Converts the byte array to a String using the specified Charset.3868*3869* @param data3870* the byte array to convert to a String3871* @param start3872* the starting offset in the byte array3873* @param length3874* the number of bytes to convert3875* @param charset3876* the Charset to use3877*3878* @throws IndexOutOfBoundsException3879* when {@code length < 0, start < 0} or {@code start + length > data.length}3880* @throws NullPointerException3881* when data is null3882*3883* @since 1.63884*3885* @see #String(byte[], Charset)3886* @see #getBytes(Charset)3887*/3888public String(byte[] data, int start, int length, Charset charset) {3889if (charset == null) {3890throw new NullPointerException();3891}38923893if (start >= 0 && 0 <= length && length <= data.length - start) {3894StringCoding.Result scResult = StringCoding.decode(charset, data, start, length);38953896value = scResult.value;3897coder = scResult.coder;38983899if (COMPACT_STRINGS) {3900initCompressionFlag();3901}3902} else {3903throw new StringIndexOutOfBoundsException();3904}3905}39063907/**3908* Converts this String to a byte encoding using the specified Charset.3909*3910* @param charset3911* the Charset to use3912* @return the byte array encoding of this String3913*3914* @since 1.63915*/3916public byte[] getBytes(Charset charset) {3917return StringCoding.encode(charset, coder, value);3918}39193920/**3921* Creates a new String by putting each element together joined by the delimiter. If an element is null, then "null" is used as string to join.3922*3923* @param delimiter3924* Used as joiner to put elements together3925* @param elements3926* Elements to be joined3927* @return string of joined elements by delimiter3928* @throws NullPointerException3929* if one of the arguments is null3930*3931*/3932public static String join(CharSequence delimiter, CharSequence... elements) {3933StringJoiner stringJoiner = new StringJoiner(delimiter);39343935for (CharSequence element : elements) {3936stringJoiner.add(element);3937}39383939return stringJoiner.toString();3940}39413942/**3943* Creates a new String by putting each element together joined by the delimiter. If an element is null, then "null" is used as string to join.3944*3945* @param delimiter3946* Used as joiner to put elements together3947* @param elements3948* Elements to be joined3949* @return string of joined elements by delimiter3950* @throws NullPointerException3951* if one of the arguments is null3952*3953*/3954public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {3955StringJoiner stringJoiner = new StringJoiner(delimiter);39563957Iterator<? extends CharSequence> elementsIterator = elements.iterator();39583959while (elementsIterator.hasNext()) {3960stringJoiner.add(elementsIterator.next());3961}39623963return stringJoiner.toString();3964}39653966static void checkBoundsBeginEnd(int begin, int end, int length) {3967if ((begin >= 0) && (begin <= end) && (end <= length)) {3968return;3969}3970throw newStringIndexOutOfBoundsException(begin, end, length);3971}39723973@Override3974public IntStream chars() {3975Spliterator.OfInt spliterator;39763977if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {3978spliterator = new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE);3979} else {3980spliterator = new StringUTF16.CharsSpliterator(value, Spliterator.IMMUTABLE);3981}39823983return StreamSupport.intStream(spliterator, false);3984}39853986@Override3987public IntStream codePoints() {3988Spliterator.OfInt spliterator;39893990if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {3991spliterator = new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE);3992} else {3993spliterator = new StringUTF16.CodePointsSpliterator(value, Spliterator.IMMUTABLE);3994}39953996return StreamSupport.intStream(spliterator, false);3997}39983999/*4000* Internal API, assuming no modification to the byte array returned.4001*/4002byte[] value() {4003return value;4004}40054006/*[IF JAVA_SPEC_VERSION >= 11]*/4007/**4008* Returns a string object containing the character (Unicode code point)4009* specified.4010*4011* @param codePoint4012* a Unicode code point.4013* @return a string containing the character (Unicode code point) supplied.4014* @throws IllegalArgumentException4015* if the codePoint is not a valid Unicode code point.4016* @since 114017*/4018static String valueOfCodePoint(int codePoint) {4019String string;4020if ((codePoint < Character.MIN_CODE_POINT) || (codePoint > Character.MAX_CODE_POINT)) {4021/*[MSG "K0800", "Invalid Unicode code point - {0}"]*/4022throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0800", Integer.toString(codePoint))); //$NON-NLS-1$4023} else if (codePoint <= 255) {4024if (COMPACT_STRINGS) {4025string = new String(compressedAsciiTable[codePoint], LATIN1);4026} else {4027string = new String(decompressedAsciiTable[codePoint], UTF16);4028}4029} else if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {4030byte[] buffer = new byte[2];4031helpers.putCharInArrayByIndex(buffer, 0, (char) codePoint);4032string = new String(buffer, UTF16);4033} else {4034byte[] buffer = new byte[4];4035helpers.putCharInArrayByIndex(buffer, 0, Character.highSurrogate(codePoint));4036helpers.putCharInArrayByIndex(buffer, 1, Character.lowSurrogate(codePoint));4037string = new String(buffer, UTF16);4038}4039return string;4040}40414042/**4043* Returns a string whose value is the concatenation of this string repeated4044* count times.4045*4046* @param count4047* a positive integer indicating the number of times to be repeated4048* @return a string whose value is the concatenation of this string repeated count times4049* @throws IllegalArgumentException4050* if the count is negative4051* @since 114052*/4053public String repeat(int count) {4054if (count < 0) {4055throw new IllegalArgumentException();4056} else if (count == 0 || isEmpty()) {4057return ""; //$NON-NLS-1$4058} else if (count == 1) {4059return this;4060}40614062int length = lengthInternal();4063if (length > Integer.MAX_VALUE / count) {4064/*[MSG "K0D01", "Array capacity exceeded"]*/4065throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$4066}4067int repeatlen = length * count;40684069if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {4070byte[] buffer = new byte[repeatlen];40714072for (int i = 0; i < count; i++) {4073compressedArrayCopy(value, 0, buffer, i * length, length);4074}40754076return new String(buffer, LATIN1);4077} else {4078byte[] buffer = StringUTF16.newBytesFor(repeatlen);40794080for (int i = 0; i < count; i++) {4081decompressedArrayCopy(value, 0, buffer, i * length, length);4082}40834084return new String(buffer, UTF16);4085}4086}4087/*[ENDIF] JAVA_SPEC_VERSION >= 11 */40884089/*[ELSE] Sidecar19-SE*/4090// DO NOT CHANGE OR MOVE THIS LINE4091// IT MUST BE THE FIRST THING IN THE INITIALIZATION4092private static final long serialVersionUID = -6849794470754667710L;40934094/**4095* Determines whether String compression is enabled.4096*/4097static final boolean COMPACT_STRINGS = com.ibm.oti.vm.VM.J9_STRING_COMPRESSION_ENABLED;40984099/**4100* CaseInsensitiveComparator compares Strings ignoring the case of the characters.4101*/4102private static final class CaseInsensitiveComparator implements Comparator<String>, Serializable {4103static final long serialVersionUID = 8575799808933029326L;41044105/**4106* Compare the two objects to determine the relative ordering.4107*4108* @param o14109* an Object to compare4110* @param o24111* an Object to compare4112* @return an int < 0 if object1 is less than object2, 0 if they are equal, and > 0 if object1 is greater4113*4114* @exception ClassCastException4115* when objects are not the correct type4116*/4117public int compare(String o1, String o2) {4118return o1.compareToIgnoreCase(o2);4119}4120};41214122/**4123* A Comparator which compares Strings ignoring the case of the characters.4124*/4125public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();41264127// Used to represent the value of an empty String4128private static final char[] emptyValue = new char[0];41294130// Used to extract the value of a single ASCII character String by the integral value of the respective character as4131// an index into this table4132private static final char[][] compressedAsciiTable;41334134private static final char[][] decompressedAsciiTable;41354136// Used to access compression related helper methods4137private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();41384139static class StringCompressionFlag implements Serializable {4140private static final long serialVersionUID = 1346155847239551492L;4141}41424143// Singleton used by all String instances to indicate a non-compressed string has been4144// allocated. JIT attempts to fold away the null check involving this static if the4145// StringCompressionFlag class has not been initialized and patches the code to bring back4146// the null check if a non-compressed String is constructed.4147private static StringCompressionFlag compressionFlag;41484149// Represents the bit in count field to test for whether this String backing array is not compressed4150// under String compression mode. This bit is not used when String compression is disabled.4151private static final int uncompressedBit = 0x80000000;41524153private static String[] stringArray;4154private static final int stringArraySize = 10;41554156private static class UnsafeHelpers {4157public final static long valueFieldOffset = getValueFieldOffset();41584159static long getValueFieldOffset() {4160try {4161return Unsafe.getUnsafe().objectFieldOffset(String.class.getDeclaredField("value")); //$NON-NLS-1$4162} catch (NoSuchFieldException e) {4163throw new RuntimeException(e);4164}4165}4166}41674168/**4169* This is a System property to enable sharing of the underlying value array in {@link #String.substring(int)} and4170* {@link #String.substring(int, int)} if the offset is zero.4171*/4172static boolean enableSharingInSubstringWhenOffsetIsZero;41734174private final char[] value;4175private final int count;4176private int hash;41774178static {4179stringArray = new String[stringArraySize];41804181compressedAsciiTable = new char[256][];41824183for (int i = 0; i < compressedAsciiTable.length; ++i) {4184char[] asciiValue = new char[1];41854186helpers.putByteInArrayByIndex(asciiValue, 0, (byte) i);41874188compressedAsciiTable[i] = asciiValue;4189}41904191decompressedAsciiTable = new char[256][];41924193for (int i = 0; i < decompressedAsciiTable.length; ++i) {4194char[] asciiValue = new char[1];41954196helpers.putCharInArrayByIndex(asciiValue, 0, (char) i);41974198decompressedAsciiTable[i] = asciiValue;4199}4200}42014202static void initCompressionFlag() {4203if (compressionFlag == null) {4204compressionFlag = new StringCompressionFlag();4205}4206}42074208/**4209* Determines whether the input character array can be encoded as a compact4210* Latin1 string.4211*4212* <p>This API implicitly assumes the following:4213* <blockquote><pre>4214* - {@code length >= 0}4215* - {@code start >= 0}4216* - {@code start + length <= data.length}4217* <blockquote><pre>4218*4219* @param c the array of characters to check4220* @param start the starting offset in the character array4221* @param length the number of characters to check starting at {@code start}4222* @return {@code true} if the input character array can be encoded4223* using the Latin1 encoding; {@code false} otherwise4224*/4225static boolean canEncodeAsLatin1(char[] c, int start, int length) {4226for (int i = start; i < start + length; ++i) {4227if (c[i] > 255) {4228return false;4229}4230}42314232return true;4233}42344235static void compress(byte[] array1, int start1, byte[] array2, int start2, int length) {4236for (int i = 0; i < length; ++i) {4237helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));4238}4239}42404241static void compress(char[] array1, int start1, byte[] array2, int start2, int length) {4242for (int i = 0; i < length; ++i) {4243helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));4244}4245}42464247static void compress(byte[] array1, int start1, char[] array2, int start2, int length) {4248for (int i = 0; i < length; ++i) {4249helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));4250}4251}42524253static void compress(char[] array1, int start1, char[] array2, int start2, int length) {4254for (int i = 0; i < length; ++i) {4255helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));4256}4257}42584259static void decompress(byte[] array1, int start1, byte[] array2, int start2, int length) {4260for (int i = 0; i < length; ++i) {4261helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));4262}4263}42644265static void decompress(char[] array1, int start1, byte[] array2, int start2, int length) {4266for (int i = 0; i < length; ++i) {4267helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));4268}4269}42704271static void decompress(byte[] array1, int start1, char[] array2, int start2, int length) {4272for (int i = 0; i < length; ++i) {4273helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));4274}4275}42764277static void decompress(char[] array1, int start1, char[] array2, int start2, int length) {4278for (int i = 0; i < length; ++i) {4279helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));4280}4281}42824283static void compressedArrayCopy(byte[] array1, int start1, byte[] array2, int start2, int length) {4284if (array1 == array2 && start1 < start2) {4285for (int i = length - 1; i >= 0; --i) {4286helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));4287}4288} else {4289for (int i = 0; i < length; ++i) {4290helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));4291}4292}4293}42944295static void compressedArrayCopy(byte[] array1, int start1, char[] array2, int start2, int length) {4296for (int i = 0; i < length; ++i) {4297helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));4298}4299}43004301static void compressedArrayCopy(char[] array1, int start1, byte[] array2, int start2, int length) {4302for (int i = 0; i < length; ++i) {4303helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));4304}4305}43064307static void compressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {4308if (array1 == array2 && start1 < start2) {4309for (int i = length - 1; i >= 0; --i) {4310helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));4311}4312} else {4313for (int i = 0; i < length; ++i) {4314helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));4315}4316}4317}43184319static void decompressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {4320System.arraycopy(array1, start1, array2, start2, length);4321}43224323boolean isCompressed() {4324// Check if the String is compressed4325if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {4326return true;4327} else {4328return false;4329}4330}43314332/**4333* Answers an empty string.4334*/4335public String() {4336value = emptyValue;4337count = 0;4338}43394340/**4341* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not4342* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.4343*4344* @param data4345* the byte array to convert to a String4346*4347* @throws NullPointerException4348* when data is null4349*4350* @see #getBytes()4351* @see #getBytes(int, int, byte[], int)4352* @see #getBytes(String)4353* @see #valueOf(boolean)4354* @see #valueOf(char)4355* @see #valueOf(char[])4356* @see #valueOf(char[], int, int)4357* @see #valueOf(double)4358* @see #valueOf(float)4359* @see #valueOf(int)4360* @see #valueOf(long)4361* @see #valueOf(Object)4362*/4363public String(byte[] data) {4364this(data, 0, data.length);4365}43664367/**4368* Converts the byte array to a String, setting the high byte of every character to the specified value.4369*4370* @param data4371* the byte array to convert to a String4372* @param high4373* the high byte to use4374*4375* @throws NullPointerException4376* when data is null4377*4378* @deprecated Use String(byte[]) or String(byte[], String) instead4379*/4380@Deprecated4381public String(byte[] data, int high) {4382this(data, high, 0, data.length);4383}43844385/**4386* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not4387* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.4388*4389* @param data4390* the byte array to convert to a String4391* @param start4392* the starting offset in the byte array4393* @param length4394* the number of bytes to convert4395*4396* @throws IndexOutOfBoundsException4397* when {@code length < 0, start < 0} or {@code start + length > data.length}4398* @throws NullPointerException4399* when data is null4400*4401* @see #getBytes()4402* @see #getBytes(int, int, byte[], int)4403* @see #getBytes(String)4404* @see #valueOf(boolean)4405* @see #valueOf(char)4406* @see #valueOf(char[])4407* @see #valueOf(char[], int, int)4408* @see #valueOf(double)4409* @see #valueOf(float)4410* @see #valueOf(int)4411* @see #valueOf(long)4412* @see #valueOf(Object)4413*/4414public String(byte[] data, int start, int length) {4415data.getClass(); // Implicit null check44164417if (start >= 0 && 0 <= length && length <= data.length - start) {4418char[] buffer = StringCoding.decode(data, start, length);44194420if (COMPACT_STRINGS) {4421if (canEncodeAsLatin1(buffer, 0, buffer.length)) {4422value = new char[(buffer.length + 1) >>> 1];4423count = buffer.length;44244425compress(buffer, 0, value, 0, buffer.length);4426} else {4427value = buffer;4428count = buffer.length | uncompressedBit;44294430initCompressionFlag();4431}4432} else {4433value = buffer;4434count = buffer.length;4435}4436} else {4437throw new StringIndexOutOfBoundsException();4438}4439}44404441/**4442* Converts the byte array to a String, setting the high byte of every character to the specified value.4443*4444* @param data4445* the byte array to convert to a String4446* @param high4447* the high byte to use4448* @param start4449* the starting offset in the byte array4450* @param length4451* the number of bytes to convert4452*4453* @throws IndexOutOfBoundsException4454* when {@code length < 0, start < 0} or {@code start + length > data.length}4455* @throws NullPointerException4456* when data is null4457*4458* @deprecated Use String(byte[], int, int) instead4459*/4460@Deprecated4461public String(byte[] data, int high, int start, int length) {4462data.getClass(); // Implicit null check44634464if (start >= 0 && 0 <= length && length <= data.length - start) {4465if (COMPACT_STRINGS) {4466if (high == 0) {4467value = new char[(length + 1) >>> 1];4468count = length;44694470compressedArrayCopy(data, start, value, 0, length);4471} else {4472value = new char[length];4473count = length | uncompressedBit;44744475high <<= 8;44764477for (int i = 0; i < length; ++i) {4478value[i] = (char) (high + (data[start++] & 0xff));4479}44804481initCompressionFlag();4482}44834484} else {4485value = new char[length];4486count = length;44874488high <<= 8;44894490for (int i = 0; i < length; ++i) {4491value[i] = (char) (high + (data[start++] & 0xff));4492}4493}4494} else {4495throw new StringIndexOutOfBoundsException();4496}4497}44984499/**4500* Converts the byte array to a String using the specified encoding.4501*4502* @param data4503* the byte array to convert to a String4504* @param start4505* the starting offset in the byte array4506* @param length4507* the number of bytes to convert4508* @param encoding4509* the encoding4510*4511* @throws IndexOutOfBoundsException4512* when {@code length < 0, start < 0} or {@code start + length > data.length}4513* @throws UnsupportedEncodingException4514* when encoding is not supported4515* @throws NullPointerException4516* when data is null4517*4518* @see #getBytes()4519* @see #getBytes(int, int, byte[], int)4520* @see #getBytes(String)4521* @see #valueOf(boolean)4522* @see #valueOf(char)4523* @see #valueOf(char[])4524* @see #valueOf(char[], int, int)4525* @see #valueOf(double)4526* @see #valueOf(float)4527* @see #valueOf(int)4528* @see #valueOf(long)4529* @see #valueOf(Object)4530* @see UnsupportedEncodingException4531*/4532public String(byte[] data, int start, int length, final String encoding) throws UnsupportedEncodingException {4533encoding.getClass(); // Implicit null check45344535data.getClass(); // Implicit null check45364537if (start >= 0 && 0 <= length && length <= data.length - start) {4538char[] buffer = StringCoding.decode(encoding, data, start, length);45394540if (COMPACT_STRINGS) {4541if (canEncodeAsLatin1(buffer, 0, buffer.length)) {4542value = new char[(buffer.length + 1) >>> 1];4543count = buffer.length;45444545compress(buffer, 0, value, 0, buffer.length);4546} else {4547value = buffer;4548count = buffer.length | uncompressedBit;45494550initCompressionFlag();4551}4552} else {4553value = buffer;4554count = buffer.length;4555}4556} else {4557throw new StringIndexOutOfBoundsException();4558}4559}45604561/**4562* Converts the byte array to a String using the specified encoding.4563*4564* @param data4565* the byte array to convert to a String4566* @param encoding4567* the encoding4568*4569* @throws UnsupportedEncodingException4570* when encoding is not supported4571* @throws NullPointerException4572* when data is null4573*4574* @see #getBytes()4575* @see #getBytes(int, int, byte[], int)4576* @see #getBytes(String)4577* @see #valueOf(boolean)4578* @see #valueOf(char)4579* @see #valueOf(char[])4580* @see #valueOf(char[], int, int)4581* @see #valueOf(double)4582* @see #valueOf(float)4583* @see #valueOf(int)4584* @see #valueOf(long)4585* @see #valueOf(Object)4586* @see UnsupportedEncodingException4587*/4588public String(byte[] data, String encoding) throws UnsupportedEncodingException {4589this(data, 0, data.length, encoding);4590}45914592private String(String s, char c) {4593if (s == null) {4594s = "null"; //$NON-NLS-1$4595}45964597int slen = s.lengthInternal();45984599int concatlen = slen + 1;4600if (concatlen < 0) {4601/*[MSG "K0D01", "Array capacity exceeded"]*/4602throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$4603}46044605if (COMPACT_STRINGS) {4606// Check if the String is compressed4607if ((null == compressionFlag || s.count >= 0) && c <= 255) {4608value = new char[(concatlen + 1) >>> 1];4609count = concatlen;46104611compressedArrayCopy(s.value, 0, value, 0, slen);46124613helpers.putByteInArrayByIndex(value, slen, (byte) c);4614} else {4615value = new char[concatlen];4616count = (concatlen) | uncompressedBit;46174618// Check if the String is compressed4619if (COMPACT_STRINGS && s.count >= 0) {4620decompress(s.value, 0, value, 0, slen);4621} else {4622decompressedArrayCopy(s.value, 0, value, 0, slen);4623}4624value[slen] = c;46254626initCompressionFlag();4627}4628} else {4629value = new char[concatlen];4630count = concatlen;46314632System.arraycopy(s.value, 0, value, 0, slen);46334634value[slen] = c;4635}4636}46374638/**4639* Initializes this String to contain the characters in the specified character array. Modifying the character array after creating the String has4640* no effect on the String.4641*4642* @param data4643* the array of characters4644*4645* @throws NullPointerException4646* when data is null4647*/4648public String(char[] data) {4649this(data, 0, data.length);4650}46514652/**4653* Initializes this String to use the specified character array. The character array should not be modified after the String is created.4654*4655* @param data4656* a non-null array of characters4657*/4658String(char[] data, boolean ignore) {4659if (COMPACT_STRINGS) {4660if (canEncodeAsLatin1(data, 0, data.length)) {4661value = new char[(data.length + 1) >>> 1];4662count = data.length;46634664compress(data, 0, value, 0, data.length);4665} else {4666value = new char[data.length];4667count = data.length | uncompressedBit;46684669System.arraycopy(data, 0, value, 0, data.length);46704671initCompressionFlag();4672}4673} else {4674value = new char[data.length];4675count = data.length;46764677System.arraycopy(data, 0, value, 0, data.length);4678}4679}46804681/**4682* Initializes this String to contain the specified characters in the character array. Modifying the character array after creating the String has4683* no effect on the String.4684*4685* @param data4686* the array of characters4687* @param start4688* the starting offset in the character array4689* @param length4690* the number of characters to use4691*4692* @throws IndexOutOfBoundsException4693* when {@code length < 0, start < 0} or {@code start + length > data.length}4694* @throws NullPointerException4695* when data is null4696*/4697public String(char[] data, int start, int length) {4698if (start >= 0 && 0 <= length && length <= data.length - start) {4699if (COMPACT_STRINGS) {4700if (canEncodeAsLatin1(data, start, length)) {4701value = new char[(length + 1) >>> 1];4702count = length;47034704compress(data, start, value, 0, length);4705} else {4706value = new char[length];4707count = length | uncompressedBit;47084709System.arraycopy(data, start, value, 0, length);47104711initCompressionFlag();4712}4713} else {4714value = new char[length];4715count = length;47164717System.arraycopy(data, start, value, 0, length);4718}4719} else {4720throw new StringIndexOutOfBoundsException();4721}4722}47234724String(char[] data, int start, int length, boolean compressed) {4725if (COMPACT_STRINGS) {4726if (length == 0) {4727value = emptyValue;4728count = 0;4729} else if (length == 1) {4730if (compressed) {4731char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));47324733value = compressedAsciiTable[theChar];4734count = 1;47354736hash = theChar;4737} else {47384739char theChar = data[start];47404741if (theChar <= 255) {4742value = decompressedAsciiTable[theChar];4743} else {4744value = new char[] { theChar };4745}47464747count = 1 | uncompressedBit;47484749hash = theChar;47504751initCompressionFlag();4752}4753} else {4754if (compressed) {4755if (start == 0) {4756value = data;4757count = length;4758} else {4759value = new char[(length + 1) >>> 1];4760count = length;47614762compressedArrayCopy(data, start, value, 0, length);4763}4764} else {4765if (start == 0) {4766value = data;4767count = length | uncompressedBit;4768} else {4769value = new char[length];4770count = length | uncompressedBit;47714772System.arraycopy(data, start, value, 0, length);4773}47744775initCompressionFlag();4776}4777}4778} else {4779if (length == 0) {4780value = emptyValue;4781count = 0;4782} else if (length == 1 && data[start] <= 255) {4783char theChar = data[start];47844785value = decompressedAsciiTable[theChar];4786count = 1;47874788hash = theChar;4789} else {4790if (start == 0) {4791value = data;4792count = length;4793} else {4794value = new char[length];4795count = length;47964797System.arraycopy(data, start, value, 0, length);4798}4799}4800}4801}48024803String(char[] data, int start, int length, boolean compressed, boolean sharingIsAllowed) {4804if (COMPACT_STRINGS) {4805if (length == 0) {4806value = emptyValue;4807count = 0;4808} else if (length == 1) {4809if (compressed) {4810char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));48114812value = compressedAsciiTable[theChar];4813count = 1;48144815hash = theChar;4816} else {4817char theChar = data[start];48184819if (theChar <= 255) {4820value = decompressedAsciiTable[theChar];4821} else {4822value = new char[] { theChar };4823}48244825count = 1 | uncompressedBit;48264827hash = theChar;48284829initCompressionFlag();4830}4831} else {4832if (compressed) {4833if (start == 0 && sharingIsAllowed) {4834value = data;4835count = length;4836} else {4837value = new char[(length + 1) >>> 1];4838count = length;48394840compressedArrayCopy(data, start, value, 0, length);4841}4842} else {4843if (start == 0 && sharingIsAllowed) {4844value = data;4845count = length | uncompressedBit;4846} else {4847value = new char[length];4848count = length | uncompressedBit;48494850System.arraycopy(data, start, value, 0, length);4851}48524853initCompressionFlag();4854}4855}4856} else {4857if (length == 0) {4858value = emptyValue;4859count = 0;4860} else if (length == 1 && data[start] <= 255) {4861char theChar = data[start];48624863value = decompressedAsciiTable[theChar];4864count = 1;48654866hash = theChar;4867} else {4868if (start == 0 && sharingIsAllowed) {4869value = data;4870count = length;4871} else {4872value = new char[length];4873count = length;48744875System.arraycopy(data, start, value, 0, length);4876}4877}4878}4879}48804881/**4882* Creates a string that is a copy of another string4883*4884* @param string4885* the String to copy4886*/4887public String(String string) {4888value = string.value;4889count = string.count;4890hash = string.hash;4891}48924893/**4894* Creates a string from the contents of a StringBuffer.4895*4896* @param buffer4897* the StringBuffer4898*/4899public String(StringBuffer buffer) {4900synchronized (buffer) {4901char[] chars = buffer.shareValue();49024903if (COMPACT_STRINGS) {4904if (buffer.isCompressed()) {4905value = chars;4906count = buffer.length();4907} else {4908value = chars;4909count = buffer.length() | uncompressedBit;49104911initCompressionFlag();4912}4913} else {4914value = chars;4915count = buffer.length();4916}4917}4918}49194920/*4921* Creates a string that is s1 + s2.4922*/4923private String(String s1, String s2) {4924if (s1 == null) {4925s1 = "null"; //$NON-NLS-1$4926}49274928if (s2 == null) {4929s2 = "null"; //$NON-NLS-1$4930}49314932int s1len = s1.lengthInternal();4933int s2len = s2.lengthInternal();49344935int concatlen = s1len + s2len;4936if (concatlen < 0) {4937/*[MSG "K0D01", "Array capacity exceeded"]*/4938throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$4939}49404941if (COMPACT_STRINGS) {4942if (null == compressionFlag || (s1.count | s2.count) >= 0) {4943value = new char[(concatlen + 1) >>> 1];4944count = concatlen;49454946compressedArrayCopy(s1.value, 0, value, 0, s1len);4947compressedArrayCopy(s2.value, 0, value, s1len, s2len);4948} else {4949value = new char[concatlen];4950count = concatlen | uncompressedBit;49514952// Check if the String is compressed4953if (s1.count >= 0) {4954decompress(s1.value, 0, value, 0, s1len);4955} else {4956System.arraycopy(s1.value, 0, value, 0, s1len);4957}49584959// Check if the String is compressed4960if (s2.count >= 0) {4961decompress(s2.value, 0, value, s1len, s2len);4962} else {4963System.arraycopy(s2.value, 0, value, s1len, s2len);4964}49654966initCompressionFlag();4967}4968} else {4969value = new char[concatlen];4970count = concatlen;49714972System.arraycopy(s1.value, 0, value, 0, s1len);4973System.arraycopy(s2.value, 0, value, s1len, s2len);4974}4975}49764977/*4978* Creates a string that is s1 + s2 + s3.4979*/4980private String(String s1, String s2, String s3) {4981if (s1 == null) {4982s1 = "null"; //$NON-NLS-1$4983}49844985if (s2 == null) {4986s2 = "null"; //$NON-NLS-1$4987}49884989if (s3 == null) {4990s3 = "null"; //$NON-NLS-1$4991}49924993int s1len = s1.lengthInternal();4994int s2len = s2.lengthInternal();4995int s3len = s3.lengthInternal();4996long totalLen = (long) s1len + (long) s2len + (long) s3len;4997if (totalLen > Integer.MAX_VALUE) {4998/*[MSG "K0D01", "Array capacity exceeded"]*/4999throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$5000}50015002int concatlen = (int) totalLen;50035004if (COMPACT_STRINGS) {5005if (null == compressionFlag || (s1.count | s2.count | s3.count) >= 0) {5006value = new char[(concatlen + 1) >>> 1];5007count = concatlen;50085009compressedArrayCopy(s1.value, 0, value, 0, s1len);5010compressedArrayCopy(s2.value, 0, value, s1len, s2len);5011compressedArrayCopy(s3.value, 0, value, s1len + s2len, s3len);5012} else {5013value = new char[concatlen];5014count = concatlen | uncompressedBit;50155016// Check if the String is compressed5017if (s1.count >= 0) {5018decompress(s1.value, 0, value, 0, s1len);5019} else {5020System.arraycopy(s1.value, 0, value, 0, s1len);5021}50225023// Check if the String is compressed5024if (s2.count >= 0) {5025decompress(s2.value, 0, value, s1len, s2len);5026} else {5027System.arraycopy(s2.value, 0, value, s1len, s2len);5028}50295030// Check if the String is compressed5031if (s3.count >= 0) {5032decompress(s3.value, 0, value, s1len + s2len, s3len);5033} else {5034System.arraycopy(s3.value, 0, value, (s1len + s2len), s3len);5035}50365037initCompressionFlag();5038}5039} else {5040value = new char[concatlen];5041count = concatlen;50425043System.arraycopy(s1.value, 0, value, 0, s1len);5044System.arraycopy(s2.value, 0, value, s1len, s2len);5045System.arraycopy(s3.value, 0, value, (s1len + s2len), s3len);5046}5047}50485049/*5050* Creates a string that is s1 + v1.5051*/5052private String(String s1, int v1) {5053if (s1 == null) {5054s1 = "null"; //$NON-NLS-1$5055}50565057// Char length of all the parameters respectively5058int s1len = s1.lengthInternal();5059int v1len = 1;50605061int quot;5062int i = v1;5063while ((i /= 10) != 0)5064v1len++;5065if (v1 >= 0) {5066quot = -v1;5067} else {5068// Leave room for '-'5069v1len++;5070quot = v1;5071}50725073// Char length of the final String5074int len = s1len + v1len;5075if (len < 0) {5076/*[MSG "K0D01", "Array capacity exceeded"]*/5077throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$5078}50795080if (COMPACT_STRINGS) {5081// Check if the String is compressed5082if (null == compressionFlag || s1.count >= 0) {5083value = new char[(len + 1) >>> 1];5084count = len;50855086// Copy in v15087int index = len - 1;50885089do {5090int res = quot / 10;5091int rem = quot - (res * 10);50925093quot = res;50945095// Write the digit into the correct position5096helpers.putByteInArrayByIndex(value, index--, (byte) ('0' - rem));5097} while (quot != 0);50985099if (v1 < 0) {5100helpers.putByteInArrayByIndex(value, index, (byte) '-');5101}51025103// Copy in s1 contents5104compressedArrayCopy(s1.value, 0, value, 0, s1len);5105} else {5106value = new char[len];5107count = len | uncompressedBit;51085109// Copy in v15110int index = len - 1;51115112do {5113int res = quot / 10;5114int rem = quot - (res * 10);51155116quot = res;51175118// Write the digit into the correct position5119value[index--] = (char) ('0' - rem);5120} while (quot != 0);51215122if (v1 < 0) {5123value[index] = '-';5124}51255126// Copy in s1 contents5127System.arraycopy(s1.value, 0, value, 0, s1len);51285129initCompressionFlag();5130}5131} else {5132value = new char[len];5133count = len;51345135// Copy in v15136int index = len - 1;51375138do {5139int res = quot / 10;5140int rem = quot - (res * 10);51415142quot = res;51435144// Write the digit into the correct position5145value[index--] = (char) ('0' - rem);5146} while (quot != 0);51475148if (v1 < 0) {5149value[index] = '-';5150}51515152// Copy in s1 contents5153System.arraycopy(s1.value, 0, value, 0, s1len);5154}5155}51565157/*5158* Creates a string that is v1 + s1 + v2 + s2 + s3.5159*/5160private String(int v1, String s1, int v2, String s2, String s3) {5161if (s1 == null) {5162s1 = "null"; //$NON-NLS-1$5163}51645165if (s2 == null) {5166s2 = "null"; //$NON-NLS-1$5167}51685169if (s3 == null) {5170s3 = "null"; //$NON-NLS-1$5171}51725173// Char length of all the parameters respectively5174int s1len = s1.lengthInternal();5175int s2len = s2.lengthInternal();5176int s3len = s3.lengthInternal();51775178int v1len = 1;5179int v2len = 1;51805181int quot1;5182int i1 = v1;5183while ((i1 /= 10) != 0)5184v1len++;5185if (v1 >= 0) {5186quot1 = -v1;5187} else {5188// Leave room for '-'5189v1len++;5190quot1 = v1;5191}51925193int quot2;5194int i2 = v2;5195while ((i2 /= 10) != 0)5196v2len++;5197if (v2 >= 0) {5198quot2 = -v2;5199} else {5200// Leave room for '-'5201v2len++;5202quot2 = v2;5203}52045205// Char length of the final String5206long totalLen = (long) s1len + (long) v1len + (long) v2len + (long) s2len + (long) s3len;5207if (totalLen > Integer.MAX_VALUE) {5208/*[MSG "K0D01", "Array capacity exceeded"]*/5209throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$5210}52115212int len = (int) totalLen;52135214if (COMPACT_STRINGS) {5215if (null == compressionFlag || (s1.count | s2.count | s3.count) >= 0) {5216value = new char[(len + 1) >>> 1];5217count = len;52185219int start = len;52205221// Copy in s3 contents5222start = start - s3len;5223compressedArrayCopy(s3.value, 0, value, start, s3len);52245225// Copy in s2 contents5226start = start - s2len;5227compressedArrayCopy(s2.value, 0, value, start, s2len);52285229// Copy in v25230int index2 = start - 1;52315232do {5233int res = quot2 / 10;5234int rem = quot2 - (res * 10);52355236quot2 = res;52375238// Write the digit into the correct position5239helpers.putByteInArrayByIndex(value, index2--, (byte) ('0' - rem));5240} while (quot2 != 0);52415242if (v2 < 0) {5243helpers.putByteInArrayByIndex(value, index2--, (byte) '-');5244}52455246// Copy in s1 contents5247start = index2 + 1 - s1len;5248compressedArrayCopy(s1.value, 0, value, start, s1len);52495250// Copy in v15251int index1 = start - 1;52525253do {5254int res = quot1 / 10;5255int rem = quot1 - (res * 10);52565257quot1 = res;52585259// Write the digit into the correct position5260helpers.putByteInArrayByIndex(value, index1--, (byte) ('0' - rem));5261} while (quot1 != 0);52625263if (v1 < 0) {5264helpers.putByteInArrayByIndex(value, index1--, (byte) '-');5265}5266} else {5267value = new char[len];5268count = len | uncompressedBit;52695270int start = len;52715272// Copy in s3 contents5273start = start - s3len;52745275// Check if the String is compressed5276if (s3.count >= 0) {5277decompress(s3.value, 0, value, start, s3len);5278} else {5279System.arraycopy(s3.value, 0, value, start, s3len);5280}52815282// Copy in s2 contents5283start = start - s2len;52845285// Check if the String is compressed5286if (s2.count >= 0) {5287decompress(s2.value, 0, value, start, s2len);5288} else {5289System.arraycopy(s2.value, 0, value, start, s2len);5290}52915292// Copy in v25293int index2 = start - 1;52945295do {5296int res = quot2 / 10;5297int rem = quot2 - (res * 10);52985299quot2 = res;53005301// Write the digit into the correct position5302value[index2--] = (char) ('0' - rem);5303} while (quot2 != 0);53045305if (v2 < 0) {5306value[index2--] = '-';5307}53085309// Copy in s1 contents5310start = index2 + 1 - s1len;53115312// Check if the String is compressed5313if (s1.count >= 0) {5314decompress(s1.value, 0, value, start, s1len);5315} else {5316System.arraycopy(s1.value, 0, value, start, s1len);5317}53185319// Copy in v15320int index1 = start - 1;53215322do {5323int res = quot1 / 10;5324int rem = quot1 - (res * 10);53255326quot1 = res;53275328// Write the digit into the correct position5329value[index1--] = (char) ('0' - rem);5330} while (quot1 != 0);53315332if (v1 < 0) {5333value[index1--] = '-';5334}53355336initCompressionFlag();5337}5338} else {5339value = new char[len];5340count = len;53415342int start = len;53435344// Copy in s3 contents5345start = start - s3len;5346System.arraycopy(s3.value, 0, value, start, s3len);53475348// Copy in s2 contents5349start = start - s2len;5350System.arraycopy(s2.value, 0, value, start, s2len);53515352// Copy in v25353int index2 = start - 1;53545355do {5356int res = quot2 / 10;5357int rem = quot2 - (res * 10);53585359quot2 = res;53605361// Write the digit into the correct position5362value[index2--] = (char) ('0' - rem);5363} while (quot2 != 0);53645365if (v2 < 0) {5366value[index2--] = '-';5367}53685369// Copy in s1 contents5370start = index2 + 1 - s1len;53715372System.arraycopy(s1.value, 0, value, start, s1len);53735374// Copy in v15375int index1 = start - 1;53765377do {5378int res = quot1 / 10;5379int rem = quot1 - (res * 10);53805381quot1 = res;53825383// Write the digit into the correct position5384value[index1--] = (char) ('0' - rem);5385} while (quot1 != 0);53865387if (v1 < 0) {5388value[index1--] = '-';5389}5390}5391}53925393/*5394* Loads from the stringArray if concatenated result is found else it creates a string that is s1 + s2 which is stored in stringArray and then5395* returned.5396*/5397static private String cachedConstantString(String s1, String s2, int index) {5398if (index < stringArraySize) {5399if (stringArray[index] == null) {5400stringArray[index] = new String(s1, s2);5401}5402} else {5403return new String(s1, s2);5404}5405return stringArray[index];5406}54075408/**5409* Answers the character at the specified offset in this String.5410*5411* @param index5412* the zero-based index in this string5413* @return the character at the index5414*5415* @throws IndexOutOfBoundsException5416* when {@code index < 0} or {@code index >= length()}5417*/5418public char charAt(int index) {5419if (0 <= index && index < lengthInternal()) {5420// Check if the String is compressed5421if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {5422return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));5423}54245425return value[index];5426}54275428throw new StringIndexOutOfBoundsException();5429}54305431// Internal version of charAt used for extracting a char from a String in compression related code.5432char charAtInternal(int index) {5433// Check if the String is compressed5434if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {5435return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));5436}54375438return value[index];5439}54405441// This method is needed so idiom recognition properly recognizes idiomatic loops where we are doing an operation on5442// the byte[] value of two Strings. In such cases we extract the String.value fields before entering the operation loop.5443// However if chatAt is used inside the loop then the JIT will anchor the load of the value byte[] inside of the loop thus5444// causing us to load the String.value on every iteration. This is very suboptimal and breaks some of the common idioms5445// that we recognize. The most prominent one is the regionMatches arraycmp idiom that is not recognized unless this method5446// is being used.5447char charAtInternal(int index, char[] value) {5448// Check if the String is compressed5449if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {5450return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));5451}54525453return value[index];5454}54555456/**5457* Compares the specified String to this String using the Unicode values of the characters. Answer 0 if the strings contain the same characters in5458* the same order. Answer a negative integer if the first non-equal character in this String has a Unicode value which is less than the Unicode5459* value of the character at the same position in the specified string, or if this String is a prefix of the specified string. Answer a positive5460* integer if the first non-equal character in this String has a Unicode value which is greater than the Unicode value of the character at the same5461* position in the specified string, or if the specified String is a prefix of the this String.5462*5463* @param string5464* the string to compare5465* @return 0 if the strings are equal, a negative integer if this String is before the specified String, or a positive integer if this String is5466* after the specified String5467*5468* @throws NullPointerException5469* when string is null5470*/5471public int compareTo(String string) {5472String s1 = this;5473String s2 = string;54745475int s1len = s1.lengthInternal();5476int s2len = s2.lengthInternal();54775478// Upper bound index on the last char to compare5479int end = s1len < s2len ? s1len : s2len;54805481int o1 = 0;5482int o2 = 0;54835484int result;54855486char[] s1Value = s1.value;5487char[] s2Value = s2.value;54885489if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {5490while (o1 < end) {5491if ((result =5492helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s1Value, o1++)) -5493helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s2Value, o2++))) != 0) {5494return result;5495}5496}5497} else {5498while (o1 < end) {5499if ((result = s1.charAtInternal(o1++, s1Value) - s2.charAtInternal(o2++, s2Value)) != 0) {5500return result;5501}5502}5503}55045505return s1len - s2len;5506}55075508private static char compareValue(char c) {5509if ('A' <= c && c <= 'Z') {5510return (char) (c + ('a' - 'A'));5511}55125513return Character.toLowerCase(Character.toUpperCase(c));5514}55155516private static char compareValue(byte b) {5517if ('A' <= b && b <= 'Z') {5518return (char) (helpers.byteToCharUnsigned(b) + ('a' - 'A'));5519}5520return Character.toLowerCase(Character.toUpperCase(helpers.byteToCharUnsigned(b)));5521}55225523private static boolean charValuesEqualIgnoreCase(char c1, char c2) {5524boolean charValuesEqual = false;5525char c1upper = (char) toUpperCase(c1);5526char c2upper = (char) toUpperCase(c2);55275528// If at least one char is ASCII, converting to upper cases then compare should be sufficient.5529// If both chars are not in ASCII char set, need to convert to lower case and compare as well.5530if (((c1 <= 255 || c2 <= 255) && (c1upper == c2upper))5531|| (toLowerCase(c1upper) == toLowerCase(c2upper))5532) {5533charValuesEqual = true;5534}55355536return charValuesEqual;5537}55385539/**5540* Compare the receiver to the specified String to determine the relative ordering when the case of the characters is ignored.5541*5542* @param string5543* a String5544* @return an {@code int < 0} if this String is less than the specified String, 0 if they are equal, and {@code > 0} if this String is greater5545*/5546public int compareToIgnoreCase(String string) {5547String s1 = this;5548String s2 = string;55495550int s1len = s1.lengthInternal();5551int s2len = s2.lengthInternal();55525553// Upper bound index on the last char to compare5554int end = s1len < s2len ? s1len : s2len;55555556int o1 = 0;5557int o2 = 0;55585559int result;55605561char[] s1Value = s1.value;5562char[] s2Value = s2.value;55635564if (COMPACT_STRINGS && ((null == compressionFlag) || ((s1.count | s2.count) >= 0))) {5565while (o1 < end) {5566byte byteAtO1;5567byte byteAtO2;55685569if ((byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++)) == (byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++))) {5570continue;5571}55725573if ((result = compareValue(byteAtO1) - compareValue(byteAtO2)) != 0) {5574return result;5575}5576}5577} else {5578while (o1 < end) {5579char charAtO1;5580char charAtO2;55815582if ((charAtO1 = s1.charAtInternal(o1++, s1Value)) == (charAtO2 = s2.charAtInternal(o2++, s2Value))) {5583continue;5584}55855586if ((result = compareValue(charAtO1) - compareValue(charAtO2)) != 0) {5587return result;5588}5589}5590}55915592return s1len - s2len;5593}55945595/**5596* Concatenates this String and the specified string.5597*5598* @param string5599* the string to concatenate5600* @return a String which is the concatenation of this String and the specified String5601*5602* @throws NullPointerException5603* if string is null5604*/5605public String concat(String string) {5606String s1 = this;5607String s2 = string;56085609int s1len = s1.lengthInternal();5610int s2len = s2.lengthInternal();56115612if (s2len == 0) {5613return s1;5614}56155616int concatlen = s1len + s2len;5617if (concatlen < 0) {5618/*[MSG "K0D01", "Array capacity exceeded"]*/5619throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$5620}56215622if (COMPACT_STRINGS && ((null == compressionFlag) || ((s1.count | s2.count) >= 0))) {5623char[] buffer = new char[(concatlen + 1) >>> 1];56245625compressedArrayCopy(s1.value, 0, buffer, 0, s1len);5626compressedArrayCopy(s2.value, 0, buffer, s1len, s2len);56275628return new String(buffer, 0, concatlen, true);5629} else {5630char[] buffer = new char[concatlen];56315632// Check if the String is compressed5633if (COMPACT_STRINGS && s1.count >= 0) {5634decompress(s1.value, 0, buffer, 0, s1len);5635} else {5636System.arraycopy(s1.value, 0, buffer, 0, s1len);5637}56385639// Check if the String is compressed5640if (COMPACT_STRINGS && s2.count >= 0) {5641decompress(s2.value, 0, buffer, s1len, s2len);5642} else {5643System.arraycopy(s2.value, 0, buffer, s1len, s2len);5644}56455646return new String(buffer, 0, concatlen, false);5647}5648}56495650/**5651* Creates a new String containing the characters in the specified character array. Modifying the character array after creating the String has no5652* effect on the String.5653*5654* @param data5655* the array of characters5656* @return the new String5657*5658* @throws NullPointerException5659* if data is null5660*/5661public static String copyValueOf(char[] data) {5662return new String(data, 0, data.length);5663}56645665/**5666* Creates a new String containing the specified characters in the character array. Modifying the character array after creating the String has no5667* effect on the String.5668*5669* @param data5670* the array of characters5671* @param start5672* the starting offset in the character array5673* @param length5674* the number of characters to use5675* @return the new String5676*5677* @throws IndexOutOfBoundsException5678* when {@code length < 0, start < 0} or {@code start + length > data.length}5679* @throws NullPointerException5680* if data is null5681*/5682public static String copyValueOf(char[] data, int start, int length) {5683return new String(data, start, length);5684}56855686/**5687* Compares the specified string to this String to determine if the specified string is a suffix.5688*5689* @param suffix5690* the string to look for5691* @return true when the specified string is a suffix of this String, false otherwise5692*5693* @throws NullPointerException5694* if suffix is null5695*/5696public boolean endsWith(String suffix) {5697return regionMatches(lengthInternal() - suffix.lengthInternal(), suffix, 0, suffix.lengthInternal());5698}56995700/**5701* Compares the specified object to this String and answer if they are equal. The object must be an instance of String with the same characters in5702* the same order.5703*5704* @param object5705* the object to compare5706* @return true if the specified object is equal to this String, false otherwise5707*5708* @see #hashCode()5709*/5710public boolean equals(Object object) {5711if (object == this) {5712return true;5713}57145715if (object instanceof String) {5716String s1 = this;5717String s2 = (String) object;57185719int s1len = s1.lengthInternal();5720int s2len = s2.lengthInternal();57215722if (s1len != s2len) {5723return false;5724}57255726char[] s1Value = s1.value;5727char[] s2Value = s2.value;5728if (s1Value == s2Value) {5729return true;5730}57315732// There was a time hole between first read of s.hash and second read if another thread does hashcode5733// computing for incoming string object5734int s1hash = s1.hash;5735int s2hash = s2.hash;57365737if (s1hash != 0 && s2hash != 0 && s1hash != s2hash) {5738return false;5739}57405741if (!regionMatchesInternal(s1, s2, s1Value, s2Value, 0, 0, s1len)) {5742return false;5743}57445745if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY != com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_DISABLED) {5746deduplicateStrings(s1, s1Value, s2, s2Value);5747}57485749return true;5750}57515752return false;5753}57545755/**5756* Deduplicate the backing buffers of the given strings.5757*5758* This updates the {@link #value} of one of the two given strings so that5759* they both share a single backing buffer. The strings must have identical5760* contents.5761*5762* Deduplication helps save space, and lets {@link #equals(Object)} exit5763* early more often.5764*5765* The strings' corresponding backing buffers are accepted as parameters5766* because the caller likely already has them.5767*5768* @param s1 The first string5769* @param value1 {@code s1.value}5770* @param s2 The second string5771* @param value2 {@code s2.value}5772*/5773private static final void deduplicateStrings(String s1, Object value1, String s2, Object value2) {5774/* This test ensures that we only deduplicate strings that are both5775* compressed or both uncompressed.5776*5777* When one string is compressed and the other isn't, we can't5778* deduplicate because doing so would require updating both value and5779* count, and other threads could see an inconsistent state.5780*5781* If (!COMPACT_STRINGS), then both strings are always uncompressed.5782* If OTOH (COMPACT_STRINGS) but (null == compressionFlag), then both5783* strings must be compressed. So it's only necessary to check the5784* compression bits when (COMPACT_STRINGS && null != compressionFlag).5785*/5786if (!COMPACT_STRINGS || null == compressionFlag || (s1.count ^ s2.count) >= 0) {5787long valueFieldOffset = UnsafeHelpers.valueFieldOffset;57885789if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY == com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_FAVOUR_LOWER) {5790if (helpers.acmplt(value1, value2)) {5791helpers.putObjectInObject(s2, valueFieldOffset, value1);5792} else {5793helpers.putObjectInObject(s1, valueFieldOffset, value2);5794}5795} else {5796if (helpers.acmplt(value2, value1)) {5797helpers.putObjectInObject(s2, valueFieldOffset, value1);5798} else {5799helpers.putObjectInObject(s1, valueFieldOffset, value2);5800}5801}5802}5803}58045805/**5806* Compares the specified String to this String ignoring the case of the characters and answer if they are equal.5807*5808* @param string5809* the string to compare5810* @return true if the specified string is equal to this String, false otherwise5811*/5812public boolean equalsIgnoreCase(String string) {5813String s1 = this;5814String s2 = string;58155816if (s1 == s2) {5817return true;5818}58195820if (s2 == null) {5821return false;5822}58235824int s1len = s1.lengthInternal();5825int s2len = s2.lengthInternal();58265827if (s1len != s2len) {5828return false;5829}58305831// Zero length strings are equal5832if (0 == s1len) {5833return true;5834}58355836int o1 = 0;5837int o2 = 0;58385839// Upper bound index on the last char to compare5840int end = s1len;58415842char[] s1Value = s1.value;5843char[] s2Value = s2.value;58445845if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {5846// Compare the last chars.5847// In order to tell 2 chars are different:5848// Under string compression, the compressible char set obeys 1-1 mapping for upper/lower case,5849// converting to upper cases then compare should be sufficient.5850byte byteAtO1Last = helpers.getByteFromArrayByIndex(s1Value, s1len - 1);5851byte byteAtO2Last = helpers.getByteFromArrayByIndex(s2Value, s1len - 1);58525853if ((byteAtO1Last != byteAtO2Last)5854&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1Last)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2Last)))5855) {5856return false;5857}58585859while (o1 < end - 1) {5860byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);5861byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);58625863if ((byteAtO1 != byteAtO2)5864&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2)))5865) {5866return false;5867}5868}5869} else {5870// Compare the last chars.5871// In order to tell 2 chars are different:5872// If at least one char is ASCII, converting to upper cases then compare should be sufficient.5873// If both chars are not in ASCII char set, need to convert to lower case and compare as well.5874char charAtO1Last = s1.charAtInternal(s1len - 1, s1Value);5875char charAtO2Last = s2.charAtInternal(s1len - 1, s2Value);58765877if ((charAtO1Last != charAtO2Last)5878&& (!charValuesEqualIgnoreCase(charAtO1Last, charAtO2Last))5879) {5880return false;5881}58825883while (o1 < end - 1) {5884char charAtO1 = s1.charAtInternal(o1++, s1Value);5885char charAtO2 = s2.charAtInternal(o2++, s2Value);58865887if ((charAtO1 != charAtO2)5888&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))5889) {5890return false;5891}5892}5893}58945895return true;5896}58975898/**5899* Converts this String to a byte encoding using the default encoding as specified by the file.encoding system property. If the system property is5900* not defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.5901*5902* @return the byte array encoding of this String5903*5904* @see String5905*/5906public byte[] getBytes() {5907int currentLength = lengthInternal();59085909char[] buffer;59105911// Check if the String is compressed5912if (COMPACT_STRINGS && count >= 0) {5913buffer = new char[currentLength];5914decompress(value, 0, buffer, 0, currentLength);5915} else {5916buffer = value;5917}59185919return StringCoding.encode(buffer, 0, currentLength);5920}59215922/**5923* Converts this String to a byte array, ignoring the high order bits of each character.5924*5925* @param start5926* the starting offset of characters to copy5927* @param end5928* the ending offset of characters to copy5929* @param data5930* the destination byte array5931* @param index5932* the starting offset in the byte array5933*5934* @throws NullPointerException5935* when data is null5936* @throws IndexOutOfBoundsException5937* when {@code start < 0, end > length(), index < 0, end - start > data.length - index}5938*5939* @deprecated Use getBytes() or getBytes(String)5940*/5941@Deprecated5942public void getBytes(int start, int end, byte[] data, int index) {5943if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {5944// Check if the String is compressed5945if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {5946compressedArrayCopy(value, start, data, index, end - start);5947} else {5948compress(value, start, data, index, end - start);5949}5950} else {5951throw new StringIndexOutOfBoundsException();5952}5953}59545955void getBytes(int start, int end, char[] data, int index) {5956if (0 <= start && start <= end && end <= lengthInternal()) {5957// Check if the String is compressed5958if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {5959compressedArrayCopy(value, start, data, index, end - start);5960} else {5961compress(value, start, data, index, end - start);5962}5963} else {5964throw new StringIndexOutOfBoundsException();5965}5966}59675968/**5969* Converts this String to a byte encoding using the specified encoding.5970*5971* @param encoding5972* the encoding5973* @return the byte array encoding of this String5974*5975* @throws UnsupportedEncodingException5976* when the encoding is not supported5977*5978* @see String5979* @see UnsupportedEncodingException5980*/5981public byte[] getBytes(String encoding) throws UnsupportedEncodingException {5982if (encoding == null) {5983throw new NullPointerException();5984}59855986int currentLength = lengthInternal();59875988char[] buffer;59895990// Check if the String is compressed5991if (COMPACT_STRINGS && count >= 0) {5992buffer = new char[currentLength];5993decompress(value, 0, buffer, 0, currentLength);5994} else {5995buffer = value;5996}59975998return StringCoding.encode(encoding, buffer, 0, currentLength);5999}60006001/**6002* Copies the specified characters in this String to the character array starting at the specified offset in the character array.6003*6004* @param start6005* the starting offset of characters to copy6006* @param end6007* the ending offset of characters to copy6008* @param data6009* the destination character array6010* @param index6011* the starting offset in the character array6012*6013* @throws IndexOutOfBoundsException6014* when {@code start < 0, end > length(), start > end, index < 0, end - start > buffer.length - index}6015* @throws NullPointerException6016* when buffer is null6017*/6018public void getChars(int start, int end, char[] data, int index) {6019if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {6020if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6021decompress(value, start, data, index, end - start);6022} else {6023System.arraycopy(value, start, data, index, end - start);6024}6025} else {6026throw new StringIndexOutOfBoundsException();6027}6028}60296030// This is a package protected method that performs the getChars operation without explicit bound checks.6031// Caller of this method must validate bound safety for String indexing and array copying.6032void getCharsNoBoundChecks(int start, int end, char[] data, int index) {6033// Check if the String is compressed6034if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6035decompress(value, start, data, index, end - start);6036} else {6037decompressedArrayCopy(value, start, data, index, end - start);6038}6039}60406041/**6042* Answers an integer hash code for the receiver. Objects which are equal answer the same value for this method.6043*6044* @return the receiver's hash6045*6046* @see #equals6047*/6048public int hashCode() {6049if (hash == 0) {6050int length = lengthInternal();6051if (length > 0) {6052// Check if the String is compressed6053if (COMPACT_STRINGS && (compressionFlag == null || count >= 0)) {6054hash = hashCodeImplCompressed(value, 0, length);6055} else {6056hash = hashCodeImplDecompressed(value, 0, length);6057}6058}6059}6060return hash;6061}60626063private static int hashCodeImplCompressed(char[] value, int offset, int count) {6064int hash = 0, end = offset + count;60656066for (int i = offset; i < end; ++i) {6067hash = (hash << 5) - hash + helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i));6068}60696070return hash;6071}60726073private static int hashCodeImplDecompressed(char[] value, int offset, int count) {6074int hash = 0, end = offset + count;60756076for (int i = offset; i < end; ++i) {6077hash = (hash << 5) - hash + value[i];6078}60796080return hash;6081}60826083/**6084* Searches in this String for the first index of the specified character. The search for the character starts at the beginning and moves towards6085* the end of this String.6086*6087* @param c6088* the character to find6089* @return the index in this String of the specified character, -1 if the character isn't found6090*6091* @see #lastIndexOf(int)6092* @see #lastIndexOf(int, int)6093* @see #lastIndexOf(String)6094* @see #lastIndexOf(String, int)6095*/6096public int indexOf(int c) {6097return indexOf(c, 0);6098}60996100/**6101* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards6102* the end of this String.6103*6104* @param c6105* the character to find6106* @param start6107* the starting offset6108* @return the index in this String of the specified character, -1 if the character isn't found6109*6110* @see #lastIndexOf(int)6111* @see #lastIndexOf(int, int)6112* @see #lastIndexOf(String)6113* @see #lastIndexOf(String, int)6114*/6115public int indexOf(int c, int start) {6116int len = lengthInternal();61176118if (start < len) {6119if (start < 0) {6120start = 0;6121}61226123if (c >= 0 && c <= Character.MAX_VALUE) {6124char[] array = value;61256126// Check if the String is compressed6127if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6128if (c <= 255) {6129return helpers.intrinsicIndexOfLatin1(array, (byte)c, start, len);6130}6131} else {6132return helpers.intrinsicIndexOfUTF16(array, (char)c, start, len);6133}6134} else if (c <= Character.MAX_CODE_POINT) {6135for (int i = start; i < len; ++i) {6136int codePoint = codePointAt(i);61376138if (codePoint == c) {6139return i;6140}61416142if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {6143++i;6144}6145}6146}6147}61486149return -1;6150}61516152/**6153* Searches in this String for the first index of the specified string. The search for the string starts at the beginning and moves towards the end6154* of this String.6155*6156* @param string6157* the string to find6158* @return the index in this String of the specified string, -1 if the string isn't found6159*6160* @throws NullPointerException6161* when string is null6162*6163* @see #lastIndexOf(int)6164* @see #lastIndexOf(int, int)6165* @see #lastIndexOf(String)6166* @see #lastIndexOf(String, int)6167*/6168public int indexOf(String string) {6169return indexOf(string, 0);6170}61716172/**6173* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the6174* end of this String.6175*6176* @param subString6177* the string to find6178* @param start6179* the starting offset6180* @return the index in this String of the specified string, -1 if the string isn't found6181*6182* @throws NullPointerException6183* when string is null6184*6185* @see #lastIndexOf(int)6186* @see #lastIndexOf(int, int)6187* @see #lastIndexOf(String)6188* @see #lastIndexOf(String, int)6189*/6190public int indexOf(String subString, int start) {6191if (subString.length() == 1) {6192return indexOf(subString.charAtInternal(0), start);6193}61946195if (start < 0) {6196start = 0;6197}61986199String s1 = this;6200String s2 = subString;62016202int s1len = s1.lengthInternal();6203int s2len = s2.lengthInternal();62046205if (s2len > 0) {6206if (start > s1len - s2len) {6207return -1;6208}62096210char[] s1Value = s1.value;6211char[] s2Value = s2.value;62126213if (COMPACT_STRINGS) {6214if (null == compressionFlag || (s1.count | s2.count) >= 0) {6215// Both s1 and s2 are compressed.6216return helpers.intrinsicIndexOfStringLatin1(s1Value, s1len, s2Value, s2len, start);6217} else if ((s1.count & s2.count) < 0) {6218// Both s1 and s2 are decompressed.6219return helpers.intrinsicIndexOfStringUTF16(s1Value, s1len, s2Value, s2len, start);6220} else {6221// Mixed case.6222char firstChar = s2.charAtInternal(0, s2Value);62236224while (true) {6225int i = indexOf(firstChar, start);62266227// Handles subCount > count || start >= count.6228if (i == -1 || s2len + i > s1len) {6229return -1;6230}62316232int o1 = i;6233int o2 = 0;62346235while (++o2 < s2len && s1.charAtInternal(++o1, s1Value) == s2.charAtInternal(o2, s2Value))6236;62376238if (o2 == s2len) {6239return i;6240}62416242start = i + 1;6243}6244}6245} else {6246// Both s1 and s2 are decompressed.6247return helpers.intrinsicIndexOfStringUTF16(s1Value, s1len, s2Value, s2len, start);6248}6249} else {6250return start < s1len ? start : s1len;6251}6252}62536254/**6255* Searches an internal table of strings for a string equal to this String. If the string is not in the table, it is added. Answers the string6256* contained in the table which is equal to this String. The same string object is always answered for strings which are equal.6257*6258* @return the interned string equal to this String6259*/6260public native String intern();62616262/**6263* Searches in this String for the last index of the specified character. The search for the character starts at the end and moves towards the6264* beginning of this String.6265*6266* @param c6267* the character to find6268* @return the index in this String of the specified character, -1 if the character isn't found6269*6270* @see #lastIndexOf(int)6271* @see #lastIndexOf(int, int)6272* @see #lastIndexOf(String)6273* @see #lastIndexOf(String, int)6274*/6275public int lastIndexOf(int c) {6276return lastIndexOf(c, lengthInternal() - 1);6277}62786279/**6280* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards6281* the beginning of this String.6282*6283* @param c6284* the character to find6285* @param start6286* the starting offset6287* @return the index in this String of the specified character, -1 if the character isn't found6288*6289* @see #lastIndexOf(int)6290* @see #lastIndexOf(int, int)6291* @see #lastIndexOf(String)6292* @see #lastIndexOf(String, int)6293*/6294public int lastIndexOf(int c, int start) {6295if (start >= 0) {6296int len = lengthInternal();62976298if (start >= len) {6299start = len - 1;6300}63016302if (c >= 0 && c <= Character.MAX_VALUE) {6303char[] array = value;63046305// Check if the String is compressed6306if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6307if (c <= 255) {6308byte b = (byte) c;63096310for (int i = start; i >= 0; --i) {6311if (helpers.getByteFromArrayByIndex(array, i) == b) {6312return i;6313}6314}6315}6316} else {6317for (int i = start; i >= 0; --i) {6318if (array[i] == c) {6319return i;6320}6321}6322}6323} else if (c <= Character.MAX_CODE_POINT) {6324for (int i = start; i >= 0; --i) {6325int codePoint = codePointAt(i);63266327if (codePoint == c) {6328return i;6329}63306331if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {6332--i;6333}6334}6335}6336}63376338return -1;6339}63406341/**6342* Searches in this String for the last index of the specified string. The search for the string starts at the end and moves towards the beginning6343* of this String.6344*6345* @param string6346* the string to find6347* @return the index in this String of the specified string, -1 if the string isn't found6348*6349* @throws NullPointerException6350* when string is null6351*6352* @see #lastIndexOf(int)6353* @see #lastIndexOf(int, int)6354* @see #lastIndexOf(String)6355* @see #lastIndexOf(String, int)6356*/6357public int lastIndexOf(String string) {6358// Use count instead of count - 1 so lastIndexOf("") answers count6359return lastIndexOf(string, lengthInternal());6360}63616362/**6363* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the6364* beginning of this String.6365*6366* @param subString6367* the string to find6368* @param start6369* the starting offset6370* @return the index in this String of the specified string, -1 if the string isn't found6371*6372* @throws NullPointerException6373* when string is null6374*6375* @see #lastIndexOf(int)6376* @see #lastIndexOf(int, int)6377* @see #lastIndexOf(String)6378* @see #lastIndexOf(String, int)6379*/6380public int lastIndexOf(String subString, int start) {6381String s1 = this;6382String s2 = subString;63836384int s1len = s1.lengthInternal();6385int s2len = s2.lengthInternal();63866387if (s2len <= s1len && start >= 0) {6388if (s2len > 0) {6389if (start > s1len - s2len) {6390start = s1len - s2len; // s1len and s2len are both >= 16391}63926393char[] s1Value = s1.value;6394char[] s2Value = s2.value;63956396if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {6397char firstChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s2Value, 0));63986399while (true) {6400int i = lastIndexOf(firstChar, start);64016402if (i == -1) {6403return -1;6404}64056406int o1 = i;6407int o2 = 0;64086409while (++o2 < s2len && helpers.getByteFromArrayByIndex(s1Value, ++o1) == helpers.getByteFromArrayByIndex(s2Value, o2))6410;64116412if (o2 == s2len) {6413return i;6414}64156416start = i - 1;6417}6418} else {6419char firstChar = s2.charAtInternal(0, s2Value);64206421while (true) {6422int i = lastIndexOf(firstChar, start);64236424if (i == -1) {6425return -1;6426}64276428int o1 = i;6429int o2 = 0;64306431while (++o2 < s2len && s1.charAtInternal(++o1, s1Value) == s2.charAtInternal(o2, s2Value))6432;64336434if (o2 == s2len) {6435return i;6436}64376438start = i - 1;6439}6440}6441} else {6442return start < s1len ? start : s1len;6443}6444} else {6445return -1;6446}6447}64486449/**6450* Answers the size of this String.6451*6452* @return the number of characters in this String6453*/6454public int length() {6455return lengthInternal();6456}64576458/**6459* Answers the size of this String. This method is to be used internally within the current package whenever6460* possible as the JIT compiler will take special precaution to avoid generating HCR guards for calls to this6461* method.6462*6463* @return the number of characters in this String6464*/6465int lengthInternal() {6466if (COMPACT_STRINGS) {6467// Check if the String is compressed6468if (compressionFlag == null || count >= 0) {6469return count;6470}64716472return count & ~uncompressedBit;6473}64746475return count;6476}64776478/**6479* Compares the specified string to this String and compares the specified range of characters to determine if they are the same.6480*6481* @param thisStart6482* the starting offset in this String6483* @param string6484* the string to compare6485* @param start6486* the starting offset in string6487* @param length6488* the number of characters to compare6489* @return true if the ranges of characters is equal, false otherwise6490*6491* @throws NullPointerException6492* when string is null6493*/6494public boolean regionMatches(int thisStart, String string, int start, int length) {6495string.getClass(); // Implicit null check64966497String s1 = this;6498String s2 = string;64996500int s1len = s1.lengthInternal();6501int s2len = s2.lengthInternal();65026503if (start < 0 || s2len - start < length) {6504return false;6505}65066507if (thisStart < 0 || s1len - thisStart < length) {6508return false;6509}65106511return regionMatchesInternal(s1, s2, s1.value, s2.value, thisStart, start, length);6512}65136514private static boolean regionMatchesInternal(String s1, String s2, char[] s1Value, char[] s2Value, int s1Start, int s2Start, int length)6515{6516if (length <= 0) {6517return true;6518}65196520// Index of the last char to compare6521int end = length - 1;65226523if (COMPACT_STRINGS && ((compressionFlag == null) || ((s1.count | s2.count) >= 0))) {6524if (helpers.getByteFromArrayByIndex(s1Value, s1Start + end) != helpers.getByteFromArrayByIndex(s2Value, s2Start + end)) {6525return false;6526} else {6527for (int i = 0; i < end; ++i) {6528if (helpers.getByteFromArrayByIndex(s1Value, s1Start + i) != helpers.getByteFromArrayByIndex(s2Value, s2Start + i)) {6529return false;6530}6531}6532}6533} else {6534if (s1.charAtInternal(s1Start + end, s1Value) != s2.charAtInternal(s2Start + end, s2Value)) {6535return false;6536} else {6537for (int i = 0; i < end; ++i) {6538if (s1.charAtInternal(s1Start + i, s1Value) != s2.charAtInternal(s2Start + i, s2Value)) {6539return false;6540}6541}6542}6543}6544return true;6545}65466547/**6548* Compares the specified string to this String and compares the specified range of characters to determine if they are the same. When ignoreCase6549* is true, the case of the characters is ignored during the comparison.6550*6551* @param ignoreCase6552* specifies if case should be ignored6553* @param thisStart6554* the starting offset in this String6555* @param string6556* the string to compare6557* @param start6558* the starting offset in string6559* @param length6560* the number of characters to compare6561* @return true if the ranges of characters is equal, false otherwise6562*6563* @throws NullPointerException6564* when string is null6565*/6566public boolean regionMatches(boolean ignoreCase, int thisStart, String string, int start, int length) {6567if (!ignoreCase) {6568return regionMatches(thisStart, string, start, length);6569}65706571string.getClass(); // Implicit null check65726573String s1 = this;6574String s2 = string;65756576int s1len = s1.lengthInternal();6577int s2len = s2.lengthInternal();65786579if (thisStart < 0 || length > s1len - thisStart) {6580return false;6581}65826583if (start < 0 || length > s2len - start) {6584return false;6585}65866587if (length <= 0) {6588return true;6589}65906591int o1 = thisStart;6592int o2 = start;65936594// Upper bound index on the last char to compare6595int end = thisStart + length;65966597char[] s1Value = s1.value;6598char[] s2Value = s2.value;65996600if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {6601while (o1 < end) {6602byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);6603byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);66046605if ((byteAtO1 != byteAtO2)6606&& (!charValuesEqualIgnoreCase(helpers.byteToCharUnsigned(byteAtO1), helpers.byteToCharUnsigned(byteAtO2)))6607) {6608return false;6609}6610}6611} else {6612while (o1 < end) {6613char charAtO1 = s1.charAtInternal(o1++, s1Value);6614char charAtO2 = s2.charAtInternal(o2++, s2Value);66156616if ((charAtO1 != charAtO2)6617&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))6618) {6619return false;6620}6621}6622}66236624return true;6625}66266627/**6628* Replaces occurrences of the specified character with another character.6629*6630* @param oldChar6631* the character to replace6632* @param newChar6633* the replacement character6634* @return a String with occurrences of oldChar replaced by newChar6635*/6636public String replace(char oldChar, char newChar) {6637int index = indexOf(oldChar, 0);66386639if (index == -1) {6640return this;6641}66426643int len = lengthInternal();66446645// Check if the String is compressed6646if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6647if (newChar <= 255) {6648char[] buffer = new char[(len + 1) >>> 1];66496650compressedArrayCopy(value, 0, buffer, 0, len);66516652do {6653helpers.putByteInArrayByIndex(buffer, index++, (byte) newChar);6654} while ((index = indexOf(oldChar, index)) != -1);66556656return new String(buffer, 0, len, true);6657} else {6658char[] buffer = new char[len];66596660decompress(value, 0, buffer, 0, len);66616662do {6663buffer[index++] = newChar;6664} while ((index = indexOf(oldChar, index)) != -1);66656666return new String(buffer, 0, len, false);6667}6668} else {6669char[] buffer = new char[len];66706671System.arraycopy(value, 0, buffer, 0, len);66726673do {6674buffer[index++] = newChar;6675} while ((index = indexOf(oldChar, index)) != -1);66766677return new String(buffer, 0, len, false);6678}6679}66806681/**6682* Compares the specified string to this String to determine if the specified string is a prefix.6683*6684* @param prefix6685* the string to look for6686* @return true when the specified string is a prefix of this String, false otherwise6687*6688* @throws NullPointerException6689* when prefix is null6690*/6691public boolean startsWith(String prefix) {6692return startsWith(prefix, 0);6693}66946695/**6696* Compares the specified string to this String, starting at the specified offset, to determine if the specified string is a prefix.6697*6698* @param prefix6699* the string to look for6700* @param start6701* the starting offset6702* @return true when the specified string occurs in this String at the specified offset, false otherwise6703*6704* @throws NullPointerException6705* when prefix is null6706*/6707public boolean startsWith(String prefix, int start) {6708if (prefix.length() == 1) {6709if (start < 0 || start >= this.length()) {6710return false;6711}6712return charAtInternal(start) == prefix.charAtInternal(0);6713}6714return regionMatches(start, prefix, 0, prefix.lengthInternal());6715}67166717/**6718* Copies a range of characters into a new String.6719*6720* @param start6721* the offset of the first character6722* @return a new String containing the characters from start to the end of the string6723*6724* @throws IndexOutOfBoundsException6725* when {@code start < 0} or {@code start > length()}6726*/6727public String substring(int start) {6728if (start == 0) {6729return this;6730}6731if (start < 0) {6732throw new StringIndexOutOfBoundsException(start);6733}6734int len = lengthInternal();6735if (start <= len) {6736// Check if the String is compressed6737if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6738return new String(value, start, len - start, true, enableSharingInSubstringWhenOffsetIsZero);6739} else {6740return new String(value, start, len - start, false, enableSharingInSubstringWhenOffsetIsZero);6741}6742}6743throw new StringIndexOutOfBoundsException("begin " + start + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$6744}67456746/**6747* Copies a range of characters.6748*6749* @param start6750* the offset of the first character6751* @param end6752* the offset one past the last character6753* @return a String containing the characters from start to end - 16754*6755* @throws IndexOutOfBoundsException6756* when {@code start < 0, start > end} or {@code end > length()}6757*/6758public String substring(int start, int end) {6759int len = lengthInternal();6760if ((start == 0) && (end == len)) {6761return this;6762}6763if ((start >= 0) && (start <= end) && (end <= len)) {6764// Check if the String is compressed6765if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6766return new String(value, start, end - start, true, enableSharingInSubstringWhenOffsetIsZero);6767} else {6768return new String(value, start, end - start, false, enableSharingInSubstringWhenOffsetIsZero);6769}6770}6771throw new StringIndexOutOfBoundsException("begin " + start + ", end " + end + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$6772}67736774/**6775* Copies the characters in this String to a character array.6776*6777* @return a character array containing the characters of this String6778*/6779public char[] toCharArray() {6780int len = lengthInternal();67816782char[] buffer = new char[len];67836784// Check if the String is compressed6785if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6786decompress(value, 0, buffer, 0, len);6787} else {6788System.arraycopy(value, 0, buffer, 0, len);6789}67906791return buffer;6792}67936794/**6795* Converts the characters in this String to lowercase, using the default Locale. To convert to lower case independent of any locale, use6796* toLowerCase(Locale.ROOT).6797*6798* @return a new String containing the lowercase characters equivalent to the characters in this String6799*/6800public String toLowerCase() {6801return toLowerCase(Locale.getDefault());6802}68036804private static int toLowerCase(int codePoint) {6805if (codePoint < 128) {6806if ('A' <= codePoint && codePoint <= 'Z') {6807return codePoint + ('a' - 'A');6808} else {6809return codePoint;6810}6811} else {6812return Character.toLowerCase(codePoint);6813}6814}68156816private static int toUpperCase(int codePoint) {6817if (codePoint < 128) {6818if ('a' <= codePoint && codePoint <= 'z') {6819return codePoint - ('a' - 'A');6820} else {6821return codePoint;6822}6823} else {6824return Character.toUpperCase(codePoint);6825}6826}68276828// Some of the data below originated from the Unicode Character Database file6829// www.unicode.org/Public/4.0-Update/SpecialCasing-4.0.0.txt. Data from this6830// file was extracted, used in the code and/or converted to an array6831// representation for performance and size.68326833/*6834UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE68356836Unicode Data Files include all data files under the directories6837http://www.unicode.org/Public/, http://www.unicode.org/reports/,6838http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and6839http://www.unicode.org/utility/trac/browser/.68406841Unicode Data Files do not include PDF online code charts under the6842directory http://www.unicode.org/Public/.68436844Software includes any source code published in the Unicode Standard6845or under the directories6846http://www.unicode.org/Public/, http://www.unicode.org/reports/,6847http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and6848http://www.unicode.org/utility/trac/browser/.68496850NOTICE TO USER: Carefully read the following legal agreement.6851BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S6852DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),6853YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE6854TERMS AND CONDITIONS OF THIS AGREEMENT.6855IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE6856THE DATA FILES OR SOFTWARE.68576858COPYRIGHT AND PERMISSION NOTICE68596860Copyright (c) 1991-2017 Unicode, Inc. All rights reserved.6861Distributed under the Terms of Use in http://www.unicode.org/copyright.html.68626863Permission is hereby granted, free of charge, to any person obtaining6864a copy of the Unicode data files and any associated documentation6865(the "Data Files") or Unicode software and any associated documentation6866(the "Software") to deal in the Data Files or Software6867without restriction, including without limitation the rights to use,6868copy, modify, merge, publish, distribute, and/or sell copies of6869the Data Files or Software, and to permit persons to whom the Data Files6870or Software are furnished to do so, provided that either6871(a) this copyright and permission notice appear with all copies6872of the Data Files or Software, or6873(b) this copyright and permission notice appear in associated6874Documentation.68756876THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF6877ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE6878WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND6879NONINFRINGEMENT OF THIRD PARTY RIGHTS.6880IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS6881NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL6882DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,6883DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER6884TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR6885PERFORMANCE OF THE DATA FILES OR SOFTWARE.68866887Except as contained in this notice, the name of a copyright holder6888shall not be used in advertising or otherwise to promote the sale,6889use or other dealings in these Data Files or Software without prior6890written authorization of the copyright holder.6891*/68926893/**6894* Converts the characters in this String to lowercase, using the specified Locale.6895*6896* @param locale6897* the Locale6898* @return a String containing the lowercase characters equivalent to the characters in this String6899*/6900public String toLowerCase(Locale locale) {6901// check locale for null6902String language = locale.getLanguage();6903int sLength = lengthInternal();69046905if (sLength == 0) {6906return this;6907}69086909if (helpers.supportsIntrinsicCaseConversion() && (language == "en")) { //$NON-NLS-1$6910if (COMPACT_STRINGS && ((null == compressionFlag) || (count >= 0))) {6911char[] output = new char[(sLength + 1) >>> 1];6912if (helpers.toLowerIntrinsicLatin1(value, output, sLength)) {6913return new String(output, 0, sLength, true);6914}6915} else if (sLength <= (Integer.MAX_VALUE / 2)) {6916char[] output = new char[sLength];6917if (helpers.toLowerIntrinsicUTF16(value, output, sLength * 2)) {6918return new String(output, 0, sLength, false);6919}6920}6921}69226923return toLowerCaseCore(language);6924}69256926/**6927* The core of lower case conversion. This is the old, not-as-fast path.6928*6929* @param language6930* a string representing the Locale6931* @return a new string object6932*/6933private String toLowerCaseCore(String language) {6934boolean turkishAzeri = false;6935boolean lithuanian = false;69366937StringBuilder builder = null;69386939int len = lengthInternal();69406941for (int i = 0; i < len; i++) {6942int codePoint = charAtInternal(i);69436944if (codePoint >= Character.MIN_HIGH_SURROGATE && codePoint <= Character.MAX_HIGH_SURROGATE) {6945codePoint = codePointAt(i);6946}69476948int lowerCase = toLowerCase(codePoint);69496950if (codePoint != lowerCase) {6951if (builder == null) {6952turkishAzeri = language == "tr" || language == "az"; //$NON-NLS-1$ //$NON-NLS-2$6953lithuanian = language == "lt"; //$NON-NLS-1$69546955builder = new StringBuilder(len);69566957// Check if the String is compressed6958if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {6959builder.append(value, 0, i, true);6960} else {6961builder.append(value, 0, i, false);6962}6963}69646965if (codePoint == 0x3A3) {6966builder.append(convertSigma(i));69676968continue;6969}69706971if (!turkishAzeri && (0x0130 == codePoint)) {6972builder.append("i\u0307"); //$NON-NLS-1$69736974continue;6975}69766977if (turkishAzeri) {6978if (codePoint == 0x49) {6979// Special case mappings. Latin Capital Letter I becomes Latin Small Letter Dotless i, unless followed by Combining Dot Above6980boolean combiningDotAbove = (i + 1) < len && charAtInternal(i + 1) == '\u0307';69816982builder.append(combiningDotAbove ? 'i' : '\u0131');69836984if (combiningDotAbove) {6985++i;6986}6987} else {6988builder.appendCodePoint(lowerCase);6989}6990} else if (lithuanian) {6991// Latin Capital Letter I, Latin Capital Letter J, Latin Capital Letter I with Ogonek6992if (codePoint == 0x49 || codePoint == 0x4A || codePoint == 0x12E) {6993builder.append(codePoint == 0x12E ? '\u012F' : (char) (codePoint + 0x20));69946995if ((i + 1) < len) {6996int nextPoint = codePointAt(i + 1);69976998if (isCombiningAbove(nextPoint)) {6999builder.append('\u0307');7000}7001}7002// Latin Capital Letter I with Grave7003} else if (codePoint == 0xCC) {7004builder.append("i\u0307\u0300"); //$NON-NLS-1$7005// Latin Capital Letter I with Acute7006} else if (codePoint == 0xCD) {7007builder.append("i\u0307\u0301"); //$NON-NLS-1$7008// Latin Capital Letter I with Tilde7009} else if (codePoint == 0x128) {7010builder.append("i\u0307\u0303"); //$NON-NLS-1$7011} else {7012builder.appendCodePoint(lowerCase);7013}7014} else {7015builder.appendCodePoint(lowerCase);70167017}7018} else if (builder != null) {7019builder.appendCodePoint(codePoint);7020}70217022if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {7023++i;7024}7025}70267027if (builder == null) {7028return this;7029}70307031return builder.toString();7032}70337034private static int binarySearchRange(char[] data, char c) {7035char value = 0;70367037int low = 0;7038int mid = -1;7039int high = data.length - 1;70407041while (low <= high) {7042mid = (low + high) >>> 1;70437044value = data[mid];70457046if (c > value) {7047low = mid + 1;7048} else if (c == value) {7049return mid;7050} else {7051high = mid - 1;7052}7053}70547055return mid - (c < value ? 1 : 0);7056}70577058/* The following code points are extracted from the Canonical_Combining_Class=Above table found in:7059* https://www.unicode.org/Public/6.2.0/ucd/extracted/DerivedCombiningClass.txt7060*/7061private static char[] startCombiningAbove = { '\u0300', '\u033D', '\u0346', '\u034A', '\u0350', '\u0357', '\u035B', '\u0363', '\u0483', '\u0592',7062'\u0597', '\u059C', '\u05A8', '\u05AB', '\u05AF', '\u05C4', '\u0610', '\u0653', '\u0657', '\u065D', '\u06D6', '\u06DF', '\u06E4', '\u06E7',7063'\u06EB', '\u0730', '\u0732', '\u0735', '\u073A', '\u073D', '\u073F', '\u0743', '\u0745', '\u0747', '\u0749', '\u07EB', '\u07F3', '\u0816',7064'\u081B', '\u0825', '\u0829', '\u08E4', '\u08E7', '\u08EA', '\u08F3', '\u08F7', '\u08FB', '\u0951', '\u0953', '\u0F82', '\u0F86', '\u135D',7065'\u17DD', '\u193A', '\u1A17', '\u1A75', '\u1B6B', '\u1B6D', '\u1CD0', '\u1CDA', '\u1CE0', '\u1CF4', '\u1DC0', '\u1DC3', '\u1DCB', '\u1DD1',7066'\u1DFE', '\u20D0', '\u20D4', '\u20DB', '\u20E1', '\u20E7', '\u20E9', '\u20F0', '\u2CEF', '\u2DE0', '\uA66F', '\uA674', '\uA69F', '\uA6F0',7067'\uA8E0', '\uAAB0', '\uAAB2', '\uAAB7', '\uAABE', '\uAAC1', '\uFE20' };7068private static char[] endCombiningAbove = { '\u0314', '\u0344', '\u0346', '\u034C', '\u0352', '\u0357', '\u035B', '\u036F', '\u0487', '\u0595',7069'\u0599', '\u05A1', '\u05A9', '\u05AC', '\u05AF', '\u05C4', '\u0617', '\u0654', '\u065B', '\u065E', '\u06DC', '\u06E2', '\u06E4', '\u06E8',7070'\u06EC', '\u0730', '\u0733', '\u0736', '\u073A', '\u073D', '\u0741', '\u0743', '\u0745', '\u0747', '\u074A', '\u07F1', '\u07F3', '\u0819',7071'\u0823', '\u0827', '\u082D', '\u08E5', '\u08E8', '\u08EC', '\u08F5', '\u08F8', '\u08FE', '\u0951', '\u0954', '\u0F83', '\u0F87', '\u135F',7072'\u17DD', '\u193A', '\u1A17', '\u1A7C', '\u1B6B', '\u1B73', '\u1CD2', '\u1CDB', '\u1CE0', '\u1CF4', '\u1DC1', '\u1DC9', '\u1DCC', '\u1DE6',7073'\u1DFE', '\u20D1', '\u20D7', '\u20DC', '\u20E1', '\u20E7', '\u20E9', '\u20F0', '\u2CF1', '\u2DFF', '\uA66F', '\uA67D', '\uA69F', '\uA6F1',7074'\uA8F1', '\uAAB0', '\uAAB3', '\uAAB8', '\uAABF', '\uAAC1', '\uFE26' };7075private static char[] upperValues = { '\u0053', '\u0053', '\u0000', '\u02BC', '\u004E', '\u0000', '\u004A', '\u030C', '\u0000', '\u0399',7076'\u0308', '\u0301', '\u03A5', '\u0308', '\u0301', '\u0535', '\u0552', '\u0000', '\u0048', '\u0331', '\u0000', '\u0054', '\u0308', '\u0000',7077'\u0057', '\u030A', '\u0000', '\u0059', '\u030A', '\u0000', '\u0041', '\u02BE', '\u0000', '\u03A5', '\u0313', '\u0000', '\u03A5', '\u0313',7078'\u0300', '\u03A5', '\u0313', '\u0301', '\u03A5', '\u0313', '\u0342', '\u1F08', '\u0399', '\u0000', '\u1F09', '\u0399', '\u0000', '\u1F0A',7079'\u0399', '\u0000', '\u1F0B', '\u0399', '\u0000', '\u1F0C', '\u0399', '\u0000', '\u1F0D', '\u0399', '\u0000', '\u1F0E', '\u0399', '\u0000',7080'\u1F0F', '\u0399', '\u0000', '\u1F08', '\u0399', '\u0000', '\u1F09', '\u0399', '\u0000', '\u1F0A', '\u0399', '\u0000', '\u1F0B', '\u0399',7081'\u0000', '\u1F0C', '\u0399', '\u0000', '\u1F0D', '\u0399', '\u0000', '\u1F0E', '\u0399', '\u0000', '\u1F0F', '\u0399', '\u0000', '\u1F28',7082'\u0399', '\u0000', '\u1F29', '\u0399', '\u0000', '\u1F2A', '\u0399', '\u0000', '\u1F2B', '\u0399', '\u0000', '\u1F2C', '\u0399', '\u0000',7083'\u1F2D', '\u0399', '\u0000', '\u1F2E', '\u0399', '\u0000', '\u1F2F', '\u0399', '\u0000', '\u1F28', '\u0399', '\u0000', '\u1F29', '\u0399',7084'\u0000', '\u1F2A', '\u0399', '\u0000', '\u1F2B', '\u0399', '\u0000', '\u1F2C', '\u0399', '\u0000', '\u1F2D', '\u0399', '\u0000', '\u1F2E',7085'\u0399', '\u0000', '\u1F2F', '\u0399', '\u0000', '\u1F68', '\u0399', '\u0000', '\u1F69', '\u0399', '\u0000', '\u1F6A', '\u0399', '\u0000',7086'\u1F6B', '\u0399', '\u0000', '\u1F6C', '\u0399', '\u0000', '\u1F6D', '\u0399', '\u0000', '\u1F6E', '\u0399', '\u0000', '\u1F6F', '\u0399',7087'\u0000', '\u1F68', '\u0399', '\u0000', '\u1F69', '\u0399', '\u0000', '\u1F6A', '\u0399', '\u0000', '\u1F6B', '\u0399', '\u0000', '\u1F6C',7088'\u0399', '\u0000', '\u1F6D', '\u0399', '\u0000', '\u1F6E', '\u0399', '\u0000', '\u1F6F', '\u0399', '\u0000', '\u1FBA', '\u0399', '\u0000',7089'\u0391', '\u0399', '\u0000', '\u0386', '\u0399', '\u0000', '\u0391', '\u0342', '\u0000', '\u0391', '\u0342', '\u0399', '\u0391', '\u0399',7090'\u0000', '\u1FCA', '\u0399', '\u0000', '\u0397', '\u0399', '\u0000', '\u0389', '\u0399', '\u0000', '\u0397', '\u0342', '\u0000', '\u0397',7091'\u0342', '\u0399', '\u0397', '\u0399', '\u0000', '\u0399', '\u0308', '\u0300', '\u0399', '\u0308', '\u0301', '\u0399', '\u0342', '\u0000',7092'\u0399', '\u0308', '\u0342', '\u03A5', '\u0308', '\u0300', '\u03A5', '\u0308', '\u0301', '\u03A1', '\u0313', '\u0000', '\u03A5', '\u0342',7093'\u0000', '\u03A5', '\u0308', '\u0342', '\u1FFA', '\u0399', '\u0000', '\u03A9', '\u0399', '\u0000', '\u038F', '\u0399', '\u0000', '\u03A9',7094'\u0342', '\u0000', '\u03A9', '\u0342', '\u0399', '\u03A9', '\u0399', '\u0000', '\u0046', '\u0046', '\u0000', '\u0046', '\u0049', '\u0000',7095'\u0046', '\u004C', '\u0000', '\u0046', '\u0046', '\u0049', '\u0046', '\u0046', '\u004C', '\u0053', '\u0054', '\u0000', '\u0053', '\u0054',7096'\u0000', '\u0544', '\u0546', '\u0000', '\u0544', '\u0535', '\u0000', '\u0544', '\u053B', '\u0000', '\u054E', '\u0546', '\u0000', '\u0544',7097'\u053D', '\u0000' };7098private static char[] upperIndexs = { '\u000B', '\u0000', '\f', '\u0000', '\r', '\u0000', '\u000E', '\u0000', '\u0000', '\u0000', '\u0000',7099'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000',7100'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000',7101'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u000F', '\u0010', '\u0011', '\u0012', '\u0013',7102'\u0014', '\u0015', '\u0016', '\u0017', '\u0018', '\u0019', '\u001A', '\u001B', '\u001C', '\u001D', '\u001E', '\u001F', '\u0020', '\u0021',7103'\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\'', '\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F',7104'\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037', '\u0038', '\u0039', '\u003A', '\u003B', '\u003C', '\u003D',7105'\u003E', '\u0000', '\u0000', '\u003F', '\u0040', '\u0041', '\u0000', '\u0042', '\u0043', '\u0000', '\u0000', '\u0000', '\u0000', '\u0044',7106'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0045', '\u0046', '\u0047', '\u0000', '\u0048', '\u0049', '\u0000', '\u0000', '\u0000',7107'\u0000', '\u004A', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u004B', '\u004C', '\u0000', '\u0000', '\u004D', '\u004E', '\u0000',7108'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u004F', '\u0050', '\u0051', '\u0000', '\u0052',7109'\u0053', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0054', '\u0055', '\u0056',7110'\u0000', '\u0057', '\u0058', '\u0000', '\u0000', '\u0000', '\u0000', '\u0059' };71117112private static boolean isCombiningAbove(int codePoint) {7113if (codePoint < 0xFFFF) {7114int index = binarySearchRange(startCombiningAbove, (char) codePoint);71157116return index >= 0 && endCombiningAbove[index] >= codePoint;7117/* The following code points are extracted from the Canonical_Combining_Class=Above table found in:7118* https://www.unicode.org/Public/6.2.0/ucd/extracted/DerivedCombiningClass.txt7119*/7120} else if (codePoint == 0x10A0F || codePoint == 0x10A38 ||7121(codePoint >= 0x11100 && codePoint <= 0x11102) ||7122(codePoint >= 0x1D185 && codePoint <= 0x1D189) ||7123(codePoint >= 0x1D1AA && codePoint <= 0x1D1AD) ||7124(codePoint >= 0x1D242 && codePoint <= 0x1D244)) {7125return true;7126}71277128return false;7129}71307131private static boolean isWordPart(int codePoint) {7132return codePoint == 0x345 || isWordStart(codePoint);7133}71347135private static boolean isWordStart(int codePoint) {7136int type = Character.getType(codePoint);71377138return (type >= Character.UPPERCASE_LETTER && type <= Character.TITLECASE_LETTER) || (codePoint >= 0x2B0 && codePoint <= 0x2B8)7139|| (codePoint >= 0x2C0 && codePoint <= 0x2C1) || (codePoint >= 0x2E0 && codePoint <= 0x2E4) || codePoint == 0x37A7140|| (codePoint >= 0x2160 && codePoint <= 0x217F) || (codePoint >= 0x1D2C && codePoint <= 0x1D61);7141}71427143private char convertSigma(int pos) {7144if (pos == 0 || !isWordStart(codePointBefore(pos)) || ((pos + 1) < lengthInternal() && isWordPart(codePointAt(pos + 1)))) {7145return '\u03C3';7146}7147return '\u03C2';7148}71497150/**7151* Answers a string containing a concise, human-readable description of the receiver.7152*7153* @return this String7154*/7155public String toString() {7156return this;7157}71587159/**7160* Converts the characters in this String to uppercase, using the default Locale. To convert to upper case independent of any locale, use7161* toUpperCase(Locale.ROOT).7162*7163* @return a String containing the uppercase characters equivalent to the characters in this String7164*/7165public String toUpperCase() {7166return toUpperCase(Locale.getDefault());7167}71687169/**7170* Return the index of the specified character into the upperValues table. The upperValues table contains three entries at each position. These7171* three characters are the upper case conversion. If only two characters are used, the third character in the table is \u0000.7172*7173* @param ch7174* the char being converted to upper case7175*7176* @return the index into the upperValues table, or -17177*/7178private static int upperIndex(int ch) {7179int index = -1;71807181if (ch <= 0x587) {7182if (ch == 0xDF) {7183index = 0;7184} else if (ch <= 0x149) {7185if (ch == 0x149) {7186index = 1;7187}7188} else if (ch <= 0x1F0) {7189if (ch == 0x1F0) {7190index = 2;7191}7192} else if (ch <= 0x390) {7193if (ch == 0x390) {7194index = 3;7195}7196} else if (ch <= 0x3B0) {7197if (ch == 0x3B0) {7198index = 4;7199}7200} else if (ch <= 0x587) {7201if (ch == 0x587) {7202index = 5;7203}7204}7205} else if (ch >= 0x1E96) {7206if (ch <= 0x1E9A) {7207index = 6 + ch - 0x1E96;7208} else if (ch >= 0x1F50 && ch <= 0x1FFC) {7209index = upperIndexs[ch - 0x1F50];72107211if (index == 0) {7212index = -1;7213}7214} else if (ch >= 0xFB00) {7215if (ch <= 0xFB06) {7216index = 90 + ch - 0xFB00;7217} else if (ch >= 0xFB13 && ch <= 0xFB17) {7218index = 97 + ch - 0xFB13;7219}7220}7221}72227223return index;7224}72257226/**7227* Converts the characters in this String to uppercase, using the specified Locale.7228*7229* @param locale7230* the Locale7231* @return a String containing the uppercase characters equivalent to the characters in this String7232*/7233public String toUpperCase(Locale locale) {7234String language = locale.getLanguage();7235int sLength = lengthInternal();72367237if (sLength == 0) {7238return this;7239}72407241if (helpers.supportsIntrinsicCaseConversion() && (language == "en")) { //$NON-NLS-1$7242if (COMPACT_STRINGS && ((null == compressionFlag) || (count >= 0))) {7243char[] output = new char[(sLength + 1) >>> 1];7244if (helpers.toUpperIntrinsicLatin1(value, output, sLength)) {7245return new String(output, 0, sLength, true);7246}7247} else if (sLength <= (Integer.MAX_VALUE / 2)) {7248char[] output = new char[sLength];7249if (helpers.toUpperIntrinsicUTF16(value, output, sLength * 2)) {7250return new String(output, 0, sLength, false);7251}7252}7253}72547255return toUpperCaseCore(language);7256}72577258/**7259* The core of upper case conversion. This is the old, not-as-fast path.7260*7261* @param language7262* the string representing the locale7263* @return the upper case string7264*/7265private String toUpperCaseCore(String language) {7266boolean turkishAzeri = language == "tr" || language == "az"; //$NON-NLS-1$ //$NON-NLS-2$7267boolean lithuanian = language == "lt"; //$NON-NLS-1$72687269StringBuilder builder = null;72707271int len = lengthInternal();72727273for (int i = 0; i < len; i++) {7274int codePoint = charAtInternal(i);72757276if (codePoint >= Character.MIN_HIGH_SURROGATE && codePoint <= Character.MAX_HIGH_SURROGATE) {7277codePoint = codePointAt(i);7278}72797280int index = -1;72817282if (codePoint >= 0xDF && codePoint <= 0xFB17) {7283index = upperIndex(codePoint);7284}72857286if (index == -1) {7287int upper = (!turkishAzeri || codePoint != 0x69) ? toUpperCase(codePoint) : 0x130;72887289if (codePoint != upper) {7290if (builder == null) {7291builder = new StringBuilder(len);72927293// Check if the String is compressed7294if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {7295builder.append(value, 0, i, true);7296} else {7297builder.append(value, 0, i, false);7298}7299}73007301builder.appendCodePoint(upper);7302} else if (builder != null) {7303builder.appendCodePoint(codePoint);7304}73057306if (lithuanian && codePoint <= 0x1ECB && (i + 1) < len && charAt(i + 1) == '\u0307'7307&& "ij\u012F\u0268\u0456\u0458\u1E2D\u1ECB".indexOf(codePoint, 0) != -1) //$NON-NLS-1$7308{7309++i;7310}7311} else {7312if (builder == null) {7313builder = new StringBuilder(len + (len / 6) + 2).append(this, 0, i);7314}73157316int target = index * 3;73177318builder.append(upperValues[target]);7319builder.append(upperValues[target + 1]);73207321char val = upperValues[target + 2];73227323if (val != 0) {7324builder.append(val);7325}7326}73277328if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {7329++i;7330}7331}73327333if (builder == null) {7334return this;7335}73367337return builder.toString();7338}73397340/**7341* Removes white space characters from the beginning and end of the string.7342*7343* @return a String with characters {@code <= \\u0020} removed from the beginning and the end7344*/7345public String trim() {7346int start = 0;7347int last = lengthInternal() - 1;7348int end = last;73497350// Check if the String is compressed7351if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {7352while ((start <= end) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, start)) <= ' ')) {7353start++;7354}73557356while ((end >= start) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, end)) <= ' ')) {7357end--;7358}73597360if (start == 0 && end == last) {7361return this;7362} else {7363return new String(value, start, end - start + 1, true);7364}7365} else {7366while ((start <= end) && (charAtInternal(start) <= ' ')) {7367start++;7368}73697370while ((end >= start) && (charAtInternal(end) <= ' ')) {7371end--;7372}73737374if (start == 0 && end == last) {7375return this;7376} else {7377return new String(value, start, end - start + 1, false);7378}7379}7380}73817382/**7383* Returns a String containing the characters in the specified character array. Modifying the character array after creating the String has no7384* effect on the String.7385*7386* @param data7387* the array of characters7388* @return the String7389*7390* @throws NullPointerException7391* when data is null7392*/7393public static String valueOf(char[] data) {7394return new String(data, 0, data.length);7395}73967397/**7398* Returns a String containing the specified characters in the character array. Modifying the character array after creating the String has no7399* effect on the String.7400*7401* @param data7402* the array of characters7403* @param start7404* the starting offset in the character array7405* @param length7406* the number of characters to use7407* @return the String7408*7409* @throws IndexOutOfBoundsException7410* when {@code length < 0, start < 0} or {@code start + length > data.length}7411* @throws NullPointerException7412* when data is null7413*/7414public static String valueOf(char[] data, int start, int length) {7415return new String(data, start, length);7416}74177418/**7419* Converts the specified character to its string representation.7420*7421* @param value7422* the character7423* @return the character converted to a string7424*/7425public static String valueOf(char value) {7426String string;74277428if (value <= 255) {7429if (COMPACT_STRINGS) {7430string = new String(compressedAsciiTable[value], 0, 1, true);7431} else {7432string = new String(decompressedAsciiTable[value], 0, 1, false);7433}7434} else {7435string = new String(new char[] { value }, 0, 1, false);7436}74377438return string;7439}74407441/**7442* Converts the specified double to its string representation.7443*7444* @param value7445* the double7446* @return the double converted to a string7447*/7448public static String valueOf(double value) {7449return Double.toString(value);7450}74517452/**7453* Converts the specified float to its string representation.7454*7455* @param value7456* the float7457* @return the float converted to a string7458*/7459public static String valueOf(float value) {7460return Float.toString(value);7461}74627463/**7464* Converts the specified integer to its string representation.7465*7466* @param value7467* the integer7468* @return the integer converted to a string7469*/7470public static String valueOf(int value) {7471return Integer.toString(value);7472}74737474/**7475* Converts the specified long to its string representation.7476*7477* @param value7478* the long7479* @return the long converted to a string7480*/7481public static String valueOf(long value) {7482return Long.toString(value);7483}74847485/**7486* Converts the specified object to its string representation. If the object is null answer the string {@code "null"}, otherwise use7487* {@code toString()} to get the string representation.7488*7489* @param value7490* the object7491* @return the object converted to a string7492*/7493public static String valueOf(Object value) {7494return value != null ? value.toString() : "null"; //$NON-NLS-1$7495}74967497/**7498* Converts the specified boolean to its string representation. When the boolean is true answer {@code "true"}, otherwise answer7499* {@code "false"}.7500*7501* @param value7502* the boolean7503* @return the boolean converted to a string7504*/7505public static String valueOf(boolean value) {7506return value ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$7507}75087509/**7510* Answers whether the characters in the StringBuffer buffer are the same as those in this String.7511*7512* @param buffer7513* the StringBuffer to compare this String to7514* @return true when the characters in buffer are identical to those in this String. If they are not, false will be returned.7515*7516* @throws NullPointerException7517* when buffer is null7518*7519* @since 1.47520*/7521public boolean contentEquals(StringBuffer buffer) {7522synchronized (buffer) {7523int size = buffer.length();75247525if (lengthInternal() != size) {7526return false;7527}75287529if (COMPACT_STRINGS && buffer.isCompressed()) {7530return regionMatches(0, new String(buffer.getValue(), 0, size, true), 0, size);7531} else {7532return regionMatches(0, new String(buffer.getValue(), 0, size, false), 0, size);7533}7534}7535}75367537/**7538* Determines whether a this String matches a given regular expression.7539*7540* @param expr7541* the regular expression to be matched7542* @return true if the expression matches, otherwise false7543*7544* @throws PatternSyntaxException7545* if the syntax of the supplied regular expression is not valid7546* @throws NullPointerException7547* if expr is null7548*7549* @since 1.47550*/7551public boolean matches(String expr) {7552return Pattern.matches(expr, this);7553}75547555/**7556* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.7557*7558* @param regex7559* the regular expression to match7560* @param substitute7561* the string to replace the matching substring with7562* @return the new string7563*7564* @throws NullPointerException7565* if expr is null7566*7567* @since 1.47568*/7569public String replaceAll(String regex, String substitute) {7570// this is a fast path to handle replacements of 1 character with another or the deletion of7571// a single character (common operations when dealing with things like package names, file7572// system paths etc). In these simple cases a linear scan of the string is all that is necessary7573// and we can avoid the cost of building a full regex pattern matcher7574if (regex != null && substitute != null && regex.lengthInternal() == 1 && !hasMetaChars(regex)) {7575int substituteLength = substitute.lengthInternal();7576int length = lengthInternal();7577if (substituteLength < 2) {7578if (COMPACT_STRINGS && isCompressed() && (substituteLength == 0 || substitute.isCompressed())) {7579char[] newChars = new char[(length + 1) >>> 1];7580byte toReplace = helpers.getByteFromArrayByIndex(regex.value, 0);7581byte replacement = (byte)-1; // assign dummy value that will never be used7582if (substituteLength == 1) {7583replacement = helpers.getByteFromArrayByIndex(substitute.value, 0);7584checkLastChar((char)replacement);7585}7586int newCharIndex = 0;7587for (int i = 0; i < length; ++i) {7588byte current = helpers.getByteFromArrayByIndex(value, i);7589if (current != toReplace) {7590helpers.putByteInArrayByIndex(newChars, newCharIndex++, current);7591} else if (substituteLength == 1) {7592helpers.putByteInArrayByIndex(newChars, newCharIndex++, replacement);7593}7594}7595return new String(newChars, 0, newCharIndex, true);7596} else if (!COMPACT_STRINGS || !isCompressed()) {7597char[] newChars = new char[length];7598char toReplace = regex.charAtInternal(0);7599char replacement = (char)-1; // assign dummy value that will never be used7600if (substituteLength == 1) {7601replacement = substitute.charAtInternal(0);7602checkLastChar(replacement);7603}7604int newCharIndex = 0;7605for (int i = 0; i < length; ++i) {7606char current = helpers.getCharFromArrayByIndex(value, i);7607if (current != toReplace) {7608helpers.putCharInArrayByIndex(newChars, newCharIndex++, current);7609} else if (substituteLength == 1) {7610helpers.putCharInArrayByIndex(newChars, newCharIndex++, replacement);7611}7612}7613return new String(newChars, 0, newCharIndex, false);7614}7615}7616}7617return Pattern.compile(regex).matcher(this).replaceAll(substitute);7618}76197620/**7621* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.7622*7623* @param expr7624* the regular expression to match7625* @param substitute7626* the string to replace the matching substring with7627* @return the new string7628*7629* @throws NullPointerException7630* if expr is null7631*7632* @since 1.47633*/7634public String replaceFirst(String expr, String substitute) {7635return Pattern.compile(expr).matcher(this).replaceFirst(substitute);7636}76377638/**7639* Splits this string around matches of the given regular expression. Calling this method is same as calling split(regex,0). Therefore, empty7640* string(s) at the end of the returned array will be discarded.7641*7642*7643* @param regex7644* Regular expression that is used as a delimiter7645* @return The array of strings which are split around the regex7646*7647* @throws PatternSyntaxException7648* if the syntax of regex is invalid7649*7650* @since 1.47651*/7652public String[] split(String regex) {7653return split(regex, 0);7654}76557656private static final char[] regexMetaChars = new char[]7657{ '.', '$', '|', '(', ')', '[', ']', '{', '}', '^', '?', '*', '+', '\\' };76587659private static final boolean hasMetaChars(String s) {7660for (int i = 0; i < s.lengthInternal(); ++i) {7661char ch = s.charAtInternal(i);76627663// Note the surrogate ranges are HIGH: \uD800-\uDBFF; LOW: \uDC00-\uDFFF7664// this check is, therefore, equivalent to returning true if the character7665// falls anywhere in this range including the range between MAX_LOW_SURROGATE7666// and MIN_HIGH_SURROGATE which happen to be adjacent7667if (ch >= Character.MIN_HIGH_SURROGATE7668&& ch <= Character.MAX_LOW_SURROGATE) { return true; }76697670for (int j = 0; j < regexMetaChars.length; ++j) {7671if (ch == regexMetaChars[j]) { return true; }7672}7673}7674return false;7675}76767677private static final boolean isSingleEscapeLiteral(String s) {7678if ((s != null) && (s.lengthInternal() == 2) && (s.charAtInternal(0) == '\\')) {7679char literal = s.charAtInternal(1);7680for (int j = 0; j < regexMetaChars.length; ++j) {7681if (literal == regexMetaChars[j]) return true;7682}7683}7684return false;7685}76867687/**7688* Splits this String using the given regular expression.7689*7690* max controls the number of times the regex is applied to this string.7691* If max is positive, then regex can be applied to this String max-1 times.7692* The returned array size can not be bigger than max, and the last element of7693* the returned array contains all input after the last match of the regex.7694* If max is negative or zero, then regex can be applied to this string as many times as7695* possible and there is no size limit in the returned array.7696* If max is 0, all the empty string(s) at the end of the returned array will be discarded.7697*7698* @param regex Regular expression that is used as a delimiter7699* @param max The threshold of the returned array7700* @return The array of strings which are split around the regex7701*7702* @throws PatternSyntaxException if the syntax of regex is invalid7703*7704* @since 1.47705*/7706public String[] split(String regex, int max) {7707// it is faster to handle simple splits inline (i.e. no fancy regex matching),7708// including single escaped literal character (e.g. \. \{),7709// so we test for a suitable string and handle this here if we can7710boolean singleEscapeLiteral = isSingleEscapeLiteral(regex);7711if ((regex != null) && (regex.lengthInternal() > 0) && (!hasMetaChars(regex) || singleEscapeLiteral)) {7712if (max == 1) {7713return new String[] { this };7714}7715java.util.ArrayList<String> parts = new java.util.ArrayList<String>((max > 0 && max < 100) ? max : 10);77167717char[] chars = this.value;77187719final boolean compressed = COMPACT_STRINGS && (null == compressionFlag || count >= 0);77207721int start = 0, current = 0, end = lengthInternal();7722if (regex.lengthInternal() == 1 || singleEscapeLiteral) {7723// if matching single escaped character, use the second char.7724char splitChar = regex.charAtInternal(singleEscapeLiteral ? 1 : 0);7725while (current < end) {7726if (charAtInternal(current, chars) == splitChar) {7727parts.add(new String(chars, start, current - start, compressed));7728start = current + 1;7729if (max > 0 && parts.size() == max - 1) {7730parts.add(new String(chars, start, end - start, compressed));7731break;7732}7733}7734current = current + 1;7735}7736} else {7737int rLength = regex.lengthInternal();77387739char[] splitChars = regex.value;77407741char firstChar = charAtInternal(0, regex.value);7742while (current < end) {7743if (charAtInternal(current, chars) == firstChar) {7744int idx = current + 1;7745int matchIdx = 1;7746while (matchIdx < rLength && idx < end) {7747if (charAtInternal(idx, chars) != charAtInternal(matchIdx, splitChars)) {7748break;7749}7750matchIdx++;7751idx++;7752}7753if (matchIdx == rLength) {7754parts.add(new String(chars, start, current - start, compressed));7755start = current + rLength;7756if (max > 0 && parts.size() == max - 1) {7757parts.add(new String(chars, start, end - start, compressed));7758break;7759}7760current = current + rLength;7761continue;7762}7763}7764current = current + 1;7765}7766}7767if (parts.size() == 0) {7768return new String[] { this };7769} else if (start <= current && parts.size() != max) {7770parts.add(new String(chars, start, current - start, compressed));7771}7772if (max == 0) {7773end = parts.size();7774while (end > 0 && parts.get(end - 1).lengthInternal() == 0) {7775end -= 1;7776parts.remove(end);7777}7778}7779return parts.toArray(new String[parts.size()]);7780}7781return Pattern.compile(regex).split(this, max);7782}77837784/**7785* Has the same result as the substring function, but is present so that String may implement the CharSequence interface.7786*7787* @param start7788* the offset the first character7789* @param end7790* the offset of one past the last character to include7791*7792* @return the subsequence requested7793*7794* @throws IndexOutOfBoundsException7795* when start or end is less than zero, start is greater than end, or end is greater than the length of the String.7796*7797* @see java.lang.CharSequence#subSequence(int, int)7798*7799* @since 1.47800*/7801public CharSequence subSequence(int start, int end) {7802return substring(start, end);7803}78047805/**7806* @param data7807* the byte array to convert to a String7808* @param start7809* the starting offset in the byte array7810* @param length7811* the number of bytes to convert7812*7813* @since 1.57814*/7815public String(int[] data, int start, int length) {7816if (start >= 0 && 0 <= length && length <= data.length - start) {7817int size = 0;78187819// Optimistically assume we can compress data[]7820boolean canEncodeAsLatin1 = COMPACT_STRINGS;78217822for (int i = start; i < start + length; ++i) {7823int codePoint = data[i];78247825if (codePoint < Character.MIN_CODE_POINT) {7826throw new IllegalArgumentException();7827} else if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {7828if (canEncodeAsLatin1 && codePoint > 255) {7829canEncodeAsLatin1 = false;7830}78317832++size;7833} else if (codePoint <= Character.MAX_CODE_POINT) {7834if (canEncodeAsLatin1) {7835codePoint -= Character.MIN_SUPPLEMENTARY_CODE_POINT;78367837int codePoint1 = Character.MIN_HIGH_SURROGATE + (codePoint >> 10);7838int codePoint2 = Character.MIN_LOW_SURROGATE + (codePoint & 0x3FF);78397840if (codePoint1 > 255 || codePoint2 > 255) {7841canEncodeAsLatin1 = false;7842}7843}78447845size += 2;7846} else {7847throw new IllegalArgumentException();7848}7849}78507851if (canEncodeAsLatin1) {7852value = new char[(size + 1) >>> 1];7853count = size;78547855for (int i = start, j = 0; i < start + length; ++i) {7856int codePoint = data[i];78577858if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {7859helpers.putByteInArrayByIndex(value, j++, (byte) codePoint);7860} else {7861codePoint -= Character.MIN_SUPPLEMENTARY_CODE_POINT;78627863int codePoint1 = Character.MIN_HIGH_SURROGATE + (codePoint >> 10);7864int codePoint2 = Character.MIN_LOW_SURROGATE + (codePoint & 0x3FF);78657866helpers.putByteInArrayByIndex(value, j++, (byte) codePoint1);7867helpers.putByteInArrayByIndex(value, j++, (byte) codePoint2);7868}7869}7870} else {7871value = new char[size];78727873if (COMPACT_STRINGS) {7874count = size | uncompressedBit;78757876initCompressionFlag();7877} else {7878count = size;7879}78807881for (int i = start, j = 0; i < start + length; ++i) {7882int codePoint = data[i];78837884if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {7885value[j++] = (char) codePoint;7886} else {7887codePoint -= Character.MIN_SUPPLEMENTARY_CODE_POINT;78887889value[j++] = (char) (Character.MIN_HIGH_SURROGATE + (codePoint >> 10));7890value[j++] = (char) (Character.MIN_LOW_SURROGATE + (codePoint & 0x3FF));7891}7892}7893}7894} else {7895throw new StringIndexOutOfBoundsException();7896}7897}78987899/**7900* Creates a string from the contents of a StringBuilder.7901*7902* @param builder7903* the StringBuilder7904*7905* @since 1.57906*/7907public String(StringBuilder builder) {7908char[] chars = builder.shareValue();79097910if (COMPACT_STRINGS) {7911if (builder.isCompressed()) {7912value = chars;7913count = builder.lengthInternal();7914} else {7915value = chars;7916count = builder.lengthInternal() | uncompressedBit;79177918initCompressionFlag();7919}7920} else {7921value = chars;7922count = builder.lengthInternal();7923}7924}79257926/**7927* Returns the Unicode character at the given point.7928*7929* @param index7930* the character index7931* @return the Unicode character value at the index7932*7933* @since 1.57934*/7935public int codePointAt(int index) {7936int len = lengthInternal();79377938if (index >= 0 && index < len) {7939// Check if the String is compressed7940if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {7941return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));7942} else {7943char high = charAtInternal(index);79447945if ((index < (len - 1)) && Character.isHighSurrogate(high)) {7946char low = charAtInternal(index + 1);79477948if (Character.isLowSurrogate(low)) {7949return Character.toCodePoint(high, low);7950}7951}79527953return high;7954}7955} else {7956throw new StringIndexOutOfBoundsException(index);7957}7958}79597960/**7961* Returns the Unicode character before the given point.7962*7963* @param index7964* the character index7965* @return the Unicode character value before the index7966*7967* @since 1.57968*/7969public int codePointBefore(int index) {7970int len = lengthInternal();79717972if (index > 0 && index <= len) {7973// Check if the String is compressed7974if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {7975return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));7976} else {7977char low = charAtInternal(index - 1);79787979if ((index > 1) && Character.isLowSurrogate(low)) {7980char high = charAtInternal(index - 2);79817982if (Character.isHighSurrogate(high)) {7983return Character.toCodePoint(high, low);7984}7985}79867987return low;7988}7989} else {7990throw new StringIndexOutOfBoundsException(index);7991}7992}79937994/**7995* Returns the total Unicode values in the specified range.7996*7997* @param start7998* first index7999* @param end8000* last index8001* @return the total Unicode values8002*8003* @since 1.58004*/8005public int codePointCount(int start, int end) {8006int len = lengthInternal();80078008if (start >= 0 && start <= end && end <= len) {8009// Check if the String is compressed8010if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {8011return end - start;8012} else {8013int count = 0;80148015for (int i = start; i < end; ++i) {8016if ((i < (end - 1))8017&& Character.isHighSurrogate(charAtInternal(i))8018&& Character.isLowSurrogate(charAtInternal(i + 1))) {8019++i;8020}80218022++count;8023}80248025return count;8026}8027} else {8028throw new IndexOutOfBoundsException();8029}8030}80318032/**8033* Returns the index of the code point that was offset by codePointCount.8034*8035* @param start8036* the position to offset8037* @param codePointCount8038* the code point count8039* @return the offset index8040*8041* @since 1.58042*/8043public int offsetByCodePoints(int start, int codePointCount) {8044int len = lengthInternal();80458046if (start >= 0 && start <= len) {8047// Check if the String is compressed8048if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {8049int index = start + codePointCount;80508051if (index > len) {8052throw new IndexOutOfBoundsException();8053} else {8054return index;8055}8056} else {8057int index = start;80588059if (codePointCount == 0) {8060return start;8061} else if (codePointCount > 0) {8062for (int i = 0; i < codePointCount; ++i) {8063if (index == len) {8064throw new IndexOutOfBoundsException();8065}80668067if ((index < (len - 1))8068&& Character.isHighSurrogate(charAtInternal(index))8069&& Character.isLowSurrogate(charAtInternal(index + 1))) {8070index++;8071}80728073index++;8074}8075} else {8076for (int i = codePointCount; i < 0; ++i) {8077if (index < 1) {8078throw new IndexOutOfBoundsException();8079}80808081if ((index > 1)8082&& Character.isLowSurrogate(charAtInternal(index - 1))8083&& Character.isHighSurrogate(charAtInternal(index - 2))) {8084index--;8085}80868087index--;8088}8089}80908091return index;8092}8093} else {8094throw new IndexOutOfBoundsException();8095}8096}80978098/**8099* Compares the content of the character sequence to this String8100*8101* @param sequence8102* the character sequence8103* @return {@code true} if the content of this String is equal to the character sequence, {@code false} otherwise.8104*8105* @since 1.58106*/8107public boolean contentEquals(CharSequence sequence) {8108int len = lengthInternal();81098110if (len != sequence.length()) {8111return false;8112}81138114for (int i = 0; i < len; ++i) {8115if (charAtInternal(i) != sequence.charAt(i)) {8116return false;8117}8118}81198120return true;8121}81228123/**8124* @param sequence8125* the sequence to compare to8126* @return {@code true} if this String contains the sequence, {@code false} otherwise.8127*8128* @since 1.58129*/8130public boolean contains(CharSequence sequence) {8131int len = lengthInternal();81328133int sequencelen = sequence.length();81348135if (sequencelen > len) {8136return false;8137}81388139int start = 0;81408141if (sequencelen > 0) {8142if (sequencelen + start > len) {8143return false;8144}81458146char charAt0 = sequence.charAt(0);81478148while (true) {8149int i = indexOf(charAt0, start);81508151if (i == -1 || sequencelen + i > len) {8152return false;8153}81548155int o1 = i;8156int o2 = 0;81578158while (++o2 < sequencelen && charAtInternal(++o1) == sequence.charAt(o2))8159;81608161if (o2 == sequencelen) {8162return true;8163}81648165start = i + 1;8166}8167} else {8168return true;8169}8170}81718172/**8173* @param sequence18174* the old character sequence8175* @param sequence28176* the new character sequence8177* @return the new String8178*8179* @since 1.58180*/8181public String replace(CharSequence sequence1, CharSequence sequence2) {8182if (sequence2 == null) {8183throw new NullPointerException();8184}81858186int len = lengthInternal();81878188int sequence1len = sequence1.length();81898190if (sequence1len == 0) {8191int sequence2len = sequence2.length();81928193if ((sequence2len != 0) && (len >= ((Integer.MAX_VALUE - len) / sequence2len))) {8194/*[MSG "K0D01", "Array capacity exceeded"]*/8195throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$8196}81978198StringBuilder builder = new StringBuilder(len + ((len + 1) * sequence2len));81998200builder.append(sequence2);82018202for (int i = 0; i < len; ++i) {8203builder.append(charAt(i)).append(sequence2);8204}82058206return builder.toString();8207} else {8208StringBuilder builder = new StringBuilder();82098210int start = 0;8211int copyStart = 0;82128213char charAt0 = sequence1.charAt(0);82148215while (start < len) {8216int firstIndex = indexOf(charAt0, start);82178218if (firstIndex == -1) {8219break;8220}82218222boolean found = true;82238224if (sequence1len > 1) {8225if (sequence1len > len - firstIndex) {8226/* the tail of this string is too short to find sequence1 */8227break;8228}82298230for (int i = 1; i < sequence1len; i++) {8231if (charAt(firstIndex + i) != sequence1.charAt(i)) {8232found = false;8233break;8234}8235}8236}82378238if (found) {8239builder.append(substring(copyStart, firstIndex)).append(sequence2);82408241copyStart = start = firstIndex + sequence1len;8242} else {8243start = firstIndex + 1;8244}8245}82468247if (builder.length() == 0 && copyStart == 0) {8248return this;8249}82508251builder.append(substring(copyStart));82528253return builder.toString();8254}8255}82568257/**8258* Format the receiver using the specified format and args.8259*8260* @param format8261* the format to use8262* @param args8263* the format arguments to use8264*8265* @return the formatted result8266*8267* @see java.util.Formatter#format(String, Object...)8268*/8269public static String format(String format, Object... args) {8270return new Formatter().format(format, args).toString();8271}82728273/**8274* Format the receiver using the specified local, format and args.8275*8276* @param locale8277* the locale used to create the Formatter, may be null8278* @param format8279* the format to use8280* @param args8281* the format arguments to use8282*8283* @return the formatted result8284*8285* @see java.util.Formatter#format(String, Object...)8286*/8287public static String format(Locale locale, String format, Object... args) {8288return new Formatter(locale).format(format, args).toString();8289}82908291private static final java.io.ObjectStreamField[] serialPersistentFields = {};82928293/**8294* Answers if this String has no characters, a length of zero.8295*8296* @return true if this String has no characters, false otherwise8297*8298* @since 1.68299*8300* @see #length8301*/8302public boolean isEmpty() {8303return lengthInternal() == 0;8304}83058306/**8307* Converts the byte array to a String using the specified Charset.8308*8309* @param data8310* the byte array to convert to a String8311* @param charset8312* the Charset to use8313*8314* @throws NullPointerException8315* when data is null8316*8317* @since 1.68318*8319* @see #String(byte[], int, int, Charset)8320* @see #getBytes(Charset)8321*/8322public String(byte[] data, Charset charset) {8323this(data, 0, data.length, charset);8324}83258326/**8327* Converts the byte array to a String using the specified Charset.8328*8329* @param data8330* the byte array to convert to a String8331* @param start8332* the starting offset in the byte array8333* @param length8334* the number of bytes to convert8335* @param charset8336* the Charset to use8337*8338* @throws IndexOutOfBoundsException8339* when {@code length < 0, start < 0} or {@code start + length > data.length}8340* @throws NullPointerException8341* when data is null8342*8343* @since 1.68344*8345* @see #String(byte[], Charset)8346* @see #getBytes(Charset)8347*/8348public String(byte[] data, int start, int length, Charset charset) {8349if (charset == null) {8350throw new NullPointerException();8351}83528353if (start >= 0 && 0 <= length && length <= data.length - start) {8354char[] chars = StringCoding.decode(charset, data, start, length);83558356if (COMPACT_STRINGS) {8357if (canEncodeAsLatin1(chars, 0, chars.length)) {8358value = new char[(chars.length + 1) >>> 1];8359count = chars.length;83608361compress(chars, 0, value, 0, chars.length);8362} else {8363value = chars;8364count = chars.length | uncompressedBit;83658366initCompressionFlag();8367}8368} else {8369value = chars;8370count = chars.length;8371}8372} else {8373throw new StringIndexOutOfBoundsException();8374}8375}83768377/**8378* Converts this String to a byte encoding using the specified Charset.8379*8380* @param charset8381* the Charset to use8382* @return the byte array encoding of this String8383*8384* @since 1.68385*/8386public byte[] getBytes(Charset charset) {8387int currentLength = lengthInternal();83888389char[] buffer;83908391// Check if the String is compressed8392if (COMPACT_STRINGS && count >= 0) {8393buffer = new char[currentLength];8394decompress(value, 0, buffer, 0, currentLength);8395} else {8396buffer = value;8397}83988399return StringCoding.encode(charset, buffer, 0, currentLength);8400}84018402/**8403* Creates a new String by putting each element together joined by the delimiter. If an element is null, then "null" is used as string to join.8404*8405* @param delimiter8406* Used as joiner to put elements together8407* @param elements8408* Elements to be joined8409* @return string of joined elements by delimiter8410* @throws NullPointerException8411* if one of the arguments is null8412*/8413public static String join(CharSequence delimiter, CharSequence... elements) {8414StringJoiner stringJoiner = new StringJoiner(delimiter);84158416for (CharSequence element : elements) {8417stringJoiner.add(element);8418}84198420return stringJoiner.toString();8421}84228423/**8424* Creates a new String by putting each element together joined by the delimiter. If an element is null, then "null" is used as string to join.8425*8426* @param delimiter8427* Used as joiner to put elements together8428* @param elements8429* Elements to be joined8430* @return string of joined elements by delimiter8431* @throws NullPointerException8432* if one of the arguments is null8433*/8434public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {8435StringJoiner stringJoiner = new StringJoiner(delimiter);84368437Iterator<? extends CharSequence> elementsIterator = elements.iterator();84388439while (elementsIterator.hasNext()) {8440stringJoiner.add(elementsIterator.next());8441}84428443return stringJoiner.toString();8444}84458446/*[ENDIF] Sidecar19-SE*/84478448/*[IF JAVA_SPEC_VERSION >= 12]*/8449/**8450* Apply a function to this string. The function expects a single String input8451* and returns an R.8452*8453* @param f8454* the functional interface to be applied8455*8456* @return the result of application of the function to this string8457*8458* @since 128459*/8460public <R> R transform(Function<? super String, ? extends R> f) {8461return f.apply(this);8462}84638464/**8465* Returns the nominal descriptor of this String instance, or an empty optional8466* if construction is not possible.8467*8468* @return Optional with nominal descriptor of String instance8469*8470* @since 128471*/8472public Optional<String> describeConstable() {8473return Optional.of(this);8474}84758476/**8477* Resolves this ConstantDesc instance.8478*8479* @param lookup8480* parameter is ignored8481*8482* @return the resolved Constable value8483*8484* @since 128485*/8486public String resolveConstantDesc(MethodHandles.Lookup lookup) {8487return this;8488}84898490/**8491* Indents each line of the string depending on the value of n, and normalizes8492* line terminators to the newline character "\n".8493*8494* @param n8495* the number of spaces to indent the string8496*8497* @return the indented string with normalized line terminators8498*8499* @since 128500*/8501public String indent(int n) {8502Stream<String> lines = lines();8503Iterator<String> iter = lines.iterator();8504StringBuilder builder = new StringBuilder();85058506String spaces = n > 0 ? " ".repeat(n) : null;8507int absN = Math.abs(n);85088509while (iter.hasNext()) {8510String currentLine = iter.next();85118512if (n > 0) {8513builder.append(spaces);8514} else if (n < 0) {8515int start = 0;85168517while ((currentLine.length() > start)8518&& (Character.isWhitespace(currentLine.charAt(start)))8519) {8520start++;85218522if (start >= absN) {8523break;8524}8525}8526currentLine = currentLine.substring(start);8527}85288529/**8530* Line terminators are removed when lines() is called. A newline character is8531* added to the end of each line, to normalize line terminators.8532*/8533builder.append(currentLine);8534builder.append("\n");8535}85368537return builder.toString();8538}8539/*[ENDIF] JAVA_SPEC_VERSION >= 12 */85408541/*[IF JAVA_SPEC_VERSION >= 13]*/8542/**8543* Determine if current String object is LATIN1.8544*8545* @return true if it is LATIN1, otherwise false.8546*/8547boolean isLatin1() {8548return LATIN1 == coder();8549}85508551/**8552* Format the string using this string as the format with supplied args.8553*8554* @param args8555* the format arguments to use8556*8557* @return the formatted result8558*8559* @see #format(String, Object...)8560*8561* @since 158562*/8563public String formatted(Object... args) {8564return String.format(this, args);8565}85668567/**8568* Removes the minimum indentation from the beginning of each line and8569* removes the trailing spaces in every line from the string8570*8571* @return this string with incidental whitespaces removed from every line8572*8573* @since 158574*/8575public String stripIndent() {8576if (isEmpty()) {8577return this;8578}85798580char lastChar = charAt(length() - 1);8581boolean trailingNewLine = ('\n' == lastChar) || ('\r' == lastChar);85828583Iterator<String> iter = lines().iterator();8584int min = Integer.MAX_VALUE;85858586if (trailingNewLine) {8587min = 0;8588} else {8589while (iter.hasNext()) {8590String line = iter.next();85918592/* The minimum indentation is calculated based on the number of leading8593* whitespace characters from all non-blank lines and the last line even8594* if it is blank.8595*/8596if (!line.isBlank() || !iter.hasNext()) {8597int count = 0;8598int limit = Math.min(min, line.length());8599while ((count < limit) && Character.isWhitespace(line.charAt(count))) {8600count++;8601}86028603if (min > count) {8604min = count;8605}8606}8607}8608/* reset iterator to beginning of the string */8609iter = lines().iterator();8610}86118612StringBuilder builder = new StringBuilder();86138614while (iter.hasNext()) {8615String line = iter.next();86168617if (line.isBlank()) {8618builder.append("");8619} else {8620line = line.substring(min);8621builder.append(line.stripTrailing());8622}8623builder.append("\n");8624}862586268627if (!trailingNewLine) {8628builder.setLength(builder.length() - 1);8629}86308631return builder.toString();8632}86338634/**8635* Translate the escape sequences in this string as if in a string literal8636*8637* @return result string after translation8638*8639* @throws IllegalArgumentException8640* If invalid escape sequence is detected8641*8642* @since 158643*/8644public String translateEscapes() {8645StringBuilder builder = new StringBuilder();8646char[] charArray = toCharArray();8647int index = 0;8648int strLength = length();8649while (index < strLength) {8650if ('\\' == charArray[index]) {8651index++;8652if (index >= strLength) {8653/*[MSG "K0D00", "Invalid escape sequence detected: {0}"]*/8654throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0D00", "\\")); //$NON-NLS-1$ //$NON-NLS-2$8655}8656int octal = 0;8657switch (charArray[index]) {8658case 'b':8659builder.append('\b');8660break;8661case 't':8662builder.append('\t');8663break;8664case 'n':8665builder.append('\n');8666break;8667case 'f':8668builder.append('\f');8669break;8670case 'r':8671builder.append('\r');8672break;8673case 's':8674builder.append(' '); /* '\s' is a new escape sequence for space (U+0020) added in JEP 368: Text Blocks (Second Preview) */8675break;8676case '\"':8677case '\'':8678case '\\':8679builder.append(charArray[index]);8680break;8681case '0':8682case '1':8683case '2':8684case '3':8685octal = charArray[index] - '0';8686/* If the octal escape sequence only has a single digit, then translate the escape and search for next escape sequence8687* If there is more than one digit, fall though to case 4-7 and save the current digit as the first digit of the sequence8688*/8689if ((index < strLength - 1) && ('0' <= charArray[index + 1]) && ('7' >= charArray[index + 1])) {8690index++;8691} else {8692builder.append((char)octal);8693break;8694}8695//$FALL-THROUGH$8696case '4':8697case '5':8698case '6':8699case '7':8700/* Shift octal value (either 0 or value fall through from the previous case) left one digit then add the current digit */8701octal = (octal * 010) + (charArray[index] - '0');87028703/* Check for last possible digit in octal escape sequence */8704if ((index < strLength - 1) && ('0' <= charArray[index + 1]) && ('7' >= charArray[index + 1])) {8705index++;8706octal = (octal * 010) + (charArray[index] - '0');8707}8708builder.append((char)octal);8709break;8710/**8711* JEP 368: Text Blocks (Second Preview)8712* '\r', "\r\n" and '\n' are ignored as per new continuation \<line-terminator> escape sequence8713* i.e. ignore line terminator and continue line8714* */8715case '\r':8716/* Check if the next character is the newline character, i.e. case "\r\n" */8717if (((index + 1) < strLength) && ('\n' == charArray[index + 1])) {8718index++;8719}8720break;8721case '\n':8722break;8723default:8724/*[MSG "K0D00", "Invalid escape sequence detected: {0}"]*/8725throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0D00", "\\" + charArray[index])); //$NON-NLS-1$ //$NON-NLS-2$8726}8727} else {8728builder.append(charArray[index]);8729}8730index++;8731}8732return builder.toString();8733}8734/*[ENDIF] JAVA_SPEC_VERSION >= 13 */8735}873687378738