/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.wicket.util.string; import java.io.IOException; /** * This is a copy or combination of <code>java.lang.StringBuffer</code> and * <code>java.lang.String</code> It has a special method getValue() which returns the internal char * array. * * Hashcode and equals methods are also implemented. * * This AppendingStringBuffer is not synchronized. * * @author Johan Compagner * @see java.lang.StringBuffer */ public final class AppendingStringBuffer implements java.io.Serializable, CharSequence { /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 1L; private static final AppendingStringBuffer NULL = new AppendingStringBuffer("null"); private static final StringBuilder SB_NULL = new StringBuilder("null"); private static final StringBuffer SBF_NULL = new StringBuffer("null"); /** * The value is used for character storage. * * @serial */ private char value[]; /** * The count is the number of characters in the buffer. * * @serial */ private int count; /** * Constructs a string buffer with no characters in it and an initial capacity of 16 characters. */ public AppendingStringBuffer() { this(16); } /** * Constructs a string buffer with no characters in it and an initial capacity specified by the * <code>length</code> argument. * * @param length * the initial capacity. * @exception NegativeArraySizeException * if the <code>length</code> argument is less than <code>0</code>. */ public AppendingStringBuffer(final int length) { value = new char[length]; } /** * Constructs a string buffer so that it represents the same sequence of characters as the * string argument; in other words, the initial contents of the string buffer is a copy of the * argument string. The initial capacity of the string buffer is <code>16</code> plus the length * of the string argument. * * @param str * the initial contents of the buffer. * @exception NullPointerException * if <code>str</code> is <code>null</code> */ public AppendingStringBuffer(final CharSequence str) { this(str.length() + 16); append(str); } /** * Returns the length (character count) of this string buffer. * * @return the length of the sequence of characters currently represented by this string buffer. */ @Override public int length() { return count; } /** * Returns the current capacity of the String buffer. The capacity is the amount of storage * available for newly inserted characters; beyond which an allocation will occur. * * @return the current capacity of this string buffer. */ public int capacity() { return value.length; } /** * Ensures that the capacity of the buffer is at least equal to the specified minimum. If the * current capacity of this string buffer is less than the argument, then a new internal buffer * is allocated with greater capacity. The new capacity is the larger of: * <ul> * <li>The <code>minimumCapacity</code> argument. * <li>Twice the old capacity, plus <code>2</code>. * </ul> * If the <code>minimumCapacity</code> argument is nonpositive, this method takes no action and * simply returns. * * @param minimumCapacity * the minimum desired capacity. */ public void ensureCapacity(final int minimumCapacity) { if (minimumCapacity > value.length) { expandCapacity(minimumCapacity); } } /** * This implements the expansion semantics of ensureCapacity but is unsynchronized for use * internally by methods which are already synchronized. * * @param minimumCapacity * * @see java.lang.StringBuffer#ensureCapacity(int) */ private void expandCapacity(final int minimumCapacity) { int newCapacity = (value.length + 1) * 2; if (newCapacity < 0) { newCapacity = Integer.MAX_VALUE; } else if (minimumCapacity > newCapacity) { newCapacity = minimumCapacity; } char newValue[] = new char[newCapacity]; System.arraycopy(value, 0, newValue, 0, count); value = newValue; } /** * Sets the length of this String buffer. This string buffer is altered to represent a new * character sequence whose length is specified by the argument. For every nonnegative index * <i>k</i> less than <code>newLength</code>, the character at index <i>k</i> in the new * character sequence is the same as the character at index <i>k</i> in the old sequence if * <i>k</i> is less than the length of the old character sequence; otherwise, it is the null * character <code>'\u0000'</code>. * * In other words, if the <code>newLength</code> argument is less than the current length of the * string buffer, the string buffer is truncated to contain exactly the number of characters * given by the <code>newLength</code> argument. * <p> * If the <code>newLength</code> argument is greater than or equal to the current length, * sufficient null characters (<code>'\u0000'</code>) are appended to the string buffer so * that length becomes the <code>newLength</code> argument. * <p> * The <code>newLength</code> argument must be greater than or equal to <code>0</code>. * * @param newLength * the new length of the buffer. * @exception IndexOutOfBoundsException * if the <code>newLength</code> argument is negative. * @see java.lang.StringBuffer#length() */ public void setLength(final int newLength) { if (newLength < 0) { throw new StringIndexOutOfBoundsException(newLength); } if (newLength > value.length) { expandCapacity(newLength); } if (count < newLength) { for (; count < newLength; count++) { value[count] = '\0'; } } else { count = newLength; } } /** * The specified character of the sequence currently represented by the string buffer, as * indicated by the <code>index</code> argument, is returned. The first character of a string * buffer is at index <code>0</code>, the next at index <code>1</code>, and so on, for array * indexing. * <p> * The index argument must be greater than or equal to <code>0</code>, and less than the length * of this string buffer. * * @param index * the index of the desired character. * @return the character at the specified index of this string buffer. * @exception IndexOutOfBoundsException * if <code>index</code> is negative or greater than or equal to * <code>length()</code>. * @see java.lang.StringBuffer#length() */ @Override public char charAt(final int index) { if ((index < 0) || (index >= count)) { throw new StringIndexOutOfBoundsException(index); } return value[index]; } /** * Characters are copied from this string buffer into the destination character array * <code>dst</code>. The first character to be copied is at index <code>srcBegin</code>; the * last character to be copied is at index <code>srcEnd-1</code>. The total number of characters * to be copied is <code>srcEnd-srcBegin</code>. The characters are copied into the subarray of * <code>dst</code> starting at index <code>dstBegin</code> and ending at index: * <p> * <blockquote> * * <pre> * dstbegin + (srcEnd - srcBegin) - 1 * </pre> * * </blockquote> * * @param srcBegin * start copying at this offset in the string buffer. * @param srcEnd * stop copying at this offset in the string buffer. * @param dst * the array to copy the data into. * @param dstBegin * offset into <code>dst</code>. * @exception NullPointerException * if <code>dst</code> is <code>null</code>. * @exception IndexOutOfBoundsException * if any of the following is true: * <ul> * <li><code>srcBegin</code> is negative <li><code>dstBegin</code> is negative * <li>the <code>srcBegin</code> argument is greater than the <code>srcEnd</code> * argument. <li><code>srcEnd</code> is greater than <code>this.length()</code>, * the current length of this string buffer. <li><code>dstBegin+srcEnd-srcBegin * </code> is greater than <code>dst.length</code> * </ul> */ public void getChars(final int srcBegin, final int srcEnd, final char dst[], final int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if ((srcEnd < 0) || (srcEnd > count)) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException("srcBegin > srcEnd"); } System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } /** * The character at the specified index of this string buffer is set to <code>ch</code>. The * string buffer is altered to represent a new character sequence that is identical to the old * character sequence, except that it contains the character <code>ch</code> at position * <code>index</code>. * <p> * The index argument must be greater than or equal to <code>0</code>, and less than the length * of this string buffer. * * @param index * the index of the character to modify. * @param ch * the new character. * @exception IndexOutOfBoundsException * if <code>index</code> is negative or greater than or equal to * <code>length()</code>. * @see java.lang.StringBuffer#length() */ public void setCharAt(final int index, final char ch) { if ((index < 0) || (index >= count)) { throw new StringIndexOutOfBoundsException(index); } value[index] = ch; } /** * Appends the string representation of the <code>Object</code> argument to this string buffer. * <p> * The argument is converted to a string as if by the method <code>String.valueOf</code>, and * the characters of that string are then appended to this string buffer. * * @param obj * an <code>Object</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @see java.lang.String#valueOf(java.lang.Object) * @see java.lang.StringBuffer#append(java.lang.String) */ public AppendingStringBuffer append(final Object obj) { if (obj instanceof AppendingStringBuffer) { return append((AppendingStringBuffer)obj); } else if (obj instanceof StringBuilder) { return append((StringBuilder)obj); } else if (obj instanceof StringBuffer) { return append(obj.toString()); } return append(String.valueOf(obj)); } /** * Appends the string to this string buffer. * <p> * The characters of the <code>String</code> argument are appended, in order, to the contents of * this string buffer, increasing the length of this string buffer by the length of the * argument. If <code>str</code> is <code>null</code>, then the four characters * <code>"null"</code> are appended to this string buffer. * <p> * Let <i>n</i> be the length of the old character sequence, the one contained in the string * buffer just prior to execution of the <code>append</code> method. Then the character at index * <i>k</i> in the new character sequence is equal to the character at index <i>k</i> in the old * character sequence, if <i>k</i> is less than <i>n</i>; otherwise, it is equal to the * character at index <i>k-n</i> in the argument <code>str</code>. * * @param str * a string. * @return a reference to this <code>AppendingStringBuffer</code>. */ public AppendingStringBuffer append(String str) { if (str == null) { str = String.valueOf(str); } int len = str.length(); int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } str.getChars(0, len, value, count); count = newcount; return this; } /** * Appends the specified <tt>AppendingStringBuffer</tt> to this <tt>AppendingStringBuffer</tt>. * <p> * The characters of the <tt>AppendingStringBuffer</tt> argument are appended, in order, to the * contents of this <tt>AppendingStringBuffer</tt>, increasing the length of this * <tt>AppendingStringBuffer</tt> by the length of the argument. If <tt>sb</tt> is <tt>null</tt> * , then the four characters <tt>"null"</tt> are appended to this * <tt>AppendingStringBuffer</tt>. * <p> * Let <i>n</i> be the length of the old character sequence, the one contained in the * <tt>AppendingStringBuffer</tt> just prior to execution of the <tt>append</tt> method. Then * the character at index <i>k</i> in the new character sequence is equal to the character at * index <i>k</i> in the old character sequence, if <i>k</i> is less than <i>n</i>; otherwise, * it is equal to the character at index <i>k-n</i> in the argument <code>sb</code>. * <p> * The method <tt>ensureCapacity</tt> is first called on this <tt>AppendingStringBuffer</tt> * with the new buffer length as its argument. (This ensures that the storage of this * <tt>AppendingStringBuffer</tt> is adequate to contain the additional characters being * appended.) * * @param sb * the <tt>AppendingStringBuffer</tt> to append. * @return a reference to this <tt>AppendingStringBuffer</tt>. * @since 1.4 */ public AppendingStringBuffer append(AppendingStringBuffer sb) { if (sb == null) { sb = NULL; } int len = sb.length(); int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } sb.getChars(0, len, value, count); count = newcount; return this; } /** * Appends the specified <tt>AppendingStringBuffer</tt> to this <tt>AppendingStringBuffer</tt>. * <p> * The characters of the <tt>AppendingStringBuffer</tt> argument are appended, in order, to the * contents of this <tt>AppendingStringBuffer</tt>, increasing the length of this * <tt>AppendingStringBuffer</tt> by the length of the argument. If <tt>sb</tt> is <tt>null</tt> * , then the four characters <tt>"null"</tt> are appended to this * <tt>AppendingStringBuffer</tt>. * <p> * Let <i>n</i> be the length of the old character sequence, the one contained in the * <tt>AppendingStringBuffer</tt> just prior to execution of the <tt>append</tt> method. Then * the character at index <i>k</i> in the new character sequence is equal to the character at * index <i>k</i> in the old character sequence, if <i>k</i> is less than <i>n</i>; otherwise, * it is equal to the character at index <i>k-n</i> in the argument <code>sb</code>. * <p> * The method <tt>ensureCapacity</tt> is first called on this <tt>AppendingStringBuffer</tt> * with the new buffer length as its argument. (This ensures that the storage of this * <tt>AppendingStringBuffer</tt> is adequate to contain the additional characters being * appended.) * * @param sb * the <tt>AppendingStringBuffer</tt> to append. * @return a reference to this <tt>AppendingStringBuffer</tt>. * @since 1.4 */ public AppendingStringBuffer append(StringBuilder sb) { if (sb == null) { sb = SB_NULL; } int len = sb.length(); int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } sb.getChars(0, len, value, count); count = newcount; return this; } /** * Appends the string representation of the <code>char</code> array argument to this string * buffer. * <p> * The characters of the array argument are appended, in order, to the contents of this string * buffer. The length of this string buffer increases by the length of the argument. * <p> * The overall effect is exactly as if the argument were converted to a string by the method * {@link String#valueOf(char[])} and the characters of that string were then * {@link #append(String) appended} to this <code>AppendingStringBuffer</code> object. * * @param str * the characters to be appended. * @return a reference to this <code>AppendingStringBuffer</code> object. */ public AppendingStringBuffer append(final char str[]) { int len = str.length; int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } System.arraycopy(str, 0, value, count, len); count = newcount; return this; } /** * Appends the string representation of a subarray of the <code>char</code> array argument to * this string buffer. * <p> * Characters of the character array <code>str</code>, starting at index <code>offset</code>, * are appended, in order, to the contents of this string buffer. The length of this string * buffer increases by the value of <code>len</code>. * <p> * The overall effect is exactly as if the arguments were converted to a string by the method * {@link String#valueOf(char[],int,int)} and the characters of that string were then * {@link #append(String) appended} to this <code>AppendingStringBuffer</code> object. * * @param str * the characters to be appended. * @param offset * the index of the first character to append. * @param len * the number of characters to append. * @return a reference to this <code>AppendingStringBuffer</code> object. */ public AppendingStringBuffer append(final char str[], final int offset, final int len) { int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } System.arraycopy(str, offset, value, count, len); count = newcount; return this; } /** * Appends the string representation of the <code>boolean</code> argument to the string buffer. * <p> * The argument is converted to a string as if by the method <code>String.valueOf</code>, and * the characters of that string are then appended to this string buffer. * * @param b * a <code>boolean</code>. * @return a reference to this <code>AppendingStringBuffer</code>. * @see java.lang.String#valueOf(boolean) * @see java.lang.StringBuffer#append(java.lang.String) */ public AppendingStringBuffer append(final boolean b) { if (b) { int newcount = count + 4; if (newcount > value.length) { expandCapacity(newcount); } value[count++] = 't'; value[count++] = 'r'; value[count++] = 'u'; value[count++] = 'e'; } else { int newcount = count + 5; if (newcount > value.length) { expandCapacity(newcount); } value[count++] = 'f'; value[count++] = 'a'; value[count++] = 'l'; value[count++] = 's'; value[count++] = 'e'; } return this; } /** * Appends the string representation of the <code>char</code> argument to this string buffer. * <p> * The argument is appended to the contents of this string buffer. The length of this string * buffer increases by <code>1</code>. * <p> * The overall effect is exactly as if the argument were converted to a string by the method * {@link String#valueOf(char)} and the character in that string were then * {@link #append(String) appended} to this <code>AppendingStringBuffer</code> object. * * @param c * a <code>char</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. */ public AppendingStringBuffer append(final char c) { int newcount = count + 1; if (newcount > value.length) { expandCapacity(newcount); } value[count++] = c; return this; } /** * Appends the string representation of the <code>int</code> argument to this string buffer. * <p> * The argument is converted to a string as if by the method <code>String.valueOf</code>, and * the characters of that string are then appended to this string buffer. * * @param i * an <code>int</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @see java.lang.String#valueOf(int) * @see java.lang.StringBuffer#append(java.lang.String) */ public AppendingStringBuffer append(final int i) { return append(String.valueOf(i)); } /** * Appends the string representation of the <code>long</code> argument to this string buffer. * <p> * The argument is converted to a string as if by the method <code>String.valueOf</code>, and * the characters of that string are then appended to this string buffer. * * @param l * a <code>long</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @see java.lang.String#valueOf(long) * @see java.lang.StringBuffer#append(java.lang.String) */ public AppendingStringBuffer append(final long l) { return append(String.valueOf(l)); } /** * Appends the string representation of the <code>float</code> argument to this string buffer. * <p> * The argument is converted to a string as if by the method <code>String.valueOf</code>, and * the characters of that string are then appended to this string buffer. * * @param f * a <code>float</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @see java.lang.String#valueOf(float) * @see java.lang.StringBuffer#append(java.lang.String) */ public AppendingStringBuffer append(final float f) { return append(String.valueOf(f)); } /** * Appends the string representation of the <code>double</code> argument to this string buffer. * <p> * The argument is converted to a string as if by the method <code>String.valueOf</code>, and * the characters of that string are then appended to this string buffer. * * @param d * a <code>double</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @see java.lang.String#valueOf(double) * @see java.lang.StringBuffer#append(java.lang.String) */ public AppendingStringBuffer append(final double d) { return append(String.valueOf(d)); } /** * Removes the characters in a substring of this <code>AppendingStringBuffer</code>. The * substring begins at the specified <code>start</code> and extends to the character at index * <code>end - 1</code> or to the end of the <code>AppendingStringBuffer</code> if no such * character exists. If <code>start</code> is equal to <code>end</code>, no changes are made. * * @param start * The beginning index, inclusive. * @param end * The ending index, exclusive. * @return This string buffer. * @exception StringIndexOutOfBoundsException * if <code>start</code> is negative, greater than <code>length()</code>, or * greater than <code>end</code>. * @since 1.2 */ public AppendingStringBuffer delete(final int start, int end) { if (start < 0) { throw new StringIndexOutOfBoundsException(start); } if (end > count) { end = count; } if (start > end) { throw new StringIndexOutOfBoundsException(); } int len = end - start; if (len > 0) { System.arraycopy(value, start + len, value, start, count - end); count -= len; } return this; } /** * Removes the character at the specified position in this <code>AppendingStringBuffer</code> * (shortening the <code>AppendingStringBuffer</code> by one character). * * @param index * Index of character to remove * @return This string buffer. * @exception StringIndexOutOfBoundsException * if the <code>index</code> is negative or greater than or equal to * <code>length()</code>. * @since 1.2 */ public AppendingStringBuffer deleteCharAt(final int index) { if ((index < 0) || (index >= count)) { throw new StringIndexOutOfBoundsException(); } System.arraycopy(value, index + 1, value, index, count - index - 1); count--; return this; } /** * Replaces the characters in a substring of this <code>AppendingStringBuffer</code> with * characters in the specified <code>String</code>. The substring begins at the specified * <code>start</code> and extends to the character at index <code>end - 1</code> or to the end * of the <code>AppendingStringBuffer</code> if no such character exists. First the characters * in the substring are removed and then the specified <code>String</code> is inserted at * <code>start</code>. (The <code>AppendingStringBuffer</code> will be lengthened to accommodate * the specified String if necessary.) * * @param start * The beginning index, inclusive. * @param end * The ending index, exclusive. * @param str * String that will replace previous contents. * @return This string buffer. * @exception StringIndexOutOfBoundsException * if <code>start</code> is negative, greater than <code>length()</code>, or * greater than <code>end</code>. * @since 1.2 */ public AppendingStringBuffer replace(final int start, int end, final String str) { if (start < 0) { throw new StringIndexOutOfBoundsException(start); } if (end > count) { end = count; } if (start > end) { throw new StringIndexOutOfBoundsException(); } int len = str.length(); int newCount = count + len - (end - start); if (newCount > value.length) { expandCapacity(newCount); } System.arraycopy(value, end, value, start + len, count - end); str.getChars(0, len, value, start); count = newCount; return this; } /** * Returns a new <code>String</code> that contains a subsequence of characters currently * contained in this <code>AppendingStringBuffer</code>.The substring begins at the specified * index and extends to the end of the <code>AppendingStringBuffer</code>. * * @param start * The beginning index, inclusive. * @return The new string. * @exception StringIndexOutOfBoundsException * if <code>start</code> is less than zero, or greater than the length of this * <code>AppendingStringBuffer</code>. * @since 1.2 */ public String substring(final int start) { return substring(start, count); } /** * Returns a new character sequence that is a subsequence of this sequence. * * <p> * An invocation of this method of the form * * <blockquote> * * <pre> * sb.subSequence(begin, end) * </pre> * * </blockquote> * * behaves in exactly the same way as the invocation * * <blockquote> * * <pre> * sb.substring(begin, end) * </pre> * * </blockquote> * * This method is provided so that the <tt>AppendingStringBuffer</tt> class can implement the * {@link CharSequence} interface. * </p> * * @param start * the start index, inclusive. * @param end * the end index, exclusive. * @return the specified subsequence. * * @throws IndexOutOfBoundsException * if <tt>start</tt> or <tt>end</tt> are negative, if <tt>end</tt> is greater than * <tt>length()</tt>, or if <tt>start</tt> is greater than <tt>end</tt> * * @since 1.4 * Specification: JSR-51 */ @Override public CharSequence subSequence(final int start, final int end) { return this.substring(start, end); } /** * Returns a new <code>String</code> that contains a subsequence of characters currently * contained in this <code>AppendingStringBuffer</code>. The substring begins at the specified * <code>start</code> and extends to the character at index <code>end - 1</code>. An exception * is thrown if * * @param start * The beginning index, inclusive. * @param end * The ending index, exclusive. * @return The new string. * @exception StringIndexOutOfBoundsException * if <code>start</code> or <code>end</code> are negative or greater than * <code>length()</code>, or <code>start</code> is greater than <code>end</code>. * @since 1.2 */ public String substring(final int start, final int end) { if (start < 0) { throw new StringIndexOutOfBoundsException(start); } if (end > count) { throw new StringIndexOutOfBoundsException(end); } if (start > end) { throw new StringIndexOutOfBoundsException(end - start); } return new String(value, start, end - start); } /** * Inserts the string representation of a subarray of the <code>str</code> array argument into * this string buffer. The subarray begins at the specified <code>offset</code> and extends * <code>len</code> characters. The characters of the subarray are inserted into this string * buffer at the position indicated by <code>index</code>. The length of this * <code>AppendingStringBuffer</code> increases by <code>len</code> characters. * * @param index * position at which to insert subarray. * @param str * A character array. * @param offset * the index of the first character in subarray to to be inserted. * @param len * the number of characters in the subarray to to be inserted. * @return This string buffer. * @exception StringIndexOutOfBoundsException * if <code>index</code> is negative or greater than <code>length()</code>, or * <code>offset</code> or <code>len</code> are negative, or * <code>(offset+len)</code> is greater than <code>str.length</code>. * @since 1.2 */ public AppendingStringBuffer insert(final int index, final char str[], final int offset, final int len) { if ((index < 0) || (index > count)) { throw new StringIndexOutOfBoundsException(); } if ((offset < 0) || (offset + len < 0) || (offset + len > str.length)) { throw new StringIndexOutOfBoundsException(offset); } if (len < 0) { throw new StringIndexOutOfBoundsException(len); } int newCount = count + len; if (newCount > value.length) { expandCapacity(newCount); } System.arraycopy(value, index, value, index + len, count - index); System.arraycopy(str, offset, value, index, len); count = newCount; return this; } /** * Inserts the string representation of the <code>Object</code> argument into this string * buffer. * <p> * The second argument is converted to a string as if by the method <code>String.valueOf</code>, * and the characters of that string are then inserted into this string buffer at the indicated * offset. * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param obj * an <code>Object</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.String#valueOf(java.lang.Object) * @see AppendingStringBuffer#insert(int, java.lang.String) * @see AppendingStringBuffer#length() */ public AppendingStringBuffer insert(final int offset, final Object obj) { if (obj instanceof AppendingStringBuffer) { AppendingStringBuffer asb = (AppendingStringBuffer)obj; return insert(offset, asb.value, 0, asb.count); } else if (obj instanceof StringBuffer) { return insert(offset, (StringBuffer)obj); } else if (obj instanceof StringBuilder) { return insert(offset, (StringBuilder)obj); } return insert(offset, String.valueOf(obj)); } /** * Inserts the string into this string buffer. * <p> * The characters of the <code>String</code> argument are inserted, in order, into this string * buffer at the indicated offset, moving up any characters originally above that position and * increasing the length of this string buffer by the length of the argument. If * <code>str</code> is <code>null</code>, then the four characters <code>"null"</code> are * inserted into this string buffer. * <p> * The character at index <i>k</i> in the new character sequence is equal to: * <ul> * <li>the character at index <i>k</i> in the old character sequence, if <i>k</i> is less than * <code>offset</code> * <li>the character at index <i>k</i><code>-offset</code> in the argument <code>str</code>, if * <i>k</i> is not less than <code>offset</code> but is less than * <code>offset+str.length()</code> * <li>the character at index <i>k</i><code>-str.length()</code> in the old character sequence, * if <i>k</i> is not less than <code>offset+str.length()</code> * </ul> * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param str * a string. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, String str) { if ((offset < 0) || (offset > count)) { throw new StringIndexOutOfBoundsException(); } if (str == null) { str = String.valueOf(str); } int len = str.length(); int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } System.arraycopy(value, offset, value, offset + len, count - offset); str.getChars(0, len, value, offset); count = newcount; return this; } /** * Inserts the string into this string buffer. * <p> * The characters of the <code>StringBuilder</code> argument are inserted, in order, into this * string buffer at the indicated offset, moving up any characters originally above that * position and increasing the length of this string buffer by the length of the argument. If * <code>str</code> is <code>null</code>, then the four characters <code>"null"</code> are * inserted into this string buffer. * <p> * The character at index <i>k</i> in the new character sequence is equal to: * <ul> * <li>the character at index <i>k</i> in the old character sequence, if <i>k</i> is less than * <code>offset</code> * <li>the character at index <i>k</i><code>-offset</code> in the argument <code>str</code>, if * <i>k</i> is not less than <code>offset</code> but is less than * <code>offset+str.length()</code> * <li>the character at index <i>k</i><code>-str.length()</code> in the old character sequence, * if <i>k</i> is not less than <code>offset+str.length()</code> * </ul> * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param str * a string. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, StringBuilder str) { if ((offset < 0) || (offset > count)) { throw new StringIndexOutOfBoundsException(); } if (str == null) { str = SB_NULL; } int len = str.length(); int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } System.arraycopy(value, offset, value, offset + len, count - offset); str.getChars(0, len, value, offset); count = newcount; return this; } /** * Inserts the string into this string buffer. * <p> * The characters of the <code>StringBuffer</code> argument are inserted, in order, into this * string buffer at the indicated offset, moving up any characters originally above that * position and increasing the length of this string buffer by the length of the argument. If * <code>str</code> is <code>null</code>, then the four characters <code>"null"</code> are * inserted into this string buffer. * <p> * The character at index <i>k</i> in the new character sequence is equal to: * <ul> * <li>the character at index <i>k</i> in the old character sequence, if <i>k</i> is less than * <code>offset</code> * <li>the character at index <i>k</i><code>-offset</code> in the argument <code>str</code>, if * <i>k</i> is not less than <code>offset</code> but is less than * <code>offset+str.length()</code> * <li>the character at index <i>k</i><code>-str.length()</code> in the old character sequence, * if <i>k</i> is not less than <code>offset+str.length()</code> * </ul> * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param str * a string. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, StringBuffer str) { if ((offset < 0) || (offset > count)) { throw new StringIndexOutOfBoundsException(); } if (str == null) { str = SBF_NULL; } int len = str.length(); int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } System.arraycopy(value, offset, value, offset + len, count - offset); str.getChars(0, len, value, offset); count = newcount; return this; } /** * Inserts the string representation of the <code>char</code> array argument into this string * buffer. * <p> * The characters of the array argument are inserted into the contents of this string buffer at * the position indicated by <code>offset</code>. The length of this string buffer increases by * the length of the argument. * <p> * The overall effect is exactly as if the argument were converted to a string by the method * {@link String#valueOf(char[])} and the characters of that string were then * {@link #insert(int,String) inserted} into this <code>AppendingStringBuffer</code> object at * the position indicated by <code>offset</code>. * * @param offset * the offset. * @param str * a character array. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. */ public AppendingStringBuffer insert(final int offset, final char str[]) { if ((offset < 0) || (offset > count)) { throw new StringIndexOutOfBoundsException(); } int len = str.length; int newcount = count + len; if (newcount > value.length) { expandCapacity(newcount); } System.arraycopy(value, offset, value, offset + len, count - offset); System.arraycopy(str, 0, value, offset, len); count = newcount; return this; } /** * Inserts the string representation of the <code>boolean</code> argument into this string * buffer. * <p> * The second argument is converted to a string as if by the method <code>String.valueOf</code>, * and the characters of that string are then inserted into this string buffer at the indicated * offset. * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param b * a <code>boolean</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.String#valueOf(boolean) * @see java.lang.StringBuffer#insert(int, java.lang.String) * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, final boolean b) { return insert(offset, String.valueOf(b)); } /** * Inserts the string representation of the <code>char</code> argument into this string buffer. * <p> * The second argument is inserted into the contents of this string buffer at the position * indicated by <code>offset</code>. The length of this string buffer increases by one. * <p> * The overall effect is exactly as if the argument were converted to a string by the method * {@link String#valueOf(char)} and the character in that string were then * {@link #insert(int, String) inserted} into this <code>AppendingStringBuffer</code> object at * the position indicated by <code>offset</code>. * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param c * a <code>char</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception IndexOutOfBoundsException * if the offset is invalid. * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, final char c) { int newcount = count + 1; if (newcount > value.length) { expandCapacity(newcount); } System.arraycopy(value, offset, value, offset + 1, count - offset); value[offset] = c; count = newcount; return this; } /** * Inserts the string representation of the second <code>int</code> argument into this string * buffer. * <p> * The second argument is converted to a string as if by the method <code>String.valueOf</code>, * and the characters of that string are then inserted into this string buffer at the indicated * offset. * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param i * an <code>int</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.String#valueOf(int) * @see java.lang.StringBuffer#insert(int, java.lang.String) * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, final int i) { return insert(offset, String.valueOf(i)); } /** * Inserts the string representation of the <code>long</code> argument into this string buffer. * <p> * The second argument is converted to a string as if by the method <code>String.valueOf</code>, * and the characters of that string are then inserted into this string buffer at the position * indicated by <code>offset</code>. * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param l * a <code>long</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.String#valueOf(long) * @see java.lang.StringBuffer#insert(int, java.lang.String) * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, final long l) { return insert(offset, String.valueOf(l)); } /** * Inserts the string representation of the <code>float</code> argument into this string buffer. * <p> * The second argument is converted to a string as if by the method <code>String.valueOf</code>, * and the characters of that string are then inserted into this string buffer at the indicated * offset. * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param f * a <code>float</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.String#valueOf(float) * @see java.lang.StringBuffer#insert(int, java.lang.String) * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, final float f) { return insert(offset, String.valueOf(f)); } /** * Inserts the string representation of the <code>double</code> argument into this string * buffer. * <p> * The second argument is converted to a string as if by the method <code>String.valueOf</code>, * and the characters of that string are then inserted into this string buffer at the indicated * offset. * <p> * The offset argument must be greater than or equal to <code>0</code>, and less than or equal * to the length of this string buffer. * * @param offset * the offset. * @param d * a <code>double</code>. * @return a reference to this <code>AppendingStringBuffer</code> object. * @exception StringIndexOutOfBoundsException * if the offset is invalid. * @see java.lang.String#valueOf(double) * @see java.lang.StringBuffer#insert(int, java.lang.String) * @see java.lang.StringBuffer#length() */ public AppendingStringBuffer insert(final int offset, final double d) { return insert(offset, String.valueOf(d)); } /** * Returns the index within this string of the first occurrence of the specified substring. The * integer returned is the smallest value <i>k</i> such that: <blockquote> * * <pre> * this.toString().startsWith(str, <i>k</i>) * </pre> * * </blockquote> is <code>true</code>. * * @param str * any string. * @return if the string argument occurs as a substring within this object, then the index of * the first character of the first such substring is returned; if it does not occur as * a substring, <code>-1</code> is returned. * @exception java.lang.NullPointerException * if <code>str</code> is <code>null</code>. * @since 1.4 */ public int indexOf(final String str) { return indexOf(str, 0); } /** * Returns the index within this string of the first occurrence of the specified substring, * starting at the specified index. The integer returned is the smallest value <tt>k</tt> for * which: <blockquote> * * <pre> * k >= Math.min(fromIndex, str.length()) && this.toString().startsWith(str, k) * </pre> * * </blockquote> If no such value of <i>k</i> exists, then -1 is returned. * * @param str * the substring for which to search. * @param fromIndex * the index from which to start the search. * @return the index within this string of the first occurrence of the specified substring, * starting at the specified index. * @exception java.lang.NullPointerException * if <code>str</code> is <code>null</code>. * @since 1.4 */ public int indexOf(final String str, final int fromIndex) { return indexOf(value, 0, count, str.toCharArray(), 0, str.length(), fromIndex); } static int indexOf(final char[] source, final int sourceOffset, final int sourceCount, final char[] target, final int targetOffset, final int targetCount, int fromIndex) { if (fromIndex >= sourceCount) { return (targetCount == 0 ? sourceCount : -1); } if (fromIndex < 0) { fromIndex = 0; } if (targetCount == 0) { return fromIndex; } char first = target[targetOffset]; int i = sourceOffset + fromIndex; int max = sourceOffset + (sourceCount - targetCount); startSearchForFirstChar : while (true) { /* Look for first character. */ while ((i <= max) && (source[i] != first)) { i++; } if (i > max) { return -1; } /* Found first character, now look at the rest of v2 */ int j = i + 1; int end = j + targetCount - 1; int k = targetOffset + 1; while (j < end) { if (source[j++] != target[k++]) { i++; /* Look for str's first char again. */ continue startSearchForFirstChar; } } return i - sourceOffset; /* Found whole string. */ } } /** * Returns the index within this string of the rightmost occurrence of the specified substring. * The rightmost empty string "" is considered to occur at the index value * <code>this.length()</code>. The returned index is the largest value <i>k</i> such that * <blockquote> * * <pre> * this.toString().startsWith(str, k) * </pre> * * </blockquote> is true. * * @param str * the substring to search for. * @return if the string argument occurs one or more times as a substring within this object, * then the index of the first character of the last such substring is returned. If it * does not occur as a substring, <code>-1</code> is returned. * @exception java.lang.NullPointerException * if <code>str</code> is <code>null</code>. * @since 1.4 */ public int lastIndexOf(final String str) { return lastIndexOf(str, count); } /** * Returns the index within this string of the last occurrence of the specified substring. The * integer returned is the largest value <i>k</i> such that: <blockquote> * * <pre> * k <= Math.min(fromIndex, str.length()) && this.toString().startsWith(str, k) * </pre> * * </blockquote> If no such value of <i>k</i> exists, then -1 is returned. * * @param str * the substring to search for. * @param fromIndex * the index to start the search from. * @return the index within this string of the last occurrence of the specified substring. * @exception java.lang.NullPointerException * if <code>str</code> is <code>null</code>. * @since 1.4 */ public int lastIndexOf(final String str, final int fromIndex) { return lastIndexOf(value, 0, count, str.toCharArray(), 0, str.length(), fromIndex); } static int lastIndexOf(final char[] source, final int sourceOffset, final int sourceCount, final char[] target, final int targetOffset, final int targetCount, int fromIndex) { /* * Check arguments; return immediately where possible. For consistency, don't check for null * str. */ int rightIndex = sourceCount - targetCount; if (fromIndex < 0) { return -1; } if (fromIndex > rightIndex) { fromIndex = rightIndex; } /* Empty string always matches. */ if (targetCount == 0) { return fromIndex; } int strLastIndex = targetOffset + targetCount - 1; char strLastChar = target[strLastIndex]; int min = sourceOffset + targetCount - 1; int i = min + fromIndex; startSearchForLastChar : while (true) { while ((i >= min) && (source[i] != strLastChar)) { i--; } if (i < min) { return -1; } int j = i - 1; int start = j - (targetCount - 1); int k = strLastIndex - 1; while (j > start) { if (source[j--] != target[k--]) { i--; continue startSearchForLastChar; } } return start - sourceOffset + 1; } } /** * Tests if this AppendingStringBuffer starts with the specified prefix beginning a specified * index. * * @param prefix * the prefix. * @param toffset * where to begin looking in the string. * @return <code>true</code> if the character sequence represented by the argument is a prefix * of the substring of this object starting at index <code>toffset</code>; * <code>false</code> otherwise. The result is <code>false</code> if * <code>toffset</code> is negative or greater than the length of this * <code>String</code> object; otherwise the result is the same as the result of the * expression * * <pre> * this.subString(toffset).startsWith(prefix) * </pre> */ public boolean startsWith(final CharSequence prefix, final int toffset) { char ta[] = value; int to = toffset; int po = 0; int pc = prefix.length(); // Note: toffset might be near -1>>>1. if ((toffset < 0) || (toffset > count - pc)) { return false; } while (--pc >= 0) { if (ta[to++] != prefix.charAt(po++)) { return false; } } return true; } /** * Tests if this AppendingStringBuffer starts with the specified prefix. * * @param prefix * the prefix. * @return <code>true</code> if the character sequence represented by the argument is a prefix * of the character sequence represented by this AppendingStringBuffer; * <code>false</code> otherwise. Note also that <code>true</code> will be returned if * the argument is an empty string or is equal to this * <code>AppendingStringBuffer</code> object as determined by the * {@link #equals(Object)} method. * @since 1. 0 */ public boolean startsWith(final CharSequence prefix) { return startsWith(prefix, 0); } /** * Tests if this AppendingStringBuffer ends with the specified suffix. * * @param suffix * the suffix. * @return <code>true</code> if the character sequence represented by the argument is a suffix * of the character sequence represented by this AppendingStringBuffer; * <code>false</code> otherwise. Note that the result will be <code>true</code> if the * argument is the empty string or is equal to this <code>AppendingStringBuffer</code> * object as determined by the {@link #equals(Object)} method. */ public boolean endsWith(final CharSequence suffix) { return startsWith(suffix, count - suffix.length()); } /** * Converts to a string representing the data in this AppendingStringBuffer. A new * <code>String</code> object is allocated and initialized to contain the character sequence * currently represented by this string buffer. This <code>String</code> is then returned. * Subsequent changes to the string buffer do not affect the contents of the <code>String</code> * . * <p> * Implementation advice: This method can be coded so as to create a new <code>String</code> * object without allocating new memory to hold a copy of the character sequence. Instead, the * string can share the memory used by the string buffer. Any subsequent operation that alters * the content or capacity of the string buffer must then make a copy of the internal buffer at * that time. This strategy is effective for reducing the amount of memory allocated by a string * concatenation operation when it is implemented using a string buffer. * * @return a string representation of the string buffer. */ @Override public String toString() { return new String(value, 0, count); } /** * This method returns the internal char array. So it is not * * @return The internal char array */ public final char[] getValue() { return value; } /** * readObject is called to restore the state of the AppendingStringBuffer from a stream. * * @param s * @throws ClassNotFoundException * @throws IOException */ private void readObject(final java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); value = value.clone(); } /** * Compares this AppendingStringBuffer to the specified object. The result is <code>true</code> * if and only if the argument is not <code>null</code> and is a * <code>AppendingStringBuffer</code> object or another charsequence object! that represents the * same sequence of characters as this object. * * @param anObject * the object to compare this <code>AppendingStringBuffer</code> against. * @return <code>true</code> if the <code>AppendingStringBuffer</code>are equal; * <code>false</code> otherwise. */ @Override public boolean equals(final Object anObject) { if (this == anObject) { return true; } if (anObject instanceof AppendingStringBuffer) { AppendingStringBuffer anotherString = (AppendingStringBuffer)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i++]) { return false; } } return true; } } else if (anObject instanceof CharSequence) { CharSequence sequence = (CharSequence)anObject; int n = count; if (sequence.length() == count) { char v1[] = value; int i = 0; while (n-- != 0) { if (v1[i] != sequence.charAt(i++)) { return false; } } return true; } } return false; } /** * Returns a hash code for this AppendingStringBuffer. The hash code for a * <code>AppendingStringBuffer</code> object is computed as <blockquote> * * <pre> * s[0]*31ˆ(n-1) + s[1]*31ˆ(n-2) + ... + s[n-1] * </pre> * * </blockquote> using <code>int</code> arithmetic, where <code>s[i]</code> is the <i>i</i>th * character of the AppendingStringBuffer, <code>n</code> is the length of the * AppendingStringBuffer, and <code>^</code> indicates exponentiation. (The hash value of the * empty AppendingStringBuffer is zero.) * * @return a hash code value for this object. */ @Override public int hashCode() { int h = 0; if (h == 0) { int off = 0; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31 * h + val[off++]; } } return h; } /** * Clears the buffer contents, but leaves the allocated size intact */ public void clear() { count = 0; } }