Source code
Description: source: package: org.apache.commons.text, class: TextStringBuilder

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