Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/jcl/src/java.base/share/classes/java/lang/String.java
12513 views
1
/*[INCLUDE-IF JAVA_SPEC_VERSION < 17]*/
2
/*******************************************************************************
3
* Copyright (c) 1998, 2021 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* 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-exception
22
*******************************************************************************/
23
package java.lang;
24
25
import java.io.Serializable;
26
27
import java.util.Locale;
28
import java.util.Comparator;
29
import java.io.UnsupportedEncodingException;
30
import java.util.regex.Pattern;
31
import java.util.regex.PatternSyntaxException;
32
import java.util.Formatter;
33
import java.util.StringJoiner;
34
import java.util.Iterator;
35
import java.nio.charset.Charset;
36
/*[IF JAVA_SPEC_VERSION >= 12]*/
37
import java.util.function.Function;
38
import java.util.Optional;
39
/*[ENDIF] JAVA_SPEC_VERSION >= 12 */
40
/*[IF Sidecar19-SE]*/
41
import java.util.Spliterator;
42
import java.util.stream.StreamSupport;
43
44
import jdk.internal.misc.Unsafe;
45
import java.util.stream.IntStream;
46
/*[ELSE] Sidecar19-SE*/
47
import sun.misc.Unsafe;
48
/*[ENDIF] Sidecar19-SE*/
49
50
/*[IF JAVA_SPEC_VERSION >= 11]*/
51
import java.util.stream.Stream;
52
/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
53
54
/*[IF JAVA_SPEC_VERSION >= 12]*/
55
import java.lang.constant.Constable;
56
import java.lang.constant.ConstantDesc;
57
import java.lang.invoke.MethodHandles;
58
import java.lang.invoke.MethodHandles.Lookup;
59
/*[ENDIF] JAVA_SPEC_VERSION >= 12 */
60
61
/**
62
* Strings are objects which represent immutable arrays of characters.
63
*
64
* @author OTI
65
* @version initial
66
*
67
* @see StringBuffer
68
*/
69
public final class String implements Serializable, Comparable<String>, CharSequence
70
/*[IF JAVA_SPEC_VERSION >= 12]*/
71
, Constable, ConstantDesc
72
/*[ENDIF] JAVA_SPEC_VERSION >= 12 */
73
{
74
75
/*
76
* Last character of String substitute in String.replaceAll(regex, substitute) can't be \ or $.
77
* The backslash (\) is used to escape literal characters, and the dollar sign ($) is treated as
78
* references to captured subsequences.
79
*/
80
private void checkLastChar(char lastChar) {
81
if (lastChar == '\\') {
82
/*[MSG "K0801", "Last character in replacement string can't be \, character to be escaped is required."]*/
83
throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0801")); //$NON-NLS-1$
84
} else if (lastChar == '$') {
85
/*[MSG "K0802", "Last character in replacement string can't be $, group index is required."]*/
86
throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0802")); //$NON-NLS-1$
87
}
88
}
89
90
/*[IF Sidecar19-SE]*/
91
// DO NOT CHANGE OR MOVE THIS LINE
92
// IT MUST BE THE FIRST THING IN THE INITIALIZATION
93
private static final long serialVersionUID = -6849794470754667710L;
94
95
/**
96
* Determines whether String compression is enabled.
97
*/
98
static final boolean COMPACT_STRINGS = com.ibm.oti.vm.VM.J9_STRING_COMPRESSION_ENABLED;
99
100
static final byte LATIN1 = 0;
101
static final byte UTF16 = 1;
102
103
// returns UTF16 when COMPACT_STRINGS is false
104
byte coder() {
105
if (COMPACT_STRINGS) {
106
return coder;
107
} else {
108
return UTF16;
109
}
110
}
111
112
/*[IF JAVA_SPEC_VERSION >= 16]*/
113
/**
114
* Copy bytes from value starting at srcIndex into the bytes array starting at
115
* destIndex. No range checking is needed. Caller ensures bytes is in UTF16.
116
*
117
* @param bytes copy destination
118
* @param srcIndex index into value
119
* @param destIndex index into bytes
120
* @param coder LATIN1 or UTF16
121
* @param length the number of elements to copy
122
*/
123
void getBytes(byte[] bytes, int srcIndex, int destIndex, byte coder, int length) {
124
// Check if the String is compressed
125
if (COMPACT_STRINGS && (null == compressionFlag || this.coder == LATIN1)) {
126
if (String.LATIN1 == coder) {
127
compressedArrayCopy(value, srcIndex, bytes, destIndex, length);
128
} else {
129
StringLatin1.inflate(value, srcIndex, bytes, destIndex, length);
130
}
131
} else {
132
decompressedArrayCopy(value, srcIndex, bytes, destIndex, length);
133
}
134
}
135
/*[ENDIF] JAVA_SPEC_VERSION >= 16 */
136
137
// no range checking, caller ensures bytes is in UTF16
138
// coder is one of LATIN1 or UTF16
139
void getBytes(byte[] bytes, int offset, byte coder) {
140
int currentLength = lengthInternal();
141
142
// Check if the String is compressed
143
if (COMPACT_STRINGS && (null == compressionFlag || this.coder == LATIN1)) {
144
if (String.LATIN1 == coder) {
145
compressedArrayCopy(value, 0, bytes, offset, currentLength);
146
} else {
147
StringLatin1.inflate(value, 0, bytes, offset, currentLength);
148
}
149
} else {
150
decompressedArrayCopy(value, 0, bytes, offset, currentLength);
151
}
152
}
153
154
static void checkIndex(int index, int length) {
155
if ((0 <= index) && (index < length)) {
156
return;
157
}
158
throw new StringIndexOutOfBoundsException("index="+index + " length="+length); //$NON-NLS-1$ //$NON-NLS-2$
159
}
160
161
static void checkOffset(int offset, int length) {
162
if ((0 <= offset) && (offset <= length)) {
163
return;
164
}
165
throw new StringIndexOutOfBoundsException("offset="+offset + " length="+length); //$NON-NLS-1$ //$NON-NLS-2$
166
}
167
168
/**
169
* CaseInsensitiveComparator compares Strings ignoring the case of the characters.
170
*/
171
private static final class CaseInsensitiveComparator implements Comparator<String>, Serializable {
172
static final long serialVersionUID = 8575799808933029326L;
173
174
/**
175
* Compare the two objects to determine the relative ordering.
176
*
177
* @param o1
178
* an Object to compare
179
* @param o2
180
* an Object to compare
181
* @return {@code < 0} if o1 is less than o2, {@code 0} if they are equal, and {@code > 0} if o1 is greater
182
*
183
* @exception ClassCastException
184
* when objects are not the correct type
185
*/
186
public int compare(String o1, String o2) {
187
return o1.compareToIgnoreCase(o2);
188
}
189
};
190
191
/**
192
* A Comparator which compares Strings ignoring the case of the characters.
193
*/
194
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
195
196
// Used to represent the value of an empty String
197
private static final byte[] emptyValue = new byte[0];
198
199
// Used to extract the value of a single ASCII character String by the integral value of the respective character as
200
// an index into this table
201
private static final byte[][] compressedAsciiTable;
202
203
private static final byte[][] decompressedAsciiTable;
204
205
// Used to access compression related helper methods
206
private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();
207
208
static class StringCompressionFlag implements Serializable {
209
private static final long serialVersionUID = 1346155847239551492L;
210
}
211
212
// Singleton used by all String instances to indicate a non-compressed string has been
213
// allocated. JIT attempts to fold away the null check involving this static if the
214
// StringCompressionFlag class has not been initialized and patches the code to bring back
215
// the null check if a non-compressed String is constructed.
216
private static StringCompressionFlag compressionFlag;
217
218
// Represents the bit in count field to test for whether this String backing array is not compressed
219
// under String compression mode. This bit is not used when String compression is disabled.
220
private static final int uncompressedBit = 0x80000000;
221
222
private static String[] stringArray;
223
private static final int stringArraySize = 10;
224
225
private static class UnsafeHelpers {
226
public final static long valueFieldOffset = getValueFieldOffset();
227
228
static long getValueFieldOffset() {
229
try {
230
return Unsafe.getUnsafe().objectFieldOffset(String.class.getDeclaredField("value")); //$NON-NLS-1$
231
} catch (NoSuchFieldException e) {
232
throw new RuntimeException(e);
233
}
234
}
235
}
236
237
/**
238
* This is a System property to enable sharing of the underlying value array in {@link #String.substring(int)} and
239
* {@link #String.substring(int, int)} if the offset is zero.
240
*/
241
static boolean enableSharingInSubstringWhenOffsetIsZero;
242
243
private final byte[] value;
244
private final byte coder;
245
private int hash;
246
247
static {
248
stringArray = new String[stringArraySize];
249
250
compressedAsciiTable = new byte[256][];
251
252
for (int i = 0; i < compressedAsciiTable.length; ++i) {
253
byte[] asciiValue = new byte[1];
254
255
helpers.putByteInArrayByIndex(asciiValue, 0, (byte) i);
256
257
compressedAsciiTable[i] = asciiValue;
258
}
259
260
decompressedAsciiTable = new byte[256][];
261
262
for (int i = 0; i < decompressedAsciiTable.length; ++i) {
263
byte[] asciiValue = new byte[2];
264
265
helpers.putCharInArrayByIndex(asciiValue, 0, (char) i);
266
267
decompressedAsciiTable[i] = asciiValue;
268
}
269
}
270
271
static void initCompressionFlag() {
272
if (compressionFlag == null) {
273
compressionFlag = new StringCompressionFlag();
274
}
275
}
276
277
/**
278
* Determines whether the input character array can be encoded as a compact
279
* Latin1 string.
280
*
281
* <p>This API implicitly assumes the following:
282
* <blockquote><pre>
283
* - {@code length >= 0}
284
* - {@code start >= 0}
285
* - {@code start + length <= data.length}
286
* <blockquote><pre>
287
*
288
* @param c the array of characters to check
289
* @param start the starting offset in the character array
290
* @param length the number of characters to check starting at {@code start}
291
* @return {@code true} if the input character array can be encoded
292
* using the Latin1 encoding; {@code false} otherwise
293
*/
294
static boolean canEncodeAsLatin1(char[] c, int start, int length) {
295
for (int i = start; i < start + length; ++i) {
296
if (c[i] > 255) {
297
return false;
298
}
299
}
300
301
return true;
302
}
303
304
static void compress(byte[] array1, int start1, byte[] array2, int start2, int length) {
305
for (int i = 0; i < length; ++i) {
306
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
307
}
308
}
309
310
static void compress(char[] array1, int start1, byte[] array2, int start2, int length) {
311
for (int i = 0; i < length; ++i) {
312
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
313
}
314
}
315
316
static void compress(byte[] array1, int start1, char[] array2, int start2, int length) {
317
for (int i = 0; i < length; ++i) {
318
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
319
}
320
}
321
322
static void compress(char[] array1, int start1, char[] array2, int start2, int length) {
323
for (int i = 0; i < length; ++i) {
324
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
325
}
326
}
327
328
static void decompress(byte[] array1, int start1, byte[] array2, int start2, int length) {
329
for (int i = 0; i < length; ++i) {
330
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
331
}
332
}
333
334
static void decompress(char[] array1, int start1, byte[] array2, int start2, int length) {
335
for (int i = 0; i < length; ++i) {
336
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
337
}
338
}
339
340
static void decompress(byte[] array1, int start1, char[] array2, int start2, int length) {
341
for (int i = 0; i < length; ++i) {
342
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
343
}
344
}
345
346
static void decompress(char[] array1, int start1, char[] array2, int start2, int length) {
347
for (int i = 0; i < length; ++i) {
348
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
349
}
350
}
351
352
static void compressedArrayCopy(byte[] array1, int start1, byte[] array2, int start2, int length) {
353
if (array1 == array2 && start1 < start2) {
354
for (int i = length - 1; i >= 0; --i) {
355
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
356
}
357
} else {
358
for (int i = 0; i < length; ++i) {
359
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
360
}
361
}
362
}
363
364
static void compressedArrayCopy(byte[] array1, int start1, char[] array2, int start2, int length) {
365
for (int i = 0; i < length; ++i) {
366
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
367
}
368
}
369
370
static void compressedArrayCopy(char[] array1, int start1, byte[] array2, int start2, int length) {
371
for (int i = 0; i < length; ++i) {
372
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
373
}
374
}
375
376
static void compressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {
377
if (array1 == array2 && start1 < start2) {
378
for (int i = length - 1; i >= 0; --i) {
379
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
380
}
381
} else {
382
for (int i = 0; i < length; ++i) {
383
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
384
}
385
}
386
}
387
388
static void decompressedArrayCopy(byte[] array1, int start1, byte[] array2, int start2, int length) {
389
if (array1 == array2 && start1 < start2) {
390
for (int i = length - 1; i >= 0; --i) {
391
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));
392
}
393
} else {
394
for (int i = 0; i < length; ++i) {
395
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));
396
}
397
}
398
}
399
400
static void decompressedArrayCopy(byte[] array1, int start1, char[] array2, int start2, int length) {
401
for (int i = 0; i < length; ++i) {
402
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));
403
}
404
}
405
406
static void decompressedArrayCopy(char[] array1, int start1, byte[] array2, int start2, int length) {
407
for (int i = 0; i < length; ++i) {
408
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.getCharFromArrayByIndex(array1, start1 + i));
409
}
410
}
411
412
static void decompressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {
413
System.arraycopy(array1, start1, array2, start2, length);
414
}
415
416
boolean isCompressed() {
417
// Check if the String is compressed
418
if (COMPACT_STRINGS) {
419
if (null == compressionFlag) {
420
return true;
421
} else {
422
return coder == String.LATIN1;
423
}
424
} else {
425
return false;
426
}
427
}
428
429
String(byte[] byteArray, byte coder) {
430
if (COMPACT_STRINGS) {
431
if (String.LATIN1 == coder) {
432
value = byteArray;
433
} else {
434
value = byteArray;
435
436
initCompressionFlag();
437
}
438
} else {
439
value = byteArray;
440
}
441
this.coder = coder;
442
}
443
444
static void checkBoundsOffCount(int offset, int count, int length) {
445
if (offset >= 0 && count >= 0 && offset <= length - count) {
446
return;
447
}
448
449
throw newStringIndexOutOfBoundsException(offset, count, length);
450
}
451
452
static private StringIndexOutOfBoundsException newStringIndexOutOfBoundsException(int offset, int count, int length) {
453
return new StringIndexOutOfBoundsException("offset = " + offset + " count = " + count + " length = " + length); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
454
}
455
456
/**
457
* Answers an empty string.
458
*/
459
public String() {
460
value = emptyValue;
461
462
if (COMPACT_STRINGS) {
463
coder = LATIN1;
464
} else {
465
coder = UTF16;
466
}
467
}
468
469
/**
470
* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not
471
* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.
472
*
473
* @param data
474
* the byte array to convert to a String
475
*
476
* @throws NullPointerException
477
* when data is null
478
*
479
* @see #getBytes()
480
* @see #getBytes(int, int, byte[], int)
481
* @see #getBytes(String)
482
* @see #valueOf(boolean)
483
* @see #valueOf(char)
484
* @see #valueOf(char[])
485
* @see #valueOf(char[], int, int)
486
* @see #valueOf(double)
487
* @see #valueOf(float)
488
* @see #valueOf(int)
489
* @see #valueOf(long)
490
* @see #valueOf(Object)
491
*
492
*/
493
public String(byte[] data) {
494
this(data, 0, data.length);
495
}
496
497
/**
498
* Converts the byte array to a String, setting the high byte of every character to the specified value.
499
*
500
* @param data
501
* the byte array to convert to a String
502
* @param high
503
* the high byte to use
504
*
505
* @throws NullPointerException
506
* when data is null
507
*
508
* @deprecated Use String(byte[]) or String(byte[], String) instead
509
*/
510
@Deprecated(forRemoval=false, since="1.1")
511
public String(byte[] data, int high) {
512
this(data, high, 0, data.length);
513
}
514
515
/**
516
* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not
517
* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.
518
*
519
* @param data
520
* the byte array to convert to a String
521
* @param start
522
* the starting offset in the byte array
523
* @param length
524
* the number of bytes to convert
525
*
526
* @throws IndexOutOfBoundsException
527
* when {@code length < 0, start < 0} or {@code start + length > data.length}
528
* @throws NullPointerException
529
* when data is null
530
*
531
* @see #getBytes()
532
* @see #getBytes(int, int, byte[], int)
533
* @see #getBytes(String)
534
* @see #valueOf(boolean)
535
* @see #valueOf(char)
536
* @see #valueOf(char[])
537
* @see #valueOf(char[], int, int)
538
* @see #valueOf(double)
539
* @see #valueOf(float)
540
* @see #valueOf(int)
541
* @see #valueOf(long)
542
* @see #valueOf(Object)
543
*
544
*/
545
public String(byte[] data, int start, int length) {
546
data.getClass(); // Implicit null check
547
548
if (start >= 0 && 0 <= length && length <= data.length - start) {
549
StringCoding.Result scResult = StringCoding.decode(data, start, length);
550
551
value = scResult.value;
552
coder = scResult.coder;
553
554
if (COMPACT_STRINGS && scResult.coder == UTF16) {
555
initCompressionFlag();
556
}
557
} else {
558
throw new StringIndexOutOfBoundsException();
559
}
560
}
561
562
/**
563
* Converts the byte array to a String, setting the high byte of every character to the specified value.
564
*
565
* @param data
566
* the byte array to convert to a String
567
* @param high
568
* the high byte to use
569
* @param start
570
* the starting offset in the byte array
571
* @param length
572
* the number of bytes to convert
573
*
574
* @throws IndexOutOfBoundsException
575
* when {@code length < 0, start < 0} or {@code start + length > data.length}
576
* @throws NullPointerException
577
* when data is null
578
*
579
* @deprecated Use String(byte[], int, int) instead
580
*/
581
@Deprecated(forRemoval=false, since="1.1")
582
public String(byte[] data, int high, int start, int length) {
583
data.getClass(); // Implicit null check
584
585
if (start >= 0 && 0 <= length && length <= data.length - start) {
586
if (COMPACT_STRINGS && high == 0) {
587
value = new byte[length];
588
coder = LATIN1;
589
590
compressedArrayCopy(data, start, value, 0, length);
591
} else {
592
value = StringUTF16.newBytesFor(length);
593
coder = UTF16;
594
595
high <<= 8;
596
597
for (int i = 0; i < length; ++i) {
598
helpers.putCharInArrayByIndex(value, i, (char) (high + (data[start++] & 0xff)));
599
}
600
601
if (COMPACT_STRINGS) {
602
initCompressionFlag();
603
}
604
}
605
} else {
606
throw new StringIndexOutOfBoundsException();
607
}
608
}
609
610
/**
611
* Converts the byte array to a String using the specified encoding.
612
*
613
* @param data
614
* the byte array to convert to a String
615
* @param start
616
* the starting offset in the byte array
617
* @param length
618
* the number of bytes to convert
619
* @param encoding
620
* the encoding
621
*
622
* @throws IndexOutOfBoundsException
623
* when {@code length < 0, start < 0} or {@code start + length > data.length}
624
* @throws UnsupportedEncodingException
625
* when encoding is not supported
626
* @throws NullPointerException
627
* when data is null
628
*
629
* @see #getBytes()
630
* @see #getBytes(int, int, byte[], int)
631
* @see #getBytes(String)
632
* @see #valueOf(boolean)
633
* @see #valueOf(char)
634
* @see #valueOf(char[])
635
* @see #valueOf(char[], int, int)
636
* @see #valueOf(double)
637
* @see #valueOf(float)
638
* @see #valueOf(int)
639
* @see #valueOf(long)
640
* @see #valueOf(Object)
641
* @see UnsupportedEncodingException
642
*/
643
public String(byte[] data, int start, int length, final String encoding) throws UnsupportedEncodingException {
644
data.getClass(); // Implicit null check
645
encoding.getClass(); // Implicit null check
646
647
if (start >= 0 && 0 <= length && length <= data.length - start) {
648
StringCoding.Result scResult = StringCoding.decode(encoding, data, start, length);
649
650
value = scResult.value;
651
coder = scResult.coder;
652
653
if (COMPACT_STRINGS && scResult.coder == UTF16) {
654
initCompressionFlag();
655
}
656
} else {
657
throw new StringIndexOutOfBoundsException();
658
}
659
}
660
661
/**
662
* Converts the byte array to a String using the specified encoding.
663
*
664
* @param data
665
* the byte array to convert to a String
666
* @param encoding
667
* the encoding
668
*
669
* @throws UnsupportedEncodingException
670
* when encoding is not supported
671
* @throws NullPointerException
672
* when data is null
673
*
674
* @see #getBytes()
675
* @see #getBytes(int, int, byte[], int)
676
* @see #getBytes(String)
677
* @see #valueOf(boolean)
678
* @see #valueOf(char)
679
* @see #valueOf(char[])
680
* @see #valueOf(char[], int, int)
681
* @see #valueOf(double)
682
* @see #valueOf(float)
683
* @see #valueOf(int)
684
* @see #valueOf(long)
685
* @see #valueOf(Object)
686
* @see UnsupportedEncodingException
687
*/
688
public String(byte[] data, String encoding) throws UnsupportedEncodingException {
689
this(data, 0, data.length, encoding);
690
}
691
692
private String(String s, char c) {
693
if (s == null) {
694
s = "null"; //$NON-NLS-1$
695
}
696
697
int slen = s.lengthInternal();
698
699
int concatlen = slen + 1;
700
if (concatlen < 0) {
701
/*[MSG "K0D01", "Array capacity exceeded"]*/
702
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
703
}
704
705
// Check if the String is compressed
706
if (COMPACT_STRINGS && (null == compressionFlag || s.coder == LATIN1) && c <= 255) {
707
value = new byte[concatlen];
708
coder = LATIN1;
709
710
compressedArrayCopy(s.value, 0, value, 0, slen);
711
712
helpers.putByteInArrayByIndex(value, slen, (byte) c);
713
} else {
714
value = StringUTF16.newBytesFor(concatlen);
715
coder = UTF16;
716
717
// Check if the String is compressed
718
if (COMPACT_STRINGS && s.coder == LATIN1) {
719
StringLatin1.inflate(s.value, 0, value, 0, slen);
720
} else {
721
decompressedArrayCopy(s.value, 0, value, 0, slen);
722
}
723
724
helpers.putCharInArrayByIndex(value, slen, c);
725
726
if (COMPACT_STRINGS) {
727
initCompressionFlag();
728
}
729
}
730
}
731
732
/**
733
* Initializes this String to contain the characters in the specified character array. Modifying the character array after creating the String has
734
* no effect on the String.
735
*
736
* @param data
737
* the array of characters
738
*
739
* @throws NullPointerException
740
* when data is null
741
*/
742
public String(char[] data) {
743
this(data, 0, data.length);
744
}
745
746
/**
747
* Initializes this String to use the specified character array. The character array should not be modified after the String is created.
748
*
749
* @param data
750
* a non-null array of characters
751
*/
752
String(char[] data, boolean ignore) {
753
if (COMPACT_STRINGS && canEncodeAsLatin1(data, 0, data.length)) {
754
value = new byte[data.length];
755
coder = LATIN1;
756
757
compress(data, 0, value, 0, data.length);
758
} else {
759
value = StringUTF16.newBytesFor(data.length);
760
coder = UTF16;
761
762
decompressedArrayCopy(data, 0, value, 0, data.length);
763
764
if (COMPACT_STRINGS) {
765
initCompressionFlag();
766
}
767
}
768
}
769
770
/**
771
* Initializes this String to contain the specified characters in the character array. Modifying the character array after creating the String has
772
* no effect on the String.
773
*
774
* @param data
775
* the array of characters
776
* @param start
777
* the starting offset in the character array
778
* @param length
779
* the number of characters to use
780
*
781
* @throws IndexOutOfBoundsException
782
* when {@code length < 0, start < 0} or {@code start + length > data.length}
783
* @throws NullPointerException
784
* when data is null
785
*/
786
public String(char[] data, int start, int length) {
787
if (start >= 0 && 0 <= length && length <= data.length - start) {
788
if (COMPACT_STRINGS && canEncodeAsLatin1(data, start, length)) {
789
value = new byte[length];
790
coder = LATIN1;
791
792
compress(data, start, value, 0, length);
793
} else {
794
value = StringUTF16.newBytesFor(length);
795
coder = UTF16;
796
797
decompressedArrayCopy(data, start, value, 0, length);
798
799
if (COMPACT_STRINGS) {
800
initCompressionFlag();
801
}
802
}
803
} else {
804
throw new StringIndexOutOfBoundsException();
805
}
806
}
807
808
String(byte[] data, int start, int length, boolean compressed) {
809
if (length == 0) {
810
value = emptyValue;
811
812
if (COMPACT_STRINGS) {
813
coder = LATIN1;
814
} else {
815
coder = UTF16;
816
}
817
} else if (length == 1) {
818
if (COMPACT_STRINGS && compressed) {
819
char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));
820
821
value = compressedAsciiTable[theChar];
822
coder = LATIN1;
823
hash = theChar;
824
} else {
825
char theChar = helpers.getCharFromArrayByIndex(data, start);
826
827
if (theChar <= 255) {
828
value = decompressedAsciiTable[theChar];
829
} else {
830
value = new byte[2];
831
832
helpers.putCharInArrayByIndex(value, 0, theChar);
833
}
834
835
coder = UTF16;
836
hash = theChar;
837
838
if (COMPACT_STRINGS) {
839
initCompressionFlag();
840
}
841
}
842
} else {
843
if (COMPACT_STRINGS && compressed) {
844
if (start == 0 && data.length == length) {
845
value = data;
846
} else {
847
value = new byte[length];
848
849
compressedArrayCopy(data, start, value, 0, length);
850
}
851
852
coder = LATIN1;
853
} else {
854
if (start == 0 && data.length == length * 2) {
855
value = data;
856
} else {
857
value = StringUTF16.newBytesFor(length);
858
859
decompressedArrayCopy(data, start, value, 0, length);
860
}
861
862
coder = UTF16;
863
864
if (COMPACT_STRINGS) {
865
initCompressionFlag();
866
}
867
}
868
}
869
}
870
871
String(byte[] data, int start, int length, boolean compressed, boolean sharingIsAllowed) {
872
if (length == 0) {
873
value = emptyValue;
874
875
if (COMPACT_STRINGS) {
876
coder = LATIN1;
877
} else {
878
coder = UTF16;
879
}
880
} else if (length == 1) {
881
if (COMPACT_STRINGS && compressed) {
882
char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));
883
884
value = compressedAsciiTable[theChar];
885
coder = LATIN1;
886
hash = theChar;
887
} else {
888
char theChar = helpers.getCharFromArrayByIndex(data, start);
889
890
if (theChar <= 255) {
891
value = decompressedAsciiTable[theChar];
892
} else {
893
value = new byte[2];
894
895
helpers.putCharInArrayByIndex(value, 0, theChar);
896
}
897
898
coder = UTF16;
899
hash = theChar;
900
901
if (COMPACT_STRINGS) {
902
initCompressionFlag();
903
}
904
}
905
} else {
906
if (COMPACT_STRINGS && compressed) {
907
if (sharingIsAllowed && start == 0 && data.length == length) {
908
value = data;
909
} else {
910
value = new byte[length];
911
912
compressedArrayCopy(data, start, value, 0, length);
913
}
914
915
coder = LATIN1;
916
} else {
917
if (sharingIsAllowed && start == 0 && data.length == length * 2) {
918
value = data;
919
} else {
920
value = StringUTF16.newBytesFor(length);
921
922
decompressedArrayCopy(data, start, value, 0, length);
923
}
924
925
coder = UTF16;
926
927
if (COMPACT_STRINGS) {
928
initCompressionFlag();
929
}
930
}
931
}
932
}
933
934
/**
935
* Creates a string that is a copy of another string
936
*
937
* @param string
938
* the String to copy
939
*/
940
public String(String string) {
941
value = string.value;
942
coder = string.coder;
943
hash = string.hash;
944
}
945
946
/**
947
* Creates a string from the contents of a StringBuffer.
948
*
949
* @param buffer
950
* the StringBuffer
951
*/
952
public String(StringBuffer buffer) {
953
this(buffer.toString());
954
}
955
956
/*
957
* Creates a string that is s1 + s2.
958
*/
959
private String(String s1, String s2) {
960
if (s1 == null) {
961
s1 = "null"; //$NON-NLS-1$
962
}
963
964
if (s2 == null) {
965
s2 = "null"; //$NON-NLS-1$
966
}
967
968
int s1len = s1.lengthInternal();
969
int s2len = s2.lengthInternal();
970
971
int concatlen = s1len + s2len;
972
if (concatlen < 0) {
973
/*[MSG "K0D01", "Array capacity exceeded"]*/
974
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
975
}
976
977
if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {
978
value = new byte[concatlen];
979
coder = LATIN1;
980
981
compressedArrayCopy(s1.value, 0, value, 0, s1len);
982
compressedArrayCopy(s2.value, 0, value, s1len, s2len);
983
} else {
984
value = StringUTF16.newBytesFor(concatlen);
985
coder = UTF16;
986
987
// Check if the String is compressed
988
if (COMPACT_STRINGS && s1.coder == LATIN1) {
989
StringLatin1.inflate(s1.value, 0, value, 0, s1len);
990
} else {
991
decompressedArrayCopy(s1.value, 0, value, 0, s1len);
992
}
993
994
// Check if the String is compressed
995
if (COMPACT_STRINGS && s2.coder == LATIN1) {
996
StringLatin1.inflate(s2.value, 0, value, s1len, s2len);
997
} else {
998
decompressedArrayCopy(s2.value, 0, value, s1len, s2len);
999
}
1000
1001
if (COMPACT_STRINGS) {
1002
initCompressionFlag();
1003
}
1004
}
1005
}
1006
1007
/*
1008
* Creates a string that is s1 + s2 + s3.
1009
*/
1010
private String(String s1, String s2, String s3) {
1011
if (s1 == null) {
1012
s1 = "null"; //$NON-NLS-1$
1013
}
1014
1015
if (s2 == null) {
1016
s2 = "null"; //$NON-NLS-1$
1017
}
1018
1019
if (s3 == null) {
1020
s3 = "null"; //$NON-NLS-1$
1021
}
1022
1023
int s1len = s1.lengthInternal();
1024
int s2len = s2.lengthInternal();
1025
int s3len = s3.lengthInternal();
1026
1027
long totalLen = (long) s1len + (long) s2len + (long) s3len;
1028
if (totalLen > Integer.MAX_VALUE) {
1029
/*[MSG "K0D01", "Array capacity exceeded"]*/
1030
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
1031
}
1032
int concatlen = (int) totalLen;
1033
1034
if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder | s3.coder) == LATIN1)) {
1035
value = new byte[concatlen];
1036
coder = LATIN1;
1037
1038
compressedArrayCopy(s1.value, 0, value, 0, s1len);
1039
compressedArrayCopy(s2.value, 0, value, s1len, s2len);
1040
compressedArrayCopy(s3.value, 0, value, s1len + s2len, s3len);
1041
} else {
1042
value = StringUTF16.newBytesFor(concatlen);
1043
coder = UTF16;
1044
1045
// Check if the String is compressed
1046
if (COMPACT_STRINGS && s1.coder == LATIN1) {
1047
StringLatin1.inflate(s1.value, 0, value, 0, s1len);
1048
} else {
1049
decompressedArrayCopy(s1.value, 0, value, 0, s1len);
1050
}
1051
1052
// Check if the String is compressed
1053
if (COMPACT_STRINGS && s2.coder == LATIN1) {
1054
StringLatin1.inflate(s2.value, 0, value, s1len, s2len);
1055
} else {
1056
decompressedArrayCopy(s2.value, 0, value, s1len, s2len);
1057
}
1058
1059
// Check if the String is compressed
1060
if (COMPACT_STRINGS && s3.coder == LATIN1) {
1061
StringLatin1.inflate(s3.value, 0, value, s1len + s2len, s3len);
1062
} else {
1063
decompressedArrayCopy(s3.value, 0, value, (s1len + s2len), s3len);
1064
}
1065
1066
if (COMPACT_STRINGS) {
1067
initCompressionFlag();
1068
}
1069
}
1070
}
1071
1072
/*
1073
* Creates a string that is s1 + v1.
1074
*/
1075
private String(String s1, int v1) {
1076
if (s1 == null) {
1077
s1 = "null"; //$NON-NLS-1$
1078
}
1079
1080
// Char length of all the parameters respectively
1081
int s1len = s1.lengthInternal();
1082
int v1len = 1;
1083
1084
int quot;
1085
int i = v1;
1086
while ((i /= 10) != 0)
1087
v1len++;
1088
if (v1 >= 0) {
1089
quot = -v1;
1090
} else {
1091
// Leave room for '-'
1092
v1len++;
1093
quot = v1;
1094
}
1095
1096
// Char length of the final String
1097
int len = s1len + v1len;
1098
if (len < 0) {
1099
/*[MSG "K0D01", "Array capacity exceeded"]*/
1100
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
1101
}
1102
1103
if (COMPACT_STRINGS && (null == compressionFlag || s1.coder == LATIN1)) {
1104
value = new byte[len];
1105
coder = LATIN1;
1106
1107
// Copy in v1
1108
int index = len - 1;
1109
1110
do {
1111
int res = quot / 10;
1112
int rem = quot - (res * 10);
1113
1114
quot = res;
1115
1116
// Write the digit into the correct position
1117
helpers.putByteInArrayByIndex(value, index--, (byte) ('0' - rem));
1118
} while (quot != 0);
1119
1120
if (v1 < 0) {
1121
helpers.putByteInArrayByIndex(value, index, (byte) '-');
1122
}
1123
1124
// Copy in s1 contents
1125
compressedArrayCopy(s1.value, 0, value, 0, s1len);
1126
} else {
1127
value = StringUTF16.newBytesFor(len);
1128
coder = UTF16;
1129
1130
// Copy in v1
1131
int index = len - 1;
1132
1133
do {
1134
int res = quot / 10;
1135
int rem = quot - (res * 10);
1136
1137
quot = res;
1138
1139
// Write the digit into the correct position
1140
helpers.putCharInArrayByIndex(value, index--, (char) ('0' - rem));
1141
} while (quot != 0);
1142
1143
if (v1 < 0) {
1144
helpers.putCharInArrayByIndex(value, index, (char) '-');
1145
}
1146
1147
// Copy in s1 contents
1148
decompressedArrayCopy(s1.value, 0, value, 0, s1len);
1149
1150
if (COMPACT_STRINGS) {
1151
initCompressionFlag();
1152
}
1153
}
1154
}
1155
1156
/*
1157
* Creates a string that is v1 + s1 + v2 + s2 + s3.
1158
*/
1159
private String(int v1, String s1, int v2, String s2, String s3) {
1160
if (s1 == null) {
1161
s1 = "null"; //$NON-NLS-1$
1162
}
1163
1164
if (s2 == null) {
1165
s2 = "null"; //$NON-NLS-1$
1166
}
1167
1168
if (s3 == null) {
1169
s3 = "null"; //$NON-NLS-1$
1170
}
1171
1172
// Char length of all the parameters respectively
1173
int s1len = s1.lengthInternal();
1174
int s2len = s2.lengthInternal();
1175
int s3len = s3.lengthInternal();
1176
1177
int v1len = 1;
1178
int v2len = 1;
1179
1180
int quot1;
1181
int i1 = v1;
1182
while ((i1 /= 10) != 0)
1183
v1len++;
1184
if (v1 >= 0) {
1185
quot1 = -v1;
1186
} else {
1187
// Leave room for '-'
1188
v1len++;
1189
quot1 = v1;
1190
}
1191
1192
int quot2;
1193
int i2 = v2;
1194
while ((i2 /= 10) != 0)
1195
v2len++;
1196
if (v2 >= 0) {
1197
quot2 = -v2;
1198
} else {
1199
// Leave room for '-'
1200
v2len++;
1201
quot2 = v2;
1202
}
1203
1204
// Char length of the final String
1205
long totalLen = (long) s1len + (long) v1len + (long) v2len + (long) s2len + (long) s3len;
1206
if (totalLen > Integer.MAX_VALUE) {
1207
/*[MSG "K0D01", "Array capacity exceeded"]*/
1208
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
1209
}
1210
int len = (int) totalLen;
1211
1212
if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder | s3.coder) == LATIN1)) {
1213
value = new byte[len];
1214
coder = LATIN1;
1215
1216
int start = len;
1217
1218
// Copy in s3 contents
1219
start = start - s3len;
1220
compressedArrayCopy(s3.value, 0, value, start, s3len);
1221
1222
// Copy in s2 contents
1223
start = start - s2len;
1224
compressedArrayCopy(s2.value, 0, value, start, s2len);
1225
1226
// Copy in v2
1227
int index2 = start - 1;
1228
1229
do {
1230
int res = quot2 / 10;
1231
int rem = quot2 - (res * 10);
1232
1233
quot2 = res;
1234
1235
// Write the digit into the correct position
1236
helpers.putByteInArrayByIndex(value, index2--, (byte) ('0' - rem));
1237
} while (quot2 != 0);
1238
1239
if (v2 < 0) {
1240
helpers.putByteInArrayByIndex(value, index2--, (byte) '-');
1241
}
1242
1243
// Copy in s1 contents
1244
start = index2 + 1 - s1len;
1245
compressedArrayCopy(s1.value, 0, value, start, s1len);
1246
1247
// Copy in v1
1248
int index1 = start - 1;
1249
1250
do {
1251
int res = quot1 / 10;
1252
int rem = quot1 - (res * 10);
1253
1254
quot1 = res;
1255
1256
// Write the digit into the correct position
1257
helpers.putByteInArrayByIndex(value, index1--, (byte) ('0' - rem));
1258
} while (quot1 != 0);
1259
1260
if (v1 < 0) {
1261
helpers.putByteInArrayByIndex(value, index1--, (byte) '-');
1262
}
1263
} else {
1264
value = StringUTF16.newBytesFor(len);
1265
coder = UTF16;
1266
1267
int start = len;
1268
1269
// Copy in s3 contents
1270
start = start - s3len;
1271
1272
// Check if the String is compressed
1273
if (COMPACT_STRINGS && s3.coder == LATIN1) {
1274
StringLatin1.inflate(s3.value, 0, value, start, s3len);
1275
} else {
1276
decompressedArrayCopy(s3.value, 0, value, start, s3len);
1277
}
1278
1279
// Copy in s2 contents
1280
start = start - s2len;
1281
1282
// Check if the String is compressed
1283
if (COMPACT_STRINGS && s2.coder == LATIN1) {
1284
StringLatin1.inflate(s2.value, 0, value, start, s2len);
1285
} else {
1286
decompressedArrayCopy(s2.value, 0, value, start, s2len);
1287
}
1288
1289
// Copy in v2
1290
int index2 = start - 1;
1291
1292
do {
1293
int res = quot2 / 10;
1294
int rem = quot2 - (res * 10);
1295
1296
quot2 = res;
1297
1298
// Write the digit into the correct position
1299
helpers.putCharInArrayByIndex(value, index2--, (char) ('0' - rem));
1300
} while (quot2 != 0);
1301
1302
if (v2 < 0) {
1303
helpers.putCharInArrayByIndex(value, index2--, (char) '-');
1304
}
1305
1306
// Copy in s1 contents
1307
start = index2 + 1 - s1len;
1308
1309
// Check if the String is compressed
1310
if (COMPACT_STRINGS && s1.coder == LATIN1) {
1311
StringLatin1.inflate(s1.value, 0, value, start, s1len);
1312
} else {
1313
decompressedArrayCopy(s1.value, 0, value, start, s1len);
1314
}
1315
1316
// Copy in v1
1317
int index1 = start - 1;
1318
1319
do {
1320
int res = quot1 / 10;
1321
int rem = quot1 - (res * 10);
1322
1323
quot1 = res;
1324
1325
// Write the digit into the correct position
1326
helpers.putCharInArrayByIndex(value, index1--, (char) ('0' - rem));
1327
} while (quot1 != 0);
1328
1329
if (v1 < 0) {
1330
helpers.putCharInArrayByIndex(value, index1--, (char) '-');
1331
}
1332
1333
if (COMPACT_STRINGS) {
1334
initCompressionFlag();
1335
}
1336
}
1337
}
1338
1339
/*
1340
* Loads from the stringArray if concatenated result is found else it creates a string that is s1 + s2 which is stored in stringArray and then
1341
* returned.
1342
*/
1343
static private String cachedConstantString(String s1, String s2, int index) {
1344
if (index < stringArraySize) {
1345
if (stringArray[index] == null) {
1346
stringArray[index] = new String(s1, s2);
1347
}
1348
} else {
1349
return new String(s1, s2);
1350
}
1351
return stringArray[index];
1352
}
1353
1354
/**
1355
* Answers the character at the specified offset in this String.
1356
*
1357
* @param index
1358
* the zero-based index in this string
1359
* @return the character at the index
1360
*
1361
* @throws IndexOutOfBoundsException
1362
* when {@code index < 0} or {@code index >= length()}
1363
*/
1364
public char charAt(int index) {
1365
if (0 <= index && index < lengthInternal()) {
1366
// Check if the String is compressed
1367
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
1368
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
1369
} else {
1370
return helpers.getCharFromArrayByIndex(value, index);
1371
}
1372
} else {
1373
throw new StringIndexOutOfBoundsException();
1374
}
1375
}
1376
1377
// Internal version of charAt used for extracting a char from a String in compression related code.
1378
char charAtInternal(int index) {
1379
// Check if the String is compressed
1380
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
1381
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
1382
} else {
1383
return helpers.getCharFromArrayByIndex(value, index);
1384
}
1385
}
1386
1387
// This method is needed so idiom recognition properly recognizes idiomatic loops where we are doing an operation on
1388
// the byte[] value of two Strings. In such cases we extract the String.value fields before entering the operation loop.
1389
// However if chatAt is used inside the loop then the JIT will anchor the load of the value byte[] inside of the loop thus
1390
// causing us to load the String.value on every iteration. This is very suboptimal and breaks some of the common idioms
1391
// that we recognize. The most prominent one is the regionMatches arraycmp idiom that is not recognized unless this method
1392
// is being used.
1393
char charAtInternal(int index, byte[] value) {
1394
// Check if the String is compressed
1395
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
1396
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
1397
} else {
1398
return helpers.getCharFromArrayByIndex(value, index);
1399
}
1400
}
1401
1402
/**
1403
* Compares the specified String to this String using the Unicode values of the characters. Answer 0 if the strings contain the same characters in
1404
* 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 Unicode
1405
* 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 positive
1406
* 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 same
1407
* position in the specified string, or if the specified String is a prefix of the this String.
1408
*
1409
* @param string
1410
* the string to compare
1411
* @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 is
1412
* after the specified String
1413
*
1414
* @throws NullPointerException
1415
* when string is null
1416
*/
1417
public int compareTo(String string) {
1418
String s1 = this;
1419
String s2 = string;
1420
1421
int s1len = s1.lengthInternal();
1422
int s2len = s2.lengthInternal();
1423
1424
// Upper bound index on the last char to compare
1425
int end = s1len < s2len ? s1len : s2len;
1426
1427
int o1 = 0;
1428
int o2 = 0;
1429
1430
byte[] s1Value = s1.value;
1431
byte[] s2Value = s2.value;
1432
1433
if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {
1434
while (o1 < end) {
1435
int result =
1436
helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s1Value, o1++)) -
1437
helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s2Value, o2++));
1438
1439
if (result != 0) {
1440
return result;
1441
}
1442
}
1443
} else {
1444
while (o1 < end) {
1445
int result =
1446
s1.charAtInternal(o1++, s1Value) -
1447
s2.charAtInternal(o2++, s2Value);
1448
1449
if (result != 0) {
1450
return result;
1451
}
1452
}
1453
}
1454
1455
return s1len - s2len;
1456
}
1457
1458
private static int compareValue(int codepoint) {
1459
if ('A' <= codepoint && codepoint <= 'Z') {
1460
return codepoint + ('a' - 'A');
1461
}
1462
1463
return Character.toLowerCase(Character.toUpperCase(codepoint));
1464
}
1465
1466
private static char compareValue(char c) {
1467
if ('A' <= c && c <= 'Z') {
1468
return (char) (c + ('a' - 'A'));
1469
}
1470
1471
return Character.toLowerCase(Character.toUpperCase(c));
1472
}
1473
1474
private static char compareValue(byte b) {
1475
if ('A' <= b && b <= 'Z') {
1476
return (char)(helpers.byteToCharUnsigned(b) + ('a' - 'A'));
1477
}
1478
return Character.toLowerCase(Character.toUpperCase(helpers.byteToCharUnsigned(b)));
1479
}
1480
1481
private static boolean charValuesEqualIgnoreCase(char c1, char c2) {
1482
boolean charValuesEqual = false;
1483
char c1upper = (char) toUpperCase(c1);
1484
char c2upper = (char) toUpperCase(c2);
1485
1486
// If at least one char is ASCII, converting to upper cases then compare should be sufficient.
1487
// If both chars are not in ASCII char set, need to convert to lower case and compare as well.
1488
if (((c1 <= 255 || c2 <= 255) && (c1upper == c2upper))
1489
|| (toLowerCase(c1upper) == toLowerCase(c2upper))
1490
) {
1491
charValuesEqual = true;
1492
}
1493
1494
return charValuesEqual;
1495
}
1496
1497
/**
1498
* Compare the receiver to the specified String to determine the relative ordering when the case of the characters is ignored.
1499
*
1500
* @param string
1501
* a String
1502
* @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 greater
1503
*/
1504
public int compareToIgnoreCase(String string) {
1505
String s1 = this;
1506
String s2 = string;
1507
1508
int s1len = s1.lengthInternal();
1509
int s2len = s2.lengthInternal();
1510
1511
// Upper bound index on the last char to compare
1512
int end = s1len < s2len ? s1len : s2len;
1513
1514
int o1 = 0;
1515
int o2 = 0;
1516
1517
byte[] s1Value = s1.value;
1518
byte[] s2Value = s2.value;
1519
1520
if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {
1521
while (o1 < end) {
1522
byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);
1523
byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);
1524
1525
if (byteAtO1 == byteAtO2) {
1526
continue;
1527
}
1528
1529
int result = compareValue(byteAtO1) - compareValue(byteAtO2);
1530
1531
if (result != 0) {
1532
return result;
1533
}
1534
}
1535
} else {
1536
while (o1 < end) {
1537
char charAtO1 = s1.charAtInternal(o1++, s1Value);
1538
char charAtO2 = s2.charAtInternal(o2++, s2Value);
1539
int codepointAtO1 = charAtO1;
1540
int codepointAtO2 = charAtO2;
1541
1542
if (charAtO1 == charAtO2) {
1543
/*[IF JAVA_SPEC_VERSION >= 16]*/
1544
if (Character.isHighSurrogate(charAtO1) && (o1 < end)) {
1545
codepointAtO1 = Character.toCodePoint(charAtO1, s1.charAtInternal(o1++, s1Value));
1546
codepointAtO2 = Character.toCodePoint(charAtO2, s2.charAtInternal(o2++, s2Value));
1547
if (codepointAtO1 == codepointAtO2) {
1548
continue;
1549
}
1550
} else {
1551
continue;
1552
}
1553
/*[ELSE]*/
1554
continue;
1555
/*[ENDIF] JAVA_SPEC_VERSION >= 16 */
1556
}
1557
1558
int result = compareValue(codepointAtO1) - compareValue(codepointAtO2);
1559
1560
if (result != 0) {
1561
return result;
1562
}
1563
}
1564
}
1565
1566
return s1len - s2len;
1567
}
1568
1569
/**
1570
* Concatenates this String and the specified string.
1571
*
1572
* @param string
1573
* the string to concatenate
1574
* @return a String which is the concatenation of this String and the specified String
1575
*
1576
* @throws NullPointerException
1577
* if string is null
1578
*/
1579
public String concat(String string) {
1580
String s1 = this;
1581
String s2 = string;
1582
1583
int s1len = s1.lengthInternal();
1584
int s2len = s2.lengthInternal();
1585
1586
if (s2len == 0) {
1587
return s1;
1588
}
1589
1590
int concatlen = s1len + s2len;
1591
if (concatlen < 0) {
1592
/*[MSG "K0D01", "Array capacity exceeded"]*/
1593
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
1594
}
1595
1596
if (COMPACT_STRINGS && ((null == compressionFlag) || ((s1.coder | s2.coder) == LATIN1))) {
1597
byte[] buffer = new byte[concatlen];
1598
1599
compressedArrayCopy(s1.value, 0, buffer, 0, s1len);
1600
compressedArrayCopy(s2.value, 0, buffer, s1len, s2len);
1601
1602
return new String(buffer, LATIN1);
1603
} else {
1604
byte[] buffer = StringUTF16.newBytesFor(concatlen);
1605
1606
// Check if the String is compressed
1607
if (COMPACT_STRINGS && s1.coder == LATIN1) {
1608
StringLatin1.inflate(s1.value, 0, buffer, 0, s1len);
1609
} else {
1610
decompressedArrayCopy(s1.value, 0, buffer, 0, s1len);
1611
}
1612
1613
// Check if the String is compressed
1614
if (COMPACT_STRINGS && s2.coder == LATIN1) {
1615
StringLatin1.inflate(s2.value, 0, buffer, s1len, s2len);
1616
} else {
1617
decompressedArrayCopy(s2.value, 0, buffer, s1len, s2len);
1618
}
1619
1620
return new String(buffer, UTF16);
1621
}
1622
}
1623
1624
/**
1625
* Creates a new String containing the characters in the specified character array. Modifying the character array after creating the String has no
1626
* effect on the String.
1627
*
1628
* @param data
1629
* the array of characters
1630
* @return the new String
1631
*
1632
* @throws NullPointerException
1633
* if data is null
1634
*/
1635
public static String copyValueOf(char[] data) {
1636
return new String(data, 0, data.length);
1637
}
1638
1639
/**
1640
* Creates a new String containing the specified characters in the character array. Modifying the character array after creating the String has no
1641
* effect on the String.
1642
*
1643
* @param data
1644
* the array of characters
1645
* @param start
1646
* the starting offset in the character array
1647
* @param length
1648
* the number of characters to use
1649
* @return the new String
1650
*
1651
* @throws IndexOutOfBoundsException
1652
* when {@code length < 0, start < 0} or {@code start + length > data.length}
1653
* @throws NullPointerException
1654
* if data is null
1655
*/
1656
public static String copyValueOf(char[] data, int start, int length) {
1657
return new String(data, start, length);
1658
}
1659
1660
/**
1661
* Compares the specified string to this String to determine if the specified string is a suffix.
1662
*
1663
* @param suffix
1664
* the string to look for
1665
* @return true when the specified string is a suffix of this String, false otherwise
1666
*
1667
* @throws NullPointerException
1668
* if suffix is null
1669
*/
1670
public boolean endsWith(String suffix) {
1671
return regionMatches(lengthInternal() - suffix.lengthInternal(), suffix, 0, suffix.lengthInternal());
1672
}
1673
1674
/**
1675
* 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 in
1676
* the same order.
1677
*
1678
* @param object
1679
* the object to compare
1680
* @return true if the specified object is equal to this String, false otherwise
1681
*
1682
* @see #hashCode()
1683
*/
1684
public boolean equals(Object object) {
1685
if (object == this) {
1686
return true;
1687
} else {
1688
if (object instanceof String) {
1689
String s1 = this;
1690
String s2 = (String) object;
1691
1692
int s1len = s1.lengthInternal();
1693
int s2len = s2.lengthInternal();
1694
1695
if (s1len != s2len) {
1696
return false;
1697
}
1698
1699
byte[] s1Value = s1.value;
1700
byte[] s2Value = s2.value;
1701
1702
if (s1Value == s2Value) {
1703
return true;
1704
} else {
1705
// There was a time hole between first read of s.hash and second read if another thread does hashcode
1706
// computing for incoming string object
1707
int s1hash = s1.hash;
1708
int s2hash = s2.hash;
1709
1710
if (s1hash != 0 && s2hash != 0 && s1hash != s2hash) {
1711
return false;
1712
}
1713
1714
if (!regionMatchesInternal(s1, s2, s1Value, s2Value, 0, 0, s1len)) {
1715
return false;
1716
}
1717
1718
if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY != com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_DISABLED) {
1719
deduplicateStrings(s1, s1Value, s2, s2Value);
1720
}
1721
1722
return true;
1723
}
1724
}
1725
1726
return false;
1727
}
1728
}
1729
1730
/**
1731
* Deduplicate the backing buffers of the given strings.
1732
*
1733
* This updates the {@link #value} of one of the two given strings so that
1734
* they both share a single backing buffer. The strings must have identical
1735
* contents.
1736
*
1737
* Deduplication helps save space, and lets {@link #equals(Object)} exit
1738
* early more often.
1739
*
1740
* The strings' corresponding backing buffers are accepted as parameters
1741
* because the caller likely already has them.
1742
*
1743
* @param s1 The first string
1744
* @param value1 {@code s1.value}
1745
* @param s2 The second string
1746
* @param value2 {@code s2.value}
1747
*/
1748
private static final void deduplicateStrings(String s1, Object value1, String s2, Object value2) {
1749
if (s1.coder == s2.coder) {
1750
long valueFieldOffset = UnsafeHelpers.valueFieldOffset;
1751
1752
if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY == com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_FAVOUR_LOWER) {
1753
if (helpers.acmplt(value1, value2)) {
1754
helpers.putObjectInObject(s2, valueFieldOffset, value1);
1755
} else {
1756
helpers.putObjectInObject(s1, valueFieldOffset, value2);
1757
}
1758
} else {
1759
if (helpers.acmplt(value2, value1)) {
1760
helpers.putObjectInObject(s2, valueFieldOffset, value1);
1761
} else {
1762
helpers.putObjectInObject(s1, valueFieldOffset, value2);
1763
}
1764
}
1765
}
1766
}
1767
1768
/**
1769
* Compares the specified String to this String ignoring the case of the characters and answer if they are equal.
1770
*
1771
* @param string
1772
* the string to compare
1773
* @return true if the specified string is equal to this String, false otherwise
1774
*/
1775
public boolean equalsIgnoreCase(String string) {
1776
String s1 = this;
1777
String s2 = string;
1778
1779
if (s1 == s2) {
1780
return true;
1781
}
1782
1783
if (s2 == null) {
1784
return false;
1785
}
1786
1787
int s1len = s1.lengthInternal();
1788
int s2len = s2.lengthInternal();
1789
1790
if (s1len != s2len) {
1791
return false;
1792
}
1793
1794
// Zero length strings are equal
1795
if (s1len == 0) {
1796
return true;
1797
}
1798
1799
int o1 = 0;
1800
int o2 = 0;
1801
1802
// Upper bound index on the last char to compare
1803
int end = s1len;
1804
1805
byte[] s1Value = s1.value;
1806
byte[] s2Value = s2.value;
1807
1808
if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {
1809
// Compare the last chars.
1810
// In order to tell 2 chars are different:
1811
// Under string compression, the compressible char set obeys 1-1 mapping for upper/lower case,
1812
// converting to upper cases then compare should be sufficient.
1813
byte byteAtO1Last = helpers.getByteFromArrayByIndex(s1Value, s1len - 1);
1814
byte byteAtO2Last = helpers.getByteFromArrayByIndex(s2Value, s1len - 1);
1815
1816
if ((byteAtO1Last != byteAtO2Last)
1817
&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1Last)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2Last)))
1818
) {
1819
return false;
1820
}
1821
1822
while (o1 < end - 1) {
1823
byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);
1824
byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);
1825
1826
if ((byteAtO1 != byteAtO2)
1827
&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2)))
1828
) {
1829
return false;
1830
}
1831
}
1832
} else {
1833
// Compare the last chars.
1834
// In order to tell 2 chars are different:
1835
// If at least one char is ASCII, converting to upper cases then compare should be sufficient.
1836
// If both chars are not in ASCII char set, need to convert to lower case and compare as well.
1837
char charAtO1Last = s1.charAtInternal(s1len - 1, s1Value);
1838
char charAtO2Last = s2.charAtInternal(s1len - 1, s2Value);
1839
1840
if ((charAtO1Last != charAtO2Last)
1841
&& !charValuesEqualIgnoreCase(charAtO1Last, charAtO2Last)
1842
/*[IF JAVA_SPEC_VERSION >= 16]*/
1843
&& (!Character.isLowSurrogate(charAtO1Last) || !Character.isLowSurrogate(charAtO2Last))
1844
/*[ENDIF] JAVA_SPEC_VERSION >= 16 */
1845
) {
1846
return false;
1847
}
1848
1849
/*[IF JAVA_SPEC_VERSION >= 16]*/
1850
while (o1 < end) {
1851
/*[ELSE]*/
1852
while (o1 < end - 1) {
1853
/*[ENDIF] JAVA_SPEC_VERSION >= 16 */
1854
char charAtO1 = s1.charAtInternal(o1++, s1Value);
1855
char charAtO2 = s2.charAtInternal(o2++, s2Value);
1856
1857
/*[IF JAVA_SPEC_VERSION >= 16]*/
1858
if (Character.isHighSurrogate(charAtO1) && Character.isHighSurrogate(charAtO2) && (o1 < end)) {
1859
int codepointAtO1 = Character.toCodePoint(charAtO1, s1.charAtInternal(o1++, s1Value));
1860
int codepointAtO2 = Character.toCodePoint(charAtO2, s2.charAtInternal(o2++, s2Value));
1861
if ((codepointAtO1 != codepointAtO2)
1862
&& (compareValue(codepointAtO1) != compareValue(codepointAtO2))
1863
) {
1864
return false;
1865
} else {
1866
continue;
1867
}
1868
}
1869
/*[ENDIF] JAVA_SPEC_VERSION >= 16 */
1870
1871
if ((charAtO1 != charAtO2)
1872
&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))
1873
) {
1874
return false;
1875
}
1876
}
1877
}
1878
1879
return true;
1880
}
1881
1882
/**
1883
* Converts this String to a byte encoding using the default encoding as specified by the file.encoding system property. If the system property is
1884
* not defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.
1885
*
1886
* @return the byte array encoding of this String
1887
*
1888
* @see String
1889
*/
1890
public byte[] getBytes() {
1891
return StringCoding.encode(coder, value);
1892
}
1893
1894
/**
1895
* Converts this String to a byte array, ignoring the high order bits of each character.
1896
*
1897
* @param start
1898
* the starting offset of characters to copy
1899
* @param end
1900
* the ending offset of characters to copy
1901
* @param data
1902
* the destination byte array
1903
* @param index
1904
* the starting offset in the byte array
1905
*
1906
* @throws NullPointerException
1907
* when data is null
1908
* @throws IndexOutOfBoundsException
1909
* when {@code start < 0, end > length(), index < 0, end - start > data.length - index}
1910
*
1911
* @deprecated Use getBytes() or getBytes(String)
1912
*/
1913
@Deprecated(forRemoval=false, since="1.1")
1914
public void getBytes(int start, int end, byte[] data, int index) {
1915
if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {
1916
// Check if the String is compressed
1917
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
1918
compressedArrayCopy(value, start, data, index, end - start);
1919
} else {
1920
compress(value, start, data, index, end - start);
1921
}
1922
} else {
1923
throw new StringIndexOutOfBoundsException();
1924
}
1925
}
1926
1927
/**
1928
* Converts this String to a byte encoding using the specified encoding.
1929
*
1930
* @param encoding
1931
* the encoding
1932
* @return the byte array encoding of this String
1933
*
1934
* @throws UnsupportedEncodingException
1935
* when the encoding is not supported
1936
*
1937
* @see String
1938
* @see UnsupportedEncodingException
1939
*/
1940
public byte[] getBytes(String encoding) throws UnsupportedEncodingException {
1941
encoding.getClass(); // Implicit null check
1942
return StringCoding.encode(encoding, coder, value);
1943
}
1944
1945
/**
1946
* Copies the specified characters in this String to the character array starting at the specified offset in the character array.
1947
*
1948
* @param start
1949
* the starting offset of characters to copy
1950
* @param end
1951
* the ending offset of characters to copy
1952
* @param data
1953
* the destination character array
1954
* @param index
1955
* the starting offset in the character array
1956
*
1957
* @throws IndexOutOfBoundsException
1958
* when {@code start < 0, end > length(), start > end, index < 0, end - start > buffer.length - index}
1959
* @throws NullPointerException
1960
* when buffer is null
1961
*/
1962
public void getChars(int start, int end, char[] data, int index) {
1963
if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {
1964
getCharsNoBoundChecks(start, end, data, index);
1965
} else {
1966
throw new StringIndexOutOfBoundsException();
1967
}
1968
}
1969
1970
// This is a package protected method that performs the getChars operation without explicit bound checks.
1971
// Caller of this method must validate bound safety for String indexing and array copying.
1972
void getCharsNoBoundChecks(int start, int end, char[] data, int index) {
1973
// Check if the String is compressed
1974
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
1975
StringLatin1.inflate(value, start, data, index, end - start);
1976
} else {
1977
decompressedArrayCopy(value, start, data, index, end - start);
1978
}
1979
}
1980
1981
// This is a package protected method that performs the getChars operation without explicit bound checks.
1982
// Caller of this method must validate bound safety for String indexing and array copying.
1983
void getCharsNoBoundChecks(int start, int end, byte[] data, int index) {
1984
// Check if the String is compressed
1985
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
1986
StringLatin1.inflate(value, start, data, index, end - start);
1987
} else {
1988
decompressedArrayCopy(value, start, data, index, end - start);
1989
}
1990
}
1991
1992
/**
1993
* Answers an integer hash code for the receiver. Objects which are equal answer the same value for this method.
1994
*
1995
* @return the receiver's hash
1996
*
1997
* @see #equals
1998
*/
1999
public int hashCode() {
2000
if (hash == 0 && value.length > 0) {
2001
// Check if the String is compressed
2002
if (COMPACT_STRINGS && (compressionFlag == null || coder == LATIN1)) {
2003
hash = hashCodeImplCompressed(value, 0, lengthInternal());
2004
} else {
2005
hash = hashCodeImplDecompressed(value, 0, lengthInternal());
2006
}
2007
}
2008
2009
return hash;
2010
}
2011
2012
private static int hashCodeImplCompressed(byte[] value, int offset, int count) {
2013
int hash = 0, end = offset + count;
2014
2015
for (int i = offset; i < end; ++i) {
2016
hash = (hash << 5) - hash + helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i));
2017
}
2018
2019
return hash;
2020
}
2021
2022
private static int hashCodeImplDecompressed(byte[] value, int offset, int count) {
2023
int hash = 0, end = offset + count;
2024
2025
for (int i = offset; i < end; ++i) {
2026
hash = (hash << 5) - hash + helpers.getCharFromArrayByIndex(value, i);
2027
}
2028
2029
return hash;
2030
}
2031
2032
/**
2033
* Searches in this String for the first index of the specified character. The search for the character starts at the beginning and moves towards
2034
* the end of this String.
2035
*
2036
* @param c
2037
* the character to find
2038
* @return the index in this String of the specified character, -1 if the character isn't found
2039
*
2040
* @see #lastIndexOf(int)
2041
* @see #lastIndexOf(int, int)
2042
* @see #lastIndexOf(String)
2043
* @see #lastIndexOf(String, int)
2044
*/
2045
public int indexOf(int c) {
2046
return indexOf(c, 0);
2047
}
2048
2049
/**
2050
* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards
2051
* the end of this String.
2052
*
2053
* @param c
2054
* the character to find
2055
* @param start
2056
* the starting offset
2057
* @return the index in this String of the specified character, -1 if the character isn't found
2058
*
2059
* @see #lastIndexOf(int)
2060
* @see #lastIndexOf(int, int)
2061
* @see #lastIndexOf(String)
2062
* @see #lastIndexOf(String, int)
2063
*/
2064
public int indexOf(int c, int start) {
2065
int len = lengthInternal();
2066
2067
if (start < len) {
2068
if (start < 0) {
2069
start = 0;
2070
}
2071
2072
if (c >= 0 && c <= Character.MAX_VALUE) {
2073
byte[] array = value;
2074
2075
// Check if the String is compressed
2076
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2077
if (c <= 255) {
2078
return helpers.intrinsicIndexOfLatin1(array, (byte)c, start, len);
2079
}
2080
} else {
2081
return helpers.intrinsicIndexOfUTF16(array, (char)c, start, len);
2082
}
2083
} else if (c <= Character.MAX_CODE_POINT) {
2084
for (int i = start; i < len; ++i) {
2085
int codePoint = codePointAt(i);
2086
2087
if (codePoint == c) {
2088
return i;
2089
}
2090
2091
if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
2092
++i;
2093
}
2094
}
2095
}
2096
}
2097
2098
return -1;
2099
}
2100
2101
/**
2102
* 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 end
2103
* of this String.
2104
*
2105
* @param string
2106
* the string to find
2107
* @return the index in this String of the specified string, -1 if the string isn't found
2108
*
2109
* @throws NullPointerException
2110
* when string is null
2111
*
2112
* @see #lastIndexOf(int)
2113
* @see #lastIndexOf(int, int)
2114
* @see #lastIndexOf(String)
2115
* @see #lastIndexOf(String, int)
2116
*
2117
*/
2118
public int indexOf(String string) {
2119
return indexOf(string, 0);
2120
}
2121
2122
/**
2123
* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the
2124
* end of this String.
2125
*
2126
* @param subString
2127
* the string to find
2128
* @param start
2129
* the starting offset
2130
* @return the index in this String of the specified string, -1 if the string isn't found
2131
*
2132
* @throws NullPointerException
2133
* when string is null
2134
*
2135
* @see #lastIndexOf(int)
2136
* @see #lastIndexOf(int, int)
2137
* @see #lastIndexOf(String)
2138
* @see #lastIndexOf(String, int)
2139
*/
2140
public int indexOf(String subString, int start) {
2141
if (subString.length() == 1) {
2142
return indexOf(subString.charAtInternal(0), start);
2143
}
2144
2145
return indexOf(value, coder, lengthInternal(), subString, start);
2146
}
2147
2148
static int indexOf(byte[] value, byte coder, int count, String str, int fromIndex) {
2149
int s1Length = count;
2150
int s2Length = str.lengthInternal();
2151
2152
if (fromIndex < 0) {
2153
fromIndex = 0;
2154
} else if (fromIndex >= s1Length) {
2155
// Handle the case where the substring is of zero length, in which case we have an indexOf hit at the end
2156
// of this string
2157
return s2Length == 0 ? s1Length : -1;
2158
}
2159
2160
if (s2Length == 0) {
2161
// At this point we know fromIndex < s1Length so there is a hit at fromIndex
2162
return fromIndex;
2163
}
2164
2165
byte[] s1Value = value;
2166
byte[] s2Value = str.value;
2167
2168
if (coder == str.coder) {
2169
if (coder == LATIN1) {
2170
return StringLatin1.indexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);
2171
} else {
2172
return StringUTF16.indexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);
2173
}
2174
}
2175
2176
if (coder == UTF16) {
2177
return StringUTF16.indexOfLatin1(s1Value, s1Length, s2Value, s2Length, fromIndex);
2178
}
2179
2180
return -1;
2181
}
2182
2183
/**
2184
* 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 string
2185
* contained in the table which is equal to this String. The same string object is always answered for strings which are equal.
2186
*
2187
* @return the interned string equal to this String
2188
*/
2189
public native String intern();
2190
2191
/**
2192
* Searches in this String for the last index of the specified character. The search for the character starts at the end and moves towards the
2193
* beginning of this String.
2194
*
2195
* @param c
2196
* the character to find
2197
* @return the index in this String of the specified character, -1 if the character isn't found
2198
*
2199
* @see #lastIndexOf(int)
2200
* @see #lastIndexOf(int, int)
2201
* @see #lastIndexOf(String)
2202
* @see #lastIndexOf(String, int)
2203
*/
2204
public int lastIndexOf(int c) {
2205
return lastIndexOf(c, lengthInternal() - 1);
2206
}
2207
2208
/**
2209
* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards
2210
* the beginning of this String.
2211
*
2212
* @param c
2213
* the character to find
2214
* @param start
2215
* the starting offset
2216
* @return the index in this String of the specified character, -1 if the character isn't found
2217
*
2218
* @see #lastIndexOf(int)
2219
* @see #lastIndexOf(int, int)
2220
* @see #lastIndexOf(String)
2221
* @see #lastIndexOf(String, int)
2222
*/
2223
public int lastIndexOf(int c, int start) {
2224
if (start >= 0) {
2225
int len = lengthInternal();
2226
2227
if (start >= len) {
2228
start = len - 1;
2229
}
2230
2231
if (c >= 0 && c <= Character.MAX_VALUE) {
2232
byte[] array = value;
2233
2234
// Check if the String is compressed
2235
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2236
if (c <= 255) {
2237
byte b = (byte) c;
2238
2239
for (int i = start; i >= 0; --i) {
2240
if (helpers.getByteFromArrayByIndex(array, i) == b) {
2241
return i;
2242
}
2243
}
2244
}
2245
} else {
2246
for (int i = start; i >= 0; --i) {
2247
if (helpers.getCharFromArrayByIndex(array, i) == c) {
2248
return i;
2249
}
2250
}
2251
}
2252
} else if (c <= Character.MAX_CODE_POINT) {
2253
for (int i = start; i >= 0; --i) {
2254
int codePoint = codePointAt(i);
2255
2256
if (codePoint == c) {
2257
return i;
2258
}
2259
2260
if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
2261
--i;
2262
}
2263
}
2264
}
2265
}
2266
2267
return -1;
2268
}
2269
2270
/**
2271
* 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 beginning
2272
* of this String.
2273
*
2274
* @param string
2275
* the string to find
2276
* @return the index in this String of the specified string, -1 if the string isn't found
2277
*
2278
* @throws NullPointerException
2279
* when string is null
2280
*
2281
* @see #lastIndexOf(int)
2282
* @see #lastIndexOf(int, int)
2283
* @see #lastIndexOf(String)
2284
* @see #lastIndexOf(String, int)
2285
*/
2286
public int lastIndexOf(String string) {
2287
return lastIndexOf(string, lengthInternal());
2288
}
2289
2290
/**
2291
* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the
2292
* beginning of this String.
2293
*
2294
* @param subString
2295
* the string to find
2296
* @param start
2297
* the starting offset
2298
* @return the index in this String of the specified string, -1 if the string isn't found
2299
*
2300
* @throws NullPointerException
2301
* when string is null
2302
*
2303
* @see #lastIndexOf(int)
2304
* @see #lastIndexOf(int, int)
2305
* @see #lastIndexOf(String)
2306
* @see #lastIndexOf(String, int)
2307
*/
2308
public int lastIndexOf(String subString, int start) {
2309
return lastIndexOf(value, coder, lengthInternal(), subString, start);
2310
}
2311
2312
static int lastIndexOf(byte[] value, byte coder, int count, String str, int fromIndex) {
2313
int s1Length = count;
2314
int s2Length = str.lengthInternal();
2315
2316
if (fromIndex > s1Length - s2Length) {
2317
fromIndex = s1Length - s2Length;
2318
}
2319
2320
if (fromIndex < 0) {
2321
return -1;
2322
}
2323
2324
if (s2Length == 0) {
2325
return fromIndex;
2326
}
2327
2328
byte[] s1Value = value;
2329
byte[] s2Value = str.value;
2330
2331
if (coder == str.coder) {
2332
if (coder == LATIN1) {
2333
return StringLatin1.lastIndexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);
2334
} else {
2335
return StringUTF16.lastIndexOf(s1Value, s1Length, s2Value, s2Length, fromIndex);
2336
}
2337
}
2338
2339
if (coder == UTF16) {
2340
return StringUTF16.lastIndexOfLatin1(s1Value, s1Length, s2Value, s2Length, fromIndex);
2341
}
2342
2343
return -1;
2344
}
2345
2346
/**
2347
* Answers the size of this String.
2348
*
2349
* @return the number of characters in this String
2350
*/
2351
public int length() {
2352
return lengthInternal();
2353
}
2354
2355
/**
2356
* Answers the size of this String. This method is to be used internally within the current package whenever
2357
* possible as the JIT compiler will take special precaution to avoid generating HCR guards for calls to this
2358
* method.
2359
*
2360
* @return the number of characters in this String
2361
*/
2362
int lengthInternal() {
2363
if (COMPACT_STRINGS) {
2364
return value.length >> coder;
2365
} else {
2366
return value.length >> 1;
2367
}
2368
}
2369
2370
/**
2371
* Compares the specified string to this String and compares the specified range of characters to determine if they are the same.
2372
*
2373
* @param thisStart
2374
* the starting offset in this String
2375
* @param string
2376
* the string to compare
2377
* @param start
2378
* the starting offset in string
2379
* @param length
2380
* the number of characters to compare
2381
* @return true if the ranges of characters is equal, false otherwise
2382
*
2383
* @throws NullPointerException
2384
* when string is null
2385
*/
2386
public boolean regionMatches(int thisStart, String string, int start, int length) {
2387
string.getClass(); // Implicit null check
2388
2389
String s1 = this;
2390
String s2 = string;
2391
2392
int s1len = s1.lengthInternal();
2393
int s2len = s2.lengthInternal();
2394
2395
if (start < 0 || s2len - start < length) {
2396
return false;
2397
}
2398
2399
if (thisStart < 0 || s1len - thisStart < length) {
2400
return false;
2401
}
2402
2403
return regionMatchesInternal(s1, s2, s1.value, s2.value, thisStart, start, length);
2404
}
2405
2406
private static boolean regionMatchesInternal(String s1, String s2, byte[] s1Value, byte[] s2Value, int s1Start, int s2Start, int length)
2407
{
2408
if (length <= 0) {
2409
return true;
2410
}
2411
2412
// Index of the last char to compare
2413
int end = length - 1;
2414
2415
if (COMPACT_STRINGS && ((compressionFlag == null) || ((s1.coder | s2.coder) == LATIN1))) {
2416
if (helpers.getByteFromArrayByIndex(s1Value, s1Start + end) != helpers.getByteFromArrayByIndex(s2Value, s2Start + end)) {
2417
return false;
2418
} else {
2419
for (int i = 0; i < end; ++i) {
2420
if (helpers.getByteFromArrayByIndex(s1Value, s1Start + i) != helpers.getByteFromArrayByIndex(s2Value, s2Start + i)) {
2421
return false;
2422
}
2423
}
2424
}
2425
} else {
2426
if (s1.charAtInternal(s1Start + end, s1Value) != s2.charAtInternal(s2Start + end, s2Value)) {
2427
return false;
2428
} else {
2429
for (int i = 0; i < end; ++i) {
2430
if (s1.charAtInternal(s1Start + i, s1Value) != s2.charAtInternal(s2Start + i, s2Value)) {
2431
return false;
2432
}
2433
}
2434
}
2435
}
2436
return true;
2437
}
2438
2439
/**
2440
* Compares the specified string to this String and compares the specified range of characters to determine if they are the same. When ignoreCase
2441
* is true, the case of the characters is ignored during the comparison.
2442
*
2443
* @param ignoreCase
2444
* specifies if case should be ignored
2445
* @param thisStart
2446
* the starting offset in this String
2447
* @param string
2448
* the string to compare
2449
* @param start
2450
* the starting offset in string
2451
* @param length
2452
* the number of characters to compare
2453
* @return true if the ranges of characters is equal, false otherwise
2454
*
2455
* @throws NullPointerException
2456
* when string is null
2457
*/
2458
public boolean regionMatches(boolean ignoreCase, int thisStart, String string, int start, int length) {
2459
if (!ignoreCase) {
2460
return regionMatches(thisStart, string, start, length);
2461
}
2462
2463
string.getClass(); // Implicit null check
2464
2465
String s1 = this;
2466
String s2 = string;
2467
2468
int s1len = s1.lengthInternal();
2469
int s2len = s2.lengthInternal();
2470
2471
if (thisStart < 0 || length > s1len - thisStart) {
2472
return false;
2473
}
2474
2475
if (start < 0 || length > s2len - start) {
2476
return false;
2477
}
2478
2479
if (length <= 0) {
2480
return true;
2481
}
2482
2483
int o1 = thisStart;
2484
int o2 = start;
2485
2486
// Upper bound index on the last char to compare
2487
int end = thisStart + length;
2488
2489
byte[] s1Value = s1.value;
2490
byte[] s2Value = s2.value;
2491
2492
if (COMPACT_STRINGS && (null == compressionFlag || (s1.coder | s2.coder) == LATIN1)) {
2493
while (o1 < end) {
2494
byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);
2495
byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);
2496
2497
if ((byteAtO1 != byteAtO2)
2498
&& (!charValuesEqualIgnoreCase(helpers.byteToCharUnsigned(byteAtO1), helpers.byteToCharUnsigned(byteAtO2)))
2499
) {
2500
return false;
2501
}
2502
}
2503
} else {
2504
while (o1 < end) {
2505
char charAtO1 = s1.charAtInternal(o1++, s1Value);
2506
char charAtO2 = s2.charAtInternal(o2++, s2Value);
2507
2508
/*[IF JAVA_SPEC_VERSION >= 16]*/
2509
if (Character.isHighSurrogate(charAtO1) && Character.isHighSurrogate(charAtO2) && (o1 < end)) {
2510
int codepointAtO1 = Character.toCodePoint(charAtO1, s1.charAtInternal(o1++, s1Value));
2511
int codepointAtO2 = Character.toCodePoint(charAtO2, s2.charAtInternal(o2++, s2Value));
2512
if ((codepointAtO1 != codepointAtO2)
2513
&& (compareValue(codepointAtO1) != compareValue(codepointAtO2))
2514
) {
2515
return false;
2516
}
2517
}
2518
/*[ENDIF] JAVA_SPEC_VERSION >= 16 */
2519
2520
if ((charAtO1 != charAtO2)
2521
&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))
2522
) {
2523
return false;
2524
}
2525
}
2526
}
2527
2528
return true;
2529
}
2530
2531
/**
2532
* Replaces occurrences of the specified character with another character.
2533
*
2534
* @param oldChar
2535
* the character to replace
2536
* @param newChar
2537
* the replacement character
2538
* @return a String with occurrences of oldChar replaced by newChar
2539
*/
2540
public String replace(char oldChar, char newChar) {
2541
int index = indexOf(oldChar, 0);
2542
2543
if (index == -1) {
2544
return this;
2545
}
2546
2547
int len = lengthInternal();
2548
2549
// Check if the String is compressed
2550
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2551
if (newChar <= 255) {
2552
byte[] buffer = new byte[len];
2553
2554
compressedArrayCopy(value, 0, buffer, 0, len);
2555
2556
do {
2557
helpers.putByteInArrayByIndex(buffer, index++, (byte) newChar);
2558
} while ((index = indexOf(oldChar, index)) != -1);
2559
2560
return new String(buffer, LATIN1);
2561
} else {
2562
byte[] buffer = StringUTF16.newBytesFor(len);
2563
2564
StringLatin1.inflate(value, 0, buffer, 0, len);
2565
2566
do {
2567
helpers.putCharInArrayByIndex(buffer, index++, (char) newChar);
2568
} while ((index = indexOf(oldChar, index)) != -1);
2569
2570
return new String(buffer, UTF16);
2571
}
2572
} else {
2573
byte[] buffer = StringUTF16.newBytesFor(len);
2574
2575
decompressedArrayCopy(value, 0, buffer, 0, len);
2576
2577
do {
2578
helpers.putCharInArrayByIndex(buffer, index++, (char) newChar);
2579
} while ((index = indexOf(oldChar, index)) != -1);
2580
2581
return new String(buffer, UTF16);
2582
}
2583
}
2584
2585
/**
2586
* Compares the specified string to this String to determine if the specified string is a prefix.
2587
*
2588
* @param prefix
2589
* the string to look for
2590
* @return true when the specified string is a prefix of this String, false otherwise
2591
*
2592
* @throws NullPointerException
2593
* when prefix is null
2594
*/
2595
public boolean startsWith(String prefix) {
2596
return startsWith(prefix, 0);
2597
}
2598
2599
/**
2600
* Compares the specified string to this String, starting at the specified offset, to determine if the specified string is a prefix.
2601
*
2602
* @param prefix
2603
* the string to look for
2604
* @param start
2605
* the starting offset
2606
* @return true when the specified string occurs in this String at the specified offset, false otherwise
2607
*
2608
* @throws NullPointerException
2609
* when prefix is null
2610
*/
2611
public boolean startsWith(String prefix, int start) {
2612
if (prefix.length() == 1) {
2613
if (start < 0 || start >= this.length()) {
2614
return false;
2615
}
2616
return charAtInternal(start) == prefix.charAtInternal(0);
2617
}
2618
return regionMatches(start, prefix, 0, prefix.lengthInternal());
2619
}
2620
2621
/*[IF JAVA_SPEC_VERSION >= 11]*/
2622
/**
2623
* Strip leading and trailing white space from a string.
2624
*
2625
* @return a substring of the original containing no leading
2626
* or trailing white space
2627
*
2628
* @since 11
2629
*/
2630
public String strip() {
2631
String result;
2632
2633
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2634
result = StringLatin1.strip(value);
2635
} else {
2636
result = StringUTF16.strip(value);
2637
}
2638
2639
return (result == null) ? this : result;
2640
}
2641
2642
/**
2643
* Strip leading white space from a string.
2644
*
2645
* @return a substring of the original containing no leading
2646
* white space
2647
*
2648
* @since 11
2649
*/
2650
public String stripLeading() {
2651
String result;
2652
2653
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2654
result = StringLatin1.stripLeading(value);
2655
} else {
2656
result = StringUTF16.stripLeading(value);
2657
}
2658
2659
return (result == null) ? this : result;
2660
}
2661
2662
/**
2663
* Strip trailing white space from a string.
2664
*
2665
* @return a substring of the original containing no trailing
2666
* white space
2667
*
2668
* @since 11
2669
*/
2670
public String stripTrailing() {
2671
String result;
2672
2673
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2674
result = StringLatin1.stripTrailing(value);
2675
} else {
2676
result = StringUTF16.stripTrailing(value);
2677
}
2678
2679
return (result == null) ? this : result;
2680
}
2681
2682
/**
2683
* Determine if the string contains only white space characters.
2684
*
2685
* @return true if the string is empty or contains only white space
2686
* characters, otherwise false.
2687
*
2688
* @since 11
2689
*/
2690
public boolean isBlank() {
2691
int index;
2692
2693
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2694
index = StringLatin1.indexOfNonWhitespace(value);
2695
} else {
2696
index = StringUTF16.indexOfNonWhitespace(value);
2697
}
2698
2699
return index >= lengthInternal();
2700
}
2701
2702
/**
2703
* Returns a stream of substrings extracted from this string partitioned by line terminators.
2704
*
2705
* Line terminators recognized are line feed "\n", carriage return "\r", and carriage return
2706
* followed by line feed "\r\n".
2707
*
2708
* @return the stream of this string's substrings partitioned by line terminators
2709
*
2710
* @since 11
2711
*/
2712
public Stream<String> lines() {
2713
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2714
return StringLatin1.lines(value);
2715
} else {
2716
return StringUTF16.lines(value);
2717
}
2718
}
2719
/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
2720
2721
/**
2722
* Copies a range of characters into a new String.
2723
*
2724
* @param start
2725
* the offset of the first character
2726
* @return a new String containing the characters from start to the end of the string
2727
*
2728
* @throws IndexOutOfBoundsException
2729
* when {@code start < 0} or {@code start > length()}
2730
*/
2731
public String substring(int start) {
2732
if (start == 0) {
2733
return this;
2734
}
2735
if (start < 0) {
2736
throw new StringIndexOutOfBoundsException(start);
2737
}
2738
int len = lengthInternal();
2739
if (start <= len) {
2740
boolean isCompressed = false;
2741
// Check if the String is compressed
2742
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2743
isCompressed = true;
2744
}
2745
return new String(value, start, len - start, isCompressed, enableSharingInSubstringWhenOffsetIsZero);
2746
}
2747
throw new StringIndexOutOfBoundsException("begin " + start + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$
2748
}
2749
2750
/**
2751
* Copies a range of characters.
2752
*
2753
* @param start
2754
* the offset of the first character
2755
* @param end
2756
* the offset one past the last character
2757
* @return a String containing the characters from start to end - 1
2758
*
2759
* @throws IndexOutOfBoundsException
2760
* when {@code start < 0, start > end} or {@code end > length()}
2761
*/
2762
public String substring(int start, int end) {
2763
int len = lengthInternal();
2764
if (start == 0 && end == len) {
2765
return this;
2766
}
2767
if ((start >= 0) && (start <= end) && (end <= len)) {
2768
boolean isCompressed = false;
2769
// Check if the String is compressed
2770
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2771
isCompressed = true;
2772
}
2773
return new String(value, start, end - start, isCompressed, enableSharingInSubstringWhenOffsetIsZero);
2774
}
2775
throw new StringIndexOutOfBoundsException("begin " + start + ", end " + end + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2776
}
2777
2778
/**
2779
* Copies the characters in this String to a character array.
2780
*
2781
* @return a character array containing the characters of this String
2782
*/
2783
public char[] toCharArray() {
2784
int len = lengthInternal();
2785
2786
char[] buffer = new char[len];
2787
2788
// Check if the String is compressed
2789
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2790
StringLatin1.inflate(value, 0, buffer, 0, len);
2791
} else {
2792
decompressedArrayCopy(value, 0, buffer, 0, len);
2793
}
2794
2795
return buffer;
2796
}
2797
2798
/**
2799
* Converts the characters in this String to lowercase, using the default Locale. To convert to lower case independent of any locale, use
2800
* toLowerCase(Locale.ROOT).
2801
*
2802
* @return a new String containing the lowercase characters equivalent to the characters in this String
2803
*/
2804
public String toLowerCase() {
2805
return toLowerCase(Locale.getDefault());
2806
}
2807
2808
private static int toLowerCase(int codePoint) {
2809
if (codePoint < 128) {
2810
if ('A' <= codePoint && codePoint <= 'Z') {
2811
return codePoint + ('a' - 'A');
2812
} else {
2813
return codePoint;
2814
}
2815
} else {
2816
return Character.toLowerCase(codePoint);
2817
}
2818
}
2819
2820
private static int toUpperCase(int codePoint) {
2821
if (codePoint < 128) {
2822
if ('a' <= codePoint && codePoint <= 'z') {
2823
return codePoint - ('a' - 'A');
2824
} else {
2825
return codePoint;
2826
}
2827
} else {
2828
return Character.toUpperCase(codePoint);
2829
}
2830
}
2831
2832
/**
2833
* Converts the characters in this String to lowercase, using the specified Locale.
2834
*
2835
* @param locale
2836
* the Locale
2837
* @return a String containing the lowercase characters equivalent to the characters in this String
2838
*/
2839
public String toLowerCase(Locale locale) {
2840
// check locale for null
2841
String language = locale.getLanguage();
2842
int sLength = lengthInternal();
2843
2844
if (sLength == 0) {
2845
return this;
2846
}
2847
2848
boolean useIntrinsic = helpers.supportsIntrinsicCaseConversion()
2849
&& (language == "en") //$NON-NLS-1$
2850
&& (sLength <= (Integer.MAX_VALUE / 2));
2851
2852
if (COMPACT_STRINGS && ((null == compressionFlag) || (coder == LATIN1))) {
2853
if (useIntrinsic) {
2854
byte[] output = new byte[sLength << coder];
2855
2856
if (helpers.toLowerIntrinsicLatin1(value, output, sLength)) {
2857
return new String(output, LATIN1);
2858
}
2859
}
2860
return StringLatin1.toLowerCase(this, value, locale);
2861
} else {
2862
if (useIntrinsic) {
2863
byte[] output = new byte[sLength << coder];
2864
2865
if (helpers.toLowerIntrinsicUTF16(value, output, sLength * 2)) {
2866
return new String(output, UTF16);
2867
}
2868
}
2869
return StringUTF16.toLowerCase(this, value, locale);
2870
}
2871
}
2872
2873
/**
2874
* Answers a string containing a concise, human-readable description of the receiver.
2875
*
2876
* @return this String
2877
*/
2878
public String toString() {
2879
return this;
2880
}
2881
2882
/**
2883
* Converts the characters in this String to uppercase, using the default Locale. To convert to upper case independent of any locale, use
2884
* toUpperCase(Locale.ROOT).
2885
*
2886
* @return a String containing the uppercase characters equivalent to the characters in this String
2887
*/
2888
public String toUpperCase() {
2889
return toUpperCase(Locale.getDefault());
2890
}
2891
2892
/**
2893
* Converts the characters in this String to uppercase, using the specified Locale.
2894
*
2895
* @param locale
2896
* the Locale
2897
* @return a String containing the uppercase characters equivalent to the characters in this String
2898
*/
2899
public String toUpperCase(Locale locale) {
2900
String language = locale.getLanguage();
2901
int sLength = lengthInternal();
2902
2903
if (sLength == 0) {
2904
return this;
2905
}
2906
2907
boolean useIntrinsic = helpers.supportsIntrinsicCaseConversion()
2908
&& (language == "en") //$NON-NLS-1$
2909
&& (sLength <= (Integer.MAX_VALUE / 2));
2910
2911
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2912
if (useIntrinsic) {
2913
byte[] output = new byte[sLength << coder];
2914
2915
if (helpers.toUpperIntrinsicLatin1(value, output, sLength)) {
2916
return new String(output, LATIN1);
2917
}
2918
}
2919
return StringLatin1.toUpperCase(this, value, locale);
2920
} else {
2921
if (useIntrinsic) {
2922
byte[] output = new byte[sLength << coder];
2923
2924
if (helpers.toUpperIntrinsicUTF16(value, output, sLength * 2)) {
2925
return new String(output, UTF16);
2926
}
2927
}
2928
return StringUTF16.toUpperCase(this, value, locale);
2929
}
2930
}
2931
2932
/**
2933
* Removes white space characters from the beginning and end of the string.
2934
*
2935
* @return a String with characters {@code <= \\u0020} removed from the beginning and the end
2936
*/
2937
public String trim() {
2938
int start = 0;
2939
int last = lengthInternal() - 1;
2940
int end = last;
2941
2942
// Check if the String is compressed
2943
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
2944
while ((start <= end) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, start)) <= ' ')) {
2945
start++;
2946
}
2947
2948
while ((end >= start) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, end)) <= ' ')) {
2949
end--;
2950
}
2951
2952
if (start == 0 && end == last) {
2953
return this;
2954
} else {
2955
return new String(value, start, end - start + 1, true);
2956
}
2957
} else {
2958
while ((start <= end) && (charAtInternal(start) <= ' ')) {
2959
start++;
2960
}
2961
2962
while ((end >= start) && (charAtInternal(end) <= ' ')) {
2963
end--;
2964
}
2965
2966
if (start == 0 && end == last) {
2967
return this;
2968
} else {
2969
return new String(value, start, end - start + 1, false);
2970
}
2971
}
2972
}
2973
2974
/**
2975
* Returns a String containing the characters in the specified character array. Modifying the character array after creating the String has no
2976
* effect on the String.
2977
*
2978
* @param data
2979
* the array of characters
2980
* @return the String
2981
*
2982
* @throws NullPointerException
2983
* when data is null
2984
*/
2985
public static String valueOf(char[] data) {
2986
return new String(data, 0, data.length);
2987
}
2988
2989
/**
2990
* Returns a String containing the specified characters in the character array. Modifying the character array after creating the String has no
2991
* effect on the String.
2992
*
2993
* @param data
2994
* the array of characters
2995
* @param start
2996
* the starting offset in the character array
2997
* @param length
2998
* the number of characters to use
2999
* @return the String
3000
*
3001
* @throws IndexOutOfBoundsException
3002
* when {@code length < 0, start < 0} or {@code start + length > data.length}
3003
* @throws NullPointerException
3004
* when data is null
3005
*/
3006
public static String valueOf(char[] data, int start, int length) {
3007
return new String(data, start, length);
3008
}
3009
3010
/**
3011
* Converts the specified character to its string representation.
3012
*
3013
* @param value
3014
* the character
3015
* @return the character converted to a string
3016
*/
3017
public static String valueOf(char value) {
3018
String string;
3019
3020
if (value <= 255) {
3021
if (COMPACT_STRINGS) {
3022
string = new String(compressedAsciiTable[value], 0, 1, true);
3023
} else {
3024
string = new String(decompressedAsciiTable[value], 0, 1, false);
3025
}
3026
} else {
3027
byte[] buffer = new byte[2];
3028
3029
helpers.putCharInArrayByIndex(buffer, 0, value);
3030
3031
string = new String(buffer, 0, 1, false);
3032
}
3033
3034
return string;
3035
}
3036
3037
/**
3038
* Converts the specified double to its string representation.
3039
*
3040
* @param value
3041
* the double
3042
* @return the double converted to a string
3043
*/
3044
public static String valueOf(double value) {
3045
return Double.toString(value);
3046
}
3047
3048
/**
3049
* Converts the specified float to its string representation.
3050
*
3051
* @param value
3052
* the float
3053
* @return the float converted to a string
3054
*/
3055
public static String valueOf(float value) {
3056
return Float.toString(value);
3057
}
3058
3059
/**
3060
* Converts the specified integer to its string representation.
3061
*
3062
* @param value
3063
* the integer
3064
* @return the integer converted to a string
3065
*/
3066
public static String valueOf(int value) {
3067
return Integer.toString(value);
3068
}
3069
3070
/**
3071
* Converts the specified long to its string representation.
3072
*
3073
* @param value
3074
* the long
3075
* @return the long converted to a string
3076
*/
3077
public static String valueOf(long value) {
3078
return Long.toString(value);
3079
}
3080
3081
/**
3082
* Converts the specified object to its string representation. If the object is null answer the string {@code "null"}, otherwise use
3083
* {@code toString()} to get the string representation.
3084
*
3085
* @param value
3086
* the object
3087
* @return the object converted to a string
3088
*/
3089
public static String valueOf(Object value) {
3090
return value != null ? value.toString() : "null"; //$NON-NLS-1$
3091
}
3092
3093
/**
3094
* Converts the specified boolean to its string representation. When the boolean is true answer {@code "true"}, otherwise answer
3095
* {@code "false"}.
3096
*
3097
* @param value
3098
* the boolean
3099
* @return the boolean converted to a string
3100
*/
3101
public static String valueOf(boolean value) {
3102
return value ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$
3103
}
3104
3105
/**
3106
* Answers whether the characters in the StringBuffer buffer are the same as those in this String.
3107
*
3108
* @param buffer
3109
* the StringBuffer to compare this String to
3110
* @return true when the characters in buffer are identical to those in this String. If they are not, false will be returned.
3111
*
3112
* @throws NullPointerException
3113
* when buffer is null
3114
*
3115
* @since 1.4
3116
*/
3117
public boolean contentEquals(StringBuffer buffer) {
3118
synchronized (buffer) {
3119
int s1Length = lengthInternal();
3120
int sbLength = buffer.length();
3121
3122
if (s1Length != sbLength) {
3123
return false;
3124
}
3125
3126
byte[] s1Value = value;
3127
byte[] sbValue = buffer.getValue();
3128
3129
if (coder == buffer.getCoder()) {
3130
for (int i = 0; i < s1Value.length; ++i) {
3131
if (s1Value[i] != sbValue[i]) {
3132
return false;
3133
}
3134
}
3135
3136
return true;
3137
}
3138
3139
// String objects are always compressed if compression is possible, thus if the buffer is compressed and the
3140
// String object is not it is impossible for their contents to equal
3141
if (coder == UTF16) {
3142
return false;
3143
}
3144
3145
// Otherwise we have a LATIN1 String and a UTF16 StringBuffer
3146
return StringUTF16.contentEquals(s1Value, sbValue, s1Length);
3147
}
3148
}
3149
3150
/**
3151
* Determines whether a this String matches a given regular expression.
3152
*
3153
* @param expr
3154
* the regular expression to be matched
3155
* @return true if the expression matches, otherwise false
3156
*
3157
* @throws PatternSyntaxException
3158
* if the syntax of the supplied regular expression is not valid
3159
* @throws NullPointerException
3160
* if expr is null
3161
*
3162
* @since 1.4
3163
*/
3164
public boolean matches(String expr) {
3165
return Pattern.matches(expr, this);
3166
}
3167
3168
/**
3169
* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.
3170
*
3171
* @param regex
3172
* the regular expression to match
3173
* @param substitute
3174
* the string to replace the matching substring with
3175
* @return the new string
3176
*
3177
* @throws NullPointerException
3178
* if expr is null
3179
*
3180
* @since 1.4
3181
*/
3182
public String replaceAll(String regex, String substitute) {
3183
// this is a fast path to handle replacements of 1 character with another or the deletion of
3184
// a single character (common operations when dealing with things like package names, file
3185
// system paths etc). In these simple cases a linear scan of the string is all that is necessary
3186
// and we can avoid the cost of building a full regex pattern matcher
3187
if (regex != null && substitute != null && regex.lengthInternal() == 1 && !hasMetaChars(regex)) {
3188
int substituteLength = substitute.lengthInternal();
3189
int length = lengthInternal();
3190
if (substituteLength < 2) {
3191
if (COMPACT_STRINGS && isCompressed() && (substituteLength == 0 || substitute.isCompressed())) {
3192
byte[] newChars = new byte[length];
3193
byte toReplace = helpers.getByteFromArrayByIndex(regex.value, 0);
3194
byte replacement = (byte)-1; // assign dummy value that will never be used
3195
if (substituteLength == 1) {
3196
replacement = helpers.getByteFromArrayByIndex(substitute.value, 0);
3197
checkLastChar((char)replacement);
3198
}
3199
int newCharIndex = 0;
3200
for (int i = 0; i < length; ++i) {
3201
byte current = helpers.getByteFromArrayByIndex(value, i);
3202
if (current != toReplace) {
3203
helpers.putByteInArrayByIndex(newChars, newCharIndex++, current);
3204
} else if (substituteLength == 1) {
3205
helpers.putByteInArrayByIndex(newChars, newCharIndex++, replacement);
3206
}
3207
}
3208
return new String(newChars, 0, newCharIndex, true);
3209
} else if (!COMPACT_STRINGS || !isCompressed()) {
3210
byte[] newChars = StringUTF16.newBytesFor(length);
3211
char toReplace = regex.charAtInternal(0);
3212
char replacement = (char)-1; // assign dummy value that will never be used
3213
if (substituteLength == 1) {
3214
replacement = substitute.charAtInternal(0);
3215
checkLastChar(replacement);
3216
}
3217
int newCharIndex = 0;
3218
for (int i = 0; i < length; ++i) {
3219
char current = helpers.getCharFromArrayByIndex(value, i);
3220
if (current != toReplace) {
3221
helpers.putCharInArrayByIndex(newChars, newCharIndex++, current);
3222
} else if (substituteLength == 1) {
3223
helpers.putCharInArrayByIndex(newChars, newCharIndex++, replacement);
3224
}
3225
}
3226
return new String(newChars, 0, newCharIndex, false);
3227
}
3228
}
3229
}
3230
return Pattern.compile(regex).matcher(this).replaceAll(substitute);
3231
}
3232
3233
/**
3234
* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.
3235
*
3236
* @param expr
3237
* the regular expression to match
3238
* @param substitute
3239
* the string to replace the matching substring with
3240
* @return the new string
3241
*
3242
* @throws NullPointerException
3243
* if expr is null
3244
*
3245
* @since 1.4
3246
*/
3247
public String replaceFirst(String expr, String substitute) {
3248
return Pattern.compile(expr).matcher(this).replaceFirst(substitute);
3249
}
3250
3251
/**
3252
* Splits this string around matches of the given regular expression. Calling this method is same as calling split(regex,0). Therefore, empty
3253
* string(s) at the end of the returned array will be discarded.
3254
*
3255
*
3256
* @param regex
3257
* Regular expression that is used as a delimiter
3258
* @return The array of strings which are split around the regex
3259
*
3260
* @throws PatternSyntaxException
3261
* if the syntax of regex is invalid
3262
*
3263
* @since 1.4
3264
*/
3265
public String[] split(String regex) {
3266
return split(regex, 0);
3267
}
3268
3269
private static final char[] regexMetaChars = new char[]
3270
{ '.', '$', '|', '(', ')', '[', ']', '{', '}', '^', '?', '*', '+', '\\' };
3271
3272
private static final boolean hasMetaChars(String s) {
3273
for (int i = 0; i < s.lengthInternal(); ++i) {
3274
char ch = s.charAtInternal(i);
3275
3276
// Note the surrogate ranges are HIGH: \uD800-\uDBFF; LOW: \uDC00-\uDFFF
3277
// this check is, therefore, equivalent to returning true if the character
3278
// falls anywhere in this range including the range between MAX_LOW_SURROGATE
3279
// and MIN_HIGH_SURROGATE which happen to be adjacent
3280
if (ch >= Character.MIN_HIGH_SURROGATE
3281
&& ch <= Character.MAX_LOW_SURROGATE) { return true; }
3282
3283
for (int j = 0; j < regexMetaChars.length; ++j) {
3284
if (ch == regexMetaChars[j]) { return true; }
3285
}
3286
}
3287
return false;
3288
}
3289
3290
private static final boolean isSingleEscapeLiteral(String s) {
3291
if ((s != null) && (s.lengthInternal() == 2) && (s.charAtInternal(0) == '\\')) {
3292
char literal = s.charAtInternal(1);
3293
for (int j = 0; j < regexMetaChars.length; ++j) {
3294
if (literal == regexMetaChars[j]) return true;
3295
}
3296
}
3297
return false;
3298
}
3299
3300
/**
3301
* Splits this String using the given regular expression.
3302
*
3303
* max controls the number of times the regex is applied to this string.
3304
* If max is positive, then regex can be applied to this String max-1 times.
3305
* The returned array size can not be bigger than max, and the last element of
3306
* the returned array contains all input after the last match of the regex.
3307
* If max is negative or zero, then regex can be applied to this string as many times as
3308
* possible and there is no size limit in the returned array.
3309
* If max is 0, all the empty string(s) at the end of the returned array will be discarded.
3310
*
3311
* @param regex Regular expression that is used as a delimiter
3312
* @param max The threshold of the returned array
3313
* @return The array of strings which are split around the regex
3314
*
3315
* @throws PatternSyntaxException if the syntax of regex is invalid
3316
*
3317
* @since 1.4
3318
*/
3319
public String[] split(String regex, int max) {
3320
// it is faster to handle simple splits inline (i.e. no fancy regex matching),
3321
// including single escaped literal character (e.g. \. \{),
3322
// so we test for a suitable string and handle this here if we can
3323
boolean singleEscapeLiteral = isSingleEscapeLiteral(regex);
3324
if ((regex != null) && (regex.lengthInternal() > 0) && (!hasMetaChars(regex) || singleEscapeLiteral)) {
3325
if (max == 1) {
3326
return new String[] { this };
3327
}
3328
java.util.ArrayList<String> parts = new java.util.ArrayList<String>((max > 0 && max < 100) ? max : 10);
3329
3330
byte[] chars = this.value;
3331
3332
final boolean compressed = COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1);
3333
3334
int start = 0, current = 0, end = lengthInternal();
3335
if (regex.lengthInternal() == 1 || singleEscapeLiteral) {
3336
// if matching single escaped character, use the second char.
3337
char splitChar = regex.charAtInternal(singleEscapeLiteral ? 1 : 0);
3338
while (current < end) {
3339
if (charAtInternal(current, chars) == splitChar) {
3340
parts.add(new String(chars, start, current - start, compressed));
3341
start = current + 1;
3342
if (max > 0 && parts.size() == max - 1) {
3343
parts.add(new String(chars, start, end - start, compressed));
3344
break;
3345
}
3346
}
3347
current = current + 1;
3348
}
3349
} else {
3350
int rLength = regex.lengthInternal();
3351
3352
byte[] splitChars = regex.value;
3353
3354
char firstChar = charAtInternal(0, regex.value);
3355
while (current < end) {
3356
if (charAtInternal(current, chars) == firstChar) {
3357
int idx = current + 1;
3358
int matchIdx = 1;
3359
while (matchIdx < rLength && idx < end) {
3360
if (charAtInternal(idx, chars) != charAtInternal(matchIdx, splitChars)) {
3361
break;
3362
}
3363
matchIdx++;
3364
idx++;
3365
}
3366
if (matchIdx == rLength) {
3367
parts.add(new String(chars, start, current - start, compressed));
3368
start = current + rLength;
3369
if (max > 0 && parts.size() == max - 1) {
3370
parts.add(new String(chars, start, end - start, compressed));
3371
break;
3372
}
3373
current = current + rLength;
3374
continue;
3375
}
3376
}
3377
current = current + 1;
3378
}
3379
}
3380
if (parts.size() == 0) {
3381
return new String[] { this };
3382
} else if (start <= current && parts.size() != max) {
3383
parts.add(new String(chars, start, current - start, compressed));
3384
}
3385
if (max == 0) {
3386
end = parts.size();
3387
while (end > 0 && parts.get(end - 1).lengthInternal() == 0) {
3388
end -= 1;
3389
parts.remove(end);
3390
}
3391
}
3392
return parts.toArray(new String[parts.size()]);
3393
}
3394
return Pattern.compile(regex).split(this, max);
3395
}
3396
3397
/**
3398
* Has the same result as the substring function, but is present so that String may implement the CharSequence interface.
3399
*
3400
* @param start
3401
* the offset the first character
3402
* @param end
3403
* the offset of one past the last character to include
3404
*
3405
* @return the subsequence requested
3406
*
3407
* @throws IndexOutOfBoundsException
3408
* when start or end is less than zero, start is greater than end, or end is greater than the length of the String.
3409
*
3410
* @see java.lang.CharSequence#subSequence(int, int)
3411
*
3412
* @since 1.4
3413
*/
3414
public CharSequence subSequence(int start, int end) {
3415
return substring(start, end);
3416
}
3417
3418
/**
3419
* @param data
3420
* the byte array to convert to a String
3421
* @param start
3422
* the starting offset in the byte array
3423
* @param length
3424
* the number of bytes to convert
3425
*
3426
* @since 1.5
3427
*/
3428
public String(int[] data, int start, int length) {
3429
if (start >= 0 && 0 <= length && length <= data.length - start) {
3430
if (COMPACT_STRINGS) {
3431
byte[] bytes = StringLatin1.toBytes(data, start, length);
3432
3433
if (bytes != null) {
3434
value = bytes;
3435
coder = LATIN1;
3436
} else {
3437
bytes = StringUTF16.toBytes(data, start, length);
3438
3439
value = bytes;
3440
coder = UTF16;
3441
3442
initCompressionFlag();
3443
}
3444
} else {
3445
byte[] bytes = StringUTF16.toBytes(data, start, length);
3446
3447
value = bytes;
3448
coder = UTF16;
3449
}
3450
} else {
3451
throw new StringIndexOutOfBoundsException();
3452
}
3453
}
3454
3455
/**
3456
* Creates a string from the contents of a StringBuilder.
3457
*
3458
* @param builder
3459
* the StringBuilder
3460
*
3461
* @since 1.5
3462
*/
3463
public String(StringBuilder builder) {
3464
this(builder.toString());
3465
}
3466
3467
/**
3468
* Returns the Unicode character at the given point.
3469
*
3470
* @param index
3471
* the character index
3472
* @return the Unicode character value at the index
3473
*
3474
* @since 1.5
3475
*/
3476
public int codePointAt(int index) {
3477
int len = lengthInternal();
3478
3479
if (index >= 0 && index < len) {
3480
// Check if the String is compressed
3481
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
3482
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
3483
} else {
3484
char high = charAtInternal(index);
3485
3486
if ((index < (len - 1)) && Character.isHighSurrogate(high)) {
3487
char low = charAtInternal(index + 1);
3488
3489
if (Character.isLowSurrogate(low)) {
3490
return Character.toCodePoint(high, low);
3491
}
3492
}
3493
3494
return high;
3495
}
3496
} else {
3497
throw new StringIndexOutOfBoundsException(index);
3498
}
3499
}
3500
3501
/**
3502
* Returns the Unicode character before the given point.
3503
*
3504
* @param index
3505
* the character index
3506
* @return the Unicode character value before the index
3507
*
3508
* @since 1.5
3509
*/
3510
public int codePointBefore(int index) {
3511
int len = lengthInternal();
3512
3513
if (index > 0 && index <= len) {
3514
// Check if the String is compressed
3515
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
3516
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));
3517
} else {
3518
char low = charAtInternal(index - 1);
3519
3520
if ((index > 1) && Character.isLowSurrogate(low)) {
3521
char high = charAtInternal(index - 2);
3522
3523
if (Character.isHighSurrogate(high)) {
3524
return Character.toCodePoint(high, low);
3525
}
3526
}
3527
3528
return low;
3529
}
3530
} else {
3531
throw new StringIndexOutOfBoundsException(index);
3532
}
3533
}
3534
3535
/**
3536
* Returns the total Unicode values in the specified range.
3537
*
3538
* @param start
3539
* first index
3540
* @param end
3541
* last index
3542
* @return the total Unicode values
3543
*
3544
* @since 1.5
3545
*/
3546
public int codePointCount(int start, int end) {
3547
int len = lengthInternal();
3548
3549
if (start >= 0 && start <= end && end <= len) {
3550
// Check if the String is compressed
3551
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
3552
return end - start;
3553
} else {
3554
int count = 0;
3555
3556
for (int i = start; i < end; ++i) {
3557
if ((i < (end - 1))
3558
&& Character.isHighSurrogate(charAtInternal(i))
3559
&& Character.isLowSurrogate(charAtInternal(i + 1))) {
3560
++i;
3561
}
3562
3563
++count;
3564
}
3565
3566
return count;
3567
}
3568
} else {
3569
throw new IndexOutOfBoundsException();
3570
}
3571
}
3572
3573
/**
3574
* Returns the index of the code point that was offset by codePointCount.
3575
*
3576
* @param start
3577
* the position to offset
3578
* @param codePointCount
3579
* the code point count
3580
* @return the offset index
3581
*
3582
* @since 1.5
3583
*/
3584
public int offsetByCodePoints(int start, int codePointCount) {
3585
int len = lengthInternal();
3586
3587
if (start >= 0 && start <= len) {
3588
// Check if the String is compressed
3589
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
3590
int index = start + codePointCount;
3591
3592
if (index > len) {
3593
throw new IndexOutOfBoundsException();
3594
} else {
3595
return index;
3596
}
3597
} else {
3598
int index = start;
3599
3600
if (codePointCount == 0) {
3601
return start;
3602
} else if (codePointCount > 0) {
3603
for (int i = 0; i < codePointCount; ++i) {
3604
if (index == len) {
3605
throw new IndexOutOfBoundsException();
3606
}
3607
3608
if ((index < (len - 1))
3609
&& Character.isHighSurrogate(charAtInternal(index))
3610
&& Character.isLowSurrogate(charAtInternal(index + 1))) {
3611
index++;
3612
}
3613
3614
index++;
3615
}
3616
} else {
3617
for (int i = codePointCount; i < 0; ++i) {
3618
if (index < 1) {
3619
throw new IndexOutOfBoundsException();
3620
}
3621
3622
if ((index > 1)
3623
&& Character.isLowSurrogate(charAtInternal(index - 1))
3624
&& Character.isHighSurrogate(charAtInternal(index - 2))) {
3625
index--;
3626
}
3627
3628
index--;
3629
}
3630
}
3631
3632
return index;
3633
}
3634
} else {
3635
throw new IndexOutOfBoundsException();
3636
}
3637
}
3638
3639
/**
3640
* Compares the content of the character sequence to this String
3641
*
3642
* @param sequence
3643
* the character sequence
3644
* @return {@code true} if the content of this String is equal to the character sequence, {@code false} otherwise.
3645
*
3646
* @since 1.5
3647
*/
3648
public boolean contentEquals(CharSequence sequence) {
3649
int len = lengthInternal();
3650
3651
if (len != sequence.length()) {
3652
return false;
3653
}
3654
3655
for (int i = 0; i < len; ++i) {
3656
if (charAtInternal(i) != sequence.charAt(i)) {
3657
return false;
3658
}
3659
}
3660
3661
return true;
3662
}
3663
3664
/**
3665
* @param sequence
3666
* the sequence to compare to
3667
* @return {@code true} if this String contains the sequence, {@code false} otherwise.
3668
*
3669
* @since 1.5
3670
*/
3671
public boolean contains(CharSequence sequence) {
3672
int len = lengthInternal();
3673
3674
int sequencelen = sequence.length();
3675
3676
if (sequencelen > len) {
3677
return false;
3678
}
3679
3680
int start = 0;
3681
3682
if (sequencelen > 0) {
3683
if (sequencelen + start > len) {
3684
return false;
3685
}
3686
3687
char charAt0 = sequence.charAt(0);
3688
3689
while (true) {
3690
int i = indexOf(charAt0, start);
3691
3692
if (i == -1 || sequencelen + i > len) {
3693
return false;
3694
}
3695
3696
int o1 = i;
3697
int o2 = 0;
3698
3699
while (++o2 < sequencelen && charAtInternal(++o1) == sequence.charAt(o2))
3700
;
3701
3702
if (o2 == sequencelen) {
3703
return true;
3704
}
3705
3706
start = i + 1;
3707
}
3708
} else {
3709
return true;
3710
}
3711
}
3712
3713
/**
3714
* @param sequence1
3715
* the old character sequence
3716
* @param sequence2
3717
* the new character sequence
3718
* @return the new String
3719
*
3720
* @since 1.5
3721
*/
3722
public String replace(CharSequence sequence1, CharSequence sequence2) {
3723
if (sequence2 == null) {
3724
throw new NullPointerException();
3725
}
3726
3727
int len = lengthInternal();
3728
3729
int sequence1len = sequence1.length();
3730
3731
if (sequence1len == 0) {
3732
int sequence2len = sequence2.length();
3733
3734
if ((sequence2len != 0) && (len >= ((Integer.MAX_VALUE - len) / sequence2len))) {
3735
/*[MSG "K0D01", "Array capacity exceeded"]*/
3736
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
3737
}
3738
3739
StringBuilder builder = new StringBuilder(len + ((len + 1) * sequence2len));
3740
3741
builder.append(sequence2);
3742
3743
for (int i = 0; i < len; ++i) {
3744
builder.append(charAt(i)).append(sequence2);
3745
}
3746
3747
return builder.toString();
3748
} else {
3749
StringBuilder builder = new StringBuilder();
3750
3751
int start = 0;
3752
int copyStart = 0;
3753
3754
char charAt0 = sequence1.charAt(0);
3755
3756
while (start < len) {
3757
int firstIndex = indexOf(charAt0, start);
3758
3759
if (firstIndex == -1) {
3760
break;
3761
}
3762
3763
boolean found = true;
3764
3765
if (sequence1len > 1) {
3766
if (sequence1len > len - firstIndex) {
3767
/* the tail of this string is too short to find sequence1 */
3768
break;
3769
}
3770
3771
for (int i = 1; i < sequence1len; i++) {
3772
if (charAt(firstIndex + i) != sequence1.charAt(i)) {
3773
found = false;
3774
break;
3775
}
3776
}
3777
}
3778
3779
if (found) {
3780
builder.append(substring(copyStart, firstIndex)).append(sequence2);
3781
3782
copyStart = start = firstIndex + sequence1len;
3783
} else {
3784
start = firstIndex + 1;
3785
}
3786
}
3787
3788
if (builder.length() == 0 && copyStart == 0) {
3789
return this;
3790
}
3791
3792
builder.append(substring(copyStart));
3793
3794
return builder.toString();
3795
}
3796
}
3797
3798
/**
3799
* Format the receiver using the specified format and args.
3800
*
3801
* @param format
3802
* the format to use
3803
* @param args
3804
* the format arguments to use
3805
*
3806
* @return the formatted result
3807
*
3808
* @see java.util.Formatter#format(String, Object...)
3809
*/
3810
public static String format(String format, Object... args) {
3811
return new Formatter().format(format, args).toString();
3812
}
3813
3814
/**
3815
* Format the receiver using the specified local, format and args.
3816
*
3817
* @param locale
3818
* the locale used to create the Formatter, may be null
3819
* @param format
3820
* the format to use
3821
* @param args
3822
* the format arguments to use
3823
*
3824
* @return the formatted result
3825
*
3826
* @see java.util.Formatter#format(String, Object...)
3827
*/
3828
public static String format(Locale locale, String format, Object... args) {
3829
return new Formatter(locale).format(format, args).toString();
3830
}
3831
3832
private static final java.io.ObjectStreamField[] serialPersistentFields = {};
3833
3834
/**
3835
* Answers if this String has no characters, a length of zero.
3836
*
3837
* @return true if this String has no characters, false otherwise
3838
*
3839
* @since 1.6
3840
*
3841
* @see #length
3842
*/
3843
public boolean isEmpty() {
3844
return lengthInternal() == 0;
3845
}
3846
3847
/**
3848
* Converts the byte array to a String using the specified Charset.
3849
*
3850
* @param data
3851
* the byte array to convert to a String
3852
* @param charset
3853
* the Charset to use
3854
*
3855
* @throws NullPointerException
3856
* when data is null
3857
*
3858
* @since 1.6
3859
*
3860
* @see #String(byte[], int, int, Charset)
3861
* @see #getBytes(Charset)
3862
*/
3863
public String(byte[] data, Charset charset) {
3864
this(data, 0, data.length, charset);
3865
}
3866
3867
/**
3868
* Converts the byte array to a String using the specified Charset.
3869
*
3870
* @param data
3871
* the byte array to convert to a String
3872
* @param start
3873
* the starting offset in the byte array
3874
* @param length
3875
* the number of bytes to convert
3876
* @param charset
3877
* the Charset to use
3878
*
3879
* @throws IndexOutOfBoundsException
3880
* when {@code length < 0, start < 0} or {@code start + length > data.length}
3881
* @throws NullPointerException
3882
* when data is null
3883
*
3884
* @since 1.6
3885
*
3886
* @see #String(byte[], Charset)
3887
* @see #getBytes(Charset)
3888
*/
3889
public String(byte[] data, int start, int length, Charset charset) {
3890
if (charset == null) {
3891
throw new NullPointerException();
3892
}
3893
3894
if (start >= 0 && 0 <= length && length <= data.length - start) {
3895
StringCoding.Result scResult = StringCoding.decode(charset, data, start, length);
3896
3897
value = scResult.value;
3898
coder = scResult.coder;
3899
3900
if (COMPACT_STRINGS) {
3901
initCompressionFlag();
3902
}
3903
} else {
3904
throw new StringIndexOutOfBoundsException();
3905
}
3906
}
3907
3908
/**
3909
* Converts this String to a byte encoding using the specified Charset.
3910
*
3911
* @param charset
3912
* the Charset to use
3913
* @return the byte array encoding of this String
3914
*
3915
* @since 1.6
3916
*/
3917
public byte[] getBytes(Charset charset) {
3918
return StringCoding.encode(charset, coder, value);
3919
}
3920
3921
/**
3922
* 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.
3923
*
3924
* @param delimiter
3925
* Used as joiner to put elements together
3926
* @param elements
3927
* Elements to be joined
3928
* @return string of joined elements by delimiter
3929
* @throws NullPointerException
3930
* if one of the arguments is null
3931
*
3932
*/
3933
public static String join(CharSequence delimiter, CharSequence... elements) {
3934
StringJoiner stringJoiner = new StringJoiner(delimiter);
3935
3936
for (CharSequence element : elements) {
3937
stringJoiner.add(element);
3938
}
3939
3940
return stringJoiner.toString();
3941
}
3942
3943
/**
3944
* 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.
3945
*
3946
* @param delimiter
3947
* Used as joiner to put elements together
3948
* @param elements
3949
* Elements to be joined
3950
* @return string of joined elements by delimiter
3951
* @throws NullPointerException
3952
* if one of the arguments is null
3953
*
3954
*/
3955
public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {
3956
StringJoiner stringJoiner = new StringJoiner(delimiter);
3957
3958
Iterator<? extends CharSequence> elementsIterator = elements.iterator();
3959
3960
while (elementsIterator.hasNext()) {
3961
stringJoiner.add(elementsIterator.next());
3962
}
3963
3964
return stringJoiner.toString();
3965
}
3966
3967
static void checkBoundsBeginEnd(int begin, int end, int length) {
3968
if ((begin >= 0) && (begin <= end) && (end <= length)) {
3969
return;
3970
}
3971
throw newStringIndexOutOfBoundsException(begin, end, length);
3972
}
3973
3974
@Override
3975
public IntStream chars() {
3976
Spliterator.OfInt spliterator;
3977
3978
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
3979
spliterator = new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE);
3980
} else {
3981
spliterator = new StringUTF16.CharsSpliterator(value, Spliterator.IMMUTABLE);
3982
}
3983
3984
return StreamSupport.intStream(spliterator, false);
3985
}
3986
3987
@Override
3988
public IntStream codePoints() {
3989
Spliterator.OfInt spliterator;
3990
3991
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
3992
spliterator = new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE);
3993
} else {
3994
spliterator = new StringUTF16.CodePointsSpliterator(value, Spliterator.IMMUTABLE);
3995
}
3996
3997
return StreamSupport.intStream(spliterator, false);
3998
}
3999
4000
/*
4001
* Internal API, assuming no modification to the byte array returned.
4002
*/
4003
byte[] value() {
4004
return value;
4005
}
4006
4007
/*[IF JAVA_SPEC_VERSION >= 11]*/
4008
/**
4009
* Returns a string object containing the character (Unicode code point)
4010
* specified.
4011
*
4012
* @param codePoint
4013
* a Unicode code point.
4014
* @return a string containing the character (Unicode code point) supplied.
4015
* @throws IllegalArgumentException
4016
* if the codePoint is not a valid Unicode code point.
4017
* @since 11
4018
*/
4019
static String valueOfCodePoint(int codePoint) {
4020
String string;
4021
if ((codePoint < Character.MIN_CODE_POINT) || (codePoint > Character.MAX_CODE_POINT)) {
4022
/*[MSG "K0800", "Invalid Unicode code point - {0}"]*/
4023
throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0800", Integer.toString(codePoint))); //$NON-NLS-1$
4024
} else if (codePoint <= 255) {
4025
if (COMPACT_STRINGS) {
4026
string = new String(compressedAsciiTable[codePoint], LATIN1);
4027
} else {
4028
string = new String(decompressedAsciiTable[codePoint], UTF16);
4029
}
4030
} else if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
4031
byte[] buffer = new byte[2];
4032
helpers.putCharInArrayByIndex(buffer, 0, (char) codePoint);
4033
string = new String(buffer, UTF16);
4034
} else {
4035
byte[] buffer = new byte[4];
4036
helpers.putCharInArrayByIndex(buffer, 0, Character.highSurrogate(codePoint));
4037
helpers.putCharInArrayByIndex(buffer, 1, Character.lowSurrogate(codePoint));
4038
string = new String(buffer, UTF16);
4039
}
4040
return string;
4041
}
4042
4043
/**
4044
* Returns a string whose value is the concatenation of this string repeated
4045
* count times.
4046
*
4047
* @param count
4048
* a positive integer indicating the number of times to be repeated
4049
* @return a string whose value is the concatenation of this string repeated count times
4050
* @throws IllegalArgumentException
4051
* if the count is negative
4052
* @since 11
4053
*/
4054
public String repeat(int count) {
4055
if (count < 0) {
4056
throw new IllegalArgumentException();
4057
} else if (count == 0 || isEmpty()) {
4058
return ""; //$NON-NLS-1$
4059
} else if (count == 1) {
4060
return this;
4061
}
4062
4063
int length = lengthInternal();
4064
if (length > Integer.MAX_VALUE / count) {
4065
/*[MSG "K0D01", "Array capacity exceeded"]*/
4066
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
4067
}
4068
int repeatlen = length * count;
4069
4070
if (COMPACT_STRINGS && (null == compressionFlag || coder == LATIN1)) {
4071
byte[] buffer = new byte[repeatlen];
4072
4073
for (int i = 0; i < count; i++) {
4074
compressedArrayCopy(value, 0, buffer, i * length, length);
4075
}
4076
4077
return new String(buffer, LATIN1);
4078
} else {
4079
byte[] buffer = StringUTF16.newBytesFor(repeatlen);
4080
4081
for (int i = 0; i < count; i++) {
4082
decompressedArrayCopy(value, 0, buffer, i * length, length);
4083
}
4084
4085
return new String(buffer, UTF16);
4086
}
4087
}
4088
/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
4089
4090
/*[ELSE] Sidecar19-SE*/
4091
// DO NOT CHANGE OR MOVE THIS LINE
4092
// IT MUST BE THE FIRST THING IN THE INITIALIZATION
4093
private static final long serialVersionUID = -6849794470754667710L;
4094
4095
/**
4096
* Determines whether String compression is enabled.
4097
*/
4098
static final boolean COMPACT_STRINGS = com.ibm.oti.vm.VM.J9_STRING_COMPRESSION_ENABLED;
4099
4100
/**
4101
* CaseInsensitiveComparator compares Strings ignoring the case of the characters.
4102
*/
4103
private static final class CaseInsensitiveComparator implements Comparator<String>, Serializable {
4104
static final long serialVersionUID = 8575799808933029326L;
4105
4106
/**
4107
* Compare the two objects to determine the relative ordering.
4108
*
4109
* @param o1
4110
* an Object to compare
4111
* @param o2
4112
* an Object to compare
4113
* @return an int < 0 if object1 is less than object2, 0 if they are equal, and > 0 if object1 is greater
4114
*
4115
* @exception ClassCastException
4116
* when objects are not the correct type
4117
*/
4118
public int compare(String o1, String o2) {
4119
return o1.compareToIgnoreCase(o2);
4120
}
4121
};
4122
4123
/**
4124
* A Comparator which compares Strings ignoring the case of the characters.
4125
*/
4126
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
4127
4128
// Used to represent the value of an empty String
4129
private static final char[] emptyValue = new char[0];
4130
4131
// Used to extract the value of a single ASCII character String by the integral value of the respective character as
4132
// an index into this table
4133
private static final char[][] compressedAsciiTable;
4134
4135
private static final char[][] decompressedAsciiTable;
4136
4137
// Used to access compression related helper methods
4138
private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();
4139
4140
static class StringCompressionFlag implements Serializable {
4141
private static final long serialVersionUID = 1346155847239551492L;
4142
}
4143
4144
// Singleton used by all String instances to indicate a non-compressed string has been
4145
// allocated. JIT attempts to fold away the null check involving this static if the
4146
// StringCompressionFlag class has not been initialized and patches the code to bring back
4147
// the null check if a non-compressed String is constructed.
4148
private static StringCompressionFlag compressionFlag;
4149
4150
// Represents the bit in count field to test for whether this String backing array is not compressed
4151
// under String compression mode. This bit is not used when String compression is disabled.
4152
private static final int uncompressedBit = 0x80000000;
4153
4154
private static String[] stringArray;
4155
private static final int stringArraySize = 10;
4156
4157
private static class UnsafeHelpers {
4158
public final static long valueFieldOffset = getValueFieldOffset();
4159
4160
static long getValueFieldOffset() {
4161
try {
4162
return Unsafe.getUnsafe().objectFieldOffset(String.class.getDeclaredField("value")); //$NON-NLS-1$
4163
} catch (NoSuchFieldException e) {
4164
throw new RuntimeException(e);
4165
}
4166
}
4167
}
4168
4169
/**
4170
* This is a System property to enable sharing of the underlying value array in {@link #String.substring(int)} and
4171
* {@link #String.substring(int, int)} if the offset is zero.
4172
*/
4173
static boolean enableSharingInSubstringWhenOffsetIsZero;
4174
4175
private final char[] value;
4176
private final int count;
4177
private int hash;
4178
4179
static {
4180
stringArray = new String[stringArraySize];
4181
4182
compressedAsciiTable = new char[256][];
4183
4184
for (int i = 0; i < compressedAsciiTable.length; ++i) {
4185
char[] asciiValue = new char[1];
4186
4187
helpers.putByteInArrayByIndex(asciiValue, 0, (byte) i);
4188
4189
compressedAsciiTable[i] = asciiValue;
4190
}
4191
4192
decompressedAsciiTable = new char[256][];
4193
4194
for (int i = 0; i < decompressedAsciiTable.length; ++i) {
4195
char[] asciiValue = new char[1];
4196
4197
helpers.putCharInArrayByIndex(asciiValue, 0, (char) i);
4198
4199
decompressedAsciiTable[i] = asciiValue;
4200
}
4201
}
4202
4203
static void initCompressionFlag() {
4204
if (compressionFlag == null) {
4205
compressionFlag = new StringCompressionFlag();
4206
}
4207
}
4208
4209
/**
4210
* Determines whether the input character array can be encoded as a compact
4211
* Latin1 string.
4212
*
4213
* <p>This API implicitly assumes the following:
4214
* <blockquote><pre>
4215
* - {@code length >= 0}
4216
* - {@code start >= 0}
4217
* - {@code start + length <= data.length}
4218
* <blockquote><pre>
4219
*
4220
* @param c the array of characters to check
4221
* @param start the starting offset in the character array
4222
* @param length the number of characters to check starting at {@code start}
4223
* @return {@code true} if the input character array can be encoded
4224
* using the Latin1 encoding; {@code false} otherwise
4225
*/
4226
static boolean canEncodeAsLatin1(char[] c, int start, int length) {
4227
for (int i = start; i < start + length; ++i) {
4228
if (c[i] > 255) {
4229
return false;
4230
}
4231
}
4232
4233
return true;
4234
}
4235
4236
static void compress(byte[] array1, int start1, byte[] array2, int start2, int length) {
4237
for (int i = 0; i < length; ++i) {
4238
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
4239
}
4240
}
4241
4242
static void compress(char[] array1, int start1, byte[] array2, int start2, int length) {
4243
for (int i = 0; i < length; ++i) {
4244
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
4245
}
4246
}
4247
4248
static void compress(byte[] array1, int start1, char[] array2, int start2, int length) {
4249
for (int i = 0; i < length; ++i) {
4250
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
4251
}
4252
}
4253
4254
static void compress(char[] array1, int start1, char[] array2, int start2, int length) {
4255
for (int i = 0; i < length; ++i) {
4256
helpers.putByteInArrayByIndex(array2, start2 + i, (byte) helpers.getCharFromArrayByIndex(array1, start1 + i));
4257
}
4258
}
4259
4260
static void decompress(byte[] array1, int start1, byte[] array2, int start2, int length) {
4261
for (int i = 0; i < length; ++i) {
4262
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
4263
}
4264
}
4265
4266
static void decompress(char[] array1, int start1, byte[] array2, int start2, int length) {
4267
for (int i = 0; i < length; ++i) {
4268
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
4269
}
4270
}
4271
4272
static void decompress(byte[] array1, int start1, char[] array2, int start2, int length) {
4273
for (int i = 0; i < length; ++i) {
4274
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
4275
}
4276
}
4277
4278
static void decompress(char[] array1, int start1, char[] array2, int start2, int length) {
4279
for (int i = 0; i < length; ++i) {
4280
helpers.putCharInArrayByIndex(array2, start2 + i, helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(array1, start1 + i)));
4281
}
4282
}
4283
4284
static void compressedArrayCopy(byte[] array1, int start1, byte[] array2, int start2, int length) {
4285
if (array1 == array2 && start1 < start2) {
4286
for (int i = length - 1; i >= 0; --i) {
4287
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
4288
}
4289
} else {
4290
for (int i = 0; i < length; ++i) {
4291
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
4292
}
4293
}
4294
}
4295
4296
static void compressedArrayCopy(byte[] array1, int start1, char[] array2, int start2, int length) {
4297
for (int i = 0; i < length; ++i) {
4298
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
4299
}
4300
}
4301
4302
static void compressedArrayCopy(char[] array1, int start1, byte[] array2, int start2, int length) {
4303
for (int i = 0; i < length; ++i) {
4304
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
4305
}
4306
}
4307
4308
static void compressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {
4309
if (array1 == array2 && start1 < start2) {
4310
for (int i = length - 1; i >= 0; --i) {
4311
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
4312
}
4313
} else {
4314
for (int i = 0; i < length; ++i) {
4315
helpers.putByteInArrayByIndex(array2, start2 + i, helpers.getByteFromArrayByIndex(array1, start1 + i));
4316
}
4317
}
4318
}
4319
4320
static void decompressedArrayCopy(char[] array1, int start1, char[] array2, int start2, int length) {
4321
System.arraycopy(array1, start1, array2, start2, length);
4322
}
4323
4324
boolean isCompressed() {
4325
// Check if the String is compressed
4326
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
4327
return true;
4328
} else {
4329
return false;
4330
}
4331
}
4332
4333
/**
4334
* Answers an empty string.
4335
*/
4336
public String() {
4337
value = emptyValue;
4338
count = 0;
4339
}
4340
4341
/**
4342
* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not
4343
* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.
4344
*
4345
* @param data
4346
* the byte array to convert to a String
4347
*
4348
* @throws NullPointerException
4349
* when data is null
4350
*
4351
* @see #getBytes()
4352
* @see #getBytes(int, int, byte[], int)
4353
* @see #getBytes(String)
4354
* @see #valueOf(boolean)
4355
* @see #valueOf(char)
4356
* @see #valueOf(char[])
4357
* @see #valueOf(char[], int, int)
4358
* @see #valueOf(double)
4359
* @see #valueOf(float)
4360
* @see #valueOf(int)
4361
* @see #valueOf(long)
4362
* @see #valueOf(Object)
4363
*/
4364
public String(byte[] data) {
4365
this(data, 0, data.length);
4366
}
4367
4368
/**
4369
* Converts the byte array to a String, setting the high byte of every character to the specified value.
4370
*
4371
* @param data
4372
* the byte array to convert to a String
4373
* @param high
4374
* the high byte to use
4375
*
4376
* @throws NullPointerException
4377
* when data is null
4378
*
4379
* @deprecated Use String(byte[]) or String(byte[], String) instead
4380
*/
4381
@Deprecated
4382
public String(byte[] data, int high) {
4383
this(data, high, 0, data.length);
4384
}
4385
4386
/**
4387
* Converts the byte array to a String using the default encoding as specified by the file.encoding system property. If the system property is not
4388
* defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.
4389
*
4390
* @param data
4391
* the byte array to convert to a String
4392
* @param start
4393
* the starting offset in the byte array
4394
* @param length
4395
* the number of bytes to convert
4396
*
4397
* @throws IndexOutOfBoundsException
4398
* when {@code length < 0, start < 0} or {@code start + length > data.length}
4399
* @throws NullPointerException
4400
* when data is null
4401
*
4402
* @see #getBytes()
4403
* @see #getBytes(int, int, byte[], int)
4404
* @see #getBytes(String)
4405
* @see #valueOf(boolean)
4406
* @see #valueOf(char)
4407
* @see #valueOf(char[])
4408
* @see #valueOf(char[], int, int)
4409
* @see #valueOf(double)
4410
* @see #valueOf(float)
4411
* @see #valueOf(int)
4412
* @see #valueOf(long)
4413
* @see #valueOf(Object)
4414
*/
4415
public String(byte[] data, int start, int length) {
4416
data.getClass(); // Implicit null check
4417
4418
if (start >= 0 && 0 <= length && length <= data.length - start) {
4419
char[] buffer = StringCoding.decode(data, start, length);
4420
4421
if (COMPACT_STRINGS) {
4422
if (canEncodeAsLatin1(buffer, 0, buffer.length)) {
4423
value = new char[(buffer.length + 1) >>> 1];
4424
count = buffer.length;
4425
4426
compress(buffer, 0, value, 0, buffer.length);
4427
} else {
4428
value = buffer;
4429
count = buffer.length | uncompressedBit;
4430
4431
initCompressionFlag();
4432
}
4433
} else {
4434
value = buffer;
4435
count = buffer.length;
4436
}
4437
} else {
4438
throw new StringIndexOutOfBoundsException();
4439
}
4440
}
4441
4442
/**
4443
* Converts the byte array to a String, setting the high byte of every character to the specified value.
4444
*
4445
* @param data
4446
* the byte array to convert to a String
4447
* @param high
4448
* the high byte to use
4449
* @param start
4450
* the starting offset in the byte array
4451
* @param length
4452
* the number of bytes to convert
4453
*
4454
* @throws IndexOutOfBoundsException
4455
* when {@code length < 0, start < 0} or {@code start + length > data.length}
4456
* @throws NullPointerException
4457
* when data is null
4458
*
4459
* @deprecated Use String(byte[], int, int) instead
4460
*/
4461
@Deprecated
4462
public String(byte[] data, int high, int start, int length) {
4463
data.getClass(); // Implicit null check
4464
4465
if (start >= 0 && 0 <= length && length <= data.length - start) {
4466
if (COMPACT_STRINGS) {
4467
if (high == 0) {
4468
value = new char[(length + 1) >>> 1];
4469
count = length;
4470
4471
compressedArrayCopy(data, start, value, 0, length);
4472
} else {
4473
value = new char[length];
4474
count = length | uncompressedBit;
4475
4476
high <<= 8;
4477
4478
for (int i = 0; i < length; ++i) {
4479
value[i] = (char) (high + (data[start++] & 0xff));
4480
}
4481
4482
initCompressionFlag();
4483
}
4484
4485
} else {
4486
value = new char[length];
4487
count = length;
4488
4489
high <<= 8;
4490
4491
for (int i = 0; i < length; ++i) {
4492
value[i] = (char) (high + (data[start++] & 0xff));
4493
}
4494
}
4495
} else {
4496
throw new StringIndexOutOfBoundsException();
4497
}
4498
}
4499
4500
/**
4501
* Converts the byte array to a String using the specified encoding.
4502
*
4503
* @param data
4504
* the byte array to convert to a String
4505
* @param start
4506
* the starting offset in the byte array
4507
* @param length
4508
* the number of bytes to convert
4509
* @param encoding
4510
* the encoding
4511
*
4512
* @throws IndexOutOfBoundsException
4513
* when {@code length < 0, start < 0} or {@code start + length > data.length}
4514
* @throws UnsupportedEncodingException
4515
* when encoding is not supported
4516
* @throws NullPointerException
4517
* when data is null
4518
*
4519
* @see #getBytes()
4520
* @see #getBytes(int, int, byte[], int)
4521
* @see #getBytes(String)
4522
* @see #valueOf(boolean)
4523
* @see #valueOf(char)
4524
* @see #valueOf(char[])
4525
* @see #valueOf(char[], int, int)
4526
* @see #valueOf(double)
4527
* @see #valueOf(float)
4528
* @see #valueOf(int)
4529
* @see #valueOf(long)
4530
* @see #valueOf(Object)
4531
* @see UnsupportedEncodingException
4532
*/
4533
public String(byte[] data, int start, int length, final String encoding) throws UnsupportedEncodingException {
4534
encoding.getClass(); // Implicit null check
4535
4536
data.getClass(); // Implicit null check
4537
4538
if (start >= 0 && 0 <= length && length <= data.length - start) {
4539
char[] buffer = StringCoding.decode(encoding, data, start, length);
4540
4541
if (COMPACT_STRINGS) {
4542
if (canEncodeAsLatin1(buffer, 0, buffer.length)) {
4543
value = new char[(buffer.length + 1) >>> 1];
4544
count = buffer.length;
4545
4546
compress(buffer, 0, value, 0, buffer.length);
4547
} else {
4548
value = buffer;
4549
count = buffer.length | uncompressedBit;
4550
4551
initCompressionFlag();
4552
}
4553
} else {
4554
value = buffer;
4555
count = buffer.length;
4556
}
4557
} else {
4558
throw new StringIndexOutOfBoundsException();
4559
}
4560
}
4561
4562
/**
4563
* Converts the byte array to a String using the specified encoding.
4564
*
4565
* @param data
4566
* the byte array to convert to a String
4567
* @param encoding
4568
* the encoding
4569
*
4570
* @throws UnsupportedEncodingException
4571
* when encoding is not supported
4572
* @throws NullPointerException
4573
* when data is null
4574
*
4575
* @see #getBytes()
4576
* @see #getBytes(int, int, byte[], int)
4577
* @see #getBytes(String)
4578
* @see #valueOf(boolean)
4579
* @see #valueOf(char)
4580
* @see #valueOf(char[])
4581
* @see #valueOf(char[], int, int)
4582
* @see #valueOf(double)
4583
* @see #valueOf(float)
4584
* @see #valueOf(int)
4585
* @see #valueOf(long)
4586
* @see #valueOf(Object)
4587
* @see UnsupportedEncodingException
4588
*/
4589
public String(byte[] data, String encoding) throws UnsupportedEncodingException {
4590
this(data, 0, data.length, encoding);
4591
}
4592
4593
private String(String s, char c) {
4594
if (s == null) {
4595
s = "null"; //$NON-NLS-1$
4596
}
4597
4598
int slen = s.lengthInternal();
4599
4600
int concatlen = slen + 1;
4601
if (concatlen < 0) {
4602
/*[MSG "K0D01", "Array capacity exceeded"]*/
4603
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
4604
}
4605
4606
if (COMPACT_STRINGS) {
4607
// Check if the String is compressed
4608
if ((null == compressionFlag || s.count >= 0) && c <= 255) {
4609
value = new char[(concatlen + 1) >>> 1];
4610
count = concatlen;
4611
4612
compressedArrayCopy(s.value, 0, value, 0, slen);
4613
4614
helpers.putByteInArrayByIndex(value, slen, (byte) c);
4615
} else {
4616
value = new char[concatlen];
4617
count = (concatlen) | uncompressedBit;
4618
4619
// Check if the String is compressed
4620
if (COMPACT_STRINGS && s.count >= 0) {
4621
decompress(s.value, 0, value, 0, slen);
4622
} else {
4623
decompressedArrayCopy(s.value, 0, value, 0, slen);
4624
}
4625
value[slen] = c;
4626
4627
initCompressionFlag();
4628
}
4629
} else {
4630
value = new char[concatlen];
4631
count = concatlen;
4632
4633
System.arraycopy(s.value, 0, value, 0, slen);
4634
4635
value[slen] = c;
4636
}
4637
}
4638
4639
/**
4640
* Initializes this String to contain the characters in the specified character array. Modifying the character array after creating the String has
4641
* no effect on the String.
4642
*
4643
* @param data
4644
* the array of characters
4645
*
4646
* @throws NullPointerException
4647
* when data is null
4648
*/
4649
public String(char[] data) {
4650
this(data, 0, data.length);
4651
}
4652
4653
/**
4654
* Initializes this String to use the specified character array. The character array should not be modified after the String is created.
4655
*
4656
* @param data
4657
* a non-null array of characters
4658
*/
4659
String(char[] data, boolean ignore) {
4660
if (COMPACT_STRINGS) {
4661
if (canEncodeAsLatin1(data, 0, data.length)) {
4662
value = new char[(data.length + 1) >>> 1];
4663
count = data.length;
4664
4665
compress(data, 0, value, 0, data.length);
4666
} else {
4667
value = new char[data.length];
4668
count = data.length | uncompressedBit;
4669
4670
System.arraycopy(data, 0, value, 0, data.length);
4671
4672
initCompressionFlag();
4673
}
4674
} else {
4675
value = new char[data.length];
4676
count = data.length;
4677
4678
System.arraycopy(data, 0, value, 0, data.length);
4679
}
4680
}
4681
4682
/**
4683
* Initializes this String to contain the specified characters in the character array. Modifying the character array after creating the String has
4684
* no effect on the String.
4685
*
4686
* @param data
4687
* the array of characters
4688
* @param start
4689
* the starting offset in the character array
4690
* @param length
4691
* the number of characters to use
4692
*
4693
* @throws IndexOutOfBoundsException
4694
* when {@code length < 0, start < 0} or {@code start + length > data.length}
4695
* @throws NullPointerException
4696
* when data is null
4697
*/
4698
public String(char[] data, int start, int length) {
4699
if (start >= 0 && 0 <= length && length <= data.length - start) {
4700
if (COMPACT_STRINGS) {
4701
if (canEncodeAsLatin1(data, start, length)) {
4702
value = new char[(length + 1) >>> 1];
4703
count = length;
4704
4705
compress(data, start, value, 0, length);
4706
} else {
4707
value = new char[length];
4708
count = length | uncompressedBit;
4709
4710
System.arraycopy(data, start, value, 0, length);
4711
4712
initCompressionFlag();
4713
}
4714
} else {
4715
value = new char[length];
4716
count = length;
4717
4718
System.arraycopy(data, start, value, 0, length);
4719
}
4720
} else {
4721
throw new StringIndexOutOfBoundsException();
4722
}
4723
}
4724
4725
String(char[] data, int start, int length, boolean compressed) {
4726
if (COMPACT_STRINGS) {
4727
if (length == 0) {
4728
value = emptyValue;
4729
count = 0;
4730
} else if (length == 1) {
4731
if (compressed) {
4732
char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));
4733
4734
value = compressedAsciiTable[theChar];
4735
count = 1;
4736
4737
hash = theChar;
4738
} else {
4739
4740
char theChar = data[start];
4741
4742
if (theChar <= 255) {
4743
value = decompressedAsciiTable[theChar];
4744
} else {
4745
value = new char[] { theChar };
4746
}
4747
4748
count = 1 | uncompressedBit;
4749
4750
hash = theChar;
4751
4752
initCompressionFlag();
4753
}
4754
} else {
4755
if (compressed) {
4756
if (start == 0) {
4757
value = data;
4758
count = length;
4759
} else {
4760
value = new char[(length + 1) >>> 1];
4761
count = length;
4762
4763
compressedArrayCopy(data, start, value, 0, length);
4764
}
4765
} else {
4766
if (start == 0) {
4767
value = data;
4768
count = length | uncompressedBit;
4769
} else {
4770
value = new char[length];
4771
count = length | uncompressedBit;
4772
4773
System.arraycopy(data, start, value, 0, length);
4774
}
4775
4776
initCompressionFlag();
4777
}
4778
}
4779
} else {
4780
if (length == 0) {
4781
value = emptyValue;
4782
count = 0;
4783
} else if (length == 1 && data[start] <= 255) {
4784
char theChar = data[start];
4785
4786
value = decompressedAsciiTable[theChar];
4787
count = 1;
4788
4789
hash = theChar;
4790
} else {
4791
if (start == 0) {
4792
value = data;
4793
count = length;
4794
} else {
4795
value = new char[length];
4796
count = length;
4797
4798
System.arraycopy(data, start, value, 0, length);
4799
}
4800
}
4801
}
4802
}
4803
4804
String(char[] data, int start, int length, boolean compressed, boolean sharingIsAllowed) {
4805
if (COMPACT_STRINGS) {
4806
if (length == 0) {
4807
value = emptyValue;
4808
count = 0;
4809
} else if (length == 1) {
4810
if (compressed) {
4811
char theChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(data, start));
4812
4813
value = compressedAsciiTable[theChar];
4814
count = 1;
4815
4816
hash = theChar;
4817
} else {
4818
char theChar = data[start];
4819
4820
if (theChar <= 255) {
4821
value = decompressedAsciiTable[theChar];
4822
} else {
4823
value = new char[] { theChar };
4824
}
4825
4826
count = 1 | uncompressedBit;
4827
4828
hash = theChar;
4829
4830
initCompressionFlag();
4831
}
4832
} else {
4833
if (compressed) {
4834
if (start == 0 && sharingIsAllowed) {
4835
value = data;
4836
count = length;
4837
} else {
4838
value = new char[(length + 1) >>> 1];
4839
count = length;
4840
4841
compressedArrayCopy(data, start, value, 0, length);
4842
}
4843
} else {
4844
if (start == 0 && sharingIsAllowed) {
4845
value = data;
4846
count = length | uncompressedBit;
4847
} else {
4848
value = new char[length];
4849
count = length | uncompressedBit;
4850
4851
System.arraycopy(data, start, value, 0, length);
4852
}
4853
4854
initCompressionFlag();
4855
}
4856
}
4857
} else {
4858
if (length == 0) {
4859
value = emptyValue;
4860
count = 0;
4861
} else if (length == 1 && data[start] <= 255) {
4862
char theChar = data[start];
4863
4864
value = decompressedAsciiTable[theChar];
4865
count = 1;
4866
4867
hash = theChar;
4868
} else {
4869
if (start == 0 && sharingIsAllowed) {
4870
value = data;
4871
count = length;
4872
} else {
4873
value = new char[length];
4874
count = length;
4875
4876
System.arraycopy(data, start, value, 0, length);
4877
}
4878
}
4879
}
4880
}
4881
4882
/**
4883
* Creates a string that is a copy of another string
4884
*
4885
* @param string
4886
* the String to copy
4887
*/
4888
public String(String string) {
4889
value = string.value;
4890
count = string.count;
4891
hash = string.hash;
4892
}
4893
4894
/**
4895
* Creates a string from the contents of a StringBuffer.
4896
*
4897
* @param buffer
4898
* the StringBuffer
4899
*/
4900
public String(StringBuffer buffer) {
4901
synchronized (buffer) {
4902
char[] chars = buffer.shareValue();
4903
4904
if (COMPACT_STRINGS) {
4905
if (buffer.isCompressed()) {
4906
value = chars;
4907
count = buffer.length();
4908
} else {
4909
value = chars;
4910
count = buffer.length() | uncompressedBit;
4911
4912
initCompressionFlag();
4913
}
4914
} else {
4915
value = chars;
4916
count = buffer.length();
4917
}
4918
}
4919
}
4920
4921
/*
4922
* Creates a string that is s1 + s2.
4923
*/
4924
private String(String s1, String s2) {
4925
if (s1 == null) {
4926
s1 = "null"; //$NON-NLS-1$
4927
}
4928
4929
if (s2 == null) {
4930
s2 = "null"; //$NON-NLS-1$
4931
}
4932
4933
int s1len = s1.lengthInternal();
4934
int s2len = s2.lengthInternal();
4935
4936
int concatlen = s1len + s2len;
4937
if (concatlen < 0) {
4938
/*[MSG "K0D01", "Array capacity exceeded"]*/
4939
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
4940
}
4941
4942
if (COMPACT_STRINGS) {
4943
if (null == compressionFlag || (s1.count | s2.count) >= 0) {
4944
value = new char[(concatlen + 1) >>> 1];
4945
count = concatlen;
4946
4947
compressedArrayCopy(s1.value, 0, value, 0, s1len);
4948
compressedArrayCopy(s2.value, 0, value, s1len, s2len);
4949
} else {
4950
value = new char[concatlen];
4951
count = concatlen | uncompressedBit;
4952
4953
// Check if the String is compressed
4954
if (s1.count >= 0) {
4955
decompress(s1.value, 0, value, 0, s1len);
4956
} else {
4957
System.arraycopy(s1.value, 0, value, 0, s1len);
4958
}
4959
4960
// Check if the String is compressed
4961
if (s2.count >= 0) {
4962
decompress(s2.value, 0, value, s1len, s2len);
4963
} else {
4964
System.arraycopy(s2.value, 0, value, s1len, s2len);
4965
}
4966
4967
initCompressionFlag();
4968
}
4969
} else {
4970
value = new char[concatlen];
4971
count = concatlen;
4972
4973
System.arraycopy(s1.value, 0, value, 0, s1len);
4974
System.arraycopy(s2.value, 0, value, s1len, s2len);
4975
}
4976
}
4977
4978
/*
4979
* Creates a string that is s1 + s2 + s3.
4980
*/
4981
private String(String s1, String s2, String s3) {
4982
if (s1 == null) {
4983
s1 = "null"; //$NON-NLS-1$
4984
}
4985
4986
if (s2 == null) {
4987
s2 = "null"; //$NON-NLS-1$
4988
}
4989
4990
if (s3 == null) {
4991
s3 = "null"; //$NON-NLS-1$
4992
}
4993
4994
int s1len = s1.lengthInternal();
4995
int s2len = s2.lengthInternal();
4996
int s3len = s3.lengthInternal();
4997
long totalLen = (long) s1len + (long) s2len + (long) s3len;
4998
if (totalLen > Integer.MAX_VALUE) {
4999
/*[MSG "K0D01", "Array capacity exceeded"]*/
5000
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
5001
}
5002
5003
int concatlen = (int) totalLen;
5004
5005
if (COMPACT_STRINGS) {
5006
if (null == compressionFlag || (s1.count | s2.count | s3.count) >= 0) {
5007
value = new char[(concatlen + 1) >>> 1];
5008
count = concatlen;
5009
5010
compressedArrayCopy(s1.value, 0, value, 0, s1len);
5011
compressedArrayCopy(s2.value, 0, value, s1len, s2len);
5012
compressedArrayCopy(s3.value, 0, value, s1len + s2len, s3len);
5013
} else {
5014
value = new char[concatlen];
5015
count = concatlen | uncompressedBit;
5016
5017
// Check if the String is compressed
5018
if (s1.count >= 0) {
5019
decompress(s1.value, 0, value, 0, s1len);
5020
} else {
5021
System.arraycopy(s1.value, 0, value, 0, s1len);
5022
}
5023
5024
// Check if the String is compressed
5025
if (s2.count >= 0) {
5026
decompress(s2.value, 0, value, s1len, s2len);
5027
} else {
5028
System.arraycopy(s2.value, 0, value, s1len, s2len);
5029
}
5030
5031
// Check if the String is compressed
5032
if (s3.count >= 0) {
5033
decompress(s3.value, 0, value, s1len + s2len, s3len);
5034
} else {
5035
System.arraycopy(s3.value, 0, value, (s1len + s2len), s3len);
5036
}
5037
5038
initCompressionFlag();
5039
}
5040
} else {
5041
value = new char[concatlen];
5042
count = concatlen;
5043
5044
System.arraycopy(s1.value, 0, value, 0, s1len);
5045
System.arraycopy(s2.value, 0, value, s1len, s2len);
5046
System.arraycopy(s3.value, 0, value, (s1len + s2len), s3len);
5047
}
5048
}
5049
5050
/*
5051
* Creates a string that is s1 + v1.
5052
*/
5053
private String(String s1, int v1) {
5054
if (s1 == null) {
5055
s1 = "null"; //$NON-NLS-1$
5056
}
5057
5058
// Char length of all the parameters respectively
5059
int s1len = s1.lengthInternal();
5060
int v1len = 1;
5061
5062
int quot;
5063
int i = v1;
5064
while ((i /= 10) != 0)
5065
v1len++;
5066
if (v1 >= 0) {
5067
quot = -v1;
5068
} else {
5069
// Leave room for '-'
5070
v1len++;
5071
quot = v1;
5072
}
5073
5074
// Char length of the final String
5075
int len = s1len + v1len;
5076
if (len < 0) {
5077
/*[MSG "K0D01", "Array capacity exceeded"]*/
5078
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
5079
}
5080
5081
if (COMPACT_STRINGS) {
5082
// Check if the String is compressed
5083
if (null == compressionFlag || s1.count >= 0) {
5084
value = new char[(len + 1) >>> 1];
5085
count = len;
5086
5087
// Copy in v1
5088
int index = len - 1;
5089
5090
do {
5091
int res = quot / 10;
5092
int rem = quot - (res * 10);
5093
5094
quot = res;
5095
5096
// Write the digit into the correct position
5097
helpers.putByteInArrayByIndex(value, index--, (byte) ('0' - rem));
5098
} while (quot != 0);
5099
5100
if (v1 < 0) {
5101
helpers.putByteInArrayByIndex(value, index, (byte) '-');
5102
}
5103
5104
// Copy in s1 contents
5105
compressedArrayCopy(s1.value, 0, value, 0, s1len);
5106
} else {
5107
value = new char[len];
5108
count = len | uncompressedBit;
5109
5110
// Copy in v1
5111
int index = len - 1;
5112
5113
do {
5114
int res = quot / 10;
5115
int rem = quot - (res * 10);
5116
5117
quot = res;
5118
5119
// Write the digit into the correct position
5120
value[index--] = (char) ('0' - rem);
5121
} while (quot != 0);
5122
5123
if (v1 < 0) {
5124
value[index] = '-';
5125
}
5126
5127
// Copy in s1 contents
5128
System.arraycopy(s1.value, 0, value, 0, s1len);
5129
5130
initCompressionFlag();
5131
}
5132
} else {
5133
value = new char[len];
5134
count = len;
5135
5136
// Copy in v1
5137
int index = len - 1;
5138
5139
do {
5140
int res = quot / 10;
5141
int rem = quot - (res * 10);
5142
5143
quot = res;
5144
5145
// Write the digit into the correct position
5146
value[index--] = (char) ('0' - rem);
5147
} while (quot != 0);
5148
5149
if (v1 < 0) {
5150
value[index] = '-';
5151
}
5152
5153
// Copy in s1 contents
5154
System.arraycopy(s1.value, 0, value, 0, s1len);
5155
}
5156
}
5157
5158
/*
5159
* Creates a string that is v1 + s1 + v2 + s2 + s3.
5160
*/
5161
private String(int v1, String s1, int v2, String s2, String s3) {
5162
if (s1 == null) {
5163
s1 = "null"; //$NON-NLS-1$
5164
}
5165
5166
if (s2 == null) {
5167
s2 = "null"; //$NON-NLS-1$
5168
}
5169
5170
if (s3 == null) {
5171
s3 = "null"; //$NON-NLS-1$
5172
}
5173
5174
// Char length of all the parameters respectively
5175
int s1len = s1.lengthInternal();
5176
int s2len = s2.lengthInternal();
5177
int s3len = s3.lengthInternal();
5178
5179
int v1len = 1;
5180
int v2len = 1;
5181
5182
int quot1;
5183
int i1 = v1;
5184
while ((i1 /= 10) != 0)
5185
v1len++;
5186
if (v1 >= 0) {
5187
quot1 = -v1;
5188
} else {
5189
// Leave room for '-'
5190
v1len++;
5191
quot1 = v1;
5192
}
5193
5194
int quot2;
5195
int i2 = v2;
5196
while ((i2 /= 10) != 0)
5197
v2len++;
5198
if (v2 >= 0) {
5199
quot2 = -v2;
5200
} else {
5201
// Leave room for '-'
5202
v2len++;
5203
quot2 = v2;
5204
}
5205
5206
// Char length of the final String
5207
long totalLen = (long) s1len + (long) v1len + (long) v2len + (long) s2len + (long) s3len;
5208
if (totalLen > Integer.MAX_VALUE) {
5209
/*[MSG "K0D01", "Array capacity exceeded"]*/
5210
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
5211
}
5212
5213
int len = (int) totalLen;
5214
5215
if (COMPACT_STRINGS) {
5216
if (null == compressionFlag || (s1.count | s2.count | s3.count) >= 0) {
5217
value = new char[(len + 1) >>> 1];
5218
count = len;
5219
5220
int start = len;
5221
5222
// Copy in s3 contents
5223
start = start - s3len;
5224
compressedArrayCopy(s3.value, 0, value, start, s3len);
5225
5226
// Copy in s2 contents
5227
start = start - s2len;
5228
compressedArrayCopy(s2.value, 0, value, start, s2len);
5229
5230
// Copy in v2
5231
int index2 = start - 1;
5232
5233
do {
5234
int res = quot2 / 10;
5235
int rem = quot2 - (res * 10);
5236
5237
quot2 = res;
5238
5239
// Write the digit into the correct position
5240
helpers.putByteInArrayByIndex(value, index2--, (byte) ('0' - rem));
5241
} while (quot2 != 0);
5242
5243
if (v2 < 0) {
5244
helpers.putByteInArrayByIndex(value, index2--, (byte) '-');
5245
}
5246
5247
// Copy in s1 contents
5248
start = index2 + 1 - s1len;
5249
compressedArrayCopy(s1.value, 0, value, start, s1len);
5250
5251
// Copy in v1
5252
int index1 = start - 1;
5253
5254
do {
5255
int res = quot1 / 10;
5256
int rem = quot1 - (res * 10);
5257
5258
quot1 = res;
5259
5260
// Write the digit into the correct position
5261
helpers.putByteInArrayByIndex(value, index1--, (byte) ('0' - rem));
5262
} while (quot1 != 0);
5263
5264
if (v1 < 0) {
5265
helpers.putByteInArrayByIndex(value, index1--, (byte) '-');
5266
}
5267
} else {
5268
value = new char[len];
5269
count = len | uncompressedBit;
5270
5271
int start = len;
5272
5273
// Copy in s3 contents
5274
start = start - s3len;
5275
5276
// Check if the String is compressed
5277
if (s3.count >= 0) {
5278
decompress(s3.value, 0, value, start, s3len);
5279
} else {
5280
System.arraycopy(s3.value, 0, value, start, s3len);
5281
}
5282
5283
// Copy in s2 contents
5284
start = start - s2len;
5285
5286
// Check if the String is compressed
5287
if (s2.count >= 0) {
5288
decompress(s2.value, 0, value, start, s2len);
5289
} else {
5290
System.arraycopy(s2.value, 0, value, start, s2len);
5291
}
5292
5293
// Copy in v2
5294
int index2 = start - 1;
5295
5296
do {
5297
int res = quot2 / 10;
5298
int rem = quot2 - (res * 10);
5299
5300
quot2 = res;
5301
5302
// Write the digit into the correct position
5303
value[index2--] = (char) ('0' - rem);
5304
} while (quot2 != 0);
5305
5306
if (v2 < 0) {
5307
value[index2--] = '-';
5308
}
5309
5310
// Copy in s1 contents
5311
start = index2 + 1 - s1len;
5312
5313
// Check if the String is compressed
5314
if (s1.count >= 0) {
5315
decompress(s1.value, 0, value, start, s1len);
5316
} else {
5317
System.arraycopy(s1.value, 0, value, start, s1len);
5318
}
5319
5320
// Copy in v1
5321
int index1 = start - 1;
5322
5323
do {
5324
int res = quot1 / 10;
5325
int rem = quot1 - (res * 10);
5326
5327
quot1 = res;
5328
5329
// Write the digit into the correct position
5330
value[index1--] = (char) ('0' - rem);
5331
} while (quot1 != 0);
5332
5333
if (v1 < 0) {
5334
value[index1--] = '-';
5335
}
5336
5337
initCompressionFlag();
5338
}
5339
} else {
5340
value = new char[len];
5341
count = len;
5342
5343
int start = len;
5344
5345
// Copy in s3 contents
5346
start = start - s3len;
5347
System.arraycopy(s3.value, 0, value, start, s3len);
5348
5349
// Copy in s2 contents
5350
start = start - s2len;
5351
System.arraycopy(s2.value, 0, value, start, s2len);
5352
5353
// Copy in v2
5354
int index2 = start - 1;
5355
5356
do {
5357
int res = quot2 / 10;
5358
int rem = quot2 - (res * 10);
5359
5360
quot2 = res;
5361
5362
// Write the digit into the correct position
5363
value[index2--] = (char) ('0' - rem);
5364
} while (quot2 != 0);
5365
5366
if (v2 < 0) {
5367
value[index2--] = '-';
5368
}
5369
5370
// Copy in s1 contents
5371
start = index2 + 1 - s1len;
5372
5373
System.arraycopy(s1.value, 0, value, start, s1len);
5374
5375
// Copy in v1
5376
int index1 = start - 1;
5377
5378
do {
5379
int res = quot1 / 10;
5380
int rem = quot1 - (res * 10);
5381
5382
quot1 = res;
5383
5384
// Write the digit into the correct position
5385
value[index1--] = (char) ('0' - rem);
5386
} while (quot1 != 0);
5387
5388
if (v1 < 0) {
5389
value[index1--] = '-';
5390
}
5391
}
5392
}
5393
5394
/*
5395
* Loads from the stringArray if concatenated result is found else it creates a string that is s1 + s2 which is stored in stringArray and then
5396
* returned.
5397
*/
5398
static private String cachedConstantString(String s1, String s2, int index) {
5399
if (index < stringArraySize) {
5400
if (stringArray[index] == null) {
5401
stringArray[index] = new String(s1, s2);
5402
}
5403
} else {
5404
return new String(s1, s2);
5405
}
5406
return stringArray[index];
5407
}
5408
5409
/**
5410
* Answers the character at the specified offset in this String.
5411
*
5412
* @param index
5413
* the zero-based index in this string
5414
* @return the character at the index
5415
*
5416
* @throws IndexOutOfBoundsException
5417
* when {@code index < 0} or {@code index >= length()}
5418
*/
5419
public char charAt(int index) {
5420
if (0 <= index && index < lengthInternal()) {
5421
// Check if the String is compressed
5422
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
5423
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
5424
}
5425
5426
return value[index];
5427
}
5428
5429
throw new StringIndexOutOfBoundsException();
5430
}
5431
5432
// Internal version of charAt used for extracting a char from a String in compression related code.
5433
char charAtInternal(int index) {
5434
// Check if the String is compressed
5435
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
5436
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
5437
}
5438
5439
return value[index];
5440
}
5441
5442
// This method is needed so idiom recognition properly recognizes idiomatic loops where we are doing an operation on
5443
// the byte[] value of two Strings. In such cases we extract the String.value fields before entering the operation loop.
5444
// However if chatAt is used inside the loop then the JIT will anchor the load of the value byte[] inside of the loop thus
5445
// causing us to load the String.value on every iteration. This is very suboptimal and breaks some of the common idioms
5446
// that we recognize. The most prominent one is the regionMatches arraycmp idiom that is not recognized unless this method
5447
// is being used.
5448
char charAtInternal(int index, char[] value) {
5449
// Check if the String is compressed
5450
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
5451
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
5452
}
5453
5454
return value[index];
5455
}
5456
5457
/**
5458
* Compares the specified String to this String using the Unicode values of the characters. Answer 0 if the strings contain the same characters in
5459
* 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 Unicode
5460
* 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 positive
5461
* 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 same
5462
* position in the specified string, or if the specified String is a prefix of the this String.
5463
*
5464
* @param string
5465
* the string to compare
5466
* @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 is
5467
* after the specified String
5468
*
5469
* @throws NullPointerException
5470
* when string is null
5471
*/
5472
public int compareTo(String string) {
5473
String s1 = this;
5474
String s2 = string;
5475
5476
int s1len = s1.lengthInternal();
5477
int s2len = s2.lengthInternal();
5478
5479
// Upper bound index on the last char to compare
5480
int end = s1len < s2len ? s1len : s2len;
5481
5482
int o1 = 0;
5483
int o2 = 0;
5484
5485
int result;
5486
5487
char[] s1Value = s1.value;
5488
char[] s2Value = s2.value;
5489
5490
if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {
5491
while (o1 < end) {
5492
if ((result =
5493
helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s1Value, o1++)) -
5494
helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s2Value, o2++))) != 0) {
5495
return result;
5496
}
5497
}
5498
} else {
5499
while (o1 < end) {
5500
if ((result = s1.charAtInternal(o1++, s1Value) - s2.charAtInternal(o2++, s2Value)) != 0) {
5501
return result;
5502
}
5503
}
5504
}
5505
5506
return s1len - s2len;
5507
}
5508
5509
private static char compareValue(char c) {
5510
if ('A' <= c && c <= 'Z') {
5511
return (char) (c + ('a' - 'A'));
5512
}
5513
5514
return Character.toLowerCase(Character.toUpperCase(c));
5515
}
5516
5517
private static char compareValue(byte b) {
5518
if ('A' <= b && b <= 'Z') {
5519
return (char) (helpers.byteToCharUnsigned(b) + ('a' - 'A'));
5520
}
5521
return Character.toLowerCase(Character.toUpperCase(helpers.byteToCharUnsigned(b)));
5522
}
5523
5524
private static boolean charValuesEqualIgnoreCase(char c1, char c2) {
5525
boolean charValuesEqual = false;
5526
char c1upper = (char) toUpperCase(c1);
5527
char c2upper = (char) toUpperCase(c2);
5528
5529
// If at least one char is ASCII, converting to upper cases then compare should be sufficient.
5530
// If both chars are not in ASCII char set, need to convert to lower case and compare as well.
5531
if (((c1 <= 255 || c2 <= 255) && (c1upper == c2upper))
5532
|| (toLowerCase(c1upper) == toLowerCase(c2upper))
5533
) {
5534
charValuesEqual = true;
5535
}
5536
5537
return charValuesEqual;
5538
}
5539
5540
/**
5541
* Compare the receiver to the specified String to determine the relative ordering when the case of the characters is ignored.
5542
*
5543
* @param string
5544
* a String
5545
* @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 greater
5546
*/
5547
public int compareToIgnoreCase(String string) {
5548
String s1 = this;
5549
String s2 = string;
5550
5551
int s1len = s1.lengthInternal();
5552
int s2len = s2.lengthInternal();
5553
5554
// Upper bound index on the last char to compare
5555
int end = s1len < s2len ? s1len : s2len;
5556
5557
int o1 = 0;
5558
int o2 = 0;
5559
5560
int result;
5561
5562
char[] s1Value = s1.value;
5563
char[] s2Value = s2.value;
5564
5565
if (COMPACT_STRINGS && ((null == compressionFlag) || ((s1.count | s2.count) >= 0))) {
5566
while (o1 < end) {
5567
byte byteAtO1;
5568
byte byteAtO2;
5569
5570
if ((byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++)) == (byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++))) {
5571
continue;
5572
}
5573
5574
if ((result = compareValue(byteAtO1) - compareValue(byteAtO2)) != 0) {
5575
return result;
5576
}
5577
}
5578
} else {
5579
while (o1 < end) {
5580
char charAtO1;
5581
char charAtO2;
5582
5583
if ((charAtO1 = s1.charAtInternal(o1++, s1Value)) == (charAtO2 = s2.charAtInternal(o2++, s2Value))) {
5584
continue;
5585
}
5586
5587
if ((result = compareValue(charAtO1) - compareValue(charAtO2)) != 0) {
5588
return result;
5589
}
5590
}
5591
}
5592
5593
return s1len - s2len;
5594
}
5595
5596
/**
5597
* Concatenates this String and the specified string.
5598
*
5599
* @param string
5600
* the string to concatenate
5601
* @return a String which is the concatenation of this String and the specified String
5602
*
5603
* @throws NullPointerException
5604
* if string is null
5605
*/
5606
public String concat(String string) {
5607
String s1 = this;
5608
String s2 = string;
5609
5610
int s1len = s1.lengthInternal();
5611
int s2len = s2.lengthInternal();
5612
5613
if (s2len == 0) {
5614
return s1;
5615
}
5616
5617
int concatlen = s1len + s2len;
5618
if (concatlen < 0) {
5619
/*[MSG "K0D01", "Array capacity exceeded"]*/
5620
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
5621
}
5622
5623
if (COMPACT_STRINGS && ((null == compressionFlag) || ((s1.count | s2.count) >= 0))) {
5624
char[] buffer = new char[(concatlen + 1) >>> 1];
5625
5626
compressedArrayCopy(s1.value, 0, buffer, 0, s1len);
5627
compressedArrayCopy(s2.value, 0, buffer, s1len, s2len);
5628
5629
return new String(buffer, 0, concatlen, true);
5630
} else {
5631
char[] buffer = new char[concatlen];
5632
5633
// Check if the String is compressed
5634
if (COMPACT_STRINGS && s1.count >= 0) {
5635
decompress(s1.value, 0, buffer, 0, s1len);
5636
} else {
5637
System.arraycopy(s1.value, 0, buffer, 0, s1len);
5638
}
5639
5640
// Check if the String is compressed
5641
if (COMPACT_STRINGS && s2.count >= 0) {
5642
decompress(s2.value, 0, buffer, s1len, s2len);
5643
} else {
5644
System.arraycopy(s2.value, 0, buffer, s1len, s2len);
5645
}
5646
5647
return new String(buffer, 0, concatlen, false);
5648
}
5649
}
5650
5651
/**
5652
* Creates a new String containing the characters in the specified character array. Modifying the character array after creating the String has no
5653
* effect on the String.
5654
*
5655
* @param data
5656
* the array of characters
5657
* @return the new String
5658
*
5659
* @throws NullPointerException
5660
* if data is null
5661
*/
5662
public static String copyValueOf(char[] data) {
5663
return new String(data, 0, data.length);
5664
}
5665
5666
/**
5667
* Creates a new String containing the specified characters in the character array. Modifying the character array after creating the String has no
5668
* effect on the String.
5669
*
5670
* @param data
5671
* the array of characters
5672
* @param start
5673
* the starting offset in the character array
5674
* @param length
5675
* the number of characters to use
5676
* @return the new String
5677
*
5678
* @throws IndexOutOfBoundsException
5679
* when {@code length < 0, start < 0} or {@code start + length > data.length}
5680
* @throws NullPointerException
5681
* if data is null
5682
*/
5683
public static String copyValueOf(char[] data, int start, int length) {
5684
return new String(data, start, length);
5685
}
5686
5687
/**
5688
* Compares the specified string to this String to determine if the specified string is a suffix.
5689
*
5690
* @param suffix
5691
* the string to look for
5692
* @return true when the specified string is a suffix of this String, false otherwise
5693
*
5694
* @throws NullPointerException
5695
* if suffix is null
5696
*/
5697
public boolean endsWith(String suffix) {
5698
return regionMatches(lengthInternal() - suffix.lengthInternal(), suffix, 0, suffix.lengthInternal());
5699
}
5700
5701
/**
5702
* 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 in
5703
* the same order.
5704
*
5705
* @param object
5706
* the object to compare
5707
* @return true if the specified object is equal to this String, false otherwise
5708
*
5709
* @see #hashCode()
5710
*/
5711
public boolean equals(Object object) {
5712
if (object == this) {
5713
return true;
5714
}
5715
5716
if (object instanceof String) {
5717
String s1 = this;
5718
String s2 = (String) object;
5719
5720
int s1len = s1.lengthInternal();
5721
int s2len = s2.lengthInternal();
5722
5723
if (s1len != s2len) {
5724
return false;
5725
}
5726
5727
char[] s1Value = s1.value;
5728
char[] s2Value = s2.value;
5729
if (s1Value == s2Value) {
5730
return true;
5731
}
5732
5733
// There was a time hole between first read of s.hash and second read if another thread does hashcode
5734
// computing for incoming string object
5735
int s1hash = s1.hash;
5736
int s2hash = s2.hash;
5737
5738
if (s1hash != 0 && s2hash != 0 && s1hash != s2hash) {
5739
return false;
5740
}
5741
5742
if (!regionMatchesInternal(s1, s2, s1Value, s2Value, 0, 0, s1len)) {
5743
return false;
5744
}
5745
5746
if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY != com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_DISABLED) {
5747
deduplicateStrings(s1, s1Value, s2, s2Value);
5748
}
5749
5750
return true;
5751
}
5752
5753
return false;
5754
}
5755
5756
/**
5757
* Deduplicate the backing buffers of the given strings.
5758
*
5759
* This updates the {@link #value} of one of the two given strings so that
5760
* they both share a single backing buffer. The strings must have identical
5761
* contents.
5762
*
5763
* Deduplication helps save space, and lets {@link #equals(Object)} exit
5764
* early more often.
5765
*
5766
* The strings' corresponding backing buffers are accepted as parameters
5767
* because the caller likely already has them.
5768
*
5769
* @param s1 The first string
5770
* @param value1 {@code s1.value}
5771
* @param s2 The second string
5772
* @param value2 {@code s2.value}
5773
*/
5774
private static final void deduplicateStrings(String s1, Object value1, String s2, Object value2) {
5775
/* This test ensures that we only deduplicate strings that are both
5776
* compressed or both uncompressed.
5777
*
5778
* When one string is compressed and the other isn't, we can't
5779
* deduplicate because doing so would require updating both value and
5780
* count, and other threads could see an inconsistent state.
5781
*
5782
* If (!COMPACT_STRINGS), then both strings are always uncompressed.
5783
* If OTOH (COMPACT_STRINGS) but (null == compressionFlag), then both
5784
* strings must be compressed. So it's only necessary to check the
5785
* compression bits when (COMPACT_STRINGS && null != compressionFlag).
5786
*/
5787
if (!COMPACT_STRINGS || null == compressionFlag || (s1.count ^ s2.count) >= 0) {
5788
long valueFieldOffset = UnsafeHelpers.valueFieldOffset;
5789
5790
if (com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY == com.ibm.oti.vm.VM.J9_JIT_STRING_DEDUP_POLICY_FAVOUR_LOWER) {
5791
if (helpers.acmplt(value1, value2)) {
5792
helpers.putObjectInObject(s2, valueFieldOffset, value1);
5793
} else {
5794
helpers.putObjectInObject(s1, valueFieldOffset, value2);
5795
}
5796
} else {
5797
if (helpers.acmplt(value2, value1)) {
5798
helpers.putObjectInObject(s2, valueFieldOffset, value1);
5799
} else {
5800
helpers.putObjectInObject(s1, valueFieldOffset, value2);
5801
}
5802
}
5803
}
5804
}
5805
5806
/**
5807
* Compares the specified String to this String ignoring the case of the characters and answer if they are equal.
5808
*
5809
* @param string
5810
* the string to compare
5811
* @return true if the specified string is equal to this String, false otherwise
5812
*/
5813
public boolean equalsIgnoreCase(String string) {
5814
String s1 = this;
5815
String s2 = string;
5816
5817
if (s1 == s2) {
5818
return true;
5819
}
5820
5821
if (s2 == null) {
5822
return false;
5823
}
5824
5825
int s1len = s1.lengthInternal();
5826
int s2len = s2.lengthInternal();
5827
5828
if (s1len != s2len) {
5829
return false;
5830
}
5831
5832
// Zero length strings are equal
5833
if (0 == s1len) {
5834
return true;
5835
}
5836
5837
int o1 = 0;
5838
int o2 = 0;
5839
5840
// Upper bound index on the last char to compare
5841
int end = s1len;
5842
5843
char[] s1Value = s1.value;
5844
char[] s2Value = s2.value;
5845
5846
if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {
5847
// Compare the last chars.
5848
// In order to tell 2 chars are different:
5849
// Under string compression, the compressible char set obeys 1-1 mapping for upper/lower case,
5850
// converting to upper cases then compare should be sufficient.
5851
byte byteAtO1Last = helpers.getByteFromArrayByIndex(s1Value, s1len - 1);
5852
byte byteAtO2Last = helpers.getByteFromArrayByIndex(s2Value, s1len - 1);
5853
5854
if ((byteAtO1Last != byteAtO2Last)
5855
&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1Last)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2Last)))
5856
) {
5857
return false;
5858
}
5859
5860
while (o1 < end - 1) {
5861
byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);
5862
byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);
5863
5864
if ((byteAtO1 != byteAtO2)
5865
&& (toUpperCase(helpers.byteToCharUnsigned(byteAtO1)) != toUpperCase(helpers.byteToCharUnsigned(byteAtO2)))
5866
) {
5867
return false;
5868
}
5869
}
5870
} else {
5871
// Compare the last chars.
5872
// In order to tell 2 chars are different:
5873
// If at least one char is ASCII, converting to upper cases then compare should be sufficient.
5874
// If both chars are not in ASCII char set, need to convert to lower case and compare as well.
5875
char charAtO1Last = s1.charAtInternal(s1len - 1, s1Value);
5876
char charAtO2Last = s2.charAtInternal(s1len - 1, s2Value);
5877
5878
if ((charAtO1Last != charAtO2Last)
5879
&& (!charValuesEqualIgnoreCase(charAtO1Last, charAtO2Last))
5880
) {
5881
return false;
5882
}
5883
5884
while (o1 < end - 1) {
5885
char charAtO1 = s1.charAtInternal(o1++, s1Value);
5886
char charAtO2 = s2.charAtInternal(o2++, s2Value);
5887
5888
if ((charAtO1 != charAtO2)
5889
&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))
5890
) {
5891
return false;
5892
}
5893
}
5894
}
5895
5896
return true;
5897
}
5898
5899
/**
5900
* Converts this String to a byte encoding using the default encoding as specified by the file.encoding system property. If the system property is
5901
* not defined, the default encoding is ISO8859_1 (ISO-Latin-1). If 8859-1 is not available, an ASCII encoding is used.
5902
*
5903
* @return the byte array encoding of this String
5904
*
5905
* @see String
5906
*/
5907
public byte[] getBytes() {
5908
int currentLength = lengthInternal();
5909
5910
char[] buffer;
5911
5912
// Check if the String is compressed
5913
if (COMPACT_STRINGS && count >= 0) {
5914
buffer = new char[currentLength];
5915
decompress(value, 0, buffer, 0, currentLength);
5916
} else {
5917
buffer = value;
5918
}
5919
5920
return StringCoding.encode(buffer, 0, currentLength);
5921
}
5922
5923
/**
5924
* Converts this String to a byte array, ignoring the high order bits of each character.
5925
*
5926
* @param start
5927
* the starting offset of characters to copy
5928
* @param end
5929
* the ending offset of characters to copy
5930
* @param data
5931
* the destination byte array
5932
* @param index
5933
* the starting offset in the byte array
5934
*
5935
* @throws NullPointerException
5936
* when data is null
5937
* @throws IndexOutOfBoundsException
5938
* when {@code start < 0, end > length(), index < 0, end - start > data.length - index}
5939
*
5940
* @deprecated Use getBytes() or getBytes(String)
5941
*/
5942
@Deprecated
5943
public void getBytes(int start, int end, byte[] data, int index) {
5944
if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {
5945
// Check if the String is compressed
5946
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
5947
compressedArrayCopy(value, start, data, index, end - start);
5948
} else {
5949
compress(value, start, data, index, end - start);
5950
}
5951
} else {
5952
throw new StringIndexOutOfBoundsException();
5953
}
5954
}
5955
5956
void getBytes(int start, int end, char[] data, int index) {
5957
if (0 <= start && start <= end && end <= lengthInternal()) {
5958
// Check if the String is compressed
5959
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
5960
compressedArrayCopy(value, start, data, index, end - start);
5961
} else {
5962
compress(value, start, data, index, end - start);
5963
}
5964
} else {
5965
throw new StringIndexOutOfBoundsException();
5966
}
5967
}
5968
5969
/**
5970
* Converts this String to a byte encoding using the specified encoding.
5971
*
5972
* @param encoding
5973
* the encoding
5974
* @return the byte array encoding of this String
5975
*
5976
* @throws UnsupportedEncodingException
5977
* when the encoding is not supported
5978
*
5979
* @see String
5980
* @see UnsupportedEncodingException
5981
*/
5982
public byte[] getBytes(String encoding) throws UnsupportedEncodingException {
5983
if (encoding == null) {
5984
throw new NullPointerException();
5985
}
5986
5987
int currentLength = lengthInternal();
5988
5989
char[] buffer;
5990
5991
// Check if the String is compressed
5992
if (COMPACT_STRINGS && count >= 0) {
5993
buffer = new char[currentLength];
5994
decompress(value, 0, buffer, 0, currentLength);
5995
} else {
5996
buffer = value;
5997
}
5998
5999
return StringCoding.encode(encoding, buffer, 0, currentLength);
6000
}
6001
6002
/**
6003
* Copies the specified characters in this String to the character array starting at the specified offset in the character array.
6004
*
6005
* @param start
6006
* the starting offset of characters to copy
6007
* @param end
6008
* the ending offset of characters to copy
6009
* @param data
6010
* the destination character array
6011
* @param index
6012
* the starting offset in the character array
6013
*
6014
* @throws IndexOutOfBoundsException
6015
* when {@code start < 0, end > length(), start > end, index < 0, end - start > buffer.length - index}
6016
* @throws NullPointerException
6017
* when buffer is null
6018
*/
6019
public void getChars(int start, int end, char[] data, int index) {
6020
if (0 <= start && start <= end && end <= lengthInternal() && 0 <= index && ((end - start) <= (data.length - index))) {
6021
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6022
decompress(value, start, data, index, end - start);
6023
} else {
6024
System.arraycopy(value, start, data, index, end - start);
6025
}
6026
} else {
6027
throw new StringIndexOutOfBoundsException();
6028
}
6029
}
6030
6031
// This is a package protected method that performs the getChars operation without explicit bound checks.
6032
// Caller of this method must validate bound safety for String indexing and array copying.
6033
void getCharsNoBoundChecks(int start, int end, char[] data, int index) {
6034
// Check if the String is compressed
6035
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6036
decompress(value, start, data, index, end - start);
6037
} else {
6038
decompressedArrayCopy(value, start, data, index, end - start);
6039
}
6040
}
6041
6042
/**
6043
* Answers an integer hash code for the receiver. Objects which are equal answer the same value for this method.
6044
*
6045
* @return the receiver's hash
6046
*
6047
* @see #equals
6048
*/
6049
public int hashCode() {
6050
if (hash == 0) {
6051
int length = lengthInternal();
6052
if (length > 0) {
6053
// Check if the String is compressed
6054
if (COMPACT_STRINGS && (compressionFlag == null || count >= 0)) {
6055
hash = hashCodeImplCompressed(value, 0, length);
6056
} else {
6057
hash = hashCodeImplDecompressed(value, 0, length);
6058
}
6059
}
6060
}
6061
return hash;
6062
}
6063
6064
private static int hashCodeImplCompressed(char[] value, int offset, int count) {
6065
int hash = 0, end = offset + count;
6066
6067
for (int i = offset; i < end; ++i) {
6068
hash = (hash << 5) - hash + helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i));
6069
}
6070
6071
return hash;
6072
}
6073
6074
private static int hashCodeImplDecompressed(char[] value, int offset, int count) {
6075
int hash = 0, end = offset + count;
6076
6077
for (int i = offset; i < end; ++i) {
6078
hash = (hash << 5) - hash + value[i];
6079
}
6080
6081
return hash;
6082
}
6083
6084
/**
6085
* Searches in this String for the first index of the specified character. The search for the character starts at the beginning and moves towards
6086
* the end of this String.
6087
*
6088
* @param c
6089
* the character to find
6090
* @return the index in this String of the specified character, -1 if the character isn't found
6091
*
6092
* @see #lastIndexOf(int)
6093
* @see #lastIndexOf(int, int)
6094
* @see #lastIndexOf(String)
6095
* @see #lastIndexOf(String, int)
6096
*/
6097
public int indexOf(int c) {
6098
return indexOf(c, 0);
6099
}
6100
6101
/**
6102
* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards
6103
* the end of this String.
6104
*
6105
* @param c
6106
* the character to find
6107
* @param start
6108
* the starting offset
6109
* @return the index in this String of the specified character, -1 if the character isn't found
6110
*
6111
* @see #lastIndexOf(int)
6112
* @see #lastIndexOf(int, int)
6113
* @see #lastIndexOf(String)
6114
* @see #lastIndexOf(String, int)
6115
*/
6116
public int indexOf(int c, int start) {
6117
int len = lengthInternal();
6118
6119
if (start < len) {
6120
if (start < 0) {
6121
start = 0;
6122
}
6123
6124
if (c >= 0 && c <= Character.MAX_VALUE) {
6125
char[] array = value;
6126
6127
// Check if the String is compressed
6128
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6129
if (c <= 255) {
6130
return helpers.intrinsicIndexOfLatin1(array, (byte)c, start, len);
6131
}
6132
} else {
6133
return helpers.intrinsicIndexOfUTF16(array, (char)c, start, len);
6134
}
6135
} else if (c <= Character.MAX_CODE_POINT) {
6136
for (int i = start; i < len; ++i) {
6137
int codePoint = codePointAt(i);
6138
6139
if (codePoint == c) {
6140
return i;
6141
}
6142
6143
if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
6144
++i;
6145
}
6146
}
6147
}
6148
}
6149
6150
return -1;
6151
}
6152
6153
/**
6154
* 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 end
6155
* of this String.
6156
*
6157
* @param string
6158
* the string to find
6159
* @return the index in this String of the specified string, -1 if the string isn't found
6160
*
6161
* @throws NullPointerException
6162
* when string is null
6163
*
6164
* @see #lastIndexOf(int)
6165
* @see #lastIndexOf(int, int)
6166
* @see #lastIndexOf(String)
6167
* @see #lastIndexOf(String, int)
6168
*/
6169
public int indexOf(String string) {
6170
return indexOf(string, 0);
6171
}
6172
6173
/**
6174
* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the
6175
* end of this String.
6176
*
6177
* @param subString
6178
* the string to find
6179
* @param start
6180
* the starting offset
6181
* @return the index in this String of the specified string, -1 if the string isn't found
6182
*
6183
* @throws NullPointerException
6184
* when string is null
6185
*
6186
* @see #lastIndexOf(int)
6187
* @see #lastIndexOf(int, int)
6188
* @see #lastIndexOf(String)
6189
* @see #lastIndexOf(String, int)
6190
*/
6191
public int indexOf(String subString, int start) {
6192
if (subString.length() == 1) {
6193
return indexOf(subString.charAtInternal(0), start);
6194
}
6195
6196
if (start < 0) {
6197
start = 0;
6198
}
6199
6200
String s1 = this;
6201
String s2 = subString;
6202
6203
int s1len = s1.lengthInternal();
6204
int s2len = s2.lengthInternal();
6205
6206
if (s2len > 0) {
6207
if (start > s1len - s2len) {
6208
return -1;
6209
}
6210
6211
char[] s1Value = s1.value;
6212
char[] s2Value = s2.value;
6213
6214
if (COMPACT_STRINGS) {
6215
if (null == compressionFlag || (s1.count | s2.count) >= 0) {
6216
// Both s1 and s2 are compressed.
6217
return helpers.intrinsicIndexOfStringLatin1(s1Value, s1len, s2Value, s2len, start);
6218
} else if ((s1.count & s2.count) < 0) {
6219
// Both s1 and s2 are decompressed.
6220
return helpers.intrinsicIndexOfStringUTF16(s1Value, s1len, s2Value, s2len, start);
6221
} else {
6222
// Mixed case.
6223
char firstChar = s2.charAtInternal(0, s2Value);
6224
6225
while (true) {
6226
int i = indexOf(firstChar, start);
6227
6228
// Handles subCount > count || start >= count.
6229
if (i == -1 || s2len + i > s1len) {
6230
return -1;
6231
}
6232
6233
int o1 = i;
6234
int o2 = 0;
6235
6236
while (++o2 < s2len && s1.charAtInternal(++o1, s1Value) == s2.charAtInternal(o2, s2Value))
6237
;
6238
6239
if (o2 == s2len) {
6240
return i;
6241
}
6242
6243
start = i + 1;
6244
}
6245
}
6246
} else {
6247
// Both s1 and s2 are decompressed.
6248
return helpers.intrinsicIndexOfStringUTF16(s1Value, s1len, s2Value, s2len, start);
6249
}
6250
} else {
6251
return start < s1len ? start : s1len;
6252
}
6253
}
6254
6255
/**
6256
* 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 string
6257
* contained in the table which is equal to this String. The same string object is always answered for strings which are equal.
6258
*
6259
* @return the interned string equal to this String
6260
*/
6261
public native String intern();
6262
6263
/**
6264
* Searches in this String for the last index of the specified character. The search for the character starts at the end and moves towards the
6265
* beginning of this String.
6266
*
6267
* @param c
6268
* the character to find
6269
* @return the index in this String of the specified character, -1 if the character isn't found
6270
*
6271
* @see #lastIndexOf(int)
6272
* @see #lastIndexOf(int, int)
6273
* @see #lastIndexOf(String)
6274
* @see #lastIndexOf(String, int)
6275
*/
6276
public int lastIndexOf(int c) {
6277
return lastIndexOf(c, lengthInternal() - 1);
6278
}
6279
6280
/**
6281
* Searches in this String for the index of the specified character. The search for the character starts at the specified offset and moves towards
6282
* the beginning of this String.
6283
*
6284
* @param c
6285
* the character to find
6286
* @param start
6287
* the starting offset
6288
* @return the index in this String of the specified character, -1 if the character isn't found
6289
*
6290
* @see #lastIndexOf(int)
6291
* @see #lastIndexOf(int, int)
6292
* @see #lastIndexOf(String)
6293
* @see #lastIndexOf(String, int)
6294
*/
6295
public int lastIndexOf(int c, int start) {
6296
if (start >= 0) {
6297
int len = lengthInternal();
6298
6299
if (start >= len) {
6300
start = len - 1;
6301
}
6302
6303
if (c >= 0 && c <= Character.MAX_VALUE) {
6304
char[] array = value;
6305
6306
// Check if the String is compressed
6307
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6308
if (c <= 255) {
6309
byte b = (byte) c;
6310
6311
for (int i = start; i >= 0; --i) {
6312
if (helpers.getByteFromArrayByIndex(array, i) == b) {
6313
return i;
6314
}
6315
}
6316
}
6317
} else {
6318
for (int i = start; i >= 0; --i) {
6319
if (array[i] == c) {
6320
return i;
6321
}
6322
}
6323
}
6324
} else if (c <= Character.MAX_CODE_POINT) {
6325
for (int i = start; i >= 0; --i) {
6326
int codePoint = codePointAt(i);
6327
6328
if (codePoint == c) {
6329
return i;
6330
}
6331
6332
if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
6333
--i;
6334
}
6335
}
6336
}
6337
}
6338
6339
return -1;
6340
}
6341
6342
/**
6343
* 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 beginning
6344
* of this String.
6345
*
6346
* @param string
6347
* the string to find
6348
* @return the index in this String of the specified string, -1 if the string isn't found
6349
*
6350
* @throws NullPointerException
6351
* when string is null
6352
*
6353
* @see #lastIndexOf(int)
6354
* @see #lastIndexOf(int, int)
6355
* @see #lastIndexOf(String)
6356
* @see #lastIndexOf(String, int)
6357
*/
6358
public int lastIndexOf(String string) {
6359
// Use count instead of count - 1 so lastIndexOf("") answers count
6360
return lastIndexOf(string, lengthInternal());
6361
}
6362
6363
/**
6364
* Searches in this String for the index of the specified string. The search for the string starts at the specified offset and moves towards the
6365
* beginning of this String.
6366
*
6367
* @param subString
6368
* the string to find
6369
* @param start
6370
* the starting offset
6371
* @return the index in this String of the specified string, -1 if the string isn't found
6372
*
6373
* @throws NullPointerException
6374
* when string is null
6375
*
6376
* @see #lastIndexOf(int)
6377
* @see #lastIndexOf(int, int)
6378
* @see #lastIndexOf(String)
6379
* @see #lastIndexOf(String, int)
6380
*/
6381
public int lastIndexOf(String subString, int start) {
6382
String s1 = this;
6383
String s2 = subString;
6384
6385
int s1len = s1.lengthInternal();
6386
int s2len = s2.lengthInternal();
6387
6388
if (s2len <= s1len && start >= 0) {
6389
if (s2len > 0) {
6390
if (start > s1len - s2len) {
6391
start = s1len - s2len; // s1len and s2len are both >= 1
6392
}
6393
6394
char[] s1Value = s1.value;
6395
char[] s2Value = s2.value;
6396
6397
if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {
6398
char firstChar = helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(s2Value, 0));
6399
6400
while (true) {
6401
int i = lastIndexOf(firstChar, start);
6402
6403
if (i == -1) {
6404
return -1;
6405
}
6406
6407
int o1 = i;
6408
int o2 = 0;
6409
6410
while (++o2 < s2len && helpers.getByteFromArrayByIndex(s1Value, ++o1) == helpers.getByteFromArrayByIndex(s2Value, o2))
6411
;
6412
6413
if (o2 == s2len) {
6414
return i;
6415
}
6416
6417
start = i - 1;
6418
}
6419
} else {
6420
char firstChar = s2.charAtInternal(0, s2Value);
6421
6422
while (true) {
6423
int i = lastIndexOf(firstChar, start);
6424
6425
if (i == -1) {
6426
return -1;
6427
}
6428
6429
int o1 = i;
6430
int o2 = 0;
6431
6432
while (++o2 < s2len && s1.charAtInternal(++o1, s1Value) == s2.charAtInternal(o2, s2Value))
6433
;
6434
6435
if (o2 == s2len) {
6436
return i;
6437
}
6438
6439
start = i - 1;
6440
}
6441
}
6442
} else {
6443
return start < s1len ? start : s1len;
6444
}
6445
} else {
6446
return -1;
6447
}
6448
}
6449
6450
/**
6451
* Answers the size of this String.
6452
*
6453
* @return the number of characters in this String
6454
*/
6455
public int length() {
6456
return lengthInternal();
6457
}
6458
6459
/**
6460
* Answers the size of this String. This method is to be used internally within the current package whenever
6461
* possible as the JIT compiler will take special precaution to avoid generating HCR guards for calls to this
6462
* method.
6463
*
6464
* @return the number of characters in this String
6465
*/
6466
int lengthInternal() {
6467
if (COMPACT_STRINGS) {
6468
// Check if the String is compressed
6469
if (compressionFlag == null || count >= 0) {
6470
return count;
6471
}
6472
6473
return count & ~uncompressedBit;
6474
}
6475
6476
return count;
6477
}
6478
6479
/**
6480
* Compares the specified string to this String and compares the specified range of characters to determine if they are the same.
6481
*
6482
* @param thisStart
6483
* the starting offset in this String
6484
* @param string
6485
* the string to compare
6486
* @param start
6487
* the starting offset in string
6488
* @param length
6489
* the number of characters to compare
6490
* @return true if the ranges of characters is equal, false otherwise
6491
*
6492
* @throws NullPointerException
6493
* when string is null
6494
*/
6495
public boolean regionMatches(int thisStart, String string, int start, int length) {
6496
string.getClass(); // Implicit null check
6497
6498
String s1 = this;
6499
String s2 = string;
6500
6501
int s1len = s1.lengthInternal();
6502
int s2len = s2.lengthInternal();
6503
6504
if (start < 0 || s2len - start < length) {
6505
return false;
6506
}
6507
6508
if (thisStart < 0 || s1len - thisStart < length) {
6509
return false;
6510
}
6511
6512
return regionMatchesInternal(s1, s2, s1.value, s2.value, thisStart, start, length);
6513
}
6514
6515
private static boolean regionMatchesInternal(String s1, String s2, char[] s1Value, char[] s2Value, int s1Start, int s2Start, int length)
6516
{
6517
if (length <= 0) {
6518
return true;
6519
}
6520
6521
// Index of the last char to compare
6522
int end = length - 1;
6523
6524
if (COMPACT_STRINGS && ((compressionFlag == null) || ((s1.count | s2.count) >= 0))) {
6525
if (helpers.getByteFromArrayByIndex(s1Value, s1Start + end) != helpers.getByteFromArrayByIndex(s2Value, s2Start + end)) {
6526
return false;
6527
} else {
6528
for (int i = 0; i < end; ++i) {
6529
if (helpers.getByteFromArrayByIndex(s1Value, s1Start + i) != helpers.getByteFromArrayByIndex(s2Value, s2Start + i)) {
6530
return false;
6531
}
6532
}
6533
}
6534
} else {
6535
if (s1.charAtInternal(s1Start + end, s1Value) != s2.charAtInternal(s2Start + end, s2Value)) {
6536
return false;
6537
} else {
6538
for (int i = 0; i < end; ++i) {
6539
if (s1.charAtInternal(s1Start + i, s1Value) != s2.charAtInternal(s2Start + i, s2Value)) {
6540
return false;
6541
}
6542
}
6543
}
6544
}
6545
return true;
6546
}
6547
6548
/**
6549
* Compares the specified string to this String and compares the specified range of characters to determine if they are the same. When ignoreCase
6550
* is true, the case of the characters is ignored during the comparison.
6551
*
6552
* @param ignoreCase
6553
* specifies if case should be ignored
6554
* @param thisStart
6555
* the starting offset in this String
6556
* @param string
6557
* the string to compare
6558
* @param start
6559
* the starting offset in string
6560
* @param length
6561
* the number of characters to compare
6562
* @return true if the ranges of characters is equal, false otherwise
6563
*
6564
* @throws NullPointerException
6565
* when string is null
6566
*/
6567
public boolean regionMatches(boolean ignoreCase, int thisStart, String string, int start, int length) {
6568
if (!ignoreCase) {
6569
return regionMatches(thisStart, string, start, length);
6570
}
6571
6572
string.getClass(); // Implicit null check
6573
6574
String s1 = this;
6575
String s2 = string;
6576
6577
int s1len = s1.lengthInternal();
6578
int s2len = s2.lengthInternal();
6579
6580
if (thisStart < 0 || length > s1len - thisStart) {
6581
return false;
6582
}
6583
6584
if (start < 0 || length > s2len - start) {
6585
return false;
6586
}
6587
6588
if (length <= 0) {
6589
return true;
6590
}
6591
6592
int o1 = thisStart;
6593
int o2 = start;
6594
6595
// Upper bound index on the last char to compare
6596
int end = thisStart + length;
6597
6598
char[] s1Value = s1.value;
6599
char[] s2Value = s2.value;
6600
6601
if (COMPACT_STRINGS && (null == compressionFlag || (s1.count | s2.count) >= 0)) {
6602
while (o1 < end) {
6603
byte byteAtO1 = helpers.getByteFromArrayByIndex(s1Value, o1++);
6604
byte byteAtO2 = helpers.getByteFromArrayByIndex(s2Value, o2++);
6605
6606
if ((byteAtO1 != byteAtO2)
6607
&& (!charValuesEqualIgnoreCase(helpers.byteToCharUnsigned(byteAtO1), helpers.byteToCharUnsigned(byteAtO2)))
6608
) {
6609
return false;
6610
}
6611
}
6612
} else {
6613
while (o1 < end) {
6614
char charAtO1 = s1.charAtInternal(o1++, s1Value);
6615
char charAtO2 = s2.charAtInternal(o2++, s2Value);
6616
6617
if ((charAtO1 != charAtO2)
6618
&& (!charValuesEqualIgnoreCase(charAtO1, charAtO2))
6619
) {
6620
return false;
6621
}
6622
}
6623
}
6624
6625
return true;
6626
}
6627
6628
/**
6629
* Replaces occurrences of the specified character with another character.
6630
*
6631
* @param oldChar
6632
* the character to replace
6633
* @param newChar
6634
* the replacement character
6635
* @return a String with occurrences of oldChar replaced by newChar
6636
*/
6637
public String replace(char oldChar, char newChar) {
6638
int index = indexOf(oldChar, 0);
6639
6640
if (index == -1) {
6641
return this;
6642
}
6643
6644
int len = lengthInternal();
6645
6646
// Check if the String is compressed
6647
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6648
if (newChar <= 255) {
6649
char[] buffer = new char[(len + 1) >>> 1];
6650
6651
compressedArrayCopy(value, 0, buffer, 0, len);
6652
6653
do {
6654
helpers.putByteInArrayByIndex(buffer, index++, (byte) newChar);
6655
} while ((index = indexOf(oldChar, index)) != -1);
6656
6657
return new String(buffer, 0, len, true);
6658
} else {
6659
char[] buffer = new char[len];
6660
6661
decompress(value, 0, buffer, 0, len);
6662
6663
do {
6664
buffer[index++] = newChar;
6665
} while ((index = indexOf(oldChar, index)) != -1);
6666
6667
return new String(buffer, 0, len, false);
6668
}
6669
} else {
6670
char[] buffer = new char[len];
6671
6672
System.arraycopy(value, 0, buffer, 0, len);
6673
6674
do {
6675
buffer[index++] = newChar;
6676
} while ((index = indexOf(oldChar, index)) != -1);
6677
6678
return new String(buffer, 0, len, false);
6679
}
6680
}
6681
6682
/**
6683
* Compares the specified string to this String to determine if the specified string is a prefix.
6684
*
6685
* @param prefix
6686
* the string to look for
6687
* @return true when the specified string is a prefix of this String, false otherwise
6688
*
6689
* @throws NullPointerException
6690
* when prefix is null
6691
*/
6692
public boolean startsWith(String prefix) {
6693
return startsWith(prefix, 0);
6694
}
6695
6696
/**
6697
* Compares the specified string to this String, starting at the specified offset, to determine if the specified string is a prefix.
6698
*
6699
* @param prefix
6700
* the string to look for
6701
* @param start
6702
* the starting offset
6703
* @return true when the specified string occurs in this String at the specified offset, false otherwise
6704
*
6705
* @throws NullPointerException
6706
* when prefix is null
6707
*/
6708
public boolean startsWith(String prefix, int start) {
6709
if (prefix.length() == 1) {
6710
if (start < 0 || start >= this.length()) {
6711
return false;
6712
}
6713
return charAtInternal(start) == prefix.charAtInternal(0);
6714
}
6715
return regionMatches(start, prefix, 0, prefix.lengthInternal());
6716
}
6717
6718
/**
6719
* Copies a range of characters into a new String.
6720
*
6721
* @param start
6722
* the offset of the first character
6723
* @return a new String containing the characters from start to the end of the string
6724
*
6725
* @throws IndexOutOfBoundsException
6726
* when {@code start < 0} or {@code start > length()}
6727
*/
6728
public String substring(int start) {
6729
if (start == 0) {
6730
return this;
6731
}
6732
if (start < 0) {
6733
throw new StringIndexOutOfBoundsException(start);
6734
}
6735
int len = lengthInternal();
6736
if (start <= len) {
6737
// Check if the String is compressed
6738
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6739
return new String(value, start, len - start, true, enableSharingInSubstringWhenOffsetIsZero);
6740
} else {
6741
return new String(value, start, len - start, false, enableSharingInSubstringWhenOffsetIsZero);
6742
}
6743
}
6744
throw new StringIndexOutOfBoundsException("begin " + start + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$
6745
}
6746
6747
/**
6748
* Copies a range of characters.
6749
*
6750
* @param start
6751
* the offset of the first character
6752
* @param end
6753
* the offset one past the last character
6754
* @return a String containing the characters from start to end - 1
6755
*
6756
* @throws IndexOutOfBoundsException
6757
* when {@code start < 0, start > end} or {@code end > length()}
6758
*/
6759
public String substring(int start, int end) {
6760
int len = lengthInternal();
6761
if ((start == 0) && (end == len)) {
6762
return this;
6763
}
6764
if ((start >= 0) && (start <= end) && (end <= len)) {
6765
// Check if the String is compressed
6766
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6767
return new String(value, start, end - start, true, enableSharingInSubstringWhenOffsetIsZero);
6768
} else {
6769
return new String(value, start, end - start, false, enableSharingInSubstringWhenOffsetIsZero);
6770
}
6771
}
6772
throw new StringIndexOutOfBoundsException("begin " + start + ", end " + end + ", length " + len); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
6773
}
6774
6775
/**
6776
* Copies the characters in this String to a character array.
6777
*
6778
* @return a character array containing the characters of this String
6779
*/
6780
public char[] toCharArray() {
6781
int len = lengthInternal();
6782
6783
char[] buffer = new char[len];
6784
6785
// Check if the String is compressed
6786
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6787
decompress(value, 0, buffer, 0, len);
6788
} else {
6789
System.arraycopy(value, 0, buffer, 0, len);
6790
}
6791
6792
return buffer;
6793
}
6794
6795
/**
6796
* Converts the characters in this String to lowercase, using the default Locale. To convert to lower case independent of any locale, use
6797
* toLowerCase(Locale.ROOT).
6798
*
6799
* @return a new String containing the lowercase characters equivalent to the characters in this String
6800
*/
6801
public String toLowerCase() {
6802
return toLowerCase(Locale.getDefault());
6803
}
6804
6805
private static int toLowerCase(int codePoint) {
6806
if (codePoint < 128) {
6807
if ('A' <= codePoint && codePoint <= 'Z') {
6808
return codePoint + ('a' - 'A');
6809
} else {
6810
return codePoint;
6811
}
6812
} else {
6813
return Character.toLowerCase(codePoint);
6814
}
6815
}
6816
6817
private static int toUpperCase(int codePoint) {
6818
if (codePoint < 128) {
6819
if ('a' <= codePoint && codePoint <= 'z') {
6820
return codePoint - ('a' - 'A');
6821
} else {
6822
return codePoint;
6823
}
6824
} else {
6825
return Character.toUpperCase(codePoint);
6826
}
6827
}
6828
6829
// Some of the data below originated from the Unicode Character Database file
6830
// www.unicode.org/Public/4.0-Update/SpecialCasing-4.0.0.txt. Data from this
6831
// file was extracted, used in the code and/or converted to an array
6832
// representation for performance and size.
6833
6834
/*
6835
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
6836
6837
Unicode Data Files include all data files under the directories
6838
http://www.unicode.org/Public/, http://www.unicode.org/reports/,
6839
http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and
6840
http://www.unicode.org/utility/trac/browser/.
6841
6842
Unicode Data Files do not include PDF online code charts under the
6843
directory http://www.unicode.org/Public/.
6844
6845
Software includes any source code published in the Unicode Standard
6846
or under the directories
6847
http://www.unicode.org/Public/, http://www.unicode.org/reports/,
6848
http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and
6849
http://www.unicode.org/utility/trac/browser/.
6850
6851
NOTICE TO USER: Carefully read the following legal agreement.
6852
BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
6853
DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
6854
YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
6855
TERMS AND CONDITIONS OF THIS AGREEMENT.
6856
IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
6857
THE DATA FILES OR SOFTWARE.
6858
6859
COPYRIGHT AND PERMISSION NOTICE
6860
6861
Copyright (c) 1991-2017 Unicode, Inc. All rights reserved.
6862
Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
6863
6864
Permission is hereby granted, free of charge, to any person obtaining
6865
a copy of the Unicode data files and any associated documentation
6866
(the "Data Files") or Unicode software and any associated documentation
6867
(the "Software") to deal in the Data Files or Software
6868
without restriction, including without limitation the rights to use,
6869
copy, modify, merge, publish, distribute, and/or sell copies of
6870
the Data Files or Software, and to permit persons to whom the Data Files
6871
or Software are furnished to do so, provided that either
6872
(a) this copyright and permission notice appear with all copies
6873
of the Data Files or Software, or
6874
(b) this copyright and permission notice appear in associated
6875
Documentation.
6876
6877
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
6878
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
6879
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
6880
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
6881
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
6882
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
6883
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
6884
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
6885
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
6886
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
6887
6888
Except as contained in this notice, the name of a copyright holder
6889
shall not be used in advertising or otherwise to promote the sale,
6890
use or other dealings in these Data Files or Software without prior
6891
written authorization of the copyright holder.
6892
*/
6893
6894
/**
6895
* Converts the characters in this String to lowercase, using the specified Locale.
6896
*
6897
* @param locale
6898
* the Locale
6899
* @return a String containing the lowercase characters equivalent to the characters in this String
6900
*/
6901
public String toLowerCase(Locale locale) {
6902
// check locale for null
6903
String language = locale.getLanguage();
6904
int sLength = lengthInternal();
6905
6906
if (sLength == 0) {
6907
return this;
6908
}
6909
6910
if (helpers.supportsIntrinsicCaseConversion() && (language == "en")) { //$NON-NLS-1$
6911
if (COMPACT_STRINGS && ((null == compressionFlag) || (count >= 0))) {
6912
char[] output = new char[(sLength + 1) >>> 1];
6913
if (helpers.toLowerIntrinsicLatin1(value, output, sLength)) {
6914
return new String(output, 0, sLength, true);
6915
}
6916
} else if (sLength <= (Integer.MAX_VALUE / 2)) {
6917
char[] output = new char[sLength];
6918
if (helpers.toLowerIntrinsicUTF16(value, output, sLength * 2)) {
6919
return new String(output, 0, sLength, false);
6920
}
6921
}
6922
}
6923
6924
return toLowerCaseCore(language);
6925
}
6926
6927
/**
6928
* The core of lower case conversion. This is the old, not-as-fast path.
6929
*
6930
* @param language
6931
* a string representing the Locale
6932
* @return a new string object
6933
*/
6934
private String toLowerCaseCore(String language) {
6935
boolean turkishAzeri = false;
6936
boolean lithuanian = false;
6937
6938
StringBuilder builder = null;
6939
6940
int len = lengthInternal();
6941
6942
for (int i = 0; i < len; i++) {
6943
int codePoint = charAtInternal(i);
6944
6945
if (codePoint >= Character.MIN_HIGH_SURROGATE && codePoint <= Character.MAX_HIGH_SURROGATE) {
6946
codePoint = codePointAt(i);
6947
}
6948
6949
int lowerCase = toLowerCase(codePoint);
6950
6951
if (codePoint != lowerCase) {
6952
if (builder == null) {
6953
turkishAzeri = language == "tr" || language == "az"; //$NON-NLS-1$ //$NON-NLS-2$
6954
lithuanian = language == "lt"; //$NON-NLS-1$
6955
6956
builder = new StringBuilder(len);
6957
6958
// Check if the String is compressed
6959
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
6960
builder.append(value, 0, i, true);
6961
} else {
6962
builder.append(value, 0, i, false);
6963
}
6964
}
6965
6966
if (codePoint == 0x3A3) {
6967
builder.append(convertSigma(i));
6968
6969
continue;
6970
}
6971
6972
if (!turkishAzeri && (0x0130 == codePoint)) {
6973
builder.append("i\u0307"); //$NON-NLS-1$
6974
6975
continue;
6976
}
6977
6978
if (turkishAzeri) {
6979
if (codePoint == 0x49) {
6980
// Special case mappings. Latin Capital Letter I becomes Latin Small Letter Dotless i, unless followed by Combining Dot Above
6981
boolean combiningDotAbove = (i + 1) < len && charAtInternal(i + 1) == '\u0307';
6982
6983
builder.append(combiningDotAbove ? 'i' : '\u0131');
6984
6985
if (combiningDotAbove) {
6986
++i;
6987
}
6988
} else {
6989
builder.appendCodePoint(lowerCase);
6990
}
6991
} else if (lithuanian) {
6992
// Latin Capital Letter I, Latin Capital Letter J, Latin Capital Letter I with Ogonek
6993
if (codePoint == 0x49 || codePoint == 0x4A || codePoint == 0x12E) {
6994
builder.append(codePoint == 0x12E ? '\u012F' : (char) (codePoint + 0x20));
6995
6996
if ((i + 1) < len) {
6997
int nextPoint = codePointAt(i + 1);
6998
6999
if (isCombiningAbove(nextPoint)) {
7000
builder.append('\u0307');
7001
}
7002
}
7003
// Latin Capital Letter I with Grave
7004
} else if (codePoint == 0xCC) {
7005
builder.append("i\u0307\u0300"); //$NON-NLS-1$
7006
// Latin Capital Letter I with Acute
7007
} else if (codePoint == 0xCD) {
7008
builder.append("i\u0307\u0301"); //$NON-NLS-1$
7009
// Latin Capital Letter I with Tilde
7010
} else if (codePoint == 0x128) {
7011
builder.append("i\u0307\u0303"); //$NON-NLS-1$
7012
} else {
7013
builder.appendCodePoint(lowerCase);
7014
}
7015
} else {
7016
builder.appendCodePoint(lowerCase);
7017
7018
}
7019
} else if (builder != null) {
7020
builder.appendCodePoint(codePoint);
7021
}
7022
7023
if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
7024
++i;
7025
}
7026
}
7027
7028
if (builder == null) {
7029
return this;
7030
}
7031
7032
return builder.toString();
7033
}
7034
7035
private static int binarySearchRange(char[] data, char c) {
7036
char value = 0;
7037
7038
int low = 0;
7039
int mid = -1;
7040
int high = data.length - 1;
7041
7042
while (low <= high) {
7043
mid = (low + high) >>> 1;
7044
7045
value = data[mid];
7046
7047
if (c > value) {
7048
low = mid + 1;
7049
} else if (c == value) {
7050
return mid;
7051
} else {
7052
high = mid - 1;
7053
}
7054
}
7055
7056
return mid - (c < value ? 1 : 0);
7057
}
7058
7059
/* The following code points are extracted from the Canonical_Combining_Class=Above table found in:
7060
* https://www.unicode.org/Public/6.2.0/ucd/extracted/DerivedCombiningClass.txt
7061
*/
7062
private static char[] startCombiningAbove = { '\u0300', '\u033D', '\u0346', '\u034A', '\u0350', '\u0357', '\u035B', '\u0363', '\u0483', '\u0592',
7063
'\u0597', '\u059C', '\u05A8', '\u05AB', '\u05AF', '\u05C4', '\u0610', '\u0653', '\u0657', '\u065D', '\u06D6', '\u06DF', '\u06E4', '\u06E7',
7064
'\u06EB', '\u0730', '\u0732', '\u0735', '\u073A', '\u073D', '\u073F', '\u0743', '\u0745', '\u0747', '\u0749', '\u07EB', '\u07F3', '\u0816',
7065
'\u081B', '\u0825', '\u0829', '\u08E4', '\u08E7', '\u08EA', '\u08F3', '\u08F7', '\u08FB', '\u0951', '\u0953', '\u0F82', '\u0F86', '\u135D',
7066
'\u17DD', '\u193A', '\u1A17', '\u1A75', '\u1B6B', '\u1B6D', '\u1CD0', '\u1CDA', '\u1CE0', '\u1CF4', '\u1DC0', '\u1DC3', '\u1DCB', '\u1DD1',
7067
'\u1DFE', '\u20D0', '\u20D4', '\u20DB', '\u20E1', '\u20E7', '\u20E9', '\u20F0', '\u2CEF', '\u2DE0', '\uA66F', '\uA674', '\uA69F', '\uA6F0',
7068
'\uA8E0', '\uAAB0', '\uAAB2', '\uAAB7', '\uAABE', '\uAAC1', '\uFE20' };
7069
private static char[] endCombiningAbove = { '\u0314', '\u0344', '\u0346', '\u034C', '\u0352', '\u0357', '\u035B', '\u036F', '\u0487', '\u0595',
7070
'\u0599', '\u05A1', '\u05A9', '\u05AC', '\u05AF', '\u05C4', '\u0617', '\u0654', '\u065B', '\u065E', '\u06DC', '\u06E2', '\u06E4', '\u06E8',
7071
'\u06EC', '\u0730', '\u0733', '\u0736', '\u073A', '\u073D', '\u0741', '\u0743', '\u0745', '\u0747', '\u074A', '\u07F1', '\u07F3', '\u0819',
7072
'\u0823', '\u0827', '\u082D', '\u08E5', '\u08E8', '\u08EC', '\u08F5', '\u08F8', '\u08FE', '\u0951', '\u0954', '\u0F83', '\u0F87', '\u135F',
7073
'\u17DD', '\u193A', '\u1A17', '\u1A7C', '\u1B6B', '\u1B73', '\u1CD2', '\u1CDB', '\u1CE0', '\u1CF4', '\u1DC1', '\u1DC9', '\u1DCC', '\u1DE6',
7074
'\u1DFE', '\u20D1', '\u20D7', '\u20DC', '\u20E1', '\u20E7', '\u20E9', '\u20F0', '\u2CF1', '\u2DFF', '\uA66F', '\uA67D', '\uA69F', '\uA6F1',
7075
'\uA8F1', '\uAAB0', '\uAAB3', '\uAAB8', '\uAABF', '\uAAC1', '\uFE26' };
7076
private static char[] upperValues = { '\u0053', '\u0053', '\u0000', '\u02BC', '\u004E', '\u0000', '\u004A', '\u030C', '\u0000', '\u0399',
7077
'\u0308', '\u0301', '\u03A5', '\u0308', '\u0301', '\u0535', '\u0552', '\u0000', '\u0048', '\u0331', '\u0000', '\u0054', '\u0308', '\u0000',
7078
'\u0057', '\u030A', '\u0000', '\u0059', '\u030A', '\u0000', '\u0041', '\u02BE', '\u0000', '\u03A5', '\u0313', '\u0000', '\u03A5', '\u0313',
7079
'\u0300', '\u03A5', '\u0313', '\u0301', '\u03A5', '\u0313', '\u0342', '\u1F08', '\u0399', '\u0000', '\u1F09', '\u0399', '\u0000', '\u1F0A',
7080
'\u0399', '\u0000', '\u1F0B', '\u0399', '\u0000', '\u1F0C', '\u0399', '\u0000', '\u1F0D', '\u0399', '\u0000', '\u1F0E', '\u0399', '\u0000',
7081
'\u1F0F', '\u0399', '\u0000', '\u1F08', '\u0399', '\u0000', '\u1F09', '\u0399', '\u0000', '\u1F0A', '\u0399', '\u0000', '\u1F0B', '\u0399',
7082
'\u0000', '\u1F0C', '\u0399', '\u0000', '\u1F0D', '\u0399', '\u0000', '\u1F0E', '\u0399', '\u0000', '\u1F0F', '\u0399', '\u0000', '\u1F28',
7083
'\u0399', '\u0000', '\u1F29', '\u0399', '\u0000', '\u1F2A', '\u0399', '\u0000', '\u1F2B', '\u0399', '\u0000', '\u1F2C', '\u0399', '\u0000',
7084
'\u1F2D', '\u0399', '\u0000', '\u1F2E', '\u0399', '\u0000', '\u1F2F', '\u0399', '\u0000', '\u1F28', '\u0399', '\u0000', '\u1F29', '\u0399',
7085
'\u0000', '\u1F2A', '\u0399', '\u0000', '\u1F2B', '\u0399', '\u0000', '\u1F2C', '\u0399', '\u0000', '\u1F2D', '\u0399', '\u0000', '\u1F2E',
7086
'\u0399', '\u0000', '\u1F2F', '\u0399', '\u0000', '\u1F68', '\u0399', '\u0000', '\u1F69', '\u0399', '\u0000', '\u1F6A', '\u0399', '\u0000',
7087
'\u1F6B', '\u0399', '\u0000', '\u1F6C', '\u0399', '\u0000', '\u1F6D', '\u0399', '\u0000', '\u1F6E', '\u0399', '\u0000', '\u1F6F', '\u0399',
7088
'\u0000', '\u1F68', '\u0399', '\u0000', '\u1F69', '\u0399', '\u0000', '\u1F6A', '\u0399', '\u0000', '\u1F6B', '\u0399', '\u0000', '\u1F6C',
7089
'\u0399', '\u0000', '\u1F6D', '\u0399', '\u0000', '\u1F6E', '\u0399', '\u0000', '\u1F6F', '\u0399', '\u0000', '\u1FBA', '\u0399', '\u0000',
7090
'\u0391', '\u0399', '\u0000', '\u0386', '\u0399', '\u0000', '\u0391', '\u0342', '\u0000', '\u0391', '\u0342', '\u0399', '\u0391', '\u0399',
7091
'\u0000', '\u1FCA', '\u0399', '\u0000', '\u0397', '\u0399', '\u0000', '\u0389', '\u0399', '\u0000', '\u0397', '\u0342', '\u0000', '\u0397',
7092
'\u0342', '\u0399', '\u0397', '\u0399', '\u0000', '\u0399', '\u0308', '\u0300', '\u0399', '\u0308', '\u0301', '\u0399', '\u0342', '\u0000',
7093
'\u0399', '\u0308', '\u0342', '\u03A5', '\u0308', '\u0300', '\u03A5', '\u0308', '\u0301', '\u03A1', '\u0313', '\u0000', '\u03A5', '\u0342',
7094
'\u0000', '\u03A5', '\u0308', '\u0342', '\u1FFA', '\u0399', '\u0000', '\u03A9', '\u0399', '\u0000', '\u038F', '\u0399', '\u0000', '\u03A9',
7095
'\u0342', '\u0000', '\u03A9', '\u0342', '\u0399', '\u03A9', '\u0399', '\u0000', '\u0046', '\u0046', '\u0000', '\u0046', '\u0049', '\u0000',
7096
'\u0046', '\u004C', '\u0000', '\u0046', '\u0046', '\u0049', '\u0046', '\u0046', '\u004C', '\u0053', '\u0054', '\u0000', '\u0053', '\u0054',
7097
'\u0000', '\u0544', '\u0546', '\u0000', '\u0544', '\u0535', '\u0000', '\u0544', '\u053B', '\u0000', '\u054E', '\u0546', '\u0000', '\u0544',
7098
'\u053D', '\u0000' };
7099
private static char[] upperIndexs = { '\u000B', '\u0000', '\f', '\u0000', '\r', '\u0000', '\u000E', '\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', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000',
7102
'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u000F', '\u0010', '\u0011', '\u0012', '\u0013',
7103
'\u0014', '\u0015', '\u0016', '\u0017', '\u0018', '\u0019', '\u001A', '\u001B', '\u001C', '\u001D', '\u001E', '\u001F', '\u0020', '\u0021',
7104
'\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\'', '\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F',
7105
'\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037', '\u0038', '\u0039', '\u003A', '\u003B', '\u003C', '\u003D',
7106
'\u003E', '\u0000', '\u0000', '\u003F', '\u0040', '\u0041', '\u0000', '\u0042', '\u0043', '\u0000', '\u0000', '\u0000', '\u0000', '\u0044',
7107
'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0045', '\u0046', '\u0047', '\u0000', '\u0048', '\u0049', '\u0000', '\u0000', '\u0000',
7108
'\u0000', '\u004A', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u004B', '\u004C', '\u0000', '\u0000', '\u004D', '\u004E', '\u0000',
7109
'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u004F', '\u0050', '\u0051', '\u0000', '\u0052',
7110
'\u0053', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0054', '\u0055', '\u0056',
7111
'\u0000', '\u0057', '\u0058', '\u0000', '\u0000', '\u0000', '\u0000', '\u0059' };
7112
7113
private static boolean isCombiningAbove(int codePoint) {
7114
if (codePoint < 0xFFFF) {
7115
int index = binarySearchRange(startCombiningAbove, (char) codePoint);
7116
7117
return index >= 0 && endCombiningAbove[index] >= codePoint;
7118
/* The following code points are extracted from the Canonical_Combining_Class=Above table found in:
7119
* https://www.unicode.org/Public/6.2.0/ucd/extracted/DerivedCombiningClass.txt
7120
*/
7121
} else if (codePoint == 0x10A0F || codePoint == 0x10A38 ||
7122
(codePoint >= 0x11100 && codePoint <= 0x11102) ||
7123
(codePoint >= 0x1D185 && codePoint <= 0x1D189) ||
7124
(codePoint >= 0x1D1AA && codePoint <= 0x1D1AD) ||
7125
(codePoint >= 0x1D242 && codePoint <= 0x1D244)) {
7126
return true;
7127
}
7128
7129
return false;
7130
}
7131
7132
private static boolean isWordPart(int codePoint) {
7133
return codePoint == 0x345 || isWordStart(codePoint);
7134
}
7135
7136
private static boolean isWordStart(int codePoint) {
7137
int type = Character.getType(codePoint);
7138
7139
return (type >= Character.UPPERCASE_LETTER && type <= Character.TITLECASE_LETTER) || (codePoint >= 0x2B0 && codePoint <= 0x2B8)
7140
|| (codePoint >= 0x2C0 && codePoint <= 0x2C1) || (codePoint >= 0x2E0 && codePoint <= 0x2E4) || codePoint == 0x37A
7141
|| (codePoint >= 0x2160 && codePoint <= 0x217F) || (codePoint >= 0x1D2C && codePoint <= 0x1D61);
7142
}
7143
7144
private char convertSigma(int pos) {
7145
if (pos == 0 || !isWordStart(codePointBefore(pos)) || ((pos + 1) < lengthInternal() && isWordPart(codePointAt(pos + 1)))) {
7146
return '\u03C3';
7147
}
7148
return '\u03C2';
7149
}
7150
7151
/**
7152
* Answers a string containing a concise, human-readable description of the receiver.
7153
*
7154
* @return this String
7155
*/
7156
public String toString() {
7157
return this;
7158
}
7159
7160
/**
7161
* Converts the characters in this String to uppercase, using the default Locale. To convert to upper case independent of any locale, use
7162
* toUpperCase(Locale.ROOT).
7163
*
7164
* @return a String containing the uppercase characters equivalent to the characters in this String
7165
*/
7166
public String toUpperCase() {
7167
return toUpperCase(Locale.getDefault());
7168
}
7169
7170
/**
7171
* Return the index of the specified character into the upperValues table. The upperValues table contains three entries at each position. These
7172
* three characters are the upper case conversion. If only two characters are used, the third character in the table is \u0000.
7173
*
7174
* @param ch
7175
* the char being converted to upper case
7176
*
7177
* @return the index into the upperValues table, or -1
7178
*/
7179
private static int upperIndex(int ch) {
7180
int index = -1;
7181
7182
if (ch <= 0x587) {
7183
if (ch == 0xDF) {
7184
index = 0;
7185
} else if (ch <= 0x149) {
7186
if (ch == 0x149) {
7187
index = 1;
7188
}
7189
} else if (ch <= 0x1F0) {
7190
if (ch == 0x1F0) {
7191
index = 2;
7192
}
7193
} else if (ch <= 0x390) {
7194
if (ch == 0x390) {
7195
index = 3;
7196
}
7197
} else if (ch <= 0x3B0) {
7198
if (ch == 0x3B0) {
7199
index = 4;
7200
}
7201
} else if (ch <= 0x587) {
7202
if (ch == 0x587) {
7203
index = 5;
7204
}
7205
}
7206
} else if (ch >= 0x1E96) {
7207
if (ch <= 0x1E9A) {
7208
index = 6 + ch - 0x1E96;
7209
} else if (ch >= 0x1F50 && ch <= 0x1FFC) {
7210
index = upperIndexs[ch - 0x1F50];
7211
7212
if (index == 0) {
7213
index = -1;
7214
}
7215
} else if (ch >= 0xFB00) {
7216
if (ch <= 0xFB06) {
7217
index = 90 + ch - 0xFB00;
7218
} else if (ch >= 0xFB13 && ch <= 0xFB17) {
7219
index = 97 + ch - 0xFB13;
7220
}
7221
}
7222
}
7223
7224
return index;
7225
}
7226
7227
/**
7228
* Converts the characters in this String to uppercase, using the specified Locale.
7229
*
7230
* @param locale
7231
* the Locale
7232
* @return a String containing the uppercase characters equivalent to the characters in this String
7233
*/
7234
public String toUpperCase(Locale locale) {
7235
String language = locale.getLanguage();
7236
int sLength = lengthInternal();
7237
7238
if (sLength == 0) {
7239
return this;
7240
}
7241
7242
if (helpers.supportsIntrinsicCaseConversion() && (language == "en")) { //$NON-NLS-1$
7243
if (COMPACT_STRINGS && ((null == compressionFlag) || (count >= 0))) {
7244
char[] output = new char[(sLength + 1) >>> 1];
7245
if (helpers.toUpperIntrinsicLatin1(value, output, sLength)) {
7246
return new String(output, 0, sLength, true);
7247
}
7248
} else if (sLength <= (Integer.MAX_VALUE / 2)) {
7249
char[] output = new char[sLength];
7250
if (helpers.toUpperIntrinsicUTF16(value, output, sLength * 2)) {
7251
return new String(output, 0, sLength, false);
7252
}
7253
}
7254
}
7255
7256
return toUpperCaseCore(language);
7257
}
7258
7259
/**
7260
* The core of upper case conversion. This is the old, not-as-fast path.
7261
*
7262
* @param language
7263
* the string representing the locale
7264
* @return the upper case string
7265
*/
7266
private String toUpperCaseCore(String language) {
7267
boolean turkishAzeri = language == "tr" || language == "az"; //$NON-NLS-1$ //$NON-NLS-2$
7268
boolean lithuanian = language == "lt"; //$NON-NLS-1$
7269
7270
StringBuilder builder = null;
7271
7272
int len = lengthInternal();
7273
7274
for (int i = 0; i < len; i++) {
7275
int codePoint = charAtInternal(i);
7276
7277
if (codePoint >= Character.MIN_HIGH_SURROGATE && codePoint <= Character.MAX_HIGH_SURROGATE) {
7278
codePoint = codePointAt(i);
7279
}
7280
7281
int index = -1;
7282
7283
if (codePoint >= 0xDF && codePoint <= 0xFB17) {
7284
index = upperIndex(codePoint);
7285
}
7286
7287
if (index == -1) {
7288
int upper = (!turkishAzeri || codePoint != 0x69) ? toUpperCase(codePoint) : 0x130;
7289
7290
if (codePoint != upper) {
7291
if (builder == null) {
7292
builder = new StringBuilder(len);
7293
7294
// Check if the String is compressed
7295
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
7296
builder.append(value, 0, i, true);
7297
} else {
7298
builder.append(value, 0, i, false);
7299
}
7300
}
7301
7302
builder.appendCodePoint(upper);
7303
} else if (builder != null) {
7304
builder.appendCodePoint(codePoint);
7305
}
7306
7307
if (lithuanian && codePoint <= 0x1ECB && (i + 1) < len && charAt(i + 1) == '\u0307'
7308
&& "ij\u012F\u0268\u0456\u0458\u1E2D\u1ECB".indexOf(codePoint, 0) != -1) //$NON-NLS-1$
7309
{
7310
++i;
7311
}
7312
} else {
7313
if (builder == null) {
7314
builder = new StringBuilder(len + (len / 6) + 2).append(this, 0, i);
7315
}
7316
7317
int target = index * 3;
7318
7319
builder.append(upperValues[target]);
7320
builder.append(upperValues[target + 1]);
7321
7322
char val = upperValues[target + 2];
7323
7324
if (val != 0) {
7325
builder.append(val);
7326
}
7327
}
7328
7329
if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
7330
++i;
7331
}
7332
}
7333
7334
if (builder == null) {
7335
return this;
7336
}
7337
7338
return builder.toString();
7339
}
7340
7341
/**
7342
* Removes white space characters from the beginning and end of the string.
7343
*
7344
* @return a String with characters {@code <= \\u0020} removed from the beginning and the end
7345
*/
7346
public String trim() {
7347
int start = 0;
7348
int last = lengthInternal() - 1;
7349
int end = last;
7350
7351
// Check if the String is compressed
7352
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
7353
while ((start <= end) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, start)) <= ' ')) {
7354
start++;
7355
}
7356
7357
while ((end >= start) && (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, end)) <= ' ')) {
7358
end--;
7359
}
7360
7361
if (start == 0 && end == last) {
7362
return this;
7363
} else {
7364
return new String(value, start, end - start + 1, true);
7365
}
7366
} else {
7367
while ((start <= end) && (charAtInternal(start) <= ' ')) {
7368
start++;
7369
}
7370
7371
while ((end >= start) && (charAtInternal(end) <= ' ')) {
7372
end--;
7373
}
7374
7375
if (start == 0 && end == last) {
7376
return this;
7377
} else {
7378
return new String(value, start, end - start + 1, false);
7379
}
7380
}
7381
}
7382
7383
/**
7384
* Returns a String containing the characters in the specified character array. Modifying the character array after creating the String has no
7385
* effect on the String.
7386
*
7387
* @param data
7388
* the array of characters
7389
* @return the String
7390
*
7391
* @throws NullPointerException
7392
* when data is null
7393
*/
7394
public static String valueOf(char[] data) {
7395
return new String(data, 0, data.length);
7396
}
7397
7398
/**
7399
* Returns a String containing the specified characters in the character array. Modifying the character array after creating the String has no
7400
* effect on the String.
7401
*
7402
* @param data
7403
* the array of characters
7404
* @param start
7405
* the starting offset in the character array
7406
* @param length
7407
* the number of characters to use
7408
* @return the String
7409
*
7410
* @throws IndexOutOfBoundsException
7411
* when {@code length < 0, start < 0} or {@code start + length > data.length}
7412
* @throws NullPointerException
7413
* when data is null
7414
*/
7415
public static String valueOf(char[] data, int start, int length) {
7416
return new String(data, start, length);
7417
}
7418
7419
/**
7420
* Converts the specified character to its string representation.
7421
*
7422
* @param value
7423
* the character
7424
* @return the character converted to a string
7425
*/
7426
public static String valueOf(char value) {
7427
String string;
7428
7429
if (value <= 255) {
7430
if (COMPACT_STRINGS) {
7431
string = new String(compressedAsciiTable[value], 0, 1, true);
7432
} else {
7433
string = new String(decompressedAsciiTable[value], 0, 1, false);
7434
}
7435
} else {
7436
string = new String(new char[] { value }, 0, 1, false);
7437
}
7438
7439
return string;
7440
}
7441
7442
/**
7443
* Converts the specified double to its string representation.
7444
*
7445
* @param value
7446
* the double
7447
* @return the double converted to a string
7448
*/
7449
public static String valueOf(double value) {
7450
return Double.toString(value);
7451
}
7452
7453
/**
7454
* Converts the specified float to its string representation.
7455
*
7456
* @param value
7457
* the float
7458
* @return the float converted to a string
7459
*/
7460
public static String valueOf(float value) {
7461
return Float.toString(value);
7462
}
7463
7464
/**
7465
* Converts the specified integer to its string representation.
7466
*
7467
* @param value
7468
* the integer
7469
* @return the integer converted to a string
7470
*/
7471
public static String valueOf(int value) {
7472
return Integer.toString(value);
7473
}
7474
7475
/**
7476
* Converts the specified long to its string representation.
7477
*
7478
* @param value
7479
* the long
7480
* @return the long converted to a string
7481
*/
7482
public static String valueOf(long value) {
7483
return Long.toString(value);
7484
}
7485
7486
/**
7487
* Converts the specified object to its string representation. If the object is null answer the string {@code "null"}, otherwise use
7488
* {@code toString()} to get the string representation.
7489
*
7490
* @param value
7491
* the object
7492
* @return the object converted to a string
7493
*/
7494
public static String valueOf(Object value) {
7495
return value != null ? value.toString() : "null"; //$NON-NLS-1$
7496
}
7497
7498
/**
7499
* Converts the specified boolean to its string representation. When the boolean is true answer {@code "true"}, otherwise answer
7500
* {@code "false"}.
7501
*
7502
* @param value
7503
* the boolean
7504
* @return the boolean converted to a string
7505
*/
7506
public static String valueOf(boolean value) {
7507
return value ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$
7508
}
7509
7510
/**
7511
* Answers whether the characters in the StringBuffer buffer are the same as those in this String.
7512
*
7513
* @param buffer
7514
* the StringBuffer to compare this String to
7515
* @return true when the characters in buffer are identical to those in this String. If they are not, false will be returned.
7516
*
7517
* @throws NullPointerException
7518
* when buffer is null
7519
*
7520
* @since 1.4
7521
*/
7522
public boolean contentEquals(StringBuffer buffer) {
7523
synchronized (buffer) {
7524
int size = buffer.length();
7525
7526
if (lengthInternal() != size) {
7527
return false;
7528
}
7529
7530
if (COMPACT_STRINGS && buffer.isCompressed()) {
7531
return regionMatches(0, new String(buffer.getValue(), 0, size, true), 0, size);
7532
} else {
7533
return regionMatches(0, new String(buffer.getValue(), 0, size, false), 0, size);
7534
}
7535
}
7536
}
7537
7538
/**
7539
* Determines whether a this String matches a given regular expression.
7540
*
7541
* @param expr
7542
* the regular expression to be matched
7543
* @return true if the expression matches, otherwise false
7544
*
7545
* @throws PatternSyntaxException
7546
* if the syntax of the supplied regular expression is not valid
7547
* @throws NullPointerException
7548
* if expr is null
7549
*
7550
* @since 1.4
7551
*/
7552
public boolean matches(String expr) {
7553
return Pattern.matches(expr, this);
7554
}
7555
7556
/**
7557
* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.
7558
*
7559
* @param regex
7560
* the regular expression to match
7561
* @param substitute
7562
* the string to replace the matching substring with
7563
* @return the new string
7564
*
7565
* @throws NullPointerException
7566
* if expr is null
7567
*
7568
* @since 1.4
7569
*/
7570
public String replaceAll(String regex, String substitute) {
7571
// this is a fast path to handle replacements of 1 character with another or the deletion of
7572
// a single character (common operations when dealing with things like package names, file
7573
// system paths etc). In these simple cases a linear scan of the string is all that is necessary
7574
// and we can avoid the cost of building a full regex pattern matcher
7575
if (regex != null && substitute != null && regex.lengthInternal() == 1 && !hasMetaChars(regex)) {
7576
int substituteLength = substitute.lengthInternal();
7577
int length = lengthInternal();
7578
if (substituteLength < 2) {
7579
if (COMPACT_STRINGS && isCompressed() && (substituteLength == 0 || substitute.isCompressed())) {
7580
char[] newChars = new char[(length + 1) >>> 1];
7581
byte toReplace = helpers.getByteFromArrayByIndex(regex.value, 0);
7582
byte replacement = (byte)-1; // assign dummy value that will never be used
7583
if (substituteLength == 1) {
7584
replacement = helpers.getByteFromArrayByIndex(substitute.value, 0);
7585
checkLastChar((char)replacement);
7586
}
7587
int newCharIndex = 0;
7588
for (int i = 0; i < length; ++i) {
7589
byte current = helpers.getByteFromArrayByIndex(value, i);
7590
if (current != toReplace) {
7591
helpers.putByteInArrayByIndex(newChars, newCharIndex++, current);
7592
} else if (substituteLength == 1) {
7593
helpers.putByteInArrayByIndex(newChars, newCharIndex++, replacement);
7594
}
7595
}
7596
return new String(newChars, 0, newCharIndex, true);
7597
} else if (!COMPACT_STRINGS || !isCompressed()) {
7598
char[] newChars = new char[length];
7599
char toReplace = regex.charAtInternal(0);
7600
char replacement = (char)-1; // assign dummy value that will never be used
7601
if (substituteLength == 1) {
7602
replacement = substitute.charAtInternal(0);
7603
checkLastChar(replacement);
7604
}
7605
int newCharIndex = 0;
7606
for (int i = 0; i < length; ++i) {
7607
char current = helpers.getCharFromArrayByIndex(value, i);
7608
if (current != toReplace) {
7609
helpers.putCharInArrayByIndex(newChars, newCharIndex++, current);
7610
} else if (substituteLength == 1) {
7611
helpers.putCharInArrayByIndex(newChars, newCharIndex++, replacement);
7612
}
7613
}
7614
return new String(newChars, 0, newCharIndex, false);
7615
}
7616
}
7617
}
7618
return Pattern.compile(regex).matcher(this).replaceAll(substitute);
7619
}
7620
7621
/**
7622
* Replace any substrings within this String that match the supplied regular expression expr, with the String substitute.
7623
*
7624
* @param expr
7625
* the regular expression to match
7626
* @param substitute
7627
* the string to replace the matching substring with
7628
* @return the new string
7629
*
7630
* @throws NullPointerException
7631
* if expr is null
7632
*
7633
* @since 1.4
7634
*/
7635
public String replaceFirst(String expr, String substitute) {
7636
return Pattern.compile(expr).matcher(this).replaceFirst(substitute);
7637
}
7638
7639
/**
7640
* Splits this string around matches of the given regular expression. Calling this method is same as calling split(regex,0). Therefore, empty
7641
* string(s) at the end of the returned array will be discarded.
7642
*
7643
*
7644
* @param regex
7645
* Regular expression that is used as a delimiter
7646
* @return The array of strings which are split around the regex
7647
*
7648
* @throws PatternSyntaxException
7649
* if the syntax of regex is invalid
7650
*
7651
* @since 1.4
7652
*/
7653
public String[] split(String regex) {
7654
return split(regex, 0);
7655
}
7656
7657
private static final char[] regexMetaChars = new char[]
7658
{ '.', '$', '|', '(', ')', '[', ']', '{', '}', '^', '?', '*', '+', '\\' };
7659
7660
private static final boolean hasMetaChars(String s) {
7661
for (int i = 0; i < s.lengthInternal(); ++i) {
7662
char ch = s.charAtInternal(i);
7663
7664
// Note the surrogate ranges are HIGH: \uD800-\uDBFF; LOW: \uDC00-\uDFFF
7665
// this check is, therefore, equivalent to returning true if the character
7666
// falls anywhere in this range including the range between MAX_LOW_SURROGATE
7667
// and MIN_HIGH_SURROGATE which happen to be adjacent
7668
if (ch >= Character.MIN_HIGH_SURROGATE
7669
&& ch <= Character.MAX_LOW_SURROGATE) { return true; }
7670
7671
for (int j = 0; j < regexMetaChars.length; ++j) {
7672
if (ch == regexMetaChars[j]) { return true; }
7673
}
7674
}
7675
return false;
7676
}
7677
7678
private static final boolean isSingleEscapeLiteral(String s) {
7679
if ((s != null) && (s.lengthInternal() == 2) && (s.charAtInternal(0) == '\\')) {
7680
char literal = s.charAtInternal(1);
7681
for (int j = 0; j < regexMetaChars.length; ++j) {
7682
if (literal == regexMetaChars[j]) return true;
7683
}
7684
}
7685
return false;
7686
}
7687
7688
/**
7689
* Splits this String using the given regular expression.
7690
*
7691
* max controls the number of times the regex is applied to this string.
7692
* If max is positive, then regex can be applied to this String max-1 times.
7693
* The returned array size can not be bigger than max, and the last element of
7694
* the returned array contains all input after the last match of the regex.
7695
* If max is negative or zero, then regex can be applied to this string as many times as
7696
* possible and there is no size limit in the returned array.
7697
* If max is 0, all the empty string(s) at the end of the returned array will be discarded.
7698
*
7699
* @param regex Regular expression that is used as a delimiter
7700
* @param max The threshold of the returned array
7701
* @return The array of strings which are split around the regex
7702
*
7703
* @throws PatternSyntaxException if the syntax of regex is invalid
7704
*
7705
* @since 1.4
7706
*/
7707
public String[] split(String regex, int max) {
7708
// it is faster to handle simple splits inline (i.e. no fancy regex matching),
7709
// including single escaped literal character (e.g. \. \{),
7710
// so we test for a suitable string and handle this here if we can
7711
boolean singleEscapeLiteral = isSingleEscapeLiteral(regex);
7712
if ((regex != null) && (regex.lengthInternal() > 0) && (!hasMetaChars(regex) || singleEscapeLiteral)) {
7713
if (max == 1) {
7714
return new String[] { this };
7715
}
7716
java.util.ArrayList<String> parts = new java.util.ArrayList<String>((max > 0 && max < 100) ? max : 10);
7717
7718
char[] chars = this.value;
7719
7720
final boolean compressed = COMPACT_STRINGS && (null == compressionFlag || count >= 0);
7721
7722
int start = 0, current = 0, end = lengthInternal();
7723
if (regex.lengthInternal() == 1 || singleEscapeLiteral) {
7724
// if matching single escaped character, use the second char.
7725
char splitChar = regex.charAtInternal(singleEscapeLiteral ? 1 : 0);
7726
while (current < end) {
7727
if (charAtInternal(current, chars) == splitChar) {
7728
parts.add(new String(chars, start, current - start, compressed));
7729
start = current + 1;
7730
if (max > 0 && parts.size() == max - 1) {
7731
parts.add(new String(chars, start, end - start, compressed));
7732
break;
7733
}
7734
}
7735
current = current + 1;
7736
}
7737
} else {
7738
int rLength = regex.lengthInternal();
7739
7740
char[] splitChars = regex.value;
7741
7742
char firstChar = charAtInternal(0, regex.value);
7743
while (current < end) {
7744
if (charAtInternal(current, chars) == firstChar) {
7745
int idx = current + 1;
7746
int matchIdx = 1;
7747
while (matchIdx < rLength && idx < end) {
7748
if (charAtInternal(idx, chars) != charAtInternal(matchIdx, splitChars)) {
7749
break;
7750
}
7751
matchIdx++;
7752
idx++;
7753
}
7754
if (matchIdx == rLength) {
7755
parts.add(new String(chars, start, current - start, compressed));
7756
start = current + rLength;
7757
if (max > 0 && parts.size() == max - 1) {
7758
parts.add(new String(chars, start, end - start, compressed));
7759
break;
7760
}
7761
current = current + rLength;
7762
continue;
7763
}
7764
}
7765
current = current + 1;
7766
}
7767
}
7768
if (parts.size() == 0) {
7769
return new String[] { this };
7770
} else if (start <= current && parts.size() != max) {
7771
parts.add(new String(chars, start, current - start, compressed));
7772
}
7773
if (max == 0) {
7774
end = parts.size();
7775
while (end > 0 && parts.get(end - 1).lengthInternal() == 0) {
7776
end -= 1;
7777
parts.remove(end);
7778
}
7779
}
7780
return parts.toArray(new String[parts.size()]);
7781
}
7782
return Pattern.compile(regex).split(this, max);
7783
}
7784
7785
/**
7786
* Has the same result as the substring function, but is present so that String may implement the CharSequence interface.
7787
*
7788
* @param start
7789
* the offset the first character
7790
* @param end
7791
* the offset of one past the last character to include
7792
*
7793
* @return the subsequence requested
7794
*
7795
* @throws IndexOutOfBoundsException
7796
* when start or end is less than zero, start is greater than end, or end is greater than the length of the String.
7797
*
7798
* @see java.lang.CharSequence#subSequence(int, int)
7799
*
7800
* @since 1.4
7801
*/
7802
public CharSequence subSequence(int start, int end) {
7803
return substring(start, end);
7804
}
7805
7806
/**
7807
* @param data
7808
* the byte array to convert to a String
7809
* @param start
7810
* the starting offset in the byte array
7811
* @param length
7812
* the number of bytes to convert
7813
*
7814
* @since 1.5
7815
*/
7816
public String(int[] data, int start, int length) {
7817
if (start >= 0 && 0 <= length && length <= data.length - start) {
7818
int size = 0;
7819
7820
// Optimistically assume we can compress data[]
7821
boolean canEncodeAsLatin1 = COMPACT_STRINGS;
7822
7823
for (int i = start; i < start + length; ++i) {
7824
int codePoint = data[i];
7825
7826
if (codePoint < Character.MIN_CODE_POINT) {
7827
throw new IllegalArgumentException();
7828
} else if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
7829
if (canEncodeAsLatin1 && codePoint > 255) {
7830
canEncodeAsLatin1 = false;
7831
}
7832
7833
++size;
7834
} else if (codePoint <= Character.MAX_CODE_POINT) {
7835
if (canEncodeAsLatin1) {
7836
codePoint -= Character.MIN_SUPPLEMENTARY_CODE_POINT;
7837
7838
int codePoint1 = Character.MIN_HIGH_SURROGATE + (codePoint >> 10);
7839
int codePoint2 = Character.MIN_LOW_SURROGATE + (codePoint & 0x3FF);
7840
7841
if (codePoint1 > 255 || codePoint2 > 255) {
7842
canEncodeAsLatin1 = false;
7843
}
7844
}
7845
7846
size += 2;
7847
} else {
7848
throw new IllegalArgumentException();
7849
}
7850
}
7851
7852
if (canEncodeAsLatin1) {
7853
value = new char[(size + 1) >>> 1];
7854
count = size;
7855
7856
for (int i = start, j = 0; i < start + length; ++i) {
7857
int codePoint = data[i];
7858
7859
if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
7860
helpers.putByteInArrayByIndex(value, j++, (byte) codePoint);
7861
} else {
7862
codePoint -= Character.MIN_SUPPLEMENTARY_CODE_POINT;
7863
7864
int codePoint1 = Character.MIN_HIGH_SURROGATE + (codePoint >> 10);
7865
int codePoint2 = Character.MIN_LOW_SURROGATE + (codePoint & 0x3FF);
7866
7867
helpers.putByteInArrayByIndex(value, j++, (byte) codePoint1);
7868
helpers.putByteInArrayByIndex(value, j++, (byte) codePoint2);
7869
}
7870
}
7871
} else {
7872
value = new char[size];
7873
7874
if (COMPACT_STRINGS) {
7875
count = size | uncompressedBit;
7876
7877
initCompressionFlag();
7878
} else {
7879
count = size;
7880
}
7881
7882
for (int i = start, j = 0; i < start + length; ++i) {
7883
int codePoint = data[i];
7884
7885
if (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
7886
value[j++] = (char) codePoint;
7887
} else {
7888
codePoint -= Character.MIN_SUPPLEMENTARY_CODE_POINT;
7889
7890
value[j++] = (char) (Character.MIN_HIGH_SURROGATE + (codePoint >> 10));
7891
value[j++] = (char) (Character.MIN_LOW_SURROGATE + (codePoint & 0x3FF));
7892
}
7893
}
7894
}
7895
} else {
7896
throw new StringIndexOutOfBoundsException();
7897
}
7898
}
7899
7900
/**
7901
* Creates a string from the contents of a StringBuilder.
7902
*
7903
* @param builder
7904
* the StringBuilder
7905
*
7906
* @since 1.5
7907
*/
7908
public String(StringBuilder builder) {
7909
char[] chars = builder.shareValue();
7910
7911
if (COMPACT_STRINGS) {
7912
if (builder.isCompressed()) {
7913
value = chars;
7914
count = builder.lengthInternal();
7915
} else {
7916
value = chars;
7917
count = builder.lengthInternal() | uncompressedBit;
7918
7919
initCompressionFlag();
7920
}
7921
} else {
7922
value = chars;
7923
count = builder.lengthInternal();
7924
}
7925
}
7926
7927
/**
7928
* Returns the Unicode character at the given point.
7929
*
7930
* @param index
7931
* the character index
7932
* @return the Unicode character value at the index
7933
*
7934
* @since 1.5
7935
*/
7936
public int codePointAt(int index) {
7937
int len = lengthInternal();
7938
7939
if (index >= 0 && index < len) {
7940
// Check if the String is compressed
7941
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
7942
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
7943
} else {
7944
char high = charAtInternal(index);
7945
7946
if ((index < (len - 1)) && Character.isHighSurrogate(high)) {
7947
char low = charAtInternal(index + 1);
7948
7949
if (Character.isLowSurrogate(low)) {
7950
return Character.toCodePoint(high, low);
7951
}
7952
}
7953
7954
return high;
7955
}
7956
} else {
7957
throw new StringIndexOutOfBoundsException(index);
7958
}
7959
}
7960
7961
/**
7962
* Returns the Unicode character before the given point.
7963
*
7964
* @param index
7965
* the character index
7966
* @return the Unicode character value before the index
7967
*
7968
* @since 1.5
7969
*/
7970
public int codePointBefore(int index) {
7971
int len = lengthInternal();
7972
7973
if (index > 0 && index <= len) {
7974
// Check if the String is compressed
7975
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
7976
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));
7977
} else {
7978
char low = charAtInternal(index - 1);
7979
7980
if ((index > 1) && Character.isLowSurrogate(low)) {
7981
char high = charAtInternal(index - 2);
7982
7983
if (Character.isHighSurrogate(high)) {
7984
return Character.toCodePoint(high, low);
7985
}
7986
}
7987
7988
return low;
7989
}
7990
} else {
7991
throw new StringIndexOutOfBoundsException(index);
7992
}
7993
}
7994
7995
/**
7996
* Returns the total Unicode values in the specified range.
7997
*
7998
* @param start
7999
* first index
8000
* @param end
8001
* last index
8002
* @return the total Unicode values
8003
*
8004
* @since 1.5
8005
*/
8006
public int codePointCount(int start, int end) {
8007
int len = lengthInternal();
8008
8009
if (start >= 0 && start <= end && end <= len) {
8010
// Check if the String is compressed
8011
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
8012
return end - start;
8013
} else {
8014
int count = 0;
8015
8016
for (int i = start; i < end; ++i) {
8017
if ((i < (end - 1))
8018
&& Character.isHighSurrogate(charAtInternal(i))
8019
&& Character.isLowSurrogate(charAtInternal(i + 1))) {
8020
++i;
8021
}
8022
8023
++count;
8024
}
8025
8026
return count;
8027
}
8028
} else {
8029
throw new IndexOutOfBoundsException();
8030
}
8031
}
8032
8033
/**
8034
* Returns the index of the code point that was offset by codePointCount.
8035
*
8036
* @param start
8037
* the position to offset
8038
* @param codePointCount
8039
* the code point count
8040
* @return the offset index
8041
*
8042
* @since 1.5
8043
*/
8044
public int offsetByCodePoints(int start, int codePointCount) {
8045
int len = lengthInternal();
8046
8047
if (start >= 0 && start <= len) {
8048
// Check if the String is compressed
8049
if (COMPACT_STRINGS && (null == compressionFlag || count >= 0)) {
8050
int index = start + codePointCount;
8051
8052
if (index > len) {
8053
throw new IndexOutOfBoundsException();
8054
} else {
8055
return index;
8056
}
8057
} else {
8058
int index = start;
8059
8060
if (codePointCount == 0) {
8061
return start;
8062
} else if (codePointCount > 0) {
8063
for (int i = 0; i < codePointCount; ++i) {
8064
if (index == len) {
8065
throw new IndexOutOfBoundsException();
8066
}
8067
8068
if ((index < (len - 1))
8069
&& Character.isHighSurrogate(charAtInternal(index))
8070
&& Character.isLowSurrogate(charAtInternal(index + 1))) {
8071
index++;
8072
}
8073
8074
index++;
8075
}
8076
} else {
8077
for (int i = codePointCount; i < 0; ++i) {
8078
if (index < 1) {
8079
throw new IndexOutOfBoundsException();
8080
}
8081
8082
if ((index > 1)
8083
&& Character.isLowSurrogate(charAtInternal(index - 1))
8084
&& Character.isHighSurrogate(charAtInternal(index - 2))) {
8085
index--;
8086
}
8087
8088
index--;
8089
}
8090
}
8091
8092
return index;
8093
}
8094
} else {
8095
throw new IndexOutOfBoundsException();
8096
}
8097
}
8098
8099
/**
8100
* Compares the content of the character sequence to this String
8101
*
8102
* @param sequence
8103
* the character sequence
8104
* @return {@code true} if the content of this String is equal to the character sequence, {@code false} otherwise.
8105
*
8106
* @since 1.5
8107
*/
8108
public boolean contentEquals(CharSequence sequence) {
8109
int len = lengthInternal();
8110
8111
if (len != sequence.length()) {
8112
return false;
8113
}
8114
8115
for (int i = 0; i < len; ++i) {
8116
if (charAtInternal(i) != sequence.charAt(i)) {
8117
return false;
8118
}
8119
}
8120
8121
return true;
8122
}
8123
8124
/**
8125
* @param sequence
8126
* the sequence to compare to
8127
* @return {@code true} if this String contains the sequence, {@code false} otherwise.
8128
*
8129
* @since 1.5
8130
*/
8131
public boolean contains(CharSequence sequence) {
8132
int len = lengthInternal();
8133
8134
int sequencelen = sequence.length();
8135
8136
if (sequencelen > len) {
8137
return false;
8138
}
8139
8140
int start = 0;
8141
8142
if (sequencelen > 0) {
8143
if (sequencelen + start > len) {
8144
return false;
8145
}
8146
8147
char charAt0 = sequence.charAt(0);
8148
8149
while (true) {
8150
int i = indexOf(charAt0, start);
8151
8152
if (i == -1 || sequencelen + i > len) {
8153
return false;
8154
}
8155
8156
int o1 = i;
8157
int o2 = 0;
8158
8159
while (++o2 < sequencelen && charAtInternal(++o1) == sequence.charAt(o2))
8160
;
8161
8162
if (o2 == sequencelen) {
8163
return true;
8164
}
8165
8166
start = i + 1;
8167
}
8168
} else {
8169
return true;
8170
}
8171
}
8172
8173
/**
8174
* @param sequence1
8175
* the old character sequence
8176
* @param sequence2
8177
* the new character sequence
8178
* @return the new String
8179
*
8180
* @since 1.5
8181
*/
8182
public String replace(CharSequence sequence1, CharSequence sequence2) {
8183
if (sequence2 == null) {
8184
throw new NullPointerException();
8185
}
8186
8187
int len = lengthInternal();
8188
8189
int sequence1len = sequence1.length();
8190
8191
if (sequence1len == 0) {
8192
int sequence2len = sequence2.length();
8193
8194
if ((sequence2len != 0) && (len >= ((Integer.MAX_VALUE - len) / sequence2len))) {
8195
/*[MSG "K0D01", "Array capacity exceeded"]*/
8196
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
8197
}
8198
8199
StringBuilder builder = new StringBuilder(len + ((len + 1) * sequence2len));
8200
8201
builder.append(sequence2);
8202
8203
for (int i = 0; i < len; ++i) {
8204
builder.append(charAt(i)).append(sequence2);
8205
}
8206
8207
return builder.toString();
8208
} else {
8209
StringBuilder builder = new StringBuilder();
8210
8211
int start = 0;
8212
int copyStart = 0;
8213
8214
char charAt0 = sequence1.charAt(0);
8215
8216
while (start < len) {
8217
int firstIndex = indexOf(charAt0, start);
8218
8219
if (firstIndex == -1) {
8220
break;
8221
}
8222
8223
boolean found = true;
8224
8225
if (sequence1len > 1) {
8226
if (sequence1len > len - firstIndex) {
8227
/* the tail of this string is too short to find sequence1 */
8228
break;
8229
}
8230
8231
for (int i = 1; i < sequence1len; i++) {
8232
if (charAt(firstIndex + i) != sequence1.charAt(i)) {
8233
found = false;
8234
break;
8235
}
8236
}
8237
}
8238
8239
if (found) {
8240
builder.append(substring(copyStart, firstIndex)).append(sequence2);
8241
8242
copyStart = start = firstIndex + sequence1len;
8243
} else {
8244
start = firstIndex + 1;
8245
}
8246
}
8247
8248
if (builder.length() == 0 && copyStart == 0) {
8249
return this;
8250
}
8251
8252
builder.append(substring(copyStart));
8253
8254
return builder.toString();
8255
}
8256
}
8257
8258
/**
8259
* Format the receiver using the specified format and args.
8260
*
8261
* @param format
8262
* the format to use
8263
* @param args
8264
* the format arguments to use
8265
*
8266
* @return the formatted result
8267
*
8268
* @see java.util.Formatter#format(String, Object...)
8269
*/
8270
public static String format(String format, Object... args) {
8271
return new Formatter().format(format, args).toString();
8272
}
8273
8274
/**
8275
* Format the receiver using the specified local, format and args.
8276
*
8277
* @param locale
8278
* the locale used to create the Formatter, may be null
8279
* @param format
8280
* the format to use
8281
* @param args
8282
* the format arguments to use
8283
*
8284
* @return the formatted result
8285
*
8286
* @see java.util.Formatter#format(String, Object...)
8287
*/
8288
public static String format(Locale locale, String format, Object... args) {
8289
return new Formatter(locale).format(format, args).toString();
8290
}
8291
8292
private static final java.io.ObjectStreamField[] serialPersistentFields = {};
8293
8294
/**
8295
* Answers if this String has no characters, a length of zero.
8296
*
8297
* @return true if this String has no characters, false otherwise
8298
*
8299
* @since 1.6
8300
*
8301
* @see #length
8302
*/
8303
public boolean isEmpty() {
8304
return lengthInternal() == 0;
8305
}
8306
8307
/**
8308
* Converts the byte array to a String using the specified Charset.
8309
*
8310
* @param data
8311
* the byte array to convert to a String
8312
* @param charset
8313
* the Charset to use
8314
*
8315
* @throws NullPointerException
8316
* when data is null
8317
*
8318
* @since 1.6
8319
*
8320
* @see #String(byte[], int, int, Charset)
8321
* @see #getBytes(Charset)
8322
*/
8323
public String(byte[] data, Charset charset) {
8324
this(data, 0, data.length, charset);
8325
}
8326
8327
/**
8328
* Converts the byte array to a String using the specified Charset.
8329
*
8330
* @param data
8331
* the byte array to convert to a String
8332
* @param start
8333
* the starting offset in the byte array
8334
* @param length
8335
* the number of bytes to convert
8336
* @param charset
8337
* the Charset to use
8338
*
8339
* @throws IndexOutOfBoundsException
8340
* when {@code length < 0, start < 0} or {@code start + length > data.length}
8341
* @throws NullPointerException
8342
* when data is null
8343
*
8344
* @since 1.6
8345
*
8346
* @see #String(byte[], Charset)
8347
* @see #getBytes(Charset)
8348
*/
8349
public String(byte[] data, int start, int length, Charset charset) {
8350
if (charset == null) {
8351
throw new NullPointerException();
8352
}
8353
8354
if (start >= 0 && 0 <= length && length <= data.length - start) {
8355
char[] chars = StringCoding.decode(charset, data, start, length);
8356
8357
if (COMPACT_STRINGS) {
8358
if (canEncodeAsLatin1(chars, 0, chars.length)) {
8359
value = new char[(chars.length + 1) >>> 1];
8360
count = chars.length;
8361
8362
compress(chars, 0, value, 0, chars.length);
8363
} else {
8364
value = chars;
8365
count = chars.length | uncompressedBit;
8366
8367
initCompressionFlag();
8368
}
8369
} else {
8370
value = chars;
8371
count = chars.length;
8372
}
8373
} else {
8374
throw new StringIndexOutOfBoundsException();
8375
}
8376
}
8377
8378
/**
8379
* Converts this String to a byte encoding using the specified Charset.
8380
*
8381
* @param charset
8382
* the Charset to use
8383
* @return the byte array encoding of this String
8384
*
8385
* @since 1.6
8386
*/
8387
public byte[] getBytes(Charset charset) {
8388
int currentLength = lengthInternal();
8389
8390
char[] buffer;
8391
8392
// Check if the String is compressed
8393
if (COMPACT_STRINGS && count >= 0) {
8394
buffer = new char[currentLength];
8395
decompress(value, 0, buffer, 0, currentLength);
8396
} else {
8397
buffer = value;
8398
}
8399
8400
return StringCoding.encode(charset, buffer, 0, currentLength);
8401
}
8402
8403
/**
8404
* 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.
8405
*
8406
* @param delimiter
8407
* Used as joiner to put elements together
8408
* @param elements
8409
* Elements to be joined
8410
* @return string of joined elements by delimiter
8411
* @throws NullPointerException
8412
* if one of the arguments is null
8413
*/
8414
public static String join(CharSequence delimiter, CharSequence... elements) {
8415
StringJoiner stringJoiner = new StringJoiner(delimiter);
8416
8417
for (CharSequence element : elements) {
8418
stringJoiner.add(element);
8419
}
8420
8421
return stringJoiner.toString();
8422
}
8423
8424
/**
8425
* 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.
8426
*
8427
* @param delimiter
8428
* Used as joiner to put elements together
8429
* @param elements
8430
* Elements to be joined
8431
* @return string of joined elements by delimiter
8432
* @throws NullPointerException
8433
* if one of the arguments is null
8434
*/
8435
public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {
8436
StringJoiner stringJoiner = new StringJoiner(delimiter);
8437
8438
Iterator<? extends CharSequence> elementsIterator = elements.iterator();
8439
8440
while (elementsIterator.hasNext()) {
8441
stringJoiner.add(elementsIterator.next());
8442
}
8443
8444
return stringJoiner.toString();
8445
}
8446
8447
/*[ENDIF] Sidecar19-SE*/
8448
8449
/*[IF JAVA_SPEC_VERSION >= 12]*/
8450
/**
8451
* Apply a function to this string. The function expects a single String input
8452
* and returns an R.
8453
*
8454
* @param f
8455
* the functional interface to be applied
8456
*
8457
* @return the result of application of the function to this string
8458
*
8459
* @since 12
8460
*/
8461
public <R> R transform(Function<? super String, ? extends R> f) {
8462
return f.apply(this);
8463
}
8464
8465
/**
8466
* Returns the nominal descriptor of this String instance, or an empty optional
8467
* if construction is not possible.
8468
*
8469
* @return Optional with nominal descriptor of String instance
8470
*
8471
* @since 12
8472
*/
8473
public Optional<String> describeConstable() {
8474
return Optional.of(this);
8475
}
8476
8477
/**
8478
* Resolves this ConstantDesc instance.
8479
*
8480
* @param lookup
8481
* parameter is ignored
8482
*
8483
* @return the resolved Constable value
8484
*
8485
* @since 12
8486
*/
8487
public String resolveConstantDesc(MethodHandles.Lookup lookup) {
8488
return this;
8489
}
8490
8491
/**
8492
* Indents each line of the string depending on the value of n, and normalizes
8493
* line terminators to the newline character "\n".
8494
*
8495
* @param n
8496
* the number of spaces to indent the string
8497
*
8498
* @return the indented string with normalized line terminators
8499
*
8500
* @since 12
8501
*/
8502
public String indent(int n) {
8503
Stream<String> lines = lines();
8504
Iterator<String> iter = lines.iterator();
8505
StringBuilder builder = new StringBuilder();
8506
8507
String spaces = n > 0 ? " ".repeat(n) : null;
8508
int absN = Math.abs(n);
8509
8510
while (iter.hasNext()) {
8511
String currentLine = iter.next();
8512
8513
if (n > 0) {
8514
builder.append(spaces);
8515
} else if (n < 0) {
8516
int start = 0;
8517
8518
while ((currentLine.length() > start)
8519
&& (Character.isWhitespace(currentLine.charAt(start)))
8520
) {
8521
start++;
8522
8523
if (start >= absN) {
8524
break;
8525
}
8526
}
8527
currentLine = currentLine.substring(start);
8528
}
8529
8530
/**
8531
* Line terminators are removed when lines() is called. A newline character is
8532
* added to the end of each line, to normalize line terminators.
8533
*/
8534
builder.append(currentLine);
8535
builder.append("\n");
8536
}
8537
8538
return builder.toString();
8539
}
8540
/*[ENDIF] JAVA_SPEC_VERSION >= 12 */
8541
8542
/*[IF JAVA_SPEC_VERSION >= 13]*/
8543
/**
8544
* Determine if current String object is LATIN1.
8545
*
8546
* @return true if it is LATIN1, otherwise false.
8547
*/
8548
boolean isLatin1() {
8549
return LATIN1 == coder();
8550
}
8551
8552
/**
8553
* Format the string using this string as the format with supplied args.
8554
*
8555
* @param args
8556
* the format arguments to use
8557
*
8558
* @return the formatted result
8559
*
8560
* @see #format(String, Object...)
8561
*
8562
* @since 15
8563
*/
8564
public String formatted(Object... args) {
8565
return String.format(this, args);
8566
}
8567
8568
/**
8569
* Removes the minimum indentation from the beginning of each line and
8570
* removes the trailing spaces in every line from the string
8571
*
8572
* @return this string with incidental whitespaces removed from every line
8573
*
8574
* @since 15
8575
*/
8576
public String stripIndent() {
8577
if (isEmpty()) {
8578
return this;
8579
}
8580
8581
char lastChar = charAt(length() - 1);
8582
boolean trailingNewLine = ('\n' == lastChar) || ('\r' == lastChar);
8583
8584
Iterator<String> iter = lines().iterator();
8585
int min = Integer.MAX_VALUE;
8586
8587
if (trailingNewLine) {
8588
min = 0;
8589
} else {
8590
while (iter.hasNext()) {
8591
String line = iter.next();
8592
8593
/* The minimum indentation is calculated based on the number of leading
8594
* whitespace characters from all non-blank lines and the last line even
8595
* if it is blank.
8596
*/
8597
if (!line.isBlank() || !iter.hasNext()) {
8598
int count = 0;
8599
int limit = Math.min(min, line.length());
8600
while ((count < limit) && Character.isWhitespace(line.charAt(count))) {
8601
count++;
8602
}
8603
8604
if (min > count) {
8605
min = count;
8606
}
8607
}
8608
}
8609
/* reset iterator to beginning of the string */
8610
iter = lines().iterator();
8611
}
8612
8613
StringBuilder builder = new StringBuilder();
8614
8615
while (iter.hasNext()) {
8616
String line = iter.next();
8617
8618
if (line.isBlank()) {
8619
builder.append("");
8620
} else {
8621
line = line.substring(min);
8622
builder.append(line.stripTrailing());
8623
}
8624
builder.append("\n");
8625
}
8626
8627
8628
if (!trailingNewLine) {
8629
builder.setLength(builder.length() - 1);
8630
}
8631
8632
return builder.toString();
8633
}
8634
8635
/**
8636
* Translate the escape sequences in this string as if in a string literal
8637
*
8638
* @return result string after translation
8639
*
8640
* @throws IllegalArgumentException
8641
* If invalid escape sequence is detected
8642
*
8643
* @since 15
8644
*/
8645
public String translateEscapes() {
8646
StringBuilder builder = new StringBuilder();
8647
char[] charArray = toCharArray();
8648
int index = 0;
8649
int strLength = length();
8650
while (index < strLength) {
8651
if ('\\' == charArray[index]) {
8652
index++;
8653
if (index >= strLength) {
8654
/*[MSG "K0D00", "Invalid escape sequence detected: {0}"]*/
8655
throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0D00", "\\")); //$NON-NLS-1$ //$NON-NLS-2$
8656
}
8657
int octal = 0;
8658
switch (charArray[index]) {
8659
case 'b':
8660
builder.append('\b');
8661
break;
8662
case 't':
8663
builder.append('\t');
8664
break;
8665
case 'n':
8666
builder.append('\n');
8667
break;
8668
case 'f':
8669
builder.append('\f');
8670
break;
8671
case 'r':
8672
builder.append('\r');
8673
break;
8674
case 's':
8675
builder.append(' '); /* '\s' is a new escape sequence for space (U+0020) added in JEP 368: Text Blocks (Second Preview) */
8676
break;
8677
case '\"':
8678
case '\'':
8679
case '\\':
8680
builder.append(charArray[index]);
8681
break;
8682
case '0':
8683
case '1':
8684
case '2':
8685
case '3':
8686
octal = charArray[index] - '0';
8687
/* If the octal escape sequence only has a single digit, then translate the escape and search for next escape sequence
8688
* If there is more than one digit, fall though to case 4-7 and save the current digit as the first digit of the sequence
8689
*/
8690
if ((index < strLength - 1) && ('0' <= charArray[index + 1]) && ('7' >= charArray[index + 1])) {
8691
index++;
8692
} else {
8693
builder.append((char)octal);
8694
break;
8695
}
8696
//$FALL-THROUGH$
8697
case '4':
8698
case '5':
8699
case '6':
8700
case '7':
8701
/* Shift octal value (either 0 or value fall through from the previous case) left one digit then add the current digit */
8702
octal = (octal * 010) + (charArray[index] - '0');
8703
8704
/* Check for last possible digit in octal escape sequence */
8705
if ((index < strLength - 1) && ('0' <= charArray[index + 1]) && ('7' >= charArray[index + 1])) {
8706
index++;
8707
octal = (octal * 010) + (charArray[index] - '0');
8708
}
8709
builder.append((char)octal);
8710
break;
8711
/**
8712
* JEP 368: Text Blocks (Second Preview)
8713
* '\r', "\r\n" and '\n' are ignored as per new continuation \<line-terminator> escape sequence
8714
* i.e. ignore line terminator and continue line
8715
* */
8716
case '\r':
8717
/* Check if the next character is the newline character, i.e. case "\r\n" */
8718
if (((index + 1) < strLength) && ('\n' == charArray[index + 1])) {
8719
index++;
8720
}
8721
break;
8722
case '\n':
8723
break;
8724
default:
8725
/*[MSG "K0D00", "Invalid escape sequence detected: {0}"]*/
8726
throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0D00", "\\" + charArray[index])); //$NON-NLS-1$ //$NON-NLS-2$
8727
}
8728
} else {
8729
builder.append(charArray[index]);
8730
}
8731
index++;
8732
}
8733
return builder.toString();
8734
}
8735
/*[ENDIF] JAVA_SPEC_VERSION >= 13 */
8736
}
8737
8738