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