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