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