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