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