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