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