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 * </p>
036 * <ul>
037 * <li>Not synchronized</li>
038 * <li>Not final</li>
039 * <li>Subclasses have direct access to character array</li>
040 * <li>Additional methods
041 *  <ul>
042 *   <li>appendWithSeparators - adds an array of values, with a separator</li>
043 *   <li>appendPadding - adds a length padding characters</li>
044 *   <li>appendFixedLength - adds a fixed width field to the builder</li>
045 *   <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
046 *   <li>delete - delete char or string</li>
047 *   <li>replace - search and replace for a char or string</li>
048 *   <li>leftString/rightString/midString - substring without exceptions</li>
049 *   <li>contains - whether the builder contains a char or string</li>
050 *   <li>size/clear/isEmpty - collections style API methods</li>
051 *  </ul>
052 * </li>
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 1583482 2014-03-31 22:54:57Z niallp $
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, final String separator) {
1132        if (array != null && array.length > 0) {
1133            @SuppressWarnings( "deprecation" ) // ObjectUtils.toString(Object) has been deprecated in 3.2
1134            final String sep = ObjectUtils.toString(separator);
1135            append(array[0]);
1136            for (int i = 1; i < array.length; i++) {
1137                append(sep);
1138                append(array[i]);
1139            }
1140        }
1141        return this;
1142    }
1143
1144    /**
1145     * Appends a iterable placing separators between each value, but
1146     * not before the first or after the last.
1147     * Appending a null iterable will have no effect.
1148     * Each object is appended using {@link #append(Object)}.
1149     *
1150     * @param iterable  the iterable to append
1151     * @param separator  the separator to use, null means no separator
1152     * @return this, to enable chaining
1153     */
1154    public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
1155        if (iterable != null) {
1156            @SuppressWarnings( "deprecation" ) // ObjectUtils.toString(Object) has been deprecated in 3.2
1157            final String sep = ObjectUtils.toString(separator);
1158            final Iterator<?> it = iterable.iterator();
1159            while (it.hasNext()) {
1160                append(it.next());
1161                if (it.hasNext()) {
1162                    append(sep);
1163                }
1164            }
1165        }
1166        return this;
1167    }
1168
1169    /**
1170     * Appends an iterator placing separators between each value, but
1171     * not before the first or after the last.
1172     * Appending a null iterator will have no effect.
1173     * Each object is appended using {@link #append(Object)}.
1174     *
1175     * @param it  the iterator to append
1176     * @param separator  the separator to use, null means no separator
1177     * @return this, to enable chaining
1178     */
1179    public StrBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
1180        if (it != null) {
1181            @SuppressWarnings( "deprecation" ) // ObjectUtils.toString(Object) has been deprecated in 3.2
1182            final String sep = ObjectUtils.toString(separator);
1183            while (it.hasNext()) {
1184                append(it.next());
1185                if (it.hasNext()) {
1186                    append(sep);
1187                }
1188            }
1189        }
1190        return this;
1191    }
1192
1193    //-----------------------------------------------------------------------
1194    /**
1195     * Appends a separator if the builder is currently non-empty.
1196     * Appending a null separator will have no effect.
1197     * The separator is appended using {@link #append(String)}.
1198     * <p>
1199     * This method is useful for adding a separator each time around the
1200     * loop except the first.
1201     * <pre>
1202     * for (Iterator it = list.iterator(); it.hasNext(); ) {
1203     *   appendSeparator(",");
1204     *   append(it.next());
1205     * }
1206     * </pre>
1207     * Note that for this simple example, you should use
1208     * {@link #appendWithSeparators(Iterable, String)}.
1209     * 
1210     * @param separator  the separator to use, null means no separator
1211     * @return this, to enable chaining
1212     * @since 2.3
1213     */
1214    public StrBuilder appendSeparator(final String separator) {
1215        return appendSeparator(separator, null);
1216    }
1217
1218    /**
1219     * Appends one of both separators to the StrBuilder.
1220     * If the builder is currently empty it will append the defaultIfEmpty-separator
1221     * Otherwise it will append the standard-separator
1222     * 
1223     * Appending a null separator will have no effect.
1224     * The separator is appended using {@link #append(String)}.
1225     * <p>
1226     * This method is for example useful for constructing queries
1227     * <pre>
1228     * StrBuilder whereClause = new StrBuilder();
1229     * if(searchCommand.getPriority() != null) {
1230     *  whereClause.appendSeparator(" and", " where");
1231     *  whereClause.append(" priority = ?")
1232     * }
1233     * if(searchCommand.getComponent() != null) {
1234     *  whereClause.appendSeparator(" and", " where");
1235     *  whereClause.append(" component = ?")
1236     * }
1237     * selectClause.append(whereClause)
1238     * </pre>
1239     * 
1240     * @param standard the separator if builder is not empty, null means no separator
1241     * @param defaultIfEmpty the separator if builder is empty, null means no separator
1242     * @return this, to enable chaining
1243     * @since 2.5
1244     */
1245    public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
1246        final String str = isEmpty() ? defaultIfEmpty : standard;
1247        if (str != null) {
1248            append(str);
1249        }
1250        return this;
1251    }
1252
1253    /**
1254     * Appends a separator if the builder is currently non-empty.
1255     * The separator is appended using {@link #append(char)}.
1256     * <p>
1257     * This method is useful for adding a separator each time around the
1258     * loop except the first.
1259     * <pre>
1260     * for (Iterator it = list.iterator(); it.hasNext(); ) {
1261     *   appendSeparator(',');
1262     *   append(it.next());
1263     * }
1264     * </pre>
1265     * Note that for this simple example, you should use
1266     * {@link #appendWithSeparators(Iterable, String)}.
1267     * 
1268     * @param separator  the separator to use
1269     * @return this, to enable chaining
1270     * @since 2.3
1271     */
1272    public StrBuilder appendSeparator(final char separator) {
1273        if (size() > 0) {
1274            append(separator);
1275        }
1276        return this;
1277    }
1278
1279    /**
1280     * Append one of both separators to the builder
1281     * If the builder is currently empty it will append the defaultIfEmpty-separator
1282     * Otherwise it will append the standard-separator
1283     *
1284     * The separator is appended using {@link #append(char)}.
1285     * @param standard the separator if builder is not empty
1286     * @param defaultIfEmpty the separator if builder is empty
1287     * @return this, to enable chaining
1288     * @since 2.5
1289     */
1290    public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
1291        if (size() > 0) {
1292            append(standard);
1293        } else {
1294            append(defaultIfEmpty);
1295        }
1296        return this;
1297    }
1298    /**
1299     * Appends a separator to the builder if the loop index is greater than zero.
1300     * Appending a null separator will have no effect.
1301     * The separator is appended using {@link #append(String)}.
1302     * <p>
1303     * This method is useful for adding a separator each time around the
1304     * loop except the first.
1305     * </p>
1306     * <pre>
1307     * for (int i = 0; i &lt; list.size(); i++) {
1308     *   appendSeparator(",", i);
1309     *   append(list.get(i));
1310     * }
1311     * </pre>
1312     * Note that for this simple example, you should use
1313     * {@link #appendWithSeparators(Iterable, String)}.
1314     * 
1315     * @param separator  the separator to use, null means no separator
1316     * @param loopIndex  the loop index
1317     * @return this, to enable chaining
1318     * @since 2.3
1319     */
1320    public StrBuilder appendSeparator(final String separator, final int loopIndex) {
1321        if (separator != null && loopIndex > 0) {
1322            append(separator);
1323        }
1324        return this;
1325    }
1326
1327    /**
1328     * Appends a separator to the builder if the loop index is greater than zero.
1329     * The separator is appended using {@link #append(char)}.
1330     * <p>
1331     * This method is useful for adding a separator each time around the
1332     * loop except the first.
1333     * </p>
1334     * <pre>
1335     * for (int i = 0; i &lt; list.size(); i++) {
1336     *   appendSeparator(",", i);
1337     *   append(list.get(i));
1338     * }
1339     * </pre>
1340     * Note that for this simple example, you should use
1341     * {@link #appendWithSeparators(Iterable, String)}.
1342     * 
1343     * @param separator  the separator to use
1344     * @param loopIndex  the loop index
1345     * @return this, to enable chaining
1346     * @since 2.3
1347     */
1348    public StrBuilder appendSeparator(final char separator, final int loopIndex) {
1349        if (loopIndex > 0) {
1350            append(separator);
1351        }
1352        return this;
1353    }
1354
1355    //-----------------------------------------------------------------------
1356    /**
1357     * Appends the pad character to the builder the specified number of times.
1358     * 
1359     * @param length  the length to append, negative means no append
1360     * @param padChar  the character to append
1361     * @return this, to enable chaining
1362     */
1363    public StrBuilder appendPadding(final int length, final char padChar) {
1364        if (length >= 0) {
1365            ensureCapacity(size + length);
1366            for (int i = 0; i < length; i++) {
1367                buffer[size++] = padChar;
1368            }
1369        }
1370        return this;
1371    }
1372
1373    //-----------------------------------------------------------------------
1374    /**
1375     * Appends an object to the builder padding on the left to a fixed width.
1376     * The <code>toString</code> of the object is used.
1377     * If the object is larger than the length, the left hand side is lost.
1378     * If the object is null, the null text value is used.
1379     * 
1380     * @param obj  the object to append, null uses null text
1381     * @param width  the fixed field width, zero or negative has no effect
1382     * @param padChar  the pad character to use
1383     * @return this, to enable chaining
1384     */
1385    public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
1386        if (width > 0) {
1387            ensureCapacity(size + width);
1388            String str = (obj == null ? getNullText() : obj.toString());
1389            if (str == null) {
1390                str = "";
1391            }
1392            final int strLen = str.length();
1393            if (strLen >= width) {
1394                str.getChars(strLen - width, strLen, buffer, size);
1395            } else {
1396                final int padLen = width - strLen;
1397                for (int i = 0; i < padLen; i++) {
1398                    buffer[size + i] = padChar;
1399                }
1400                str.getChars(0, strLen, buffer, size + padLen);
1401            }
1402            size += width;
1403        }
1404        return this;
1405    }
1406
1407    /**
1408     * Appends an object to the builder padding on the left to a fixed width.
1409     * The <code>String.valueOf</code> of the <code>int</code> value is used.
1410     * If the formatted value is larger than the length, the left hand side is lost.
1411     * 
1412     * @param value  the value to append
1413     * @param width  the fixed field width, zero or negative has no effect
1414     * @param padChar  the pad character to use
1415     * @return this, to enable chaining
1416     */
1417    public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
1418        return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
1419    }
1420
1421    /**
1422     * Appends an object to the builder padding on the right to a fixed length.
1423     * The <code>toString</code> of the object is used.
1424     * If the object is larger than the length, the right hand side is lost.
1425     * If the object is null, null text value is used.
1426     * 
1427     * @param obj  the object to append, null uses null text
1428     * @param width  the fixed field width, zero or negative has no effect
1429     * @param padChar  the pad character to use
1430     * @return this, to enable chaining
1431     */
1432    public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
1433        if (width > 0) {
1434            ensureCapacity(size + width);
1435            String str = (obj == null ? getNullText() : obj.toString());
1436            if (str == null) {
1437                str = "";
1438            }
1439            final int strLen = str.length();
1440            if (strLen >= width) {
1441                str.getChars(0, width, buffer, size);
1442            } else {
1443                final int padLen = width - strLen;
1444                str.getChars(0, strLen, buffer, size);
1445                for (int i = 0; i < padLen; i++) {
1446                    buffer[size + strLen + i] = padChar;
1447                }
1448            }
1449            size += width;
1450        }
1451        return this;
1452    }
1453
1454    /**
1455     * Appends an object to the builder padding on the right to a fixed length.
1456     * The <code>String.valueOf</code> of the <code>int</code> value is used.
1457     * If the object is larger than the length, the right hand side is lost.
1458     * 
1459     * @param value  the value to append
1460     * @param width  the fixed field width, zero or negative has no effect
1461     * @param padChar  the pad character to use
1462     * @return this, to enable chaining
1463     */
1464    public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
1465        return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
1466    }
1467
1468    //-----------------------------------------------------------------------
1469    /**
1470     * Inserts the string representation of an object into this builder.
1471     * Inserting null will use the stored null text value.
1472     *
1473     * @param index  the index to add at, must be valid
1474     * @param obj  the object to insert
1475     * @return this, to enable chaining
1476     * @throws IndexOutOfBoundsException if the index is invalid
1477     */
1478    public StrBuilder insert(final int index, final Object obj) {
1479        if (obj == null) {
1480            return insert(index, nullText);
1481        }
1482        return insert(index, obj.toString());
1483    }
1484
1485    /**
1486     * Inserts the string into this builder.
1487     * Inserting null will use the stored null text value.
1488     *
1489     * @param index  the index to add at, must be valid
1490     * @param str  the string to insert
1491     * @return this, to enable chaining
1492     * @throws IndexOutOfBoundsException if the index is invalid
1493     */
1494    public StrBuilder insert(final int index, String str) {
1495        validateIndex(index);
1496        if (str == null) {
1497            str = nullText;
1498        }
1499        if (str != null) {
1500            final int strLen = str.length();
1501            if (strLen > 0) {
1502                final int newSize = size + strLen;
1503                ensureCapacity(newSize);
1504                System.arraycopy(buffer, index, buffer, index + strLen, size - index);
1505                size = newSize;
1506                str.getChars(0, strLen, buffer, index);
1507            }
1508        }
1509        return this;
1510    }
1511
1512    /**
1513     * Inserts the character array into this builder.
1514     * Inserting null will use the stored null text value.
1515     *
1516     * @param index  the index to add at, must be valid
1517     * @param chars  the char array to insert
1518     * @return this, to enable chaining
1519     * @throws IndexOutOfBoundsException if the index is invalid
1520     */
1521    public StrBuilder insert(final int index, final char chars[]) {
1522        validateIndex(index);
1523        if (chars == null) {
1524            return insert(index, nullText);
1525        }
1526        final int len = chars.length;
1527        if (len > 0) {
1528            ensureCapacity(size + len);
1529            System.arraycopy(buffer, index, buffer, index + len, size - index);
1530            System.arraycopy(chars, 0, buffer, index, len);
1531            size += len;
1532        }
1533        return this;
1534    }
1535
1536    /**
1537     * Inserts part of the character array into this builder.
1538     * Inserting null will use the stored null text value.
1539     *
1540     * @param index  the index to add at, must be valid
1541     * @param chars  the char array to insert
1542     * @param offset  the offset into the character array to start at, must be valid
1543     * @param length  the length of the character array part to copy, must be positive
1544     * @return this, to enable chaining
1545     * @throws IndexOutOfBoundsException if any index is invalid
1546     */
1547    public StrBuilder insert(final int index, final char chars[], final int offset, final int length) {
1548        validateIndex(index);
1549        if (chars == null) {
1550            return insert(index, nullText);
1551        }
1552        if (offset < 0 || offset > chars.length) {
1553            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
1554        }
1555        if (length < 0 || offset + length > chars.length) {
1556            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
1557        }
1558        if (length > 0) {
1559            ensureCapacity(size + length);
1560            System.arraycopy(buffer, index, buffer, index + length, size - index);
1561            System.arraycopy(chars, offset, buffer, index, length);
1562            size += length;
1563        }
1564        return this;
1565    }
1566
1567    /**
1568     * Inserts the value into this builder.
1569     *
1570     * @param index  the index to add at, must be valid
1571     * @param value  the value to insert
1572     * @return this, to enable chaining
1573     * @throws IndexOutOfBoundsException if the index is invalid
1574     */
1575    public StrBuilder insert(int index, final boolean value) {
1576        validateIndex(index);
1577        if (value) {
1578            ensureCapacity(size + 4);
1579            System.arraycopy(buffer, index, buffer, index + 4, size - index);
1580            buffer[index++] = 't';
1581            buffer[index++] = 'r';
1582            buffer[index++] = 'u';
1583            buffer[index] = 'e';
1584            size += 4;
1585        } else {
1586            ensureCapacity(size + 5);
1587            System.arraycopy(buffer, index, buffer, index + 5, size - index);
1588            buffer[index++] = 'f';
1589            buffer[index++] = 'a';
1590            buffer[index++] = 'l';
1591            buffer[index++] = 's';
1592            buffer[index] = 'e';
1593            size += 5;
1594        }
1595        return this;
1596    }
1597
1598    /**
1599     * Inserts the value into this builder.
1600     *
1601     * @param index  the index to add at, must be valid
1602     * @param value  the value to insert
1603     * @return this, to enable chaining
1604     * @throws IndexOutOfBoundsException if the index is invalid
1605     */
1606    public StrBuilder insert(final int index, final char value) {
1607        validateIndex(index);
1608        ensureCapacity(size + 1);
1609        System.arraycopy(buffer, index, buffer, index + 1, size - index);
1610        buffer[index] = value;
1611        size++;
1612        return this;
1613    }
1614
1615    /**
1616     * Inserts the value into this builder.
1617     *
1618     * @param index  the index to add at, must be valid
1619     * @param value  the value to insert
1620     * @return this, to enable chaining
1621     * @throws IndexOutOfBoundsException if the index is invalid
1622     */
1623    public StrBuilder insert(final int index, final int value) {
1624        return insert(index, String.valueOf(value));
1625    }
1626
1627    /**
1628     * Inserts the value into this builder.
1629     *
1630     * @param index  the index to add at, must be valid
1631     * @param value  the value to insert
1632     * @return this, to enable chaining
1633     * @throws IndexOutOfBoundsException if the index is invalid
1634     */
1635    public StrBuilder insert(final int index, final long value) {
1636        return insert(index, String.valueOf(value));
1637    }
1638
1639    /**
1640     * Inserts the value into this builder.
1641     *
1642     * @param index  the index to add at, must be valid
1643     * @param value  the value to insert
1644     * @return this, to enable chaining
1645     * @throws IndexOutOfBoundsException if the index is invalid
1646     */
1647    public StrBuilder insert(final int index, final float value) {
1648        return insert(index, String.valueOf(value));
1649    }
1650
1651    /**
1652     * Inserts the value into this builder.
1653     *
1654     * @param index  the index to add at, must be valid
1655     * @param value  the value to insert
1656     * @return this, to enable chaining
1657     * @throws IndexOutOfBoundsException if the index is invalid
1658     */
1659    public StrBuilder insert(final int index, final double value) {
1660        return insert(index, String.valueOf(value));
1661    }
1662
1663    //-----------------------------------------------------------------------
1664    /**
1665     * Internal method to delete a range without validation.
1666     *
1667     * @param startIndex  the start index, must be valid
1668     * @param endIndex  the end index (exclusive), must be valid
1669     * @param len  the length, must be valid
1670     * @throws IndexOutOfBoundsException if any index is invalid
1671     */
1672    private void deleteImpl(final int startIndex, final int endIndex, final int len) {
1673        System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1674        size -= len;
1675    }
1676
1677    /**
1678     * Deletes the characters between the two specified indices.
1679     *
1680     * @param startIndex  the start index, inclusive, must be valid
1681     * @param endIndex  the end index, exclusive, must be valid except
1682     *  that if too large it is treated as end of string
1683     * @return this, to enable chaining
1684     * @throws IndexOutOfBoundsException if the index is invalid
1685     */
1686    public StrBuilder delete(final int startIndex, int endIndex) {
1687        endIndex = validateRange(startIndex, endIndex);
1688        final int len = endIndex - startIndex;
1689        if (len > 0) {
1690            deleteImpl(startIndex, endIndex, len);
1691        }
1692        return this;
1693    }
1694
1695    //-----------------------------------------------------------------------
1696    /**
1697     * Deletes the character wherever it occurs in the builder.
1698     *
1699     * @param ch  the character to delete
1700     * @return this, to enable chaining
1701     */
1702    public StrBuilder deleteAll(final char ch) {
1703        for (int i = 0; i < size; i++) {
1704            if (buffer[i] == ch) {
1705                final int start = i;
1706                while (++i < size) {
1707                    if (buffer[i] != ch) {
1708                        break;
1709                    }
1710                }
1711                final int len = i - start;
1712                deleteImpl(start, i, len);
1713                i -= len;
1714            }
1715        }
1716        return this;
1717    }
1718
1719    /**
1720     * Deletes the character wherever it occurs in the builder.
1721     *
1722     * @param ch  the character to delete
1723     * @return this, to enable chaining
1724     */
1725    public StrBuilder deleteFirst(final char ch) {
1726        for (int i = 0; i < size; i++) {
1727            if (buffer[i] == ch) {
1728                deleteImpl(i, i + 1, 1);
1729                break;
1730            }
1731        }
1732        return this;
1733    }
1734
1735    //-----------------------------------------------------------------------
1736    /**
1737     * Deletes the string wherever it occurs in the builder.
1738     *
1739     * @param str  the string to delete, null causes no action
1740     * @return this, to enable chaining
1741     */
1742    public StrBuilder deleteAll(final String str) {
1743        final int len = (str == null ? 0 : str.length());
1744        if (len > 0) {
1745            int index = indexOf(str, 0);
1746            while (index >= 0) {
1747                deleteImpl(index, index + len, len);
1748                index = indexOf(str, index);
1749            }
1750        }
1751        return this;
1752    }
1753
1754    /**
1755     * Deletes the string wherever it occurs in the builder.
1756     *
1757     * @param str  the string to delete, null causes no action
1758     * @return this, to enable chaining
1759     */
1760    public StrBuilder deleteFirst(final String str) {
1761        final int len = (str == null ? 0 : str.length());
1762        if (len > 0) {
1763            final int index = indexOf(str, 0);
1764            if (index >= 0) {
1765                deleteImpl(index, index + len, len);
1766            }
1767        }
1768        return this;
1769    }
1770
1771    //-----------------------------------------------------------------------
1772    /**
1773     * Deletes all parts of the builder that the matcher matches.
1774     * <p>
1775     * Matchers can be used to perform advanced deletion behaviour.
1776     * For example you could write a matcher to delete all occurrences
1777     * where the character 'a' is followed by a number.
1778     *
1779     * @param matcher  the matcher to use to find the deletion, null causes no action
1780     * @return this, to enable chaining
1781     */
1782    public StrBuilder deleteAll(final StrMatcher matcher) {
1783        return replace(matcher, null, 0, size, -1);
1784    }
1785
1786    /**
1787     * Deletes the first match within the builder using the specified matcher.
1788     * <p>
1789     * Matchers can be used to perform advanced deletion behaviour.
1790     * For example you could write a matcher to delete
1791     * where the character 'a' is followed by a number.
1792     *
1793     * @param matcher  the matcher to use to find the deletion, null causes no action
1794     * @return this, to enable chaining
1795     */
1796    public StrBuilder deleteFirst(final StrMatcher matcher) {
1797        return replace(matcher, null, 0, size, 1);
1798    }
1799
1800    //-----------------------------------------------------------------------
1801    /**
1802     * Internal method to delete a range without validation.
1803     *
1804     * @param startIndex  the start index, must be valid
1805     * @param endIndex  the end index (exclusive), must be valid
1806     * @param removeLen  the length to remove (endIndex - startIndex), must be valid
1807     * @param insertStr  the string to replace with, null means delete range
1808     * @param insertLen  the length of the insert string, must be valid
1809     * @throws IndexOutOfBoundsException if any index is invalid
1810     */
1811    private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) {
1812        final int newSize = size - removeLen + insertLen;
1813        if (insertLen != removeLen) {
1814            ensureCapacity(newSize);
1815            System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
1816            size = newSize;
1817        }
1818        if (insertLen > 0) {
1819            insertStr.getChars(0, insertLen, buffer, startIndex);
1820        }
1821    }
1822
1823    /**
1824     * Replaces a portion of the string builder with another string.
1825     * The length of the inserted string does not have to match the removed length.
1826     *
1827     * @param startIndex  the start index, inclusive, must be valid
1828     * @param endIndex  the end index, exclusive, must be valid except
1829     *  that if too large it is treated as end of string
1830     * @param replaceStr  the string to replace with, null means delete range
1831     * @return this, to enable chaining
1832     * @throws IndexOutOfBoundsException if the index is invalid
1833     */
1834    public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
1835        endIndex = validateRange(startIndex, endIndex);
1836        final int insertLen = (replaceStr == null ? 0 : replaceStr.length());
1837        replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
1838        return this;
1839    }
1840
1841    //-----------------------------------------------------------------------
1842    /**
1843     * Replaces the search character with the replace character
1844     * throughout the builder.
1845     *
1846     * @param search  the search character
1847     * @param replace  the replace character
1848     * @return this, to enable chaining
1849     */
1850    public StrBuilder replaceAll(final char search, final char replace) {
1851        if (search != replace) {
1852            for (int i = 0; i < size; i++) {
1853                if (buffer[i] == search) {
1854                    buffer[i] = replace;
1855                }
1856            }
1857        }
1858        return this;
1859    }
1860
1861    /**
1862     * Replaces the first instance of the search character with the
1863     * replace character in the builder.
1864     *
1865     * @param search  the search character
1866     * @param replace  the replace character
1867     * @return this, to enable chaining
1868     */
1869    public StrBuilder replaceFirst(final char search, final char replace) {
1870        if (search != replace) {
1871            for (int i = 0; i < size; i++) {
1872                if (buffer[i] == search) {
1873                    buffer[i] = replace;
1874                    break;
1875                }
1876            }
1877        }
1878        return this;
1879    }
1880
1881    //-----------------------------------------------------------------------
1882    /**
1883     * Replaces the search string with the replace string throughout the builder.
1884     *
1885     * @param searchStr  the search string, null causes no action to occur
1886     * @param replaceStr  the replace string, null is equivalent to an empty string
1887     * @return this, to enable chaining
1888     */
1889    public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
1890        final int searchLen = (searchStr == null ? 0 : searchStr.length());
1891        if (searchLen > 0) {
1892            final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1893            int index = indexOf(searchStr, 0);
1894            while (index >= 0) {
1895                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
1896                index = indexOf(searchStr, index + replaceLen);
1897            }
1898        }
1899        return this;
1900    }
1901
1902    /**
1903     * Replaces the first instance of the search string with the replace string.
1904     *
1905     * @param searchStr  the search string, null causes no action to occur
1906     * @param replaceStr  the replace string, null is equivalent to an empty string
1907     * @return this, to enable chaining
1908     */
1909    public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
1910        final int searchLen = (searchStr == null ? 0 : searchStr.length());
1911        if (searchLen > 0) {
1912            final int index = indexOf(searchStr, 0);
1913            if (index >= 0) {
1914                final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1915                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
1916            }
1917        }
1918        return this;
1919    }
1920
1921    //-----------------------------------------------------------------------
1922    /**
1923     * Replaces all matches within the builder with the replace string.
1924     * <p>
1925     * Matchers can be used to perform advanced replace behaviour.
1926     * For example you could write a matcher to replace all occurrences
1927     * where the character 'a' is followed by a number.
1928     *
1929     * @param matcher  the matcher to use to find the deletion, null causes no action
1930     * @param replaceStr  the replace string, null is equivalent to an empty string
1931     * @return this, to enable chaining
1932     */
1933    public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
1934        return replace(matcher, replaceStr, 0, size, -1);
1935    }
1936
1937    /**
1938     * Replaces the first match within the builder with the replace string.
1939     * <p>
1940     * Matchers can be used to perform advanced replace behaviour.
1941     * For example you could write a matcher to replace
1942     * where the character 'a' is followed by a number.
1943     *
1944     * @param matcher  the matcher to use to find the deletion, null causes no action
1945     * @param replaceStr  the replace string, null is equivalent to an empty string
1946     * @return this, to enable chaining
1947     */
1948    public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
1949        return replace(matcher, replaceStr, 0, size, 1);
1950    }
1951
1952    // -----------------------------------------------------------------------
1953    /**
1954     * Advanced search and replaces within the builder using a matcher.
1955     * <p>
1956     * Matchers can be used to perform advanced behaviour.
1957     * For example you could write a matcher to delete all occurrences
1958     * where the character 'a' is followed by a number.
1959     *
1960     * @param matcher  the matcher to use to find the deletion, null causes no action
1961     * @param replaceStr  the string to replace the match with, null is a delete
1962     * @param startIndex  the start index, inclusive, must be valid
1963     * @param endIndex  the end index, exclusive, must be valid except
1964     *  that if too large it is treated as end of string
1965     * @param replaceCount  the number of times to replace, -1 for replace all
1966     * @return this, to enable chaining
1967     * @throws IndexOutOfBoundsException if start index is invalid
1968     */
1969    public StrBuilder replace(
1970            final StrMatcher matcher, final String replaceStr,
1971            final int startIndex, int endIndex, final int replaceCount) {
1972        endIndex = validateRange(startIndex, endIndex);
1973        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
1974    }
1975
1976    /**
1977     * Replaces within the builder using a matcher.
1978     * <p>
1979     * Matchers can be used to perform advanced behaviour.
1980     * For example you could write a matcher to delete all occurrences
1981     * where the character 'a' is followed by a number.
1982     *
1983     * @param matcher  the matcher to use to find the deletion, null causes no action
1984     * @param replaceStr  the string to replace the match with, null is a delete
1985     * @param from  the start index, must be valid
1986     * @param to  the end index (exclusive), must be valid
1987     * @param replaceCount  the number of times to replace, -1 for replace all
1988     * @return this, to enable chaining
1989     * @throws IndexOutOfBoundsException if any index is invalid
1990     */
1991    private StrBuilder replaceImpl(
1992            final StrMatcher matcher, final String replaceStr,
1993            final int from, int to, int replaceCount) {
1994        if (matcher == null || size == 0) {
1995            return this;
1996        }
1997        final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1998        final char[] buf = buffer;
1999        for (int i = from; i < to && replaceCount != 0; i++) {
2000            final int removeLen = matcher.isMatch(buf, i, from, to);
2001            if (removeLen > 0) {
2002                replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2003                to = to - removeLen + replaceLen;
2004                i = i + replaceLen - 1;
2005                if (replaceCount > 0) {
2006                    replaceCount--;
2007                }
2008            }
2009        }
2010        return this;
2011    }
2012
2013    //-----------------------------------------------------------------------
2014    /**
2015     * Reverses the string builder placing each character in the opposite index.
2016     * 
2017     * @return this, to enable chaining
2018     */
2019    public StrBuilder reverse() {
2020        if (size == 0) {
2021            return this;
2022        }
2023        
2024        final int half = size / 2;
2025        final char[] buf = buffer;
2026        for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++,rightIdx--) {
2027            final char swap = buf[leftIdx];
2028            buf[leftIdx] = buf[rightIdx];
2029            buf[rightIdx] = swap;
2030        }
2031        return this;
2032    }
2033
2034    //-----------------------------------------------------------------------
2035    /**
2036     * Trims the builder by removing characters less than or equal to a space
2037     * from the beginning and end.
2038     *
2039     * @return this, to enable chaining
2040     */
2041    public StrBuilder trim() {
2042        if (size == 0) {
2043            return this;
2044        }
2045        int len = size;
2046        final char[] buf = buffer;
2047        int pos = 0;
2048        while (pos < len && buf[pos] <= ' ') {
2049            pos++;
2050        }
2051        while (pos < len && buf[len - 1] <= ' ') {
2052            len--;
2053        }
2054        if (len < size) {
2055            delete(len, size);
2056        }
2057        if (pos > 0) {
2058            delete(0, pos);
2059        }
2060        return this;
2061    }
2062
2063    //-----------------------------------------------------------------------
2064    /**
2065     * Checks whether this builder starts with the specified string.
2066     * <p>
2067     * Note that this method handles null input quietly, unlike String.
2068     * 
2069     * @param str  the string to search for, null returns false
2070     * @return true if the builder starts with the string
2071     */
2072    public boolean startsWith(final String str) {
2073        if (str == null) {
2074            return false;
2075        }
2076        final int len = str.length();
2077        if (len == 0) {
2078            return true;
2079        }
2080        if (len > size) {
2081            return false;
2082        }
2083        for (int i = 0; i < len; i++) {
2084            if (buffer[i] != str.charAt(i)) {
2085                return false;
2086            }
2087        }
2088        return true;
2089    }
2090
2091    /**
2092     * Checks whether this builder ends with the specified string.
2093     * <p>
2094     * Note that this method handles null input quietly, unlike String.
2095     * 
2096     * @param str  the string to search for, null returns false
2097     * @return true if the builder ends with the string
2098     */
2099    public boolean endsWith(final String str) {
2100        if (str == null) {
2101            return false;
2102        }
2103        final int len = str.length();
2104        if (len == 0) {
2105            return true;
2106        }
2107        if (len > size) {
2108            return false;
2109        }
2110        int pos = size - len;
2111        for (int i = 0; i < len; i++,pos++) {
2112            if (buffer[pos] != str.charAt(i)) {
2113                return false;
2114            }
2115        }
2116        return true;
2117    }
2118
2119    //-----------------------------------------------------------------------
2120    /**
2121     * {@inheritDoc}
2122     * @since 3.0
2123     */
2124    @Override
2125    public CharSequence subSequence(final int startIndex, final int endIndex) {
2126      if (startIndex < 0) {
2127          throw new StringIndexOutOfBoundsException(startIndex);
2128      }
2129      if (endIndex > size) {
2130          throw new StringIndexOutOfBoundsException(endIndex);
2131      }
2132      if (startIndex > endIndex) {
2133          throw new StringIndexOutOfBoundsException(endIndex - startIndex);
2134      }
2135      return substring(startIndex, endIndex);
2136    }
2137
2138    /**
2139     * Extracts a portion of this string builder as a string.
2140     * 
2141     * @param start  the start index, inclusive, must be valid
2142     * @return the new string
2143     * @throws IndexOutOfBoundsException if the index is invalid
2144     */
2145    public String substring(final int start) {
2146        return substring(start, size);
2147    }
2148
2149    /**
2150     * Extracts a portion of this string builder as a string.
2151     * <p>
2152     * Note: This method treats an endIndex greater than the length of the
2153     * builder as equal to the length of the builder, and continues
2154     * without error, unlike StringBuffer or String.
2155     * 
2156     * @param startIndex  the start index, inclusive, must be valid
2157     * @param endIndex  the end index, exclusive, must be valid except
2158     *  that if too large it is treated as end of string
2159     * @return the new string
2160     * @throws IndexOutOfBoundsException if the index is invalid
2161     */
2162    public String substring(final int startIndex, int endIndex) {
2163        endIndex = validateRange(startIndex, endIndex);
2164        return new String(buffer, startIndex, endIndex - startIndex);
2165    }
2166
2167    /**
2168     * Extracts the leftmost characters from the string builder without
2169     * throwing an exception.
2170     * <p>
2171     * This method extracts the left <code>length</code> characters from
2172     * the builder. If this many characters are not available, the whole
2173     * builder is returned. Thus the returned string may be shorter than the
2174     * length requested.
2175     * 
2176     * @param length  the number of characters to extract, negative returns empty string
2177     * @return the new string
2178     */
2179    public String leftString(final int length) {
2180        if (length <= 0) {
2181            return "";
2182        } else if (length >= size) {
2183            return new String(buffer, 0, size);
2184        } else {
2185            return new String(buffer, 0, length);
2186        }
2187    }
2188
2189    /**
2190     * Extracts the rightmost characters from the string builder without
2191     * throwing an exception.
2192     * <p>
2193     * This method extracts the right <code>length</code> characters from
2194     * the builder. If this many characters are not available, the whole
2195     * builder is returned. Thus the returned string may be shorter than the
2196     * length requested.
2197     * 
2198     * @param length  the number of characters to extract, negative returns empty string
2199     * @return the new string
2200     */
2201    public String rightString(final int length) {
2202        if (length <= 0) {
2203            return "";
2204        } else if (length >= size) {
2205            return new String(buffer, 0, size);
2206        } else {
2207            return new String(buffer, size - length, length);
2208        }
2209    }
2210
2211    /**
2212     * Extracts some characters from the middle of the string builder without
2213     * throwing an exception.
2214     * <p>
2215     * This method extracts <code>length</code> characters from the builder
2216     * at the specified index.
2217     * If the index is negative it is treated as zero.
2218     * If the index is greater than the builder size, it is treated as the builder size.
2219     * If the length is negative, the empty string is returned.
2220     * If insufficient characters are available in the builder, as much as possible is returned.
2221     * Thus the returned string may be shorter than the length requested.
2222     * 
2223     * @param index  the index to start at, negative means zero
2224     * @param length  the number of characters to extract, negative returns empty string
2225     * @return the new string
2226     */
2227    public String midString(int index, final int length) {
2228        if (index < 0) {
2229            index = 0;
2230        }
2231        if (length <= 0 || index >= size) {
2232            return "";
2233        }
2234        if (size <= index + length) {
2235            return new String(buffer, index, size - index);
2236        }
2237        return new String(buffer, index, length);
2238    }
2239
2240    //-----------------------------------------------------------------------
2241    /**
2242     * Checks if the string builder contains the specified char.
2243     *
2244     * @param ch  the character to find
2245     * @return true if the builder contains the character
2246     */
2247    public boolean contains(final char ch) {
2248        final char[] thisBuf = buffer;
2249        for (int i = 0; i < this.size; i++) {
2250            if (thisBuf[i] == ch) {
2251                return true;
2252            }
2253        }
2254        return false;
2255    }
2256
2257    /**
2258     * Checks if the string builder contains the specified string.
2259     *
2260     * @param str  the string to find
2261     * @return true if the builder contains the string
2262     */
2263    public boolean contains(final String str) {
2264        return indexOf(str, 0) >= 0;
2265    }
2266
2267    /**
2268     * Checks if the string builder contains a string matched using the
2269     * specified matcher.
2270     * <p>
2271     * Matchers can be used to perform advanced searching behaviour.
2272     * For example you could write a matcher to search for the character
2273     * 'a' followed by a number.
2274     *
2275     * @param matcher  the matcher to use, null returns -1
2276     * @return true if the matcher finds a match in the builder
2277     */
2278    public boolean contains(final StrMatcher matcher) {
2279        return indexOf(matcher, 0) >= 0;
2280    }
2281
2282    //-----------------------------------------------------------------------
2283    /**
2284     * Searches the string builder to find the first reference to the specified char.
2285     * 
2286     * @param ch  the character to find
2287     * @return the first index of the character, or -1 if not found
2288     */
2289    public int indexOf(final char ch) {
2290        return indexOf(ch, 0);
2291    }
2292
2293    /**
2294     * Searches the string builder to find the first reference to the specified char.
2295     * 
2296     * @param ch  the character to find
2297     * @param startIndex  the index to start at, invalid index rounded to edge
2298     * @return the first index of the character, or -1 if not found
2299     */
2300    public int indexOf(final char ch, int startIndex) {
2301        startIndex = (startIndex < 0 ? 0 : startIndex);
2302        if (startIndex >= size) {
2303            return -1;
2304        }
2305        final char[] thisBuf = buffer;
2306        for (int i = startIndex; i < size; i++) {
2307            if (thisBuf[i] == ch) {
2308                return i;
2309            }
2310        }
2311        return -1;
2312    }
2313
2314    /**
2315     * Searches the string builder to find the first reference to the specified string.
2316     * <p>
2317     * Note that a null input string will return -1, whereas the JDK throws an exception.
2318     * 
2319     * @param str  the string to find, null returns -1
2320     * @return the first index of the string, or -1 if not found
2321     */
2322    public int indexOf(final String str) {
2323        return indexOf(str, 0);
2324    }
2325
2326    /**
2327     * Searches the string builder to find the first reference to the specified
2328     * string starting searching from the given index.
2329     * <p>
2330     * Note that a null input string will return -1, whereas the JDK throws an exception.
2331     * 
2332     * @param str  the string to find, null returns -1
2333     * @param startIndex  the index to start at, invalid index rounded to edge
2334     * @return the first index of the string, or -1 if not found
2335     */
2336    public int indexOf(final String str, int startIndex) {
2337        startIndex = (startIndex < 0 ? 0 : startIndex);
2338        if (str == null || startIndex >= size) {
2339            return -1;
2340        }
2341        final int strLen = str.length();
2342        if (strLen == 1) {
2343            return indexOf(str.charAt(0), startIndex);
2344        }
2345        if (strLen == 0) {
2346            return startIndex;
2347        }
2348        if (strLen > size) {
2349            return -1;
2350        }
2351        final char[] thisBuf = buffer;
2352        final int len = size - strLen + 1;
2353        outer:
2354        for (int i = startIndex; i < len; i++) {
2355            for (int j = 0; j < strLen; j++) {
2356                if (str.charAt(j) != thisBuf[i + j]) {
2357                    continue outer;
2358                }
2359            }
2360            return i;
2361        }
2362        return -1;
2363    }
2364
2365    /**
2366     * Searches the string builder using the matcher to find the first match.
2367     * <p>
2368     * Matchers can be used to perform advanced searching behaviour.
2369     * For example you could write a matcher to find the character 'a'
2370     * followed by a number.
2371     *
2372     * @param matcher  the matcher to use, null returns -1
2373     * @return the first index matched, or -1 if not found
2374     */
2375    public int indexOf(final StrMatcher matcher) {
2376        return indexOf(matcher, 0);
2377    }
2378
2379    /**
2380     * Searches the string builder using the matcher to find the first
2381     * match searching from the given index.
2382     * <p>
2383     * Matchers can be used to perform advanced searching behaviour.
2384     * For example you could write a matcher to find the character 'a'
2385     * followed by a number.
2386     *
2387     * @param matcher  the matcher to use, null returns -1
2388     * @param startIndex  the index to start at, invalid index rounded to edge
2389     * @return the first index matched, or -1 if not found
2390     */
2391    public int indexOf(final StrMatcher matcher, int startIndex) {
2392        startIndex = (startIndex < 0 ? 0 : startIndex);
2393        if (matcher == null || startIndex >= size) {
2394            return -1;
2395        }
2396        final int len = size;
2397        final char[] buf = buffer;
2398        for (int i = startIndex; i < len; i++) {
2399            if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2400                return i;
2401            }
2402        }
2403        return -1;
2404    }
2405
2406    //-----------------------------------------------------------------------
2407    /**
2408     * Searches the string builder to find the last reference to the specified char.
2409     * 
2410     * @param ch  the character to find
2411     * @return the last index of the character, or -1 if not found
2412     */
2413    public int lastIndexOf(final char ch) {
2414        return lastIndexOf(ch, size - 1);
2415    }
2416
2417    /**
2418     * Searches the string builder to find the last reference to the specified char.
2419     * 
2420     * @param ch  the character to find
2421     * @param startIndex  the index to start at, invalid index rounded to edge
2422     * @return the last index of the character, or -1 if not found
2423     */
2424    public int lastIndexOf(final char ch, int startIndex) {
2425        startIndex = (startIndex >= size ? size - 1 : startIndex);
2426        if (startIndex < 0) {
2427            return -1;
2428        }
2429        for (int i = startIndex; i >= 0; i--) {
2430            if (buffer[i] == ch) {
2431                return i;
2432            }
2433        }
2434        return -1;
2435    }
2436
2437    /**
2438     * Searches the string builder to find the last reference to the specified string.
2439     * <p>
2440     * Note that a null input string will return -1, whereas the JDK throws an exception.
2441     * 
2442     * @param str  the string to find, null returns -1
2443     * @return the last index of the string, or -1 if not found
2444     */
2445    public int lastIndexOf(final String str) {
2446        return lastIndexOf(str, size - 1);
2447    }
2448
2449    /**
2450     * Searches the string builder to find the last reference to the specified
2451     * string starting searching from the given index.
2452     * <p>
2453     * Note that a null input string will return -1, whereas the JDK throws an exception.
2454     * 
2455     * @param str  the string to find, null returns -1
2456     * @param startIndex  the index to start at, invalid index rounded to edge
2457     * @return the last index of the string, or -1 if not found
2458     */
2459    public int lastIndexOf(final String str, int startIndex) {
2460        startIndex = (startIndex >= size ? size - 1 : startIndex);
2461        if (str == null || startIndex < 0) {
2462            return -1;
2463        }
2464        final int strLen = str.length();
2465        if (strLen > 0 && strLen <= size) {
2466            if (strLen == 1) {
2467                return lastIndexOf(str.charAt(0), startIndex);
2468            }
2469
2470            outer:
2471            for (int i = startIndex - strLen + 1; i >= 0; i--) {
2472                for (int j = 0; j < strLen; j++) {
2473                    if (str.charAt(j) != buffer[i + j]) {
2474                        continue outer;
2475                    }
2476                }
2477                return i;
2478            }
2479            
2480        } else if (strLen == 0) {
2481            return startIndex;
2482        }
2483        return -1;
2484    }
2485
2486    /**
2487     * Searches the string builder using the matcher to find the last match.
2488     * <p>
2489     * Matchers can be used to perform advanced searching behaviour.
2490     * For example you could write a matcher to find the character 'a'
2491     * followed by a number.
2492     *
2493     * @param matcher  the matcher to use, null returns -1
2494     * @return the last index matched, or -1 if not found
2495     */
2496    public int lastIndexOf(final StrMatcher matcher) {
2497        return lastIndexOf(matcher, size);
2498    }
2499
2500    /**
2501     * Searches the string builder using the matcher to find the last
2502     * match searching from the given index.
2503     * <p>
2504     * Matchers can be used to perform advanced searching behaviour.
2505     * For example you could write a matcher to find the character 'a'
2506     * followed by a number.
2507     *
2508     * @param matcher  the matcher to use, null returns -1
2509     * @param startIndex  the index to start at, invalid index rounded to edge
2510     * @return the last index matched, or -1 if not found
2511     */
2512    public int lastIndexOf(final StrMatcher matcher, int startIndex) {
2513        startIndex = (startIndex >= size ? size - 1 : startIndex);
2514        if (matcher == null || startIndex < 0) {
2515            return -1;
2516        }
2517        final char[] buf = buffer;
2518        final int endIndex = startIndex + 1;
2519        for (int i = startIndex; i >= 0; i--) {
2520            if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2521                return i;
2522            }
2523        }
2524        return -1;
2525    }
2526
2527    //-----------------------------------------------------------------------
2528    /**
2529     * Creates a tokenizer that can tokenize the contents of this builder.
2530     * <p>
2531     * This method allows the contents of this builder to be tokenized.
2532     * The tokenizer will be setup by default to tokenize on space, tab,
2533     * newline and formfeed (as per StringTokenizer). These values can be
2534     * changed on the tokenizer class, before retrieving the tokens.
2535     * <p>
2536     * The returned tokenizer is linked to this builder. You may intermix
2537     * calls to the buider and tokenizer within certain limits, however
2538     * there is no synchronization. Once the tokenizer has been used once,
2539     * it must be {@link StrTokenizer#reset() reset} to pickup the latest
2540     * changes in the builder. For example:
2541     * <pre>
2542     * StrBuilder b = new StrBuilder();
2543     * b.append("a b ");
2544     * StrTokenizer t = b.asTokenizer();
2545     * String[] tokens1 = t.getTokenArray();  // returns a,b
2546     * b.append("c d ");
2547     * String[] tokens2 = t.getTokenArray();  // returns a,b (c and d ignored)
2548     * t.reset();              // reset causes builder changes to be picked up
2549     * String[] tokens3 = t.getTokenArray();  // returns a,b,c,d
2550     * </pre>
2551     * In addition to simply intermixing appends and tokenization, you can also
2552     * call the set methods on the tokenizer to alter how it tokenizes. Just
2553     * remember to call reset when you want to pickup builder changes.
2554     * <p>
2555     * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])}
2556     * with a non-null value will break the link with the builder.
2557     *
2558     * @return a tokenizer that is linked to this builder
2559     */
2560    public StrTokenizer asTokenizer() {
2561        return new StrBuilderTokenizer();
2562    }
2563
2564    //-----------------------------------------------------------------------
2565    /**
2566     * Gets the contents of this builder as a Reader.
2567     * <p>
2568     * This method allows the contents of the builder to be read
2569     * using any standard method that expects a Reader.
2570     * <p>
2571     * To use, simply create a <code>StrBuilder</code>, populate it with
2572     * data, call <code>asReader</code>, and then read away.
2573     * <p>
2574     * The internal character array is shared between the builder and the reader.
2575     * This allows you to append to the builder after creating the reader,
2576     * and the changes will be picked up.
2577     * Note however, that no synchronization occurs, so you must perform
2578     * all operations with the builder and the reader in one thread.
2579     * <p>
2580     * The returned reader supports marking, and ignores the flush method.
2581     *
2582     * @return a reader that reads from this builder
2583     */
2584    public Reader asReader() {
2585        return new StrBuilderReader();
2586    }
2587
2588    //-----------------------------------------------------------------------
2589    /**
2590     * Gets this builder as a Writer that can be written to.
2591     * <p>
2592     * This method allows you to populate the contents of the builder
2593     * using any standard method that takes a Writer.
2594     * <p>
2595     * To use, simply create a <code>StrBuilder</code>,
2596     * call <code>asWriter</code>, and populate away. The data is available
2597     * at any time using the methods of the <code>StrBuilder</code>.
2598     * <p>
2599     * The internal character array is shared between the builder and the writer.
2600     * This allows you to intermix calls that append to the builder and
2601     * write using the writer and the changes will be occur correctly.
2602     * Note however, that no synchronization occurs, so you must perform
2603     * all operations with the builder and the writer in one thread.
2604     * <p>
2605     * The returned writer ignores the close and flush methods.
2606     *
2607     * @return a writer that populates this builder
2608     */
2609    public Writer asWriter() {
2610        return new StrBuilderWriter();
2611    }
2612
2613    //-----------------------------------------------------------------------
2614//    /**
2615//     * Gets a String version of the string builder by calling the internal
2616//     * constructor of String by reflection.
2617//     * <p>
2618//     * WARNING: You must not use the StrBuilder after calling this method
2619//     * as the buffer is now shared with the String object. To ensure this,
2620//     * the internal character array is set to null, so you will get
2621//     * NullPointerExceptions on all method calls.
2622//     *
2623//     * @return the builder as a String
2624//     */
2625//    public String toSharedString() {
2626//        try {
2627//            Constructor con = String.class.getDeclaredConstructor(
2628//                new Class[] {int.class, int.class, char[].class});
2629//            con.setAccessible(true);
2630//            char[] buffer = buf;
2631//            buf = null;
2632//            size = -1;
2633//            nullText = null;
2634//            return (String) con.newInstance(
2635//                new Object[] {Integer.valueOf(0), Integer.valueOf(size), buffer});
2636//            
2637//        } catch (Exception ex) {
2638//            ex.printStackTrace();
2639//            throw new UnsupportedOperationException("StrBuilder.toSharedString is unsupported: " + ex.getMessage());
2640//        }
2641//    }
2642
2643    //-----------------------------------------------------------------------
2644    /**
2645     * Checks the contents of this builder against another to see if they
2646     * contain the same character content ignoring case.
2647     *
2648     * @param other  the object to check, null returns false
2649     * @return true if the builders contain the same characters in the same order
2650     */
2651    public boolean equalsIgnoreCase(final StrBuilder other) {
2652        if (this == other) {
2653            return true;
2654        }
2655        if (this.size != other.size) {
2656            return false;
2657        }
2658        final char thisBuf[] = this.buffer;
2659        final char otherBuf[] = other.buffer;
2660        for (int i = size - 1; i >= 0; i--) {
2661            final char c1 = thisBuf[i];
2662            final char c2 = otherBuf[i];
2663            if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
2664                return false;
2665            }
2666        }
2667        return true;
2668    }
2669
2670    /**
2671     * Checks the contents of this builder against another to see if they
2672     * contain the same character content.
2673     *
2674     * @param other  the object to check, null returns false
2675     * @return true if the builders contain the same characters in the same order
2676     */
2677    public boolean equals(final StrBuilder other) {
2678        if (this == other) {
2679            return true;
2680        }
2681        if (this.size != other.size) {
2682            return false;
2683        }
2684        final char thisBuf[] = this.buffer;
2685        final char otherBuf[] = other.buffer;
2686        for (int i = size - 1; i >= 0; i--) {
2687            if (thisBuf[i] != otherBuf[i]) {
2688                return false;
2689            }
2690        }
2691        return true;
2692    }
2693
2694    /**
2695     * Checks the contents of this builder against another to see if they
2696     * contain the same character content.
2697     *
2698     * @param obj  the object to check, null returns false
2699     * @return true if the builders contain the same characters in the same order
2700     */
2701    @Override
2702    public boolean equals(final Object obj) {
2703        if (obj instanceof StrBuilder) {
2704            return equals((StrBuilder) obj);
2705        }
2706        return false;
2707    }
2708
2709    /**
2710     * Gets a suitable hash code for this builder.
2711     *
2712     * @return a hash code
2713     */
2714    @Override
2715    public int hashCode() {
2716        final char buf[] = buffer;
2717        int hash = 0;
2718        for (int i = size - 1; i >= 0; i--) {
2719            hash = 31 * hash + buf[i];
2720        }
2721        return hash;
2722    }
2723
2724    //-----------------------------------------------------------------------
2725    /**
2726     * Gets a String version of the string builder, creating a new instance
2727     * each time the method is called.
2728     * <p>
2729     * Note that unlike StringBuffer, the string version returned is
2730     * independent of the string builder.
2731     *
2732     * @return the builder as a String
2733     */
2734    @Override
2735    public String toString() {
2736        return new String(buffer, 0, size);
2737    }
2738
2739    /**
2740     * Gets a StringBuffer version of the string builder, creating a
2741     * new instance each time the method is called.
2742     *
2743     * @return the builder as a StringBuffer
2744     */
2745    public StringBuffer toStringBuffer() {
2746        return new StringBuffer(size).append(buffer, 0, size);
2747    }
2748
2749    /**
2750     * Gets a StringBuilder version of the string builder, creating a
2751     * new instance each time the method is called.
2752     *
2753     * @return the builder as a StringBuilder
2754     * @since 3.2
2755     */
2756    public StringBuilder toStringBuilder() {
2757        return new StringBuilder(size).append(buffer, 0, size);
2758    }
2759
2760    /**
2761     * Implement the {@link Builder} interface.
2762     * @return the builder as a String
2763     * @since 3.2
2764     * @see #toString()
2765     */
2766    @Override
2767    public String build() {
2768        return toString();
2769    }
2770
2771    //-----------------------------------------------------------------------
2772    /**
2773     * Validates parameters defining a range of the builder.
2774     * 
2775     * @param startIndex  the start index, inclusive, must be valid
2776     * @param endIndex  the end index, exclusive, must be valid except
2777     *  that if too large it is treated as end of string
2778     * @return the new string
2779     * @throws IndexOutOfBoundsException if the index is invalid
2780     */
2781    protected int validateRange(final int startIndex, int endIndex) {
2782        if (startIndex < 0) {
2783            throw new StringIndexOutOfBoundsException(startIndex);
2784        }
2785        if (endIndex > size) {
2786            endIndex = size;
2787        }
2788        if (startIndex > endIndex) {
2789            throw new StringIndexOutOfBoundsException("end < start");
2790        }
2791        return endIndex;
2792    }
2793
2794    /**
2795     * Validates parameters defining a single index in the builder.
2796     * 
2797     * @param index  the index, must be valid
2798     * @throws IndexOutOfBoundsException if the index is invalid
2799     */
2800    protected void validateIndex(final int index) {
2801        if (index < 0 || index > size) {
2802            throw new StringIndexOutOfBoundsException(index);
2803        }
2804    }
2805
2806    //-----------------------------------------------------------------------
2807    /**
2808     * Inner class to allow StrBuilder to operate as a tokenizer.
2809     */
2810    class StrBuilderTokenizer extends StrTokenizer {
2811
2812        /**
2813         * Default constructor.
2814         */
2815        StrBuilderTokenizer() {
2816            super();
2817        }
2818
2819        /** {@inheritDoc} */
2820        @Override
2821        protected List<String> tokenize(final char[] chars, final int offset, final int count) {
2822            if (chars == null) {
2823                return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size());
2824            }
2825            return super.tokenize(chars, offset, count);
2826        }
2827
2828        /** {@inheritDoc} */
2829        @Override
2830        public String getContent() {
2831            final String str = super.getContent();
2832            if (str == null) {
2833                return StrBuilder.this.toString();
2834            }
2835            return str;
2836        }
2837    }
2838
2839    //-----------------------------------------------------------------------
2840    /**
2841     * Inner class to allow StrBuilder to operate as a reader.
2842     */
2843    class StrBuilderReader extends Reader {
2844        /** The current stream position. */
2845        private int pos;
2846        /** The last mark position. */
2847        private int mark;
2848
2849        /**
2850         * Default constructor.
2851         */
2852        StrBuilderReader() {
2853            super();
2854        }
2855
2856        /** {@inheritDoc} */
2857        @Override
2858        public void close() {
2859            // do nothing
2860        }
2861
2862        /** {@inheritDoc} */
2863        @Override
2864        public int read() {
2865            if (ready() == false) {
2866                return -1;
2867            }
2868            return StrBuilder.this.charAt(pos++);
2869        }
2870
2871        /** {@inheritDoc} */
2872        @Override
2873        public int read(final char b[], final int off, int len) {
2874            if (off < 0 || len < 0 || off > b.length ||
2875                    (off + len) > b.length || (off + len) < 0) {
2876                throw new IndexOutOfBoundsException();
2877            }
2878            if (len == 0) {
2879                return 0;
2880            }
2881            if (pos >= StrBuilder.this.size()) {
2882                return -1;
2883            }
2884            if (pos + len > size()) {
2885                len = StrBuilder.this.size() - pos;
2886            }
2887            StrBuilder.this.getChars(pos, pos + len, b, off);
2888            pos += len;
2889            return len;
2890        }
2891
2892        /** {@inheritDoc} */
2893        @Override
2894        public long skip(long n) {
2895            if (pos + n > StrBuilder.this.size()) {
2896                n = StrBuilder.this.size() - pos;
2897            }
2898            if (n < 0) {
2899                return 0;
2900            }
2901            pos += n;
2902            return n;
2903        }
2904
2905        /** {@inheritDoc} */
2906        @Override
2907        public boolean ready() {
2908            return pos < StrBuilder.this.size();
2909        }
2910
2911        /** {@inheritDoc} */
2912        @Override
2913        public boolean markSupported() {
2914            return true;
2915        }
2916
2917        /** {@inheritDoc} */
2918        @Override
2919        public void mark(final int readAheadLimit) {
2920            mark = pos;
2921        }
2922
2923        /** {@inheritDoc} */
2924        @Override
2925        public void reset() {
2926            pos = mark;
2927        }
2928    }
2929
2930    //-----------------------------------------------------------------------
2931    /**
2932     * Inner class to allow StrBuilder to operate as a writer.
2933     */
2934    class StrBuilderWriter extends Writer {
2935
2936        /**
2937         * Default constructor.
2938         */
2939        StrBuilderWriter() {
2940            super();
2941        }
2942
2943        /** {@inheritDoc} */
2944        @Override
2945        public void close() {
2946            // do nothing
2947        }
2948
2949        /** {@inheritDoc} */
2950        @Override
2951        public void flush() {
2952            // do nothing
2953        }
2954
2955        /** {@inheritDoc} */
2956        @Override
2957        public void write(final int c) {
2958            StrBuilder.this.append((char) c);
2959        }
2960
2961        /** {@inheritDoc} */
2962        @Override
2963        public void write(final char[] cbuf) {
2964            StrBuilder.this.append(cbuf);
2965        }
2966
2967        /** {@inheritDoc} */
2968        @Override
2969        public void write(final char[] cbuf, final int off, final int len) {
2970            StrBuilder.this.append(cbuf, off, len);
2971        }
2972
2973        /** {@inheritDoc} */
2974        @Override
2975        public void write(final String str) {
2976            StrBuilder.this.append(str);
2977        }
2978
2979        /** {@inheritDoc} */
2980        @Override
2981        public void write(final String str, final int off, final int len) {
2982            StrBuilder.this.append(str, off, len);
2983        }
2984    }
2985
2986}