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 18 package com.badlogic.gdx.utils; 19 20 import java.util.Arrays; 21 22 /** A {@link java.lang.StringBuilder} that implements equals and hashcode. 23 * @see CharSequence 24 * @see Appendable 25 * @see java.lang.StringBuilder 26 * @see String */ 27 public class StringBuilder implements Appendable, CharSequence { 28 static final int INITIAL_CAPACITY = 16; 29 30 public char[] chars; 31 public int length; 32 33 private static final char[] digits = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; 34 35 /** @return the number of characters required to represent the specified value with the specified radix */ numChars(int value, int radix)36 public static int numChars (int value, int radix) { 37 int result = (value < 0) ? 2 : 1; 38 while ((value /= radix) != 0) 39 ++result; 40 return result; 41 } 42 43 /** @return the number of characters required to represent the specified value with the specified radix */ numChars(long value, int radix)44 public static int numChars (long value, int radix) { 45 int result = (value < 0) ? 2 : 1; 46 while ((value /= radix) != 0) 47 ++result; 48 return result; 49 } 50 51 /* 52 * Returns the character array. 53 */ getValue()54 final char[] getValue () { 55 return chars; 56 } 57 58 /** Constructs an instance with an initial capacity of {@code 16}. 59 * 60 * @see #capacity() */ StringBuilder()61 public StringBuilder () { 62 chars = new char[INITIAL_CAPACITY]; 63 } 64 65 /** Constructs an instance with the specified capacity. 66 * 67 * @param capacity the initial capacity to use. 68 * @throws NegativeArraySizeException if the specified {@code capacity} is negative. 69 * @see #capacity() */ StringBuilder(int capacity)70 public StringBuilder (int capacity) { 71 if (capacity < 0) { 72 throw new NegativeArraySizeException(); 73 } 74 chars = new char[capacity]; 75 } 76 77 /** Constructs an instance that's initialized with the contents of the specified {@code CharSequence}. The capacity of the new 78 * builder will be the length of the {@code CharSequence} plus 16. 79 * 80 * @param seq the {@code CharSequence} to copy into the builder. 81 * @throws NullPointerException if {@code seq} is {@code null}. */ StringBuilder(CharSequence seq)82 public StringBuilder (CharSequence seq) { 83 this(seq.toString()); 84 } 85 StringBuilder(StringBuilder builder)86 public StringBuilder (StringBuilder builder) { 87 length = builder.length; 88 chars = new char[length + INITIAL_CAPACITY]; 89 System.arraycopy(builder.chars, 0, chars, 0, length); 90 } 91 92 /** Constructs an instance that's initialized with the contents of the specified {@code String}. The capacity of the new builder 93 * will be the length of the {@code String} plus 16. 94 * 95 * @param string the {@code String} to copy into the builder. 96 * @throws NullPointerException if {@code str} is {@code null}. */ StringBuilder(String string)97 public StringBuilder (String string) { 98 length = string.length(); 99 chars = new char[length + INITIAL_CAPACITY]; 100 string.getChars(0, length, chars, 0); 101 } 102 enlargeBuffer(int min)103 private void enlargeBuffer (int min) { 104 int newSize = (chars.length >> 1) + chars.length + 2; 105 char[] newData = new char[min > newSize ? min : newSize]; 106 System.arraycopy(chars, 0, newData, 0, length); 107 chars = newData; 108 } 109 appendNull()110 final void appendNull () { 111 int newSize = length + 4; 112 if (newSize > chars.length) { 113 enlargeBuffer(newSize); 114 } 115 chars[length++] = 'n'; 116 chars[length++] = 'u'; 117 chars[length++] = 'l'; 118 chars[length++] = 'l'; 119 } 120 append0(char[] value)121 final void append0 (char[] value) { 122 int newSize = length + value.length; 123 if (newSize > chars.length) { 124 enlargeBuffer(newSize); 125 } 126 System.arraycopy(value, 0, chars, length, value.length); 127 length = newSize; 128 } 129 append0(char[] value, int offset, int length)130 final void append0 (char[] value, int offset, int length) { 131 // Force null check of chars first! 132 if (offset > value.length || offset < 0) { 133 throw new ArrayIndexOutOfBoundsException("Offset out of bounds: " + offset); 134 } 135 if (length < 0 || value.length - offset < length) { 136 throw new ArrayIndexOutOfBoundsException("Length out of bounds: " + length); 137 } 138 139 int newSize = this.length + length; 140 if (newSize > chars.length) { 141 enlargeBuffer(newSize); 142 } 143 System.arraycopy(value, offset, chars, this.length, length); 144 this.length = newSize; 145 } 146 append0(char ch)147 final void append0 (char ch) { 148 if (length == chars.length) { 149 enlargeBuffer(length + 1); 150 } 151 chars[length++] = ch; 152 } 153 append0(String string)154 final void append0 (String string) { 155 if (string == null) { 156 appendNull(); 157 return; 158 } 159 int adding = string.length(); 160 int newSize = length + adding; 161 if (newSize > chars.length) { 162 enlargeBuffer(newSize); 163 } 164 string.getChars(0, adding, chars, length); 165 length = newSize; 166 } 167 append0(CharSequence s, int start, int end)168 final void append0 (CharSequence s, int start, int end) { 169 if (s == null) { 170 s = "null"; 171 } 172 if (start < 0 || end < 0 || start > end || end > s.length()) { 173 throw new IndexOutOfBoundsException(); 174 } 175 176 append0(s.subSequence(start, end).toString()); 177 } 178 179 /** Returns the number of characters that can be held without growing. 180 * 181 * @return the capacity 182 * @see #ensureCapacity 183 * @see #length */ capacity()184 public int capacity () { 185 return chars.length; 186 } 187 188 /** Retrieves the character at the {@code index}. 189 * 190 * @param index the index of the character to retrieve. 191 * @return the char value. 192 * @throws IndexOutOfBoundsException if {@code index} is negative or greater than or equal to the current {@link #length()}. */ charAt(int index)193 public char charAt (int index) { 194 if (index < 0 || index >= length) { 195 throw new StringIndexOutOfBoundsException(index); 196 } 197 return chars[index]; 198 } 199 delete0(int start, int end)200 final void delete0 (int start, int end) { 201 if (start >= 0) { 202 if (end > length) { 203 end = length; 204 } 205 if (end == start) { 206 return; 207 } 208 if (end > start) { 209 int count = length - end; 210 if (count >= 0) System.arraycopy(chars, end, chars, start, count); 211 length -= end - start; 212 return; 213 } 214 } 215 throw new StringIndexOutOfBoundsException(); 216 } 217 deleteCharAt0(int location)218 final void deleteCharAt0 (int location) { 219 if (0 > location || location >= length) { 220 throw new StringIndexOutOfBoundsException(location); 221 } 222 int count = length - location - 1; 223 if (count > 0) { 224 System.arraycopy(chars, location + 1, chars, location, count); 225 } 226 length--; 227 } 228 229 /** Ensures that this object has a minimum capacity available before requiring the internal buffer to be enlarged. The general 230 * policy of this method is that if the {@code minimumCapacity} is larger than the current {@link #capacity()}, then the 231 * capacity will be increased to the largest value of either the {@code minimumCapacity} or the current capacity multiplied by 232 * two plus two. Although this is the general policy, there is no guarantee that the capacity will change. 233 * 234 * @param min the new minimum capacity to set. */ ensureCapacity(int min)235 public void ensureCapacity (int min) { 236 if (min > chars.length) { 237 int twice = (chars.length << 1) + 2; 238 enlargeBuffer(twice > min ? twice : min); 239 } 240 } 241 242 /** Copies the requested sequence of characters to the {@code char[]} passed starting at {@code destStart}. 243 * 244 * @param start the inclusive start index of the characters to copy. 245 * @param end the exclusive end index of the characters to copy. 246 * @param dest the {@code char[]} to copy the characters to. 247 * @param destStart the inclusive start index of {@code dest} to begin copying to. 248 * @throws IndexOutOfBoundsException if the {@code start} is negative, the {@code destStart} is negative, the {@code start} is 249 * greater than {@code end}, the {@code end} is greater than the current {@link #length()} or 250 * {@code destStart + end - begin} is greater than {@code dest.length}. */ getChars(int start, int end, char[] dest, int destStart)251 public void getChars (int start, int end, char[] dest, int destStart) { 252 if (start > length || end > length || start > end) { 253 throw new StringIndexOutOfBoundsException(); 254 } 255 System.arraycopy(chars, start, dest, destStart, end - start); 256 } 257 insert0(int index, char[] value)258 final void insert0 (int index, char[] value) { 259 if (0 > index || index > length) { 260 throw new StringIndexOutOfBoundsException(index); 261 } 262 if (value.length != 0) { 263 move(value.length, index); 264 System.arraycopy(value, 0, value, index, value.length); 265 length += value.length; 266 } 267 } 268 insert0(int index, char[] value, int start, int length)269 final void insert0 (int index, char[] value, int start, int length) { 270 if (0 <= index && index <= length) { 271 // start + length could overflow, start/length maybe MaxInt 272 if (start >= 0 && 0 <= length && length <= value.length - start) { 273 if (length != 0) { 274 move(length, index); 275 System.arraycopy(value, start, chars, index, length); 276 this.length += length; 277 } 278 return; 279 } 280 throw new StringIndexOutOfBoundsException("offset " + start + ", length " + length + ", char[].length " + value.length); 281 } 282 throw new StringIndexOutOfBoundsException(index); 283 } 284 insert0(int index, char ch)285 final void insert0 (int index, char ch) { 286 if (0 > index || index > length) { 287 // RI compatible exception type 288 throw new ArrayIndexOutOfBoundsException(index); 289 } 290 move(1, index); 291 chars[index] = ch; 292 length++; 293 } 294 insert0(int index, String string)295 final void insert0 (int index, String string) { 296 if (0 <= index && index <= length) { 297 if (string == null) { 298 string = "null"; 299 } 300 int min = string.length(); 301 if (min != 0) { 302 move(min, index); 303 string.getChars(0, min, chars, index); 304 length += min; 305 } 306 } else { 307 throw new StringIndexOutOfBoundsException(index); 308 } 309 } 310 insert0(int index, CharSequence s, int start, int end)311 final void insert0 (int index, CharSequence s, int start, int end) { 312 if (s == null) { 313 s = "null"; 314 } 315 if (index < 0 || index > length || start < 0 || end < 0 || start > end || end > s.length()) { 316 throw new IndexOutOfBoundsException(); 317 } 318 insert0(index, s.subSequence(start, end).toString()); 319 } 320 321 /** The current length. 322 * 323 * @return the number of characters contained in this instance. */ length()324 public int length () { 325 return length; 326 } 327 move(int size, int index)328 private void move (int size, int index) { 329 if (chars.length - length >= size) { 330 System.arraycopy(chars, index, chars, index + size, length - index); // index == count case is no-op 331 return; 332 } 333 int a = length + size, b = (chars.length << 1) + 2; 334 int newSize = a > b ? a : b; 335 char[] newData = new char[newSize]; 336 System.arraycopy(chars, 0, newData, 0, index); 337 // index == count case is no-op 338 System.arraycopy(chars, index, newData, index + size, length - index); 339 chars = newData; 340 } 341 replace0(int start, int end, String string)342 final void replace0 (int start, int end, String string) { 343 if (start >= 0) { 344 if (end > length) { 345 end = length; 346 } 347 if (end > start) { 348 int stringLength = string.length(); 349 int diff = end - start - stringLength; 350 if (diff > 0) { // replacing with fewer characters 351 // index == count case is no-op 352 System.arraycopy(chars, end, chars, start + stringLength, length - end); 353 } else if (diff < 0) { 354 // replacing with more characters...need some room 355 move(-diff, end); 356 } 357 string.getChars(0, stringLength, chars, start); 358 length -= diff; 359 return; 360 } 361 if (start == end) { 362 if (string == null) { 363 throw new NullPointerException(); 364 } 365 insert0(start, string); 366 return; 367 } 368 } 369 throw new StringIndexOutOfBoundsException(); 370 } 371 reverse0()372 final void reverse0 () { 373 if (length < 2) { 374 return; 375 } 376 int end = length - 1; 377 char frontHigh = chars[0]; 378 char endLow = chars[end]; 379 boolean allowFrontSur = true, allowEndSur = true; 380 for (int i = 0, mid = length / 2; i < mid; i++, --end) { 381 char frontLow = chars[i + 1]; 382 char endHigh = chars[end - 1]; 383 boolean surAtFront = allowFrontSur && frontLow >= 0xdc00 && frontLow <= 0xdfff && frontHigh >= 0xd800 384 && frontHigh <= 0xdbff; 385 if (surAtFront && length < 3) { 386 return; 387 } 388 boolean surAtEnd = allowEndSur && endHigh >= 0xd800 && endHigh <= 0xdbff && endLow >= 0xdc00 && endLow <= 0xdfff; 389 allowFrontSur = allowEndSur = true; 390 if (surAtFront == surAtEnd) { 391 if (surAtFront) { 392 // both surrogates 393 chars[end] = frontLow; 394 chars[end - 1] = frontHigh; 395 chars[i] = endHigh; 396 chars[i + 1] = endLow; 397 frontHigh = chars[i + 2]; 398 endLow = chars[end - 2]; 399 i++; 400 end--; 401 } else { 402 // neither surrogates 403 chars[end] = frontHigh; 404 chars[i] = endLow; 405 frontHigh = frontLow; 406 endLow = endHigh; 407 } 408 } else { 409 if (surAtFront) { 410 // surrogate only at the front 411 chars[end] = frontLow; 412 chars[i] = endLow; 413 endLow = endHigh; 414 allowFrontSur = false; 415 } else { 416 // surrogate only at the end 417 chars[end] = frontHigh; 418 chars[i] = endHigh; 419 frontHigh = frontLow; 420 allowEndSur = false; 421 } 422 } 423 } 424 if ((length & 1) == 1 && (!allowFrontSur || !allowEndSur)) { 425 chars[end] = allowFrontSur ? endLow : frontHigh; 426 } 427 } 428 429 /** Sets the character at the {@code index}. 430 * 431 * @param index the zero-based index of the character to replace. 432 * @param ch the character to set. 433 * @throws IndexOutOfBoundsException if {@code index} is negative or greater than or equal to the current {@link #length()}. */ setCharAt(int index, char ch)434 public void setCharAt (int index, char ch) { 435 if (0 > index || index >= length) { 436 throw new StringIndexOutOfBoundsException(index); 437 } 438 chars[index] = ch; 439 } 440 441 /** Sets the current length to a new value. If the new length is larger than the current length, then the new characters at the 442 * end of this object will contain the {@code char} value of {@code \u0000}. 443 * 444 * @param newLength the new length of this StringBuilder. 445 * @exception IndexOutOfBoundsException if {@code length < 0}. 446 * @see #length */ setLength(int newLength)447 public void setLength (int newLength) { 448 if (newLength < 0) { 449 throw new StringIndexOutOfBoundsException(newLength); 450 } 451 if (newLength > chars.length) { 452 enlargeBuffer(newLength); 453 } else { 454 if (length < newLength) { 455 Arrays.fill(chars, length, newLength, (char)0); 456 } 457 } 458 length = newLength; 459 } 460 461 /** Returns the String value of the subsequence from the {@code start} index to the current end. 462 * 463 * @param start the inclusive start index to begin the subsequence. 464 * @return a String containing the subsequence. 465 * @throws StringIndexOutOfBoundsException if {@code start} is negative or greater than the current {@link #length()}. */ substring(int start)466 public String substring (int start) { 467 if (0 <= start && start <= length) { 468 if (start == length) { 469 return ""; 470 } 471 472 // Remove String sharing for more performance 473 return new String(chars, start, length - start); 474 } 475 throw new StringIndexOutOfBoundsException(start); 476 } 477 478 /** Returns the String value of the subsequence from the {@code start} index to the {@code end} index. 479 * 480 * @param start the inclusive start index to begin the subsequence. 481 * @param end the exclusive end index to end the subsequence. 482 * @return a String containing the subsequence. 483 * @throws StringIndexOutOfBoundsException if {@code start} is negative, greater than {@code end} or if {@code end} is greater 484 * than the current {@link #length()}. */ substring(int start, int end)485 public String substring (int start, int end) { 486 if (0 <= start && start <= end && end <= length) { 487 if (start == end) { 488 return ""; 489 } 490 491 // Remove String sharing for more performance 492 return new String(chars, start, end - start); 493 } 494 throw new StringIndexOutOfBoundsException(); 495 } 496 497 /** Returns the current String representation. 498 * 499 * @return a String containing the characters in this instance. */ 500 @Override toString()501 public String toString () { 502 if (length == 0) return ""; 503 return new String(chars, 0, length); 504 } 505 506 /** Returns a {@code CharSequence} of the subsequence from the {@code start} index to the {@code end} index. 507 * 508 * @param start the inclusive start index to begin the subsequence. 509 * @param end the exclusive end index to end the subsequence. 510 * @return a CharSequence containing the subsequence. 511 * @throws IndexOutOfBoundsException if {@code start} is negative, greater than {@code end} or if {@code end} is greater than 512 * the current {@link #length()}. 513 * @since 1.4 */ subSequence(int start, int end)514 public CharSequence subSequence (int start, int end) { 515 return substring(start, end); 516 } 517 518 /** Searches for the first index of the specified character. The search for the character starts at the beginning and moves 519 * towards the end. 520 * 521 * @param string the string to find. 522 * @return the index of the specified character, -1 if the character isn't found. 523 * @see #lastIndexOf(String) 524 * @since 1.4 */ indexOf(String string)525 public int indexOf (String string) { 526 return indexOf(string, 0); 527 } 528 529 /** Searches for the index of the specified character. The search for the character starts at the specified offset and moves 530 * towards the end. 531 * 532 * @param subString the string to find. 533 * @param start the starting offset. 534 * @return the index of the specified character, -1 if the character isn't found 535 * @see #lastIndexOf(String,int) 536 * @since 1.4 */ indexOf(String subString, int start)537 public int indexOf (String subString, int start) { 538 if (start < 0) { 539 start = 0; 540 } 541 int subCount = subString.length(); 542 if (subCount > 0) { 543 if (subCount + start > length) { 544 return -1; 545 } 546 char firstChar = subString.charAt(0); 547 while (true) { 548 int i = start; 549 boolean found = false; 550 for (; i < length; i++) { 551 if (chars[i] == firstChar) { 552 found = true; 553 break; 554 } 555 } 556 if (!found || subCount + i > length) { 557 return -1; // handles subCount > count || start >= count 558 } 559 int o1 = i, o2 = 0; 560 while (++o2 < subCount && chars[++o1] == subString.charAt(o2)) { 561 // Intentionally empty 562 } 563 if (o2 == subCount) { 564 return i; 565 } 566 start = i + 1; 567 } 568 } 569 return start < length || start == 0 ? start : length; 570 } 571 572 /** Searches for the last index of the specified character. The search for the character starts at the end and moves towards the 573 * beginning. 574 * 575 * @param string the string to find. 576 * @return the index of the specified character, -1 if the character isn't found. 577 * @throws NullPointerException if {@code string} is {@code null}. 578 * @see String#lastIndexOf(java.lang.String) 579 * @since 1.4 */ lastIndexOf(String string)580 public int lastIndexOf (String string) { 581 return lastIndexOf(string, length); 582 } 583 584 /** Searches for the index of the specified character. The search for the character starts at the specified offset and moves 585 * towards the beginning. 586 * 587 * @param subString the string to find. 588 * @param start the starting offset. 589 * @return the index of the specified character, -1 if the character isn't found. 590 * @throws NullPointerException if {@code subString} is {@code null}. 591 * @see String#lastIndexOf(String,int) 592 * @since 1.4 */ lastIndexOf(String subString, int start)593 public int lastIndexOf (String subString, int start) { 594 int subCount = subString.length(); 595 if (subCount <= length && start >= 0) { 596 if (subCount > 0) { 597 if (start > length - subCount) { 598 start = length - subCount; // count and subCount are both 599 } 600 // >= 1 601 char firstChar = subString.charAt(0); 602 while (true) { 603 int i = start; 604 boolean found = false; 605 for (; i >= 0; --i) { 606 if (chars[i] == firstChar) { 607 found = true; 608 break; 609 } 610 } 611 if (!found) { 612 return -1; 613 } 614 int o1 = i, o2 = 0; 615 while (++o2 < subCount && chars[++o1] == subString.charAt(o2)) { 616 // Intentionally empty 617 } 618 if (o2 == subCount) { 619 return i; 620 } 621 start = i - 1; 622 } 623 } 624 return start < length ? start : length; 625 } 626 return -1; 627 } 628 629 /** Trims off any extra capacity beyond the current length. Note, this method is NOT guaranteed to change the capacity of this 630 * object. 631 * 632 * @since 1.5 */ trimToSize()633 public void trimToSize () { 634 if (length < chars.length) { 635 char[] newValue = new char[length]; 636 System.arraycopy(chars, 0, newValue, 0, length); 637 chars = newValue; 638 } 639 } 640 641 /** Retrieves the Unicode code point value at the {@code index}. 642 * 643 * @param index the index to the {@code char} code unit. 644 * @return the Unicode code point value. 645 * @throws IndexOutOfBoundsException if {@code index} is negative or greater than or equal to {@link #length()}. 646 * @see Character 647 * @see Character#codePointAt(char[], int, int) 648 * @since 1.5 */ codePointAt(int index)649 public int codePointAt (int index) { 650 if (index < 0 || index >= length) { 651 throw new StringIndexOutOfBoundsException(index); 652 } 653 return Character.codePointAt(chars, index, length); 654 } 655 656 /** Retrieves the Unicode code point value that precedes the {@code index}. 657 * 658 * @param index the index to the {@code char} code unit within this object. 659 * @return the Unicode code point value. 660 * @throws IndexOutOfBoundsException if {@code index} is less than 1 or greater than {@link #length()}. 661 * @see Character 662 * @see Character#codePointBefore(char[], int, int) 663 * @since 1.5 */ codePointBefore(int index)664 public int codePointBefore (int index) { 665 if (index < 1 || index > length) { 666 throw new StringIndexOutOfBoundsException(index); 667 } 668 return Character.codePointBefore(chars, index); 669 } 670 671 /** Calculates the number of Unicode code points between {@code beginIndex} and {@code endIndex}. 672 * 673 * @param beginIndex the inclusive beginning index of the subsequence. 674 * @param endIndex the exclusive end index of the subsequence. 675 * @return the number of Unicode code points in the subsequence. 676 * @throws IndexOutOfBoundsException if {@code beginIndex} is negative or greater than {@code endIndex} or {@code endIndex} is 677 * greater than {@link #length()}. 678 * @see Character 679 * @see Character#codePointCount(char[], int, int) 680 * @since 1.5 */ codePointCount(int beginIndex, int endIndex)681 public int codePointCount (int beginIndex, int endIndex) { 682 if (beginIndex < 0 || endIndex > length || beginIndex > endIndex) { 683 throw new StringIndexOutOfBoundsException(); 684 } 685 return Character.codePointCount(chars, beginIndex, endIndex - beginIndex); 686 } 687 688 /** Returns the index that is offset {@code codePointOffset} code points from {@code index}. 689 * 690 * @param index the index to calculate the offset from. 691 * @param codePointOffset the number of code points to count. 692 * @return the index that is {@code codePointOffset} code points away from index. 693 * @throws IndexOutOfBoundsException if {@code index} is negative or greater than {@link #length()} or if there aren't enough 694 * code points before or after {@code index} to match {@code codePointOffset}. 695 * @see Character 696 * @see Character#offsetByCodePoints(char[], int, int, int, int) 697 * @since 1.5 */ offsetByCodePoints(int index, int codePointOffset)698 public int offsetByCodePoints (int index, int codePointOffset) { 699 return Character.offsetByCodePoints(chars, 0, length, index, codePointOffset); 700 } 701 702 /** Appends the string representation of the specified {@code boolean} value. The {@code boolean} value is converted to a String 703 * according to the rule defined by {@link String#valueOf(boolean)}. 704 * 705 * @param b the {@code boolean} value to append. 706 * @return this builder. 707 * @see String#valueOf(boolean) */ append(boolean b)708 public StringBuilder append (boolean b) { 709 append0(b ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$ 710 return this; 711 } 712 713 /** Appends the string representation of the specified {@code char} value. The {@code char} value is converted to a string 714 * according to the rule defined by {@link String#valueOf(char)}. 715 * 716 * @param c the {@code char} value to append. 717 * @return this builder. 718 * @see String#valueOf(char) */ append(char c)719 public StringBuilder append (char c) { 720 append0(c); 721 return this; 722 } 723 724 /** Appends the string representation of the specified {@code int} value. The {@code int} value is converted to a string without 725 * memory allocation. 726 * 727 * @param value the {@code int} value to append. 728 * @return this builder. 729 * @see String#valueOf(int) */ append(int value)730 public StringBuilder append (int value) { 731 return append(value, 0); 732 } 733 734 /** Appends the string representation of the specified {@code int} value. The {@code int} value is converted to a string without 735 * memory allocation. 736 * 737 * @param value the {@code int} value to append. 738 * @param minLength the minimum number of characters to add 739 * @return this builder. 740 * @see String#valueOf(int) */ append(int value, int minLength)741 public StringBuilder append (int value, int minLength) { 742 return append(value, minLength, '0'); 743 } 744 745 /** Appends the string representation of the specified {@code int} value. The {@code int} value is converted to a string without 746 * memory allocation. 747 * 748 * @param value the {@code int} value to append. 749 * @param minLength the minimum number of characters to add 750 * @param prefix the character to use as prefix 751 * @return this builder. 752 * @see String#valueOf(int) */ append(int value, final int minLength, final char prefix)753 public StringBuilder append (int value, final int minLength, final char prefix) { 754 if (value == Integer.MIN_VALUE) { 755 append0("-2147483648"); 756 return this; 757 } 758 if (value < 0) { 759 append0('-'); 760 value = -value; 761 } 762 if (minLength > 1) { 763 for (int j = minLength - numChars(value, 10); j > 0; --j) 764 append(prefix); 765 } 766 if (value >= 10000) { 767 if (value >= 1000000000) append0(digits[(int)((long)value % 10000000000L / 1000000000L)]); 768 if (value >= 100000000) append0(digits[value % 1000000000 / 100000000]); 769 if (value >= 10000000) append0(digits[value % 100000000 / 10000000]); 770 if (value >= 1000000) append0(digits[value % 10000000 / 1000000]); 771 if (value >= 100000) append0(digits[value % 1000000 / 100000]); 772 append0(digits[value % 100000 / 10000]); 773 } 774 if (value >= 1000) append0(digits[value % 10000 / 1000]); 775 if (value >= 100) append0(digits[value % 1000 / 100]); 776 if (value >= 10) append0(digits[value % 100 / 10]); 777 append0(digits[value % 10]); 778 return this; 779 } 780 781 /** Appends the string representation of the specified {@code long} value. The {@code long} value is converted to a string 782 * without memory allocation. 783 * 784 * @param value the {@code long} value. 785 * @return this builder. */ append(long value)786 public StringBuilder append (long value) { 787 return append(value, 0); 788 } 789 790 /** Appends the string representation of the specified {@code long} value. The {@code long} value is converted to a string 791 * without memory allocation. 792 * 793 * @param value the {@code long} value. 794 * @param minLength the minimum number of characters to add 795 * @return this builder. */ append(long value, int minLength)796 public StringBuilder append (long value, int minLength) { 797 return append(value, minLength, '0'); 798 } 799 800 /** Appends the string representation of the specified {@code long} value. The {@code long} value is converted to a string 801 * without memory allocation. 802 * 803 * @param value the {@code long} value. 804 * @param minLength the minimum number of characters to add 805 * @param prefix the character to use as prefix 806 * @return this builder. */ append(long value, int minLength, char prefix)807 public StringBuilder append (long value, int minLength, char prefix) { 808 if (value == Long.MIN_VALUE) { 809 append0("-9223372036854775808"); 810 return this; 811 } 812 if (value < 0L) { 813 append0('-'); 814 value = -value; 815 } 816 if (minLength > 1) { 817 for (int j = minLength - numChars(value, 10); j > 0; --j) 818 append(prefix); 819 } 820 if (value >= 10000) { 821 if (value >= 1000000000000000000L) append0(digits[(int)(value % 10000000000000000000D / 1000000000000000000L)]); 822 if (value >= 100000000000000000L) append0(digits[(int)(value % 1000000000000000000L / 100000000000000000L)]); 823 if (value >= 10000000000000000L) append0(digits[(int)(value % 100000000000000000L / 10000000000000000L)]); 824 if (value >= 1000000000000000L) append0(digits[(int)(value % 10000000000000000L / 1000000000000000L)]); 825 if (value >= 100000000000000L) append0(digits[(int)(value % 1000000000000000L / 100000000000000L)]); 826 if (value >= 10000000000000L) append0(digits[(int)(value % 100000000000000L / 10000000000000L)]); 827 if (value >= 1000000000000L) append0(digits[(int)(value % 10000000000000L / 1000000000000L)]); 828 if (value >= 100000000000L) append0(digits[(int)(value % 1000000000000L / 100000000000L)]); 829 if (value >= 10000000000L) append0(digits[(int)(value % 100000000000L / 10000000000L)]); 830 if (value >= 1000000000L) append0(digits[(int)(value % 10000000000L / 1000000000L)]); 831 if (value >= 100000000L) append0(digits[(int)(value % 1000000000L / 100000000L)]); 832 if (value >= 10000000L) append0(digits[(int)(value % 100000000L / 10000000L)]); 833 if (value >= 1000000L) append0(digits[(int)(value % 10000000L / 1000000L)]); 834 if (value >= 100000L) append0(digits[(int)(value % 1000000L / 100000L)]); 835 append0(digits[(int)(value % 100000L / 10000L)]); 836 } 837 if (value >= 1000L) append0(digits[(int)(value % 10000L / 1000L)]); 838 if (value >= 100L) append0(digits[(int)(value % 1000L / 100L)]); 839 if (value >= 10L) append0(digits[(int)(value % 100L / 10L)]); 840 append0(digits[(int)(value % 10L)]); 841 return this; 842 } 843 844 /** Appends the string representation of the specified {@code float} value. The {@code float} value is converted to a string 845 * according to the rule defined by {@link String#valueOf(float)}. 846 * 847 * @param f the {@code float} value to append. 848 * @return this builder. */ append(float f)849 public StringBuilder append (float f) { 850 append0(Float.toString(f)); 851 return this; 852 } 853 854 /** Appends the string representation of the specified {@code double} value. The {@code double} value is converted to a string 855 * according to the rule defined by {@link String#valueOf(double)}. 856 * 857 * @param d the {@code double} value to append. 858 * @return this builder. 859 * @see String#valueOf(double) */ append(double d)860 public StringBuilder append (double d) { 861 append0(Double.toString(d)); 862 return this; 863 } 864 865 /** Appends the string representation of the specified {@code Object}. The {@code Object} value is converted to a string 866 * according to the rule defined by {@link String#valueOf(Object)}. 867 * 868 * @param obj the {@code Object} to append. 869 * @return this builder. 870 * @see String#valueOf(Object) */ append(Object obj)871 public StringBuilder append (Object obj) { 872 if (obj == null) { 873 appendNull(); 874 } else { 875 append0(obj.toString()); 876 } 877 return this; 878 } 879 880 /** Appends the contents of the specified string. If the string is {@code null}, then the string {@code "null"} is appended. 881 * 882 * @param str the string to append. 883 * @return this builder. */ append(String str)884 public StringBuilder append (String str) { 885 append0(str); 886 return this; 887 } 888 889 /** Appends the string representation of the specified {@code char[]}. The {@code char[]} is converted to a string according to 890 * the rule defined by {@link String#valueOf(char[])}. 891 * 892 * @param ch the {@code char[]} to append.. 893 * @return this builder. 894 * @see String#valueOf(char[]) */ append(char[] ch)895 public StringBuilder append (char[] ch) { 896 append0(ch); 897 return this; 898 } 899 900 /** Appends the string representation of the specified subset of the {@code char[]}. The {@code char[]} value is converted to a 901 * String according to the rule defined by {@link String#valueOf(char[],int,int)}. 902 * 903 * @param str the {@code char[]} to append. 904 * @param offset the inclusive offset index. 905 * @param len the number of characters. 906 * @return this builder. 907 * @throws ArrayIndexOutOfBoundsException if {@code offset} and {@code len} do not specify a valid subsequence. 908 * @see String#valueOf(char[],int,int) */ append(char[] str, int offset, int len)909 public StringBuilder append (char[] str, int offset, int len) { 910 append0(str, offset, len); 911 return this; 912 } 913 914 /** Appends the string representation of the specified {@code CharSequence}. If the {@code CharSequence} is {@code null}, then 915 * the string {@code "null"} is appended. 916 * 917 * @param csq the {@code CharSequence} to append. 918 * @return this builder. */ append(CharSequence csq)919 public StringBuilder append (CharSequence csq) { 920 if (csq == null) { 921 appendNull(); 922 } else if (csq instanceof StringBuilder) { 923 StringBuilder builder = (StringBuilder)csq; 924 append0(builder.chars, 0, builder.length); 925 } else { 926 append0(csq.toString()); 927 } 928 return this; 929 } 930 append(StringBuilder builder)931 public StringBuilder append (StringBuilder builder) { 932 if (builder == null) 933 appendNull(); 934 else 935 append0(builder.chars, 0, builder.length); 936 return this; 937 } 938 939 /** Appends the string representation of the specified subsequence of the {@code CharSequence}. If the {@code CharSequence} is 940 * {@code null}, then the string {@code "null"} is used to extract the subsequence from. 941 * 942 * @param csq the {@code CharSequence} to append. 943 * @param start the beginning index. 944 * @param end the ending index. 945 * @return this builder. 946 * @throws IndexOutOfBoundsException if {@code start} or {@code end} are negative, {@code start} is greater than {@code end} or 947 * {@code end} is greater than the length of {@code csq}. */ append(CharSequence csq, int start, int end)948 public StringBuilder append (CharSequence csq, int start, int end) { 949 append0(csq, start, end); 950 return this; 951 } 952 append(StringBuilder builder, int start, int end)953 public StringBuilder append (StringBuilder builder, int start, int end) { 954 if (builder == null) 955 appendNull(); 956 else 957 append0(builder.chars, start, end); 958 return this; 959 } 960 961 /** Appends the encoded Unicode code point. The code point is converted to a {@code char[]} as defined by 962 * {@link Character#toChars(int)}. 963 * 964 * @param codePoint the Unicode code point to encode and append. 965 * @return this builder. 966 * @see Character#toChars(int) */ appendCodePoint(int codePoint)967 public StringBuilder appendCodePoint (int codePoint) { 968 append0(Character.toChars(codePoint)); 969 return this; 970 } 971 972 /** Deletes a sequence of characters specified by {@code start} and {@code end}. Shifts any remaining characters to the left. 973 * 974 * @param start the inclusive start index. 975 * @param end the exclusive end index. 976 * @return this builder. 977 * @throws StringIndexOutOfBoundsException if {@code start} is less than zero, greater than the current length or greater than 978 * {@code end}. */ delete(int start, int end)979 public StringBuilder delete (int start, int end) { 980 delete0(start, end); 981 return this; 982 } 983 984 /** Deletes the character at the specified index. shifts any remaining characters to the left. 985 * 986 * @param index the index of the character to delete. 987 * @return this builder. 988 * @throws StringIndexOutOfBoundsException if {@code index} is less than zero or is greater than or equal to the current 989 * length. */ deleteCharAt(int index)990 public StringBuilder deleteCharAt (int index) { 991 deleteCharAt0(index); 992 return this; 993 } 994 995 /** Inserts the string representation of the specified {@code boolean} value at the specified {@code offset}. The 996 * {@code boolean} value is converted to a string according to the rule defined by {@link String#valueOf(boolean)}. 997 * 998 * @param offset the index to insert at. 999 * @param b the {@code boolean} value to insert. 1000 * @return this builder. 1001 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length}. 1002 * @see String#valueOf(boolean) */ insert(int offset, boolean b)1003 public StringBuilder insert (int offset, boolean b) { 1004 insert0(offset, b ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$ 1005 return this; 1006 } 1007 1008 /** Inserts the string representation of the specified {@code char} value at the specified {@code offset}. The {@code char} 1009 * value is converted to a string according to the rule defined by {@link String#valueOf(char)}. 1010 * 1011 * @param offset the index to insert at. 1012 * @param c the {@code char} value to insert. 1013 * @return this builder. 1014 * @throws IndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. 1015 * @see String#valueOf(char) */ insert(int offset, char c)1016 public StringBuilder insert (int offset, char c) { 1017 insert0(offset, c); 1018 return this; 1019 } 1020 1021 /** Inserts the string representation of the specified {@code int} value at the specified {@code offset}. The {@code int} value 1022 * is converted to a String according to the rule defined by {@link String#valueOf(int)}. 1023 * 1024 * @param offset the index to insert at. 1025 * @param i the {@code int} value to insert. 1026 * @return this builder. 1027 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. 1028 * @see String#valueOf(int) */ insert(int offset, int i)1029 public StringBuilder insert (int offset, int i) { 1030 insert0(offset, Integer.toString(i)); 1031 return this; 1032 } 1033 1034 /** Inserts the string representation of the specified {@code long} value at the specified {@code offset}. The {@code long} 1035 * value is converted to a String according to the rule defined by {@link String#valueOf(long)}. 1036 * 1037 * @param offset the index to insert at. 1038 * @param l the {@code long} value to insert. 1039 * @return this builder. 1040 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {code length()}. 1041 * @see String#valueOf(long) */ insert(int offset, long l)1042 public StringBuilder insert (int offset, long l) { 1043 insert0(offset, Long.toString(l)); 1044 return this; 1045 } 1046 1047 /** Inserts the string representation of the specified {@code float} value at the specified {@code offset}. The {@code float} 1048 * value is converted to a string according to the rule defined by {@link String#valueOf(float)}. 1049 * 1050 * @param offset the index to insert at. 1051 * @param f the {@code float} value to insert. 1052 * @return this builder. 1053 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. 1054 * @see String#valueOf(float) */ insert(int offset, float f)1055 public StringBuilder insert (int offset, float f) { 1056 insert0(offset, Float.toString(f)); 1057 return this; 1058 } 1059 1060 /** Inserts the string representation of the specified {@code double} value at the specified {@code offset}. The {@code double} 1061 * value is converted to a String according to the rule defined by {@link String#valueOf(double)}. 1062 * 1063 * @param offset the index to insert at. 1064 * @param d the {@code double} value to insert. 1065 * @return this builder. 1066 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. 1067 * @see String#valueOf(double) */ insert(int offset, double d)1068 public StringBuilder insert (int offset, double d) { 1069 insert0(offset, Double.toString(d)); 1070 return this; 1071 } 1072 1073 /** Inserts the string representation of the specified {@code Object} at the specified {@code offset}. The {@code Object} value 1074 * is converted to a String according to the rule defined by {@link String#valueOf(Object)}. 1075 * 1076 * @param offset the index to insert at. 1077 * @param obj the {@code Object} to insert. 1078 * @return this builder. 1079 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. 1080 * @see String#valueOf(Object) */ insert(int offset, Object obj)1081 public StringBuilder insert (int offset, Object obj) { 1082 insert0(offset, obj == null ? "null" : obj.toString()); //$NON-NLS-1$ 1083 return this; 1084 } 1085 1086 /** Inserts the specified string at the specified {@code offset}. If the specified string is null, then the String 1087 * {@code "null"} is inserted. 1088 * 1089 * @param offset the index to insert at. 1090 * @param str the {@code String} to insert. 1091 * @return this builder. 1092 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. */ insert(int offset, String str)1093 public StringBuilder insert (int offset, String str) { 1094 insert0(offset, str); 1095 return this; 1096 } 1097 1098 /** Inserts the string representation of the specified {@code char[]} at the specified {@code offset}. The {@code char[]} value 1099 * is converted to a String according to the rule defined by {@link String#valueOf(char[])}. 1100 * 1101 * @param offset the index to insert at. 1102 * @param ch the {@code char[]} to insert. 1103 * @return this builder. 1104 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. 1105 * @see String#valueOf(char[]) */ insert(int offset, char[] ch)1106 public StringBuilder insert (int offset, char[] ch) { 1107 insert0(offset, ch); 1108 return this; 1109 } 1110 1111 /** Inserts the string representation of the specified subsequence of the {@code char[]} at the specified {@code offset}. The 1112 * {@code char[]} value is converted to a String according to the rule defined by {@link String#valueOf(char[],int,int)}. 1113 * 1114 * @param offset the index to insert at. 1115 * @param str the {@code char[]} to insert. 1116 * @param strOffset the inclusive index. 1117 * @param strLen the number of characters. 1118 * @return this builder. 1119 * @throws StringIndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}, or 1120 * {@code strOffset} and {@code strLen} do not specify a valid subsequence. 1121 * @see String#valueOf(char[],int,int) */ insert(int offset, char[] str, int strOffset, int strLen)1122 public StringBuilder insert (int offset, char[] str, int strOffset, int strLen) { 1123 insert0(offset, str, strOffset, strLen); 1124 return this; 1125 } 1126 1127 /** Inserts the string representation of the specified {@code CharSequence} at the specified {@code offset}. The 1128 * {@code CharSequence} is converted to a String as defined by {@link CharSequence#toString()}. If {@code s} is {@code null}, 1129 * then the String {@code "null"} is inserted. 1130 * 1131 * @param offset the index to insert at. 1132 * @param s the {@code CharSequence} to insert. 1133 * @return this builder. 1134 * @throws IndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}. 1135 * @see CharSequence#toString() */ insert(int offset, CharSequence s)1136 public StringBuilder insert (int offset, CharSequence s) { 1137 insert0(offset, s == null ? "null" : s.toString()); //$NON-NLS-1$ 1138 return this; 1139 } 1140 1141 /** Inserts the string representation of the specified subsequence of the {@code CharSequence} at the specified {@code offset}. 1142 * The {@code CharSequence} is converted to a String as defined by {@link CharSequence#subSequence(int, int)}. If the 1143 * {@code CharSequence} is {@code null}, then the string {@code "null"} is used to determine the subsequence. 1144 * 1145 * @param offset the index to insert at. 1146 * @param s the {@code CharSequence} to insert. 1147 * @param start the start of the subsequence of the character sequence. 1148 * @param end the end of the subsequence of the character sequence. 1149 * @return this builder. 1150 * @throws IndexOutOfBoundsException if {@code offset} is negative or greater than the current {@code length()}, or 1151 * {@code start} and {@code end} do not specify a valid subsequence. 1152 * @see CharSequence#subSequence(int, int) */ insert(int offset, CharSequence s, int start, int end)1153 public StringBuilder insert (int offset, CharSequence s, int start, int end) { 1154 insert0(offset, s, start, end); 1155 return this; 1156 } 1157 1158 /** Replaces the specified subsequence in this builder with the specified string. 1159 * 1160 * @param start the inclusive begin index. 1161 * @param end the exclusive end index. 1162 * @param str the replacement string. 1163 * @return this builder. 1164 * @throws StringIndexOutOfBoundsException if {@code start} is negative, greater than the current {@code length()} or greater 1165 * than {@code end}. 1166 * @throws NullPointerException if {@code str} is {@code null}. */ replace(int start, int end, String str)1167 public StringBuilder replace (int start, int end, String str) { 1168 replace0(start, end, str); 1169 return this; 1170 } 1171 1172 /** Replaces all instances of {@code find} with {@code replace}. */ replace(String find, String replace)1173 public StringBuilder replace (String find, String replace) { 1174 int findLength = find.length(), replaceLength = replace.length(); 1175 int index = 0; 1176 while (true) { 1177 index = indexOf(find, index); 1178 if (index == -1) break; 1179 replace0(index, index + findLength, replace); 1180 index += replaceLength; 1181 } 1182 return this; 1183 } 1184 1185 /** Replaces all instances of {@code find} with {@code replace}. */ replace(char find, String replace)1186 public StringBuilder replace (char find, String replace) { 1187 int replaceLength = replace.length(); 1188 int index = 0; 1189 while (true) { 1190 while (true) { 1191 if (index == length) return this; 1192 if (chars[index] == find) break; 1193 index++; 1194 } 1195 replace0(index, index + 1, replace); 1196 index += replaceLength; 1197 } 1198 } 1199 1200 /** Reverses the order of characters in this builder. 1201 * 1202 * @return this buffer. */ reverse()1203 public StringBuilder reverse () { 1204 reverse0(); 1205 return this; 1206 } 1207 hashCode()1208 public int hashCode () { 1209 final int prime = 31; 1210 int result = 1; 1211 result = prime + length; 1212 result = prime * result + Arrays.hashCode(chars); 1213 return result; 1214 } 1215 equals(Object obj)1216 public boolean equals (Object obj) { 1217 if (this == obj) return true; 1218 if (obj == null) return false; 1219 if (getClass() != obj.getClass()) return false; 1220 StringBuilder other = (StringBuilder)obj; 1221 int length = this.length; 1222 if (length != other.length) return false; 1223 char[] chars = this.chars; 1224 char[] chars2 = other.chars; 1225 if (chars == chars2) return true; 1226 if (chars == null || chars2 == null) return false; 1227 for (int i = 0; i < length; i++) 1228 if (chars[i] != chars2[i]) return false; 1229 return true; 1230 } 1231 } 1232