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