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