Source for gnu.java.lang.CPStringBuilder

   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 &gt;= 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 &gt;= 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 &gt;= 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 &gt;= 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: }