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