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