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/StringBuilder.java
12513 views
1
/*[INCLUDE-IF JAVA_SPEC_VERSION == 8]*/
2
/*******************************************************************************
3
* Copyright (c) 2005, 2022 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.IOException;
26
import java.io.ObjectInputStream;
27
import java.io.ObjectOutputStream;
28
import java.io.Serializable;
29
import java.io.StreamCorruptedException;
30
import java.util.Arrays;
31
import java.util.Properties;
32
33
/**
34
* StringBuilder is not thread safe. For a synchronized implementation, use
35
* StringBuffer.
36
*
37
* StringBuilder is a variable size contiguous indexable array of characters.
38
* The length of the StringBuilder is the number of characters it contains.
39
* The capacity of the StringBuilder is the number of characters it can hold.
40
* <p>
41
* Characters may be inserted at any position up to the length of the
42
* StringBuilder, increasing the length of the StringBuilder. Characters at any
43
* position in the StringBuilder may be replaced, which does not affect the
44
* StringBuilder length.
45
* <p>
46
* The capacity of a StringBuilder may be specified when the StringBuilder is
47
* created. If the capacity of the StringBuilder is exceeded, the capacity
48
* is increased.
49
*
50
* @author OTI
51
* @version initial
52
*
53
* @see StringBuffer
54
*
55
* @since 1.5
56
*/
57
public final class StringBuilder extends AbstractStringBuilder implements Serializable, CharSequence, Appendable {
58
private static final long serialVersionUID = 4383685877147921099L;
59
60
private static final int INITIAL_SIZE = 16;
61
62
private static boolean TOSTRING_COPY_BUFFER_ENABLED = false;
63
private static boolean growAggressively = false;
64
65
// Used to access compression related helper methods
66
private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();
67
68
// Represents the bit in count field to test for whether this StringBuilder backing array is not compressed
69
// under String compression mode. This bit is not used when String compression is disabled.
70
private static final int uncompressedBit = 0x80000000;
71
72
// Represents the bit in capacity field to test for whether this StringBuilder backing array is shared.
73
private static final int sharedBit = 0x80000000;
74
75
private transient int count;
76
private transient char[] value;
77
private transient int capacity;
78
79
private int decompress(int min) {
80
int currentLength = lengthInternal();
81
int currentCapacity = capacityInternal();
82
char[] newValue;
83
84
if (min > currentCapacity) {
85
/* twice may be negative, in which case we'll use min */
86
int twice = (currentCapacity << 1) + 2;
87
88
newValue = new char[min > twice ? min : twice];
89
} else {
90
newValue = new char[currentCapacity];
91
}
92
93
String.decompress(value, 0, newValue, 0, currentLength);
94
95
count = count | uncompressedBit;
96
value = newValue;
97
capacity = newValue.length;
98
99
String.initCompressionFlag();
100
return capacity;
101
}
102
103
/**
104
* Constructs a new StringBuffer using the default capacity.
105
*/
106
public StringBuilder() {
107
this(INITIAL_SIZE);
108
}
109
110
/**
111
* Constructs a new StringBuilder using the specified capacity.
112
*
113
* @param capacity the initial capacity
114
*/
115
public StringBuilder(int capacity) {
116
/* capacity argument is used to determine the byte/char array size. If
117
* capacity argument is Integer.MIN_VALUE (-2147483648), then capacity *= 2
118
* will yield a non-negative number due to overflow. We will fail to throw
119
* NegativeArraySizeException. The check below will assure that
120
* NegativeArraySizeException is thrown if capacity argument is less than 0.
121
*/
122
if (capacity < 0) {
123
throw new NegativeArraySizeException(String.valueOf(capacity));
124
}
125
int arraySize = capacity;
126
127
if (String.COMPACT_STRINGS) {
128
arraySize = (capacity + 1) >>> 1;
129
}
130
value = new char[arraySize];
131
132
this.capacity = capacity;
133
}
134
135
/**
136
* Constructs a new StringBuilder containing the characters in
137
* the specified string and the default capacity.
138
*
139
* @param string the initial contents of this StringBuilder
140
* @exception NullPointerException when string is null
141
*/
142
public StringBuilder (String string) {
143
int stringLength = string.lengthInternal();
144
145
int newLength = stringLength + INITIAL_SIZE;
146
if (newLength < stringLength) {
147
newLength = stringLength;
148
}
149
150
if (String.COMPACT_STRINGS) {
151
if (string.isCompressed ()) {
152
value = new char[(newLength + 1) >>> 1];
153
154
capacity = newLength;
155
156
string.getBytes(0, stringLength, value, 0);
157
158
count = stringLength;
159
} else {
160
value = new char[newLength];
161
162
string.getCharsNoBoundChecks(0, stringLength, value, 0);
163
164
capacity = newLength;
165
166
count = stringLength | uncompressedBit;
167
168
String.initCompressionFlag();
169
}
170
} else {
171
value = new char[newLength];
172
173
string.getCharsNoBoundChecks(0, stringLength, value, 0);
174
175
capacity = newLength;
176
177
count = stringLength;
178
}
179
}
180
181
/**
182
* Adds the character array to the end of this StringBuilder.
183
*
184
* @param chars the character array
185
* @return this StringBuilder
186
*
187
* @exception NullPointerException when chars is null
188
*/
189
public StringBuilder append (char[] chars) {
190
int currentLength = lengthInternal();
191
int currentCapacity = capacityInternal();
192
193
int newLength = currentLength + chars.length;
194
if (newLength < 0) {
195
/*[MSG "K0D01", "Array capacity exceeded"]*/
196
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
197
}
198
199
if (String.COMPACT_STRINGS) {
200
// Check if the StringBuilder is compressed
201
if (count >= 0 && String.canEncodeAsLatin1(chars, 0, chars.length)) {
202
if (newLength > currentCapacity) {
203
ensureCapacityImpl(newLength);
204
}
205
206
String.compress(chars, 0, value, currentLength, chars.length);
207
208
count = newLength;
209
} else {
210
// Check if the StringBuilder is compressed
211
if (count >= 0) {
212
currentCapacity = decompress(newLength);
213
}
214
215
if (newLength > currentCapacity) {
216
ensureCapacityImpl(newLength);
217
}
218
219
String.decompressedArrayCopy(chars, 0, value, currentLength, chars.length);
220
221
count = newLength | uncompressedBit;
222
}
223
} else {
224
if (newLength > currentCapacity) {
225
ensureCapacityImpl(newLength);
226
}
227
228
String.decompressedArrayCopy(chars, 0, value, currentLength, chars.length);
229
230
count = newLength;
231
}
232
233
return this;
234
}
235
236
/**
237
* Adds the specified sequence of characters to the end of
238
* this StringBuilder.
239
*
240
* @param chars a character array
241
* @param start the starting offset
242
* @param length the number of characters
243
* @return this StringBuilder
244
*
245
* @exception IndexOutOfBoundsException when {@code length < 0, start < 0} or
246
* {@code start + length > chars.length}
247
* @exception NullPointerException when chars is null
248
*/
249
public StringBuilder append (char chars[], int start, int length) {
250
if (start >= 0 && 0 <= length && length <= chars.length - start) {
251
int currentLength = lengthInternal();
252
int currentCapacity = capacityInternal();
253
254
int newLength = currentLength + length;
255
if (newLength < 0) {
256
/*[MSG "K0D01", "Array capacity exceeded"]*/
257
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
258
}
259
260
if (String.COMPACT_STRINGS) {
261
// Check if the StringBuilder is compressed
262
if (count >= 0 && String.canEncodeAsLatin1(chars, start, length)) {
263
if (newLength > currentCapacity) {
264
ensureCapacityImpl(newLength);
265
}
266
267
String.compress(chars, start, value, currentLength, length);
268
269
count = newLength;
270
} else {
271
// Check if the StringBuilder is compressed
272
if (count >= 0) {
273
currentCapacity = decompress(newLength);
274
}
275
276
if (newLength > currentCapacity) {
277
ensureCapacityImpl(newLength);
278
}
279
280
String.decompressedArrayCopy(chars, start, value, currentLength, length);
281
282
count = newLength | uncompressedBit;
283
}
284
} else {
285
if (newLength > currentCapacity) {
286
ensureCapacityImpl(newLength);
287
}
288
289
String.decompressedArrayCopy(chars, start, value, currentLength, length);
290
291
count = newLength;
292
}
293
294
return this;
295
} else {
296
throw new StringIndexOutOfBoundsException();
297
}
298
}
299
300
StringBuilder append (char[] chars, int start, int length, boolean compressed) {
301
int currentLength = lengthInternal();
302
int currentCapacity = capacityInternal();
303
304
int newLength = currentLength + length;
305
if (newLength < 0) {
306
/*[MSG "K0D01", "Array capacity exceeded"]*/
307
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
308
}
309
310
if (String.COMPACT_STRINGS) {
311
// Check if the StringBuilder is compressed
312
if (count >= 0 && compressed) {
313
if (newLength > currentCapacity) {
314
ensureCapacityImpl(newLength);
315
}
316
317
String.compressedArrayCopy(chars, start, value, currentLength, length);
318
319
count = newLength;
320
} else {
321
// Check if the StringBuilder is compressed
322
if (count >= 0) {
323
currentCapacity = decompress(newLength);
324
}
325
326
if (newLength > currentCapacity) {
327
ensureCapacityImpl(newLength);
328
}
329
330
if (compressed) {
331
String.decompress(chars, start, value, currentLength, length);
332
} else {
333
String.decompressedArrayCopy(chars, start, value, currentLength, length);
334
}
335
336
count = newLength | uncompressedBit;
337
}
338
} else {
339
if (newLength > currentCapacity) {
340
ensureCapacityImpl(newLength);
341
}
342
343
if (compressed) {
344
String.decompress(chars, start, value, currentLength, length);
345
} else {
346
String.decompressedArrayCopy(chars, start, value, currentLength, length);
347
}
348
349
count = newLength;
350
}
351
352
return this;
353
}
354
355
/**
356
* Adds the specified character to the end of
357
* this StringBuilder.
358
*
359
* @param ch a character
360
* @return this StringBuilder
361
*/
362
@Override
363
public StringBuilder append(char ch) {
364
int currentLength = lengthInternal();
365
int currentCapacity = capacityInternal();
366
367
int newLength = currentLength + 1;
368
if (newLength < 0) {
369
/*[MSG "K0D01", "Array capacity exceeded"]*/
370
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
371
}
372
373
if (String.COMPACT_STRINGS) {
374
// Check if the StringBuilder is compressed
375
if (count >= 0 && ch <= 255) {
376
if (newLength > currentCapacity) {
377
ensureCapacityImpl(newLength);
378
}
379
380
helpers.putByteInArrayByIndex(value, currentLength, (byte) ch);
381
382
count = newLength;
383
} else {
384
// Check if the StringBuilder is compressed
385
if (count >= 0) {
386
currentCapacity = decompress(newLength);
387
}
388
389
if (newLength > currentCapacity) {
390
ensureCapacityImpl(newLength);
391
}
392
393
value[currentLength] = ch;
394
395
count = newLength | uncompressedBit;
396
}
397
} else {
398
if (newLength > currentCapacity) {
399
ensureCapacityImpl(newLength);
400
}
401
402
value[currentLength] = ch;
403
404
count = newLength;
405
}
406
407
return this;
408
}
409
410
/**
411
* Adds the string representation of the specified double to the
412
* end of this StringBuilder.
413
*
414
* @param value the double
415
* @return this StringBuilder
416
*/
417
public StringBuilder append (double value) {
418
return append (String.valueOf (value));
419
}
420
421
/**
422
* Adds the string representation of the specified float to the
423
* end of this StringBuilder.
424
*
425
* @param value the float
426
* @return this StringBuilder
427
*/
428
public StringBuilder append (float value) {
429
return append (String.valueOf (value));
430
}
431
432
/**
433
* Adds the string representation of the specified integer to the
434
* end of this StringBuilder.
435
*
436
* @param value the integer
437
* @return this StringBuilder
438
*/
439
public StringBuilder append(int value) {
440
if (value != Integer.MIN_VALUE) {
441
if (String.COMPACT_STRINGS && count >= 0) {
442
return append(Integer.toString(value));
443
} else {
444
int currentLength = lengthInternal();
445
int currentCapacity = capacityInternal();
446
447
int valueLength;
448
if (value < 0) {
449
/* stringSize can't handle negative numbers in Java 8 */
450
valueLength = Integer.stringSize(-value) + 1;
451
} else {
452
valueLength = Integer.stringSize(value);
453
}
454
455
int newLength = currentLength + valueLength;
456
if (newLength < 0) {
457
/*[MSG "K0D01", "Array capacity exceeded"]*/
458
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
459
}
460
461
if (newLength > currentCapacity) {
462
ensureCapacityImpl(newLength);
463
}
464
465
Integer.getChars(value, newLength, this.value);
466
467
if (String.COMPACT_STRINGS) {
468
count = newLength | uncompressedBit;
469
} else {
470
count = newLength;
471
}
472
473
return this;
474
}
475
} else {
476
// Append Integer.MIN_VALUE as a String
477
return append("-2147483648"); //$NON-NLS-1$
478
}
479
}
480
481
/**
482
* Adds the string representation of the specified long to the
483
* end of this StringBuilder.
484
*
485
* @param value the long
486
* @return this StringBuilder
487
*/
488
public StringBuilder append(long value) {
489
if (value != Long.MIN_VALUE) {
490
if (String.COMPACT_STRINGS && count >= 0) {
491
return append(Long.toString(value));
492
} else {
493
int currentLength = lengthInternal();
494
int currentCapacity = capacityInternal();
495
496
int valueLength;
497
if (value < 0) {
498
/* stringSize can't handle negative numbers in Java 8 */
499
valueLength = Long.stringSize(-value) + 1;
500
} else {
501
valueLength = Long.stringSize(value);
502
}
503
504
int newLength = currentLength + valueLength;
505
if (newLength < 0) {
506
/*[MSG "K0D01", "Array capacity exceeded"]*/
507
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
508
}
509
510
if (newLength > currentCapacity) {
511
ensureCapacityImpl(newLength);
512
}
513
514
Long.getChars(value, newLength, this.value);
515
516
if (String.COMPACT_STRINGS) {
517
count = newLength | uncompressedBit;
518
} else {
519
count = newLength;
520
}
521
522
return this;
523
}
524
} else {
525
// Append Long.MIN_VALUE as a String
526
return append("-9223372036854775808"); //$NON-NLS-1$
527
}
528
}
529
530
/**
531
* Adds the string representation of the specified object to the
532
* end of this StringBuilder.
533
*
534
* @param value the object
535
* @return this StringBuilder
536
*/
537
public StringBuilder append (Object value) {
538
return append (String.valueOf (value));
539
}
540
541
/**
542
* Adds the specified string to the end of this StringBuilder.
543
*
544
* @param string the string
545
* @return this StringBuilder
546
*/
547
public StringBuilder append (String string) {
548
if (string == null) {
549
string = "null"; //$NON-NLS-1$
550
}
551
552
int currentLength = lengthInternal();
553
int currentCapacity = capacityInternal();
554
555
int stringLength = string.lengthInternal();
556
557
int newLength = currentLength + stringLength;
558
if (newLength < 0) {
559
/*[MSG "K0D01", "Array capacity exceeded"]*/
560
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
561
}
562
563
if (String.COMPACT_STRINGS) {
564
// Check if the StringBuilder is compressed
565
if (count >= 0 && string.isCompressed ()) {
566
if (newLength > currentCapacity) {
567
ensureCapacityImpl(newLength);
568
}
569
570
string.getBytes(0, stringLength, value, currentLength);
571
572
count = newLength;
573
} else {
574
// Check if the StringBuilder is compressed
575
if (count >= 0) {
576
currentCapacity = decompress(newLength);
577
}
578
579
if (newLength > currentCapacity) {
580
ensureCapacityImpl(newLength);
581
}
582
583
string.getCharsNoBoundChecks(0, stringLength, value, currentLength);
584
585
count = newLength | uncompressedBit;
586
}
587
} else {
588
if (newLength > currentCapacity) {
589
ensureCapacityImpl(newLength);
590
}
591
592
string.getCharsNoBoundChecks(0, stringLength, value, currentLength);
593
594
count = newLength;
595
}
596
597
return this;
598
}
599
600
/**
601
* Adds the string representation of the specified boolean to the
602
* end of this StringBuilder.
603
*
604
* @param value the boolean
605
* @return this StringBuilder
606
*/
607
public StringBuilder append (boolean value) {
608
return append (String.valueOf (value));
609
}
610
611
/**
612
* Answers the number of characters this StringBuilder can hold without
613
* growing.
614
*
615
* @return the capacity of this StringBuilder
616
*
617
* @see #ensureCapacity
618
* @see #length
619
*/
620
public int capacity() {
621
return capacityInternal();
622
}
623
624
/**
625
* Answers the number of characters this StringBuilder can hold without growing. This method is to be used internally
626
* within the current package whenever possible as the JIT compiler will take special precaution to avoid generating
627
* HCR guards for calls to this method.
628
*
629
* @return the capacity of this StringBuilder
630
*
631
* @see #ensureCapacity
632
* @see #length
633
*/
634
int capacityInternal() {
635
return capacity & ~sharedBit;
636
}
637
638
/**
639
* Answers the character at the specified offset in this StringBuilder.
640
*
641
* @param index the zero-based index in this StringBuilder
642
* @return the character at the index
643
*
644
* @exception IndexOutOfBoundsException when {@code index < 0} or
645
* {@code index >= length()}
646
*/
647
@Override
648
public char charAt(int index) {
649
int currentLength = lengthInternal();
650
651
if (index >= 0 && index < currentLength) {
652
// Check if the StringBuilder is compressed
653
if (String.COMPACT_STRINGS && count >= 0) {
654
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
655
} else {
656
return value[index];
657
}
658
}
659
660
throw new StringIndexOutOfBoundsException(index);
661
}
662
663
/**
664
* Deletes a range of characters.
665
*
666
* @param start the offset of the first character
667
* @param end the offset one past the last character
668
* @return this StringBuilder
669
*
670
* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or
671
* {@code end > length()}
672
*/
673
public StringBuilder delete(int start, int end) {
674
int currentLength = lengthInternal();
675
676
if (start >= 0) {
677
if (end > currentLength) {
678
end = currentLength;
679
}
680
681
if (end > start) {
682
int numberOfTailChars = currentLength - end;
683
684
try {
685
// Check if the StringBuilder is not shared
686
if (capacity >= 0) {
687
if (numberOfTailChars > 0) {
688
// Check if the StringBuilder is compressed
689
if (String.COMPACT_STRINGS && count >= 0) {
690
String.compressedArrayCopy(value, end, value, start, numberOfTailChars);
691
} else {
692
String.decompressedArrayCopy(value, end, value, start, numberOfTailChars);
693
}
694
}
695
} else {
696
char[] newData = new char[value.length];
697
698
// Check if the StringBuilder is compressed
699
if (String.COMPACT_STRINGS && count >= 0) {
700
if (start > 0) {
701
String.compressedArrayCopy(value, 0, newData, 0, start);
702
}
703
704
if (numberOfTailChars > 0) {
705
String.compressedArrayCopy(value, end, newData, start, numberOfTailChars);
706
}
707
} else {
708
if (start > 0) {
709
String.decompressedArrayCopy(value, 0, newData, 0, start);
710
}
711
712
if (numberOfTailChars > 0) {
713
String.decompressedArrayCopy(value, end, newData, start, numberOfTailChars);
714
}
715
}
716
717
value = newData;
718
719
capacity = capacity & ~sharedBit;
720
}
721
} catch (IndexOutOfBoundsException e) {
722
throw new StringIndexOutOfBoundsException();
723
}
724
725
if (String.COMPACT_STRINGS) {
726
// Check if the StringBuilder is compressed
727
if (count >= 0) {
728
count = currentLength - (end - start);
729
} else {
730
count = (currentLength - (end - start)) | uncompressedBit;
731
732
String.initCompressionFlag();
733
}
734
} else {
735
count = currentLength - (end - start);
736
}
737
738
return this;
739
}
740
741
if (start == end) {
742
return this;
743
}
744
}
745
746
throw new StringIndexOutOfBoundsException();
747
}
748
749
/**
750
* Deletes a single character
751
*
752
* @param location the offset of the character to delete
753
* @return this StringBuilder
754
*
755
* @exception StringIndexOutOfBoundsException when {@code location < 0} or
756
* {@code location >= length()}
757
*/
758
public StringBuilder deleteCharAt(int location) {
759
int currentLength = lengthInternal();
760
761
if (currentLength != 0) {
762
return delete (location, location + 1);
763
} else {
764
throw new StringIndexOutOfBoundsException ();
765
}
766
}
767
768
/**
769
* Ensures that this StringBuilder can hold the specified number of characters
770
* without growing.
771
*
772
* @param min the minimum number of elements that this
773
* StringBuilder will hold before growing
774
*/
775
public void ensureCapacity(int min) {
776
int currentCapacity = capacityInternal();
777
778
if (min > currentCapacity) {
779
ensureCapacityImpl(min);
780
}
781
}
782
783
private void ensureCapacityImpl(int min) {
784
int currentLength = lengthInternal();
785
int currentCapacity = capacityInternal();
786
787
int newCapacity = (currentCapacity << 1) + 2;
788
789
if (growAggressively && (newCapacity < currentCapacity)) {
790
newCapacity = Integer.MAX_VALUE;
791
}
792
793
int newLength = min > newCapacity ? min : newCapacity;
794
795
// Check if the StringBuilder is compressed
796
if (String.COMPACT_STRINGS && count >= 0) {
797
char[] newData = new char[(newLength + 1) >>> 1];
798
799
String.compressedArrayCopy(value, 0, newData, 0, currentLength);
800
801
value = newData;
802
} else {
803
char[] newData = new char[newLength];
804
805
String.decompressedArrayCopy(value, 0, newData, 0, currentLength);
806
value = newData;
807
}
808
809
capacity = newLength;
810
}
811
812
/**
813
* Copies the specified characters in this StringBuilder to the character array
814
* starting at the specified offset in the character array.
815
*
816
* @param start the starting offset of characters to copy
817
* @param end the ending offset of characters to copy
818
* @param buffer the destination character array
819
* @param index the starting offset in the character array
820
*
821
* @exception IndexOutOfBoundsException when {@code start < 0, end > length(),
822
* start > end, index < 0, end - start > buffer.length - index}
823
* @exception NullPointerException when buffer is null
824
*/
825
public void getChars(int start, int end, char[] buffer, int index) {
826
try {
827
int currentLength = lengthInternal();
828
829
if (start <= currentLength && end <= currentLength) {
830
// Note that we must explicitly check all the conditions because we are not using System.arraycopy which would
831
// have implicitly checked these conditions
832
if (start >= 0 && start <= end && index >= 0 && end - start <= buffer.length - index) {
833
// Check if the StringBuilder is compressed
834
if (String.COMPACT_STRINGS && count >= 0) {
835
String.decompress(value, start, buffer, index, end - start);
836
837
return;
838
} else {
839
System.arraycopy(value, start, buffer, index, end - start);
840
841
return;
842
}
843
}
844
}
845
} catch(IndexOutOfBoundsException e) {
846
// Void
847
}
848
849
throw new StringIndexOutOfBoundsException ();
850
}
851
852
/**
853
* Inserts the character array at the specified offset in this StringBuilder.
854
*
855
* @param index the index at which to insert
856
* @param chars the character array to insert
857
* @return this StringBuilder
858
*
859
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
860
* {@code index > length()}
861
* @exception NullPointerException when chars is null
862
*/
863
public StringBuilder insert(int index, char[] chars) {
864
int currentLength = lengthInternal();
865
866
if (0 <= index && index <= currentLength) {
867
move(chars.length, index);
868
869
if (String.COMPACT_STRINGS) {
870
// Check if the StringBuilder is compressed
871
if (count >= 0 && String.canEncodeAsLatin1(chars, 0, chars.length)) {
872
String.compress(chars, 0, value, index, chars.length);
873
874
count = currentLength + chars.length;
875
876
return this;
877
} else {
878
// Check if the StringBuilder is compressed
879
if (count >= 0) {
880
decompress(value.length);
881
}
882
883
String.decompressedArrayCopy(chars, 0, value, index, chars.length);
884
885
count = (currentLength + chars.length) | uncompressedBit;
886
887
return this;
888
}
889
} else {
890
String.decompressedArrayCopy(chars, 0, value, index, chars.length);
891
892
count = currentLength + chars.length;
893
894
return this;
895
}
896
} else {
897
throw new StringIndexOutOfBoundsException(index);
898
}
899
}
900
901
/**
902
* Inserts the specified sequence of characters at the
903
* specified offset in this StringBuilder.
904
*
905
* @param index the index at which to insert
906
* @param chars a character array
907
* @param start the starting offset
908
* @param length the number of characters
909
* @return this StringBuilder
910
*
911
* @exception StringIndexOutOfBoundsException when {@code length < 0, start < 0,
912
* start + length > chars.length, index < 0} or
913
* {@code index > length()}
914
* @exception NullPointerException when chars is null
915
*/
916
public StringBuilder insert(int index, char[] chars, int start, int length) {
917
int currentLength = lengthInternal();
918
919
if (0 <= index && index <= currentLength) {
920
if (start >= 0 && 0 <= length && length <= chars.length - start) {
921
move(length, index);
922
923
if (String.COMPACT_STRINGS) {
924
// Check if the StringBuilder is compressed
925
if (count >= 0 && String.canEncodeAsLatin1(chars, start, length)) {
926
String.compress(chars, start, value, index, length);
927
928
count = currentLength + length;
929
930
return this;
931
} else {
932
// Check if the StringBuilder is compressed
933
if (count >= 0) {
934
decompress(value.length);
935
}
936
937
String.decompressedArrayCopy(chars, start, value, index, length);
938
939
count = (currentLength + length) | uncompressedBit;
940
941
return this;
942
}
943
} else {
944
String.decompressedArrayCopy(chars, start, value, index, length);
945
946
count = currentLength + length;
947
948
return this;
949
}
950
} else {
951
throw new StringIndexOutOfBoundsException();
952
}
953
} else {
954
throw new StringIndexOutOfBoundsException(index);
955
}
956
}
957
958
StringBuilder insert(int index, char[] chars, int start, int length, boolean compressed) {
959
int currentLength = lengthInternal();
960
961
move(length, index);
962
963
if (String.COMPACT_STRINGS) {
964
// Check if the StringBuilder is compressed
965
if (count >= 0 && compressed) {
966
String.compressedArrayCopy(chars, start, value, index, length);
967
968
count = currentLength + length;
969
970
return this;
971
} else {
972
if (count >= 0) {
973
decompress(value.length);
974
}
975
976
String.decompressedArrayCopy(chars, start, value, index, length);
977
978
count = (currentLength + length) | uncompressedBit;
979
980
return this;
981
}
982
} else {
983
String.decompressedArrayCopy(chars, start, value, index, length);
984
985
count = currentLength + length;
986
987
return this;
988
}
989
}
990
991
/**
992
* Inserts the character at the specified offset in this StringBuilder.
993
*
994
* @param index the index at which to insert
995
* @param ch the character to insert
996
* @return this StringBuilder
997
*
998
* @exception IndexOutOfBoundsException when {@code index < 0} or
999
* {@code index > length()}
1000
*/
1001
public StringBuilder insert(int index, char ch) {
1002
int currentLength = lengthInternal();
1003
1004
if (0 <= index && index <= currentLength) {
1005
move(1, index);
1006
1007
if (String.COMPACT_STRINGS ) {
1008
// Check if the StringBuilder is compressed
1009
if (count >= 0 && ch <= 255) {
1010
helpers.putByteInArrayByIndex(value, index, (byte) ch);
1011
1012
count = currentLength + 1;
1013
1014
return this;
1015
} else {
1016
// Check if the StringBuilder is compressed
1017
if (count >= 0) {
1018
decompress(value.length);
1019
}
1020
1021
value[index] = ch;
1022
1023
count = (currentLength + 1) | uncompressedBit;
1024
1025
return this;
1026
}
1027
} else {
1028
value[index] = ch;
1029
1030
count = currentLength + 1;
1031
1032
return this;
1033
}
1034
} else {
1035
throw new StringIndexOutOfBoundsException(index);
1036
}
1037
}
1038
1039
/**
1040
* Inserts the string representation of the specified double at the specified
1041
* offset in this StringBuilder.
1042
*
1043
* @param index the index at which to insert
1044
* @param value the double to insert
1045
* @return this StringBuilder
1046
*
1047
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1048
* {@code index > length()}
1049
*/
1050
public StringBuilder insert(int index, double value) {
1051
return insert(index, String.valueOf(value));
1052
}
1053
1054
/**
1055
* Inserts the string representation of the specified float at the specified
1056
* offset in this StringBuilder.
1057
*
1058
* @param index the index at which to insert
1059
* @param value the float to insert
1060
* @return this StringBuilder
1061
*
1062
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1063
* {@code index > length()}
1064
*/
1065
public StringBuilder insert(int index, float value) {
1066
return insert(index, String.valueOf(value));
1067
}
1068
1069
/**
1070
* Inserts the string representation of the specified integer at the specified
1071
* offset in this StringBuilder.
1072
*
1073
* @param index the index at which to insert
1074
* @param value the integer to insert
1075
* @return this StringBuilder
1076
*
1077
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1078
* {@code index > length()}
1079
*/
1080
public StringBuilder insert(int index, int value) {
1081
return insert(index, Integer.toString(value));
1082
}
1083
1084
/**
1085
* Inserts the string representation of the specified long at the specified
1086
* offset in this StringBuilder.
1087
*
1088
* @param index the index at which to insert
1089
* @param value the long to insert
1090
* @return this StringBuilder
1091
*
1092
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1093
* {@code index > length()}
1094
*/
1095
public StringBuilder insert(int index, long value) {
1096
return insert(index, Long.toString(value));
1097
}
1098
1099
/**
1100
* Inserts the string representation of the specified object at the specified
1101
* offset in this StringBuilder.
1102
*
1103
* @param index the index at which to insert
1104
* @param value the object to insert
1105
* @return this StringBuilder
1106
*
1107
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1108
* {@code index > length()}
1109
*/
1110
public StringBuilder insert(int index, Object value) {
1111
return insert(index, String.valueOf(value));
1112
}
1113
1114
/**
1115
* Inserts the string at the specified offset in this StringBuilder.
1116
*
1117
* @param index the index at which to insert
1118
* @param string the string to insert
1119
* @return this StringBuilder
1120
*
1121
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1122
* {@code index > length()}
1123
*/
1124
public StringBuilder insert(int index, String string) {
1125
int currentLength = lengthInternal();
1126
1127
if (0 <= index && index <= currentLength) {
1128
if (string == null) {
1129
string = "null"; //$NON-NLS-1$
1130
}
1131
1132
int stringLength = string.lengthInternal();
1133
1134
move(stringLength, index);
1135
1136
if (String.COMPACT_STRINGS) {
1137
// Check if the StringBuilder is compressed
1138
if (count >= 0 && string.isCompressed()) {
1139
string.getBytes(0, stringLength, value, index);
1140
1141
count = currentLength + stringLength;
1142
1143
return this;
1144
} else {
1145
// Check if the StringBuilder is compressed
1146
if (count >= 0) {
1147
decompress(value.length);
1148
}
1149
1150
string.getCharsNoBoundChecks(0, stringLength, value, index);
1151
1152
count = (currentLength + stringLength) | uncompressedBit;
1153
1154
return this;
1155
}
1156
} else {
1157
string.getCharsNoBoundChecks(0, stringLength, value, index);
1158
1159
count = currentLength + stringLength;
1160
1161
return this;
1162
}
1163
} else {
1164
throw new StringIndexOutOfBoundsException(index);
1165
}
1166
}
1167
1168
/**
1169
* Inserts the string representation of the specified boolean at the specified
1170
* offset in this StringBuilder.
1171
*
1172
* @param index the index at which to insert
1173
* @param value the boolean to insert
1174
* @return this StringBuilder
1175
*
1176
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1177
* {@code index > length()}
1178
*/
1179
public StringBuilder insert(int index, boolean value) {
1180
return insert(index, String.valueOf(value));
1181
}
1182
1183
/**
1184
* Answers the size of this StringBuilder.
1185
*
1186
* @return the number of characters in this StringBuilder
1187
*/
1188
@Override
1189
public int length() {
1190
return lengthInternal();
1191
}
1192
1193
/**
1194
* Answers the size of this StringBuilder. This method is to be used internally within the current package whenever
1195
* possible as the JIT compiler will take special precaution to avoid generating HCR guards for calls to this
1196
* method.
1197
*
1198
* @return the number of characters in this StringBuilder
1199
*/
1200
int lengthInternal() {
1201
if (String.COMPACT_STRINGS) {
1202
// Check if the StringBuilder is compressed
1203
if (count >= 0) {
1204
return count;
1205
} else {
1206
return count & ~uncompressedBit;
1207
}
1208
} else {
1209
return count;
1210
}
1211
}
1212
1213
private void move(int size, int index) {
1214
int currentLength = lengthInternal();
1215
int currentCapacity = capacityInternal();
1216
1217
// Check if the StringBuilder is compressed
1218
if (String.COMPACT_STRINGS && count >= 0) {
1219
int newLength;
1220
1221
if (currentCapacity - currentLength >= size) {
1222
// Check if the StringBuilder is not shared
1223
if (capacity >= 0) {
1224
String.compressedArrayCopy(value, index, value, index + size, currentLength - index);
1225
1226
return;
1227
}
1228
1229
newLength = currentCapacity;
1230
} else {
1231
newLength = Integer.max(currentLength + size, (currentCapacity << 1) + 2);
1232
if (newLength < 0) {
1233
/*[MSG "K0D01", "Array capacity exceeded"]*/
1234
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
1235
}
1236
}
1237
1238
char[] newData = new char[(newLength + 1) >>> 1];
1239
1240
String.compressedArrayCopy(value, 0, newData, 0, index);
1241
String.compressedArrayCopy(value, index, newData, index + size, currentLength - index);
1242
1243
value = newData;
1244
1245
capacity = newLength;
1246
} else {
1247
int newLength;
1248
1249
if (currentCapacity - currentLength >= size) {
1250
// Check if the StringBuilder is not shared
1251
if (capacity >= 0) {
1252
String.decompressedArrayCopy(value, index, value, index + size, currentLength - index);
1253
1254
return;
1255
}
1256
1257
newLength = currentCapacity;
1258
} else {
1259
newLength = Integer.max(currentLength + size, (currentCapacity << 1) + 2);
1260
if (newLength < 0) {
1261
/*[MSG "K0D01", "Array capacity exceeded"]*/
1262
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
1263
}
1264
}
1265
1266
char[] newData = new char[newLength];
1267
1268
String.decompressedArrayCopy(value, 0, newData, 0, index);
1269
String.decompressedArrayCopy(value, index, newData, index + size, currentLength - index);
1270
1271
value = newData;
1272
1273
capacity = newLength;
1274
}
1275
}
1276
1277
/**
1278
* Replace a range of characters with the characters in the specified String.
1279
*
1280
* @param start the offset of the first character
1281
* @param end the offset one past the last character
1282
* @param string a String
1283
* @return this StringBuilder
1284
*
1285
* @exception StringIndexOutOfBoundsException when {@code start < 0} or
1286
* {@code start > end}
1287
*/
1288
public StringBuilder replace(int start, int end, String string) {
1289
int currentLength = lengthInternal();
1290
1291
if (String.COMPACT_STRINGS) {
1292
// Check if the StringBuilder is compressed
1293
if (count >= 0 && string.isCompressed()) {
1294
if (start >= 0) {
1295
if (end > currentLength) {
1296
end = currentLength;
1297
}
1298
1299
if (end > start) {
1300
int size = string.lengthInternal();
1301
1302
// Difference between the substring we wish to replace and the size of the string parameter
1303
int difference = end - start - size;
1304
1305
if (difference > 0) {
1306
// Check if the StringBuilder is not shared
1307
if (capacity >= 0) {
1308
String.compressedArrayCopy(value, end, value, start + size, currentLength - end);
1309
} else {
1310
char[] newData = new char[value.length];
1311
1312
String.compressedArrayCopy(value, 0, newData, 0, start);
1313
String.compressedArrayCopy(value, end, newData, start + size, currentLength - end);
1314
1315
value = newData;
1316
1317
capacity = capacity & ~sharedBit;
1318
}
1319
} else if (difference < 0) {
1320
move(-difference, end);
1321
} else if (capacity < 0) {
1322
value = value.clone();
1323
1324
capacity = capacity & ~sharedBit;
1325
}
1326
1327
string.getBytes(0, size, value, start);
1328
1329
count = currentLength - difference;
1330
1331
return this;
1332
}
1333
1334
if (start == end) {
1335
return insert(start, string);
1336
}
1337
}
1338
} else {
1339
// Check if the StringBuilder is compressed
1340
if (count >= 0) {
1341
decompress(value.length);
1342
}
1343
1344
if (start >= 0) {
1345
if (end > currentLength) {
1346
end = currentLength;
1347
}
1348
1349
if (end > start) {
1350
int size = string.lengthInternal();
1351
1352
// Difference between the substring we wish to replace and the size of the string parameter
1353
int difference = end - start - size;
1354
1355
if (difference > 0) {
1356
// Check if the StringBuilder is not shared
1357
if (capacity >= 0) {
1358
String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);
1359
} else {
1360
char[] newData = new char[value.length];
1361
1362
String.decompressedArrayCopy(value, 0, newData, 0, start);
1363
String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);
1364
1365
value = newData;
1366
1367
capacity = capacity & ~sharedBit;
1368
}
1369
} else if (difference < 0) {
1370
move(-difference, end);
1371
} else if (capacity < 0) {
1372
value = value.clone();
1373
1374
capacity = capacity & ~sharedBit;
1375
}
1376
1377
string.getCharsNoBoundChecks(0, size, value, start);
1378
1379
count = (currentLength - difference) | uncompressedBit;
1380
1381
return this;
1382
}
1383
1384
if (start == end) {
1385
string.getClass(); // Implicit null check
1386
1387
return insert(start, string);
1388
}
1389
}
1390
}
1391
} else {
1392
if (start >= 0) {
1393
if (end > currentLength) {
1394
end = currentLength;
1395
}
1396
1397
if (end > start) {
1398
int size = string.lengthInternal();
1399
1400
// Difference between the substring we wish to replace and the size of the string parameter
1401
int difference = end - start - size;
1402
1403
if (difference > 0) {
1404
// Check if the StringBuilder is not shared
1405
if (capacity >= 0) {
1406
String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);
1407
} else {
1408
char[] newData = new char[value.length];
1409
1410
String.decompressedArrayCopy(value, 0, newData, 0, start);
1411
String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);
1412
1413
value = newData;
1414
1415
capacity = capacity & ~sharedBit;
1416
}
1417
} else if (difference < 0) {
1418
move(-difference, end);
1419
} else if (capacity < 0) {
1420
value = value.clone();
1421
1422
capacity = capacity & ~sharedBit;
1423
}
1424
1425
string.getCharsNoBoundChecks(0, size, value, start);
1426
1427
count = currentLength - difference;
1428
1429
return this;
1430
}
1431
1432
if (start == end) {
1433
string.getClass(); // Implicit null check
1434
1435
return insert(start, string);
1436
}
1437
}
1438
}
1439
1440
throw new StringIndexOutOfBoundsException();
1441
}
1442
1443
/**
1444
* Reverses the order of characters in this StringBuilder.
1445
*
1446
* @return this StringBuilder
1447
*/
1448
public StringBuilder reverse() {
1449
int currentLength = lengthInternal();
1450
1451
if (currentLength < 2) {
1452
return this;
1453
}
1454
1455
// Check if the StringBuilder is compressed
1456
if (String.COMPACT_STRINGS && count >= 0) {
1457
// Check if the StringBuilder is not shared
1458
if (capacity >= 0) {
1459
for (int i = 0, mid = currentLength / 2, j = currentLength - 1; i < mid; ++i, --j) {
1460
byte a = helpers.getByteFromArrayByIndex(value, i);
1461
byte b = helpers.getByteFromArrayByIndex(value, j);
1462
1463
helpers.putByteInArrayByIndex(value, i, b);
1464
helpers.putByteInArrayByIndex(value, j, a);
1465
}
1466
1467
return this;
1468
} else {
1469
char[] newData = new char[value.length];
1470
1471
for (int i = 0, j = currentLength - 1; i < currentLength; ++i, --j) {
1472
helpers.putByteInArrayByIndex(newData, j, helpers.getByteFromArrayByIndex(value, i));
1473
}
1474
1475
value = newData;
1476
1477
capacity = capacity & ~sharedBit;
1478
1479
return this;
1480
}
1481
} else {
1482
// Check if the StringBuilder is not shared
1483
if (capacity >= 0) {
1484
int end = currentLength - 1;
1485
1486
char frontHigh = value[0];
1487
char endLow = value[end];
1488
boolean allowFrontSur = true, allowEndSur = true;
1489
for (int i = 0, mid = currentLength / 2; i < mid; i++, --end) {
1490
char frontLow = value[i + 1];
1491
char endHigh = value[end - 1];
1492
boolean surAtFront = false, surAtEnd = false;
1493
if (allowFrontSur && frontLow >= Character.MIN_LOW_SURROGATE && frontLow <= Character.MAX_LOW_SURROGATE && frontHigh >= Character.MIN_HIGH_SURROGATE && frontHigh <= Character.MAX_HIGH_SURROGATE) {
1494
surAtFront = true;
1495
if (currentLength < 3) return this;
1496
}
1497
if (allowEndSur && endHigh >= Character.MIN_HIGH_SURROGATE && endHigh <= Character.MAX_HIGH_SURROGATE && endLow >= Character.MIN_LOW_SURROGATE && endLow <= Character.MAX_LOW_SURROGATE) {
1498
surAtEnd = true;
1499
}
1500
allowFrontSur = true;
1501
allowEndSur = true;
1502
if (surAtFront == surAtEnd) {
1503
if (surAtFront) {
1504
// both surrogates
1505
value[end] = frontLow;
1506
value[end - 1] = frontHigh;
1507
value[i] = endHigh;
1508
value[i + 1] = endLow;
1509
frontHigh = value[i + 2];
1510
endLow = value[end - 2];
1511
i++;
1512
--end;
1513
} else {
1514
// neither surrogates
1515
value[end] = frontHigh;
1516
value[i] = endLow;
1517
frontHigh = frontLow;
1518
endLow = endHigh;
1519
}
1520
} else {
1521
if (surAtFront) {
1522
// surrogate only at the front
1523
value[end] = frontLow;
1524
value[i] = endLow;
1525
endLow = endHigh;
1526
allowFrontSur = false;
1527
} else {
1528
// surrogate only at the end
1529
value[end] = frontHigh;
1530
value[i] = endHigh;
1531
frontHigh = frontLow;
1532
allowEndSur = false;
1533
}
1534
}
1535
}
1536
if ((currentLength & 1) == 1 && (!allowFrontSur || !allowEndSur)) {
1537
value[end] = allowFrontSur ? endLow : frontHigh;
1538
}
1539
} else {
1540
char[] newData = new char[value.length];
1541
1542
for (int i = 0, end = currentLength; i < currentLength; i++) {
1543
char high = value[i];
1544
1545
if ((i + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
1546
char low = value[i + 1];
1547
1548
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
1549
newData[--end] = low;
1550
i++;
1551
}
1552
}
1553
newData[--end] = high;
1554
}
1555
1556
value = newData;
1557
1558
capacity = capacity & ~sharedBit;
1559
}
1560
1561
return this;
1562
}
1563
}
1564
1565
/**
1566
* Sets the character at the specified offset in this StringBuilder.
1567
*
1568
* @param index the zero-based index in this StringBuilder
1569
* @param ch the character
1570
*
1571
* @exception IndexOutOfBoundsException when {@code index < 0} or
1572
* {@code index >= length()}
1573
*/
1574
public void setCharAt(int index, char ch) {
1575
int currentLength = lengthInternal();
1576
1577
if (0 <= index && index < currentLength) {
1578
if (String.COMPACT_STRINGS) {
1579
// Check if the StringBuilder is compressed
1580
if (count >= 0 && ch <= 255) {
1581
if (capacity < 0) {
1582
value = value.clone();
1583
1584
capacity = capacity & ~sharedBit;
1585
}
1586
1587
helpers.putByteInArrayByIndex(value, index, (byte) ch);
1588
} else {
1589
// Check if the StringBuilder is compressed
1590
if (count >= 0) {
1591
decompress(value.length);
1592
}
1593
1594
if (capacity < 0) {
1595
value = value.clone();
1596
1597
capacity = capacity & ~sharedBit;
1598
}
1599
1600
value[index] = ch;
1601
}
1602
} else {
1603
if (capacity < 0) {
1604
value = value.clone();
1605
1606
capacity = capacity & ~sharedBit;
1607
}
1608
1609
value[index] = ch;
1610
}
1611
} else {
1612
throw new StringIndexOutOfBoundsException(index);
1613
}
1614
}
1615
1616
/**
1617
* Sets the length of this StringBuilder to the specified length. If there
1618
* are more than length characters in this StringBuilder, the characters
1619
* at end are lost. If there are less than length characters in the
1620
* StringBuilder, the additional characters are set to {@code \\u0000}.
1621
*
1622
* @param length the new length of this StringBuilder
1623
*
1624
* @exception IndexOutOfBoundsException when {@code length < 0}
1625
*
1626
* @see #length
1627
*/
1628
public void setLength(int length) {
1629
int currentLength = lengthInternal();
1630
int currentCapacity = capacityInternal();
1631
1632
// Check if the StringBuilder is compressed
1633
if (String.COMPACT_STRINGS && count >= 0) {
1634
if (length > currentCapacity) {
1635
ensureCapacityImpl(length);
1636
} else if (length > currentLength) {
1637
for (int i = currentLength; i < length; ++i) {
1638
helpers.putByteInArrayByIndex(value, i, (byte) 0);
1639
}
1640
} else if (capacity < 0) {
1641
if (length < 0) {
1642
throw new IndexOutOfBoundsException();
1643
}
1644
1645
char[] newData = new char[value.length];
1646
1647
if (length > 0) {
1648
String.compressedArrayCopy(value, 0, newData, 0, length);
1649
}
1650
1651
value = newData;
1652
1653
capacity = capacity & ~sharedBit;
1654
} else if (length < 0) {
1655
throw new IndexOutOfBoundsException();
1656
}
1657
} else {
1658
if (length > currentCapacity) {
1659
ensureCapacityImpl(length);
1660
} else if (length > currentLength) {
1661
Arrays.fill(value, currentLength, length, (char) 0);
1662
} else if (capacity < 0) {
1663
if (length < 0) {
1664
throw new IndexOutOfBoundsException();
1665
}
1666
1667
char[] newData = new char[value.length];
1668
1669
if (length > 0) {
1670
String.decompressedArrayCopy(value, 0, newData, 0, length);
1671
}
1672
1673
value = newData;
1674
1675
capacity = capacity & ~sharedBit;
1676
} else if (length < 0) {
1677
throw new IndexOutOfBoundsException();
1678
}
1679
}
1680
1681
if (String.COMPACT_STRINGS) {
1682
// Check if the StringBuilder is compressed
1683
if (count >= 0) {
1684
count = length;
1685
} else {
1686
count = length | uncompressedBit;
1687
}
1688
} else {
1689
count = length;
1690
}
1691
}
1692
1693
/**
1694
* Copies a range of characters into a new String.
1695
*
1696
* @param start the offset of the first character
1697
* @return a new String containing the characters from start to the end
1698
* of the string
1699
*
1700
* @exception StringIndexOutOfBoundsException when {@code start < 0} or
1701
* {@code start > length()}
1702
*/
1703
public String substring(int start) {
1704
int currentLength = lengthInternal();
1705
1706
// Check if the StringBuilder is compressed
1707
if (String.COMPACT_STRINGS && count >= 0) {
1708
if (0 <= start && start <= currentLength) {
1709
return new String(value, start, currentLength - start, true, false);
1710
}
1711
} else {
1712
if (0 <= start && start <= currentLength) {
1713
return new String(value, start, currentLength - start, false, false);
1714
}
1715
}
1716
1717
throw new StringIndexOutOfBoundsException(start);
1718
}
1719
1720
/**
1721
* Copies a range of characters into a new String.
1722
*
1723
* @param start the offset of the first character
1724
* @param end the offset one past the last character
1725
* @return a new String containing the characters from start to end - 1
1726
*
1727
* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or
1728
* {@code end > length()}
1729
*/
1730
public String substring(int start, int end) {
1731
int currentLength = lengthInternal();
1732
1733
// Check if the StringBuilder is compressed
1734
if (String.COMPACT_STRINGS && count >= 0) {
1735
if (0 <= start && start <= end && end <= currentLength) {
1736
return new String(value, start, end - start, true, false);
1737
}
1738
} else {
1739
if (0 <= start && start <= end && end <= currentLength) {
1740
return new String(value, start, end - start, false, false);
1741
}
1742
}
1743
1744
throw new StringIndexOutOfBoundsException();
1745
}
1746
1747
static void initFromSystemProperties(Properties props) {
1748
String prop = props.getProperty("java.lang.string.create.unique"); //$NON-NLS-1$
1749
TOSTRING_COPY_BUFFER_ENABLED = "true".equals(prop) || "StringBuilder".equals(prop); //$NON-NLS-1$ //$NON-NLS-2$
1750
1751
// growAggressively by default
1752
String growAggressivelyProperty = props.getProperty("java.lang.stringBuffer.growAggressively", ""); //$NON-NLS-1$ //$NON-NLS-2$
1753
growAggressively = "".equals(growAggressivelyProperty) || Boolean.parseBoolean(growAggressivelyProperty); //$NON-NLS-1$
1754
}
1755
1756
/**
1757
* Answers the contents of this StringBuilder.
1758
*
1759
* @return a String containing the characters in this StringBuilder
1760
*/
1761
@Override
1762
public String toString () {
1763
int currentLength = lengthInternal();
1764
int currentCapacity = capacityInternal();
1765
1766
if (false == TOSTRING_COPY_BUFFER_ENABLED) {
1767
int wasted = currentCapacity - currentLength;
1768
if (wasted >= 768 || (wasted >= INITIAL_SIZE && wasted >= (currentCapacity >> 1))) {
1769
// Check if the StringBuffer is compressed
1770
if (String.COMPACT_STRINGS && count >= 0) {
1771
return new String (value, 0, currentLength, true, false);
1772
} else {
1773
return new String (value, 0, currentLength, false, false);
1774
}
1775
}
1776
} else {
1777
// Do not copy the char[] if it will not get smaller because of object alignment
1778
int roundedCount = (currentLength + 3) & ~3;
1779
if (roundedCount < currentCapacity) {
1780
// Check if the StringBuffer is compressed
1781
if (String.COMPACT_STRINGS && count >= 0) {
1782
return new String (value, 0, currentLength, true, false);
1783
} else {
1784
return new String (value, 0, currentLength, false, false);
1785
}
1786
}
1787
}
1788
1789
capacity = capacity | sharedBit;
1790
1791
// Check if the StringBuffer is compressed
1792
if (String.COMPACT_STRINGS && count >= 0) {
1793
return new String (value, 0, currentLength, true);
1794
} else {
1795
return new String (value, 0, currentLength, false);
1796
}
1797
}
1798
1799
private void writeObject(ObjectOutputStream stream) throws IOException {
1800
int currentLength = lengthInternal();
1801
1802
stream.defaultWriteObject();
1803
stream.writeInt(currentLength);
1804
1805
// Check if the StringBuilder is compressed
1806
if (String.COMPACT_STRINGS && count >= 0) {
1807
char[] newData = new char[currentLength];
1808
1809
String.decompress(value, 0, newData, 0, currentLength);
1810
1811
stream.writeObject(newData);
1812
} else {
1813
stream.writeObject(value);
1814
}
1815
}
1816
1817
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
1818
stream.defaultReadObject();
1819
int streamCount = stream.readInt();
1820
char[] streamValue = (char[])stream.readObject();
1821
1822
if ((streamCount < 0) || (streamCount > streamValue.length)) {
1823
/*[MSG "K0199", "count value invalid"]*/
1824
throw new StreamCorruptedException(com.ibm.oti.util.Msg.getString("K0199")); //$NON-NLS-1$
1825
}
1826
if (String.COMPACT_STRINGS) {
1827
if (String.canEncodeAsLatin1(streamValue, 0, streamValue.length)) {
1828
value = new char[(streamValue.length + 1) >>> 1];
1829
String.compress(streamValue, 0, value, 0, streamValue.length);
1830
count = streamCount;
1831
capacity = streamValue.length;
1832
} else {
1833
value = new char[streamValue.length];
1834
System.arraycopy(streamValue, 0, value, 0, streamValue.length);
1835
count = streamCount | uncompressedBit;
1836
capacity = streamValue.length;
1837
String.initCompressionFlag();
1838
}
1839
} else {
1840
value = new char[streamValue.length];
1841
System.arraycopy(streamValue, 0, value, 0, streamValue.length);
1842
count = streamCount;
1843
capacity = streamValue.length;
1844
}
1845
}
1846
1847
/**
1848
* Adds the specified StringBuffer to the end of this StringBuilder.
1849
*
1850
* @param buffer the StringBuffer
1851
* @return this StringBuilder
1852
*/
1853
public StringBuilder append(StringBuffer buffer) {
1854
if (buffer == null) {
1855
return append((String)null);
1856
}
1857
1858
synchronized (buffer) {
1859
if (String.COMPACT_STRINGS && buffer.isCompressed()) {
1860
return append(buffer.getValue(), 0, buffer.length(), true);
1861
} else {
1862
return append(buffer.getValue(), 0, buffer.length(), false);
1863
}
1864
}
1865
}
1866
1867
/**
1868
* Copies a range of characters into a new String.
1869
*
1870
* @param start the offset of the first character
1871
* @param end the offset one past the last character
1872
* @return a new String containing the characters from start to end - 1
1873
*
1874
* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or
1875
* {@code end > length()}
1876
*/
1877
@Override
1878
public CharSequence subSequence(int start, int end) {
1879
return substring(start, end);
1880
}
1881
1882
/**
1883
* Searches in this StringBuilder for the first index of the specified character. The
1884
* search for the character starts at the beginning and moves towards the
1885
* end.
1886
*
1887
* @param string the string to find
1888
* @return the index in this StringBuilder of the specified character, -1 if the
1889
* character isn't found
1890
*
1891
* @see #lastIndexOf(String)
1892
*/
1893
public int indexOf(String string) {
1894
return indexOf(string, 0);
1895
}
1896
1897
/**
1898
* Searches in this StringBuilder for the index of the specified character. The
1899
* search for the character starts at the specified offset and moves towards
1900
* the end.
1901
*
1902
* @param subString the string to find
1903
* @param start the starting offset
1904
* @return the index in this StringBuilder of the specified character, -1 if the
1905
* character isn't found
1906
*
1907
* @see #lastIndexOf(String,int)
1908
*/
1909
public int indexOf(String subString, int start) {
1910
int currentLength = lengthInternal();
1911
1912
if (start < 0) {
1913
start = 0;
1914
}
1915
1916
int subStringLength = subString.lengthInternal();
1917
1918
if (subStringLength > 0) {
1919
if (subStringLength + start > currentLength) {
1920
return -1;
1921
}
1922
1923
char firstChar = subString.charAtInternal(0);
1924
1925
// Check if the StringBuilder is compressed
1926
if (String.COMPACT_STRINGS && count >= 0) {
1927
if (!subString.isCompressed()) {
1928
return -1;
1929
}
1930
1931
while (true) {
1932
int i = start;
1933
1934
boolean found = false;
1935
1936
for (; i < currentLength; ++i) {
1937
if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {
1938
found = true;
1939
break;
1940
}
1941
}
1942
1943
// Handles subStringLength > currentLength || start >= currentLength
1944
if (!found || subStringLength + i > currentLength) {
1945
return -1;
1946
}
1947
1948
int o1 = i;
1949
int o2 = 0;
1950
1951
while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))
1952
;
1953
1954
if (o2 == subStringLength) {
1955
return i;
1956
}
1957
1958
start = i + 1;
1959
}
1960
} else {
1961
while (true) {
1962
int i = start;
1963
1964
boolean found = false;
1965
1966
for (; i < currentLength; ++i) {
1967
if (value[i] == firstChar) {
1968
found = true;
1969
break;
1970
}
1971
}
1972
1973
// Handles subStringLength > currentLength || start >= currentLength
1974
if (!found || subStringLength + i > currentLength) {
1975
return -1;
1976
}
1977
1978
int o1 = i;
1979
int o2 = 0;
1980
1981
while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))
1982
;
1983
1984
if (o2 == subStringLength) {
1985
return i;
1986
}
1987
1988
start = i + 1;
1989
}
1990
}
1991
1992
} else {
1993
return (start < currentLength || start == 0) ? start : currentLength;
1994
}
1995
}
1996
1997
/**
1998
* Searches in this StringBuilder for the last index of the specified character. The
1999
* search for the character starts at the end and moves towards the beginning.
2000
*
2001
* @param string the string to find
2002
* @return the index in this StringBuilder of the specified character, -1 if the
2003
* character isn't found
2004
*
2005
* @see #indexOf(String)
2006
*/
2007
public int lastIndexOf(String string) {
2008
int currentLength = lengthInternal();
2009
2010
return lastIndexOf(string, currentLength);
2011
}
2012
2013
/**
2014
* Searches in this StringBuilder for the index of the specified character. The
2015
* search for the character starts at the specified offset and moves towards
2016
* the beginning.
2017
*
2018
* @param subString the string to find
2019
* @param start the starting offset
2020
* @return the index in this StringBuilder of the specified character, -1 if the
2021
* character isn't found
2022
*
2023
* @see #indexOf(String,int)
2024
*/
2025
public int lastIndexOf(String subString, int start) {
2026
int currentLength = lengthInternal();
2027
2028
int subStringLength = subString.lengthInternal();
2029
2030
if (subStringLength <= currentLength && start >= 0) {
2031
if (subStringLength > 0) {
2032
if (start > currentLength - subStringLength) {
2033
start = currentLength - subStringLength;
2034
}
2035
2036
char firstChar = subString.charAtInternal(0);
2037
2038
// Check if the StringBuilder is compressed
2039
if (String.COMPACT_STRINGS && count >= 0) {
2040
if (!subString.isCompressed()) {
2041
return -1;
2042
}
2043
2044
while (true) {
2045
int i = start;
2046
2047
boolean found = false;
2048
2049
for (; i >= 0; --i) {
2050
if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {
2051
found = true;
2052
break;
2053
}
2054
}
2055
2056
if (!found) {
2057
return -1;
2058
}
2059
2060
int o1 = i;
2061
int o2 = 0;
2062
2063
while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))
2064
;
2065
2066
if (o2 == subStringLength) {
2067
return i;
2068
}
2069
2070
start = i - 1;
2071
}
2072
} else {
2073
while (true) {
2074
int i = start;
2075
2076
boolean found = false;
2077
2078
for (; i >= 0; --i) {
2079
if (value[i] == firstChar) {
2080
found = true;
2081
break;
2082
}
2083
}
2084
2085
if (!found) {
2086
return -1;
2087
}
2088
2089
int o1 = i;
2090
int o2 = 0;
2091
2092
while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))
2093
;
2094
2095
if (o2 == subStringLength) {
2096
return i;
2097
}
2098
2099
start = i - 1;
2100
}
2101
}
2102
} else {
2103
return start < currentLength ? start : currentLength;
2104
}
2105
} else {
2106
return -1;
2107
}
2108
}
2109
2110
/**
2111
* Return the underlying buffer and set the shared flag.
2112
*
2113
*/
2114
char[] shareValue() {
2115
capacity = capacity | sharedBit;
2116
2117
return value;
2118
}
2119
2120
boolean isCompressed() {
2121
// Check if the StringBuilder is compressed
2122
if (String.COMPACT_STRINGS && count >= 0) {
2123
return true;
2124
} else {
2125
return false;
2126
}
2127
}
2128
2129
/**
2130
* Constructs a new StringBuilder containing the characters in
2131
* the specified CharSequence and the default capacity.
2132
*
2133
* @param sequence the initial contents of this StringBuilder
2134
* @exception NullPointerException when sequence is null
2135
*/
2136
public StringBuilder(CharSequence sequence) {
2137
int size = sequence.length();
2138
2139
if (size < 0) {
2140
size = 0;
2141
}
2142
2143
int newLength = INITIAL_SIZE + size;
2144
if (newLength < size) {
2145
newLength = size;
2146
}
2147
2148
if (String.COMPACT_STRINGS) {
2149
value = new char[(newLength + 1) >>> 1];
2150
} else {
2151
value = new char[newLength];
2152
}
2153
2154
capacity = newLength;
2155
2156
if (sequence instanceof String) {
2157
append((String)sequence);
2158
} else if (sequence instanceof StringBuffer) {
2159
append((StringBuffer)sequence);
2160
} else {
2161
if (String.COMPACT_STRINGS) {
2162
boolean isCompressed = true;
2163
2164
for (int i = 0; i < size; ++i) {
2165
if (sequence.charAt(i) > 255) {
2166
isCompressed = false;
2167
2168
break;
2169
}
2170
}
2171
2172
if (isCompressed) {
2173
count = size;
2174
2175
for (int i = 0; i < size; ++i) {
2176
helpers.putByteInArrayByIndex(value, i, (byte) sequence.charAt(i));
2177
}
2178
} else {
2179
value = new char[newLength];
2180
2181
count = size | uncompressedBit;
2182
2183
for (int i = 0; i < size; ++i) {
2184
value[i] = sequence.charAt(i);
2185
}
2186
2187
String.initCompressionFlag();
2188
}
2189
} else {
2190
count = size;
2191
2192
for (int i = 0; i < size; ++i) {
2193
value[i] = sequence.charAt(i);
2194
}
2195
}
2196
}
2197
}
2198
2199
/**
2200
* Adds the specified CharSequence to the end of this StringBuilder.
2201
*
2202
* @param sequence the CharSequence
2203
* @return this StringBuilder
2204
*/
2205
@Override
2206
public StringBuilder append(CharSequence sequence) {
2207
if (sequence == null) {
2208
return append(String.valueOf(sequence));
2209
} else if (sequence instanceof String) {
2210
return append((String)sequence);
2211
} else if (sequence instanceof StringBuffer) {
2212
return append((StringBuffer)sequence);
2213
} else if (sequence instanceof StringBuilder) {
2214
StringBuilder builder = (StringBuilder) sequence;
2215
2216
// Check if the StringBuilder is compressed
2217
if (String.COMPACT_STRINGS && builder.count >= 0) {
2218
return append(builder.value, 0, builder.lengthInternal(), true);
2219
} else {
2220
return append(builder.value, 0, builder.lengthInternal(), false);
2221
}
2222
} else {
2223
int currentLength = lengthInternal();
2224
int currentCapacity = capacityInternal();
2225
2226
int sequenceLength = sequence.length();
2227
2228
int newLength = currentLength + sequenceLength;
2229
if (newLength < 0) {
2230
/*[MSG "K0D01", "Array capacity exceeded"]*/
2231
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
2232
}
2233
2234
if (String.COMPACT_STRINGS) {
2235
boolean isCompressed = true;
2236
2237
if (count >= 0) {
2238
for (int i = 0; i < sequence.length(); ++i) {
2239
if (sequence.charAt(i) > 255) {
2240
isCompressed = false;
2241
2242
break;
2243
}
2244
}
2245
}
2246
2247
// Check if the StringBuilder is compressed
2248
if (count >= 0 && isCompressed) {
2249
if (newLength > currentCapacity) {
2250
ensureCapacityImpl(newLength);
2251
}
2252
2253
for (int i = 0; i < sequence.length(); ++i) {
2254
helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(i));
2255
}
2256
2257
count = newLength;
2258
} else {
2259
// Check if the StringBuilder is compressed
2260
if (count >= 0) {
2261
currentCapacity = decompress(newLength);
2262
}
2263
2264
if (newLength > currentCapacity) {
2265
ensureCapacityImpl(newLength);
2266
}
2267
2268
for (int i = 0; i < sequence.length(); ++i) {
2269
value[currentLength + i] = sequence.charAt(i);
2270
}
2271
2272
count = newLength | uncompressedBit;
2273
}
2274
} else {
2275
if (newLength > currentCapacity) {
2276
ensureCapacityImpl(newLength);
2277
}
2278
2279
for (int i = 0; i < sequence.length(); ++i) {
2280
value[currentLength + i] = sequence.charAt(i);
2281
}
2282
2283
count = newLength;
2284
}
2285
2286
return this;
2287
}
2288
}
2289
2290
/**
2291
* Adds the specified CharSequence to the end of this StringBuilder.
2292
*
2293
* @param sequence the CharSequence
2294
* @param start the offset of the first character
2295
* @param end the offset one past the last character
2296
* @return this StringBuilder
2297
*
2298
* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or
2299
* {@code end > length()}
2300
*/
2301
@Override
2302
public StringBuilder append(CharSequence sequence, int start, int end) {
2303
if (sequence == null) {
2304
return append(String.valueOf(sequence), start, end);
2305
} else if (sequence instanceof String) {
2306
String sequenceString = (String) sequence;
2307
if (start >= 0 && start <= end && end <= sequenceString.lengthInternal()) {
2308
2309
int currentLength = lengthInternal();
2310
int currentCapacity = capacityInternal();
2311
int newLength = currentLength + end - start;
2312
if (newLength < 0) {
2313
/*[MSG "K0D01", "Array capacity exceeded"]*/
2314
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
2315
}
2316
2317
if (String.COMPACT_STRINGS) {
2318
2319
// Check if the StringBuilder is compressed
2320
if (count >= 0 && sequenceString.isCompressed()) {
2321
if (newLength > currentCapacity) {
2322
ensureCapacityImpl(newLength);
2323
}
2324
2325
sequenceString.getBytes(start, end, value, currentLength);
2326
count = newLength;
2327
} else {
2328
// Check if the StringBuilder is compressed
2329
if (count >= 0) {
2330
currentCapacity = decompress(newLength);
2331
}
2332
2333
if (newLength > currentCapacity) {
2334
ensureCapacityImpl(newLength);
2335
}
2336
2337
sequenceString.getCharsNoBoundChecks(start, end, value, currentLength);
2338
count = newLength | uncompressedBit;
2339
}
2340
} else {
2341
if (newLength > currentCapacity) {
2342
ensureCapacityImpl(newLength);
2343
}
2344
2345
sequenceString.getCharsNoBoundChecks(start, end, value, currentLength);
2346
count = newLength;
2347
}
2348
return this;
2349
} else {
2350
throw new IndexOutOfBoundsException();
2351
}
2352
} else if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {
2353
if (sequence instanceof StringBuffer) {
2354
synchronized (sequence) {
2355
StringBuffer buffer = (StringBuffer) sequence;
2356
2357
if (String.COMPACT_STRINGS && buffer.isCompressed()) {
2358
return append(buffer.getValue(), start, end - start, true);
2359
} else {
2360
return append(buffer.getValue(), start, end - start, false);
2361
}
2362
}
2363
} else if (sequence instanceof StringBuilder) {
2364
synchronized (sequence) {
2365
StringBuilder builder = (StringBuilder) sequence;
2366
2367
// Check if the StringBuilder is compressed
2368
if (String.COMPACT_STRINGS && builder.count >= 0) {
2369
return append(builder.value, start, end - start, true);
2370
} else {
2371
return append(builder.value, start, end - start, false);
2372
}
2373
}
2374
} else {
2375
int currentLength = lengthInternal();
2376
int currentCapacity = capacityInternal();
2377
2378
int newLength = currentLength + end - start;
2379
if (newLength < 0) {
2380
/*[MSG "K0D01", "Array capacity exceeded"]*/
2381
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
2382
}
2383
2384
if (String.COMPACT_STRINGS) {
2385
boolean isCompressed = true;
2386
2387
if (count >= 0) {
2388
for (int i = 0; i < sequence.length(); ++i) {
2389
if (sequence.charAt(i) > 255) {
2390
isCompressed = false;
2391
2392
break;
2393
}
2394
}
2395
}
2396
2397
// Check if the StringBuilder is compressed
2398
if (count >= 0 && isCompressed) {
2399
if (newLength > currentCapacity) {
2400
ensureCapacityImpl(newLength);
2401
}
2402
2403
for (int i = 0; i < end - start; ++i) {
2404
helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(start + i));
2405
}
2406
2407
count = newLength;
2408
} else {
2409
// Check if the StringBuilder is compressed
2410
if (count >= 0) {
2411
currentCapacity = decompress(newLength);
2412
}
2413
2414
if (newLength > currentCapacity) {
2415
ensureCapacityImpl(newLength);
2416
}
2417
2418
for (int i = 0; i < end - start; ++i) {
2419
value[currentLength + i] = sequence.charAt(start + i);
2420
}
2421
2422
count = newLength | uncompressedBit;
2423
}
2424
} else {
2425
if (newLength > currentCapacity) {
2426
ensureCapacityImpl(newLength);
2427
}
2428
2429
for (int i = 0; i < end - start; ++i) {
2430
value[currentLength + i] = sequence.charAt(start + i);
2431
}
2432
2433
count = newLength;
2434
}
2435
2436
return this;
2437
}
2438
} else {
2439
throw new IndexOutOfBoundsException();
2440
}
2441
}
2442
2443
/**
2444
* Inserts the CharSequence at the specified offset in this StringBuilder.
2445
*
2446
* @param index the index at which to insert
2447
* @param sequence the CharSequence to insert
2448
* @return this StringBuilder
2449
*
2450
* @exception IndexOutOfBoundsException when {@code index < 0} or
2451
* {@code index > length()}
2452
*/
2453
public StringBuilder insert(int index, CharSequence sequence) {
2454
int currentLength = lengthInternal();
2455
2456
if (index >= 0 && index <= currentLength) {
2457
if (sequence == null) {
2458
return insert(index, String.valueOf(sequence));
2459
} else if (sequence instanceof String) {
2460
return insert(index, (String) sequence);
2461
} else if (sequence instanceof StringBuffer) {
2462
synchronized(sequence) {
2463
StringBuffer buffer = (StringBuffer) sequence;
2464
2465
if (String.COMPACT_STRINGS && buffer.isCompressed()) {
2466
return insert(index, buffer.getValue(), 0, buffer.length(), true);
2467
} else {
2468
return insert(index, buffer.getValue(), 0, buffer.length(), false);
2469
}
2470
}
2471
} else if (sequence instanceof StringBuilder) {
2472
synchronized (sequence) {
2473
StringBuilder builder = (StringBuilder) sequence;
2474
2475
// Check if the StringBuilder is compressed
2476
if (String.COMPACT_STRINGS && builder.count >= 0) {
2477
return insert(index, builder.value, 0, builder.lengthInternal(), true);
2478
} else {
2479
return insert(index, builder.value, 0, builder.lengthInternal(), false);
2480
}
2481
}
2482
} else {
2483
int sequneceLength = sequence.length();
2484
2485
if (sequneceLength > 0) {
2486
move(sequneceLength, index);
2487
2488
int newLength = currentLength + sequneceLength;
2489
2490
if (String.COMPACT_STRINGS) {
2491
boolean isCompressed = true;
2492
2493
for (int i = 0; i < sequneceLength; ++i) {
2494
if (sequence.charAt(i) > 255) {
2495
isCompressed = false;
2496
2497
break;
2498
}
2499
}
2500
2501
// Check if the StringBuilder is compressed
2502
if (count >= 0 && isCompressed) {
2503
for (int i = 0; i < sequneceLength; ++i) {
2504
helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(i));
2505
}
2506
2507
count = newLength;
2508
2509
return this;
2510
} else {
2511
// Check if the StringBuilder is compressed
2512
if (count >= 0) {
2513
decompress(value.length);
2514
}
2515
2516
for (int i = 0; i < sequneceLength; ++i) {
2517
value[index + i] = sequence.charAt(i);
2518
}
2519
2520
count = newLength | uncompressedBit;
2521
}
2522
} else {
2523
for (int i = 0; i < sequneceLength; ++i) {
2524
value[index + i] = sequence.charAt(i);
2525
}
2526
2527
count = newLength;
2528
}
2529
}
2530
2531
return this;
2532
}
2533
} else {
2534
throw new IndexOutOfBoundsException();
2535
}
2536
}
2537
2538
/**
2539
* Inserts the CharSequence at the specified offset in this StringBuilder.
2540
*
2541
* @param index the index at which to insert
2542
* @param sequence the CharSequence to insert
2543
* @param start the offset of the first character
2544
* @param end the offset one past the last character
2545
* @return this StringBuilder
2546
*
2547
* @exception IndexOutOfBoundsException when {@code index < 0} or
2548
* {@code index > length()}, or when {@code start < 0, start > end} or
2549
* {@code end > length()}
2550
*/
2551
public StringBuilder insert(int index, CharSequence sequence, int start, int end) {
2552
int currentLength = lengthInternal();
2553
2554
if (index >= 0 && index <= currentLength) {
2555
if (sequence == null)
2556
return insert(index, String.valueOf(sequence), start, end);
2557
if (sequence instanceof String) {
2558
return insert(index, ((String) sequence).substring(start, end));
2559
}
2560
if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {
2561
if (sequence instanceof StringBuffer) {
2562
synchronized(sequence) {
2563
StringBuffer buffer = (StringBuffer) sequence;
2564
2565
if (String.COMPACT_STRINGS && buffer.isCompressed()) {
2566
return insert(index, buffer.getValue(), start, end - start, true);
2567
} else {
2568
return insert(index, buffer.getValue(), start, end - start, false);
2569
}
2570
}
2571
} else if (sequence instanceof StringBuilder) {
2572
synchronized(sequence) {
2573
StringBuilder builder = (StringBuilder) sequence;
2574
2575
// Check if the StringBuilder is compressed
2576
if (String.COMPACT_STRINGS && builder.count >= 0) {
2577
return insert(index, builder.value, start, end - start, true);
2578
} else {
2579
return insert(index, builder.value, start, end - start, false);
2580
}
2581
}
2582
} else {
2583
int sequenceLength = end - start;
2584
2585
if (sequenceLength > 0) {
2586
move(sequenceLength, index);
2587
2588
int newLength = currentLength + sequenceLength;
2589
2590
if (String.COMPACT_STRINGS) {
2591
boolean isCompressed = true;
2592
2593
for (int i = 0; i < sequenceLength; ++i) {
2594
if (sequence.charAt(start + i) > 255) {
2595
isCompressed = false;
2596
2597
break;
2598
}
2599
}
2600
2601
// Check if the StringBuilder is compressed
2602
if (count >= 0 && isCompressed) {
2603
for (int i = 0; i < sequenceLength; ++i) {
2604
helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(start + i));
2605
}
2606
2607
count = newLength;
2608
2609
return this;
2610
} else {
2611
// Check if the StringBuilder is compressed
2612
if (count >= 0) {
2613
decompress(value.length);
2614
}
2615
2616
for (int i = 0; i < sequenceLength; ++i) {
2617
value[index + i] = sequence.charAt(start + i);
2618
}
2619
2620
count = newLength | uncompressedBit;
2621
}
2622
} else {
2623
for (int i = 0; i < sequenceLength; ++i) {
2624
value[index + i] = sequence.charAt(start + i);
2625
}
2626
2627
count = newLength;
2628
}
2629
}
2630
2631
return this;
2632
}
2633
} else {
2634
throw new IndexOutOfBoundsException();
2635
}
2636
} else {
2637
throw new IndexOutOfBoundsException();
2638
}
2639
}
2640
2641
/**
2642
* Optionally modify the underlying char array to only
2643
* be large enough to hold the characters in this StringBuffer.
2644
*/
2645
public void trimToSize() {
2646
int currentLength = lengthInternal();
2647
int currentCapacity = capacityInternal();
2648
2649
// Check if the StringBuilder is compressed
2650
if (String.COMPACT_STRINGS && count >= 0) {
2651
// Check if the StringBuilder is not shared
2652
if (capacity >= 0 && currentCapacity != currentLength) {
2653
char[] newData = new char[(currentLength + 1) / 2];
2654
2655
String.compressedArrayCopy(value, 0, newData, 0, currentLength);
2656
2657
value = newData;
2658
2659
capacity = currentLength;
2660
}
2661
} else {
2662
// Check if the StringBuilder is not shared
2663
if (capacity >= 0 && currentCapacity != currentLength) {
2664
char[] newData = new char[currentLength];
2665
2666
String.decompressedArrayCopy(value, 0, newData, 0, currentLength);
2667
2668
value = newData;
2669
2670
capacity = currentLength;
2671
}
2672
}
2673
}
2674
2675
/**
2676
* Returns the Unicode character at the given point.
2677
*
2678
* @param index the character index
2679
* @return the Unicode character value at the index
2680
*/
2681
public int codePointAt(int index) {
2682
int currentLength = lengthInternal();
2683
2684
if (index >= 0 && index < currentLength) {
2685
// Check if the StringBuilder is compressed
2686
if (String.COMPACT_STRINGS && count >= 0) {
2687
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
2688
} else {
2689
int high = value[index];
2690
2691
if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2692
int low = value[index + 1];
2693
2694
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2695
return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);
2696
}
2697
}
2698
2699
return high;
2700
}
2701
} else {
2702
throw new StringIndexOutOfBoundsException(index);
2703
}
2704
}
2705
2706
/**
2707
* Returns the Unicode character before the given point.
2708
*
2709
* @param index the character index
2710
* @return the Unicode character value before the index
2711
*/
2712
public int codePointBefore(int index) {
2713
int currentLength = lengthInternal();
2714
2715
if (index > 0 && index <= currentLength) {
2716
// Check if the StringBuilder is compressed
2717
if (String.COMPACT_STRINGS && count >= 0) {
2718
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));
2719
} else {
2720
int low = value[index - 1];
2721
2722
if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2723
int high = value[index - 2];
2724
2725
if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2726
return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);
2727
}
2728
}
2729
2730
return low;
2731
}
2732
} else {
2733
throw new StringIndexOutOfBoundsException(index);
2734
}
2735
}
2736
2737
/**
2738
* Returns the total Unicode values in the specified range.
2739
*
2740
* @param start first index
2741
* @param end last index
2742
* @return the total Unicode values
2743
*/
2744
public int codePointCount(int start, int end) {
2745
int currentLength = lengthInternal();
2746
2747
if (start >= 0 && start <= end && end <= currentLength) {
2748
// Check if the StringBuilder is compressed
2749
if (String.COMPACT_STRINGS && count >= 0) {
2750
return end - start;
2751
} else {
2752
int count = 0;
2753
2754
for (int i = start; i < end; ++i) {
2755
int high = value[i];
2756
2757
if (i + 1 < end && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2758
int low = value[i + 1];
2759
2760
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2761
++i;
2762
}
2763
}
2764
2765
++count;
2766
}
2767
2768
return count;
2769
}
2770
} else {
2771
throw new IndexOutOfBoundsException();
2772
}
2773
}
2774
2775
/**
2776
* Returns the index of the code point that was offset by {@code codePointCount}.
2777
*
2778
* @param start the position to offset
2779
* @param codePointCount the code point count
2780
* @return the offset index
2781
*/
2782
public int offsetByCodePoints(int start, int codePointCount) {
2783
int currentLength = lengthInternal();
2784
2785
if (start >= 0 && start <= currentLength) {
2786
// Check if the StringBuilder is compressed
2787
if (String.COMPACT_STRINGS && count >= 0) {
2788
int index = start + codePointCount;
2789
2790
if (index >= currentLength) {
2791
throw new IndexOutOfBoundsException();
2792
} else {
2793
return index;
2794
}
2795
} else {
2796
int index = start;
2797
2798
if (codePointCount == 0) {
2799
return start;
2800
} else if (codePointCount > 0) {
2801
for (int i = 0; i < codePointCount; ++i) {
2802
if (index == currentLength) {
2803
throw new IndexOutOfBoundsException();
2804
}
2805
2806
int high = value[index];
2807
2808
if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2809
int low = value[index + 1];
2810
2811
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2812
index++;
2813
}
2814
}
2815
2816
index++;
2817
}
2818
} else {
2819
for (int i = codePointCount; i < 0; ++i) {
2820
if (index < 1) {
2821
throw new IndexOutOfBoundsException();
2822
}
2823
2824
int low = value[index - 1];
2825
2826
if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2827
int high = value[index - 2];
2828
2829
if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2830
index--;
2831
}
2832
}
2833
2834
index--;
2835
}
2836
}
2837
2838
return index;
2839
}
2840
} else {
2841
throw new IndexOutOfBoundsException();
2842
}
2843
}
2844
2845
/**
2846
* Adds the specified code point to the end of this StringBuffer.
2847
*
2848
* @param codePoint the code point
2849
* @return this StringBuffer
2850
*/
2851
public StringBuilder appendCodePoint(int codePoint) {
2852
if (codePoint >= 0) {
2853
if (codePoint < 0x10000) {
2854
return append((char)codePoint);
2855
} else if (codePoint < 0x110000) {
2856
// Check if the StringBuilder is compressed
2857
if (String.COMPACT_STRINGS && count >= 0) {
2858
decompress(value.length);
2859
}
2860
2861
int currentLength = lengthInternal();
2862
int currentCapacity = capacityInternal();
2863
2864
int newLength = currentLength + 2;
2865
if (newLength < 0) {
2866
/*[MSG "K0D01", "Array capacity exceeded"]*/
2867
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
2868
}
2869
2870
if (newLength > currentCapacity) {
2871
ensureCapacityImpl(newLength);
2872
}
2873
2874
codePoint -= 0x10000;
2875
2876
value[currentLength] = (char) (Character.MIN_HIGH_SURROGATE + (codePoint >> 10));
2877
value[currentLength + 1] = (char) (Character.MIN_LOW_SURROGATE + (codePoint & 0x3ff));
2878
2879
if (String.COMPACT_STRINGS) {
2880
count = newLength | uncompressedBit;
2881
} else {
2882
count = newLength;
2883
}
2884
2885
return this;
2886
}
2887
}
2888
2889
throw new IllegalArgumentException();
2890
}
2891
2892
/*
2893
* Returns the character array for this StringBuilder.
2894
*/
2895
char[] getValue() {
2896
return value;
2897
}
2898
2899
}
2900
2901