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