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