1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.text;
18
19 import java.io.IOException;
20 import java.io.Reader;
21 import java.io.Serializable;
22 import java.io.Writer;
23 import java.nio.CharBuffer;
24 import java.util.Arrays;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Objects;
28
29 import org.apache.commons.lang3.ArrayUtils;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.text.matcher.StringMatcher;
32
33 /**
34 * Builds a string from constituent parts providing a more flexible and powerful API than {@link StringBuffer} and
35 * {@link StringBuilder}.
36 * <p>
37 * The main differences from StringBuffer/StringBuilder are:
38 * </p>
39 * <ul>
40 * <li>Not synchronized</li>
41 * <li>Not final</li>
42 * <li>Subclasses have direct access to character array</li>
43 * <li>Additional methods
44 * <ul>
45 * <li>appendWithSeparators - adds an array of values, with a separator</li>
46 * <li>appendPadding - adds a length padding characters</li>
47 * <li>appendFixedLength - adds a fixed width field to the builder</li>
48 * <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
49 * <li>delete - delete char or string</li>
50 * <li>replace - search and replace for a char or string</li>
51 * <li>leftString/rightString/midString - substring without exceptions</li>
52 * <li>contains - whether the builder contains a char or string</li>
53 * <li>size/clear/isEmpty - collections style API methods</li>
54 * </ul>
55 * </li>
56 * <li>Views
57 * <ul>
58 * <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li>
59 * <li>asReader - uses the internal buffer as the source of a Reader</li>
60 * <li>asWriter - allows a Writer to write directly to the internal buffer</li>
61 * </ul>
62 * </li>
63 * </ul>
64 * <p>
65 * The aim has been to provide an API that mimics very closely what StringBuffer provides, but with additional methods.
66 * It should be noted that some edge cases, with invalid indices or null input, have been altered - see individual
67 * methods. The biggest of these changes is that by default, null will not output the text 'null'. This can be
68 * controlled by a property, {@link #setNullText(String)}.
69 * </p>
70 * <p>
71 * This class is called {@code TextStringBuilder} instead of {@code StringBuilder} to avoid clashing with
72 * {@link StringBuilder}.
73 * </p>
74 *
75 * @since 1.3
76 */
77 public class TextStringBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
78
79 /**
80 * Inner class to allow StrBuilder to operate as a reader.
81 */
82 final class TextStringBuilderReader extends Reader {
83
84 /** The last mark position. */
85 private int mark;
86
87 /** The current stream position. */
88 private int pos;
89
90 /**
91 * Default constructor.
92 */
93 TextStringBuilderReader() {
94 }
95
96 /** {@inheritDoc} */
97 @Override
98 public void close() {
99 // do nothing
100 }
101
102 /** {@inheritDoc} */
103 @Override
104 public void mark(final int readAheadLimit) {
105 mark = pos;
106 }
107
108 /** {@inheritDoc} */
109 @Override
110 public boolean markSupported() {
111 return true;
112 }
113
114 /** {@inheritDoc} */
115 @Override
116 public int read() {
117 return ready() ? charAt(pos++) : -1;
118 }
119
120 /** {@inheritDoc} */
121 @Override
122 public int read(final char[] b, final int off, int len) {
123 if (off < 0 || len < 0 || off > b.length || off + len > b.length || off + len < 0) {
124 throw new IndexOutOfBoundsException();
125 }
126 if (len == 0) {
127 return 0;
128 }
129 if (pos >= size()) {
130 return -1;
131 }
132 if (pos + len > size()) {
133 len = size() - pos;
134 }
135 TextStringBuilder.this.getChars(pos, pos + len, b, off);
136 pos += len;
137 return len;
138 }
139
140 /** {@inheritDoc} */
141 @Override
142 public boolean ready() {
143 return pos < size();
144 }
145
146 /** {@inheritDoc} */
147 @Override
148 public void reset() {
149 pos = mark;
150 }
151
152 /** {@inheritDoc} */
153 @Override
154 public long skip(long n) {
155 if (pos + n > size()) {
156 n = size() - pos;
157 }
158 if (n < 0) {
159 return 0;
160 }
161 pos = Math.addExact(pos, Math.toIntExact(n));
162 return n;
163 }
164 }
165
166 /**
167 * Inner class to allow StrBuilder to operate as a tokenizer.
168 */
169 final class TextStringBuilderTokenizer extends StringTokenizer {
170
171 /**
172 * Default constructor.
173 */
174 TextStringBuilderTokenizer() {
175 }
176
177 /** {@inheritDoc} */
178 @Override
179 public String getContent() {
180 final String str = super.getContent();
181 return str != null ? str : TextStringBuilder.this.toString();
182 }
183
184 /** {@inheritDoc} */
185 @Override
186 protected List<String> tokenize(final char[] chars, final int offset, final int count) {
187 if (chars == null) {
188 return super.tokenize(getBuffer(), 0, TextStringBuilder.this.size());
189 }
190 return super.tokenize(chars, offset, count);
191 }
192 }
193
194 /**
195 * Inner class to allow StrBuilder to operate as a writer.
196 */
197 final class TextStringBuilderWriter extends Writer {
198
199 /**
200 * Default constructor.
201 */
202 TextStringBuilderWriter() {
203 }
204
205 /** {@inheritDoc} */
206 @Override
207 public void close() {
208 // do nothing
209 }
210
211 /** {@inheritDoc} */
212 @Override
213 public void flush() {
214 // do nothing
215 }
216
217 /** {@inheritDoc} */
218 @Override
219 public void write(final char[] cbuf) {
220 TextStringBuilder.this.append(cbuf);
221 }
222
223 /** {@inheritDoc} */
224 @Override
225 public void write(final char[] cbuf, final int off, final int len) {
226 TextStringBuilder.this.append(cbuf, off, len);
227 }
228
229 /** {@inheritDoc} */
230 @Override
231 public void write(final int c) {
232 TextStringBuilder.this.append((char) c);
233 }
234
235 /** {@inheritDoc} */
236 @Override
237 public void write(final String str) {
238 TextStringBuilder.this.append(str);
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public void write(final String str, final int off, final int len) {
244 TextStringBuilder.this.append(str, off, len);
245 }
246 }
247
248 /** The space character. */
249 private static final char SPACE = ' ';
250
251 /**
252 * The extra capacity for new builders.
253 */
254 static final int CAPACITY = 32;
255
256 /**
257 * End-Of-Stream.
258 */
259 private static final int EOS = -1;
260
261 /**
262 * The size of the string {@code "false"}.
263 */
264 private static final int FALSE_STRING_SIZE = Boolean.FALSE.toString().length();
265
266 /**
267 * Required for serialization support.
268 *
269 * @see java.io.Serializable
270 */
271 private static final long serialVersionUID = 1L;
272
273 /**
274 * The size of the string {@code "true"}.
275 */
276 private static final int TRUE_STRING_SIZE = Boolean.TRUE.toString().length();
277
278 /**
279 * The maximum size buffer to allocate.
280 *
281 * <p>This is set to the same size used in the JDK {@link java.util.ArrayList}:</p>
282 * <blockquote>
283 * Some VMs reserve some header words in an array.
284 * Attempts to allocate larger arrays may result in
285 * OutOfMemoryError: Requested array size exceeds VM limit.
286 * </blockquote>
287 */
288 private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
289
290 /**
291 * Creates a positive capacity at least as large the minimum required capacity.
292 * If the minimum capacity is negative then this throws an OutOfMemoryError as no array
293 * can be allocated.
294 *
295 * @param minCapacity the minimum capacity
296 * @return the capacity
297 * @throws OutOfMemoryError if the {@code minCapacity} is negative
298 */
299 private static int createPositiveCapacity(final int minCapacity) {
300 if (minCapacity < 0) {
301 // overflow
302 throw new OutOfMemoryError("Unable to allocate array size: " + Integer.toUnsignedString(minCapacity));
303 }
304 // This is called when we require buffer expansion to a very big array.
305 // Use the conservative maximum buffer size if possible, otherwise the biggest required.
306 //
307 // Note: In this situation JDK 1.8 java.util.ArrayList returns Integer.MAX_VALUE.
308 // This excludes some VMs that can exceed MAX_BUFFER_SIZE but not allocate a full
309 // Integer.MAX_VALUE length array.
310 // The result is that we may have to allocate an array of this size more than once if
311 // the capacity must be expanded again.
312 return Math.max(minCapacity, MAX_BUFFER_SIZE);
313 }
314
315 /**
316 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this
317 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to
318 * be initialized without copying the input array.
319 *
320 * @param initialBuffer The initial array that will back the new builder.
321 * @return A new instance.
322 * @since 1.9
323 */
324 public static TextStringBuilder wrap(final char[] initialBuffer) {
325 Objects.requireNonNull(initialBuffer, "initialBuffer");
326 return new TextStringBuilder(initialBuffer, initialBuffer.length);
327 }
328
329 /**
330 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this
331 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to
332 * be initialized without copying the input array.
333 *
334 * @param initialBuffer The initial array that will back the new builder.
335 * @param length The length of the subarray to be used; must be non-negative and no larger than
336 * {@code initialBuffer.length}. The new builder's size will be set to {@code length}.
337 * @return A new instance.
338 * @since 1.9
339 */
340 public static TextStringBuilder wrap(final char[] initialBuffer, final int length) {
341 return new TextStringBuilder(initialBuffer, length);
342 }
343
344 /** Internal data storage. */
345 private char[] buffer;
346
347 /**
348 * The new line, {@code null} means use the system default from {@link System#lineSeparator()}.
349 */
350 private String newLine;
351
352 /** The null text. */
353 private String nullText;
354
355 /** Incremented when the buffer is reallocated. */
356 private int reallocations;
357
358 /** Current size of the buffer. */
359 private int size;
360
361 /**
362 * Constructs an empty builder with an initial capacity of 32 characters.
363 */
364 public TextStringBuilder() {
365 this(CAPACITY);
366 }
367
368 /**
369 * Constructs an instance from a reference to a character array.
370 *
371 * @param initialBuffer a reference to a character array, must not be null.
372 * @param length The length of the subarray to be used; must be non-negative and no larger than {@code initialBuffer.length}. The new builder's size
373 * will be set to {@code length}.
374 * @throws NullPointerException If {@code initialBuffer} is null.
375 * @throws IllegalArgumentException if {@code length} is bad.
376 */
377 private TextStringBuilder(final char[] initialBuffer, final int length) {
378 this.buffer = Objects.requireNonNull(initialBuffer, "initialBuffer");
379 if (length < 0 || length > initialBuffer.length) {
380 throw new IllegalArgumentException("initialBuffer.length=" + initialBuffer.length + ", length=" + length);
381 }
382 this.size = length;
383 }
384
385 /**
386 * Constructs an instance from a character sequence, allocating 32 extra characters for growth.
387 *
388 * @param seq the string to copy, null treated as blank string.
389 * @since 1.9
390 */
391 public TextStringBuilder(final CharSequence seq) {
392 this(StringUtils.length(seq) + CAPACITY);
393 if (seq != null) {
394 append(seq);
395 }
396 }
397
398 /**
399 * Constructs an instance with the specified initial capacity.
400 *
401 * @param initialCapacity the initial capacity, zero or less will be converted to 32.
402 */
403 public TextStringBuilder(final int initialCapacity) {
404 buffer = new char[initialCapacity <= 0 ? CAPACITY : initialCapacity];
405 }
406
407 /**
408 * Constructs an instance from a string, allocating 32 extra characters for growth.
409 *
410 * @param str the string to copy, null treated as blank string.
411 */
412 public TextStringBuilder(final String str) {
413 this(StringUtils.length(str) + CAPACITY);
414 if (str != null) {
415 append(str);
416 }
417 }
418
419 /**
420 * Appends a boolean value to the string builder.
421 *
422 * @param value the value to append.
423 * @return {@code this} instance.
424 */
425 public TextStringBuilder append(final boolean value) {
426 if (value) {
427 ensureCapacityInternal(size + TRUE_STRING_SIZE);
428 appendTrue(size);
429 } else {
430 ensureCapacityInternal(size + FALSE_STRING_SIZE);
431 appendFalse(size);
432 }
433 return this;
434 }
435
436 /**
437 * Appends a char value to the string builder.
438 *
439 * @param ch the value to append.
440 * @return {@code this} instance.
441 */
442 @Override
443 public TextStringBuilder append(final char ch) {
444 final int len = length();
445 ensureCapacityInternal(len + 1);
446 buffer[size++] = ch;
447 return this;
448 }
449
450 /**
451 * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
452 *
453 * @param chars the char array to append.
454 * @return {@code this} instance.
455 */
456 public TextStringBuilder append(final char[] chars) {
457 if (chars == null) {
458 return appendNull();
459 }
460 final int strLen = chars.length;
461 if (strLen > 0) {
462 final int len = length();
463 ensureCapacityInternal(len + strLen);
464 System.arraycopy(chars, 0, buffer, len, strLen);
465 size += strLen;
466 }
467 return this;
468 }
469
470 /**
471 * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
472 *
473 * @param chars the char array to append.
474 * @param startIndex the start index, inclusive, must be valid.
475 * @param length the length to append, must be valid.
476 * @return {@code this} instance.
477 * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the range {@code 0 <= startIndex <= chars.length}.
478 * @throws StringIndexOutOfBoundsException if {@code length < 0}.
479 * @throws StringIndexOutOfBoundsException if {@code startIndex + length > chars.length}.
480 */
481 public TextStringBuilder append(final char[] chars, final int startIndex, final int length) {
482 if (chars == null) {
483 return appendNull();
484 }
485 if (startIndex < 0 || startIndex > chars.length) {
486 throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
487 }
488 if (length < 0 || startIndex + length > chars.length) {
489 throw new StringIndexOutOfBoundsException("Invalid length: " + length);
490 }
491 if (length > 0) {
492 final int len = length();
493 ensureCapacityInternal(len + length);
494 System.arraycopy(chars, startIndex, buffer, len, length);
495 size += length;
496 }
497 return this;
498 }
499
500 /**
501 * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
502 *
503 * @param str the char buffer to append.
504 * @return {@code this} instance.
505 */
506 public TextStringBuilder append(final CharBuffer str) {
507 return append(str, 0, StringUtils.length(str));
508 }
509
510 /**
511 * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
512 *
513 * @param buf the char buffer to append.
514 * @param startIndex the start index, inclusive, must be valid.
515 * @param length the length to append, must be valid.
516 * @return {@code this} instance.
517 */
518 public TextStringBuilder append(final CharBuffer buf, final int startIndex, final int length) {
519 if (buf == null) {
520 return appendNull();
521 }
522 if (buf.hasArray()) {
523 final int totalLength = buf.remaining();
524 if (startIndex < 0 || startIndex > totalLength) {
525 throw new StringIndexOutOfBoundsException("startIndex must be valid");
526 }
527 if (length < 0 || startIndex + length > totalLength) {
528 throw new StringIndexOutOfBoundsException("length must be valid");
529 }
530 final int len = length();
531 ensureCapacityInternal(len + length);
532 System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length);
533 size += length;
534 } else {
535 append(buf.toString(), startIndex, length);
536 }
537 return this;
538 }
539
540 /**
541 * Appends a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
542 *
543 * @param seq the CharSequence to append.
544 * @return {@code this} instance.
545 */
546 @Override
547 public TextStringBuilder append(final CharSequence seq) {
548 if (seq == null) {
549 return appendNull();
550 }
551 if (seq instanceof TextStringBuilder) {
552 return append((TextStringBuilder) seq);
553 }
554 if (seq instanceof StringBuilder) {
555 return append((StringBuilder) seq);
556 }
557 if (seq instanceof StringBuffer) {
558 return append((StringBuffer) seq);
559 }
560 if (seq instanceof CharBuffer) {
561 return append((CharBuffer) seq);
562 }
563 return append(seq.toString());
564 }
565
566 /**
567 * Appends part of a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
568 *
569 * @param seq the CharSequence to append.
570 * @param startIndex the start index, inclusive, must be valid.
571 * @param endIndex the end index, exclusive, must be valid.
572 * @return {@code this} instance.
573 */
574 @Override
575 public TextStringBuilder append(final CharSequence seq, final int startIndex, final int endIndex) {
576 if (seq == null) {
577 return appendNull();
578 }
579 if (endIndex <= 0) {
580 throw new StringIndexOutOfBoundsException("endIndex must be valid");
581 }
582 if (startIndex >= endIndex) {
583 throw new StringIndexOutOfBoundsException("endIndex must be greater than startIndex");
584 }
585 return append(seq.toString(), startIndex, endIndex - startIndex);
586 }
587
588 /**
589 * Appends a double value to the string builder using {@code String.valueOf}.
590 *
591 * @param value the value to append.
592 * @return {@code this} instance.
593 */
594 public TextStringBuilder append(final double value) {
595 return append(String.valueOf(value));
596 }
597
598 /**
599 * Appends a float value to the string builder using {@code String.valueOf}.
600 *
601 * @param value the value to append.
602 * @return {@code this} instance.
603 */
604 public TextStringBuilder append(final float value) {
605 return append(String.valueOf(value));
606 }
607
608 /**
609 * Appends an int value to the string builder using {@code String.valueOf}.
610 *
611 * @param value the value to append.
612 * @return {@code this} instance.
613 */
614 public TextStringBuilder append(final int value) {
615 return append(String.valueOf(value));
616 }
617
618 /**
619 * Appends a long value to the string builder using {@code String.valueOf}.
620 *
621 * @param value the value to append.
622 * @return {@code this} instance.
623 */
624 public TextStringBuilder append(final long value) {
625 return append(String.valueOf(value));
626 }
627
628 /**
629 * Appends an object to this string builder. Appending null will call {@link #appendNull()}.
630 *
631 * @param obj the object to append.
632 * @return {@code this} instance.
633 */
634 public TextStringBuilder append(final Object obj) {
635 if (obj == null) {
636 return appendNull();
637 }
638 if (obj instanceof CharSequence) {
639 return append((CharSequence) obj);
640 }
641 return append(obj.toString());
642 }
643
644 /**
645 * Appends a string to this string builder. Appending null will call {@link #appendNull()}.
646 *
647 * @param str the string to append.
648 * @return {@code this} instance.
649 */
650 public TextStringBuilder append(final String str) {
651 return append(str, 0, StringUtils.length(str));
652 }
653
654 /**
655 * Appends part of a string to this string builder. Appending null will call {@link #appendNull()}.
656 *
657 * @param str the string to append.
658 * @param startIndex the start index, inclusive, must be valid.
659 * @param length the length to append, must be valid.
660 * @return {@code this} instance.
661 * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the range {@code 0 <= startIndex <= str.length()}.
662 * @throws StringIndexOutOfBoundsException if {@code length < 0}.
663 * @throws StringIndexOutOfBoundsException if {@code startIndex + length > str.length()}.
664 */
665 public TextStringBuilder append(final String str, final int startIndex, final int length) {
666 if (str == null) {
667 return appendNull();
668 }
669 if (startIndex < 0 || startIndex > str.length()) {
670 throw new StringIndexOutOfBoundsException("startIndex must be valid");
671 }
672 if (length < 0 || startIndex + length > str.length()) {
673 throw new StringIndexOutOfBoundsException("length must be valid");
674 }
675 if (length > 0) {
676 final int len = length();
677 ensureCapacityInternal(len + length);
678 str.getChars(startIndex, startIndex + length, buffer, len);
679 size += length;
680 }
681 return this;
682 }
683
684 /**
685 * Calls {@link String#format(String, Object...)} and appends the result.
686 *
687 * @param format the format string.
688 * @param objs the objects to use in the format string.
689 * @return {@code this} to enable chaining.
690 * @see String#format(String, Object...)
691 */
692 public TextStringBuilder append(final String format, final Object... objs) {
693 return append(String.format(format, objs));
694 }
695
696 /**
697 * Appends a string buffer to this string builder. Appending null will call {@link #appendNull()}.
698 *
699 * @param str the string buffer to append.
700 * @return {@code this} instance.
701 */
702 public TextStringBuilder append(final StringBuffer str) {
703 return append(str, 0, StringUtils.length(str));
704 }
705
706 /**
707 * Appends part of a string buffer to this string builder. Appending null will call {@link #appendNull()}.
708 *
709 * @param str the string to append.
710 * @param startIndex the start index, inclusive, must be valid.
711 * @param length the length to append, must be valid.
712 * @return {@code this} instance.
713 */
714 public TextStringBuilder append(final StringBuffer str, final int startIndex, final int length) {
715 if (str == null) {
716 return appendNull();
717 }
718 if (startIndex < 0 || startIndex > str.length()) {
719 throw new StringIndexOutOfBoundsException("startIndex must be valid");
720 }
721 if (length < 0 || startIndex + length > str.length()) {
722 throw new StringIndexOutOfBoundsException("length must be valid");
723 }
724 if (length > 0) {
725 final int len = length();
726 ensureCapacityInternal(len + length);
727 str.getChars(startIndex, startIndex + length, buffer, len);
728 size += length;
729 }
730 return this;
731 }
732
733 /**
734 * Appends a StringBuilder to this string builder. Appending null will call {@link #appendNull()}.
735 *
736 * @param str the StringBuilder to append.
737 * @return {@code this} instance.
738 */
739 public TextStringBuilder append(final StringBuilder str) {
740 return append(str, 0, StringUtils.length(str));
741 }
742
743 /**
744 * Appends part of a StringBuilder to this string builder. Appending null will call {@link #appendNull()}.
745 *
746 * @param str the StringBuilder to append.
747 * @param startIndex the start index, inclusive, must be valid.
748 * @param length the length to append, must be valid.
749 * @return {@code this} instance.
750 */
751 public TextStringBuilder append(final StringBuilder str, final int startIndex, final int length) {
752 if (str == null) {
753 return appendNull();
754 }
755 if (startIndex < 0 || startIndex > str.length()) {
756 throw new StringIndexOutOfBoundsException("startIndex must be valid");
757 }
758 if (length < 0 || startIndex + length > str.length()) {
759 throw new StringIndexOutOfBoundsException("length must be valid");
760 }
761 if (length > 0) {
762 final int len = length();
763 ensureCapacityInternal(len + length);
764 str.getChars(startIndex, startIndex + length, buffer, len);
765 size += length;
766 }
767 return this;
768 }
769
770 /**
771 * Appends another string builder to this string builder. Appending null will call {@link #appendNull()}.
772 *
773 * @param str the string builder to append.
774 * @return {@code this} instance.
775 */
776 public TextStringBuilder append(final TextStringBuilder str) {
777 return append(str, 0, StringUtils.length(str));
778 }
779
780 /**
781 * Appends part of a string builder to this string builder. Appending null will call {@link #appendNull()}.
782 *
783 * @param str the string to append.
784 * @param startIndex the start index, inclusive, must be valid.
785 * @param length the length to append, must be valid.
786 * @return {@code this} instance.
787 */
788 public TextStringBuilder append(final TextStringBuilder str, final int startIndex, final int length) {
789 if (str == null) {
790 return appendNull();
791 }
792 if (startIndex < 0 || startIndex > str.length()) {
793 throw new StringIndexOutOfBoundsException("startIndex must be valid");
794 }
795 if (length < 0 || startIndex + length > str.length()) {
796 throw new StringIndexOutOfBoundsException("length must be valid");
797 }
798 if (length > 0) {
799 final int len = length();
800 ensureCapacityInternal(len + length);
801 str.getChars(startIndex, startIndex + length, buffer, len);
802 size += length;
803 }
804 return this;
805 }
806
807 /**
808 * Appends each item in an iterable to the builder without any separators. Appending a null iterable will have no effect. Each object is appended using
809 * {@link #append(Object)}.
810 *
811 * @param iterable the iterable to append.
812 * @return {@code this} instance.
813 */
814 public TextStringBuilder appendAll(final Iterable<?> iterable) {
815 if (iterable != null) {
816 iterable.forEach(this::append);
817 }
818 return this;
819 }
820
821 /**
822 * Appends each item in an iterator to the builder without any separators. Appending a null iterator will have no effect. Each object is appended using
823 * {@link #append(Object)}.
824 *
825 * @param it the iterator to append.
826 * @return {@code this} instance.
827 */
828 public TextStringBuilder appendAll(final Iterator<?> it) {
829 if (it != null) {
830 it.forEachRemaining(this::append);
831 }
832 return this;
833 }
834
835 /**
836 * Appends each item in an array to the builder without any separators. Appending a null array will have no effect. Each object is appended using
837 * {@link #append(Object)}.
838 *
839 * @param <T> the element type.
840 * @param array the array to append.
841 * @return {@code this} instance.
842 */
843 public <T> TextStringBuilder appendAll(@SuppressWarnings("unchecked") final T... array) {
844 /*
845 * @SuppressWarnings used to hide warning about vararg usage. We cannot use @SafeVarargs, since this method is
846 * not final. Using @SuppressWarnings is fine, because it isn't inherited by subclasses, so each subclass must
847 * vouch for itself whether its use of 'array' is safe.
848 */
849 if (array != null && array.length > 0) {
850 for (final Object element : array) {
851 append(element);
852 }
853 }
854 return this;
855 }
856
857 /** Appends {@code "false"}. */
858 private void appendFalse(int index) {
859 buffer[index++] = 'f';
860 buffer[index++] = 'a';
861 buffer[index++] = 'l';
862 buffer[index++] = 's';
863 buffer[index] = 'e';
864 size += FALSE_STRING_SIZE;
865 }
866
867 /**
868 * Appends an object to the builder padding on the left to a fixed width. The {@code String.valueOf} of the {@code int} value is used. If the formatted
869 * value is larger than the length, the left hand side is lost.
870 *
871 * @param value the value to append.
872 * @param width the fixed field width, zero or negative has no effect.
873 * @param padChar the pad character to use.
874 * @return {@code this} instance.
875 */
876 public TextStringBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
877 return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
878 }
879
880 /**
881 * Appends an object to the builder padding on the left to a fixed width. The {@code toString} of the object is used. If the object is larger than the
882 * length, the left hand side is lost. If the object is null, the null text value is used.
883 *
884 * @param obj the object to append, null uses null text.
885 * @param width the fixed field width, zero or negative has no effect.
886 * @param padChar the pad character to use.
887 * @return {@code this} instance.
888 */
889 public TextStringBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
890 if (width > 0) {
891 ensureCapacityInternal(size + width);
892 String str = Objects.toString(obj, getNullText());
893 if (str == null) {
894 str = StringUtils.EMPTY;
895 }
896 final int strLen = str.length();
897 if (strLen >= width) {
898 str.getChars(strLen - width, strLen, buffer, size);
899 } else {
900 final int padLen = width - strLen;
901 final int toIndex = size + padLen;
902 Arrays.fill(buffer, size, toIndex, padChar);
903 str.getChars(0, strLen, buffer, toIndex);
904 }
905 size += width;
906 }
907 return this;
908 }
909
910 /**
911 * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the {@code int} value is used. If the object is
912 * larger than the length, the right hand side is lost.
913 *
914 * @param value the value to append.
915 * @param width the fixed field width, zero or negative has no effect.
916 * @param padChar the pad character to use.
917 * @return {@code this} instance.
918 */
919 public TextStringBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
920 return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
921 }
922
923 /**
924 * Appends an object to the builder padding on the right to a fixed length. The {@code toString} of the object is used. If the object is larger than the
925 * length, the right hand side is lost. If the object is null, null text value is used.
926 *
927 * @param obj the object to append, null uses null text.
928 * @param width the fixed field width, zero or negative has no effect.
929 * @param padChar the pad character to use.
930 * @return {@code this} instance.
931 */
932 public TextStringBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
933 if (width > 0) {
934 ensureCapacityInternal(size + width);
935 String str = Objects.toString(obj, getNullText());
936 if (str == null) {
937 str = StringUtils.EMPTY;
938 }
939 final int strLen = str.length();
940 if (strLen >= width) {
941 str.getChars(0, width, buffer, size);
942 } else {
943 str.getChars(0, strLen, buffer, size);
944 final int fromIndex = size + strLen;
945 Arrays.fill(buffer, fromIndex, fromIndex + width - strLen, padChar);
946 }
947 size += width;
948 }
949 return this;
950 }
951
952 /**
953 * Appends a boolean value followed by a new line to the string builder.
954 *
955 * @param value the value to append.
956 * @return {@code this} instance.
957 */
958 public TextStringBuilder appendln(final boolean value) {
959 return append(value).appendNewLine();
960 }
961
962 /**
963 * Appends a char value followed by a new line to the string builder.
964 *
965 * @param ch the value to append.
966 * @return {@code this} instance.
967 */
968 public TextStringBuilder appendln(final char ch) {
969 return append(ch).appendNewLine();
970 }
971
972 /**
973 * Appends a char array followed by a new line to the string builder. Appending null will call
974 * {@link #appendNull()}.
975 *
976 * @param chars the char array to append.
977 * @return {@code this} instance.
978 */
979 public TextStringBuilder appendln(final char[] chars) {
980 return append(chars).appendNewLine();
981 }
982
983 /**
984 * Appends a char array followed by a new line to the string builder. Appending null will call
985 * {@link #appendNull()}.
986 *
987 * @param chars the char array to append.
988 * @param startIndex the start index, inclusive, must be valid.
989 * @param length the length to append, must be valid.
990 * @return {@code this} instance.
991 */
992 public TextStringBuilder appendln(final char[] chars, final int startIndex, final int length) {
993 return append(chars, startIndex, length).appendNewLine();
994 }
995
996 /**
997 * Appends a double value followed by a new line to the string builder using {@code String.valueOf}.
998 *
999 * @param value the value to append.
1000 * @return {@code this} instance.
1001 */
1002 public TextStringBuilder appendln(final double value) {
1003 return append(value).appendNewLine();
1004 }
1005
1006 /**
1007 * Appends a float value followed by a new line to the string builder using {@code String.valueOf}.
1008 *
1009 * @param value the value to append.
1010 * @return {@code this} instance.
1011 */
1012 public TextStringBuilder appendln(final float value) {
1013 return append(value).appendNewLine();
1014 }
1015
1016 /**
1017 * Appends an int value followed by a new line to the string builder using {@code String.valueOf}.
1018 *
1019 * @param value the value to append.
1020 * @return {@code this} instance.
1021 */
1022 public TextStringBuilder appendln(final int value) {
1023 return append(value).appendNewLine();
1024 }
1025
1026 /**
1027 * Appends a long value followed by a new line to the string builder using {@code String.valueOf}.
1028 *
1029 * @param value the value to append.
1030 * @return {@code this} instance.
1031 */
1032 public TextStringBuilder appendln(final long value) {
1033 return append(value).appendNewLine();
1034 }
1035
1036 /**
1037 * Appends an object followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
1038 *
1039 * @param obj the object to append.
1040 * @return {@code this} instance.
1041 */
1042 public TextStringBuilder appendln(final Object obj) {
1043 return append(obj).appendNewLine();
1044 }
1045
1046 /**
1047 * Appends a string followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
1048 *
1049 * @param str the string to append.
1050 * @return {@code this} instance.
1051 */
1052 public TextStringBuilder appendln(final String str) {
1053 return append(str).appendNewLine();
1054 }
1055
1056 /**
1057 * Appends part of a string followed by a new line to this string builder. Appending null will call
1058 * {@link #appendNull()}.
1059 *
1060 * @param str the string to append.
1061 * @param startIndex the start index, inclusive, must be valid.
1062 * @param length the length to append, must be valid.
1063 * @return {@code this} instance.
1064 */
1065 public TextStringBuilder appendln(final String str, final int startIndex, final int length) {
1066 return append(str, startIndex, length).appendNewLine();
1067 }
1068
1069 /**
1070 * Calls {@link String#format(String, Object...)} and appends the result.
1071 *
1072 * @param format the format string.
1073 * @param objs the objects to use in the format string.
1074 * @return {@code this} to enable chaining.
1075 * @see String#format(String, Object...)
1076 */
1077 public TextStringBuilder appendln(final String format, final Object... objs) {
1078 return append(format, objs).appendNewLine();
1079 }
1080
1081 /**
1082 * Appends a string buffer followed by a new line to this string builder. Appending null will call
1083 * {@link #appendNull()}.
1084 *
1085 * @param str the string buffer to append.
1086 * @return {@code this} instance.
1087 */
1088 public TextStringBuilder appendln(final StringBuffer str) {
1089 return append(str).appendNewLine();
1090 }
1091
1092 /**
1093 * Appends part of a string buffer followed by a new line to this string builder. Appending null will call
1094 * {@link #appendNull()}.
1095 *
1096 * @param str the string to append.
1097 * @param startIndex the start index, inclusive, must be valid.
1098 * @param length the length to append, must be valid.
1099 * @return {@code this} instance.
1100 */
1101 public TextStringBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
1102 return append(str, startIndex, length).appendNewLine();
1103 }
1104
1105 /**
1106 * Appends a string builder followed by a new line to this string builder. Appending null will call
1107 * {@link #appendNull()}.
1108 *
1109 * @param str the string builder to append.
1110 * @return {@code this} instance.
1111 */
1112 public TextStringBuilder appendln(final StringBuilder str) {
1113 return append(str).appendNewLine();
1114 }
1115
1116 /**
1117 * Appends part of a string builder followed by a new line to this string builder. Appending null will call
1118 * {@link #appendNull()}.
1119 *
1120 * @param str the string builder to append.
1121 * @param startIndex the start index, inclusive, must be valid.
1122 * @param length the length to append, must be valid.
1123 * @return {@code this} instance.
1124 */
1125 public TextStringBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
1126 return append(str, startIndex, length).appendNewLine();
1127 }
1128
1129 /**
1130 * Appends another string builder followed by a new line to this string builder. Appending null will call
1131 * {@link #appendNull()}.
1132 *
1133 * @param str the string builder to append.
1134 * @return {@code this} instance.
1135 */
1136 public TextStringBuilder appendln(final TextStringBuilder str) {
1137 return append(str).appendNewLine();
1138 }
1139
1140 /**
1141 * Appends part of a string builder followed by a new line to this string builder. Appending null will call
1142 * {@link #appendNull()}.
1143 *
1144 * @param str the string to append.
1145 * @param startIndex the start index, inclusive, must be valid.
1146 * @param length the length to append, must be valid.
1147 * @return {@code this} instance.
1148 */
1149 public TextStringBuilder appendln(final TextStringBuilder str, final int startIndex, final int length) {
1150 return append(str, startIndex, length).appendNewLine();
1151 }
1152
1153 /**
1154 * Appends this builder's new line string to this builder.
1155 * <p>
1156 * By default, the new line is the system default from {@link System#lineSeparator()}.
1157 * </p>
1158 * <p>
1159 * The new line string can be changed using {@link #setNewLineText(String)}. For example, you can use this to force the output to always use Unix line
1160 * endings even when on Windows.
1161 * </p>
1162 *
1163 * @return {@code this} instance.
1164 * @see #getNewLineText()
1165 * @see #setNewLineText(String)
1166 */
1167 public TextStringBuilder appendNewLine() {
1168 return append(newLine == null ? System.lineSeparator() : newLine);
1169 }
1170
1171 /**
1172 * Appends the text representing {@code null} to this string builder.
1173 *
1174 * @return {@code this} instance.
1175 */
1176 public TextStringBuilder appendNull() {
1177 return nullText != null ? append(nullText) : this;
1178 }
1179
1180 /**
1181 * Appends the pad character to the builder the specified number of times.
1182 *
1183 * @param length the length to append, negative means no append.
1184 * @param padChar the character to append.
1185 * @return {@code this} instance.
1186 */
1187 public TextStringBuilder appendPadding(final int length, final char padChar) {
1188 if (length >= 0) {
1189 ensureCapacityInternal(size + length);
1190 for (int i = 0; i < length; i++) {
1191 buffer[size++] = padChar;
1192 }
1193 }
1194 return this;
1195 }
1196
1197 /**
1198 * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}.
1199 * <p>
1200 * This method is useful for adding a separator each time around the loop except the first.
1201 * </p>
1202 *
1203 * <pre>
1204 * for (Iterator it = list.iterator(); it.hasNext();) {
1205 * appendSeparator(',');
1206 * append(it.next());
1207 * }
1208 * </pre>
1209 *
1210 * <p>
1211 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1212 * </p>
1213 *
1214 * @param separator the separator to use.
1215 * @return {@code this} instance.
1216 */
1217 public TextStringBuilder appendSeparator(final char separator) {
1218 return isEmpty() ? this : append(separator);
1219 }
1220
1221 /**
1222 * Appends one of both separators to the builder If the builder is currently empty it will append the defaultIfEmpty-separator Otherwise it will append the
1223 * standard-separator
1224 * <p>
1225 * The separator is appended using {@link #append(char)}.
1226 * </p>
1227 *
1228 * @param standard the separator if builder is not empty.
1229 * @param defaultIfEmpty the separator if builder is empty.
1230 * @return {@code this} instance.
1231 */
1232 public TextStringBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
1233 return append(isEmpty() ? defaultIfEmpty : standard);
1234 }
1235
1236 /**
1237 * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using
1238 * {@link #append(char)}.
1239 * <p>
1240 * This method is useful for adding a separator each time around the loop except the first.
1241 * </p>
1242 *
1243 * <pre>
1244 * for (int i = 0; i < list.size(); i++) {
1245 * appendSeparator(",", i);
1246 * append(list.get(i));
1247 * }
1248 * </pre>
1249 *
1250 * <p>
1251 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1252 * </p>
1253 *
1254 * @param separator the separator to use.
1255 * @param loopIndex the loop index.
1256 * @return {@code this} instance.
1257 */
1258 public TextStringBuilder appendSeparator(final char separator, final int loopIndex) {
1259 return loopIndex > 0 ? append(separator) : this;
1260 }
1261
1262 /**
1263 * Appends a separator if the builder is currently non-empty. Appending a null separator will have no effect. The
1264 * separator is appended using {@link #append(String)}.
1265 * <p>
1266 * This method is useful for adding a separator each time around the loop except the first.
1267 * </p>
1268 *
1269 * <pre>
1270 * for (Iterator it = list.iterator(); it.hasNext();) {
1271 * appendSeparator(",");
1272 * append(it.next());
1273 * }
1274 * </pre>
1275 *
1276 * <p>
1277 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1278 * </p>
1279 *
1280 * @param separator the separator to use, null means no separator.
1281 * @return {@code this} instance.
1282 */
1283 public TextStringBuilder appendSeparator(final String separator) {
1284 return appendSeparator(separator, null);
1285 }
1286
1287 /**
1288 * Appends a separator to the builder if the loop index is greater than zero. Appending a null separator will have
1289 * no effect. The separator is appended using {@link #append(String)}.
1290 * <p>
1291 * This method is useful for adding a separator each time around the loop except the first.
1292 * </p>
1293 *
1294 * <pre>
1295 * for (int i = 0; i < list.size(); i++) {
1296 * appendSeparator(",", i);
1297 * append(list.get(i));
1298 * }
1299 * </pre>
1300 *
1301 * <p>
1302 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1303 * </p>
1304 *
1305 * @param separator the separator to use, null means no separator.
1306 * @param loopIndex the loop index.
1307 * @return {@code this} instance.
1308 */
1309 public TextStringBuilder appendSeparator(final String separator, final int loopIndex) {
1310 return separator != null && loopIndex > 0 ? append(separator) : this;
1311 }
1312
1313 /**
1314 * Appends one of both separators to the StrBuilder. If the builder is currently empty, it will append the
1315 * defaultIfEmpty-separator, otherwise it will append the standard-separator.
1316 * <p>
1317 * Appending a null separator will have no effect. The separator is appended using {@link #append(String)}.
1318 * </p>
1319 * <p>
1320 * This method is for example useful for constructing queries
1321 * </p>
1322 *
1323 * <pre>
1324 * StrBuilder whereClause = new StrBuilder();
1325 * if (searchCommand.getPriority() != null) {
1326 * whereClause.appendSeparator(" and", " where");
1327 * whereClause.append(" priority = ?")
1328 * }
1329 * if (searchCommand.getComponent() != null) {
1330 * whereClause.appendSeparator(" and", " where");
1331 * whereClause.append(" component = ?")
1332 * }
1333 * selectClause.append(whereClause)
1334 * </pre>
1335 *
1336 * @param standard the separator if builder is not empty, null means no separator.
1337 * @param defaultIfEmpty the separator if builder is empty, null means no separator.
1338 * @return {@code this} instance.
1339 */
1340 public TextStringBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
1341 final String str = isEmpty() ? defaultIfEmpty : standard;
1342 return str != null ? append(str) : this;
1343 }
1344
1345 /**
1346 * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}.
1347 * <p>
1348 * This method tries to avoid doing any extra copies of contents.
1349 * </p>
1350 *
1351 * @param appendable the appendable to append data to.
1352 * @throws IOException if an I/O error occurs.
1353 * @see #readFrom(Readable)
1354 */
1355 public void appendTo(final Appendable appendable) throws IOException {
1356 if (appendable instanceof Writer) {
1357 ((Writer) appendable).write(buffer, 0, size);
1358 } else if (appendable instanceof StringBuilder) {
1359 ((StringBuilder) appendable).append(buffer, 0, size);
1360 } else if (appendable instanceof StringBuffer) {
1361 ((StringBuffer) appendable).append(buffer, 0, size);
1362 } else if (appendable instanceof CharBuffer) {
1363 ((CharBuffer) appendable).put(buffer, 0, size);
1364 } else {
1365 appendable.append(this);
1366 }
1367 }
1368
1369 /** Appends {@code "true"}. */
1370 private void appendTrue(int index) {
1371 buffer[index++] = 't';
1372 buffer[index++] = 'r';
1373 buffer[index++] = 'u';
1374 buffer[index] = 'e';
1375 size += TRUE_STRING_SIZE;
1376 }
1377
1378 /**
1379 * Appends an iterable placing separators between each value, but not before the first or after the last. Appending
1380 * a null iterable will have no effect. Each object is appended using {@link #append(Object)}.
1381 *
1382 * @param iterable the iterable to append.
1383 * @param separator the separator to use, null means no separator.
1384 * @return {@code this} instance.
1385 */
1386 public TextStringBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
1387 if (iterable != null) {
1388 appendWithSeparators(iterable.iterator(), separator);
1389 }
1390 return this;
1391 }
1392
1393 /**
1394 * Appends an iterator placing separators between each value, but not before the first or after the last. Appending
1395 * a null iterator will have no effect. Each object is appended using {@link #append(Object)}.
1396 *
1397 * @param it the iterator to append.
1398 * @param separator the separator to use, null means no separator.
1399 * @return {@code this} instance.
1400 */
1401 public TextStringBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
1402 if (it != null) {
1403 final String sep = Objects.toString(separator, StringUtils.EMPTY);
1404 while (it.hasNext()) {
1405 append(it.next());
1406 if (it.hasNext()) {
1407 append(sep);
1408 }
1409 }
1410 }
1411 return this;
1412 }
1413
1414 /**
1415 * Appends an array placing separators between each value, but not before the first or after the last. Appending a
1416 * null array will have no effect. Each object is appended using {@link #append(Object)}.
1417 *
1418 * @param array the array to append.
1419 * @param separator the separator to use, null means no separator.
1420 * @return {@code this} instance.
1421 */
1422 public TextStringBuilder appendWithSeparators(final Object[] array, final String separator) {
1423 if (array != null && array.length > 0) {
1424 final String sep = Objects.toString(separator, StringUtils.EMPTY);
1425 append(array[0]);
1426 for (int i = 1; i < array.length; i++) {
1427 append(sep).append(array[i]);
1428 }
1429 }
1430 return this;
1431 }
1432
1433 /**
1434 * Gets the contents of this builder as a Reader.
1435 * <p>
1436 * This method allows the contents of the builder to be read using any standard method that expects a Reader.
1437 * </p>
1438 * <p>
1439 * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read away.
1440 * </p>
1441 * <p>
1442 * The internal character array is shared between the builder and the reader. This allows you to append to the
1443 * builder after creating the reader, and the changes will be picked up. Note however, that no synchronization
1444 * occurs, so you must perform all operations with the builder and the reader in one thread.
1445 * </p>
1446 * <p>
1447 * The returned reader supports marking, and ignores the flush method.
1448 * </p>
1449 *
1450 * @return a reader that reads from this builder.
1451 */
1452 public Reader asReader() {
1453 return new TextStringBuilderReader();
1454 }
1455
1456 /**
1457 * Creates a tokenizer that can tokenize the contents of this builder.
1458 * <p>
1459 * This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to
1460 * tokenize on space, tab, newline and form feed (as per StringTokenizer). These values can be changed on the
1461 * tokenizer class, before retrieving the tokens.
1462 * </p>
1463 * <p>
1464 * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within
1465 * certain limits, however there is no synchronization. Once the tokenizer has been used once, it must be
1466 * {@link StringTokenizer#reset() reset} to pickup the latest changes in the builder. For example:
1467 * </p>
1468 *
1469 * <pre>
1470 * StrBuilder b = new StrBuilder();
1471 * b.append("a b ");
1472 * StrTokenizer t = b.asTokenizer();
1473 * String[] tokens1 = t.getTokenArray(); // returns a,b
1474 * b.append("c d ");
1475 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
1476 * t.reset(); // reset causes builder changes to be picked up
1477 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
1478 * </pre>
1479 *
1480 * <p>
1481 * In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to
1482 * alter how it tokenizes. Just remember to call reset when you want to pickup builder changes.
1483 * </p>
1484 * <p>
1485 * Calling {@link StringTokenizer#reset(String)} or {@link StringTokenizer#reset(char[])} with a non-null value will
1486 * break the link with the builder.
1487 * </p>
1488 *
1489 * @return a tokenizer that is linked to this builder.
1490 */
1491 public StringTokenizer asTokenizer() {
1492 return new TextStringBuilderTokenizer();
1493 }
1494
1495 /**
1496 * Gets this builder as a Writer that can be written to.
1497 * <p>
1498 * This method allows you to populate the contents of the builder using any standard method that takes a Writer.
1499 * </p>
1500 * <p>
1501 * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is available at
1502 * any time using the methods of the {@code StrBuilder}.
1503 * </p>
1504 * <p>
1505 * The internal character array is shared between the builder and the writer. This allows you to intermix calls that
1506 * append to the builder and write using the writer and the changes will be occur correctly. Note however, that no
1507 * synchronization occurs, so you must perform all operations with the builder and the writer in one thread.
1508 * </p>
1509 * <p>
1510 * The returned writer ignores the close and flush methods.
1511 * </p>
1512 *
1513 * @return a writer that populates this builder.
1514 */
1515 public Writer asWriter() {
1516 return new TextStringBuilderWriter();
1517 }
1518
1519 /**
1520 * Converts this instance to a String.
1521 *
1522 * @return This instance as a String.
1523 * @see #toString()
1524 * @deprecated Use {@link #get()}.
1525 */
1526 @Deprecated
1527 @Override
1528 public String build() {
1529 return toString();
1530 }
1531
1532 /**
1533 * Gets the current size of the internal character array buffer.
1534 *
1535 * @return The capacity.
1536 */
1537 public int capacity() {
1538 return buffer.length;
1539 }
1540
1541 /**
1542 * Gets the character at the specified index.
1543 *
1544 * @param index the index to retrieve, must be valid.
1545 * @return The character at the index.
1546 * @throws IndexOutOfBoundsException if the index is invalid.
1547 * @see #setCharAt(int, char)
1548 * @see #deleteCharAt(int)
1549 */
1550 @Override
1551 public char charAt(final int index) {
1552 validateIndex(index);
1553 return buffer[index];
1554 }
1555
1556 /**
1557 * Clears the string builder (convenience Collections API style method).
1558 * <p>
1559 * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed
1560 * by {@link #minimizeCapacity()}.
1561 * </p>
1562 * <p>
1563 * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of
1564 * Collections.
1565 * </p>
1566 *
1567 * @return {@code this} instance.
1568 */
1569 public TextStringBuilder clear() {
1570 size = 0;
1571 return this;
1572 }
1573
1574 /**
1575 * Tests if the string builder contains the specified char.
1576 *
1577 * @param ch the character to find.
1578 * @return true if the builder contains the character.
1579 */
1580 public boolean contains(final char ch) {
1581 final char[] thisBuf = buffer;
1582 for (int i = 0; i < this.size; i++) {
1583 if (thisBuf[i] == ch) {
1584 return true;
1585 }
1586 }
1587 return false;
1588 }
1589
1590 /**
1591 * Tests if the string builder contains the specified string.
1592 *
1593 * @param str the string to find.
1594 * @return true if the builder contains the string.
1595 */
1596 public boolean contains(final String str) {
1597 return indexOf(str, 0) >= 0;
1598 }
1599
1600 /**
1601 * Tests if the string builder contains a string matched using the specified matcher.
1602 * <p>
1603 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for
1604 * the character 'a' followed by a number.
1605 * </p>
1606 *
1607 * @param matcher the matcher to use, null returns -1.
1608 * @return true if the matcher finds a match in the builder.
1609 */
1610 public boolean contains(final StringMatcher matcher) {
1611 return indexOf(matcher, 0) >= 0;
1612 }
1613
1614 /**
1615 * Deletes the characters between the two specified indices.
1616 *
1617 * @param startIndex the start index, inclusive, must be valid.
1618 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string.
1619 * @return {@code this} instance.
1620 * @throws IndexOutOfBoundsException if the index is invalid.
1621 */
1622 public TextStringBuilder delete(final int startIndex, final int endIndex) {
1623 final int actualEndIndex = validateRange(startIndex, endIndex);
1624 final int len = actualEndIndex - startIndex;
1625 if (len > 0) {
1626 deleteImpl(startIndex, actualEndIndex, len);
1627 }
1628 return this;
1629 }
1630
1631 /**
1632 * Deletes the character wherever it occurs in the builder.
1633 *
1634 * @param ch the character to delete.
1635 * @return {@code this} instance.
1636 */
1637 public TextStringBuilder deleteAll(final char ch) {
1638 for (int i = 0; i < size; i++) {
1639 if (buffer[i] == ch) {
1640 final int start = i;
1641 while (++i < size) {
1642 if (buffer[i] != ch) {
1643 break;
1644 }
1645 }
1646 final int len = i - start;
1647 deleteImpl(start, i, len);
1648 i -= len;
1649 }
1650 }
1651 return this;
1652 }
1653
1654 /**
1655 * Deletes the string wherever it occurs in the builder.
1656 *
1657 * @param str the string to delete, null causes no action.
1658 * @return {@code this} instance.
1659 */
1660 public TextStringBuilder deleteAll(final String str) {
1661 final int len = str == null ? 0 : str.length();
1662 if (len > 0) {
1663 int index = indexOf(str, 0);
1664 while (index >= 0) {
1665 deleteImpl(index, index + len, len);
1666 index = indexOf(str, index);
1667 }
1668 }
1669 return this;
1670 }
1671
1672 /**
1673 * Deletes all parts of the builder that the matcher matches.
1674 * <p>
1675 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all
1676 * occurrences where the character 'a' is followed by a number.
1677 * </p>
1678 *
1679 * @param matcher the matcher to use to find the deletion, null causes no action.
1680 * @return {@code this} instance.
1681 */
1682 public TextStringBuilder deleteAll(final StringMatcher matcher) {
1683 return replace(matcher, null, 0, size, -1);
1684 }
1685
1686 /**
1687 * Deletes the character at the specified index.
1688 *
1689 * @param index the index to delete.
1690 * @return {@code this} instance.
1691 * @throws IndexOutOfBoundsException if the index is invalid.
1692 * @see #charAt(int)
1693 * @see #setCharAt(int, char)
1694 */
1695 public TextStringBuilder deleteCharAt(final int index) {
1696 validateIndex(index);
1697 deleteImpl(index, index + 1, 1);
1698 return this;
1699 }
1700
1701 /**
1702 * Deletes the character wherever it occurs in the builder.
1703 *
1704 * @param ch the character to delete.
1705 * @return {@code this} instance.
1706 */
1707 public TextStringBuilder deleteFirst(final char ch) {
1708 for (int i = 0; i < size; i++) {
1709 if (buffer[i] == ch) {
1710 deleteImpl(i, i + 1, 1);
1711 break;
1712 }
1713 }
1714 return this;
1715 }
1716
1717 /**
1718 * Deletes the string wherever it occurs in the builder.
1719 *
1720 * @param str the string to delete, null causes no action.
1721 * @return {@code this} instance.
1722 */
1723 public TextStringBuilder deleteFirst(final String str) {
1724 final int len = str == null ? 0 : str.length();
1725 if (len > 0) {
1726 final int index = indexOf(str, 0);
1727 if (index >= 0) {
1728 deleteImpl(index, index + len, len);
1729 }
1730 }
1731 return this;
1732 }
1733
1734 /**
1735 * Deletes the first match within the builder using the specified matcher.
1736 * <p>
1737 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete where
1738 * the character 'a' is followed by a number.
1739 * </p>
1740 *
1741 * @param matcher the matcher to use to find the deletion, null causes no action.
1742 * @return {@code this} instance.
1743 */
1744 public TextStringBuilder deleteFirst(final StringMatcher matcher) {
1745 return replace(matcher, null, 0, size, 1);
1746 }
1747
1748 /**
1749 * Internal method to delete a range without validation.
1750 *
1751 * @param startIndex the start index, must be valid.
1752 * @param endIndex the end index (exclusive), must be valid.
1753 * @param len the length, must be valid.
1754 * @throws IndexOutOfBoundsException if any index is invalid.
1755 */
1756 private void deleteImpl(final int startIndex, final int endIndex, final int len) {
1757 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1758 size -= len;
1759 }
1760
1761 /**
1762 * Gets the character at the specified index before deleting it.
1763 *
1764 * @param index the index to retrieve, must be valid
1765 * @return The character at the index
1766 * @throws IndexOutOfBoundsException if the index is invalid
1767 * @since 1.9
1768 * @see #charAt(int)
1769 * @see #deleteCharAt(int)
1770 */
1771 public char drainChar(final int index) {
1772 validateIndex(index);
1773 final char c = buffer[index];
1774 deleteCharAt(index);
1775 return c;
1776 }
1777
1778 /**
1779 * Drains (copies, then deletes) this character sequence into the specified array. This is equivalent to copying the
1780 * characters from this sequence into the target and then deleting those character from this sequence.
1781 *
1782 * @param startIndex first index to copy, inclusive.
1783 * @param endIndex last index to copy, exclusive.
1784 * @param target the target array, must not be {@code null}.
1785 * @param targetIndex the index to start copying in the target.
1786 * @return How many characters where copied (then deleted). If this builder is empty, return {@code 0}.
1787 * @since 1.9
1788 */
1789 public int drainChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) {
1790 final int length = endIndex - startIndex;
1791 if (isEmpty() || length == 0 || target.length == 0) {
1792 return 0;
1793 }
1794 final int actualLen = Math.min(Math.min(size, length), target.length - targetIndex);
1795 getChars(startIndex, actualLen, target, targetIndex);
1796 delete(startIndex, actualLen);
1797 return actualLen;
1798 }
1799
1800 /**
1801 * Checks whether this builder ends with the specified string.
1802 * <p>
1803 * Note that this method handles null input quietly, unlike String.
1804 * </p>
1805 *
1806 * @param str the string to search for, null returns false.
1807 * @return true if the builder ends with the string.
1808 */
1809 public boolean endsWith(final String str) {
1810 if (str == null) {
1811 return false;
1812 }
1813 final int len = str.length();
1814 if (len == 0) {
1815 return true;
1816 }
1817 if (len > size) {
1818 return false;
1819 }
1820 int pos = size - len;
1821 for (int i = 0; i < len; i++, pos++) {
1822 if (buffer[pos] != str.charAt(i)) {
1823 return false;
1824 }
1825 }
1826 return true;
1827 }
1828
1829 /**
1830 * Tests the capacity and ensures that it is at least the size specified.
1831 *
1832 * <p>
1833 * Note: This method can be used to minimise memory reallocations during
1834 * repeated addition of values by pre-allocating the character buffer.
1835 * The method ignores a negative {@code capacity} argument.
1836 * </p>
1837 *
1838 * @param capacity the capacity to ensure.
1839 * @return {@code this} instance.
1840 * @throws OutOfMemoryError if the capacity cannot be allocated.
1841 */
1842 public TextStringBuilder ensureCapacity(final int capacity) {
1843 if (capacity > 0) {
1844 ensureCapacityInternal(capacity);
1845 }
1846 return this;
1847 }
1848
1849 /**
1850 * Ensures that the buffer is at least the size specified. The {@code capacity} argument
1851 * is treated as an unsigned integer.
1852 *
1853 * <p>
1854 * This method will raise an {@link OutOfMemoryError} if the capacity is too large
1855 * for an array, or cannot be allocated.
1856 * </p>
1857 *
1858 * @param capacity the capacity to ensure.
1859 * @throws OutOfMemoryError if the capacity cannot be allocated.
1860 */
1861 private void ensureCapacityInternal(final int capacity) {
1862 // Check for overflow of the current buffer.
1863 // Assumes capacity is an unsigned integer up to Integer.MAX_VALUE * 2
1864 // (the largest possible addition of two maximum length arrays).
1865 if (capacity - buffer.length > 0) {
1866 resizeBuffer(capacity);
1867 }
1868 }
1869
1870 /**
1871 * Tests the contents of this builder against another to see if they contain the same character content.
1872 *
1873 * @param obj the object to check, null returns false.
1874 * @return true if the builders contain the same characters in the same order.
1875 */
1876 @Override
1877 public boolean equals(final Object obj) {
1878 return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj);
1879 }
1880
1881 /**
1882 * Tests the contents of this builder against another to see if they contain the same character content.
1883 *
1884 * @param other the object to check, null returns false.
1885 * @return true if the builders contain the same characters in the same order.
1886 */
1887 public boolean equals(final TextStringBuilder other) {
1888 if (this == other) {
1889 return true;
1890 }
1891 if (other == null) {
1892 return false;
1893 }
1894 if (this.size != other.size) {
1895 return false;
1896 }
1897 // Be aware not to use Arrays.equals(buffer, other.buffer) for equals() method
1898 // as length of the buffers may be different (TEXT-211)
1899 final char[] thisBuf = this.buffer;
1900 final char[] otherBuf = other.buffer;
1901 for (int i = size - 1; i >= 0; i--) {
1902 if (thisBuf[i] != otherBuf[i]) {
1903 return false;
1904 }
1905 }
1906 return true;
1907 }
1908
1909 /**
1910 * Tests the contents of this builder against another to see if they contain the same character content ignoring
1911 * case.
1912 *
1913 * @param other the object to check, null returns false.
1914 * @return true if the builders contain the same characters in the same order.
1915 */
1916 public boolean equalsIgnoreCase(final TextStringBuilder other) {
1917 if (this == other) {
1918 return true;
1919 }
1920 if (this.size != other.size) {
1921 return false;
1922 }
1923 final char[] thisBuf = this.buffer;
1924 final char[] otherBuf = other.buffer;
1925 for (int i = size - 1; i >= 0; i--) {
1926 final char c1 = thisBuf[i];
1927 final char c2 = otherBuf[i];
1928 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
1929 return false;
1930 }
1931 }
1932 return true;
1933 }
1934
1935 /**
1936 * Converts this instance to a String.
1937 *
1938 * @return This instance as a String.
1939 * @see #toString()
1940 * @since 1.12.0
1941 */
1942 @Override
1943 public String get() {
1944 return toString();
1945 }
1946
1947 /**
1948 * Gets a direct reference to internal storage, not for public consumption.
1949 */
1950 char[] getBuffer() {
1951 return buffer;
1952 }
1953
1954 /**
1955 * Copies this character array into the specified array.
1956 *
1957 * @param target the target array, null will cause an array to be created.
1958 * @return The input array, unless that was null or too small.
1959 */
1960 public char[] getChars(char[] target) {
1961 final int len = length();
1962 if (target == null || target.length < len) {
1963 target = new char[len];
1964 }
1965 System.arraycopy(buffer, 0, target, 0, len);
1966 return target;
1967 }
1968
1969 /**
1970 * Copies this character array into the specified array.
1971 *
1972 * @param startIndex first index to copy, inclusive, must be valid.
1973 * @param endIndex last index to copy, exclusive, must be valid.
1974 * @param target the target array, must not be null or too small.
1975 * @param targetIndex the index to start copying in target.
1976 * @throws NullPointerException if the array is null.
1977 * @throws IndexOutOfBoundsException if any index is invalid.
1978 */
1979 public void getChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) {
1980 if (startIndex < 0) {
1981 throw new StringIndexOutOfBoundsException(startIndex);
1982 }
1983 if (endIndex < 0 || endIndex > length()) {
1984 throw new StringIndexOutOfBoundsException(endIndex);
1985 }
1986 if (startIndex > endIndex) {
1987 throw new StringIndexOutOfBoundsException("end < start");
1988 }
1989 System.arraycopy(buffer, startIndex, target, targetIndex, endIndex - startIndex);
1990 }
1991
1992 /**
1993 * Gets the text to be appended when a {@link #appendNewLine() new line} is added.
1994 *
1995 * @return The new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
1996 */
1997 public String getNewLineText() {
1998 return newLine;
1999 }
2000
2001 /**
2002 * Gets the text to be appended when null is added.
2003 *
2004 * @return The null text, null means no append.
2005 */
2006 public String getNullText() {
2007 return nullText;
2008 }
2009
2010 /**
2011 * Gets a suitable hash code for this builder.
2012 *
2013 * @return a hash code.
2014 */
2015 @Override
2016 public int hashCode() {
2017 // no allocation
2018 final char[] buf = buffer;
2019 int result = 0;
2020 for (int i = 0; i < size; i++) {
2021 result = 31 * result + buf[i];
2022 }
2023 return result;
2024 }
2025
2026 /**
2027 * Searches the string builder to find the first reference to the specified char.
2028 *
2029 * @param ch the character to find.
2030 * @return The first index of the character, or -1 if not found.
2031 */
2032 public int indexOf(final char ch) {
2033 return indexOf(ch, 0);
2034 }
2035
2036 /**
2037 * Searches the string builder to find the first reference to the specified char.
2038 *
2039 * @param ch the character to find.
2040 * @param startIndex the index to start at, invalid index rounded to edge.
2041 * @return The first index of the character, or -1 if not found.
2042 */
2043 public int indexOf(final char ch, int startIndex) {
2044 startIndex = Math.max(0, startIndex);
2045 if (startIndex >= size) {
2046 return StringUtils.INDEX_NOT_FOUND;
2047 }
2048 final char[] thisBuf = buffer;
2049 for (int i = startIndex; i < size; i++) {
2050 if (thisBuf[i] == ch) {
2051 return i;
2052 }
2053 }
2054 return StringUtils.INDEX_NOT_FOUND;
2055 }
2056
2057 /**
2058 * Searches the string builder to find the first reference to the specified string.
2059 * <p>
2060 * Note that a null input string will return -1, whereas the JDK throws an exception.
2061 * </p>
2062 *
2063 * @param str the string to find, null returns -1.
2064 * @return The first index of the string, or -1 if not found.
2065 */
2066 public int indexOf(final String str) {
2067 return indexOf(str, 0);
2068 }
2069
2070 /**
2071 * Searches the string builder to find the first reference to the specified string starting searching from the given
2072 * index.
2073 * <p>
2074 * Note that a null input string will return -1, whereas the JDK throws an exception.
2075 * </p>
2076 *
2077 * @param str the string to find, null returns -1.
2078 * @param startIndex the index to start at, invalid index rounded to edge.
2079 * @return The first index of the string, or -1 if not found.
2080 */
2081 public int indexOf(final String str, int startIndex) {
2082 startIndex = Math.max(0, startIndex);
2083 if (str == null || startIndex >= size) {
2084 return StringUtils.INDEX_NOT_FOUND;
2085 }
2086 final int strLen = str.length();
2087 if (strLen == 1) {
2088 return indexOf(str.charAt(0), startIndex);
2089 }
2090 if (strLen == 0) {
2091 return startIndex;
2092 }
2093 if (strLen > size) {
2094 return StringUtils.INDEX_NOT_FOUND;
2095 }
2096 final char[] thisBuf = buffer;
2097 final int searchLen = size - strLen + 1;
2098 for (int i = startIndex; i < searchLen; i++) {
2099 boolean found = true;
2100 for (int j = 0; j < strLen && found; j++) {
2101 found = str.charAt(j) == thisBuf[i + j];
2102 }
2103 if (found) {
2104 return i;
2105 }
2106 }
2107 return StringUtils.INDEX_NOT_FOUND;
2108 }
2109
2110 /**
2111 * Searches the string builder using the matcher to find the first match.
2112 * <p>
2113 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2114 * character 'a' followed by a number.
2115 * </p>
2116 *
2117 * @param matcher the matcher to use, null returns -1.
2118 * @return The first index matched, or -1 if not found.
2119 */
2120 public int indexOf(final StringMatcher matcher) {
2121 return indexOf(matcher, 0);
2122 }
2123
2124 /**
2125 * Searches the string builder using the matcher to find the first match searching from the given index.
2126 * <p>
2127 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2128 * character 'a' followed by a number.
2129 * </p>
2130 *
2131 * @param matcher the matcher to use, null returns -1.
2132 * @param startIndex the index to start at, invalid index rounded to edge.
2133 * @return The first index matched, or -1 if not found.
2134 */
2135 public int indexOf(final StringMatcher matcher, int startIndex) {
2136 startIndex = Math.max(0, startIndex);
2137 if (matcher == null || startIndex >= size) {
2138 return StringUtils.INDEX_NOT_FOUND;
2139 }
2140 final int len = size;
2141 final char[] buf = buffer;
2142 for (int i = startIndex; i < len; i++) {
2143 if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2144 return i;
2145 }
2146 }
2147 return StringUtils.INDEX_NOT_FOUND;
2148 }
2149
2150 /**
2151 * Inserts the value into this builder.
2152 *
2153 * @param index the index to add at, must be valid.
2154 * @param value the value to insert.
2155 * @return {@code this} instance.
2156 * @throws IndexOutOfBoundsException if the index is invalid.
2157 */
2158 public TextStringBuilder insert(final int index, final boolean value) {
2159 validateRange(index, size);
2160 if (value) {
2161 ensureCapacityInternal(size + TRUE_STRING_SIZE);
2162 System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index);
2163 appendTrue(index);
2164 } else {
2165 ensureCapacityInternal(size + FALSE_STRING_SIZE);
2166 System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index);
2167 appendFalse(index);
2168 }
2169 return this;
2170 }
2171
2172 /**
2173 * Inserts the value into this builder.
2174 *
2175 * @param index the index to add at, must be valid.
2176 * @param value the value to insert.
2177 * @return {@code this} instance.
2178 * @throws IndexOutOfBoundsException if the index is invalid.
2179 */
2180 public TextStringBuilder insert(final int index, final char value) {
2181 validateRange(index, size);
2182 ensureCapacityInternal(size + 1);
2183 System.arraycopy(buffer, index, buffer, index + 1, size - index);
2184 buffer[index] = value;
2185 size++;
2186 return this;
2187 }
2188
2189 /**
2190 * Inserts the character array into this builder. Inserting null will use the stored null text value.
2191 *
2192 * @param index the index to add at, must be valid.
2193 * @param chars the char array to insert.
2194 * @return {@code this} instance.
2195 * @throws IndexOutOfBoundsException if the index is invalid.
2196 */
2197 public TextStringBuilder insert(final int index, final char[] chars) {
2198 validateRange(index, size);
2199 if (chars == null) {
2200 return insert(index, nullText);
2201 }
2202 final int len = chars.length;
2203 if (len > 0) {
2204 ensureCapacityInternal(size + len);
2205 System.arraycopy(buffer, index, buffer, index + len, size - index);
2206 System.arraycopy(chars, 0, buffer, index, len);
2207 size += len;
2208 }
2209 return this;
2210 }
2211
2212 /**
2213 * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
2214 *
2215 * @param index the index to add at, must be valid.
2216 * @param chars the char array to insert.
2217 * @param offset the offset into the character array to start at, must be valid.
2218 * @param length the length of the character array part to copy, must be positive.
2219 * @return {@code this} instance.
2220 * @throws IndexOutOfBoundsException if any index is invalid.
2221 */
2222 public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) {
2223 validateRange(index, size);
2224 if (chars == null) {
2225 return insert(index, nullText);
2226 }
2227 if (offset < 0 || offset > chars.length) {
2228 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
2229 }
2230 if (length < 0 || offset + length > chars.length) {
2231 throw new StringIndexOutOfBoundsException("Invalid length: " + length);
2232 }
2233 if (length > 0) {
2234 ensureCapacityInternal(size + length);
2235 System.arraycopy(buffer, index, buffer, index + length, size - index);
2236 System.arraycopy(chars, offset, buffer, index, length);
2237 size += length;
2238 }
2239 return this;
2240 }
2241
2242 /**
2243 * Inserts the value into this builder.
2244 *
2245 * @param index the index to add at, must be valid.
2246 * @param value the value to insert.
2247 * @return {@code this} instance.
2248 * @throws IndexOutOfBoundsException if the index is invalid.
2249 */
2250 public TextStringBuilder insert(final int index, final double value) {
2251 return insert(index, String.valueOf(value));
2252 }
2253
2254 /**
2255 * Inserts the value into this builder.
2256 *
2257 * @param index the index to add at, must be valid.
2258 * @param value the value to insert.
2259 * @return {@code this} instance.
2260 * @throws IndexOutOfBoundsException if the index is invalid.
2261 */
2262 public TextStringBuilder insert(final int index, final float value) {
2263 return insert(index, String.valueOf(value));
2264 }
2265
2266 /**
2267 * Inserts the value into this builder.
2268 *
2269 * @param index the index to add at, must be valid.
2270 * @param value the value to insert.
2271 * @return {@code this} instance.
2272 * @throws IndexOutOfBoundsException if the index is invalid.
2273 */
2274 public TextStringBuilder insert(final int index, final int value) {
2275 return insert(index, String.valueOf(value));
2276 }
2277
2278 /**
2279 * Inserts the value into this builder.
2280 *
2281 * @param index the index to add at, must be valid.
2282 * @param value the value to insert.
2283 * @return {@code this} instance.
2284 * @throws IndexOutOfBoundsException if the index is invalid.
2285 */
2286 public TextStringBuilder insert(final int index, final long value) {
2287 return insert(index, String.valueOf(value));
2288 }
2289
2290 /**
2291 * Inserts the string representation of an object into this builder. Inserting null will use the stored null text
2292 * value.
2293 *
2294 * @param index the index to add at, must be valid.
2295 * @param obj the object to insert.
2296 * @return {@code this} instance.
2297 * @throws IndexOutOfBoundsException if the index is invalid.
2298 */
2299 public TextStringBuilder insert(final int index, final Object obj) {
2300 return insert(index, Objects.toString(obj, nullText));
2301 }
2302
2303 /**
2304 * Inserts the string into this builder. Inserting null will use the stored null text value.
2305 *
2306 * @param index the index to add at, must be valid.
2307 * @param str the string to insert.
2308 * @return {@code this} instance.
2309 * @throws IndexOutOfBoundsException if the index is invalid.
2310 */
2311 public TextStringBuilder insert(final int index, String str) {
2312 validateRange(index, size);
2313 if (str == null) {
2314 str = nullText;
2315 }
2316 if (str != null) {
2317 final int strLen = str.length();
2318 if (strLen > 0) {
2319 final int newSize = size + strLen;
2320 ensureCapacityInternal(newSize);
2321 System.arraycopy(buffer, index, buffer, index + strLen, size - index);
2322 size = newSize;
2323 str.getChars(0, strLen, buffer, index);
2324 }
2325 }
2326 return this;
2327 }
2328
2329 /**
2330 * Checks is the string builder is empty (convenience Collections API style method).
2331 * <p>
2332 * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2333 * </p>
2334 *
2335 * @return {@code true} if the size is {@code 0}.
2336 */
2337 public boolean isEmpty() {
2338 return size == 0;
2339 }
2340
2341 /**
2342 * Checks is the string builder is not empty.
2343 * <p>
2344 * This method is the same as checking {@link #length()}.
2345 * </p>
2346 *
2347 * @return {@code true} if the size is not {@code 0}.
2348 * @since 1.9
2349 */
2350 public boolean isNotEmpty() {
2351 return size != 0;
2352 }
2353
2354 /**
2355 * Gets whether the internal buffer has been reallocated.
2356 *
2357 * @return Whether the internal buffer has been reallocated.
2358 * @since 1.9
2359 */
2360 public boolean isReallocated() {
2361 return reallocations > 0;
2362 }
2363
2364 /**
2365 * Searches the string builder to find the last reference to the specified char.
2366 *
2367 * @param ch the character to find.
2368 * @return The last index of the character, or -1 if not found.
2369 */
2370 public int lastIndexOf(final char ch) {
2371 return lastIndexOf(ch, size - 1);
2372 }
2373
2374 /**
2375 * Searches the string builder to find the last reference to the specified char.
2376 *
2377 * @param ch the character to find.
2378 * @param startIndex the index to start at, invalid index rounded to edge.
2379 * @return The last index of the character, or -1 if not found.
2380 */
2381 public int lastIndexOf(final char ch, int startIndex) {
2382 startIndex = startIndex >= size ? size - 1 : startIndex;
2383 if (startIndex < 0) {
2384 return StringUtils.INDEX_NOT_FOUND;
2385 }
2386 for (int i = startIndex; i >= 0; i--) {
2387 if (buffer[i] == ch) {
2388 return i;
2389 }
2390 }
2391 return StringUtils.INDEX_NOT_FOUND;
2392 }
2393
2394 /**
2395 * Searches the string builder to find the last reference to the specified string.
2396 * <p>
2397 * Note that a null input string will return -1, whereas the JDK throws an exception.
2398 * </p>
2399 *
2400 * @param str the string to find, null returns -1.
2401 * @return The last index of the string, or -1 if not found.
2402 */
2403 public int lastIndexOf(final String str) {
2404 return lastIndexOf(str, size - 1);
2405 }
2406
2407 /**
2408 * Searches the string builder to find the last reference to the specified string starting searching from the given
2409 * index.
2410 * <p>
2411 * Note that a null input string will return -1, whereas the JDK throws an exception.
2412 * </p>
2413 *
2414 * @param str the string to find, null returns -1.
2415 * @param startIndex the index to start at, invalid index rounded to edge.
2416 * @return The last index of the string, or -1 if not found.
2417 */
2418 public int lastIndexOf(final String str, int startIndex) {
2419 startIndex = startIndex >= size ? size - 1 : startIndex;
2420 if (str == null || startIndex < 0) {
2421 return StringUtils.INDEX_NOT_FOUND;
2422 }
2423 final int strLen = str.length();
2424 if (strLen == 0) {
2425 return startIndex;
2426 }
2427 if (strLen > size) {
2428 return StringUtils.INDEX_NOT_FOUND;
2429 }
2430 if (strLen == 1) {
2431 return lastIndexOf(str.charAt(0), startIndex);
2432 }
2433 for (int i = startIndex - strLen + 1; i >= 0; i--) {
2434 boolean found = true;
2435 for (int j = 0; j < strLen && found; j++) {
2436 found = str.charAt(j) == buffer[i + j];
2437 }
2438 if (found) {
2439 return i;
2440 }
2441 }
2442 return StringUtils.INDEX_NOT_FOUND;
2443 }
2444
2445 /**
2446 * Searches the string builder using the matcher to find the last match.
2447 * <p>
2448 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2449 * character 'a' followed by a number.
2450 * </p>
2451 *
2452 * @param matcher the matcher to use, null returns -1.
2453 * @return The last index matched, or -1 if not found.
2454 */
2455 public int lastIndexOf(final StringMatcher matcher) {
2456 return lastIndexOf(matcher, size);
2457 }
2458
2459 /**
2460 * Searches the string builder using the matcher to find the last match searching from the given index.
2461 * <p>
2462 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2463 * character 'a' followed by a number.
2464 * </p>
2465 *
2466 * @param matcher the matcher to use, null returns -1.
2467 * @param startIndex the index to start at, invalid index rounded to edge.
2468 * @return The last index matched, or -1 if not found.
2469 */
2470 public int lastIndexOf(final StringMatcher matcher, int startIndex) {
2471 startIndex = startIndex >= size ? size - 1 : startIndex;
2472 if (matcher == null || startIndex < 0) {
2473 return StringUtils.INDEX_NOT_FOUND;
2474 }
2475 final char[] buf = buffer;
2476 final int endIndex = startIndex + 1;
2477 for (int i = startIndex; i >= 0; i--) {
2478 if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2479 return i;
2480 }
2481 }
2482 return StringUtils.INDEX_NOT_FOUND;
2483 }
2484
2485 /**
2486 * Extracts the leftmost characters from the string builder without throwing an exception.
2487 * <p>
2488 * This method extracts the left {@code length} characters from the builder. If this many characters are not
2489 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested.
2490 * </p>
2491 *
2492 * @param length the number of characters to extract, negative returns empty string.
2493 * @return The new string.
2494 */
2495 public String leftString(final int length) {
2496 if (length <= 0) {
2497 return StringUtils.EMPTY;
2498 }
2499 if (length >= size) {
2500 return new String(buffer, 0, size);
2501 }
2502 return new String(buffer, 0, length);
2503 }
2504
2505 /**
2506 * Gets the length of the string builder.
2507 *
2508 * @return The length
2509 */
2510 @Override
2511 public int length() {
2512 return size;
2513 }
2514
2515 /**
2516 * Extracts some characters from the middle of the string builder without throwing an exception.
2517 * <p>
2518 * This method extracts {@code length} characters from the builder at the specified index. If the index is negative
2519 * it is treated as zero. If the index is greater than the builder size, it is treated as the builder size. If the
2520 * length is negative, the empty string is returned. If insufficient characters are available in the builder, as
2521 * much as possible is returned. Thus the returned string may be shorter than the length requested.
2522 * </p>
2523 *
2524 * @param index the index to start at, negative means zero.
2525 * @param length the number of characters to extract, negative returns empty string.
2526 * @return The new string.
2527 */
2528 public String midString(int index, final int length) {
2529 if (index < 0) {
2530 index = 0;
2531 }
2532 if (length <= 0 || index >= size) {
2533 return StringUtils.EMPTY;
2534 }
2535 if (size <= index + length) {
2536 return new String(buffer, index, size - index);
2537 }
2538 return new String(buffer, index, length);
2539 }
2540
2541 /**
2542 * Minimizes the capacity to the actual length of the string.
2543 *
2544 * @return {@code this} instance.
2545 */
2546 public TextStringBuilder minimizeCapacity() {
2547 if (buffer.length > size) {
2548 reallocate(size);
2549 }
2550 return this;
2551 }
2552
2553 /**
2554 * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without
2555 * making extra copies.
2556 *
2557 * @param charBuffer CharBuffer to read.
2558 * @return The number of characters read.
2559 * @see #appendTo(Appendable)
2560 * @since 1.9
2561 */
2562 public int readFrom(final CharBuffer charBuffer) {
2563 final int oldSize = size;
2564 final int remaining = charBuffer.remaining();
2565 ensureCapacityInternal(size + remaining);
2566 charBuffer.get(buffer, size, remaining);
2567 size += remaining;
2568 return size - oldSize;
2569 }
2570
2571 /**
2572 * If possible, reads all chars from the provided {@link Readable} directly into underlying character buffer without
2573 * making extra copies.
2574 *
2575 * @param readable object to read from.
2576 * @return The number of characters read.
2577 * @throws IOException if an I/O error occurs.
2578 * @see #appendTo(Appendable)
2579 */
2580 public int readFrom(final Readable readable) throws IOException {
2581 if (readable instanceof Reader) {
2582 return readFrom((Reader) readable);
2583 }
2584 if (readable instanceof CharBuffer) {
2585 return readFrom((CharBuffer) readable);
2586 }
2587 final int oldSize = size;
2588 while (true) {
2589 ensureCapacityInternal(size + 1);
2590 final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
2591 final int read = readable.read(buf);
2592 if (read == EOS) {
2593 break;
2594 }
2595 size += read;
2596 }
2597 return size - oldSize;
2598 }
2599
2600 /**
2601 * If possible, reads all chars from the provided {@link Reader} directly into underlying character buffer without
2602 * making extra copies.
2603 *
2604 * @param reader Reader to read.
2605 * @return The number of characters read or -1 if we reached the end of stream.
2606 * @throws IOException if an I/O error occurs.
2607 * @see #appendTo(Appendable)
2608 * @since 1.9
2609 */
2610 public int readFrom(final Reader reader) throws IOException {
2611 final int oldSize = size;
2612 ensureCapacityInternal(size + 1);
2613 int readCount = reader.read(buffer, size, buffer.length - size);
2614 if (readCount == EOS) {
2615 return EOS;
2616 }
2617 do {
2618 size += readCount;
2619 ensureCapacityInternal(size + 1);
2620 readCount = reader.read(buffer, size, buffer.length - size);
2621 } while (readCount != EOS);
2622 return size - oldSize;
2623 }
2624
2625 /**
2626 * If possible, reads {@code count} chars from the provided {@link Reader} directly into underlying character buffer without making extra copies.
2627 *
2628 * @param reader Reader to read.
2629 * @param count The maximum characters to read, a value <= 0 returns 0.
2630 * @return The number of characters read. If less than {@code count}, then we've reached the end-of-stream, or -1 if we reached the end of stream.
2631 * @throws IOException if an I/O error occurs.
2632 * @see #appendTo(Appendable)
2633 * @since 1.9
2634 */
2635 public int readFrom(final Reader reader, final int count) throws IOException {
2636 if (count <= 0) {
2637 return 0;
2638 }
2639 final int oldSize = size;
2640 ensureCapacityInternal(size + count);
2641 int target = count;
2642 int readCount = reader.read(buffer, size, target);
2643 if (readCount == EOS) {
2644 return EOS;
2645 }
2646 do {
2647 target -= readCount;
2648 size += readCount;
2649 readCount = reader.read(buffer, size, target);
2650 } while (target > 0 && readCount != EOS);
2651 return size - oldSize;
2652 }
2653
2654 /**
2655 * Reallocates the buffer to the new length.
2656 *
2657 * @param newLength the length of the copy to be returned.
2658 */
2659 private void reallocate(final int newLength) {
2660 this.buffer = Arrays.copyOf(buffer, newLength);
2661 this.reallocations++;
2662 }
2663
2664 /**
2665 * Replaces a portion of the string builder with another string. The length of the inserted string does not have to match the removed length.
2666 *
2667 * @param startIndex the start index, inclusive, must be valid.
2668 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string.
2669 * @param replaceStr the string to replace with, null means delete range.
2670 * @return {@code this} instance.
2671 * @throws IndexOutOfBoundsException if the index is invalid.
2672 */
2673 public TextStringBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
2674 endIndex = validateRange(startIndex, endIndex);
2675 final int insertLen = replaceStr == null ? 0 : replaceStr.length();
2676 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
2677 return this;
2678 }
2679
2680 /**
2681 * Advanced search and replaces within the builder using a matcher.
2682 * <p>
2683 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all occurrences where the character 'a' is followed by
2684 * a number.
2685 * </p>
2686 *
2687 * @param matcher the matcher to use to find the deletion, null causes no action.
2688 * @param replaceStr the string to replace the match with, null is a delete.
2689 * @param startIndex the start index, inclusive, must be valid.
2690 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string.
2691 * @param replaceCount the number of times to replace, -1 for replace all.
2692 * @return {@code this} instance.
2693 * @throws IndexOutOfBoundsException if start index is invalid.
2694 */
2695 public TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex,
2696 int endIndex, final int replaceCount) {
2697 endIndex = validateRange(startIndex, endIndex);
2698 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
2699 }
2700
2701 /**
2702 * Replaces the search character with the replace character throughout the builder.
2703 *
2704 * @param search the search character.
2705 * @param replace the replace character.
2706 * @return {@code this} instance.
2707 */
2708 public TextStringBuilder replaceAll(final char search, final char replace) {
2709 if (search != replace) {
2710 for (int i = 0; i < size; i++) {
2711 if (buffer[i] == search) {
2712 buffer[i] = replace;
2713 }
2714 }
2715 }
2716 return this;
2717 }
2718
2719 /**
2720 * Replaces the search string with the replace string throughout the builder.
2721 *
2722 * @param searchStr the search string, null causes no action to occur.
2723 * @param replaceStr the replace string, null is equivalent to an empty string.
2724 * @return {@code this} instance.
2725 */
2726 public TextStringBuilder replaceAll(final String searchStr, final String replaceStr) {
2727 final int searchLen = searchStr == null ? 0 : searchStr.length();
2728 if (searchLen > 0) {
2729 final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2730 int index = indexOf(searchStr, 0);
2731 while (index >= 0) {
2732 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2733 index = indexOf(searchStr, index + replaceLen);
2734 }
2735 }
2736 return this;
2737 }
2738
2739 /**
2740 * Replaces all matches within the builder with the replace string.
2741 * <p>
2742 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all
2743 * occurrences where the character 'a' is followed by a number.
2744 * </p>
2745 *
2746 * @param matcher the matcher to use to find the deletion, null causes no action.
2747 * @param replaceStr the replace string, null is equivalent to an empty string.
2748 * @return {@code this} instance.
2749 */
2750 public TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) {
2751 return replace(matcher, replaceStr, 0, size, -1);
2752 }
2753
2754 /**
2755 * Replaces the first instance of the search character with the replace character in the builder.
2756 *
2757 * @param search the search character.
2758 * @param replace the replace character.
2759 * @return {@code this} instance.
2760 */
2761 public TextStringBuilder replaceFirst(final char search, final char replace) {
2762 if (search != replace) {
2763 for (int i = 0; i < size; i++) {
2764 if (buffer[i] == search) {
2765 buffer[i] = replace;
2766 break;
2767 }
2768 }
2769 }
2770 return this;
2771 }
2772
2773 /**
2774 * Replaces the first instance of the search string with the replace string.
2775 *
2776 * @param searchStr the search string, null causes no action to occur.
2777 * @param replaceStr the replace string, null is equivalent to an empty string.
2778 * @return {@code this} instance.
2779 */
2780 public TextStringBuilder replaceFirst(final String searchStr, final String replaceStr) {
2781 final int searchLen = searchStr == null ? 0 : searchStr.length();
2782 if (searchLen > 0) {
2783 final int index = indexOf(searchStr, 0);
2784 if (index >= 0) {
2785 final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2786 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2787 }
2788 }
2789 return this;
2790 }
2791
2792 /**
2793 * Replaces the first match within the builder with the replace string.
2794 * <p>
2795 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace where
2796 * the character 'a' is followed by a number.
2797 * </p>
2798 *
2799 * @param matcher the matcher to use to find the deletion, null causes no action.
2800 * @param replaceStr the replace string, null is equivalent to an empty string.
2801 * @return {@code this} instance.
2802 */
2803 public TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) {
2804 return replace(matcher, replaceStr, 0, size, 1);
2805 }
2806
2807 /**
2808 * Internal method to delete a range without validation.
2809 *
2810 * @param startIndex the start index, must be valid.
2811 * @param endIndex the end index (exclusive), must be valid.
2812 * @param removeLen the length to remove (endIndex - startIndex), must be valid.
2813 * @param insertStr the string to replace with, null means delete range.
2814 * @param insertLen the length of the insert string, must be valid.
2815 * @throws IndexOutOfBoundsException if any index is invalid.
2816 */
2817 private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr,
2818 final int insertLen) {
2819 final int newSize = size - removeLen + insertLen;
2820 if (insertLen != removeLen) {
2821 ensureCapacityInternal(newSize);
2822 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
2823 size = newSize;
2824 }
2825 if (insertLen > 0) {
2826 insertStr.getChars(0, insertLen, buffer, startIndex);
2827 }
2828 }
2829
2830 /**
2831 * Replaces within the builder using a matcher.
2832 * <p>
2833 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all
2834 * occurrences where the character 'a' is followed by a number.
2835 * </p>
2836 *
2837 * @param matcher the matcher to use to find the deletion, null causes no action.
2838 * @param replaceStr the string to replace the match with, null is a delete.
2839 * @param from the start index, must be valid.
2840 * @param to the end index (exclusive), must be valid.
2841 * @param replaceCount the number of times to replace, -1 for replace all.
2842 * @return {@code this} instance.
2843 * @throws IndexOutOfBoundsException if any index is invalid.
2844 */
2845 private TextStringBuilder replaceImpl(final StringMatcher matcher, final String replaceStr, final int from, int to,
2846 int replaceCount) {
2847 if (matcher == null || size == 0) {
2848 return this;
2849 }
2850 final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2851 for (int i = from; i < to && replaceCount != 0; i++) {
2852 final char[] buf = buffer;
2853 final int removeLen = matcher.isMatch(buf, i, from, to);
2854 if (removeLen > 0) {
2855 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2856 to = to - removeLen + replaceLen;
2857 i = i + replaceLen - 1;
2858 if (replaceCount > 0) {
2859 replaceCount--;
2860 }
2861 }
2862 }
2863 return this;
2864 }
2865
2866 /**
2867 * Resizes the buffer to at least the size specified.
2868 *
2869 * @param minCapacity the minimum required capacity.
2870 * @throws OutOfMemoryError if the {@code minCapacity} is negative.
2871 */
2872 private void resizeBuffer(final int minCapacity) {
2873 // Overflow-conscious code treats the min and new capacity as unsigned.
2874 final int oldCapacity = buffer.length;
2875 int newCapacity = oldCapacity * 2;
2876 if (Integer.compareUnsigned(newCapacity, minCapacity) < 0) {
2877 newCapacity = minCapacity;
2878 }
2879 if (Integer.compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) {
2880 newCapacity = createPositiveCapacity(minCapacity);
2881 }
2882 reallocate(newCapacity);
2883 }
2884
2885 /**
2886 * Reverses the string builder placing each character in the opposite index.
2887 *
2888 * @return {@code this} instance.
2889 */
2890 public TextStringBuilder reverse() {
2891 if (size == 0) {
2892 return this;
2893 }
2894 final int half = size / 2;
2895 final char[] buf = buffer;
2896 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
2897 final char swap = buf[leftIdx];
2898 buf[leftIdx] = buf[rightIdx];
2899 buf[rightIdx] = swap;
2900 }
2901 return this;
2902 }
2903
2904 /**
2905 * Extracts the rightmost characters from the string builder without throwing an exception.
2906 * <p>
2907 * This method extracts the right {@code length} characters from the builder. If this many characters are not
2908 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested.
2909 * </p>
2910 *
2911 * @param length the number of characters to extract, negative returns empty string.
2912 * @return The new string.
2913 */
2914 public String rightString(final int length) {
2915 if (length <= 0) {
2916 return StringUtils.EMPTY;
2917 }
2918 if (length >= size) {
2919 return new String(buffer, 0, size);
2920 }
2921 return new String(buffer, size - length, length);
2922 }
2923
2924 /**
2925 * Clears and sets this builder to the given value.
2926 *
2927 * @param str the new value.
2928 * @return {@code this} instance.
2929 * @since 1.9
2930 * @see #charAt(int)
2931 * @see #deleteCharAt(int)
2932 */
2933 public TextStringBuilder set(final CharSequence str) {
2934 return clear().append(str);
2935 }
2936
2937 /**
2938 * Sets the character at the specified index.
2939 *
2940 * @param index the index to set
2941 * @param ch the new character
2942 * @return {@code this} instance.
2943 * @throws IndexOutOfBoundsException if the index is invalid
2944 * @see #charAt(int)
2945 * @see #deleteCharAt(int)
2946 */
2947 public TextStringBuilder setCharAt(final int index, final char ch) {
2948 validateIndex(index);
2949 buffer[index] = ch;
2950 return this;
2951 }
2952
2953 /**
2954 * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero.
2955 *
2956 * @param length the length to set to, must be zero or positive.
2957 * @return {@code this} instance.
2958 * @throws IndexOutOfBoundsException if the length is negative.
2959 */
2960 public TextStringBuilder setLength(final int length) {
2961 if (length < 0) {
2962 throw new StringIndexOutOfBoundsException(length);
2963 }
2964 if (length < size) {
2965 size = length;
2966 } else if (length > size) {
2967 ensureCapacityInternal(length);
2968 final int oldEnd = size;
2969 size = length;
2970 Arrays.fill(buffer, oldEnd, length, '\0');
2971 }
2972 return this;
2973 }
2974
2975 /**
2976 * Sets the text to be appended when {@link #appendNewLine() new line} is called.
2977 *
2978 * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
2979 * @return {@code this} instance.
2980 */
2981 public TextStringBuilder setNewLineText(final String newLine) {
2982 this.newLine = newLine;
2983 return this;
2984 }
2985
2986 /**
2987 * Sets the text to be appended when null is added.
2988 *
2989 * @param nullText the null text, null means no append.
2990 * @return {@code this} instance.
2991 */
2992 public TextStringBuilder setNullText(String nullText) {
2993 if (nullText != null && nullText.isEmpty()) {
2994 nullText = null;
2995 }
2996 this.nullText = nullText;
2997 return this;
2998 }
2999
3000 /**
3001 * Gets the length of the string builder.
3002 * <p>
3003 * This method is the same as {@link #length()} and is provided to match the API of Collections.
3004 * </p>
3005 *
3006 * @return The length.
3007 */
3008 public int size() {
3009 return size;
3010 }
3011
3012 /**
3013 * Checks whether this builder starts with the specified string.
3014 * <p>
3015 * Note that this method handles null input quietly, unlike String.
3016 * </p>
3017 *
3018 * @param str the string to search for, null returns false.
3019 * @return true if the builder starts with the string.
3020 */
3021 public boolean startsWith(final String str) {
3022 if (str == null) {
3023 return false;
3024 }
3025 final int len = str.length();
3026 if (len == 0) {
3027 return true;
3028 }
3029 if (len > size) {
3030 return false;
3031 }
3032 for (int i = 0; i < len; i++) {
3033 if (buffer[i] != str.charAt(i)) {
3034 return false;
3035 }
3036 }
3037 return true;
3038 }
3039
3040 /**
3041 * {@inheritDoc}
3042 */
3043 @Override
3044 public CharSequence subSequence(final int startIndex, final int endIndex) {
3045 if (startIndex < 0) {
3046 throw new StringIndexOutOfBoundsException(startIndex);
3047 }
3048 if (endIndex > size) {
3049 throw new StringIndexOutOfBoundsException(endIndex);
3050 }
3051 if (startIndex > endIndex) {
3052 throw new StringIndexOutOfBoundsException(endIndex - startIndex);
3053 }
3054 return substring(startIndex, endIndex);
3055 }
3056
3057 /**
3058 * Extracts a portion of this string builder as a string.
3059 *
3060 * @param start the start index, inclusive, must be valid.
3061 * @return The new string.
3062 * @throws IndexOutOfBoundsException if the index is invalid.
3063 */
3064 public String substring(final int start) {
3065 return substring(start, size);
3066 }
3067
3068 /**
3069 * Extracts a portion of this string builder as a string.
3070 * <p>
3071 * Note: This method treats an endIndex greater than the length of the builder as equal to the length of the
3072 * builder, and continues without error, unlike StringBuffer or String.
3073 * </p>
3074 *
3075 * @param startIndex the start index, inclusive, must be valid.
3076 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string.
3077 * @return The new string.
3078 * @throws IndexOutOfBoundsException if the index is invalid.
3079 */
3080 public String substring(final int startIndex, int endIndex) {
3081 endIndex = validateRange(startIndex, endIndex);
3082 return new String(buffer, startIndex, endIndex - startIndex);
3083 }
3084
3085 /**
3086 * Copies the builder's character array into a new character array.
3087 *
3088 * @return a new array that represents the contents of the builder.
3089 */
3090 public char[] toCharArray() {
3091 return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size);
3092 }
3093
3094 /**
3095 * Copies part of the builder's character array into a new character array.
3096 *
3097 * @param startIndex the start index, inclusive, must be valid.
3098 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string.
3099 * @return a new array that holds part of the contents of the builder.
3100 * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than size is valid).
3101 */
3102 public char[] toCharArray(final int startIndex, int endIndex) {
3103 endIndex = validateRange(startIndex, endIndex);
3104 final int len = endIndex - startIndex;
3105 return len == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOfRange(buffer, startIndex, endIndex);
3106 }
3107
3108 /**
3109 * Gets a String version of the string builder, creating a new instance each time the method is called.
3110 * <p>
3111 * Note that unlike StringBuffer, the string version returned is independent of the string builder.
3112 * </p>
3113 *
3114 * @return The builder as a String.
3115 */
3116 @Override
3117 public String toString() {
3118 return new String(buffer, 0, size);
3119 }
3120
3121 /**
3122 * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called.
3123 *
3124 * @return The builder as a StringBuffer.
3125 */
3126 public StringBuffer toStringBuffer() {
3127 return new StringBuffer(size).append(buffer, 0, size);
3128 }
3129
3130 /**
3131 * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called.
3132 *
3133 * @return The builder as a StringBuilder.
3134 */
3135 public StringBuilder toStringBuilder() {
3136 return new StringBuilder(size).append(buffer, 0, size);
3137 }
3138
3139 /**
3140 * Trims the builder by removing characters less than or equal to a space from the beginning and end.
3141 *
3142 * @return {@code this} instance.
3143 */
3144 public TextStringBuilder trim() {
3145 if (size == 0) {
3146 return this;
3147 }
3148 int len = size;
3149 final char[] buf = buffer;
3150 int pos = 0;
3151 while (pos < len && buf[pos] <= SPACE) {
3152 pos++;
3153 }
3154 while (pos < len && buf[len - 1] <= SPACE) {
3155 len--;
3156 }
3157 if (len < size) {
3158 delete(len, size);
3159 }
3160 if (pos > 0) {
3161 delete(0, pos);
3162 }
3163 return this;
3164 }
3165
3166 /**
3167 * Validates that an index is in the range {@code 0 <= index < size}.
3168 *
3169 * @param index the index to test.
3170 * @throws IndexOutOfBoundsException Thrown when the index is not the range {@code 0 <= index < size}.
3171 */
3172 protected void validateIndex(final int index) {
3173 if (index < 0 || index >= size) {
3174 throw new StringIndexOutOfBoundsException(index);
3175 }
3176 }
3177
3178 /**
3179 * Validates parameters defining a range of the builder.
3180 *
3181 * @param startIndex the start index, inclusive, must be valid.
3182 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string.
3183 * @return A valid end index.
3184 * @throws StringIndexOutOfBoundsException if the index is invalid.
3185 */
3186 protected int validateRange(final int startIndex, int endIndex) {
3187 if (startIndex < 0) {
3188 throw new StringIndexOutOfBoundsException(startIndex);
3189 }
3190 if (endIndex > size) {
3191 endIndex = size;
3192 }
3193 if (startIndex > endIndex) {
3194 throw new StringIndexOutOfBoundsException("end < start");
3195 }
3196 return endIndex;
3197 }
3198
3199 }