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