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