// StringBuffer.java - Growable strings. /* Copyright (C) 1998, 1999 Cygnus Solutions 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 * @date October 23, 1998. */ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 */ public final class StringBuffer implements Serializable { public StringBuffer append (boolean bool) { return append (String.valueOf(bool)); } public synchronized StringBuffer append (char ch) { ensureCapacity (count + 1); value[count++] = ch; return this; } public StringBuffer append (int inum) { return append (String.valueOf(inum)); } public StringBuffer append (long lnum) { return append (String.valueOf(lnum)); } public StringBuffer append (float fnum) { return append (String.valueOf(fnum)); } public StringBuffer append (double dnum) { return append (String.valueOf(dnum)); } public StringBuffer append (Object obj) { return append (String.valueOf(obj)); } public synchronized StringBuffer append (String str) { if (str == null) str = "null"; int len = str.length(); ensureCapacity (count + len); str.getChars(0, len, value, count); count += len; return this; } public StringBuffer append (char[] data) { return append (data, 0, data.length); } public synchronized StringBuffer append (char[] data, int offset, int count) { ensureCapacity (this.count + count); System.arraycopy(data, offset, value, this.count, count); this.count += count; return this; } public int capacity () { return value.length; } public synchronized char charAt (int index) { if (index >= count) throw new StringIndexOutOfBoundsException (index); return value[index]; } 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 = Math.max(minimumCapacity, max); char[] nb = new char[minimumCapacity]; System.arraycopy(value, 0, nb, 0, count); value = nb; shared = false; } } 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); } public StringBuffer insert (int offset, boolean bool) { return insert (offset, bool ? "true" : "false"); } public synchronized StringBuffer insert (int offset, char ch) { if (offset < 0 || offset > count) throw new StringIndexOutOfBoundsException (offset); ensureCapacity (count+1); System.arraycopy(value, offset, value, offset+1, count-offset); value[offset] = ch; count++; return this; } public StringBuffer insert (int offset, int inum) { return insert (offset, String.valueOf(inum)); } public StringBuffer insert (int offset, long lnum) { return insert (offset, String.valueOf(lnum)); } public StringBuffer insert (int offset, float fnum) { return insert (offset, String.valueOf(fnum)); } public StringBuffer insert (int offset, double dnum) { return insert (offset, String.valueOf(dnum)); } public StringBuffer insert (int offset, Object obj) { return insert (offset, String.valueOf(obj)); } 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(count+len); System.arraycopy(value, offset, value, offset+len, count-offset); str.getChars(0, len, value, offset); count += len; return this; } public synchronized StringBuffer insert (int offset, char[] data) { if (offset < 0 || offset > count) throw new StringIndexOutOfBoundsException (offset); int len = data.length; ensureCapacity (count+len); System.arraycopy(value, offset, value, offset+len, count-offset); System.arraycopy(data, 0, value, offset, len); count += len; return this; } public int length () { return count; } public synchronized StringBuffer reverse () { 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; } 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 (count); value[index] = ch; } public synchronized void setLength (int newLength) { if (newLength < 0) throw new StringIndexOutOfBoundsException (newLength); ensureCapacity (newLength); for (int i = count; i < newLength; ++i) value[i] = '\0'; count = newLength; } public StringBuffer () { this (16); } public StringBuffer (int capacity) { count = 0; value = new char[capacity]; shared = false; } public StringBuffer (String str) { // Note: nowhere does it say that we should handle a null // argument here. In fact, the JCL implies that we should not. // But this leads to an asymmetry: `null + ""' will fail, while // `"" + null' will work. if (str == null) str = "null"; count = str.length(); // JLS: The initial capacity of the string buffer is 16 plus the // length of the argument string. value = new char[count + 16]; str.getChars(0, count, value, 0); shared = false; } public String toString () { shared = true; return new String (this); } // The buffer. Note that this has permissions set this way so that // String can get the value. char[] value; // Index of next available character. Note that this has // permissions set this way so that String can get the value. int count; // 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. private boolean shared; }