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