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