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