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