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