0001: /*
0002: * @(#)StringBuilder.java 1.9 04/07/16
0003: *
0004: * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
0005: * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
0006: */
0007:
0008: package org.wings.util;
0009:
0010: /**
0011: * A mutable sequence of characters. This class provides an API compatible
0012: * with <code>StringBuffer</code>, but with no guarantee of synchronization.
0013: * This class is designed for use as a drop-in replacement for
0014: * <code>StringBuffer</code> in places where the string buffer was being
0015: * used by a single thread (as is generally the case). Where possible,
0016: * it is recommended that this class be used in preference to
0017: * <code>StringBuffer</code> as it will be faster under most implementations.
0018: *
0019: * <p>The principal operations on a <code>StringBuilder</code> are the
0020: * <code>append</code> and <code>insert</code> methods, which are
0021: * overloaded so as to accept data of any type. Each effectively
0022: * converts a given datum to a string and then appends or inserts the
0023: * characters of that string to the string builder. The
0024: * <code>append</code> method always adds these characters at the end
0025: * of the builder; the <code>insert</code> method adds the characters at
0026: * a specified point.
0027: * <p>
0028: * For example, if <code>z</code> refers to a string builder object
0029: * whose current contents are "<code>start</code>", then
0030: * the method call <code>z.append("le")</code> would cause the string
0031: * builder to contain "<code>startle</code>", whereas
0032: * <code>z.insert(4, "le")</code> would alter the string builder to
0033: * contain "<code>starlet</code>".
0034: * <p>
0035: * In general, if sb refers to an instance of a <code>StringBuilder</code>,
0036: * then <code>sb.append(x)</code> has the same effect as
0037: * <code>sb.insert(sb.length(), x)</code>.
0038: *
0039: * Every string builder has a capacity. As long as the length of the
0040: * character sequence contained in the string builder does not exceed
0041: * the capacity, it is not necessary to allocate a new internal
0042: * buffer. If the internal buffer overflows, it is automatically made larger.
0043: *
0044: * <p>Instances of <code>StringBuilder</code> are not safe for
0045: * use by multiple threads. If such synchronization is required then it is
0046: * recommended that {@link java.lang.StringBuffer} be used.
0047: *
0048: * @author Michael McCloskey
0049: * @version 1.9, 07/16/04
0050: * @see java.lang.StringBuffer
0051: * @see java.lang.String
0052: * @since 1.5
0053: */
0054: public final class SStringBuilder implements java.io.Serializable,
0055: CharSequence {
0056: /** use serialVersionUID for interoperability */
0057: static final long serialVersionUID = 4383685877147921099L;
0058:
0059: /**
0060: * The value is used for character storage.
0061: */
0062: char value[];
0063:
0064: /**
0065: * The count is the number of characters used.
0066: */
0067: int count;
0068:
0069: /**
0070: * Constructs a string builder with no characters in it and an
0071: * initial capacity of 16 characters.
0072: */
0073: public SStringBuilder() {
0074: this (16);
0075: }
0076:
0077: /**
0078: * Constructs a string builder with no characters in it and an
0079: * initial capacity specified by the <code>capacity</code> argument.
0080: *
0081: * @param capacity the initial capacity.
0082: * @throws NegativeArraySizeException if the <code>capacity</code>
0083: * argument is less than <code>0</code>.
0084: */
0085: public SStringBuilder(int capacity) {
0086: value = new char[capacity];
0087: }
0088:
0089: /**
0090: * Constructs a string builder initialized to the contents of the
0091: * specified string. The initial capacity of the string builder is
0092: * <code>16</code> plus the length of the string argument.
0093: *
0094: * @param str the initial contents of the buffer.
0095: * @throws NullPointerException if <code>str</code> is <code>null</code>
0096: */
0097: public SStringBuilder(String str) {
0098: this (str.length() + 16);
0099: append(str);
0100: }
0101:
0102: /**
0103: * Constructs a string builder that contains the same characters
0104: * as the specified <code>CharSequence</code>. The initial capacity of
0105: * the string builder is <code>16</code> plus the length of the
0106: * <code>CharSequence</code> argument.
0107: *
0108: * @param seq the sequence to copy.
0109: * @throws NullPointerException if <code>seq</code> is <code>null</code>
0110: */
0111: public SStringBuilder(CharSequence seq) {
0112: this (seq.length() + 16);
0113: append(seq);
0114: }
0115:
0116: /**
0117: * Returns the length (character count).
0118: *
0119: * @return the length of the sequence of characters currently
0120: * represented by this object
0121: */
0122: public int length() {
0123: return count;
0124: }
0125:
0126: /**
0127: * Returns the current capacity. The capacity is the amount of storage
0128: * available for newly inserted characters, beyond which an allocation
0129: * will occur.
0130: *
0131: * @return the current capacity
0132: */
0133: public int capacity() {
0134: return value.length;
0135: }
0136:
0137: /**
0138: * Ensures that the capacity is at least equal to the specified minimum.
0139: * If the current capacity is less than the argument, then a new internal
0140: * array is allocated with greater capacity. The new capacity is the
0141: * larger of:
0142: * <ul>
0143: * <li>The <code>minimumCapacity</code> argument.
0144: * <li>Twice the old capacity, plus <code>2</code>.
0145: * </ul>
0146: * If the <code>minimumCapacity</code> argument is nonpositive, this
0147: * method takes no action and simply returns.
0148: *
0149: * @param minimumCapacity the minimum desired capacity.
0150: */
0151: public void ensureCapacity(int minimumCapacity) {
0152: if (minimumCapacity > value.length) {
0153: expandCapacity(minimumCapacity);
0154: }
0155: }
0156:
0157: /**
0158: * This implements the expansion semantics of ensureCapacity with no
0159: * size check or synchronization.
0160: */
0161: void expandCapacity(int minimumCapacity) {
0162: int newCapacity = (value.length + 1) * 2;
0163: if (newCapacity < 0) {
0164: newCapacity = Integer.MAX_VALUE;
0165: } else if (minimumCapacity > newCapacity) {
0166: newCapacity = minimumCapacity;
0167: }
0168: char newValue[] = new char[newCapacity];
0169: System.arraycopy(value, 0, newValue, 0, count);
0170: value = newValue;
0171: }
0172:
0173: /**
0174: * Attempts to reduce storage used for the character sequence.
0175: * If the buffer is larger than necessary to hold its current sequence of
0176: * characters, then it may be resized to become more space efficient.
0177: * Calling this method may, but is not required to, affect the value
0178: * returned by a subsequent call to the {@link #capacity()} method.
0179: */
0180: public void trimToSize() {
0181: if (count < value.length) {
0182: char[] newValue = new char[count];
0183: System.arraycopy(value, 0, newValue, 0, count);
0184: this .value = newValue;
0185: }
0186: }
0187:
0188: /**
0189: * Sets the length of the character sequence.
0190: * The sequence is changed to a new character sequence
0191: * whose length is specified by the argument. For every nonnegative
0192: * index <i>k</i> less than <code>newLength</code>, the character at
0193: * index <i>k</i> in the new character sequence is the same as the
0194: * character at index <i>k</i> in the old sequence if <i>k</i> is less
0195: * than the length of the old character sequence; otherwise, it is the
0196: * null character <code>'\u0000'</code>.
0197: *
0198: * In other words, if the <code>newLength</code> argument is less than
0199: * the current length, the length is changed to the specified length.
0200: * <p>
0201: * If the <code>newLength</code> argument is greater than or equal
0202: * to the current length, sufficient null characters
0203: * (<code>'\u0000'</code>) are appended so that
0204: * length becomes the <code>newLength</code> argument.
0205: * <p>
0206: * The <code>newLength</code> argument must be greater than or equal
0207: * to <code>0</code>.
0208: *
0209: * @param newLength the new length
0210: * @throws IndexOutOfBoundsException if the
0211: * <code>newLength</code> argument is negative.
0212: */
0213: public void setLength(int newLength) {
0214: if (newLength < 0)
0215: throw new StringIndexOutOfBoundsException(newLength);
0216: if (newLength > value.length)
0217: expandCapacity(newLength);
0218:
0219: if (count < newLength) {
0220: for (; count < newLength; count++)
0221: value[count] = '\0';
0222: } else {
0223: count = newLength;
0224: }
0225: }
0226:
0227: /**
0228: * Returns the <code>char</code> value in this sequence at the specified index.
0229: * The first <code>char</code> value is at index <code>0</code>, the next at index
0230: * <code>1</code>, and so on, as in array indexing.
0231: * <p>
0232: * The index argument must be greater than or equal to
0233: * <code>0</code>, and less than the length of this sequence.
0234: *
0235: * <p>If the <code>char</code> value specified by the index is a
0236: * <a href="Character.html#unicode">surrogate</a>, the surrogate
0237: * value is returned.
0238: *
0239: * @param index the index of the desired <code>char</code> value.
0240: * @return the <code>char</code> value at the specified index.
0241: * @throws IndexOutOfBoundsException if <code>index</code> is
0242: * negative or greater than or equal to <code>length()</code>.
0243: */
0244: public char charAt(int index) {
0245: if ((index < 0) || (index >= count))
0246: throw new StringIndexOutOfBoundsException(index);
0247: return value[index];
0248: }
0249:
0250: /**
0251: * Returns the character (Unicode code point) at the specified
0252: * index. The index refers to <code>char</code> values
0253: * (Unicode code units) and ranges from <code>0</code> to
0254: * {@link #length()}<code> - 1</code>.
0255: *
0256: * <p> If the <code>char</code> value specified at the given index
0257: * is in the high-surrogate range, the following index is less
0258: * than the length of this sequence, and the
0259: * <code>char</code> value at the following index is in the
0260: * low-surrogate range, then the supplementary code point
0261: * corresponding to this surrogate pair is returned. Otherwise,
0262: * the <code>char</code> value at the given index is returned.
0263: *
0264: * @param index the index to the <code>char</code> values
0265: * @return the code point value of the character at the
0266: * <code>index</code>
0267: * @exception IndexOutOfBoundsException if the <code>index</code>
0268: * argument is negative or not less than the length of this
0269: * sequence.
0270: */
0271: // TODO: Character.codePointAt(value, index) since JDK 1.5
0272: // public int codePointAt(int index) {
0273: // if ((index < 0) || (index >= count)) {
0274: // throw new StringIndexOutOfBoundsException(index);
0275: // }
0276: // return Character.codePointAt(value, index);
0277: // }
0278: /**
0279: * Returns the character (Unicode code point) before the specified
0280: * index. The index refers to <code>char</code> values
0281: * (Unicode code units) and ranges from <code>1</code> to {@link
0282: * #length()}.
0283: *
0284: * <p> If the <code>char</code> value at <code>(index - 1)</code>
0285: * is in the low-surrogate range, <code>(index - 2)</code> is not
0286: * negative, and the <code>char</code> value at <code>(index -
0287: * 2)</code> is in the high-surrogate range, then the
0288: * supplementary code point value of the surrogate pair is
0289: * returned. If the <code>char</code> value at <code>index -
0290: * 1</code> is an unpaired low-surrogate or a high-surrogate, the
0291: * surrogate value is returned.
0292: *
0293: * @param index the index following the code point that should be returned
0294: * @return the Unicode code point value before the given index.
0295: * @exception IndexOutOfBoundsException if the <code>index</code>
0296: * argument is less than 1 or greater than the length
0297: * of this sequence.
0298: */
0299: // TODO: Character.codePointBefore(value, index) since JDK 1.5
0300: // public int codePointBefore(int index) {
0301: // int i = index - 1;
0302: // if ((i < 0) || (i >= count)) {
0303: // throw new StringIndexOutOfBoundsException(index);
0304: // }
0305: // return Character.codePointBefore(value, index);
0306: // }
0307: /**
0308: * Returns the number of Unicode code points in the specified text
0309: * range of this sequence. The text range begins at the specified
0310: * <code>beginIndex</code> and extends to the <code>char</code> at
0311: * index <code>endIndex - 1</code>. Thus the length (in
0312: * <code>char</code>s) of the text range is
0313: * <code>endIndex-beginIndex</code>. Unpaired surrogates within
0314: * this sequence count as one code point each.
0315: *
0316: * @param beginIndex the index to the first <code>char</code> of
0317: * the text range.
0318: * @param endIndex the index after the last <code>char</code> of
0319: * the text range.
0320: * @return the number of Unicode code points in the specified text
0321: * range
0322: * @exception IndexOutOfBoundsException if the
0323: * <code>beginIndex</code> is negative, or <code>endIndex</code>
0324: * is larger than the length of this sequence, or
0325: * <code>beginIndex</code> is larger than <code>endIndex</code>.
0326: */
0327: // public int codePointCount(int beginIndex, int endIndex) {
0328: // if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
0329: // throw new IndexOutOfBoundsException();
0330: // }
0331: // return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
0332: // }
0333: //
0334: /**
0335: * Returns the index within this sequence that is offset from the
0336: * given <code>index</code> by <code>codePointOffset</code> code
0337: * points. Unpaired surrogates within the text range given by
0338: * <code>index</code> and <code>codePointOffset</code> count as
0339: * one code point each.
0340: *
0341: * @param index the index to be offset
0342: * @param codePointOffset the offset in code points
0343: * @return the index within this sequence
0344: * @exception IndexOutOfBoundsException if <code>index</code>
0345: * is negative or larger then the length of this sequence,
0346: * or if <code>codePointOffset</code> is positive and the subsequence
0347: * starting with <code>index</code> has fewer than
0348: * <code>codePointOffset</code> code points,
0349: * or if <code>codePointOffset</code> is negative and the subsequence
0350: * before <code>index</code> has fewer than the absolute value of
0351: * <code>codePointOffset</code> code points.
0352: */
0353: // public int offsetByCodePoints(int index, int codePointOffset) {
0354: // if (index < 0 || index > count) {
0355: // throw new IndexOutOfBoundsException();
0356: // }
0357: // return Character.offsetByCodePointsImpl(value, 0, count,
0358: // index, codePointOffset);
0359: // }
0360: //
0361: /**
0362: * Characters are copied from this sequence into the
0363: * destination character array <code>dst</code>. The first character to
0364: * be copied is at index <code>srcBegin</code>; the last character to
0365: * be copied is at index <code>srcEnd-1</code>. The total number of
0366: * characters to be copied is <code>srcEnd-srcBegin</code>. The
0367: * characters are copied into the subarray of <code>dst</code> starting
0368: * at index <code>dstBegin</code> and ending at index:
0369: * <p><blockquote><pre>
0370: * dstbegin + (srcEnd-srcBegin) - 1
0371: * </pre></blockquote>
0372: *
0373: * @param srcBegin start copying at this offset.
0374: * @param srcEnd stop copying at this offset.
0375: * @param dst the array to copy the data into.
0376: * @param dstBegin offset into <code>dst</code>.
0377: * @throws NullPointerException if <code>dst</code> is
0378: * <code>null</code>.
0379: * @throws IndexOutOfBoundsException if any of the following is true:
0380: * <ul>
0381: * <li><code>srcBegin</code> is negative
0382: * <li><code>dstBegin</code> is negative
0383: * <li>the <code>srcBegin</code> argument is greater than
0384: * the <code>srcEnd</code> argument.
0385: * <li><code>srcEnd</code> is greater than
0386: * <code>this.length()</code>.
0387: * <li><code>dstBegin+srcEnd-srcBegin</code> is greater than
0388: * <code>dst.length</code>
0389: * </ul>
0390: */
0391: public void getChars(int srcBegin, int srcEnd, char dst[],
0392: int dstBegin) {
0393: if (srcBegin < 0)
0394: throw new StringIndexOutOfBoundsException(srcBegin);
0395: if ((srcEnd < 0) || (srcEnd > count))
0396: throw new StringIndexOutOfBoundsException(srcEnd);
0397: if (srcBegin > srcEnd)
0398: throw new StringIndexOutOfBoundsException(
0399: "srcBegin > srcEnd");
0400: System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd
0401: - srcBegin);
0402: }
0403:
0404: /**
0405: * The character at the specified index is set to <code>ch</code>. This
0406: * sequence is altered to represent a new character sequence that is
0407: * identical to the old character sequence, except that it contains the
0408: * character <code>ch</code> at position <code>index</code>.
0409: * <p>
0410: * The index argument must be greater than or equal to
0411: * <code>0</code>, and less than the length of this sequence.
0412: *
0413: * @param index the index of the character to modify.
0414: * @param ch the new character.
0415: * @throws IndexOutOfBoundsException if <code>index</code> is
0416: * negative or greater than or equal to <code>length()</code>.
0417: */
0418: public void setCharAt(int index, char ch) {
0419: if ((index < 0) || (index >= count))
0420: throw new StringIndexOutOfBoundsException(index);
0421: value[index] = ch;
0422: }
0423:
0424: /**
0425: * Appends the string representation of the <code>Object</code>
0426: * argument.
0427: * <p>
0428: * The argument is converted to a string as if by the method
0429: * <code>String.valueOf</code>, and the characters of that
0430: * string are then appended to this sequence.
0431: *
0432: * @param obj an <code>Object</code>.
0433: * @return a reference to this object.
0434: */
0435: public SStringBuilder append(Object obj) {
0436: return append(String.valueOf(obj));
0437: }
0438:
0439: /**
0440: * Appends the specified string to this character sequence.
0441: * <p>
0442: * The characters of the <code>String</code> argument are appended, in
0443: * order, increasing the length of this sequence by the length of the
0444: * argument. If <code>str</code> is <code>null</code>, then the four
0445: * characters <code>"null"</code> are appended.
0446: * <p>
0447: * Let <i>n</i> be the length of this character sequence just prior to
0448: * execution of the <code>append</code> method. Then the character at
0449: * index <i>k</i> in the new character sequence is equal to the character
0450: * at index <i>k</i> in the old character sequence, if <i>k</i> is less
0451: * than <i>n</i>; otherwise, it is equal to the character at index
0452: * <i>k-n</i> in the argument <code>str</code>.
0453: *
0454: * @param str a string.
0455: * @return a reference to this object.
0456: */
0457: public SStringBuilder append(String str) {
0458: if (str == null)
0459: str = "null";
0460: int len = str.length();
0461: if (len == 0)
0462: return this ;
0463: int newCount = count + len;
0464: if (newCount > value.length)
0465: expandCapacity(newCount);
0466: str.getChars(0, len, value, count);
0467: count = newCount;
0468: return this ;
0469: }
0470:
0471: // Documentation in subclasses because of synchro difference
0472: public SStringBuilder append(StringBuffer sb) {
0473: if (sb == null)
0474: return append("null");
0475: int len = sb.length();
0476: int newCount = count + len;
0477: if (newCount > value.length)
0478: expandCapacity(newCount);
0479: sb.getChars(0, len, value, count);
0480: count = newCount;
0481: return this ;
0482: }
0483:
0484: /**
0485: * Appends a subsequence of the specified <code>CharSequence</code> to this
0486: * sequence.
0487: * <p>
0488: * Characters of the argument <code>s</code>, starting at
0489: * index <code>start</code>, are appended, in order, to the contents of
0490: * this sequence up to the (exclusive) index <code>end</code>. The length
0491: * of this sequence is increased by the value of <code>end - start</code>.
0492: * <p>
0493: * Let <i>n</i> be the length of this character sequence just prior to
0494: * execution of the <code>append</code> method. Then the character at
0495: * index <i>k</i> in this character sequence becomes equal to the
0496: * character at index <i>k</i> in this sequence, if <i>k</i> is less than
0497: * <i>n</i>; otherwise, it is equal to the character at index
0498: * <i>k+start-n</i> in the argument <code>s</code>.
0499: * <p>
0500: * If <code>s</code> is <code>null</code>, then this method appends
0501: * characters as if the s parameter was a sequence containing the four
0502: * characters <code>"null"</code>.
0503: *
0504: * @param s the sequence to append.
0505: * @param start the starting index of the subsequence to be appended.
0506: * @param end the end index of the subsequence to be appended.
0507: * @return a reference to this object.
0508: * @throws IndexOutOfBoundsException if
0509: * <code>start</code> or <code>end</code> are negative, or
0510: * <code>start</code> is greater than <code>end</code> or
0511: * <code>end</code> is greater than <code>s.length()</code>
0512: */
0513: public SStringBuilder append(CharSequence s, int start, int end) {
0514: if (s == null)
0515: s = "null";
0516: if ((start < 0) || (end < 0) || (start > end)
0517: || (end > s.length()))
0518: throw new IndexOutOfBoundsException("start " + start
0519: + ", end " + end + ", s.length() " + s.length());
0520: int len = end - start;
0521: if (len == 0)
0522: return this ;
0523: int newCount = count + len;
0524: if (newCount > value.length)
0525: expandCapacity(newCount);
0526: for (int i = start; i < end; i++)
0527: value[count++] = s.charAt(i);
0528: count = newCount;
0529: return this ;
0530: }
0531:
0532: /**
0533: * Appends the string representation of the <code>char</code> array
0534: * argument to this sequence.
0535: * <p>
0536: * The characters of the array argument are appended, in order, to
0537: * the contents of this sequence. The length of this sequence
0538: * increases by the length of the argument.
0539: * <p>
0540: * The overall effect is exactly as if the argument were converted to
0541: * a string by the method {@link String#valueOf(char[])} and the
0542: * characters of that string were then {@link #append(String) appended}
0543: * to this character sequence.
0544: *
0545: * @param str the characters to be appended.
0546: * @return a reference to this object.
0547: */
0548: public SStringBuilder append(char str[]) {
0549: int newCount = count + str.length;
0550: if (newCount > value.length)
0551: expandCapacity(newCount);
0552: System.arraycopy(str, 0, value, count, str.length);
0553: count = newCount;
0554: return this ;
0555: }
0556:
0557: /**
0558: * Appends the string representation of a subarray of the
0559: * <code>char</code> array argument to this sequence.
0560: * <p>
0561: * Characters of the <code>char</code> array <code>str</code>, starting at
0562: * index <code>offset</code>, are appended, in order, to the contents
0563: * of this sequence. The length of this sequence increases
0564: * by the value of <code>len</code>.
0565: * <p>
0566: * The overall effect is exactly as if the arguments were converted to
0567: * a string by the method {@link String#valueOf(char[],int,int)} and the
0568: * characters of that string were then {@link #append(String) appended}
0569: * to this character sequence.
0570: *
0571: * @param str the characters to be appended.
0572: * @param offset the index of the first <code>char</code> to append.
0573: * @param len the number of <code>char</code>s to append.
0574: * @return a reference to this object.
0575: */
0576: public SStringBuilder append(char str[], int offset, int len) {
0577: int newCount = count + len;
0578: if (newCount > value.length)
0579: expandCapacity(newCount);
0580: System.arraycopy(str, offset, value, count, len);
0581: count = newCount;
0582: return this ;
0583: }
0584:
0585: /**
0586: * Appends the string representation of the <code>boolean</code>
0587: * argument to the sequence.
0588: * <p>
0589: * The argument is converted to a string as if by the method
0590: * <code>String.valueOf</code>, and the characters of that
0591: * string are then appended to this sequence.
0592: *
0593: * @param b a <code>boolean</code>.
0594: * @return a reference to this object.
0595: */
0596: public SStringBuilder append(boolean b) {
0597: if (b) {
0598: int newCount = count + 4;
0599: if (newCount > value.length)
0600: expandCapacity(newCount);
0601: value[count++] = 't';
0602: value[count++] = 'r';
0603: value[count++] = 'u';
0604: value[count++] = 'e';
0605: } else {
0606: int newCount = count + 5;
0607: if (newCount > value.length)
0608: expandCapacity(newCount);
0609: value[count++] = 'f';
0610: value[count++] = 'a';
0611: value[count++] = 'l';
0612: value[count++] = 's';
0613: value[count++] = 'e';
0614: }
0615: return this ;
0616: }
0617:
0618: /**
0619: * Appends the string representation of the <code>char</code>
0620: * argument to this sequence.
0621: * <p>
0622: * The argument is appended to the contents of this sequence.
0623: * The length of this sequence increases by <code>1</code>.
0624: * <p>
0625: * The overall effect is exactly as if the argument were converted to
0626: * a string by the method {@link String#valueOf(char)} and the character
0627: * in that string were then {@link #append(String) appended} to this
0628: * character sequence.
0629: *
0630: * @param c a <code>char</code>.
0631: * @return a reference to this object.
0632: */
0633: public SStringBuilder append(char c) {
0634: int newCount = count + 1;
0635: if (newCount > value.length)
0636: expandCapacity(newCount);
0637: value[count++] = c;
0638: return this ;
0639: }
0640:
0641: /**
0642: * Appends the string representation of the <code>int</code>
0643: * argument to this sequence.
0644: * <p>
0645: * The argument is converted to a string as if by the method
0646: * <code>String.valueOf</code>, and the characters of that
0647: * string are then appended to this sequence.
0648: *
0649: * @param i an <code>int</code>.
0650: * @return a reference to this object.
0651: */
0652: public SStringBuilder append(int i) {
0653: if (i == Integer.MIN_VALUE) {
0654: append("-2147483648");
0655: return this ;
0656: }
0657: append(String.valueOf(i));
0658: return this ;
0659: }
0660:
0661: final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999,
0662: 9999999, 99999999, 999999999, Integer.MAX_VALUE };
0663:
0664: // Requires positive x
0665: static int stringSizeOfInt(int x) {
0666: for (int i = 0;; i++)
0667: if (x <= sizeTable[i])
0668: return i + 1;
0669: }
0670:
0671: /**
0672: * Appends the string representation of the <code>long</code>
0673: * argument to this sequence.
0674: * <p>
0675: * The argument is converted to a string as if by the method
0676: * <code>String.valueOf</code>, and the characters of that
0677: * string are then appended to this sequence.
0678: *
0679: * @param l a <code>long</code>.
0680: * @return a reference to this object.
0681: */
0682: public SStringBuilder append(long l) {
0683: if (l == Long.MIN_VALUE) {
0684: append("-9223372036854775808");
0685: return this ;
0686: }
0687: append(String.valueOf(l));
0688: return this ;
0689: }
0690:
0691: // Requires positive x
0692: static int stringSizeOfLong(long x) {
0693: long p = 10;
0694: for (int i = 1; i < 19; i++) {
0695: if (x < p)
0696: return i;
0697: p = 10 * p;
0698: }
0699: return 19;
0700: }
0701:
0702: /**
0703: * Appends the string representation of the <code>float</code>
0704: * argument to this sequence.
0705: * <p>
0706: * The argument is converted to a string as if by the method
0707: * <code>String.valueOf</code>, and the characters of that
0708: * string are then appended to this string sequence.
0709: *
0710: * @param f a <code>float</code>.
0711: * @return a reference to this object.
0712: */
0713: public SStringBuilder append(float f) {
0714: append(String.valueOf(f));
0715: return this ;
0716: }
0717:
0718: /**
0719: * Appends the string representation of the <code>double</code>
0720: * argument to this sequence.
0721: * <p>
0722: * The argument is converted to a string as if by the method
0723: * <code>String.valueOf</code>, and the characters of that
0724: * string are then appended to this sequence.
0725: *
0726: * @param d a <code>double</code>.
0727: * @return a reference to this object.
0728: */
0729: public SStringBuilder append(double d) {
0730: append(String.valueOf(d));
0731: return this ;
0732: }
0733:
0734: /**
0735: * Removes the characters in a substring of this sequence.
0736: * The substring begins at the specified <code>start</code> and extends to
0737: * the character at index <code>end - 1</code> or to the end of the
0738: * sequence if no such character exists. If
0739: * <code>start</code> is equal to <code>end</code>, no changes are made.
0740: *
0741: * @param start The beginning index, inclusive.
0742: * @param end The ending index, exclusive.
0743: * @return This object.
0744: * @throws StringIndexOutOfBoundsException if <code>start</code>
0745: * is negative, greater than <code>length()</code>, or
0746: * greater than <code>end</code>.
0747: */
0748: public SStringBuilder delete(int start, int end) {
0749: if (start < 0)
0750: throw new StringIndexOutOfBoundsException(start);
0751: if (end > count)
0752: end = count;
0753: if (start > end)
0754: throw new StringIndexOutOfBoundsException();
0755: int len = end - start;
0756: if (len > 0) {
0757: System.arraycopy(value, start + len, value, start, count
0758: - end);
0759: count -= len;
0760: }
0761: return this ;
0762: }
0763:
0764: /**
0765: * Appends the string representation of the <code>codePoint</code>
0766: * argument to this sequence.
0767: *
0768: * <p> The argument is appended to the contents of this sequence.
0769: * The length of this sequence increases by
0770: * {@link Character#charCount(int) Character.charCount(codePoint)}.
0771: *
0772: * <p> The overall effect is exactly as if the argument were
0773: * converted to a <code>char</code> array by the method {@link
0774: * Character#toChars(int)} and the character in that array were
0775: * then {@link #append(char[]) appended} to this character
0776: * sequence.
0777: *
0778: * @param codePoint a Unicode code point
0779: * @return a reference to this object.
0780: * @exception IllegalArgumentException if the specified
0781: * <code>codePoint</code> isn't a valid Unicode code point
0782: */
0783: // public StringBuilder appendCodePoint(int codePoint) {
0784: // if (!Character.isValidCodePoint(codePoint)) {
0785: // throw new IllegalArgumentException();
0786: // }
0787: // int n = 1;
0788: // if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
0789: // n++;
0790: // }
0791: // int newCount = count + n;
0792: // if (newCount > value.length) {
0793: // expandCapacity(newCount);
0794: // }
0795: // if (n == 1) {
0796: // value[count++] = (char) codePoint;
0797: // } else {
0798: // Character.toSurrogates(codePoint, value, count);
0799: // count += n;
0800: // }
0801: // return this;
0802: // }
0803: //
0804: /**
0805: * Removes the <code>char</code> at the specified position in this
0806: * sequence. This sequence is shortened by one <code>char</code>.
0807: *
0808: * <p>Note: If the character at the given index is a supplementary
0809: * character, this method does not remove the entire character. If
0810: * correct handling of supplementary characters is required,
0811: * determine the number of <code>char</code>s to remove by calling
0812: * <code>Character.charCount(thisSequence.codePointAt(index))</code>,
0813: * where <code>thisSequence</code> is this sequence.
0814: *
0815: * @param index Index of <code>char</code> to remove
0816: * @return This object.
0817: * @throws StringIndexOutOfBoundsException if the <code>index</code>
0818: * is negative or greater than or equal to
0819: * <code>length()</code>.
0820: */
0821: public SStringBuilder deleteCharAt(int index) {
0822: if ((index < 0) || (index >= count))
0823: throw new StringIndexOutOfBoundsException(index);
0824: System.arraycopy(value, index + 1, value, index, count - index
0825: - 1);
0826: count--;
0827: return this ;
0828: }
0829:
0830: /**
0831: * Replaces the characters in a substring of this sequence
0832: * with characters in the specified <code>String</code>. The substring
0833: * begins at the specified <code>start</code> and extends to the character
0834: * at index <code>end - 1</code> or to the end of the
0835: * sequence if no such character exists. First the
0836: * characters in the substring are removed and then the specified
0837: * <code>String</code> is inserted at <code>start</code>. (This
0838: * sequence will be lengthened to accommodate the
0839: * specified String if necessary.)
0840: *
0841: * @param start The beginning index, inclusive.
0842: * @param end The ending index, exclusive.
0843: * @param str String that will replace previous contents.
0844: * @return This object.
0845: * @throws StringIndexOutOfBoundsException if <code>start</code>
0846: * is negative, greater than <code>length()</code>, or
0847: * greater than <code>end</code>.
0848: */
0849: // public StringBuilder replace(int start, int end, String str) {
0850: // if (start < 0)
0851: // throw new StringIndexOutOfBoundsException(start);
0852: // if (end > count)
0853: // end = count;
0854: // if (start > end)
0855: // throw new StringIndexOutOfBoundsException("start > end");
0856: //
0857: // int len = str.length();
0858: // int newCount = count + len - (end - start);
0859: // if (newCount > value.length)
0860: // expandCapacity(newCount);
0861: //
0862: // System.arraycopy(value, end, value, start + len, count - end);
0863: // str.getChars(value, start);
0864: // count = newCount;
0865: // return this;
0866: // }
0867: //
0868: /**
0869: * Returns a new <code>String</code> that contains a subsequence of
0870: * characters currently contained in this character sequence. The
0871: * substring begins at the specified index and extends to the end of
0872: * this sequence.
0873: *
0874: * @param start The beginning index, inclusive.
0875: * @return The new string.
0876: * @throws StringIndexOutOfBoundsException if <code>start</code> is
0877: * less than zero, or greater than the length of this object.
0878: */
0879: public String substring(int start) {
0880: return substring(start, count);
0881: }
0882:
0883: /**
0884: * Returns a new character sequence that is a subsequence of this sequence.
0885: *
0886: * <p> An invocation of this method of the form
0887: *
0888: * <blockquote><pre>
0889: * sb.subSequence(begin, end)</pre></blockquote>
0890: *
0891: * behaves in exactly the same way as the invocation
0892: *
0893: * <blockquote><pre>
0894: * sb.substring(begin, end)</pre></blockquote>
0895: *
0896: * This method is provided so that this class can
0897: * implement the {@link CharSequence} interface. </p>
0898: *
0899: * @param start the start index, inclusive.
0900: * @param end the end index, exclusive.
0901: * @return the specified subsequence.
0902: *
0903: * @throws IndexOutOfBoundsException
0904: * if <tt>start</tt> or <tt>end</tt> are negative,
0905: * if <tt>end</tt> is greater than <tt>length()</tt>,
0906: * or if <tt>start</tt> is greater than <tt>end</tt>
0907: * @spec JSR-51
0908: */
0909: public CharSequence subSequence(int start, int end) {
0910: return substring(start, end);
0911: }
0912:
0913: /**
0914: * Returns a new <code>String</code> that contains a subsequence of
0915: * characters currently contained in this sequence. The
0916: * substring begins at the specified <code>start</code> and
0917: * extends to the character at index <code>end - 1</code>.
0918: *
0919: * @param start The beginning index, inclusive.
0920: * @param end The ending index, exclusive.
0921: * @return The new string.
0922: * @throws StringIndexOutOfBoundsException if <code>start</code>
0923: * or <code>end</code> are negative or greater than
0924: * <code>length()</code>, or <code>start</code> is
0925: * greater than <code>end</code>.
0926: */
0927: public String substring(int start, int end) {
0928: if (start < 0)
0929: throw new StringIndexOutOfBoundsException(start);
0930: if (end > count)
0931: throw new StringIndexOutOfBoundsException(end);
0932: if (start > end)
0933: throw new StringIndexOutOfBoundsException(end - start);
0934: return new String(value, start, end - start);
0935: }
0936:
0937: /**
0938: * Returns the index within this string of the first occurrence of the
0939: * specified substring. The integer returned is the smallest value
0940: * <i>k</i> such that:
0941: * <blockquote><pre>
0942: * this.toString().startsWith(str, <i>k</i>)
0943: * </pre></blockquote>
0944: * is <code>true</code>.
0945: *
0946: * @param str any string.
0947: * @return if the string argument occurs as a substring within this
0948: * object, then the index of the first character of the first
0949: * such substring is returned; if it does not occur as a
0950: * substring, <code>-1</code> is returned.
0951: * @throws java.lang.NullPointerException if <code>str</code> is
0952: * <code>null</code>.
0953: */
0954: // public int indexOf(String str) {
0955: // return indexOf(str, 0);
0956: // }
0957: /**
0958: * Returns the index within this string of the first occurrence of the
0959: * specified substring, starting at the specified index. The integer
0960: * returned is the smallest value <tt>k</tt> for which:
0961: * <blockquote><pre>
0962: * k >= Math.min(fromIndex, str.length()) &&
0963: * this.toString().startsWith(str, k)
0964: * </pre></blockquote>
0965: * If no such value of <i>k</i> exists, then -1 is returned.
0966: *
0967: * @param str the substring for which to search.
0968: * @param fromIndex the index from which to start the search.
0969: * @return the index within this string of the first occurrence of the
0970: * specified substring, starting at the specified index.
0971: * @throws java.lang.NullPointerException if <code>str</code> is
0972: * <code>null</code>.
0973: */
0974: // public int indexOf(String str, int fromIndex) {
0975: // return String.indexOf(value, 0, count,
0976: // str.toCharArray(), 0, str.length(), fromIndex);
0977: // }
0978: //
0979: /**
0980: * Returns the index within this string of the rightmost occurrence
0981: * of the specified substring. The rightmost empty string "" is
0982: * considered to occur at the index value <code>this.length()</code>.
0983: * The returned index is the largest value <i>k</i> such that
0984: * <blockquote><pre>
0985: * this.toString().startsWith(str, k)
0986: * </pre></blockquote>
0987: * is true.
0988: *
0989: * @param str the substring to search for.
0990: * @return if the string argument occurs one or more times as a substring
0991: * within this object, then the index of the first character of
0992: * the last such substring is returned. If it does not occur as
0993: * a substring, <code>-1</code> is returned.
0994: * @throws java.lang.NullPointerException if <code>str</code> is
0995: * <code>null</code>.
0996: */
0997: // public int lastIndexOf(String str) {
0998: // return lastIndexOf(str, count);
0999: // }
1000: //
1001: /**
1002: * Returns the index within this string of the last occurrence of the
1003: * specified substring. The integer returned is the largest value <i>k</i>
1004: * such that:
1005: * <blockquote><pre>
1006: * k <= Math.min(fromIndex, str.length()) &&
1007: * this.toString().startsWith(str, k)
1008: * </pre></blockquote>
1009: * If no such value of <i>k</i> exists, then -1 is returned.
1010: *
1011: * @param str the substring to search for.
1012: * @param fromIndex the index to start the search from.
1013: * @return the index within this sequence of the last occurrence of the
1014: * specified substring.
1015: * @throws java.lang.NullPointerException if <code>str</code> is
1016: * <code>null</code>.
1017: */
1018: // public int lastIndexOf(String str, int fromIndex) {
1019: // return String.lastIndexOf(value, 0, count,
1020: // str.toCharArray(), 0, str.length(), fromIndex);
1021: // }
1022: /**
1023: * Causes this character sequence to be replaced by the reverse of
1024: * the sequence. If there are any surrogate pairs included in the
1025: * sequence, these are treated as single characters for the
1026: * reverse operation. Thus, the order of the high-low surrogates
1027: * is never reversed.
1028: *
1029: * Let <i>n</i> be the character length of this character sequence
1030: * (not the length in <code>char</code> values) just prior to
1031: * execution of the <code>reverse</code> method. Then the
1032: * character at index <i>k</i> in the new character sequence is
1033: * equal to the character at index <i>n-k-1</i> in the old
1034: * character sequence.
1035: *
1036: * <p>Note that the reverse operation may result in producing
1037: * surrogate pairs that were unpaired low-surrogates and
1038: * high-surrogates before the operation. For example, reversing
1039: * "\uDC00\uD800" produces "\uD800\uDC00" which is
1040: * a valid surrogate pair.
1041: *
1042: * @return a reference to this object.
1043: */
1044: // TODO: Character.reverse() since JDK 1.5
1045: // public SStringBuilder reverse() {
1046: // boolean hasSurrogate = false;
1047: // int n = count - 1;
1048: // for (int j = (n-1) >> 1; j >= 0; --j) {
1049: // char temp = value[j];
1050: // char temp2 = value[n - j];
1051: // if (!hasSurrogate) {
1052: // hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
1053: // || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
1054: // }
1055: // value[j] = temp2;
1056: // value[n - j] = temp;
1057: // }
1058: // if (hasSurrogate) {
1059: // // Reverse back all valid surrogate pairs
1060: // for (int i = 0; i < count - 1; i++) {
1061: // char c2 = value[i];
1062: // if (Character.isLowSurrogate(c2)) {
1063: // char c1 = value[i + 1];
1064: // if (Character.isHighSurrogate(c1)) {
1065: // value[i++] = c1;
1066: // value[i] = c2;
1067: // }
1068: // }
1069: // }
1070: // }
1071: // return this;
1072: // }
1073: /**
1074: * Needed by <tt>String</tt> for the contentEquals method.
1075: */
1076: final char[] getValue() {
1077: return value;
1078: }
1079:
1080: // Appends the specified string builder to this sequence.
1081: private SStringBuilder append(SStringBuilder sb) {
1082: if (sb == null)
1083: return append("null");
1084: int len = sb.length();
1085: int newcount = count + len;
1086: if (newcount > value.length)
1087: expandCapacity(newcount);
1088: sb.getChars(0, len, value, count);
1089: count = newcount;
1090: return this ;
1091: }
1092:
1093: /**
1094: * @throws IndexOutOfBoundsException {@inheritDoc}
1095: */
1096: public SStringBuilder append(CharSequence s) {
1097: if (s == null)
1098: s = "null";
1099: if (s instanceof String)
1100: return this .append((String) s);
1101: if (s instanceof StringBuffer)
1102: return this .append((StringBuffer) s);
1103: if (s instanceof SStringBuilder)
1104: return this .append((SStringBuilder) s);
1105: return this .append(s, 0, s.length());
1106: }
1107:
1108: public String toString() {
1109: // Create a copy, don't share the array
1110: return new String(value, 0, count);
1111: }
1112:
1113: /**
1114: * Save the state of the <tt>StringBuilder</tt> instance to a stream
1115: * (that is, serialize it).
1116: *
1117: * @serialData the number of characters currently stored in the string
1118: * builder (<tt>int</tt>), followed by the characters in the
1119: * string builder (<tt>char[]</tt>). The length of the
1120: * <tt>char</tt> array may be greater than the number of
1121: * characters currently stored in the string builder, in which
1122: * case extra characters are ignored.
1123: */
1124: private void writeObject(java.io.ObjectOutputStream s)
1125: throws java.io.IOException {
1126: s.defaultWriteObject();
1127: s.writeInt(count);
1128: s.writeObject(value);
1129: }
1130:
1131: /**
1132: * readObject is called to restore the state of the StringBuffer from
1133: * a stream.
1134: */
1135: private void readObject(java.io.ObjectInputStream s)
1136: throws java.io.IOException, ClassNotFoundException {
1137: s.defaultReadObject();
1138: count = s.readInt();
1139: value = (char[]) s.readObject();
1140: }
1141:
1142: /**
1143: * Inserts the string into this character sequence.
1144: * <p>
1145: * The characters of the <code>String</code> argument are inserted, in
1146: * order, into this sequence at the indicated offset, moving up any
1147: * characters originally above that position and increasing the length
1148: * of this sequence by the length of the argument. If
1149: * <code>str</code> is <code>null</code>, then the four characters
1150: * <code>"null"</code> are inserted into this sequence.
1151: * <p>
1152: * The character at index <i>k</i> in the new character sequence is
1153: * equal to:
1154: * <ul>
1155: * <li>the character at index <i>k</i> in the old character sequence, if
1156: * <i>k</i> is less than <code>offset</code>
1157: * <li>the character at index <i>k</i><code>-offset</code> in the
1158: * argument <code>str</code>, if <i>k</i> is not less than
1159: * <code>offset</code> but is less than <code>offset+str.length()</code>
1160: * <li>the character at index <i>k</i><code>-str.length()</code> in the
1161: * old character sequence, if <i>k</i> is not less than
1162: * <code>offset+str.length()</code>
1163: * </ul><p>
1164: * The offset argument must be greater than or equal to
1165: * <code>0</code>, and less than or equal to the length of this
1166: * sequence.
1167: *
1168: * @param offset the offset.
1169: * @param str a string.
1170: * @return a reference to this object.
1171: * @throws StringIndexOutOfBoundsException if the offset is invalid.
1172: */
1173: public SStringBuilder insert(int offset, String str) {
1174: if ((offset < 0) || (offset > length()))
1175: throw new StringIndexOutOfBoundsException(offset);
1176: if (str == null)
1177: str = "null";
1178: int len = str.length();
1179: int newCount = count + len;
1180: if (newCount > value.length)
1181: expandCapacity(newCount);
1182: System.arraycopy(value, offset, value, offset + len, count
1183: - offset);
1184: System.arraycopy(str.toCharArray(), 0, value, offset, str
1185: .length());
1186: count = newCount;
1187: return this;
1188: }
1189:
1190: }
|