Frames | No Frames |
1: /* ClasspathStringBuffer.java -- Growable strings without locking or copying 2: Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: package gnu.java.lang; 40: 41: import gnu.classpath.SystemProperties; 42: 43: import java.io.Serializable; 44: 45: /** 46: * This class is based on java.lang.AbstractStringBuffer but 47: * without the copying of the string by toString. 48: * If you modify this, please consider also modifying that code. 49: * This code is not thread-safe; limit its use to internal use within 50: * methods. 51: */ 52: public final class CPStringBuilder 53: implements Serializable, CharSequence, Appendable 54: { 55: 56: /** 57: * Index of next available character (and thus the size of the current 58: * string contents). Note that this has permissions set this way so that 59: * String can get the value. 60: * 61: * @serial the number of characters in the buffer 62: */ 63: private int count; 64: 65: /** 66: * The buffer. Note that this has permissions set this way so that String 67: * can get the value. 68: * 69: * @serial the buffer 70: */ 71: private char[] value; 72: 73: /** 74: * A flag to denote whether the string being created has been 75: * allocated to a {@link String} object. On construction, 76: * the character array, {@link #value} is referenced only 77: * by this class. Once {@link #toString()}, 78: * {@link #substring(int)} or {@link #substring(int,int)} 79: * are called, the array is also referenced by a {@link String} 80: * object and this flag is set. Subsequent modifications to 81: * this buffer cause a new array to be allocated and the flag 82: * to be reset. 83: */ 84: private boolean allocated = false; 85: 86: /** 87: * The default capacity of a buffer. 88: * This can be configured using gnu.classpath.cpstringbuilder.capacity 89: */ 90: private static final int DEFAULT_CAPACITY; 91: 92: static 93: { 94: String cap = 95: SystemProperties.getProperty("gnu.classpath.cpstringbuilder.capacity"); 96: if (cap == null) 97: DEFAULT_CAPACITY = 32; 98: else 99: DEFAULT_CAPACITY = Integer.parseInt(cap); 100: } 101: 102: /** 103: * Create a new CPStringBuilder with the default capacity. 104: */ 105: public CPStringBuilder() 106: { 107: this(DEFAULT_CAPACITY); 108: } 109: 110: /** 111: * Create an empty <code>CPStringBuilder</code> with the specified initial 112: * capacity. 113: * 114: * @param capacity the initial capacity 115: * @throws NegativeArraySizeException if capacity is negative 116: */ 117: public CPStringBuilder(int capacity) 118: { 119: value = new char[capacity]; 120: } 121: 122: /** 123: * Create a new <code>CPStringBuilder</code> with the characters in the 124: * specified <code>String</code>. Initial capacity will be the size of the 125: * String plus the default capacity. 126: * 127: * @param str the <code>String</code> to convert 128: * @throws NullPointerException if str is null 129: */ 130: public CPStringBuilder(String str) 131: { 132: count = str.length(); 133: value = new char[count + DEFAULT_CAPACITY]; 134: str.getChars(0, count, value, 0); 135: } 136: 137: /** 138: * Create a new <code>CPStringBuilder</code> with the characters in the 139: * specified <code>StringBuffer</code>. Initial capacity will be the size of the 140: * String plus the default capacity. 141: * 142: * @param str the <code>String</code> to convert 143: * @throws NullPointerException if str is null 144: */ 145: public CPStringBuilder(StringBuffer str) 146: { 147: count = str.length(); 148: value = new char[count + DEFAULT_CAPACITY]; 149: str.getChars(0, count, value, 0); 150: } 151: 152: /** 153: * Create a new <code>CPStringBuilder</code> with the characters in the 154: * specified <code>StringBuilder</code>. Initial capacity will be the size of the 155: * String plus the default capacity. 156: * 157: * @param str the <code>String</code> to convert 158: * @throws NullPointerException if str is null 159: */ 160: public CPStringBuilder(StringBuilder str) 161: { 162: count = str.length(); 163: value = new char[count + DEFAULT_CAPACITY]; 164: str.getChars(0, count, value, 0); 165: } 166: 167: /** 168: * Create a new <code>CPStringBuilder</code> with the characters in the 169: * specified <code>CharSequence</code>. Initial capacity will be the 170: * length of the sequence plus the default capacity; if the sequence 171: * reports a length less than or equal to 0, then the initial capacity 172: * will be the default. 173: * 174: * @param seq the initializing <code>CharSequence</code> 175: * @throws NullPointerException if str is null 176: * @since 1.5 177: */ 178: public CPStringBuilder(CharSequence seq) 179: { 180: int len = seq.length(); 181: count = len <= 0 ? 0 : len; 182: value = new char[count + DEFAULT_CAPACITY]; 183: for (int i = 0; i < len; ++i) 184: value[i] = seq.charAt(i); 185: } 186: 187: /** 188: * Set the length of this StringBuffer. If the new length is greater than 189: * the current length, all the new characters are set to '\0'. If the new 190: * length is less than the current length, the first <code>newLength</code> 191: * characters of the old array will be preserved, and the remaining 192: * characters are truncated. 193: * 194: * @param newLength the new length 195: * @throws IndexOutOfBoundsException if the new length is negative 196: * (while unspecified, this is a StringIndexOutOfBoundsException) 197: * @see #length() 198: */ 199: public void setLength(int newLength) 200: { 201: if (newLength < 0) 202: throw new StringIndexOutOfBoundsException(newLength); 203: 204: int valueLength = value.length; 205: 206: /* Always call ensureCapacity in order to preserve 207: copy-on-write semantics, except when the position 208: is simply being reset 209: */ 210: if (newLength > 0) 211: ensureCapacity(newLength); 212: 213: if (newLength < valueLength) 214: { 215: /* If the StringBuffer's value just grew, then we know that 216: value is newly allocated and the region between count and 217: newLength is filled with '\0'. */ 218: count = newLength; 219: } 220: else 221: { 222: /* The StringBuffer's value doesn't need to grow. However, 223: we should clear out any cruft that may exist. */ 224: while (count < newLength) 225: value[count++] = '\0'; 226: } 227: } 228: 229: /** 230: * Get the character at the specified index. 231: * 232: * @param index the index of the character to get, starting at 0 233: * @return the character at the specified index 234: * @throws IndexOutOfBoundsException if index is negative or >= length() 235: * (while unspecified, this is a StringIndexOutOfBoundsException) 236: */ 237: public char charAt(int index) 238: { 239: if (index < 0 || index >= count) 240: throw new StringIndexOutOfBoundsException(index); 241: return value[index]; 242: } 243: 244: /** 245: * Get the code point at the specified index. This is like #charAt(int), 246: * but if the character is the start of a surrogate pair, and the 247: * following character completes the pair, then the corresponding 248: * supplementary code point is returned. 249: * @param index the index of the codepoint to get, starting at 0 250: * @return the codepoint at the specified index 251: * @throws IndexOutOfBoundsException if index is negative or >= length() 252: * @since 1.5 253: */ 254: public int codePointAt(int index) 255: { 256: return Character.codePointAt(value, index, count); 257: } 258: 259: /** 260: * Get the code point before the specified index. This is like 261: * #codePointAt(int), but checks the characters at <code>index-1</code> and 262: * <code>index-2</code> to see if they form a supplementary code point. 263: * @param index the index just past the codepoint to get, starting at 0 264: * @return the codepoint at the specified index 265: * @throws IndexOutOfBoundsException if index is negative or >= length() 266: * @since 1.5 267: */ 268: public int codePointBefore(int index) 269: { 270: // Character.codePointBefore() doesn't perform this check. We 271: // could use the CharSequence overload, but this is just as easy. 272: if (index >= count) 273: throw new IndexOutOfBoundsException(); 274: return Character.codePointBefore(value, index, 1); 275: } 276: 277: /** 278: * Get the specified array of characters. <code>srcOffset - srcEnd</code> 279: * characters will be copied into the array you pass in. 280: * 281: * @param srcOffset the index to start copying from (inclusive) 282: * @param srcEnd the index to stop copying from (exclusive) 283: * @param dst the array to copy into 284: * @param dstOffset the index to start copying into 285: * @throws NullPointerException if dst is null 286: * @throws IndexOutOfBoundsException if any source or target indices are 287: * out of range (while unspecified, source problems cause a 288: * StringIndexOutOfBoundsException, and dest problems cause an 289: * ArrayIndexOutOfBoundsException) 290: * @see System#arraycopy(Object, int, Object, int, int) 291: */ 292: public void getChars(int srcOffset, int srcEnd, 293: char[] dst, int dstOffset) 294: { 295: if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset) 296: throw new StringIndexOutOfBoundsException(); 297: System.arraycopy(value, srcOffset, dst, dstOffset, srcEnd - srcOffset); 298: } 299: 300: /** 301: * Set the character at the specified index. 302: * 303: * @param index the index of the character to set starting at 0 304: * @param ch the value to set that character to 305: * @throws IndexOutOfBoundsException if index is negative or >= length() 306: * (while unspecified, this is a StringIndexOutOfBoundsException) 307: */ 308: public void setCharAt(int index, char ch) 309: { 310: if (index < 0 || index >= count) 311: throw new StringIndexOutOfBoundsException(index); 312: // Call ensureCapacity to enforce copy-on-write. 313: ensureCapacity(count); 314: value[index] = ch; 315: } 316: 317: /** 318: * Append the <code>String</code> value of the argument to this 319: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 320: * to <code>String</code>. 321: * 322: * @param obj the <code>Object</code> to convert and append 323: * @return this <code>StringBuffer</code> 324: * @see String#valueOf(Object) 325: * @see #append(String) 326: */ 327: public CPStringBuilder append(Object obj) 328: { 329: return append(String.valueOf(obj)); 330: } 331: 332: /** 333: * Append the <code>String</code> to this <code>StringBuffer</code>. If 334: * str is null, the String "null" is appended. 335: * 336: * @param str the <code>String</code> to append 337: * @return this <code>StringBuffer</code> 338: */ 339: public CPStringBuilder append(String str) 340: { 341: if (str == null) 342: str = "null"; 343: int len = str.length(); 344: ensureCapacity(count + len); 345: str.getChars(0, len, value, count); 346: count += len; 347: return this; 348: } 349: 350: /** 351: * Append the <code>StringBuilder</code> value of the argument to this 352: * <code>StringBuilder</code>. This behaves the same as 353: * <code>append((Object) stringBuffer)</code>, except it is more efficient. 354: * 355: * @param stringBuffer the <code>StringBuilder</code> to convert and append 356: * @return this <code>StringBuilder</code> 357: * @see #append(Object) 358: */ 359: public CPStringBuilder append(StringBuffer stringBuffer) 360: { 361: if (stringBuffer == null) 362: return append("null"); 363: synchronized (stringBuffer) 364: { 365: int len = stringBuffer.length(); 366: ensureCapacity(count + len); 367: stringBuffer.getChars(0, len, value, count); 368: count += len; 369: } 370: return this; 371: } 372: 373: /** 374: * Append the <code>char</code> array to this <code>StringBuffer</code>. 375: * This is similar (but more efficient) than 376: * <code>append(new String(data))</code>, except in the case of null. 377: * 378: * @param data the <code>char[]</code> to append 379: * @return this <code>StringBuffer</code> 380: * @throws NullPointerException if <code>str</code> is <code>null</code> 381: * @see #append(char[], int, int) 382: */ 383: public CPStringBuilder append(char[] data) 384: { 385: return append(data, 0, data.length); 386: } 387: 388: /** 389: * Append part of the <code>char</code> array to this 390: * <code>StringBuffer</code>. This is similar (but more efficient) than 391: * <code>append(new String(data, offset, count))</code>, except in the case 392: * of null. 393: * 394: * @param data the <code>char[]</code> to append 395: * @param offset the start location in <code>str</code> 396: * @param count the number of characters to get from <code>str</code> 397: * @return this <code>StringBuffer</code> 398: * @throws NullPointerException if <code>str</code> is <code>null</code> 399: * @throws IndexOutOfBoundsException if offset or count is out of range 400: * (while unspecified, this is a StringIndexOutOfBoundsException) 401: */ 402: public CPStringBuilder append(char[] data, int offset, int count) 403: { 404: if (offset < 0 || count < 0 || offset > data.length - count) 405: throw new StringIndexOutOfBoundsException(); 406: ensureCapacity(this.count + count); 407: System.arraycopy(data, offset, value, this.count, count); 408: this.count += count; 409: return this; 410: } 411: 412: /** 413: * Append the <code>String</code> value of the argument to this 414: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 415: * to <code>String</code>. 416: * 417: * @param bool the <code>boolean</code> to convert and append 418: * @return this <code>StringBuffer</code> 419: * @see String#valueOf(boolean) 420: */ 421: public CPStringBuilder append(boolean bool) 422: { 423: return append(bool ? "true" : "false"); 424: } 425: 426: /** 427: * Append the <code>char</code> to this <code>StringBuffer</code>. 428: * 429: * @param ch the <code>char</code> to append 430: * @return this <code>StringBuffer</code> 431: */ 432: public CPStringBuilder append(char ch) 433: { 434: ensureCapacity(count + 1); 435: value[count++] = ch; 436: return this; 437: } 438: 439: /** 440: * Append the characters in the <code>CharSequence</code> to this 441: * buffer. 442: * 443: * @param seq the <code>CharSequence</code> providing the characters 444: * @return this <code>StringBuffer</code> 445: * @since 1.5 446: */ 447: public CPStringBuilder append(CharSequence seq) 448: { 449: return append(seq, 0, seq.length()); 450: } 451: 452: /** 453: * Append some characters from the <code>CharSequence</code> to this 454: * buffer. If the argument is null, the four characters "null" are 455: * appended. 456: * 457: * @param seq the <code>CharSequence</code> providing the characters 458: * @param start the starting index 459: * @param end one past the final index 460: * @return this <code>StringBuffer</code> 461: * @since 1.5 462: */ 463: public CPStringBuilder append(CharSequence seq, int start, int end) 464: { 465: if (seq == null) 466: return append("null"); 467: if (end - start > 0) 468: { 469: ensureCapacity(count + end - start); 470: for (; start < end; ++start) 471: value[count++] = seq.charAt(start); 472: } 473: return this; 474: } 475: 476: /** 477: * Append the <code>String</code> value of the argument to this 478: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 479: * to <code>String</code>. 480: * 481: * @param inum the <code>int</code> to convert and append 482: * @return this <code>StringBuffer</code> 483: * @see String#valueOf(int) 484: */ 485: // This is native in libgcj, for efficiency. 486: public CPStringBuilder append(int inum) 487: { 488: return append(String.valueOf(inum)); 489: } 490: 491: /** 492: * Append the <code>String</code> value of the argument to this 493: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 494: * to <code>String</code>. 495: * 496: * @param lnum the <code>long</code> to convert and append 497: * @return this <code>StringBuffer</code> 498: * @see String#valueOf(long) 499: */ 500: public CPStringBuilder append(long lnum) 501: { 502: return append(Long.toString(lnum, 10)); 503: } 504: 505: /** 506: * Append the <code>String</code> value of the argument to this 507: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 508: * to <code>String</code>. 509: * 510: * @param fnum the <code>float</code> to convert and append 511: * @return this <code>StringBuffer</code> 512: * @see String#valueOf(float) 513: */ 514: public CPStringBuilder append(float fnum) 515: { 516: return append(Float.toString(fnum)); 517: } 518: 519: /** 520: * Append the <code>String</code> value of the argument to this 521: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 522: * to <code>String</code>. 523: * 524: * @param dnum the <code>double</code> to convert and append 525: * @return this <code>StringBuffer</code> 526: * @see String#valueOf(double) 527: */ 528: public CPStringBuilder append(double dnum) 529: { 530: return append(Double.toString(dnum)); 531: } 532: 533: /** 534: * Append the code point to this <code>StringBuffer</code>. 535: * This is like #append(char), but will append two characters 536: * if a supplementary code point is given. 537: * 538: * @param code the code point to append 539: * @return this <code>StringBuffer</code> 540: * @see Character#toChars(int, char[], int) 541: * @since 1.5 542: */ 543: public CPStringBuilder appendCodePoint(int code) 544: { 545: int len = Character.charCount(code); 546: ensureCapacity(count + len); 547: Character.toChars(code, value, count); 548: count += len; 549: return this; 550: } 551: 552: /** 553: * Delete characters from this <code>StringBuffer</code>. 554: * <code>delete(10, 12)</code> will delete 10 and 11, but not 12. It is 555: * harmless for end to be larger than length(). 556: * 557: * @param start the first character to delete 558: * @param end the index after the last character to delete 559: * @return this <code>StringBuffer</code> 560: * @throws StringIndexOutOfBoundsException if start or end are out of bounds 561: * @since 1.2 562: */ 563: public CPStringBuilder delete(int start, int end) 564: { 565: if (start < 0 || start > count || start > end) 566: throw new StringIndexOutOfBoundsException(start); 567: if (end > count) 568: end = count; 569: ensureCapacity(count); 570: if (count - end != 0) 571: System.arraycopy(value, end, value, start, count - end); 572: count -= end - start; 573: return this; 574: } 575: 576: /** 577: * Delete a character from this <code>StringBuffer</code>. 578: * 579: * @param index the index of the character to delete 580: * @return this <code>StringBuffer</code> 581: * @throws StringIndexOutOfBoundsException if index is out of bounds 582: * @since 1.2 583: */ 584: public CPStringBuilder deleteCharAt(int index) 585: { 586: return delete(index, index + 1); 587: } 588: 589: /** 590: * Replace characters between index <code>start</code> (inclusive) and 591: * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code> 592: * is larger than the size of this StringBuffer, all characters after 593: * <code>start</code> are replaced. 594: * 595: * @param start the beginning index of characters to delete (inclusive) 596: * @param end the ending index of characters to delete (exclusive) 597: * @param str the new <code>String</code> to insert 598: * @return this <code>StringBuffer</code> 599: * @throws StringIndexOutOfBoundsException if start or end are out of bounds 600: * @throws NullPointerException if str is null 601: * @since 1.2 602: */ 603: public CPStringBuilder replace(int start, int end, String str) 604: { 605: if (start < 0 || start > count || start > end) 606: throw new StringIndexOutOfBoundsException(start); 607: 608: int len = str.length(); 609: // Calculate the difference in 'count' after the replace. 610: int delta = len - (end > count ? count : end) + start; 611: ensureCapacity(count + delta); 612: 613: if (delta != 0 && end < count) 614: System.arraycopy(value, end, value, end + delta, count - end); 615: 616: str.getChars(0, len, value, start); 617: count += delta; 618: return this; 619: } 620: 621: /** 622: * Insert a subarray of the <code>char[]</code> argument into this 623: * <code>StringBuffer</code>. 624: * 625: * @param offset the place to insert in this buffer 626: * @param str the <code>char[]</code> to insert 627: * @param str_offset the index in <code>str</code> to start inserting from 628: * @param len the number of characters to insert 629: * @return this <code>StringBuffer</code> 630: * @throws NullPointerException if <code>str</code> is <code>null</code> 631: * @throws StringIndexOutOfBoundsException if any index is out of bounds 632: * @since 1.2 633: */ 634: public CPStringBuilder insert(int offset, char[] str, int str_offset, int len) 635: { 636: if (offset < 0 || offset > count || len < 0 637: || str_offset < 0 || str_offset > str.length - len) 638: throw new StringIndexOutOfBoundsException(); 639: ensureCapacity(count + len); 640: System.arraycopy(value, offset, value, offset + len, count - offset); 641: System.arraycopy(str, str_offset, value, offset, len); 642: count += len; 643: return this; 644: } 645: 646: /** 647: * Insert the <code>String</code> value of the argument into this 648: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 649: * to <code>String</code>. 650: * 651: * @param offset the place to insert in this buffer 652: * @param obj the <code>Object</code> to convert and insert 653: * @return this <code>StringBuffer</code> 654: * @exception StringIndexOutOfBoundsException if offset is out of bounds 655: * @see String#valueOf(Object) 656: */ 657: public CPStringBuilder insert(int offset, Object obj) 658: { 659: return insert(offset, obj == null ? "null" : obj.toString()); 660: } 661: 662: /** 663: * Insert the <code>String</code> argument into this 664: * <code>StringBuffer</code>. If str is null, the String "null" is used 665: * instead. 666: * 667: * @param offset the place to insert in this buffer 668: * @param str the <code>String</code> to insert 669: * @return this <code>StringBuffer</code> 670: * @throws StringIndexOutOfBoundsException if offset is out of bounds 671: */ 672: public CPStringBuilder insert(int offset, String str) 673: { 674: if (offset < 0 || offset > count) 675: throw new StringIndexOutOfBoundsException(offset); 676: if (str == null) 677: str = "null"; 678: int len = str.length(); 679: ensureCapacity(count + len); 680: System.arraycopy(value, offset, value, offset + len, count - offset); 681: str.getChars(0, len, value, offset); 682: count += len; 683: return this; 684: } 685: 686: /** 687: * Insert the <code>CharSequence</code> argument into this 688: * <code>StringBuffer</code>. If the sequence is null, the String 689: * "null" is used instead. 690: * 691: * @param offset the place to insert in this buffer 692: * @param sequence the <code>CharSequence</code> to insert 693: * @return this <code>StringBuffer</code> 694: * @throws IndexOutOfBoundsException if offset is out of bounds 695: * @since 1.5 696: */ 697: public CPStringBuilder insert(int offset, CharSequence sequence) 698: { 699: if (sequence == null) 700: sequence = "null"; 701: return insert(offset, sequence, 0, sequence.length()); 702: } 703: 704: /** 705: * Insert a subsequence of the <code>CharSequence</code> argument into this 706: * <code>StringBuffer</code>. If the sequence is null, the String 707: * "null" is used instead. 708: * 709: * @param offset the place to insert in this buffer 710: * @param sequence the <code>CharSequence</code> to insert 711: * @param start the starting index of the subsequence 712: * @param end one past the ending index of the subsequence 713: * @return this <code>StringBuffer</code> 714: * @throws IndexOutOfBoundsException if offset, start, 715: * or end are out of bounds 716: * @since 1.5 717: */ 718: public CPStringBuilder insert(int offset, CharSequence sequence, int start, int end) 719: { 720: if (sequence == null) 721: sequence = "null"; 722: if (start < 0 || end < 0 || start > end || end > sequence.length()) 723: throw new IndexOutOfBoundsException(); 724: int len = end - start; 725: ensureCapacity(count + len); 726: System.arraycopy(value, offset, value, offset + len, count - offset); 727: for (int i = start; i < end; ++i) 728: value[offset++] = sequence.charAt(i); 729: count += len; 730: return this; 731: } 732: 733: /** 734: * Insert the <code>char[]</code> argument into this 735: * <code>StringBuffer</code>. 736: * 737: * @param offset the place to insert in this buffer 738: * @param data the <code>char[]</code> to insert 739: * @return this <code>StringBuffer</code> 740: * @throws NullPointerException if <code>data</code> is <code>null</code> 741: * @throws StringIndexOutOfBoundsException if offset is out of bounds 742: * @see #insert(int, char[], int, int) 743: */ 744: public CPStringBuilder insert(int offset, char[] data) 745: { 746: return insert(offset, data, 0, data.length); 747: } 748: 749: /** 750: * Insert the <code>String</code> value of the argument into this 751: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 752: * to <code>String</code>. 753: * 754: * @param offset the place to insert in this buffer 755: * @param bool the <code>boolean</code> to convert and insert 756: * @return this <code>StringBuffer</code> 757: * @throws StringIndexOutOfBoundsException if offset is out of bounds 758: * @see String#valueOf(boolean) 759: */ 760: public CPStringBuilder insert(int offset, boolean bool) 761: { 762: return insert(offset, bool ? "true" : "false"); 763: } 764: 765: /** 766: * Insert the <code>char</code> argument into this <code>StringBuffer</code>. 767: * 768: * @param offset the place to insert in this buffer 769: * @param ch the <code>char</code> to insert 770: * @return this <code>StringBuffer</code> 771: * @throws StringIndexOutOfBoundsException if offset is out of bounds 772: */ 773: public CPStringBuilder insert(int offset, char ch) 774: { 775: if (offset < 0 || offset > count) 776: throw new StringIndexOutOfBoundsException(offset); 777: ensureCapacity(count + 1); 778: System.arraycopy(value, offset, value, offset + 1, count - offset); 779: value[offset] = ch; 780: count++; 781: return this; 782: } 783: 784: /** 785: * Insert the <code>String</code> value of the argument into this 786: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 787: * to <code>String</code>. 788: * 789: * @param offset the place to insert in this buffer 790: * @param inum the <code>int</code> to convert and insert 791: * @return this <code>StringBuffer</code> 792: * @throws StringIndexOutOfBoundsException if offset is out of bounds 793: * @see String#valueOf(int) 794: */ 795: public CPStringBuilder insert(int offset, int inum) 796: { 797: return insert(offset, String.valueOf(inum)); 798: } 799: 800: /** 801: * Insert the <code>String</code> value of the argument into this 802: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 803: * to <code>String</code>. 804: * 805: * @param offset the place to insert in this buffer 806: * @param lnum the <code>long</code> to convert and insert 807: * @return this <code>StringBuffer</code> 808: * @throws StringIndexOutOfBoundsException if offset is out of bounds 809: * @see String#valueOf(long) 810: */ 811: public CPStringBuilder insert(int offset, long lnum) 812: { 813: return insert(offset, Long.toString(lnum, 10)); 814: } 815: 816: /** 817: * Insert the <code>String</code> value of the argument into this 818: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 819: * to <code>String</code>. 820: * 821: * @param offset the place to insert in this buffer 822: * @param fnum the <code>float</code> to convert and insert 823: * @return this <code>StringBuffer</code> 824: * @throws StringIndexOutOfBoundsException if offset is out of bounds 825: * @see String#valueOf(float) 826: */ 827: public CPStringBuilder insert(int offset, float fnum) 828: { 829: return insert(offset, Float.toString(fnum)); 830: } 831: 832: /** 833: * Insert the <code>String</code> value of the argument into this 834: * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert 835: * to <code>String</code>. 836: * 837: * @param offset the place to insert in this buffer 838: * @param dnum the <code>double</code> to convert and insert 839: * @return this <code>StringBuffer</code> 840: * @throws StringIndexOutOfBoundsException if offset is out of bounds 841: * @see String#valueOf(double) 842: */ 843: public CPStringBuilder insert(int offset, double dnum) 844: { 845: return insert(offset, Double.toString(dnum)); 846: } 847: 848: /** 849: * Finds the first instance of a substring in this StringBuilder. 850: * 851: * @param str String to find 852: * @return location (base 0) of the String, or -1 if not found 853: * @throws NullPointerException if str is null 854: * @see #indexOf(String, int) 855: */ 856: public int indexOf(String str) 857: { 858: return indexOf(str, 0); 859: } 860: 861: /** 862: * Finds the first instance of a String in this StringBuffer, starting at 863: * a given index. If starting index is less than 0, the search starts at 864: * the beginning of this String. If the starting index is greater than the 865: * length of this String, or the substring is not found, -1 is returned. 866: * 867: * @param str String to find 868: * @param fromIndex index to start the search 869: * @return location (base 0) of the String, or -1 if not found 870: * @throws NullPointerException if str is null 871: * @since 1.4 872: */ 873: public int indexOf(String str, int fromIndex) 874: { 875: if (fromIndex < 0) 876: fromIndex = 0; 877: int olength = str.length(); 878: int limit = count - olength; 879: String s = VMCPStringBuilder.toString(value, 0, count); 880: for (; fromIndex <= limit; ++fromIndex) 881: if (s.regionMatches(fromIndex, str, 0, olength)) 882: return fromIndex; 883: return -1; 884: } 885: 886: /** 887: * Finds the last instance of a substring in this StringBuffer. 888: * 889: * @param str String to find 890: * @return location (base 0) of the String, or -1 if not found 891: * @throws NullPointerException if str is null 892: * @see #lastIndexOf(String, int) 893: * @since 1.4 894: */ 895: public int lastIndexOf(String str) 896: { 897: return lastIndexOf(str, count - str.length()); 898: } 899: 900: /** 901: * Finds the last instance of a String in this StringBuffer, starting at a 902: * given index. If starting index is greater than the maximum valid index, 903: * then the search begins at the end of this String. If the starting index 904: * is less than zero, or the substring is not found, -1 is returned. 905: * 906: * @param str String to find 907: * @param fromIndex index to start the search 908: * @return location (base 0) of the String, or -1 if not found 909: * @throws NullPointerException if str is null 910: * @since 1.4 911: */ 912: public int lastIndexOf(String str, int fromIndex) 913: { 914: fromIndex = Math.min(fromIndex, count - str.length()); 915: String s = VMCPStringBuilder.toString(value, 0, count); 916: int olength = str.length(); 917: for ( ; fromIndex >= 0; fromIndex--) 918: if (s.regionMatches(fromIndex, str, 0, olength)) 919: return fromIndex; 920: return -1; 921: } 922: 923: /** 924: * Reverse the characters in this StringBuffer. The same sequence of 925: * characters exists, but in the reverse index ordering. 926: * 927: * @return this <code>StringBuffer</code> 928: */ 929: public CPStringBuilder reverse() 930: { 931: // Call ensureCapacity to enforce copy-on-write. 932: ensureCapacity(count); 933: for (int i = count >> 1, j = count - i; --i >= 0; ++j) 934: { 935: char c = value[i]; 936: value[i] = value[j]; 937: value[j] = c; 938: } 939: return this; 940: } 941: 942: /** 943: * This may reduce the amount of memory used by the StringBuffer, 944: * by resizing the internal array to remove unused space. However, 945: * this method is not required to resize, so this behavior cannot 946: * be relied upon. 947: * @since 1.5 948: */ 949: public void trimToSize() 950: { 951: int wouldSave = value.length - count; 952: // Some random heuristics: if we save less than 20 characters, who 953: // cares. 954: if (wouldSave < 20) 955: return; 956: // If we save more than 200 characters, shrink. 957: // If we save more than 1/4 of the buffer, shrink. 958: if (wouldSave > 200 || wouldSave * 4 > value.length) 959: allocateArray(count); 960: } 961: 962: /** 963: * Return the number of code points between two indices in the 964: * <code>StringBuffer</code>. An unpaired surrogate counts as a 965: * code point for this purpose. Characters outside the indicated 966: * range are not examined, even if the range ends in the middle of a 967: * surrogate pair. 968: * 969: * @param start the starting index 970: * @param end one past the ending index 971: * @return the number of code points 972: * @since 1.5 973: */ 974: public int codePointCount(int start, int end) 975: { 976: if (start < 0 || end >= count || start > end) 977: throw new StringIndexOutOfBoundsException(); 978: 979: int count = 0; 980: while (start < end) 981: { 982: char base = value[start]; 983: if (base < Character.MIN_HIGH_SURROGATE 984: || base > Character.MAX_HIGH_SURROGATE 985: || start == end 986: || start == count 987: || value[start + 1] < Character.MIN_LOW_SURROGATE 988: || value[start + 1] > Character.MAX_LOW_SURROGATE) 989: { 990: // Nothing. 991: } 992: else 993: { 994: // Surrogate pair. 995: ++start; 996: } 997: ++start; 998: ++count; 999: } 1000: return count; 1001: } 1002: 1003: /** 1004: * Starting at the given index, this counts forward by the indicated 1005: * number of code points, and then returns the resulting index. An 1006: * unpaired surrogate counts as a single code point for this 1007: * purpose. 1008: * 1009: * @param start the starting index 1010: * @param codePoints the number of code points 1011: * @return the resulting index 1012: * @since 1.5 1013: */ 1014: public int offsetByCodePoints(int start, int codePoints) 1015: { 1016: while (codePoints > 0) 1017: { 1018: char base = value[start]; 1019: if (base < Character.MIN_HIGH_SURROGATE 1020: || base > Character.MAX_HIGH_SURROGATE 1021: || start == count 1022: || value[start + 1] < Character.MIN_LOW_SURROGATE 1023: || value[start + 1] > Character.MAX_LOW_SURROGATE) 1024: { 1025: // Nothing. 1026: } 1027: else 1028: { 1029: // Surrogate pair. 1030: ++start; 1031: } 1032: ++start; 1033: --codePoints; 1034: } 1035: return start; 1036: } 1037: 1038: /** 1039: * Increase the capacity of this <code>StringBuilder</code>. This will 1040: * ensure that an expensive growing operation will not occur until either 1041: * <code>minimumCapacity</code> is reached or the array has been allocated. 1042: * The buffer is grown to either <code>minimumCapacity * 2</code>, if 1043: * the array has been allocated or the larger of <code>minimumCapacity</code> and 1044: * <code>capacity() * 2 + 2</code>, if it is not already large enough. 1045: * 1046: * @param minimumCapacity the new capacity 1047: * @see #length() 1048: */ 1049: public void ensureCapacity(int minimumCapacity) 1050: { 1051: if (allocated || minimumCapacity > value.length) 1052: { 1053: if (minimumCapacity > value.length) 1054: { 1055: int max = value.length * 2 + 2; 1056: minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); 1057: } 1058: else 1059: minimumCapacity *= 2; 1060: allocateArray(minimumCapacity); 1061: } 1062: } 1063: 1064: /** 1065: * Allocates a new character array. This method is triggered when 1066: * a write is attempted after the array has been passed to a 1067: * {@link String} object, so that the builder does not modify 1068: * the immutable {@link String}. 1069: * 1070: * @param capacity the size of the new array. 1071: */ 1072: private void allocateArray(int capacity) 1073: { 1074: char[] nb = new char[capacity]; 1075: System.arraycopy(value, 0, nb, 0, count); 1076: value = nb; 1077: allocated = false; 1078: } 1079: 1080: /** 1081: * Get the length of the <code>String</code> this <code>StringBuilder</code> 1082: * would create. Not to be confused with the <em>capacity</em> of the 1083: * <code>StringBuilder</code>. 1084: * 1085: * @return the length of this <code>StringBuilder</code> 1086: * @see #capacity() 1087: * @see #setLength(int) 1088: */ 1089: public int length() 1090: { 1091: return count; 1092: } 1093: 1094: /** 1095: * Creates a substring of this StringBuilder, starting at a specified index 1096: * and ending at one character before a specified index. This is implemented 1097: * the same as <code>substring(beginIndex, endIndex)</code>, to satisfy 1098: * the CharSequence interface. 1099: * 1100: * @param beginIndex index to start at (inclusive, base 0) 1101: * @param endIndex index to end at (exclusive) 1102: * @return new String which is a substring of this StringBuilder 1103: * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of 1104: * bounds 1105: * @see #substring(int, int) 1106: */ 1107: public CharSequence subSequence(int beginIndex, int endIndex) 1108: { 1109: return substring(beginIndex, endIndex); 1110: } 1111: 1112: /** 1113: * Creates a substring of this CPStringBuilder, starting at a specified index 1114: * and ending at the end of this StringBuilder. 1115: * 1116: * @param beginIndex index to start substring (base 0) 1117: * @return new String which is a substring of this StringBuilder 1118: * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds 1119: * @see #substring(int, int) 1120: */ 1121: public String substring(int beginIndex) 1122: { 1123: return substring(beginIndex, count); 1124: } 1125: 1126: /** 1127: * Creates a substring of this CPStringBuilder, starting at a specified index 1128: * and ending at one character before a specified index. 1129: * 1130: * @param beginIndex index to start at (inclusive, base 0) 1131: * @param endIndex index to end at (exclusive) 1132: * @return new String which is a substring of this StringBuilder 1133: * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out 1134: * of bounds 1135: */ 1136: public String substring(int beginIndex, int endIndex) 1137: { 1138: if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) 1139: throw new StringIndexOutOfBoundsException(); 1140: int len = endIndex - beginIndex; 1141: if (len == 0) 1142: return ""; 1143: allocated = true; 1144: return VMCPStringBuilder.toString(value, beginIndex, len); 1145: } 1146: 1147: /** 1148: * Convert this <code>CPStringBuilder</code> to a <code>String</code>. The 1149: * String is composed of the characters currently in this StringBuilder. Note 1150: * that the result is not a copy, so we flag this here and make sure to 1151: * allocate a new array on the next write attempt (see {@link #ensureCapacity(int)}). 1152: * 1153: * @return the characters in this StringBuilder 1154: */ 1155: public String toString() 1156: { 1157: allocated = true; 1158: return VMCPStringBuilder.toString(value, 0, count); 1159: } 1160: 1161: }