Source code
Description: source: package: org.apache.commons.text, class: TextStringBuilder

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