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