    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}