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