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 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 >= size()) {
133                 return -1;
134             }
135             if (pos + len > size()) {
136                 len = 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 < 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 > size()) {
159                 n = 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(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     /**
354      * The new line, {@code null} means use the system default from {@link System#lineSeparator()}.
355      */
356     private String newLine;
357 
358     /** The null text. */
359     private String nullText;
360 
361     /** Incremented when the buffer is reallocated. */
362     private int reallocations;
363 
364     /** Current size of the buffer. */
365     private int size;
366 
367     /**
368      * Constructs an empty builder with an initial capacity of 32 characters.
369      */
370     public TextStringBuilder() {
371         this(CAPACITY);
372     }
373 
374     /**
375      * Constructs an instance from a reference to a character array.
376      *
377      * @param initialBuffer a reference to a character array, must not be null.
378      * @param length The length of the subarray to be used; must be non-negative and no larger than
379      *        {@code initialBuffer.length}. The new builder's size will be set to {@code length}.
380      * @throws NullPointerException If {@code initialBuffer} is null.
381      * @throws IllegalArgumentException if {@code length} is bad.
382      */
383     private TextStringBuilder(final char[] initialBuffer, final int length) {
384         this.buffer = Objects.requireNonNull(initialBuffer, "initialBuffer");
385         if (length < 0 || length > initialBuffer.length) {
386             throw new IllegalArgumentException("initialBuffer.length=" + initialBuffer.length + ", length=" + length);
387         }
388         this.size = length;
389     }
390 
391     /**
392      * Constructs an instance from a character sequence, allocating 32 extra characters for growth.
393      *
394      * @param seq the string to copy, null treated as blank string
395      * @since 1.9
396      */
397     public TextStringBuilder(final CharSequence seq) {
398         this(StringUtils.length(seq) + CAPACITY);
399         if (seq != null) {
400             append(seq);
401         }
402     }
403 
404     /**
405      * Constructs an instance with the specified initial capacity.
406      *
407      * @param initialCapacity the initial capacity, zero or less will be converted to 32
408      */
409     public TextStringBuilder(final int initialCapacity) {
410         buffer = new char[initialCapacity <= 0 ? CAPACITY : initialCapacity];
411     }
412 
413     /**
414      * Constructs an instance from a string, allocating 32 extra characters for growth.
415      *
416      * @param str the string to copy, null treated as blank string
417      */
418     public TextStringBuilder(final String str) {
419         this(StringUtils.length(str) + CAPACITY);
420         if (str != null) {
421             append(str);
422         }
423     }
424 
425     /**
426      * Appends a boolean value to the string builder.
427      *
428      * @param value the value to append
429      * @return this, to enable chaining
430      */
431     public TextStringBuilder append(final boolean value) {
432         if (value) {
433             ensureCapacityInternal(size + TRUE_STRING_SIZE);
434             appendTrue(size);
435         } else {
436             ensureCapacityInternal(size + FALSE_STRING_SIZE);
437             appendFalse(size);
438         }
439         return this;
440     }
441 
442     /**
443      * Appends a char value to the string builder.
444      *
445      * @param ch the value to append
446      * @return this, to enable chaining
447      */
448     @Override
449     public TextStringBuilder append(final char ch) {
450         final int len = length();
451         ensureCapacityInternal(len + 1);
452         buffer[size++] = ch;
453         return this;
454     }
455 
456     /**
457      * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
458      *
459      * @param chars the char array to append
460      * @return this, to enable chaining
461      */
462     public TextStringBuilder append(final char[] chars) {
463         if (chars == null) {
464             return appendNull();
465         }
466         final int strLen = chars.length;
467         if (strLen > 0) {
468             final int len = length();
469             ensureCapacityInternal(len + strLen);
470             System.arraycopy(chars, 0, buffer, len, strLen);
471             size += strLen;
472         }
473         return this;
474     }
475 
476     /**
477      * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
478      *
479      * @param chars the char array to append
480      * @param startIndex the start index, inclusive, must be valid
481      * @param length the length to append, must be valid
482      * @return this, to enable chaining
483      * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the
484      *  range {@code 0 <= startIndex <= chars.length}
485      * @throws StringIndexOutOfBoundsException if {@code length < 0}
486      * @throws StringIndexOutOfBoundsException if {@code startIndex + length > chars.length}
487      */
488     public TextStringBuilder append(final char[] chars, final int startIndex, final int length) {
489         if (chars == null) {
490             return appendNull();
491         }
492         if (startIndex < 0 || startIndex > chars.length) {
493             throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
494         }
495         if (length < 0 || startIndex + length > chars.length) {
496             throw new StringIndexOutOfBoundsException("Invalid length: " + length);
497         }
498         if (length > 0) {
499             final int len = length();
500             ensureCapacityInternal(len + length);
501             System.arraycopy(chars, startIndex, buffer, len, length);
502             size += length;
503         }
504         return this;
505     }
506 
507     /**
508      * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
509      *
510      * @param str the char buffer to append
511      * @return this, to enable chaining
512      */
513     public TextStringBuilder append(final CharBuffer str) {
514         return append(str, 0, StringUtils.length(str));
515     }
516 
517     /**
518      * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
519      *
520      * @param buf the char buffer to append
521      * @param startIndex the start index, inclusive, must be valid
522      * @param length the length to append, must be valid
523      * @return this, to enable chaining
524      */
525     public TextStringBuilder append(final CharBuffer buf, final int startIndex, final int length) {
526         if (buf == null) {
527             return appendNull();
528         }
529         if (buf.hasArray()) {
530             final int totalLength = buf.remaining();
531             if (startIndex < 0 || startIndex > totalLength) {
532                 throw new StringIndexOutOfBoundsException("startIndex must be valid");
533             }
534             if (length < 0 || startIndex + length > totalLength) {
535                 throw new StringIndexOutOfBoundsException("length must be valid");
536             }
537             final int len = length();
538             ensureCapacityInternal(len + length);
539             System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length);
540             size += length;
541         } else {
542             append(buf.toString(), startIndex, length);
543         }
544         return this;
545     }
546 
547     /**
548      * Appends a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
549      *
550      * @param seq the CharSequence to append
551      * @return this, to enable chaining
552      */
553     @Override
554     public TextStringBuilder append(final CharSequence seq) {
555         if (seq == null) {
556             return appendNull();
557         }
558         if (seq instanceof TextStringBuilder) {
559             return append((TextStringBuilder) seq);
560         }
561         if (seq instanceof StringBuilder) {
562             return append((StringBuilder) seq);
563         }
564         if (seq instanceof StringBuffer) {
565             return append((StringBuffer) seq);
566         }
567         if (seq instanceof CharBuffer) {
568             return append((CharBuffer) seq);
569         }
570         return append(seq.toString());
571     }
572 
573     /**
574      * Appends part of a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
575      *
576      * @param seq the CharSequence to append
577      * @param startIndex the start index, inclusive, must be valid
578      * @param endIndex the end index, exclusive, must be valid
579      * @return this, to enable chaining
580      */
581     @Override
582     public TextStringBuilder append(final CharSequence seq, final int startIndex, final int endIndex) {
583         if (seq == null) {
584             return appendNull();
585         }
586         if (endIndex <= 0) {
587             throw new StringIndexOutOfBoundsException("endIndex must be valid");
588         }
589         if (startIndex >= endIndex) {
590             throw new StringIndexOutOfBoundsException("endIndex must be greater than startIndex");
591         }
592         return append(seq.toString(), startIndex, endIndex - startIndex);
593     }
594 
595     /**
596      * Appends a double value to the string builder using {@code String.valueOf}.
597      *
598      * @param value the value to append
599      * @return this, to enable chaining
600      */
601     public TextStringBuilder append(final double value) {
602         return append(String.valueOf(value));
603     }
604 
605     /**
606      * Appends a float value to the string builder using {@code String.valueOf}.
607      *
608      * @param value the value to append
609      * @return this, to enable chaining
610      */
611     public TextStringBuilder append(final float value) {
612         return append(String.valueOf(value));
613     }
614 
615     /**
616      * Appends an int value to the string builder using {@code String.valueOf}.
617      *
618      * @param value the value to append
619      * @return this, to enable chaining
620      */
621     public TextStringBuilder append(final int value) {
622         return append(String.valueOf(value));
623     }
624 
625     /**
626      * Appends a long value to the string builder using {@code String.valueOf}.
627      *
628      * @param value the value to append
629      * @return this, to enable chaining
630      */
631     public TextStringBuilder append(final long value) {
632         return append(String.valueOf(value));
633     }
634 
635     /**
636      * Appends an object to this string builder. Appending null will call {@link #appendNull()}.
637      *
638      * @param obj the object to append
639      * @return this, to enable chaining
640      */
641     public TextStringBuilder append(final Object obj) {
642         if (obj == null) {
643             return appendNull();
644         }
645         if (obj instanceof CharSequence) {
646             return append((CharSequence) obj);
647         }
648         return append(obj.toString());
649     }
650 
651     /**
652      * Appends a string to this string builder. Appending null will call {@link #appendNull()}.
653      *
654      * @param str the string to append
655      * @return this, to enable chaining
656      */
657     public TextStringBuilder append(final String str) {
658         return append(str, 0, StringUtils.length(str));
659     }
660 
661     /**
662      * Appends part of a string to this string builder. Appending null will call {@link #appendNull()}.
663      *
664      * @param str the string to append
665      * @param startIndex the start index, inclusive, must be valid
666      * @param length the length to append, must be valid
667      * @return this, to enable chaining
668      * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the
669      *  range {@code 0 <= startIndex <= str.length()}
670      * @throws StringIndexOutOfBoundsException if {@code length < 0}
671      * @throws StringIndexOutOfBoundsException if {@code startIndex + length > str.length()}
672      */
673     public TextStringBuilder append(final String str, final int startIndex, final int length) {
674         if (str == null) {
675             return appendNull();
676         }
677         if (startIndex < 0 || startIndex > str.length()) {
678             throw new StringIndexOutOfBoundsException("startIndex must be valid");
679         }
680         if (length < 0 || startIndex + length > str.length()) {
681             throw new StringIndexOutOfBoundsException("length must be valid");
682         }
683         if (length > 0) {
684             final int len = length();
685             ensureCapacityInternal(len + length);
686             str.getChars(startIndex, startIndex + length, buffer, len);
687             size += length;
688         }
689         return this;
690     }
691 
692     /**
693      * Calls {@link String#format(String, Object...)} and appends the result.
694      *
695      * @param format the format string
696      * @param objs the objects to use in the format string
697      * @return {@code this} to enable chaining
698      * @see String#format(String, Object...)
699      */
700     public TextStringBuilder append(final String format, final Object... objs) {
701         return append(String.format(format, objs));
702     }
703 
704     /**
705      * Appends a string buffer to this string builder. Appending null will call {@link #appendNull()}.
706      *
707      * @param str the string buffer to append
708      * @return this, to enable chaining
709      */
710     public TextStringBuilder append(final StringBuffer str) {
711         return append(str, 0, StringUtils.length(str));
712     }
713 
714     /**
715      * Appends part of a string buffer to this string builder. Appending null will call {@link #appendNull()}.
716      *
717      * @param str the string to append
718      * @param startIndex the start index, inclusive, must be valid
719      * @param length the length to append, must be valid
720      * @return this, to enable chaining
721      */
722     public TextStringBuilder append(final StringBuffer str, final int startIndex, final int length) {
723         if (str == null) {
724             return appendNull();
725         }
726         if (startIndex < 0 || startIndex > str.length()) {
727             throw new StringIndexOutOfBoundsException("startIndex must be valid");
728         }
729         if (length < 0 || startIndex + length > str.length()) {
730             throw new StringIndexOutOfBoundsException("length must be valid");
731         }
732         if (length > 0) {
733             final int len = length();
734             ensureCapacityInternal(len + length);
735             str.getChars(startIndex, startIndex + length, buffer, len);
736             size += length;
737         }
738         return this;
739     }
740 
741     /**
742      * Appends a StringBuilder to this string builder. Appending null will call {@link #appendNull()}.
743      *
744      * @param str the StringBuilder to append
745      * @return this, to enable chaining
746      */
747     public TextStringBuilder append(final StringBuilder str) {
748         return append(str, 0, StringUtils.length(str));
749     }
750 
751     /**
752      * Appends part of a StringBuilder to this string builder. Appending null will call {@link #appendNull()}.
753      *
754      * @param str the StringBuilder to append
755      * @param startIndex the start index, inclusive, must be valid
756      * @param length the length to append, must be valid
757      * @return this, to enable chaining
758      */
759     public TextStringBuilder append(final StringBuilder str, final int startIndex, final int length) {
760         if (str == null) {
761             return appendNull();
762         }
763         if (startIndex < 0 || startIndex > str.length()) {
764             throw new StringIndexOutOfBoundsException("startIndex must be valid");
765         }
766         if (length < 0 || startIndex + length > str.length()) {
767             throw new StringIndexOutOfBoundsException("length must be valid");
768         }
769         if (length > 0) {
770             final int len = length();
771             ensureCapacityInternal(len + length);
772             str.getChars(startIndex, startIndex + length, buffer, len);
773             size += length;
774         }
775         return this;
776     }
777 
778     /**
779      * Appends another string builder to this string builder. Appending null will call {@link #appendNull()}.
780      *
781      * @param str the string builder to append
782      * @return this, to enable chaining
783      */
784     public TextStringBuilder append(final TextStringBuilder str) {
785         return append(str, 0, StringUtils.length(str));
786     }
787 
788     /**
789      * Appends part of a string builder to this string builder. Appending null will call {@link #appendNull()}.
790      *
791      * @param str the string to append
792      * @param startIndex the start index, inclusive, must be valid
793      * @param length the length to append, must be valid
794      * @return this, to enable chaining
795      */
796     public TextStringBuilder append(final TextStringBuilder str, final int startIndex, final int length) {
797         if (str == null) {
798             return appendNull();
799         }
800         if (startIndex < 0 || startIndex > str.length()) {
801             throw new StringIndexOutOfBoundsException("startIndex must be valid");
802         }
803         if (length < 0 || startIndex + length > str.length()) {
804             throw new StringIndexOutOfBoundsException("length must be valid");
805         }
806         if (length > 0) {
807             final int len = length();
808             ensureCapacityInternal(len + length);
809             str.getChars(startIndex, startIndex + length, buffer, len);
810             size += length;
811         }
812         return this;
813     }
814 
815     /**
816      * Appends each item in an iterable to the builder without any separators. Appending a null iterable will have no
817      * effect. Each object is appended using {@link #append(Object)}.
818      *
819      * @param iterable the iterable to append
820      * @return this, to enable chaining
821      */
822     public TextStringBuilder appendAll(final Iterable<?> iterable) {
823         if (iterable != null) {
824             iterable.forEach(this::append);
825         }
826         return this;
827     }
828 
829     /**
830      * Appends each item in an iterator to the builder without any separators. Appending a null iterator will have no
831      * effect. Each object is appended using {@link #append(Object)}.
832      *
833      * @param it the iterator to append
834      * @return this, to enable chaining
835      */
836     public TextStringBuilder appendAll(final Iterator<?> it) {
837         if (it != null) {
838             it.forEachRemaining(this::append);
839         }
840         return this;
841     }
842 
843     /**
844      * Appends each item in an array to the builder without any separators. Appending a null array will have no effect.
845      * Each object is appended using {@link #append(Object)}.
846      *
847      * @param <T> the element type
848      * @param array the array to append
849      * @return this, to enable chaining
850      */
851     public <T> TextStringBuilder appendAll(@SuppressWarnings("unchecked") final T... array) {
852         /*
853          * @SuppressWarnings used to hide warning about vararg usage. We cannot use @SafeVarargs, since this method is
854          * not final. Using @SuppressWarnings is fine, because it isn't inherited by subclasses, so each subclass must
855          * vouch for itself whether its use of 'array' is safe.
856          */
857         if (array != null && array.length > 0) {
858             for (final Object element : array) {
859                 append(element);
860             }
861         }
862         return this;
863     }
864 
865     /** Appends {@code "false"}. */
866     private void appendFalse(int index) {
867         buffer[index++] = 'f';
868         buffer[index++] = 'a';
869         buffer[index++] = 'l';
870         buffer[index++] = 's';
871         buffer[index] = 'e';
872         size += FALSE_STRING_SIZE;
873     }
874 
875     /**
876      * Appends an object to the builder padding on the left to a fixed width. The {@code String.valueOf} of the
877      * {@code int} value is used. If the formatted value is larger than the length, the left hand side is lost.
878      *
879      * @param value the value to append
880      * @param width the fixed field width, zero or negative has no effect
881      * @param padChar the pad character to use
882      * @return this, to enable chaining
883      */
884     public TextStringBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
885         return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
886     }
887 
888     /**
889      * Appends an object to the builder padding on the left to a fixed width. The {@code toString} of the object is
890      * used. If the object is larger than the length, the left hand side is lost. If the object is null, the null text
891      * value is used.
892      *
893      * @param obj the object to append, null uses null text
894      * @param width the fixed field width, zero or negative has no effect
895      * @param padChar the pad character to use
896      * @return this, to enable chaining
897      */
898     public TextStringBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
899         if (width > 0) {
900             ensureCapacityInternal(size + width);
901             String str = Objects.toString(obj, getNullText());
902             if (str == null) {
903                 str = StringUtils.EMPTY;
904             }
905             final int strLen = str.length();
906             if (strLen >= width) {
907                 str.getChars(strLen - width, strLen, buffer, size);
908             } else {
909                 final int padLen = width - strLen;
910                 final int toIndex = size + padLen;
911                 Arrays.fill(buffer, size, toIndex, padChar);
912                 str.getChars(0, strLen, buffer, toIndex);
913             }
914             size += width;
915         }
916         return this;
917     }
918 
919     /**
920      * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the
921      * {@code int} value is used. If the object is larger than the length, the right hand side is lost.
922      *
923      * @param value the value to append
924      * @param width the fixed field width, zero or negative has no effect
925      * @param padChar the pad character to use
926      * @return this, to enable chaining
927      */
928     public TextStringBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
929         return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
930     }
931 
932     /**
933      * Appends an object to the builder padding on the right to a fixed length. The {@code toString} of the object is
934      * used. If the object is larger than the length, the right hand side is lost. If the object is null, null text
935      * value is used.
936      *
937      * @param obj the object to append, null uses null text
938      * @param width the fixed field width, zero or negative has no effect
939      * @param padChar the pad character to use
940      * @return this, to enable chaining
941      */
942     public TextStringBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
943         if (width > 0) {
944             ensureCapacityInternal(size + width);
945             String str = Objects.toString(obj, getNullText());
946             if (str == null) {
947                 str = StringUtils.EMPTY;
948             }
949             final int strLen = str.length();
950             if (strLen >= width) {
951                 str.getChars(0, width, buffer, size);
952             } else {
953                 str.getChars(0, strLen, buffer, size);
954                 final int fromIndex = size + strLen;
955                 Arrays.fill(buffer, fromIndex, fromIndex + width - strLen, padChar);
956             }
957             size += width;
958         }
959         return this;
960     }
961 
962     /**
963      * Appends a boolean value followed by a new line to the string builder.
964      *
965      * @param value the value to append
966      * @return this, to enable chaining
967      */
968     public TextStringBuilder appendln(final boolean value) {
969         return append(value).appendNewLine();
970     }
971 
972     /**
973      * Appends a char value followed by a new line to the string builder.
974      *
975      * @param ch the value to append
976      * @return this, to enable chaining
977      */
978     public TextStringBuilder appendln(final char ch) {
979         return append(ch).appendNewLine();
980     }
981 
982     /**
983      * Appends a char array followed by a new line to the string builder. Appending null will call
984      * {@link #appendNull()}.
985      *
986      * @param chars the char array to append
987      * @return this, to enable chaining
988      */
989     public TextStringBuilder appendln(final char[] chars) {
990         return append(chars).appendNewLine();
991     }
992 
993     /**
994      * Appends a char array followed by a new line to the string builder. Appending null will call
995      * {@link #appendNull()}.
996      *
997      * @param chars the char array to append
998      * @param startIndex the start index, inclusive, must be valid
999      * @param length the length to append, must be valid
1000      * @return this, to enable chaining
1001      */
1002     public TextStringBuilder appendln(final char[] chars, final int startIndex, final int length) {
1003         return append(chars, startIndex, length).appendNewLine();
1004     }
1005 
1006     /**
1007      * Appends a double value followed by a new line to the string builder using {@code String.valueOf}.
1008      *
1009      * @param value the value to append
1010      * @return this, to enable chaining
1011      */
1012     public TextStringBuilder appendln(final double value) {
1013         return append(value).appendNewLine();
1014     }
1015 
1016     /**
1017      * Appends a float value followed by a new line to the string builder using {@code String.valueOf}.
1018      *
1019      * @param value the value to append
1020      * @return this, to enable chaining
1021      */
1022     public TextStringBuilder appendln(final float value) {
1023         return append(value).appendNewLine();
1024     }
1025 
1026     /**
1027      * Appends an int value followed by a new line to the string builder using {@code String.valueOf}.
1028      *
1029      * @param value the value to append
1030      * @return this, to enable chaining
1031      */
1032     public TextStringBuilder appendln(final int value) {
1033         return append(value).appendNewLine();
1034     }
1035 
1036     /**
1037      * Appends a long value followed by a new line to the string builder using {@code String.valueOf}.
1038      *
1039      * @param value the value to append
1040      * @return this, to enable chaining
1041      */
1042     public TextStringBuilder appendln(final long value) {
1043         return append(value).appendNewLine();
1044     }
1045 
1046     /**
1047      * Appends an object followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
1048      *
1049      * @param obj the object to append
1050      * @return this, to enable chaining
1051      */
1052     public TextStringBuilder appendln(final Object obj) {
1053         return append(obj).appendNewLine();
1054     }
1055 
1056     /**
1057      * Appends a string followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
1058      *
1059      * @param str the string to append
1060      * @return this, to enable chaining
1061      */
1062     public TextStringBuilder appendln(final String str) {
1063         return append(str).appendNewLine();
1064     }
1065 
1066     /**
1067      * Appends part of a string followed by a new line to this string builder. Appending null will call
1068      * {@link #appendNull()}.
1069      *
1070      * @param str the string to append
1071      * @param startIndex the start index, inclusive, must be valid
1072      * @param length the length to append, must be valid
1073      * @return this, to enable chaining
1074      */
1075     public TextStringBuilder appendln(final String str, final int startIndex, final int length) {
1076         return append(str, startIndex, length).appendNewLine();
1077     }
1078 
1079     /**
1080      * Calls {@link String#format(String, Object...)} and appends the result.
1081      *
1082      * @param format the format string
1083      * @param objs the objects to use in the format string
1084      * @return {@code this} to enable chaining
1085      * @see String#format(String, Object...)
1086      */
1087     public TextStringBuilder appendln(final String format, final Object... objs) {
1088         return append(format, objs).appendNewLine();
1089     }
1090 
1091     /**
1092      * Appends a string buffer followed by a new line to this string builder. Appending null will call
1093      * {@link #appendNull()}.
1094      *
1095      * @param str the string buffer to append
1096      * @return this, to enable chaining
1097      */
1098     public TextStringBuilder appendln(final StringBuffer str) {
1099         return append(str).appendNewLine();
1100     }
1101 
1102     /**
1103      * Appends part of a string buffer followed by a new line to this string builder. Appending null will call
1104      * {@link #appendNull()}.
1105      *
1106      * @param str the string to append
1107      * @param startIndex the start index, inclusive, must be valid
1108      * @param length the length to append, must be valid
1109      * @return this, to enable chaining
1110      */
1111     public TextStringBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
1112         return append(str, startIndex, length).appendNewLine();
1113     }
1114 
1115     /**
1116      * Appends a string builder followed by a new line to this string builder. Appending null will call
1117      * {@link #appendNull()}.
1118      *
1119      * @param str the string builder to append
1120      * @return this, to enable chaining
1121      */
1122     public TextStringBuilder appendln(final StringBuilder str) {
1123         return append(str).appendNewLine();
1124     }
1125 
1126     /**
1127      * Appends part of a string builder followed by a new line to this string builder. Appending null will call
1128      * {@link #appendNull()}.
1129      *
1130      * @param str the string builder to append
1131      * @param startIndex the start index, inclusive, must be valid
1132      * @param length the length to append, must be valid
1133      * @return this, to enable chaining
1134      */
1135     public TextStringBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
1136         return append(str, startIndex, length).appendNewLine();
1137     }
1138 
1139     /**
1140      * Appends another string builder followed by a new line to this string builder. Appending null will call
1141      * {@link #appendNull()}.
1142      *
1143      * @param str the string builder to append
1144      * @return this, to enable chaining
1145      */
1146     public TextStringBuilder appendln(final TextStringBuilder str) {
1147         return append(str).appendNewLine();
1148     }
1149 
1150     /**
1151      * Appends part of a string builder followed by a new line to this string builder. Appending null will call
1152      * {@link #appendNull()}.
1153      *
1154      * @param str the string to append
1155      * @param startIndex the start index, inclusive, must be valid
1156      * @param length the length to append, must be valid
1157      * @return this, to enable chaining
1158      */
1159     public TextStringBuilder appendln(final TextStringBuilder str, final int startIndex, final int length) {
1160         return append(str, startIndex, length).appendNewLine();
1161     }
1162 
1163     /**
1164      * Appends this builder's new line string to this builder.
1165      * <p>
1166      * By default, the new line is the system default from {@link System#lineSeparator()}.
1167      * </p>
1168      * <p>
1169      * The new line string can be changed using {@link #setNewLineText(String)}. For example, you can use this to force the output to always use Unix line
1170      * endings even when on Windows.
1171      * </p>
1172      *
1173      * @return this
1174      * @see #getNewLineText()
1175      * @see #setNewLineText(String)
1176      */
1177     public TextStringBuilder appendNewLine() {
1178         if (newLine == null) {
1179             append(System.lineSeparator());
1180             return this;
1181         }
1182         return append(newLine);
1183     }
1184 
1185     /**
1186      * Appends the text representing {@code null} to this string builder.
1187      *
1188      * @return this, to enable chaining
1189      */
1190     public TextStringBuilder appendNull() {
1191         if (nullText == null) {
1192             return this;
1193         }
1194         return append(nullText);
1195     }
1196 
1197     /**
1198      * Appends the pad character to the builder the specified number of times.
1199      *
1200      * @param length the length to append, negative means no append
1201      * @param padChar the character to append
1202      * @return this, to enable chaining
1203      */
1204     public TextStringBuilder appendPadding(final int length, final char padChar) {
1205         if (length >= 0) {
1206             ensureCapacityInternal(size + length);
1207             for (int i = 0; i < length; i++) {
1208                 buffer[size++] = padChar;
1209             }
1210         }
1211         return this;
1212     }
1213 
1214     /**
1215      * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}.
1216      * <p>
1217      * This method is useful for adding a separator each time around the loop except the first.
1218      * </p>
1219      *
1220      * <pre>
1221      * for (Iterator it = list.iterator(); it.hasNext();) {
1222      *     appendSeparator(',');
1223      *     append(it.next());
1224      * }
1225      * </pre>
1226      *
1227      * <p>
1228      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1229      * </p>
1230      *
1231      * @param separator the separator to use
1232      * @return this, to enable chaining
1233      */
1234     public TextStringBuilder appendSeparator(final char separator) {
1235         if (isNotEmpty()) {
1236             append(separator);
1237         }
1238         return this;
1239     }
1240 
1241     /**
1242      * Appends one of both separators to the builder If the builder is currently empty it will append the
1243      * defaultIfEmpty-separator Otherwise it will append the standard-separator
1244      *
1245      * The separator is appended using {@link #append(char)}.
1246      *
1247      * @param standard the separator if builder is not empty
1248      * @param defaultIfEmpty the separator if builder is empty
1249      * @return this, to enable chaining
1250      */
1251     public TextStringBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
1252         if (isEmpty()) {
1253             append(defaultIfEmpty);
1254         } else {
1255             append(standard);
1256         }
1257         return this;
1258     }
1259 
1260     /**
1261      * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using
1262      * {@link #append(char)}.
1263      * <p>
1264      * This method is useful for adding a separator each time around the loop except the first.
1265      * </p>
1266      *
1267      * <pre>
1268      * for (int i = 0; i &lt; list.size(); i++) {
1269      *     appendSeparator(",", i);
1270      *     append(list.get(i));
1271      * }
1272      * </pre>
1273      *
1274      * <p>
1275      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1276      * </p>
1277      *
1278      * @param separator the separator to use
1279      * @param loopIndex the loop index
1280      * @return this, to enable chaining
1281      */
1282     public TextStringBuilder appendSeparator(final char separator, final int loopIndex) {
1283         if (loopIndex > 0) {
1284             append(separator);
1285         }
1286         return this;
1287     }
1288 
1289     /**
1290      * Appends a separator if the builder is currently non-empty. Appending a null separator will have no effect. The
1291      * separator is appended using {@link #append(String)}.
1292      * <p>
1293      * This method is useful for adding a separator each time around the loop except the first.
1294      * </p>
1295      *
1296      * <pre>
1297      * for (Iterator it = list.iterator(); it.hasNext();) {
1298      *     appendSeparator(",");
1299      *     append(it.next());
1300      * }
1301      * </pre>
1302      *
1303      * <p>
1304      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1305      * </p>
1306      *
1307      * @param separator the separator to use, null means no separator
1308      * @return this, to enable chaining
1309      */
1310     public TextStringBuilder appendSeparator(final String separator) {
1311         return appendSeparator(separator, null);
1312     }
1313 
1314     /**
1315      * Appends a separator to the builder if the loop index is greater than zero. Appending a null separator will have
1316      * no effect. The separator is appended using {@link #append(String)}.
1317      * <p>
1318      * This method is useful for adding a separator each time around the loop except the first.
1319      * </p>
1320      *
1321      * <pre>
1322      * for (int i = 0; i &lt; list.size(); i++) {
1323      *     appendSeparator(",", i);
1324      *     append(list.get(i));
1325      * }
1326      * </pre>
1327      *
1328      * <p>
1329      * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1330      * </p>
1331      *
1332      * @param separator the separator to use, null means no separator
1333      * @param loopIndex the loop index
1334      * @return this, to enable chaining
1335      */
1336     public TextStringBuilder appendSeparator(final String separator, final int loopIndex) {
1337         if (separator != null && loopIndex > 0) {
1338             append(separator);
1339         }
1340         return this;
1341     }
1342 
1343     /**
1344      * Appends one of both separators to the StrBuilder. If the builder is currently empty, it will append the
1345      * defaultIfEmpty-separator, otherwise it will append the standard-separator.
1346      * <p>
1347      * Appending a null separator will have no effect. The separator is appended using {@link #append(String)}.
1348      * </p>
1349      * <p>
1350      * This method is for example useful for constructing queries
1351      * </p>
1352      *
1353      * <pre>
1354      * StrBuilder whereClause = new StrBuilder();
1355      * if (searchCommand.getPriority() != null) {
1356      *  whereClause.appendSeparator(" and", " where");
1357      *  whereClause.append(" priority = ?")
1358      * }
1359      * if (searchCommand.getComponent() != null) {
1360      *  whereClause.appendSeparator(" and", " where");
1361      *  whereClause.append(" component = ?")
1362      * }
1363      * selectClause.append(whereClause)
1364      * </pre>
1365      *
1366      * @param standard the separator if builder is not empty, null means no separator
1367      * @param defaultIfEmpty the separator if builder is empty, null means no separator
1368      * @return this, to enable chaining
1369      */
1370     public TextStringBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
1371         final String str = isEmpty() ? defaultIfEmpty : standard;
1372         if (str != null) {
1373             append(str);
1374         }
1375         return this;
1376     }
1377 
1378     /**
1379      * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}.
1380      * <p>
1381      * This method tries to avoid doing any extra copies of contents.
1382      * </p>
1383      *
1384      * @param appendable the appendable to append data to
1385      * @throws IOException if an I/O error occurs.
1386      * @see #readFrom(Readable)
1387      */
1388     public void appendTo(final Appendable appendable) throws IOException {
1389         if (appendable instanceof Writer) {
1390             ((Writer) appendable).write(buffer, 0, size);
1391         } else if (appendable instanceof StringBuilder) {
1392             ((StringBuilder) appendable).append(buffer, 0, size);
1393         } else if (appendable instanceof StringBuffer) {
1394             ((StringBuffer) appendable).append(buffer, 0, size);
1395         } else if (appendable instanceof CharBuffer) {
1396             ((CharBuffer) appendable).put(buffer, 0, size);
1397         } else {
1398             appendable.append(this);
1399         }
1400     }
1401 
1402     /** Appends {@code "true"}. */
1403     private void appendTrue(int index) {
1404         buffer[index++] = 't';
1405         buffer[index++] = 'r';
1406         buffer[index++] = 'u';
1407         buffer[index] = 'e';
1408         size += TRUE_STRING_SIZE;
1409     }
1410 
1411     /**
1412      * Appends an iterable placing separators between each value, but not before the first or after the last. Appending
1413      * a null iterable will have no effect. Each object is appended using {@link #append(Object)}.
1414      *
1415      * @param iterable the iterable to append
1416      * @param separator the separator to use, null means no separator
1417      * @return this, to enable chaining
1418      */
1419     public TextStringBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
1420         if (iterable != null) {
1421             appendWithSeparators(iterable.iterator(), separator);
1422         }
1423         return this;
1424     }
1425 
1426     /**
1427      * Appends an iterator placing separators between each value, but not before the first or after the last. Appending
1428      * a null iterator will have no effect. Each object is appended using {@link #append(Object)}.
1429      *
1430      * @param it the iterator to append
1431      * @param separator the separator to use, null means no separator
1432      * @return this, to enable chaining
1433      */
1434     public TextStringBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
1435         if (it != null) {
1436             final String sep = Objects.toString(separator, StringUtils.EMPTY);
1437             while (it.hasNext()) {
1438                 append(it.next());
1439                 if (it.hasNext()) {
1440                     append(sep);
1441                 }
1442             }
1443         }
1444         return this;
1445     }
1446 
1447     /**
1448      * Appends an array placing separators between each value, but not before the first or after the last. Appending a
1449      * null array will have no effect. Each object is appended using {@link #append(Object)}.
1450      *
1451      * @param array the array to append
1452      * @param separator the separator to use, null means no separator
1453      * @return this, to enable chaining
1454      */
1455     public TextStringBuilder appendWithSeparators(final Object[] array, final String separator) {
1456         if (array != null && array.length > 0) {
1457             final String sep = Objects.toString(separator, StringUtils.EMPTY);
1458             append(array[0]);
1459             for (int i = 1; i < array.length; i++) {
1460                 append(sep);
1461                 append(array[i]);
1462             }
1463         }
1464         return this;
1465     }
1466 
1467     /**
1468      * Gets the contents of this builder as a Reader.
1469      * <p>
1470      * This method allows the contents of the builder to be read using any standard method that expects a Reader.
1471      * </p>
1472      * <p>
1473      * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read away.
1474      * </p>
1475      * <p>
1476      * The internal character array is shared between the builder and the reader. This allows you to append to the
1477      * builder after creating the reader, and the changes will be picked up. Note however, that no synchronization
1478      * occurs, so you must perform all operations with the builder and the reader in one thread.
1479      * </p>
1480      * <p>
1481      * The returned reader supports marking, and ignores the flush method.
1482      * </p>
1483      *
1484      * @return a reader that reads from this builder
1485      */
1486     public Reader asReader() {
1487         return new TextStringBuilderReader();
1488     }
1489 
1490     /**
1491      * Creates a tokenizer that can tokenize the contents of this builder.
1492      * <p>
1493      * This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to
1494      * tokenize on space, tab, newline and form feed (as per StringTokenizer). These values can be changed on the
1495      * tokenizer class, before retrieving the tokens.
1496      * </p>
1497      * <p>
1498      * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within
1499      * certain limits, however there is no synchronization. Once the tokenizer has been used once, it must be
1500      * {@link StringTokenizer#reset() reset} to pickup the latest changes in the builder. For example:
1501      * </p>
1502      *
1503      * <pre>
1504      * StrBuilder b = new StrBuilder();
1505      * b.append("a b ");
1506      * StrTokenizer t = b.asTokenizer();
1507      * String[] tokens1 = t.getTokenArray(); // returns a,b
1508      * b.append("c d ");
1509      * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
1510      * t.reset(); // reset causes builder changes to be picked up
1511      * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
1512      * </pre>
1513      *
1514      * <p>
1515      * In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to
1516      * alter how it tokenizes. Just remember to call reset when you want to pickup builder changes.
1517      * </p>
1518      * <p>
1519      * Calling {@link StringTokenizer#reset(String)} or {@link StringTokenizer#reset(char[])} with a non-null value will
1520      * break the link with the builder.
1521      * </p>
1522      *
1523      * @return a tokenizer that is linked to this builder
1524      */
1525     public StringTokenizer asTokenizer() {
1526         return new TextStringBuilderTokenizer();
1527     }
1528 
1529     /**
1530      * Gets this builder as a Writer that can be written to.
1531      * <p>
1532      * This method allows you to populate the contents of the builder using any standard method that takes a Writer.
1533      * </p>
1534      * <p>
1535      * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is available at
1536      * any time using the methods of the {@code StrBuilder}.
1537      * </p>
1538      * <p>
1539      * The internal character array is shared between the builder and the writer. This allows you to intermix calls that
1540      * append to the builder and write using the writer and the changes will be occur correctly. Note however, that no
1541      * synchronization occurs, so you must perform all operations with the builder and the writer in one thread.
1542      * </p>
1543      * <p>
1544      * The returned writer ignores the close and flush methods.
1545      * </p>
1546      *
1547      * @return a writer that populates this builder
1548      */
1549     public Writer asWriter() {
1550         return new TextStringBuilderWriter();
1551     }
1552 
1553     /**
1554      * Converts this instance to a String.
1555      *
1556      * @return This instance as a String
1557      * @see #toString()
1558      * @deprecated Use {@link #get()}.
1559      */
1560     @Deprecated
1561     @Override
1562     public String build() {
1563         return toString();
1564     }
1565 
1566     /**
1567      * Gets the current size of the internal character array buffer.
1568      *
1569      * @return The capacity
1570      */
1571     public int capacity() {
1572         return buffer.length;
1573     }
1574 
1575     /**
1576      * Gets the character at the specified index.
1577      *
1578      * @see #setCharAt(int, char)
1579      * @see #deleteCharAt(int)
1580      * @param index the index to retrieve, must be valid
1581      * @return The character at the index
1582      * @throws IndexOutOfBoundsException if the index is invalid
1583      */
1584     @Override
1585     public char charAt(final int index) {
1586         validateIndex(index);
1587         return buffer[index];
1588     }
1589 
1590     /**
1591      * Clears the string builder (convenience Collections API style method).
1592      * <p>
1593      * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed
1594      * by {@link #minimizeCapacity()}.
1595      * </p>
1596      * <p>
1597      * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of
1598      * Collections.
1599      * </p>
1600      *
1601      * @return this, to enable chaining
1602      */
1603     public TextStringBuilder clear() {
1604         size = 0;
1605         return this;
1606     }
1607 
1608     /**
1609      * Tests if the string builder contains the specified char.
1610      *
1611      * @param ch the character to find
1612      * @return true if the builder contains the character
1613      */
1614     public boolean contains(final char ch) {
1615         final char[] thisBuf = buffer;
1616         for (int i = 0; i < this.size; i++) {
1617             if (thisBuf[i] == ch) {
1618                 return true;
1619             }
1620         }
1621         return false;
1622     }
1623 
1624     /**
1625      * Tests if the string builder contains the specified string.
1626      *
1627      * @param str the string to find
1628      * @return true if the builder contains the string
1629      */
1630     public boolean contains(final String str) {
1631         return indexOf(str, 0) >= 0;
1632     }
1633 
1634     /**
1635      * Tests if the string builder contains a string matched using the specified matcher.
1636      * <p>
1637      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for
1638      * the character 'a' followed by a number.
1639      * </p>
1640      *
1641      * @param matcher the matcher to use, null returns -1
1642      * @return true if the matcher finds a match in the builder
1643      */
1644     public boolean contains(final StringMatcher matcher) {
1645         return indexOf(matcher, 0) >= 0;
1646     }
1647 
1648     /**
1649      * Deletes the characters between the two specified indices.
1650      *
1651      * @param startIndex the start index, inclusive, must be valid
1652      * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string
1653      * @return this, to enable chaining
1654      * @throws IndexOutOfBoundsException if the index is invalid
1655      */
1656     public TextStringBuilder delete(final int startIndex, final int endIndex) {
1657         final int actualEndIndex = validateRange(startIndex, endIndex);
1658         final int len = actualEndIndex - startIndex;
1659         if (len > 0) {
1660             deleteImpl(startIndex, actualEndIndex, len);
1661         }
1662         return this;
1663     }
1664 
1665     /**
1666      * Deletes the character wherever it occurs in the builder.
1667      *
1668      * @param ch the character to delete
1669      * @return this, to enable chaining
1670      */
1671     public TextStringBuilder deleteAll(final char ch) {
1672         for (int i = 0; i < size; i++) {
1673             if (buffer[i] == ch) {
1674                 final int start = i;
1675                 while (++i < size) {
1676                     if (buffer[i] != ch) {
1677                         break;
1678                     }
1679                 }
1680                 final int len = i - start;
1681                 deleteImpl(start, i, len);
1682                 i -= len;
1683             }
1684         }
1685         return this;
1686     }
1687 
1688     /**
1689      * Deletes the string wherever it occurs in the builder.
1690      *
1691      * @param str the string to delete, null causes no action
1692      * @return this, to enable chaining
1693      */
1694     public TextStringBuilder deleteAll(final String str) {
1695         final int len = str == null ? 0 : str.length();
1696         if (len > 0) {
1697             int index = indexOf(str, 0);
1698             while (index >= 0) {
1699                 deleteImpl(index, index + len, len);
1700                 index = indexOf(str, index);
1701             }
1702         }
1703         return this;
1704     }
1705 
1706     /**
1707      * Deletes all parts of the builder that the matcher matches.
1708      * <p>
1709      * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all
1710      * occurrences where the character 'a' is followed by a number.
1711      * </p>
1712      *
1713      * @param matcher the matcher to use to find the deletion, null causes no action
1714      * @return this, to enable chaining
1715      */
1716     public TextStringBuilder deleteAll(final StringMatcher matcher) {
1717         return replace(matcher, null, 0, size, -1);
1718     }
1719 
1720     /**
1721      * Deletes the character at the specified index.
1722      *
1723      * @see #charAt(int)
1724      * @see #setCharAt(int, char)
1725      * @param index the index to delete
1726      * @return this, to enable chaining
1727      * @throws IndexOutOfBoundsException if the index is invalid
1728      */
1729     public TextStringBuilder deleteCharAt(final int index) {
1730         validateIndex(index);
1731         deleteImpl(index, index + 1, 1);
1732         return this;
1733     }
1734 
1735     /**
1736      * Deletes the character wherever it occurs in the builder.
1737      *
1738      * @param ch the character to delete
1739      * @return this, to enable chaining
1740      */
1741     public TextStringBuilder deleteFirst(final char ch) {
1742         for (int i = 0; i < size; i++) {
1743             if (buffer[i] == ch) {
1744                 deleteImpl(i, i + 1, 1);
1745                 break;
1746             }
1747         }
1748         return this;
1749     }
1750 
1751     /**
1752      * Deletes the string wherever it occurs in the builder.
1753      *
1754      * @param str the string to delete, null causes no action
1755      * @return this, to enable chaining
1756      */
1757     public TextStringBuilder deleteFirst(final String str) {
1758         final int len = str == null ? 0 : str.length();
1759         if (len > 0) {
1760             final int index = indexOf(str, 0);
1761             if (index >= 0) {
1762                 deleteImpl(index, index + len, len);
1763             }
1764         }
1765         return this;
1766     }
1767 
1768     /**
1769      * Deletes the first match within the builder using the specified matcher.
1770      * <p>
1771      * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete where
1772      * the character 'a' is followed by a number.
1773      * </p>
1774      *
1775      * @param matcher the matcher to use to find the deletion, null causes no action
1776      * @return this, to enable chaining
1777      */
1778     public TextStringBuilder deleteFirst(final StringMatcher matcher) {
1779         return replace(matcher, null, 0, size, 1);
1780     }
1781 
1782     /**
1783      * Internal method to delete a range without validation.
1784      *
1785      * @param startIndex the start index, must be valid
1786      * @param endIndex the end index (exclusive), must be valid
1787      * @param len the length, must be valid
1788      * @throws IndexOutOfBoundsException if any index is invalid
1789      */
1790     private void deleteImpl(final int startIndex, final int endIndex, final int len) {
1791         System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1792         size -= len;
1793     }
1794 
1795     /**
1796      * Gets the character at the specified index before deleting it.
1797      *
1798      * @see #charAt(int)
1799      * @see #deleteCharAt(int)
1800      * @param index the index to retrieve, must be valid
1801      * @return The character at the index
1802      * @throws IndexOutOfBoundsException if the index is invalid
1803      * @since 1.9
1804      */
1805     public char drainChar(final int index) {
1806         validateIndex(index);
1807         final char c = buffer[index];
1808         deleteCharAt(index);
1809         return c;
1810     }
1811 
1812     /**
1813      * Drains (copies, then deletes) this character sequence into the specified array. This is equivalent to copying the
1814      * characters from this sequence into the target and then deleting those character from this sequence.
1815      *
1816      * @param startIndex first index to copy, inclusive.
1817      * @param endIndex last index to copy, exclusive.
1818      * @param target the target array, must not be {@code null}.
1819      * @param targetIndex the index to start copying in the target.
1820      * @return How many characters where copied (then deleted). If this builder is empty, return {@code 0}.
1821      * @since 1.9
1822      */
1823     public int drainChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) {
1824         final int length = endIndex - startIndex;
1825         if (isEmpty() || length == 0 || target.length == 0) {
1826             return 0;
1827         }
1828         final int actualLen = Math.min(Math.min(size, length), target.length - targetIndex);
1829         getChars(startIndex, actualLen, target, targetIndex);
1830         delete(startIndex, actualLen);
1831         return actualLen;
1832     }
1833 
1834     /**
1835      * Checks whether this builder ends with the specified string.
1836      * <p>
1837      * Note that this method handles null input quietly, unlike String.
1838      * </p>
1839      *
1840      * @param str the string to search for, null returns false
1841      * @return true if the builder ends with the string
1842      */
1843     public boolean endsWith(final String str) {
1844         if (str == null) {
1845             return false;
1846         }
1847         final int len = str.length();
1848         if (len == 0) {
1849             return true;
1850         }
1851         if (len > size) {
1852             return false;
1853         }
1854         int pos = size - len;
1855         for (int i = 0; i < len; i++, pos++) {
1856             if (buffer[pos] != str.charAt(i)) {
1857                 return false;
1858             }
1859         }
1860         return true;
1861     }
1862 
1863     /**
1864      * Tests the capacity and ensures that it is at least the size specified.
1865      *
1866      * <p>
1867      * Note: This method can be used to minimise memory reallocations during
1868      * repeated addition of values by pre-allocating the character buffer.
1869      * The method ignores a negative {@code capacity} argument.
1870      * </p>
1871      *
1872      * @param capacity the capacity to ensure
1873      * @return this, to enable chaining
1874      * @throws OutOfMemoryError if the capacity cannot be allocated
1875      */
1876     public TextStringBuilder ensureCapacity(final int capacity) {
1877         if (capacity > 0) {
1878             ensureCapacityInternal(capacity);
1879         }
1880         return this;
1881     }
1882 
1883     /**
1884      * Ensures that the buffer is at least the size specified. The {@code capacity} argument
1885      * is treated as an unsigned integer.
1886      *
1887      * <p>
1888      * This method will raise an {@link OutOfMemoryError} if the capacity is too large
1889      * for an array, or cannot be allocated.
1890      * </p>
1891      *
1892      * @param capacity the capacity to ensure
1893      * @throws OutOfMemoryError if the capacity cannot be allocated
1894      */
1895     private void ensureCapacityInternal(final int capacity) {
1896         // Check for overflow of the current buffer.
1897         // Assumes capacity is an unsigned integer up to Integer.MAX_VALUE * 2
1898         // (the largest possible addition of two maximum length arrays).
1899         if (capacity - buffer.length > 0) {
1900             resizeBuffer(capacity);
1901         }
1902     }
1903 
1904     /**
1905      * Tests the contents of this builder against another to see if they contain the same character content.
1906      *
1907      * @param obj the object to check, null returns false
1908      * @return true if the builders contain the same characters in the same order
1909      */
1910     @Override
1911     public boolean equals(final Object obj) {
1912         return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj);
1913     }
1914 
1915     /**
1916      * Tests the contents of this builder against another to see if they contain the same character content.
1917      *
1918      * @param other the object to check, null returns false
1919      * @return true if the builders contain the same characters in the same order
1920      */
1921     public boolean equals(final TextStringBuilder other) {
1922         if (this == other) {
1923             return true;
1924         }
1925         if (other == null) {
1926             return false;
1927         }
1928         if (this.size != other.size) {
1929             return false;
1930         }
1931         // Be aware not to use Arrays.equals(buffer, other.buffer) for equals() method
1932         // as length of the buffers may be different (TEXT-211)
1933         final char[] thisBuf = this.buffer;
1934         final char[] otherBuf = other.buffer;
1935         for (int i = size - 1; i >= 0; i--) {
1936             if (thisBuf[i] != otherBuf[i]) {
1937                 return false;
1938             }
1939         }
1940         return true;
1941     }
1942 
1943     /**
1944      * Tests the contents of this builder against another to see if they contain the same character content ignoring
1945      * case.
1946      *
1947      * @param other the object to check, null returns false
1948      * @return true if the builders contain the same characters in the same order
1949      */
1950     public boolean equalsIgnoreCase(final TextStringBuilder other) {
1951         if (this == other) {
1952             return true;
1953         }
1954         if (this.size != other.size) {
1955             return false;
1956         }
1957         final char[] thisBuf = this.buffer;
1958         final char[] otherBuf = other.buffer;
1959         for (int i = size - 1; i >= 0; i--) {
1960             final char c1 = thisBuf[i];
1961             final char c2 = otherBuf[i];
1962             if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
1963                 return false;
1964             }
1965         }
1966         return true;
1967     }
1968 
1969     /**
1970      * Converts this instance to a String.
1971      *
1972      * @return This instance as a String
1973      * @see #toString()
1974      * @since 1.12.0
1975      */
1976     @Override
1977     public String get() {
1978         return toString();
1979     }
1980 
1981     /**
1982      * Gets a direct reference to internal storage, not for public consumption.
1983      */
1984     char[] getBuffer() {
1985         return buffer;
1986     }
1987 
1988     /**
1989      * Copies this character array into the specified array.
1990      *
1991      * @param target the target array, null will cause an array to be created
1992      * @return The input array, unless that was null or too small
1993      */
1994     public char[] getChars(char[] target) {
1995         final int len = length();
1996         if (target == null || target.length < len) {
1997             target = new char[len];
1998         }
1999         System.arraycopy(buffer, 0, target, 0, len);
2000         return target;
2001     }
2002 
2003     /**
2004      * Copies this character array into the specified array.
2005      *
2006      * @param startIndex first index to copy, inclusive, must be valid.
2007      * @param endIndex last index to copy, exclusive, must be valid.
2008      * @param target the target array, must not be null or too small.
2009      * @param targetIndex the index to start copying in target.
2010      * @throws NullPointerException if the array is null.
2011      * @throws IndexOutOfBoundsException if any index is invalid.
2012      */
2013     public void getChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) {
2014         if (startIndex < 0) {
2015             throw new StringIndexOutOfBoundsException(startIndex);
2016         }
2017         if (endIndex < 0 || endIndex > length()) {
2018             throw new StringIndexOutOfBoundsException(endIndex);
2019         }
2020         if (startIndex > endIndex) {
2021             throw new StringIndexOutOfBoundsException("end < start");
2022         }
2023         System.arraycopy(buffer, startIndex, target, targetIndex, endIndex - startIndex);
2024     }
2025 
2026     /**
2027      * Gets the text to be appended when a {@link #appendNewLine() new line} is added.
2028      *
2029      * @return The new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
2030      */
2031     public String getNewLineText() {
2032         return newLine;
2033     }
2034 
2035     /**
2036      * Gets the text to be appended when null is added.
2037      *
2038      * @return The null text, null means no append
2039      */
2040     public String getNullText() {
2041         return nullText;
2042     }
2043 
2044     /**
2045      * Gets a suitable hash code for this builder.
2046      *
2047      * @return a hash code
2048      */
2049     @Override
2050     public int hashCode() {
2051         // no allocation
2052         final char[] buf = buffer;
2053         int result = 0;
2054         for (int i = 0; i < size; i++) {
2055             result = 31 * result + buf[i];
2056         }
2057         return result;
2058     }
2059 
2060     /**
2061      * Searches the string builder to find the first reference to the specified char.
2062      *
2063      * @param ch the character to find
2064      * @return The first index of the character, or -1 if not found
2065      */
2066     public int indexOf(final char ch) {
2067         return indexOf(ch, 0);
2068     }
2069 
2070     /**
2071      * Searches the string builder to find the first reference to the specified char.
2072      *
2073      * @param ch the character to find
2074      * @param startIndex the index to start at, invalid index rounded to edge
2075      * @return The first index of the character, or -1 if not found
2076      */
2077     public int indexOf(final char ch, int startIndex) {
2078         startIndex = Math.max(0, startIndex);
2079         if (startIndex >= size) {
2080             return StringUtils.INDEX_NOT_FOUND;
2081         }
2082         final char[] thisBuf = buffer;
2083         for (int i = startIndex; i < size; i++) {
2084             if (thisBuf[i] == ch) {
2085                 return i;
2086             }
2087         }
2088         return StringUtils.INDEX_NOT_FOUND;
2089     }
2090 
2091     /**
2092      * Searches the string builder to find the first reference to the specified string.
2093      * <p>
2094      * Note that a null input string will return -1, whereas the JDK throws an exception.
2095      * </p>
2096      *
2097      * @param str the string to find, null returns -1
2098      * @return The first index of the string, or -1 if not found
2099      */
2100     public int indexOf(final String str) {
2101         return indexOf(str, 0);
2102     }
2103 
2104     /**
2105      * Searches the string builder to find the first reference to the specified string starting searching from the given
2106      * index.
2107      * <p>
2108      * Note that a null input string will return -1, whereas the JDK throws an exception.
2109      * </p>
2110      *
2111      * @param str the string to find, null returns -1
2112      * @param startIndex the index to start at, invalid index rounded to edge
2113      * @return The first index of the string, or -1 if not found
2114      */
2115     public int indexOf(final String str, int startIndex) {
2116         startIndex = Math.max(0, startIndex);
2117         if (str == null || startIndex >= size) {
2118             return StringUtils.INDEX_NOT_FOUND;
2119         }
2120         final int strLen = str.length();
2121         if (strLen == 1) {
2122             return indexOf(str.charAt(0), startIndex);
2123         }
2124         if (strLen == 0) {
2125             return startIndex;
2126         }
2127         if (strLen > size) {
2128             return StringUtils.INDEX_NOT_FOUND;
2129         }
2130         final char[] thisBuf = buffer;
2131         final int len = size - strLen + 1;
2132         outer: for (int i = startIndex; i < len; i++) {
2133             for (int j = 0; j < strLen; j++) {
2134                 if (str.charAt(j) != thisBuf[i + j]) {
2135                     continue outer;
2136                 }
2137             }
2138             return i;
2139         }
2140         return StringUtils.INDEX_NOT_FOUND;
2141     }
2142 
2143     /**
2144      * Searches the string builder using the matcher to find the first match.
2145      * <p>
2146      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2147      * character 'a' followed by a number.
2148      * </p>
2149      *
2150      * @param matcher the matcher to use, null returns -1
2151      * @return The first index matched, or -1 if not found
2152      */
2153     public int indexOf(final StringMatcher matcher) {
2154         return indexOf(matcher, 0);
2155     }
2156 
2157     /**
2158      * Searches the string builder using the matcher to find the first match searching from the given index.
2159      * <p>
2160      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2161      * character 'a' followed by a number.
2162      * </p>
2163      *
2164      * @param matcher the matcher to use, null returns -1
2165      * @param startIndex the index to start at, invalid index rounded to edge
2166      * @return The first index matched, or -1 if not found
2167      */
2168     public int indexOf(final StringMatcher matcher, int startIndex) {
2169         startIndex = Math.max(0, startIndex);
2170         if (matcher == null || startIndex >= size) {
2171             return StringUtils.INDEX_NOT_FOUND;
2172         }
2173         final int len = size;
2174         final char[] buf = buffer;
2175         for (int i = startIndex; i < len; i++) {
2176             if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2177                 return i;
2178             }
2179         }
2180         return StringUtils.INDEX_NOT_FOUND;
2181     }
2182 
2183     /**
2184      * Inserts the value into this builder.
2185      *
2186      * @param index the index to add at, must be valid
2187      * @param value the value to insert
2188      * @return this, to enable chaining
2189      * @throws IndexOutOfBoundsException if the index is invalid
2190      */
2191     public TextStringBuilder insert(final int index, final boolean value) {
2192         validateIndex(index);
2193         if (value) {
2194             ensureCapacityInternal(size + TRUE_STRING_SIZE);
2195             System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index);
2196             appendTrue(index);
2197         } else {
2198             ensureCapacityInternal(size + FALSE_STRING_SIZE);
2199             System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index);
2200             appendFalse(index);
2201         }
2202         return this;
2203     }
2204 
2205     /**
2206      * Inserts the value into this builder.
2207      *
2208      * @param index the index to add at, must be valid
2209      * @param value the value to insert
2210      * @return this, to enable chaining
2211      * @throws IndexOutOfBoundsException if the index is invalid
2212      */
2213     public TextStringBuilder insert(final int index, final char value) {
2214         validateIndex(index);
2215         ensureCapacityInternal(size + 1);
2216         System.arraycopy(buffer, index, buffer, index + 1, size - index);
2217         buffer[index] = value;
2218         size++;
2219         return this;
2220     }
2221 
2222     /**
2223      * Inserts the character array into this builder. Inserting null will use the stored null text value.
2224      *
2225      * @param index the index to add at, must be valid
2226      * @param chars the char array to insert
2227      * @return this, to enable chaining
2228      * @throws IndexOutOfBoundsException if the index is invalid
2229      */
2230     public TextStringBuilder insert(final int index, final char[] chars) {
2231         validateIndex(index);
2232         if (chars == null) {
2233             return insert(index, nullText);
2234         }
2235         final int len = chars.length;
2236         if (len > 0) {
2237             ensureCapacityInternal(size + len);
2238             System.arraycopy(buffer, index, buffer, index + len, size - index);
2239             System.arraycopy(chars, 0, buffer, index, len);
2240             size += len;
2241         }
2242         return this;
2243     }
2244 
2245     /**
2246      * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
2247      *
2248      * @param index the index to add at, must be valid
2249      * @param chars the char array to insert
2250      * @param offset the offset into the character array to start at, must be valid
2251      * @param length the length of the character array part to copy, must be positive
2252      * @return this, to enable chaining
2253      * @throws IndexOutOfBoundsException if any index is invalid
2254      */
2255     public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) {
2256         validateIndex(index);
2257         if (chars == null) {
2258             return insert(index, nullText);
2259         }
2260         if (offset < 0 || offset > chars.length) {
2261             throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
2262         }
2263         if (length < 0 || offset + length > chars.length) {
2264             throw new StringIndexOutOfBoundsException("Invalid length: " + length);
2265         }
2266         if (length > 0) {
2267             ensureCapacityInternal(size + length);
2268             System.arraycopy(buffer, index, buffer, index + length, size - index);
2269             System.arraycopy(chars, offset, buffer, index, length);
2270             size += length;
2271         }
2272         return this;
2273     }
2274 
2275     /**
2276      * Inserts the value into this builder.
2277      *
2278      * @param index the index to add at, must be valid
2279      * @param value the value to insert
2280      * @return this, to enable chaining
2281      * @throws IndexOutOfBoundsException if the index is invalid
2282      */
2283     public TextStringBuilder insert(final int index, final double value) {
2284         return insert(index, String.valueOf(value));
2285     }
2286 
2287     /**
2288      * Inserts the value into this builder.
2289      *
2290      * @param index the index to add at, must be valid
2291      * @param value the value to insert
2292      * @return this, to enable chaining
2293      * @throws IndexOutOfBoundsException if the index is invalid
2294      */
2295     public TextStringBuilder insert(final int index, final float value) {
2296         return insert(index, String.valueOf(value));
2297     }
2298 
2299     /**
2300      * Inserts the value into this builder.
2301      *
2302      * @param index the index to add at, must be valid
2303      * @param value the value to insert
2304      * @return this, to enable chaining
2305      * @throws IndexOutOfBoundsException if the index is invalid
2306      */
2307     public TextStringBuilder insert(final int index, final int value) {
2308         return insert(index, String.valueOf(value));
2309     }
2310 
2311     /**
2312      * Inserts the value into this builder.
2313      *
2314      * @param index the index to add at, must be valid
2315      * @param value the value to insert
2316      * @return this, to enable chaining
2317      * @throws IndexOutOfBoundsException if the index is invalid
2318      */
2319     public TextStringBuilder insert(final int index, final long value) {
2320         return insert(index, String.valueOf(value));
2321     }
2322 
2323     /**
2324      * Inserts the string representation of an object into this builder. Inserting null will use the stored null text
2325      * value.
2326      *
2327      * @param index the index to add at, must be valid
2328      * @param obj the object to insert
2329      * @return this, to enable chaining
2330      * @throws IndexOutOfBoundsException if the index is invalid
2331      */
2332     public TextStringBuilder insert(final int index, final Object obj) {
2333         if (obj == null) {
2334             return insert(index, nullText);
2335         }
2336         return insert(index, obj.toString());
2337     }
2338 
2339     /**
2340      * Inserts the string into this builder. Inserting null will use the stored null text value.
2341      *
2342      * @param index the index to add at, must be valid
2343      * @param str the string to insert
2344      * @return this, to enable chaining
2345      * @throws IndexOutOfBoundsException if the index is invalid
2346      */
2347     public TextStringBuilder insert(final int index, String str) {
2348         validateIndex(index);
2349         if (str == null) {
2350             str = nullText;
2351         }
2352         if (str != null) {
2353             final int strLen = str.length();
2354             if (strLen > 0) {
2355                 final int newSize = size + strLen;
2356                 ensureCapacityInternal(newSize);
2357                 System.arraycopy(buffer, index, buffer, index + strLen, size - index);
2358                 size = newSize;
2359                 str.getChars(0, strLen, buffer, index);
2360             }
2361         }
2362         return this;
2363     }
2364 
2365     /**
2366      * Checks is the string builder is empty (convenience Collections API style method).
2367      * <p>
2368      * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2369      * </p>
2370      *
2371      * @return {@code true} if the size is {@code 0}.
2372      */
2373     public boolean isEmpty() {
2374         return size == 0;
2375     }
2376 
2377     /**
2378      * Checks is the string builder is not empty.
2379      * <p>
2380      * This method is the same as checking {@link #length()}.
2381      * </p>
2382      *
2383      * @return {@code true} if the size is not {@code 0}.
2384      * @since 1.9
2385      */
2386     public boolean isNotEmpty() {
2387         return size != 0;
2388     }
2389 
2390     /**
2391      * Gets whether the internal buffer has been reallocated.
2392      *
2393      * @return Whether the internal buffer has been reallocated.
2394      * @since 1.9
2395      */
2396     public boolean isReallocated() {
2397         return reallocations > 0;
2398     }
2399 
2400     /**
2401      * Searches the string builder to find the last reference to the specified char.
2402      *
2403      * @param ch the character to find
2404      * @return The last index of the character, or -1 if not found
2405      */
2406     public int lastIndexOf(final char ch) {
2407         return lastIndexOf(ch, size - 1);
2408     }
2409 
2410     /**
2411      * Searches the string builder to find the last reference to the specified char.
2412      *
2413      * @param ch the character to find
2414      * @param startIndex the index to start at, invalid index rounded to edge
2415      * @return The last index of the character, or -1 if not found
2416      */
2417     public int lastIndexOf(final char ch, int startIndex) {
2418         startIndex = startIndex >= size ? size - 1 : startIndex;
2419         if (startIndex < 0) {
2420             return StringUtils.INDEX_NOT_FOUND;
2421         }
2422         for (int i = startIndex; i >= 0; i--) {
2423             if (buffer[i] == ch) {
2424                 return i;
2425             }
2426         }
2427         return StringUtils.INDEX_NOT_FOUND;
2428     }
2429 
2430     /**
2431      * Searches the string builder to find the last reference to the specified string.
2432      * <p>
2433      * Note that a null input string will return -1, whereas the JDK throws an exception.
2434      * </p>
2435      *
2436      * @param str the string to find, null returns -1
2437      * @return The last index of the string, or -1 if not found
2438      */
2439     public int lastIndexOf(final String str) {
2440         return lastIndexOf(str, size - 1);
2441     }
2442 
2443     /**
2444      * Searches the string builder to find the last reference to the specified string starting searching from the given
2445      * index.
2446      * <p>
2447      * Note that a null input string will return -1, whereas the JDK throws an exception.
2448      * </p>
2449      *
2450      * @param str the string to find, null returns -1
2451      * @param startIndex the index to start at, invalid index rounded to edge
2452      * @return The last index of the string, or -1 if not found
2453      */
2454     public int lastIndexOf(final String str, int startIndex) {
2455         startIndex = startIndex >= size ? size - 1 : startIndex;
2456         if (str == null || startIndex < 0) {
2457             return StringUtils.INDEX_NOT_FOUND;
2458         }
2459         final int strLen = str.length();
2460         if (strLen > 0 && strLen <= size) {
2461             if (strLen == 1) {
2462                 return lastIndexOf(str.charAt(0), startIndex);
2463             }
2464 
2465             outer: for (int i = startIndex - strLen + 1; i >= 0; i--) {
2466                 for (int j = 0; j < strLen; j++) {
2467                     if (str.charAt(j) != buffer[i + j]) {
2468                         continue outer;
2469                     }
2470                 }
2471                 return i;
2472             }
2473 
2474         } else if (strLen == 0) {
2475             return startIndex;
2476         }
2477         return StringUtils.INDEX_NOT_FOUND;
2478     }
2479 
2480     /**
2481      * Searches the string builder using the matcher to find the last match.
2482      * <p>
2483      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2484      * character 'a' followed by a number.
2485      * </p>
2486      *
2487      * @param matcher the matcher to use, null returns -1
2488      * @return The last index matched, or -1 if not found
2489      */
2490     public int lastIndexOf(final StringMatcher matcher) {
2491         return lastIndexOf(matcher, size);
2492     }
2493 
2494     /**
2495      * Searches the string builder using the matcher to find the last match searching from the given index.
2496      * <p>
2497      * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
2498      * character 'a' followed by a number.
2499      * </p>
2500      *
2501      * @param matcher the matcher to use, null returns -1
2502      * @param startIndex the index to start at, invalid index rounded to edge
2503      * @return The last index matched, or -1 if not found
2504      */
2505     public int lastIndexOf(final StringMatcher matcher, int startIndex) {
2506         startIndex = startIndex >= size ? size - 1 : startIndex;
2507         if (matcher == null || startIndex < 0) {
2508             return StringUtils.INDEX_NOT_FOUND;
2509         }
2510         final char[] buf = buffer;
2511         final int endIndex = startIndex + 1;
2512         for (int i = startIndex; i >= 0; i--) {
2513             if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2514                 return i;
2515             }
2516         }
2517         return StringUtils.INDEX_NOT_FOUND;
2518     }
2519 
2520     /**
2521      * Extracts the leftmost characters from the string builder without throwing an exception.
2522      * <p>
2523      * This method extracts the left {@code length} characters from the builder. If this many characters are not
2524      * available, the whole builder is returned. Thus the returned string may be shorter than the length requested.
2525      * </p>
2526      *
2527      * @param length the number of characters to extract, negative returns empty string
2528      * @return The new string
2529      */
2530     public String leftString(final int length) {
2531         if (length <= 0) {
2532             return StringUtils.EMPTY;
2533         }
2534         if (length >= size) {
2535             return new String(buffer, 0, size);
2536         }
2537         return new String(buffer, 0, length);
2538     }
2539 
2540     /**
2541      * Gets the length of the string builder.
2542      *
2543      * @return The length
2544      */
2545     @Override
2546     public int length() {
2547         return size;
2548     }
2549 
2550     /**
2551      * Extracts some characters from the middle of the string builder without throwing an exception.
2552      * <p>
2553      * This method extracts {@code length} characters from the builder at the specified index. If the index is negative
2554      * it is treated as zero. If the index is greater than the builder size, it is treated as the builder size. If the
2555      * length is negative, the empty string is returned. If insufficient characters are available in the builder, as
2556      * much as possible is returned. Thus the returned string may be shorter than the length requested.
2557      * </p>
2558      *
2559      * @param index the index to start at, negative means zero
2560      * @param length the number of characters to extract, negative returns empty string
2561      * @return The new string
2562      */
2563     public String midString(int index, final int length) {
2564         if (index < 0) {
2565             index = 0;
2566         }
2567         if (length <= 0 || index >= size) {
2568             return StringUtils.EMPTY;
2569         }
2570         if (size <= index + length) {
2571             return new String(buffer, index, size - index);
2572         }
2573         return new String(buffer, index, length);
2574     }
2575 
2576     /**
2577      * Minimizes the capacity to the actual length of the string.
2578      *
2579      * @return this, to enable chaining
2580      */
2581     public TextStringBuilder minimizeCapacity() {
2582         if (buffer.length > size) {
2583             reallocate(size);
2584         }
2585         return this;
2586     }
2587 
2588     /**
2589      * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without
2590      * making extra copies.
2591      *
2592      * @param charBuffer CharBuffer to read.
2593      * @return The number of characters read.
2594      * @see #appendTo(Appendable)
2595      * @since 1.9
2596      */
2597     public int readFrom(final CharBuffer charBuffer) {
2598         final int oldSize = size;
2599         final int remaining = charBuffer.remaining();
2600         ensureCapacityInternal(size + remaining);
2601         charBuffer.get(buffer, size, remaining);
2602         size += remaining;
2603         return size - oldSize;
2604     }
2605 
2606     /**
2607      * If possible, reads all chars from the provided {@link Readable} directly into underlying character buffer without
2608      * making extra copies.
2609      *
2610      * @param readable object to read from
2611      * @return The number of characters read
2612      * @throws IOException if an I/O error occurs.
2613      * @see #appendTo(Appendable)
2614      */
2615     public int readFrom(final Readable readable) throws IOException {
2616         if (readable instanceof Reader) {
2617             return readFrom((Reader) readable);
2618         }
2619         if (readable instanceof CharBuffer) {
2620             return readFrom((CharBuffer) readable);
2621         }
2622         final int oldSize = size;
2623         while (true) {
2624             ensureCapacityInternal(size + 1);
2625             final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
2626             final int read = readable.read(buf);
2627             if (read == EOS) {
2628                 break;
2629             }
2630             size += read;
2631         }
2632         return size - oldSize;
2633     }
2634 
2635     /**
2636      * If possible, reads all chars from the provided {@link Reader} directly into underlying character buffer without
2637      * making extra copies.
2638      *
2639      * @param reader Reader to read.
2640      * @return The number of characters read or -1 if we reached the end of stream.
2641      * @throws IOException if an I/O error occurs.
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 {@link #appendNewLine() new line} is called.
3018      *
3019      * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
3020      * @return this instance.
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 }