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