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