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