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