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/StringBuffer.java
12513 views
1
/*[INCLUDE-IF JAVA_SPEC_VERSION == 8]*/
2
/*******************************************************************************
3
* Copyright (c) 1998, 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
* StringBuffer is a variable size contiguous indexable array of characters.
35
* The length of the StringBuffer is the number of characters it contains.
36
* The capacity of the StringBuffer is the number of characters it can hold.
37
* <p>
38
* Characters may be inserted at any position up to the length of the
39
* StringBuffer, increasing the length of the StringBuffer. Characters at any
40
* position in the StringBuffer may be replaced, which does not affect the
41
* StringBuffer length.
42
* <p>
43
* The capacity of a StringBuffer may be specified when the StringBuffer is
44
* created. If the capacity of the StringBuffer is exceeded, the capacity
45
* is increased.
46
*
47
* @author OTI
48
* @version initial
49
*
50
* @see String
51
*/
52
public final class StringBuffer extends AbstractStringBuilder implements Serializable, CharSequence, Appendable {
53
private static final long serialVersionUID = 3388685877147921107L;
54
55
private static final int INITIAL_SIZE = 16;
56
57
private static boolean TOSTRING_COPY_BUFFER_ENABLED = false;
58
private static boolean growAggressively = false;
59
60
// Used to access compression related helper methods
61
private static final com.ibm.jit.JITHelpers helpers = com.ibm.jit.JITHelpers.getHelpers();
62
63
// Represents the bit in count field to test for whether this StringBuffer backing array is not compressed
64
// under String compression mode. This bit is not used when String compression is disabled.
65
private static final int uncompressedBit = 0x80000000;
66
67
// Represents the bit in capacity field to test for whether this StringBuffer backing array is shared.
68
private static final int sharedBit = 0x80000000;
69
70
private static final java.io.ObjectStreamField serialPersistentFields[] = new java.io.ObjectStreamField[] {
71
new java.io.ObjectStreamField("count", Integer.TYPE), //$NON-NLS-1$
72
new java.io.ObjectStreamField("value", char[].class), //$NON-NLS-1$
73
new java.io.ObjectStreamField("shared", Boolean.TYPE), //$NON-NLS-1$
74
};
75
76
private int count;
77
private char[] value;
78
private int capacity;
79
80
private void decompress(int min) {
81
int currentLength = lengthInternalUnsynchronized();
82
int currentCapacity = capacityInternal();
83
char[] newValue;
84
85
if (min > currentCapacity) {
86
/* twice may be negative, in which case we'll use min */
87
int twice = (currentCapacity << 1) + 2;
88
89
newValue = new char[min > twice ? min : twice];
90
} else {
91
newValue = new char[currentCapacity];
92
}
93
94
String.decompress(value, 0, newValue, 0, currentLength);
95
96
count = count | uncompressedBit;
97
value = newValue;
98
capacity = newValue.length;
99
100
String.initCompressionFlag();
101
}
102
103
/**
104
* Constructs a new StringBuffer using the default capacity.
105
*/
106
public StringBuffer() {
107
this(INITIAL_SIZE);
108
}
109
110
/**
111
* Constructs a new StringBuffer using the specified capacity.
112
*
113
* @param capacity the initial capacity
114
*/
115
public StringBuffer(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 StringBuffer containing the characters in
137
* the specified string and the default capacity.
138
*
139
* @param string the initial contents of this StringBuffer
140
* @exception NullPointerException when string is null
141
*/
142
public StringBuffer (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
string.getBytes(0, stringLength, value, 0);
155
156
capacity = newLength;
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 StringBuffer.
183
*
184
* @param chars the character array
185
* @return this StringBuffer
186
*
187
* @exception NullPointerException when chars is null
188
*/
189
public synchronized StringBuffer append (char[] chars) {
190
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer is compressed
211
if (count >= 0) {
212
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 StringBuffer.
239
*
240
* @param chars a character array
241
* @param start the starting offset
242
* @param length the number of characters
243
* @return this StringBuffer
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 synchronized StringBuffer append (char chars[], int start, int length) {
250
if (start >= 0 && 0 <= length && length <= chars.length - start) {
251
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer is compressed
272
if (count >= 0) {
273
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
synchronized StringBuffer append (char[] chars, int start, int length, boolean compressed) {
301
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer is compressed
322
if (count >= 0) {
323
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 StringBuffer.
358
*
359
* @param ch a character
360
* @return this StringBuffer
361
*/
362
@Override
363
public synchronized StringBuffer append(char ch) {
364
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer is compressed
385
if (count >= 0) {
386
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 StringBuffer.
413
*
414
* @param value the double
415
* @return this StringBuffer
416
*/
417
public StringBuffer 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 StringBuffer.
424
*
425
* @param value the float
426
* @return this StringBuffer
427
*/
428
public StringBuffer 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 StringBuffer.
435
*
436
* @param value the integer
437
* @return this StringBuffer
438
*/
439
public synchronized StringBuffer 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 = lengthInternalUnsynchronized();
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 StringBuffer.
484
*
485
* @param value the long
486
* @return this StringBuffer
487
*/
488
public synchronized StringBuffer 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 = lengthInternalUnsynchronized();
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 StringBuffer.
533
*
534
* @param value the object
535
* @return this StringBuffer
536
*/
537
public StringBuffer append (Object value) {
538
return append (String.valueOf (value));
539
}
540
541
/**
542
* Adds the specified string to the end of this StringBuffer.
543
*
544
* @param string the string
545
* @return this StringBuffer
546
*/
547
public synchronized StringBuffer append (String string) {
548
if (string == null) {
549
string = "null"; //$NON-NLS-1$
550
}
551
552
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer is compressed
575
if (count >= 0) {
576
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 StringBuffer.
603
*
604
* @param value the boolean
605
* @return this StringBuffer
606
*/
607
public StringBuffer append (boolean value) {
608
return append (String.valueOf (value));
609
}
610
611
/**
612
* Answers the number of characters this StringBuffer can hold without
613
* growing.
614
*
615
* @return the capacity of this StringBuffer
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 StringBuffer 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 StringBuffer
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 StringBuffer.
640
*
641
* @param index the zero-based index in this StringBuffer
642
* @return the character at the index
643
*
644
* @exception IndexOutOfBoundsException
645
* If {@code index < 0} or {@code index >= length()}
646
*/
647
@Override
648
public synchronized char charAt(int index) {
649
int currentLength = lengthInternalUnsynchronized();
650
651
if (index >= 0 && index < currentLength) {
652
// Check if the StringBuffer 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 StringBuffer
669
*
670
* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or
671
* {@code end > length()}
672
*/
673
public synchronized StringBuffer delete(int start, int end) {
674
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer is not shared
686
if (capacity >= 0) {
687
if (numberOfTailChars > 0) {
688
// Check if the StringBuffer 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 StringBuffer 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 StringBuffer 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 StringBuffer
754
*
755
* @exception StringIndexOutOfBoundsException when {@code location < 0} or
756
* {@code location >= length()}
757
*/
758
public synchronized StringBuffer deleteCharAt(int location) {
759
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer can hold the specified number of characters
770
* without growing.
771
*
772
* @param min the minimum number of elements that this
773
* StringBuffer will hold before growing
774
*/
775
public synchronized 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 = lengthInternalUnsynchronized();
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 StringBuffer 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 synchronized void getChars(int start, int end, char[] buffer, int index) {
826
try {
827
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer.
854
*
855
* @param index the index at which to insert
856
* @param chars the character array to insert
857
* @return this StringBuffer
858
*
859
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
860
* {@code index > length()}
861
* @exception NullPointerException when chars is null
862
*/
863
public synchronized StringBuffer insert(int index, char[] chars) {
864
int currentLength = lengthInternalUnsynchronized();
865
866
if (0 <= index && index <= currentLength) {
867
move(chars.length, index);
868
869
if (String.COMPACT_STRINGS) {
870
// Check if the StringBuffer 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 StringBuffer 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 StringBuffer.
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 StringBuffer
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 synchronized StringBuffer insert(int index, char[] chars, int start, int length) {
917
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer 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
synchronized StringBuffer insert(int index, char[] chars, int start, int length, boolean compressed) {
959
int currentLength = lengthInternalUnsynchronized();
960
961
move(length, index);
962
963
if (String.COMPACT_STRINGS) {
964
// Check if the StringBuffer 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 StringBuffer.
993
*
994
* @param index the index at which to insert
995
* @param ch the character to insert
996
* @return this StringBuffer
997
*
998
* @exception IndexOutOfBoundsException when {@code index < 0} or
999
* {@code index > length()}
1000
*/
1001
public synchronized StringBuffer insert(int index, char ch) {
1002
int currentLength = lengthInternalUnsynchronized();
1003
1004
if (0 <= index && index <= currentLength) {
1005
move(1, index);
1006
1007
if (String.COMPACT_STRINGS ) {
1008
// Check if the StringBuffer 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 StringBuffer 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 StringBuffer.
1042
*
1043
* @param index the index at which to insert
1044
* @param value the double to insert
1045
* @return this StringBuffer
1046
*
1047
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1048
* {@code index > length()}
1049
*/
1050
public StringBuffer 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 StringBuffer.
1057
*
1058
* @param index the index at which to insert
1059
* @param value the float to insert
1060
* @return this StringBuffer
1061
*
1062
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1063
* {@code index > length()}
1064
*/
1065
public StringBuffer 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 StringBuffer.
1072
*
1073
* @param index the index at which to insert
1074
* @param value the integer to insert
1075
* @return this StringBuffer
1076
*
1077
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1078
* {@code index > length()}
1079
*/
1080
public StringBuffer 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 StringBuffer.
1087
*
1088
* @param index the index at which to insert
1089
* @param value the long to insert
1090
* @return this StringBuffer
1091
*
1092
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1093
* {@code index > length()}
1094
*/
1095
public StringBuffer 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 StringBuffer.
1102
*
1103
* @param index the index at which to insert
1104
* @param value the object to insert
1105
* @return this StringBuffer
1106
*
1107
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1108
* {@code index > length()}
1109
*/
1110
public StringBuffer 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 StringBuffer.
1116
*
1117
* @param index the index at which to insert
1118
* @param string the string to insert
1119
* @return this StringBuffer
1120
*
1121
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1122
* {@code index > length()}
1123
*/
1124
public synchronized StringBuffer insert(int index, String string) {
1125
int currentLength = lengthInternalUnsynchronized();
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 StringBuffer 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 StringBuffer 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 StringBuffer.
1171
*
1172
* @param index the index at which to insert
1173
* @param value the boolean to insert
1174
* @return this StringBuffer
1175
*
1176
* @exception StringIndexOutOfBoundsException when {@code index < 0} or
1177
* {@code index > length()}
1178
*/
1179
public StringBuffer insert(int index, boolean value) {
1180
return insert(index, String.valueOf(value));
1181
}
1182
1183
/**
1184
* Answers the size of this StringBuffer.
1185
*
1186
* @return the number of characters in this StringBuffer
1187
*/
1188
@Override
1189
public synchronized int length() {
1190
return lengthInternalUnsynchronized();
1191
}
1192
1193
/**
1194
* Answers the size of this StringBuffer. This is an unsynchronized private method and is meant to be called only
1195
* from methods of this class which have already synchronized on the this StringBuffer object.
1196
*
1197
* The JIT compiler will take special precaution to avoid generating HCR guards for calls to this method.
1198
* @return the number of characters in this StringBuffer
1199
*/
1200
private int lengthInternalUnsynchronized() {
1201
if (String.COMPACT_STRINGS) {
1202
// Check if the StringBuffer 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 = lengthInternalUnsynchronized();
1215
int currentCapacity = capacityInternal();
1216
1217
// Check if the StringBuffer is compressed
1218
if (String.COMPACT_STRINGS && count >= 0) {
1219
int newLength;
1220
1221
if (currentCapacity - currentLength >= size) {
1222
// Check if the StringBuffer 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 StringBuffer is not shared
1251
if (capacity >= 0) {
1252
String.decompressedArrayCopy(value, index, value, index + size, currentLength - index);
1253
return;
1254
}
1255
1256
newLength = currentCapacity;
1257
} else {
1258
newLength = Integer.max(currentLength + size, (currentCapacity << 1) + 2);
1259
if (newLength < 0) {
1260
/*[MSG "K0D01", "Array capacity exceeded"]*/
1261
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
1262
}
1263
}
1264
1265
char[] newData = new char[newLength];
1266
1267
String.decompressedArrayCopy(value, 0, newData, 0, index);
1268
String.decompressedArrayCopy(value, index, newData, index + size, currentLength - index);
1269
1270
value = newData;
1271
1272
capacity = newLength;
1273
}
1274
}
1275
1276
/**
1277
* Replace a range of characters with the characters in the specified String.
1278
*
1279
* @param start the offset of the first character
1280
* @param end the offset one past the last character
1281
* @param string a String
1282
* @return this StringBuffer
1283
*
1284
* @exception StringIndexOutOfBoundsException when {@code start < 0} or
1285
* {@code start > end}
1286
*/
1287
public synchronized StringBuffer replace(int start, int end, String string) {
1288
int currentLength = lengthInternalUnsynchronized();
1289
1290
if (String.COMPACT_STRINGS) {
1291
// Check if the StringBuffer is compressed
1292
if (count >= 0 && string.isCompressed()) {
1293
if (start >= 0) {
1294
if (end > currentLength) {
1295
end = currentLength;
1296
}
1297
1298
if (end > start) {
1299
int size = string.lengthInternal();
1300
1301
// Difference between the substring we wish to replace and the size of the string parameter
1302
int difference = end - start - size;
1303
1304
if (difference > 0) {
1305
// Check if the StringBuffer is not shared
1306
if (capacity >= 0) {
1307
String.compressedArrayCopy(value, end, value, start + size, currentLength - end);
1308
} else {
1309
char[] newData = new char[value.length];
1310
1311
String.compressedArrayCopy(value, 0, newData, 0, start);
1312
String.compressedArrayCopy(value, end, newData, start + size, currentLength - end);
1313
1314
value = newData;
1315
1316
capacity = capacity & ~sharedBit;
1317
}
1318
} else if (difference < 0) {
1319
move(-difference, end);
1320
} else if (capacity < 0) {
1321
value = value.clone();
1322
1323
capacity = capacity & ~sharedBit;
1324
}
1325
1326
string.getBytes(0, size, value, start);
1327
1328
count = currentLength - difference;
1329
1330
return this;
1331
}
1332
1333
if (start == end) {
1334
return insert(start, string);
1335
}
1336
}
1337
} else {
1338
// Check if the StringBuffer is compressed
1339
if (count >= 0) {
1340
decompress(value.length);
1341
}
1342
1343
if (start >= 0) {
1344
if (end > currentLength) {
1345
end = currentLength;
1346
}
1347
1348
if (end > start) {
1349
int size = string.lengthInternal();
1350
1351
// Difference between the substring we wish to replace and the size of the string parameter
1352
int difference = end - start - size;
1353
1354
if (difference > 0) {
1355
// Check if the StringBuffer is not shared
1356
if (capacity >= 0) {
1357
String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);
1358
} else {
1359
char[] newData = new char[value.length];
1360
1361
String.decompressedArrayCopy(value, 0, newData, 0, start);
1362
String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);
1363
1364
value = newData;
1365
1366
capacity = capacity & ~sharedBit;
1367
}
1368
} else if (difference < 0) {
1369
move(-difference, end);
1370
} else if (capacity < 0) {
1371
value = value.clone();
1372
1373
capacity = capacity & ~sharedBit;
1374
}
1375
1376
string.getCharsNoBoundChecks(0, size, value, start);
1377
1378
count = (currentLength - difference) | uncompressedBit;
1379
1380
return this;
1381
}
1382
1383
if (start == end) {
1384
string.getClass(); // Implicit null check
1385
1386
return insert(start, string);
1387
}
1388
}
1389
}
1390
} else {
1391
if (start >= 0) {
1392
if (end > currentLength) {
1393
end = currentLength;
1394
}
1395
1396
if (end > start) {
1397
int size = string.lengthInternal();
1398
1399
// Difference between the substring we wish to replace and the size of the string parameter
1400
int difference = end - start - size;
1401
1402
if (difference > 0) {
1403
// Check if the StringBuffer is not shared
1404
if (capacity >= 0) {
1405
String.decompressedArrayCopy(value, end, value, start + size, currentLength - end);
1406
} else {
1407
char[] newData = new char[value.length];
1408
1409
String.decompressedArrayCopy(value, 0, newData, 0, start);
1410
String.decompressedArrayCopy(value, end, newData, start + size, currentLength - end);
1411
value = newData;
1412
1413
capacity = capacity & ~sharedBit;
1414
}
1415
} else if (difference < 0) {
1416
move(-difference, end);
1417
} else if (capacity < 0) {
1418
value = value.clone();
1419
1420
capacity = capacity & ~sharedBit;
1421
}
1422
1423
string.getCharsNoBoundChecks(0, size, value, start);
1424
1425
count = currentLength - difference;
1426
1427
return this;
1428
}
1429
1430
if (start == end) {
1431
string.getClass(); // Implicit null check
1432
1433
return insert(start, string);
1434
}
1435
}
1436
}
1437
1438
throw new StringIndexOutOfBoundsException();
1439
}
1440
1441
/**
1442
* Reverses the order of characters in this StringBuffer.
1443
*
1444
* @return this StringBuffer
1445
*/
1446
public synchronized StringBuffer reverse() {
1447
int currentLength = lengthInternalUnsynchronized();
1448
1449
if (currentLength < 2) {
1450
return this;
1451
}
1452
1453
// Check if the StringBuffer is compressed
1454
if (String.COMPACT_STRINGS && count >= 0) {
1455
// Check if the StringBuffer is not shared
1456
if (capacity >= 0) {
1457
for (int i = 0, mid = currentLength / 2, j = currentLength - 1; i < mid; ++i, --j) {
1458
byte a = helpers.getByteFromArrayByIndex(value, i);
1459
byte b = helpers.getByteFromArrayByIndex(value, j);
1460
1461
helpers.putByteInArrayByIndex(value, i, b);
1462
helpers.putByteInArrayByIndex(value, j, a);
1463
}
1464
1465
return this;
1466
} else {
1467
char[] newData = new char[value.length];
1468
1469
for (int i = 0, j = currentLength - 1; i < currentLength; ++i, --j) {
1470
helpers.putByteInArrayByIndex(newData, j, helpers.getByteFromArrayByIndex(value, i));
1471
}
1472
1473
value = newData;
1474
1475
capacity = capacity & ~sharedBit;
1476
1477
return this;
1478
}
1479
} else {
1480
// Check if the StringBuffer is not shared
1481
if (capacity >= 0) {
1482
int end = currentLength - 1;
1483
1484
char frontHigh = value[0];
1485
char endLow = value[end];
1486
boolean allowFrontSur = true, allowEndSur = true;
1487
for (int i = 0, mid = currentLength / 2; i < mid; i++, --end) {
1488
char frontLow = value[i + 1];
1489
char endHigh = value[end - 1];
1490
boolean surAtFront = false, surAtEnd = false;
1491
if (allowFrontSur && frontLow >= Character.MIN_LOW_SURROGATE && frontLow <= Character.MAX_LOW_SURROGATE && frontHigh >= Character.MIN_HIGH_SURROGATE && frontHigh <= Character.MAX_HIGH_SURROGATE) {
1492
surAtFront = true;
1493
if (currentLength < 3) return this;
1494
}
1495
if (allowEndSur && endHigh >= Character.MIN_HIGH_SURROGATE && endHigh <= Character.MAX_HIGH_SURROGATE && endLow >= Character.MIN_LOW_SURROGATE && endLow <= Character.MAX_LOW_SURROGATE) {
1496
surAtEnd = true;
1497
}
1498
allowFrontSur = true;
1499
allowEndSur = true;
1500
if (surAtFront == surAtEnd) {
1501
if (surAtFront) {
1502
// both surrogates
1503
value[end] = frontLow;
1504
value[end - 1] = frontHigh;
1505
value[i] = endHigh;
1506
value[i + 1] = endLow;
1507
frontHigh = value[i + 2];
1508
endLow = value[end - 2];
1509
i++;
1510
--end;
1511
} else {
1512
// neither surrogates
1513
value[end] = frontHigh;
1514
value[i] = endLow;
1515
frontHigh = frontLow;
1516
endLow = endHigh;
1517
}
1518
} else {
1519
if (surAtFront) {
1520
// surrogate only at the front
1521
value[end] = frontLow;
1522
value[i] = endLow;
1523
endLow = endHigh;
1524
allowFrontSur = false;
1525
} else {
1526
// surrogate only at the end
1527
value[end] = frontHigh;
1528
value[i] = endHigh;
1529
frontHigh = frontLow;
1530
allowEndSur = false;
1531
}
1532
}
1533
}
1534
if ((currentLength & 1) == 1 && (!allowFrontSur || !allowEndSur)) {
1535
value[end] = allowFrontSur ? endLow : frontHigh;
1536
}
1537
} else {
1538
char[] newData = new char[value.length];
1539
1540
for (int i = 0, end = currentLength; i < currentLength; i++) {
1541
char high = value[i];
1542
1543
if ((i + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
1544
char low = value[i + 1];
1545
1546
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
1547
newData[--end] = low;
1548
i++;
1549
}
1550
}
1551
newData[--end] = high;
1552
}
1553
1554
value = newData;
1555
1556
capacity = capacity & ~sharedBit;
1557
}
1558
1559
return this;
1560
}
1561
}
1562
1563
/**
1564
* Sets the character at the specified offset in this StringBuffer.
1565
*
1566
* @param index the zero-based index in this StringBuffer
1567
* @param ch the character
1568
*
1569
* @exception IndexOutOfBoundsException when {@code index < 0} or
1570
* {@code index >= length()}
1571
*/
1572
public synchronized void setCharAt(int index, char ch) {
1573
int currentLength = lengthInternalUnsynchronized();
1574
1575
if (0 <= index && index < currentLength) {
1576
if (String.COMPACT_STRINGS) {
1577
// Check if the StringBuffer is compressed
1578
if (count >= 0 && ch <= 255) {
1579
if (capacity < 0) {
1580
value = value.clone();
1581
1582
capacity = capacity & ~sharedBit;
1583
}
1584
1585
helpers.putByteInArrayByIndex(value, index, (byte) ch);
1586
} else {
1587
// Check if the StringBuffer is compressed
1588
if (count >= 0) {
1589
decompress(value.length);
1590
}
1591
1592
if (capacity < 0) {
1593
value = value.clone();
1594
1595
capacity = capacity & ~sharedBit;
1596
}
1597
1598
value[index] = ch;
1599
}
1600
} else {
1601
if (capacity < 0) {
1602
value = value.clone();
1603
1604
capacity = capacity & ~sharedBit;
1605
}
1606
1607
value[index] = ch;
1608
}
1609
} else {
1610
throw new StringIndexOutOfBoundsException(index);
1611
}
1612
}
1613
1614
/**
1615
* Sets the length of this StringBuffer to the specified length. If there
1616
* are more than length characters in this StringBuffer, the characters
1617
* at end are lost. If there are less than length characters in the
1618
* StringBuffer, the additional characters are set to {@code \\u0000}.
1619
*
1620
* @param length the new length of this StringBuffer
1621
*
1622
* @exception IndexOutOfBoundsException when {@code length < 0}
1623
*
1624
* @see #length
1625
*/
1626
public synchronized void setLength(int length) {
1627
int currentLength = lengthInternalUnsynchronized();
1628
int currentCapacity = capacityInternal();
1629
1630
// Check if the StringBuffer is compressed
1631
if (String.COMPACT_STRINGS && count >= 0) {
1632
if (length > currentCapacity) {
1633
ensureCapacityImpl(length);
1634
} else if (length > currentLength) {
1635
for (int i = currentLength; i < length; ++i) {
1636
helpers.putByteInArrayByIndex(value, i, (byte) 0);
1637
}
1638
} else if (capacity < 0) {
1639
if (length < 0) {
1640
throw new IndexOutOfBoundsException();
1641
}
1642
1643
char[] newData = new char[value.length];
1644
1645
if (length > 0) {
1646
String.compressedArrayCopy(value, 0, newData, 0, length);
1647
}
1648
1649
value = newData;
1650
1651
capacity = capacity & ~sharedBit;
1652
} else if (length < 0) {
1653
throw new IndexOutOfBoundsException();
1654
}
1655
} else {
1656
if (length > currentCapacity) {
1657
ensureCapacityImpl(length);
1658
} else if (length > currentLength) {
1659
Arrays.fill(value, currentLength, length, (char) 0);
1660
} else if (capacity < 0) {
1661
if (length < 0) {
1662
throw new IndexOutOfBoundsException();
1663
}
1664
1665
char[] newData = new char[value.length];
1666
1667
if (length > 0) {
1668
String.decompressedArrayCopy(value, 0, newData, 0, length);
1669
}
1670
1671
value = newData;
1672
1673
capacity = capacity & ~sharedBit;
1674
} else if (length < 0) {
1675
throw new IndexOutOfBoundsException();
1676
}
1677
}
1678
1679
if (String.COMPACT_STRINGS) {
1680
// Check if the StringBuffer is compressed
1681
if (count >= 0) {
1682
count = length;
1683
} else {
1684
count = length | uncompressedBit;
1685
}
1686
} else {
1687
count = length;
1688
}
1689
}
1690
1691
/**
1692
* Copies a range of characters into a new String.
1693
*
1694
* @param start the offset of the first character
1695
* @return a new String containing the characters from start to the end
1696
* of the string
1697
*
1698
* @exception StringIndexOutOfBoundsException when {@code start < 0} or
1699
* {@code start > length()}
1700
*/
1701
public synchronized String substring(int start) {
1702
int currentLength = lengthInternalUnsynchronized();
1703
1704
// Check if the StringBuffer is compressed
1705
if (String.COMPACT_STRINGS && count >= 0) {
1706
if (0 <= start && start <= currentLength) {
1707
return new String(value, start, currentLength - start, true, false);
1708
}
1709
} else {
1710
if (0 <= start && start <= currentLength) {
1711
return new String(value, start, currentLength - start, false, false);
1712
}
1713
}
1714
1715
throw new StringIndexOutOfBoundsException(start);
1716
}
1717
1718
/**
1719
* Copies a range of characters into a new String.
1720
*
1721
* @param start the offset of the first character
1722
* @param end the offset one past the last character
1723
* @return a new String containing the characters from start to end - 1
1724
*
1725
* @exception StringIndexOutOfBoundsException when {@code start < 0, start > end} or
1726
* {@code end > length()}
1727
*/
1728
public synchronized String substring(int start, int end) {
1729
int currentLength = lengthInternalUnsynchronized();
1730
1731
// Check if the StringBuffer is compressed
1732
if (String.COMPACT_STRINGS && count >= 0) {
1733
if (0 <= start && start <= end && end <= currentLength) {
1734
return new String(value, start, end - start, true, false);
1735
}
1736
} else {
1737
if (0 <= start && start <= end && end <= currentLength) {
1738
return new String(value, start, end - start, false, false);
1739
}
1740
}
1741
1742
throw new StringIndexOutOfBoundsException();
1743
}
1744
1745
static void initFromSystemProperties(Properties props) {
1746
String prop = props.getProperty("java.lang.string.create.unique"); //$NON-NLS-1$
1747
TOSTRING_COPY_BUFFER_ENABLED = "true".equals(prop) || "StringBuffer".equals(prop); //$NON-NLS-1$ //$NON-NLS-2$
1748
1749
// growAggressively by default
1750
String growAggressivelyProperty = props.getProperty("java.lang.stringBuffer.growAggressively", ""); //$NON-NLS-1$ //$NON-NLS-2$
1751
growAggressively = "".equals(growAggressivelyProperty) || Boolean.parseBoolean(growAggressivelyProperty); //$NON-NLS-1$
1752
}
1753
1754
/**
1755
* Answers the contents of this StringBuffer.
1756
*
1757
* @return a String containing the characters in this StringBuffer
1758
*/
1759
@Override
1760
public synchronized String toString () {
1761
int currentLength = lengthInternalUnsynchronized();
1762
int currentCapacity = capacityInternal();
1763
1764
if (false == TOSTRING_COPY_BUFFER_ENABLED) {
1765
int wasted = currentCapacity - currentLength;
1766
if (wasted >= 768 || (wasted >= INITIAL_SIZE && wasted >= (currentCapacity >> 1))) {
1767
// Check if the StringBuffer is compressed
1768
if (String.COMPACT_STRINGS && count >= 0) {
1769
return new String (value, 0, currentLength, true, false);
1770
} else {
1771
return new String (value, 0, currentLength, false, false);
1772
}
1773
}
1774
} else {
1775
// Do not copy the char[] if it will not get smaller because of object alignment
1776
int roundedCount = (currentLength + 3) & ~3;
1777
if (roundedCount < currentCapacity) {
1778
// Check if the StringBuffer is compressed
1779
if (String.COMPACT_STRINGS && count >= 0) {
1780
return new String (value, 0, currentLength, true, false);
1781
} else {
1782
return new String (value, 0, currentLength, false, false);
1783
}
1784
}
1785
}
1786
1787
capacity = capacity | sharedBit;
1788
1789
// Check if the StringBuffer is compressed
1790
if (String.COMPACT_STRINGS && count >= 0) {
1791
return new String (value, 0, currentLength, true);
1792
} else {
1793
return new String (value, 0, currentLength, false);
1794
}
1795
}
1796
1797
private synchronized void writeObject(ObjectOutputStream stream) throws IOException {
1798
int currentLength = lengthInternalUnsynchronized();
1799
1800
ObjectOutputStream.PutField pf = stream.putFields();
1801
1802
pf.put("count", currentLength); //$NON-NLS-1$
1803
1804
// Check if the StringBuffer is compressed
1805
if (String.COMPACT_STRINGS && count >= 0) {
1806
char[] newData = new char[currentLength];
1807
1808
String.decompress(value, 0, newData, 0, currentLength);
1809
1810
pf.put("value", newData); //$NON-NLS-1$
1811
} else {
1812
pf.put("value", value); //$NON-NLS-1$
1813
}
1814
1815
pf.put("shared", false); //$NON-NLS-1$
1816
1817
stream.writeFields();
1818
}
1819
1820
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
1821
ObjectInputStream.GetField gf = stream.readFields();
1822
int streamCount = gf.get("count", 0); //$NON-NLS-1$
1823
char[] streamValue = (char[]) gf.get("value", null); //$NON-NLS-1$
1824
1825
if ((streamCount < 0) || (streamCount > streamValue.length)) {
1826
/*[MSG "K0199", "count value invalid"]*/
1827
throw new StreamCorruptedException(com.ibm.oti.util.Msg.getString("K0199")); //$NON-NLS-1$
1828
}
1829
if (String.COMPACT_STRINGS) {
1830
if (String.canEncodeAsLatin1(streamValue, 0, streamValue.length)) {
1831
value = new char[(streamValue.length + 1) >>> 1];
1832
String.compress(streamValue, 0, value, 0, streamValue.length);
1833
count = streamCount;
1834
capacity = streamValue.length;
1835
} else {
1836
value = new char[streamValue.length];
1837
System.arraycopy(streamValue, 0, value, 0, streamValue.length);
1838
count = streamCount | uncompressedBit;
1839
capacity = streamValue.length;
1840
String.initCompressionFlag();
1841
}
1842
} else {
1843
value = new char[streamValue.length];
1844
System.arraycopy(streamValue, 0, value, 0, streamValue.length);
1845
count = streamCount;
1846
capacity = streamValue.length;
1847
}
1848
}
1849
1850
/**
1851
* Adds the specified StringBuffer to the end of this StringBuffer.
1852
*
1853
* @param buffer the StringBuffer
1854
* @return this StringBuffer
1855
*
1856
* @since 1.4
1857
*/
1858
public synchronized StringBuffer append(StringBuffer buffer) {
1859
if (buffer == null) {
1860
return append((String)null);
1861
} else {
1862
synchronized (buffer) {
1863
// Check if the StringBuffer is compressed
1864
if (String.COMPACT_STRINGS && buffer.count >= 0) {
1865
return append(buffer.value, 0, buffer.lengthInternalUnsynchronized(), true);
1866
} else {
1867
return append(buffer.value, 0, buffer.lengthInternalUnsynchronized(), false);
1868
}
1869
}
1870
}
1871
}
1872
1873
/**
1874
* Copies a range of characters into a new String.
1875
*
1876
* @param start the offset of the first character
1877
* @param end the offset one past the last character
1878
* @return a new String containing the characters from start to end - 1
1879
*
1880
* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or
1881
* {@code end > length()}
1882
*
1883
* @since 1.4
1884
*/
1885
@Override
1886
public CharSequence subSequence(int start, int end) {
1887
return substring(start, end);
1888
}
1889
1890
/**
1891
* Searches in this StringBuffer for the first index of the specified character. The
1892
* search for the character starts at the beginning and moves towards the
1893
* end.
1894
*
1895
* @param string the string to find
1896
* @return the index in this StringBuffer of the specified character, -1 if the
1897
* character isn't found
1898
*
1899
* @see #lastIndexOf(String)
1900
*
1901
* @since 1.4
1902
*/
1903
public int indexOf(String string) {
1904
return indexOf(string, 0);
1905
}
1906
1907
/**
1908
* Searches in this StringBuffer for the index of the specified character. The
1909
* search for the character starts at the specified offset and moves towards
1910
* the end.
1911
*
1912
* @param subString the string to find
1913
* @param start the starting offset
1914
* @return the index in this StringBuffer of the specified character, -1 if the
1915
* character isn't found
1916
*
1917
* @see #lastIndexOf(String,int)
1918
*
1919
* @since 1.4
1920
*/
1921
public synchronized int indexOf(String subString, int start) {
1922
int currentLength = lengthInternalUnsynchronized();
1923
1924
if (start < 0) {
1925
start = 0;
1926
}
1927
1928
int subStringLength = subString.lengthInternal();
1929
1930
if (subStringLength > 0) {
1931
if (subStringLength + start > currentLength) {
1932
return -1;
1933
}
1934
1935
char firstChar = subString.charAtInternal(0);
1936
1937
// Check if the StringBuffer is compressed
1938
if (String.COMPACT_STRINGS && count >= 0) {
1939
if (!subString.isCompressed()) {
1940
return -1;
1941
}
1942
1943
while (true) {
1944
int i = start;
1945
1946
boolean found = false;
1947
1948
for (; i < currentLength; ++i) {
1949
if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {
1950
found = true;
1951
break;
1952
}
1953
}
1954
1955
// Handles subStringLength > currentLength || start >= currentLength
1956
if (!found || subStringLength + i > currentLength) {
1957
return -1;
1958
}
1959
1960
int o1 = i;
1961
int o2 = 0;
1962
1963
while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))
1964
;
1965
1966
if (o2 == subStringLength) {
1967
return i;
1968
}
1969
1970
start = i + 1;
1971
}
1972
} else {
1973
while (true) {
1974
int i = start;
1975
1976
boolean found = false;
1977
1978
for (; i < currentLength; ++i) {
1979
if (value[i] == firstChar) {
1980
found = true;
1981
break;
1982
}
1983
}
1984
1985
// Handles subStringLength > currentLength || start >= currentLength
1986
if (!found || subStringLength + i > currentLength) {
1987
return -1;
1988
}
1989
1990
int o1 = i;
1991
int o2 = 0;
1992
1993
while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))
1994
;
1995
1996
if (o2 == subStringLength) {
1997
return i;
1998
}
1999
2000
start = i + 1;
2001
}
2002
}
2003
2004
} else {
2005
return (start < currentLength || start == 0) ? start : currentLength;
2006
}
2007
}
2008
2009
/**
2010
* Searches in this StringBuffer for the last index of the specified character. The
2011
* search for the character starts at the end and moves towards the beginning.
2012
*
2013
* @param string the string to find
2014
* @return the index in this StringBuffer of the specified character, -1 if the
2015
* character isn't found
2016
*
2017
* @see #indexOf(String)
2018
*
2019
* @since 1.4
2020
*/
2021
public synchronized int lastIndexOf(String string) {
2022
int currentLength = lengthInternalUnsynchronized();
2023
2024
return lastIndexOf(string, currentLength);
2025
}
2026
2027
/**
2028
* Searches in this StringBuffer for the index of the specified character. The
2029
* search for the character starts at the specified offset and moves towards
2030
* the beginning.
2031
*
2032
* @param subString the string to find
2033
* @param start the starting offset
2034
* @return the index in this StringBuffer of the specified character, -1 if the
2035
* character isn't found
2036
*
2037
* @see #indexOf(String,int)
2038
*
2039
* @since 1.4
2040
*/
2041
public synchronized int lastIndexOf(String subString, int start) {
2042
int currentLength = lengthInternalUnsynchronized();
2043
2044
int subStringLength = subString.lengthInternal();
2045
2046
if (subStringLength <= currentLength && start >= 0) {
2047
if (subStringLength > 0) {
2048
if (start > currentLength - subStringLength) {
2049
start = currentLength - subStringLength;
2050
}
2051
2052
char firstChar = subString.charAtInternal(0);
2053
2054
// Check if the StringBuffer is compressed
2055
if (String.COMPACT_STRINGS && count >= 0) {
2056
if (!subString.isCompressed()) {
2057
return -1;
2058
}
2059
2060
while (true) {
2061
int i = start;
2062
2063
boolean found = false;
2064
2065
for (; i >= 0; --i) {
2066
if (helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, i)) == firstChar) {
2067
found = true;
2068
break;
2069
}
2070
}
2071
2072
if (!found) {
2073
return -1;
2074
}
2075
2076
int o1 = i;
2077
int o2 = 0;
2078
2079
while (++o2 < subStringLength && helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, ++o1)) == subString.charAtInternal(o2))
2080
;
2081
2082
if (o2 == subStringLength) {
2083
return i;
2084
}
2085
2086
start = i - 1;
2087
}
2088
} else {
2089
while (true) {
2090
int i = start;
2091
2092
boolean found = false;
2093
2094
for (; i >= 0; --i) {
2095
if (value[i] == firstChar) {
2096
found = true;
2097
break;
2098
}
2099
}
2100
2101
if (!found) {
2102
return -1;
2103
}
2104
2105
int o1 = i;
2106
int o2 = 0;
2107
2108
while (++o2 < subStringLength && value[++o1] == subString.charAtInternal(o2))
2109
;
2110
2111
if (o2 == subStringLength) {
2112
return i;
2113
}
2114
2115
start = i - 1;
2116
}
2117
}
2118
} else {
2119
return start < currentLength ? start : currentLength;
2120
}
2121
} else {
2122
return -1;
2123
}
2124
}
2125
2126
/*
2127
* Return the underlying buffer and set the shared flag.
2128
*
2129
*/
2130
char[] shareValue() {
2131
capacity = capacity | sharedBit;
2132
2133
return value;
2134
}
2135
2136
boolean isCompressed() {
2137
// Check if the StringBuffer is compressed
2138
if (String.COMPACT_STRINGS && count >= 0) {
2139
return true;
2140
} else {
2141
return false;
2142
}
2143
}
2144
2145
/**
2146
* Constructs a new StringBuffer containing the characters in
2147
* the specified CharSequence and the default capacity.
2148
*
2149
* @param sequence the initial contents of this StringBuffer
2150
* @exception NullPointerException when sequence is null
2151
*
2152
* @since 1.5
2153
*/
2154
public StringBuffer(CharSequence sequence) {
2155
int size = sequence.length();
2156
2157
if (size < 0) {
2158
size = 0;
2159
}
2160
2161
int newLength = INITIAL_SIZE + size;
2162
if (newLength < size) {
2163
newLength = size;
2164
}
2165
2166
if (String.COMPACT_STRINGS) {
2167
value = new char[(newLength + 1) >>> 1];
2168
} else {
2169
value = new char[newLength];
2170
}
2171
2172
capacity = newLength;
2173
2174
if (sequence instanceof String) {
2175
append((String)sequence);
2176
} else if (sequence instanceof StringBuffer) {
2177
append((StringBuffer)sequence);
2178
} else {
2179
if (String.COMPACT_STRINGS) {
2180
boolean isCompressed = true;
2181
2182
for (int i = 0; i < size; ++i) {
2183
if (sequence.charAt(i) > 255) {
2184
isCompressed = false;
2185
2186
break;
2187
}
2188
}
2189
2190
if (isCompressed) {
2191
count = size;
2192
2193
for (int i = 0; i < size; ++i) {
2194
helpers.putByteInArrayByIndex(value, i, (byte) sequence.charAt(i));
2195
}
2196
} else {
2197
value = new char[newLength];
2198
2199
count = size | uncompressedBit;
2200
2201
for (int i = 0; i < size; ++i) {
2202
value[i] = sequence.charAt(i);
2203
}
2204
2205
String.initCompressionFlag();
2206
}
2207
} else {
2208
count = size;
2209
2210
for (int i = 0; i < size; ++i) {
2211
value[i] = sequence.charAt(i);
2212
}
2213
}
2214
}
2215
}
2216
2217
/**
2218
* Adds the specified CharSequence to the end of this StringBuffer.
2219
*
2220
* @param sequence the CharSequence
2221
* @return this StringBuffer
2222
*
2223
* @since 1.5
2224
*/
2225
@Override
2226
public synchronized StringBuffer append(CharSequence sequence) {
2227
if (sequence == null) {
2228
return append(String.valueOf(sequence));
2229
} else if (sequence instanceof String) {
2230
return append((String)sequence);
2231
} else if (sequence instanceof StringBuffer) {
2232
return append((StringBuffer)sequence);
2233
} else {
2234
int currentLength = lengthInternalUnsynchronized();
2235
int currentCapacity = capacityInternal();
2236
2237
int sequenceLength = sequence.length();
2238
2239
int newLength = currentLength + sequenceLength;
2240
if (newLength < 0) {
2241
/*[MSG "K0D01", "Array capacity exceeded"]*/
2242
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
2243
}
2244
2245
if (String.COMPACT_STRINGS) {
2246
boolean isCompressed = true;
2247
2248
if (count >= 0) {
2249
for (int i = 0; i < sequence.length(); ++i) {
2250
if (sequence.charAt(i) > 255) {
2251
isCompressed = false;
2252
2253
break;
2254
}
2255
}
2256
}
2257
2258
// Check if the StringBuffer is compressed
2259
if (count >= 0 && isCompressed) {
2260
if (newLength > currentCapacity) {
2261
ensureCapacityImpl(newLength);
2262
}
2263
2264
for (int i = 0; i < sequence.length(); ++i) {
2265
helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(i));
2266
}
2267
2268
count = newLength;
2269
} else {
2270
// Check if the StringBuffer is compressed
2271
if (count >= 0) {
2272
decompress(newLength);
2273
}
2274
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 | uncompressedBit;
2284
}
2285
} else {
2286
if (newLength > currentCapacity) {
2287
ensureCapacityImpl(newLength);
2288
}
2289
2290
for (int i = 0; i < sequence.length(); ++i) {
2291
value[currentLength + i] = sequence.charAt(i);
2292
}
2293
2294
count = newLength;
2295
}
2296
2297
return this;
2298
}
2299
}
2300
2301
/**
2302
* Adds the specified CharSequence to the end of this StringBuffer.
2303
*
2304
* @param sequence the CharSequence
2305
* @param start the offset of the first character
2306
* @param end the offset one past the last character
2307
* @return this StringBuffer
2308
*
2309
* @exception IndexOutOfBoundsException when {@code start < 0, start > end} or
2310
* {@code end > length()}
2311
*
2312
* @since 1.5
2313
*/
2314
@Override
2315
public synchronized StringBuffer append(CharSequence sequence, int start, int end) {
2316
if (sequence == null) {
2317
return append(String.valueOf(sequence), start, end);
2318
} else if (sequence instanceof String) {
2319
return append(((String)sequence).substring(start, end));
2320
} else if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {
2321
if (sequence instanceof StringBuffer) {
2322
synchronized (sequence) {
2323
StringBuffer buffer = (StringBuffer) sequence;
2324
2325
// Check if the StringBuffer is compressed
2326
if (String.COMPACT_STRINGS && buffer.count >= 0) {
2327
return append(buffer.value, start, end - start, true);
2328
} else {
2329
return append(buffer.value, start, end - start, false);
2330
}
2331
}
2332
} else if (sequence instanceof StringBuilder) {
2333
synchronized (sequence) {
2334
StringBuilder builder = (StringBuilder) sequence;
2335
2336
if (String.COMPACT_STRINGS && builder.isCompressed()) {
2337
return append(builder.getValue(), start, end - start, true);
2338
} else {
2339
return append(builder.getValue(), start, end - start, false);
2340
}
2341
}
2342
} else {
2343
int currentLength = lengthInternalUnsynchronized();
2344
int currentCapacity = capacityInternal();
2345
2346
int newLength = currentLength + end - start;
2347
if (newLength < 0) {
2348
/*[MSG "K0D01", "Array capacity exceeded"]*/
2349
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
2350
}
2351
2352
if (String.COMPACT_STRINGS) {
2353
boolean isCompressed = true;
2354
2355
if (count >= 0) {
2356
for (int i = 0; i < sequence.length(); ++i) {
2357
if (sequence.charAt(i) > 255) {
2358
isCompressed = false;
2359
2360
break;
2361
}
2362
}
2363
}
2364
2365
// Check if the StringBuffer is compressed
2366
if (count >= 0 && isCompressed) {
2367
if (newLength > currentCapacity) {
2368
ensureCapacityImpl(newLength);
2369
}
2370
2371
for (int i = 0; i < end - start; ++i) {
2372
helpers.putByteInArrayByIndex(value, currentLength + i, (byte) sequence.charAt(start + i));
2373
}
2374
2375
count = newLength;
2376
} else {
2377
// Check if the StringBuffer is compressed
2378
if (count >= 0) {
2379
decompress(newLength);
2380
}
2381
2382
if (newLength > currentCapacity) {
2383
ensureCapacityImpl(newLength);
2384
}
2385
2386
for (int i = 0; i < end - start; ++i) {
2387
value[currentLength + i] = sequence.charAt(start + i);
2388
}
2389
2390
count = newLength | uncompressedBit;
2391
}
2392
} else {
2393
if (newLength > currentCapacity) {
2394
ensureCapacityImpl(newLength);
2395
}
2396
2397
for (int i = 0; i < end - start; ++i) {
2398
value[currentLength + i] = sequence.charAt(start + i);
2399
}
2400
2401
count = newLength;
2402
}
2403
2404
return this;
2405
}
2406
} else {
2407
throw new IndexOutOfBoundsException();
2408
}
2409
}
2410
2411
/**
2412
* Inserts the CharSequence at the specified offset in this StringBuffer.
2413
*
2414
* @param index the index at which to insert
2415
* @param sequence the CharSequence to insert
2416
* @return this StringBuffer
2417
*
2418
* @exception IndexOutOfBoundsException when {@code index < 0} or
2419
* {@code index > length()}
2420
*
2421
* @since 1.5
2422
*/
2423
public synchronized StringBuffer insert(int index, CharSequence sequence) {
2424
int currentLength = lengthInternalUnsynchronized();
2425
2426
if (index >= 0 && index <= currentLength) {
2427
if (sequence == null) {
2428
return insert(index, String.valueOf(sequence));
2429
} else if (sequence instanceof String) {
2430
return insert(index, (String) sequence);
2431
} else if (sequence instanceof StringBuffer) {
2432
synchronized(sequence) {
2433
StringBuffer buffer = (StringBuffer) sequence;
2434
2435
// Check if the StringBuffer is compressed
2436
if (String.COMPACT_STRINGS && buffer.count >= 0) {
2437
return insert(index, buffer.value, 0, buffer.lengthInternalUnsynchronized(), true);
2438
} else {
2439
return insert(index, buffer.value, 0, buffer.lengthInternalUnsynchronized(), false);
2440
}
2441
}
2442
} else if (sequence instanceof StringBuilder) {
2443
synchronized (sequence) {
2444
StringBuilder builder = (StringBuilder) sequence;
2445
2446
if (String.COMPACT_STRINGS && builder.isCompressed()) {
2447
return insert(index, builder.getValue(), 0, builder.lengthInternal(), true);
2448
} else {
2449
return insert(index, builder.getValue(), 0, builder.lengthInternal(), false);
2450
}
2451
}
2452
} else {
2453
int sequneceLength = sequence.length();
2454
2455
if (sequneceLength > 0) {
2456
move(sequneceLength, index);
2457
2458
int newLength = currentLength + sequneceLength;
2459
2460
if (String.COMPACT_STRINGS) {
2461
boolean isCompressed = true;
2462
2463
for (int i = 0; i < sequneceLength; ++i) {
2464
if (sequence.charAt(i) > 255) {
2465
isCompressed = false;
2466
2467
break;
2468
}
2469
}
2470
2471
// Check if the StringBuffer is compressed
2472
if (count >= 0 && isCompressed) {
2473
for (int i = 0; i < sequneceLength; ++i) {
2474
helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(i));
2475
}
2476
2477
count = newLength;
2478
2479
return this;
2480
} else {
2481
// Check if the StringBuffer is compressed
2482
if (count >= 0) {
2483
decompress(value.length);
2484
}
2485
2486
for (int i = 0; i < sequneceLength; ++i) {
2487
value[index + i] = sequence.charAt(i);
2488
}
2489
2490
count = newLength | uncompressedBit;
2491
}
2492
} else {
2493
for (int i = 0; i < sequneceLength; ++i) {
2494
value[index + i] = sequence.charAt(i);
2495
}
2496
2497
count = newLength;
2498
}
2499
}
2500
2501
return this;
2502
}
2503
} else {
2504
throw new IndexOutOfBoundsException();
2505
}
2506
}
2507
2508
/**
2509
* Inserts the CharSequence at the specified offset in this StringBuffer.
2510
*
2511
* @param index the index at which to insert
2512
* @param sequence the CharSequence to insert
2513
* @param start the offset of the first character
2514
* @param end the offset one past the last character
2515
* @return this StringBuffer
2516
*
2517
* @exception IndexOutOfBoundsException when {@code index < 0} or
2518
* {@code index > length()}, or when {@code start < 0, start > end} or
2519
* {@code end > length()}
2520
*
2521
* @since 1.5
2522
*/
2523
public synchronized StringBuffer insert(int index, CharSequence sequence, int start, int end) {
2524
int currentLength = lengthInternalUnsynchronized();
2525
2526
if (index >= 0 && index <= currentLength) {
2527
if (sequence == null)
2528
return insert(index, String.valueOf(sequence), start, end);
2529
if (sequence instanceof String) {
2530
return insert(index, ((String) sequence).substring(start, end));
2531
}
2532
if (start >= 0 && end >= 0 && start <= end && end <= sequence.length()) {
2533
if (sequence instanceof StringBuffer) {
2534
synchronized(sequence) {
2535
StringBuffer buffer = (StringBuffer) sequence;
2536
2537
// Check if the StringBuffer is compressed
2538
if (String.COMPACT_STRINGS && buffer.count >= 0) {
2539
return insert(index, buffer.value, start, end - start, true);
2540
} else {
2541
return insert(index, buffer.value, start, end - start, false);
2542
}
2543
}
2544
} else if (sequence instanceof StringBuilder) {
2545
synchronized(sequence) {
2546
StringBuilder builder = (StringBuilder) sequence;
2547
2548
if (String.COMPACT_STRINGS && builder.isCompressed()) {
2549
return insert(index, builder.getValue(), start, end - start, true);
2550
} else {
2551
return insert(index, builder.getValue(), start, end - start, false);
2552
}
2553
}
2554
} else {
2555
int sequenceLength = end - start;
2556
2557
if (sequenceLength > 0) {
2558
move(sequenceLength, index);
2559
2560
int newLength = currentLength + sequenceLength;
2561
2562
if (String.COMPACT_STRINGS) {
2563
boolean isCompressed = true;
2564
2565
for (int i = 0; i < sequenceLength; ++i) {
2566
if (sequence.charAt(start + i) > 255) {
2567
isCompressed = false;
2568
2569
break;
2570
}
2571
}
2572
2573
// Check if the StringBuffer is compressed
2574
if (count >= 0 && isCompressed) {
2575
for (int i = 0; i < sequenceLength; ++i) {
2576
helpers.putByteInArrayByIndex(value, index + i, (byte) sequence.charAt(start + i));
2577
}
2578
2579
count = newLength;
2580
2581
return this;
2582
} else {
2583
// Check if the StringBuffer is compressed
2584
if (count >= 0) {
2585
decompress(value.length);
2586
}
2587
2588
for (int i = 0; i < sequenceLength; ++i) {
2589
value[index + i] = sequence.charAt(start + i);
2590
}
2591
2592
count = newLength | uncompressedBit;
2593
}
2594
} else {
2595
for (int i = 0; i < sequenceLength; ++i) {
2596
value[index + i] = sequence.charAt(start + i);
2597
}
2598
2599
count = newLength;
2600
}
2601
}
2602
2603
return this;
2604
}
2605
} else {
2606
throw new IndexOutOfBoundsException();
2607
}
2608
} else {
2609
throw new IndexOutOfBoundsException();
2610
}
2611
}
2612
2613
/**
2614
* Optionally modify the underlying char array to only
2615
* be large enough to hold the characters in this StringBuffer.
2616
*
2617
* @since 1.5
2618
*/
2619
public synchronized void trimToSize() {
2620
int currentLength = lengthInternalUnsynchronized();
2621
int currentCapacity = capacityInternal();
2622
2623
// Check if the StringBuffer is compressed
2624
if (String.COMPACT_STRINGS && count >= 0) {
2625
// Check if the StringBuffer is not shared
2626
if (capacity >= 0 && currentCapacity != currentLength) {
2627
char[] newData = new char[(currentLength + 1) / 2];
2628
2629
String.compressedArrayCopy(value, 0, newData, 0, currentLength);
2630
2631
value = newData;
2632
2633
capacity = currentLength;
2634
}
2635
} else {
2636
// Check if the StringBuffer is not shared
2637
if (capacity >= 0 && currentCapacity != currentLength) {
2638
char[] newData = new char[currentLength];
2639
2640
String.decompressedArrayCopy(value, 0, newData, 0, currentLength);
2641
value = newData;
2642
2643
capacity = currentLength;
2644
}
2645
}
2646
}
2647
2648
/**
2649
* Returns the Unicode character at the given point.
2650
*
2651
* @param index the character index
2652
* @return the Unicode character value at the index
2653
*
2654
* @since 1.5
2655
*/
2656
public synchronized int codePointAt(int index) {
2657
int currentLength = lengthInternalUnsynchronized();
2658
2659
if (index >= 0 && index < currentLength) {
2660
// Check if the StringBuffer is compressed
2661
if (String.COMPACT_STRINGS && count >= 0) {
2662
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index));
2663
} else {
2664
int high = value[index];
2665
2666
if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2667
int low = value[index + 1];
2668
2669
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2670
return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);
2671
}
2672
}
2673
2674
return high;
2675
}
2676
} else {
2677
throw new StringIndexOutOfBoundsException(index);
2678
}
2679
}
2680
2681
/**
2682
* Returns the Unicode character before the given point.
2683
*
2684
* @param index the character index
2685
* @return the Unicode character value before the index
2686
*
2687
* @since 1.5
2688
*/
2689
public synchronized int codePointBefore(int index) {
2690
int currentLength = lengthInternalUnsynchronized();
2691
2692
if (index > 0 && index <= currentLength) {
2693
// Check if the StringBuffer is compressed
2694
if (String.COMPACT_STRINGS && count >= 0) {
2695
return helpers.byteToCharUnsigned(helpers.getByteFromArrayByIndex(value, index - 1));
2696
} else {
2697
int low = value[index - 1];
2698
2699
if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2700
int high = value[index - 2];
2701
2702
if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2703
return 0x10000 + ((high - Character.MIN_HIGH_SURROGATE) << 10) + (low - Character.MIN_LOW_SURROGATE);
2704
}
2705
}
2706
2707
return low;
2708
}
2709
} else {
2710
throw new StringIndexOutOfBoundsException(index);
2711
}
2712
}
2713
2714
/**
2715
* Returns the total Unicode values in the specified range.
2716
*
2717
* @param start first index
2718
* @param end last index
2719
* @return the total Unicode values
2720
*
2721
* @since 1.5
2722
*/
2723
public synchronized int codePointCount(int start, int end) {
2724
int currentLength = lengthInternalUnsynchronized();
2725
2726
if (start >= 0 && start <= end && end <= currentLength) {
2727
// Check if the StringBuffer is compressed
2728
if (String.COMPACT_STRINGS && count >= 0) {
2729
return end - start;
2730
} else {
2731
int count = 0;
2732
2733
for (int i = start; i < end; ++i) {
2734
int high = value[i];
2735
2736
if (i + 1 < end && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2737
int low = value[i + 1];
2738
2739
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2740
++i;
2741
}
2742
}
2743
2744
++count;
2745
}
2746
2747
return count;
2748
}
2749
} else {
2750
throw new IndexOutOfBoundsException();
2751
}
2752
}
2753
2754
/**
2755
* Returns the index of the code point that was offset by {@code codePointCount}.
2756
*
2757
* @param start the position to offset
2758
* @param codePointCount the code point count
2759
* @return the offset index
2760
*
2761
* @since 1.5
2762
*/
2763
public synchronized int offsetByCodePoints(int start, int codePointCount) {
2764
int currentLength = lengthInternalUnsynchronized();
2765
2766
if (start >= 0 && start <= currentLength) {
2767
// Check if the StringBuffer is compressed
2768
if (String.COMPACT_STRINGS && count >= 0) {
2769
int index = start + codePointCount;
2770
2771
if (index >= currentLength) {
2772
throw new IndexOutOfBoundsException();
2773
} else {
2774
return index;
2775
}
2776
} else {
2777
int index = start;
2778
2779
if (codePointCount == 0) {
2780
return start;
2781
} else if (codePointCount > 0) {
2782
for (int i = 0; i < codePointCount; ++i) {
2783
if (index == currentLength) {
2784
throw new IndexOutOfBoundsException();
2785
}
2786
2787
int high = value[index];
2788
2789
if ((index + 1) < currentLength && high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2790
int low = value[index + 1];
2791
2792
if (low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2793
index++;
2794
}
2795
}
2796
2797
index++;
2798
}
2799
} else {
2800
for (int i = codePointCount; i < 0; ++i) {
2801
if (index < 1) {
2802
throw new IndexOutOfBoundsException();
2803
}
2804
2805
int low = value[index - 1];
2806
2807
if (index > 1 && low >= Character.MIN_LOW_SURROGATE && low <= Character.MAX_LOW_SURROGATE) {
2808
int high = value[index - 2];
2809
2810
if (high >= Character.MIN_HIGH_SURROGATE && high <= Character.MAX_HIGH_SURROGATE) {
2811
index--;
2812
}
2813
}
2814
2815
index--;
2816
}
2817
}
2818
2819
return index;
2820
}
2821
} else {
2822
throw new IndexOutOfBoundsException();
2823
}
2824
}
2825
2826
/**
2827
* Adds the specified code point to the end of this StringBuffer.
2828
*
2829
* @param codePoint the code point
2830
* @return this StringBuffer
2831
*
2832
* @since 1.5
2833
*/
2834
public synchronized StringBuffer appendCodePoint(int codePoint) {
2835
if (codePoint >= 0) {
2836
if (codePoint < 0x10000) {
2837
return append((char)codePoint);
2838
} else if (codePoint < 0x110000) {
2839
// Check if the StringBuffer is compressed
2840
if (String.COMPACT_STRINGS && count >= 0) {
2841
decompress(value.length);
2842
}
2843
2844
int currentLength = lengthInternalUnsynchronized();
2845
int currentCapacity = capacityInternal();
2846
2847
int newLength = currentLength + 2;
2848
if (newLength < 0) {
2849
/*[MSG "K0D01", "Array capacity exceeded"]*/
2850
throw new OutOfMemoryError(com.ibm.oti.util.Msg.getString("K0D01")); //$NON-NLS-1$
2851
}
2852
2853
if (newLength > currentCapacity) {
2854
ensureCapacityImpl(newLength);
2855
}
2856
2857
codePoint -= 0x10000;
2858
2859
value[currentLength] = (char) (Character.MIN_HIGH_SURROGATE + (codePoint >> 10));
2860
value[currentLength + 1] = (char) (Character.MIN_LOW_SURROGATE + (codePoint & 0x3ff));
2861
2862
if (String.COMPACT_STRINGS) {
2863
count = newLength | uncompressedBit;
2864
} else {
2865
count = newLength;
2866
}
2867
2868
return this;
2869
}
2870
}
2871
2872
throw new IllegalArgumentException();
2873
}
2874
2875
/*
2876
* Returns the character array for this StringBuffer.
2877
*/
2878
char[] getValue() {
2879
return value;
2880
}
2881
2882
}
2883
2884