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