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