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