gcc/libjava/java/lang/StringBuffer.java

687 lines
25 KiB
Java
Raw Normal View History

1999-04-07 16:42:40 +02:00
// StringBuffer.java - Growable strings.
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
1999-04-07 16:42:40 +02:00
This file is part of libgcj.
This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
package java.lang;
import java.io.Serializable;
/**
* @author Tom Tromey <tromey@cygnus.com>
* @date October 23, 1998.
*/
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
* Updated using online JDK 1.2 docs.
* Believed complete and correct to JDK 1.2.
* Merged with Classpath.
1999-04-07 16:42:40 +02:00
*/
/**
* <code>StringBuffer</code> represents a changeable <code>String</code>.
* It provides the operations required to modify the
* <code>StringBuffer</code> including insert, replace, delete, append,
* and reverse.
* <P>
*
* <code>StringBuffer</code>s are variable-length in nature, so even if
* you initialize them to a certain size, they can still grow larger than
* that. <EM>Capacity</EM> indicates the number of characters the
* <code>StringBuffer</code> can have in it before it has to grow (growing
* the char array is an expensive operation involving <code>new</code>).
* <P>
*
* Incidentally, the String operator "+" actually is turned into a
* <code>StringBuffer</code> operation:
* <BR>
* <code>a + b</code>
* <BR>
* is the same as
* <BR>
* <code>new StringBuffer(a).append(b).toString()</code>.
*
* @implnote Classpath's StringBuffer is capable of sharing memory with
* Strings for efficiency. This will help in two instances:
* first, when a StringBuffer is created from a String but is
* never changed, and second, when a StringBuffer is converted
* to a String and the StringBuffer is not changed after that.
*
* @since JDK1.0
* @author Paul Fisher
* @author John Keiser
* @author Tom Tromey
* @see java.lang.String
*/
1999-04-07 16:42:40 +02:00
public final class StringBuffer implements Serializable
{
/** Append the <code>String</code> value of the argument to this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param bool the <code>boolean</code> to convert and append.
* @return this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(boolean)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer append (boolean bool)
{
return append (String.valueOf(bool));
}
/** Append the <code>char</code> to this <code>StringBuffer</code>.
* @param c the <code>char</code> to append.
* @return this <code>StringBuffer</code>.
*/
1999-04-07 16:42:40 +02:00
public synchronized StringBuffer append (char ch)
{
ensureCapacity_unsynchronized (count + 1);
value[count++] = ch;
return this;
}
/** Append the <code>String</code> value of the argument to this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param inum the <code>int</code> to convert and append.
* @return this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(int)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer append (int inum)
{
return append (String.valueOf(inum));
}
/** Append the <code>String</code> value of the argument to this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param lnum the <code>long</code> to convert and append.
* @return this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(long)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer append (long lnum)
{
return append (String.valueOf(lnum));
}
/** Append the <code>String</code> value of the argument to this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param fnum the <code>float</code> to convert and append.
* @return this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(float)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer append (float fnum)
{
return append (String.valueOf(fnum));
}
/** Append the <code>String</code> value of the argument to this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param dnum the <code>double</code> to convert and append.
* @return this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(double)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer append (double dnum)
{
return append (String.valueOf(dnum));
}
/** Append the <code>String</code> value of the argument to this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param obj the <code>Object</code> to convert and append.
* @return this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(java.lang.Object)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer append (Object obj)
{
return append (String.valueOf(obj));
}
/** Append the <code>String</code> to this <code>StringBuffer</code>.
* @param str the <code>String</code> to append.
* @return this <code>StringBuffer</code>.
*/
1999-04-07 16:42:40 +02:00
public synchronized StringBuffer append (String str)
{
if (str == null)
str = "null";
int len = str.length();
ensureCapacity_unsynchronized (count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
/** Append the <code>char</code> array to this <code>StringBuffer</code>.
* @param data the <code>char[]</code> to append.
* @return this <code>StringBuffer</code>.
* @exception NullPointerException if <code>str</code> is <code>null</code>.
*/
1999-04-07 16:42:40 +02:00
public StringBuffer append (char[] data)
{
return append (data, 0, data.length);
}
/** Append the <code>char</code> array to this <code>StringBuffer</code>.
* @param data the <code>char[]</code> to append.
* @param offset the place to start grabbing characters from
* <code>str</code>.
* @param count the number of characters to get from <code>str</code>.
* @return this <code>StringBuffer</code>.
* @exception NullPointerException if <code>str</code> is <code>null</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> or
* <code>offset+len</code> is out of range.
*/
1999-04-07 16:42:40 +02:00
public synchronized StringBuffer append (char[] data, int offset, int count)
{
ensureCapacity_unsynchronized (this.count + count);
System.arraycopy(data, offset, value, this.count, count);
this.count += count;
return this;
}
/** Get the total number of characters this <code>StringBuffer</code>
* can support before it must be grown. Not to be confused with
* <em>length</em>.
* @return the capacity of this <code>StringBuffer</code>
* @see #length()
* @see #ensureCapacity(int)
*/
1999-04-07 16:42:40 +02:00
public int capacity ()
{
return value.length;
}
/** Get the character at the specified index.
* @param index the index of the character to get, starting at 0.
* @return the character at the specified index.
* @exception IndexOutOfBoundsException if the desired character index
* is not between 0 and length() - 1 (inclusive).
*/
1999-04-07 16:42:40 +02:00
public synchronized char charAt (int index)
{
if (index >= count)
throw new StringIndexOutOfBoundsException (index);
return value[index];
}
/** Delete characters from this <code>StringBuffer</code>.
* <code>delete(10, 12)</code> will delete 10 and 11, but not 12.
* @param start the first character to delete.
* @param end the index after the last character to delete.
* @return this <code>StringBuffer</code>.
* @exception StringIndexOutOfBoundsException if <code>start</code>
* or <code>end-1</code> are out of bounds, or if
* <code>start > end</code>.
*/
public synchronized StringBuffer delete (int start, int end)
{
if (start < 0 || start > count || start > end)
throw new StringIndexOutOfBoundsException (start);
if (end > count)
end = count;
// This will unshare if required.
ensureCapacity_unsynchronized (count);
if (count - end != 0)
System.arraycopy (value, end, value, start, count - end);
count -= (end - start);
return this;
}
/** Delete a character from this <code>StringBuffer</code>.
* @param index the index of the character to delete.
* @return this <code>StringBuffer</code>.
* @exception StringIndexOutOfBoundsException if <code>index</code>
* is out of bounds.
*/
public StringBuffer deleteCharAt(int index)
{
return delete (index, index + 1);
}
/** Increase the capacity of this <code>StringBuffer</code>.
* This will ensure that an expensive growing operation will not occur
* until <code>minimumCapacity</code> is reached.
* If the capacity is actually already greater than <code>minimumCapacity</code>
* @param minimumCapacity the new capacity.
* @see #capacity()
*/
1999-04-07 16:42:40 +02:00
public synchronized void ensureCapacity (int minimumCapacity)
{
if (shared || minimumCapacity > value.length)
{
// We don't want to make a larger vector when `shared' is
// set. If we do, then setLength becomes very inefficient
// when repeatedly reusing a StringBuffer in a loop.
int max = (minimumCapacity > value.length
? value.length*2+2
: value.length);
minimumCapacity = (minimumCapacity < max ? max : minimumCapacity);
char[] nb = new char[minimumCapacity];
System.arraycopy(value, 0, nb, 0, count);
value = nb;
shared = false;
}
}
// ensureCapacity is used by several synchronized methods in StringBuffer.
// There's no need to synchronize again.
private void ensureCapacity_unsynchronized (int minimumCapacity)
{
if (shared || minimumCapacity > value.length)
{
// We don't want to make a larger vector when `shared' is
// set. If we do, then setLength becomes very inefficient
// when repeatedly reusing a StringBuffer in a loop.
int max = (minimumCapacity > value.length
? value.length*2+2
: value.length);
minimumCapacity = (minimumCapacity < max ? max : minimumCapacity);
char[] nb = new char[minimumCapacity];
System.arraycopy(value, 0, nb, 0, count);
value = nb;
shared = false;
}
}
/** Get the specified array of characters.
* The characters will be copied into the array you pass in.
* @param srcOffset the index to start copying from in the
* <code>StringBuffer</code>.
* @param srcEnd the number of characters to copy.
* @param dst the array to copy into.
* @param dstOffset the index to start copying into <code>dst</code>.
* @exception NullPointerException if dst is null.
* @exception IndexOutOfBoundsException if any source or target
* indices are out of range.
* @see java.lang.System#arraycopy(java.lang.Object,int,java.lang.Object,int,int)
*/
1999-04-07 16:42:40 +02:00
public synchronized void getChars (int srcOffset, int srcEnd,
char[] dst, int dstOffset)
{
if (srcOffset < 0 || srcOffset > srcEnd)
throw new StringIndexOutOfBoundsException (srcOffset);
int todo = srcEnd - srcOffset;
if (srcEnd > count || dstOffset + todo > count)
throw new StringIndexOutOfBoundsException (srcEnd);
System.arraycopy(value, srcOffset, dst, dstOffset, todo);
}
/** Insert the <code>String</code> value of the argument into this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param offset the place to insert.
* @param bool the <code>boolean</code> to convert and insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(boolean)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer insert (int offset, boolean bool)
{
return insert (offset, bool ? "true" : "false");
}
/** Insert the <code>char</code> argument into this <code>StringBuffer</code>.
* @param offset the place to insert.
* @param ch the <code>char</code> to insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
*/
1999-04-07 16:42:40 +02:00
public synchronized StringBuffer insert (int offset, char ch)
{
if (offset < 0 || offset > count)
throw new StringIndexOutOfBoundsException (offset);
ensureCapacity_unsynchronized (count+1);
System.arraycopy(value, offset, value, offset+1, count-offset);
value[offset] = ch;
count++;
return this;
}
/** Insert the <code>String</code> value of the argument into this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param offset the place to insert.
* @param inum the <code>int</code> to convert and insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(int)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer insert (int offset, int inum)
{
return insert (offset, String.valueOf(inum));
}
/** Insert the <code>String</code> value of the argument into this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param offset the place to insert.
* @param lnum the <code>long</code> to convert and insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(long)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer insert (int offset, long lnum)
{
return insert (offset, String.valueOf(lnum));
}
/** Insert the <code>String</code> value of the argument into this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param offset the place to insert.
* @param fnum the <code>float</code> to convert and insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(float)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer insert (int offset, float fnum)
{
return insert (offset, String.valueOf(fnum));
}
/** Insert the <code>String</code> value of the argument into this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param offset the place to insert.
* @param dnum the <code>double</code> to convert and insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(double)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer insert (int offset, double dnum)
{
return insert (offset, String.valueOf(dnum));
}
/** Insert the <code>String</code> value of the argument into this <code>StringBuffer</code>.
* Uses <code>String.valueOf()</code> to convert to
* <code>String</code>.
* @param offset the place to insert.
* @param obj the <code>Object</code> to convert and insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
* @see java.lang.String#valueOf(java.lang.Object)
*/
1999-04-07 16:42:40 +02:00
public StringBuffer insert (int offset, Object obj)
{
return insert (offset, String.valueOf(obj));
}
/** Insert the <code>String</code> argument into this <code>StringBuffer</code>.
* @param offset the place to insert.
* @param str the <code>String</code> to insert.
* @return this <code>StringBuffer</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
*/
1999-04-07 16:42:40 +02:00
public synchronized StringBuffer insert (int offset, String str)
{
if (offset < 0 || offset > count)
throw new StringIndexOutOfBoundsException (offset);
// Note that using `null' is from JDK 1.2.
if (str == null)
str = "null";
int len = str.length();
ensureCapacity_unsynchronized (count+len);
System.arraycopy(value, offset, value, offset+len, count-offset);
str.getChars(0, len, value, offset);
count += len;
return this;
}
/** Insert the <code>char[]</code> argument into this
* <code>StringBuffer</code>.
* @param offset the place to insert.
* @param data the <code>char[]</code> to insert.
* @return this <code>StringBuffer</code>.
* @exception NullPointerException if <code>data</code> is
* <code>null</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range for this <code>StringBuffer</code>.
*/
public StringBuffer insert (int offset, char[] data)
{
// One could check if offset is invalid here instead of making sure that
// data isn't null before dereferencing, but this works just as well.
return insert (offset, data, 0, data == null ? 0 : data.length);
}
/** Insert the <code>char[]</code> argument into this
* <code>StringBuffer</code>.
* @param offset the place to insert.
* @param str the <code>char[]</code> to insert.
* @param str_offset the index in <code>str</code> to start inserting
* from.
* @param len the number of characters to insert.
* @return this <code>StringBuffer</code>.
* @exception NullPointerException if <code>str</code> is <code>null</code>.
* @exception IndexOutOfBoundsException if <code>offset</code> is out
* of range, for this <code>StringBuffer</code>, or if
* <code>str_offset</code> or <code>str_offset+len</code>
* are out of range for <code>str</code>.
*/
public synchronized StringBuffer insert(int offset, char[] str,
int str_offset, int len)
{
if (offset < 0 || offset > count)
throw new StringIndexOutOfBoundsException (offset);
if (len < 0)
throw new StringIndexOutOfBoundsException (len);
if (str_offset < 0 || str_offset + len > str.length)
throw new StringIndexOutOfBoundsException (str_offset);
ensureCapacity_unsynchronized (count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
System.arraycopy(str, str_offset, value, offset, len);
count += len;
return this;
}
/** Get the length of the <code>String</code> this
* <code>StringBuffer</code> would create. Not to be confused with the
* <em>capacity</em> of the <code>StringBuffer</code>.
* @return the length of this <code>StringBuffer</code>.
* @see #capacity()
* @see #setLength(int)
*/
1999-04-07 16:42:40 +02:00
public int length ()
{
return count;
}
/** Replace characters between index <code>start</code> (inclusive) and
* <code>end</code> (exclusive) with <code>str</code>. If <code>end</code>
* is larger than the size of this StringBuffer, all characters after
* <code>start</code> are replaced.
* @param start the beginning index of characters to delete (inclusive).
* @param end the ending index of characters to delete (exclusive).
* @param str the new <code>String</code> to insert.
* @return this <code>StringBuffer</code>.
*/
public synchronized StringBuffer replace (int start, int end, String str)
{
if (start < 0 || start > count || start > end)
throw new StringIndexOutOfBoundsException (start);
int len = str.length();
// Calculate the difference in 'count' after the replace.
int delta = len - ((end > count ? count : end) - start);
ensureCapacity_unsynchronized (count + delta);
if (delta != 0 && end < count)
System.arraycopy(value, end, value, end + delta, count - end);
str.getChars (0, len, value, start);
count += delta;
return this;
}
/** Reverse the characters in this StringBuffer.
* @return this <code>StringBuffer</code>.
*/
1999-04-07 16:42:40 +02:00
public synchronized StringBuffer reverse ()
{
// Call ensureCapacity to enforce copy-on-write.
ensureCapacity_unsynchronized (count);
for (int i = 0; i < count / 2; ++i)
{
char c = value[i];
value[i] = value[count - i - 1];
value[count - i - 1] = c;
}
return this;
}
/** Set the character at the specified index.
* @param index the index of the character to set starting at 0.
* @param ch the value to set that character to.
* @exception IndexOutOfBoundsException if the specified character
* index is not between 0 and length() - 1 (inclusive).
*/
1999-04-07 16:42:40 +02:00
public synchronized void setCharAt (int index, char ch)
{
if (index < 0 || index >= count)
throw new StringIndexOutOfBoundsException (index);
// Call ensureCapacity to enforce copy-on-write.
ensureCapacity_unsynchronized (count);
value[index] = ch;
}
/** Set the length of this StringBuffer.
* <P>
* If the new length is greater than the current length, all the new
* characters are set to '\0'.
* <P>
* If the new length is less than the current length, the first
* <code>newLength</code> characters of the old array will be
* @param newLength the new length
* @exception IndexOutOfBoundsException if the new length is
* negative.
* @see #length()
*/
1999-04-07 16:42:40 +02:00
public synchronized void setLength (int newLength)
{
if (newLength < 0)
throw new StringIndexOutOfBoundsException (newLength);
ensureCapacity_unsynchronized (newLength);
for (int i = count; i < newLength; ++i)
value[i] = '\0';
count = newLength;
}
/** Create a new StringBuffer with default capacity 16.
* @see JLS 20.13.1
*/
1999-04-07 16:42:40 +02:00
public StringBuffer ()
{
this (DEFAULT_CAPACITY);
}
1999-04-07 16:42:40 +02:00
/** Create an empty <code>StringBuffer</code> with the specified initial capacity.
* @param capacity the initial capacity.
*/
1999-04-07 16:42:40 +02:00
public StringBuffer (int capacity)
{
count = 0;
value = new char[capacity];
shared = false;
}
/** Create a new <code>StringBuffer</code> with the characters in the specified <code>String</code>.
* Initial capacity will be the size of the String plus 16.
* @param str the <code>String</code> to make a <code>StringBuffer</code> out of.
* @XXX optimize for sharing.
*/
1999-04-07 16:42:40 +02:00
public StringBuffer (String str)
{
// The documentation is not clear, but experimentation with
// other implementations indicates that StringBuffer(null)
// should throw a NullPointerException.
count = str.length();
// JLS: The initial capacity of the string buffer is 16 plus the
// length of the argument string.
value = new char[count + DEFAULT_CAPACITY];
str.getChars(0, count, value, 0);
shared = false;
}
/**
* Creates a substring of this StringBuffer, starting at a specified index
* and ending at the end of this StringBuffer.
*
* @param beginIndex index to start substring (base 0)
*
* @return new String which is a substring of this StringBuffer
*
* @exception StringIndexOutOfBoundsException
* if (beginIndex < 0 || beginIndex > this.length())
*/
public String substring (int beginIndex)
{
return substring (beginIndex, count);
}
/**
* Creates a substring of this StringBuffer, starting at a specified index
* and ending at one character before a specified index.
*
* @param beginIndex index to start substring (base 0)
* @param endIndex index after the last character to be
* copied into the substring
*
* @return new String which is a substring of this StringBuffer
*
* @exception StringIndexOutOfBoundsException
* if (beginIndex < 0 || endIndex > this.length() || beginIndex > endIndex)
*/
public synchronized String substring (int beginIndex, int endIndex)
{
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex)
throw new StringIndexOutOfBoundsException ();
// FIXME: for libgcj it would be possible, and more efficient, to
// enable sharing here.
return new String (value, beginIndex, endIndex - beginIndex);
}
/** Convert this <code>StringBuffer</code> to a <code>String</code>.
* @return the characters in this StringBuffer
*/
1999-04-07 16:42:40 +02:00
public String toString ()
{
// Note: in libgcj this causes the StringBuffer to be shared. In
// Classpath it does not.
return new String (this);
}
1999-04-07 16:42:40 +02:00
// Index of next available character. Note that this has
// permissions set this way so that String can get the value.
int count;
// The buffer. Note that this has permissions set this way so that
// String can get the value.
char[] value;
1999-04-07 16:42:40 +02:00
// True if we need to copy the buffer before writing to it again.
// FIXME: JDK 1.2 doesn't specify this. The new buffer-growing
// semantics make this less useful in that case, too. Note that
// this has permissions set this way so that String can get the
// value.
boolean shared;
static final long serialVersionUID = 3388685877147921107L;
private final static int DEFAULT_CAPACITY = 16; // JLS 20.13.1
1999-04-07 16:42:40 +02:00
}