Index: src/main/java/java/lang/StringBuffer.java =================================================================== --- src/main/java/java/lang/StringBuffer.java (revision 412006) +++ src/main/java/java/lang/StringBuffer.java (working copy) @@ -16,11 +16,10 @@ package java.lang; import java.io.IOException; -import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; import java.io.Serializable; -import java.util.Arrays; /** * StringBuffer is a variable size contiguous indexable array of characters. The @@ -40,23 +39,16 @@ * @see StringBuilder * @since 1.0 */ -public final class StringBuffer implements Appendable, Serializable, CharSequence { +public final class StringBuffer extends AbstractStringBuilder +implements Appendable, Serializable, CharSequence { private static final long serialVersionUID = 3388685877147921107L; - private static final int INITIAL_SIZE = 16; - - private int count; - - private boolean shared; - - private char[] value; - /** * Constructs a new StringBuffer using the default capacity. */ public StringBuffer() { - this(INITIAL_SIZE); + super(); } /** @@ -66,9 +58,7 @@ * the initial capacity */ public StringBuffer(int capacity) { - count = 0; - shared = false; - value = new char[capacity]; + super(capacity); } /** @@ -83,10 +73,7 @@ * string */ public StringBuffer(String string) { - count = string.length(); - shared = false; - value = new char[count + INITIAL_SIZE]; - string.getChars(0, count, value, 0); + super(string); } /** @@ -101,13 +88,7 @@ * @since 1.5 */ public StringBuffer(CharSequence cs) { - super(); - count = cs.length(); - shared = false; - value = new char[count + INITIAL_SIZE]; - for (int i = 0; i < count; i++) { - value[i] = cs.charAt(i); - } + super(cs.toString()); } /** @@ -121,15 +102,7 @@ * when chars is null */ public synchronized StringBuffer append(char chars[]) { - int newSize = count + chars.length; - if (newSize > value.length) { - ensureCapacityImpl(newSize); - } else if (shared) { - value = (char[]) value.clone(); - shared = false; - } - System.arraycopy(chars, 0, value, count, chars.length); - count = newSize; + append0(chars); return this; } @@ -152,23 +125,8 @@ * when chars is null */ public synchronized StringBuffer append(char chars[], int start, int length) { - if (chars == null) { - throw new NullPointerException(); - } - // start + length could overflow, start/length maybe MaxInt - if (start >= 0 && 0 <= length && length <= chars.length - start) { - int newSize = count + length; - if (newSize > value.length) { - ensureCapacityImpl(newSize); - } else if (shared) { - value = (char[]) value.clone(); - shared = false; - } - System.arraycopy(chars, start, value, count, length); - count = newSize; - return this; - } - throw new ArrayIndexOutOfBoundsException(); + append0(chars, start, length); + return this; } /** @@ -179,16 +137,8 @@ * @return this StringBuffer */ public synchronized StringBuffer append(char ch) { - if (count >= value.length) { - ensureCapacityImpl(count + 1); - } - if (shared) { - value = (char[]) value.clone(); - shared = false; - } - value[count] = ch; - count++; - return this; + append0(ch); + return this; } /** @@ -200,7 +150,7 @@ * @return this StringBuffer */ public StringBuffer append(double d) { - return append(String.valueOf(d)); + return append(Double.toString(d)); } /** @@ -212,7 +162,7 @@ * @return this StringBuffer */ public StringBuffer append(float f) { - return append(String.valueOf(f)); + return append(Float.toString(f)); } /** @@ -247,8 +197,12 @@ * the object * @return this StringBuffer */ - public StringBuffer append(Object obj) { - return append(String.valueOf(obj)); + public synchronized StringBuffer append(Object obj) { + if (obj == null) + appendNull(); + else + append0(obj.toString()); + return this; } /** @@ -259,19 +213,8 @@ * @return this StringBuffer */ public synchronized StringBuffer append(String string) { - if (string == null) - string = String.valueOf(string); - int adding = string.length(); - int newSize = count + adding; - if (newSize > value.length) { - ensureCapacityImpl(newSize); - } else if (shared) { - value = (char[]) value.clone(); - shared = false; - } - string.getChars(0, adding, value, count); - count = newSize; - return this; + append0(string); + return this; } /** @@ -283,23 +226,10 @@ * @return this StringBuffer */ public StringBuffer append(boolean b) { - return append(String.valueOf(b)); + return append(b ? "true" : "false"); } /** - * Answers the number of characters this StringBuffer can hold without - * growing. - * - * @return the capacity of this StringBuffer - * - * @see #ensureCapacity - * @see #length - */ - public int capacity() { - return value.length; - } - - /** * Answers the character at the specified offset in this StringBuffer. * * @param index @@ -311,12 +241,7 @@ * index >= length() */ public synchronized char charAt(int index) { - try { - if (index < count) - return value[index]; - } catch (IndexOutOfBoundsException e) { - } - throw new StringIndexOutOfBoundsException(index); + return super.charAt(index); } /** @@ -333,35 +258,8 @@ * end > length() */ public synchronized StringBuffer delete(int start, int end) { - if (start >= 0) { - if (end > count) - end = count; - if (end > start) { - int length = count - end; - if (length > 0) { - try { - if (!shared) { - System.arraycopy(value, end, value, start, length); - } else { - char[] newData = new char[value.length]; - System.arraycopy(value, 0, newData, 0, start); - System - .arraycopy(value, end, newData, start, - length); - value = newData; - shared = false; - } - } catch (IndexOutOfBoundsException e) { - throw new StringIndexOutOfBoundsException(); - } - } - count -= end - start; - return this; - } - if (start == end) - return this; - } - throw new StringIndexOutOfBoundsException(); + delete0(start, end); + return this; } /** @@ -376,29 +274,8 @@ * location >= length() */ public synchronized StringBuffer deleteCharAt(int location) { - if (0 <= location && location < count) { - int length = count - location - 1; - if (length > 0) { - try { - if (!shared) { - System.arraycopy(value, location + 1, value, location, - length); - } else { - char[] newData = new char[value.length]; - System.arraycopy(value, 0, newData, 0, location); - System.arraycopy(value, location + 1, newData, - location, length); - value = newData; - shared = false; - } - } catch (IndexOutOfBoundsException e) { - throw new StringIndexOutOfBoundsException(location); - } - } - count--; - return this; - } - throw new StringIndexOutOfBoundsException(location); + deleteCharAt0(location); + return this; } /** @@ -410,18 +287,9 @@ * hold before growing */ public synchronized void ensureCapacity(int min) { - if (min > value.length) - ensureCapacityImpl(min); + super.ensureCapacity(min); } - private void ensureCapacityImpl(int min) { - int twice = (value.length << 1) + 2; - char[] newData = new char[min > twice ? min : twice]; - System.arraycopy(value, 0, newData, 0, count); - value = newData; - shared = false; - } - /** * Copies the specified characters in this StringBuffer to the character * array starting at the specified offset in the character array. @@ -441,17 +309,8 @@ * @exception NullPointerException * when buffer is null */ - public synchronized void getChars(int start, int end, char[] buffer, - int index) { - // NOTE last character not copied! - try { - if (start <= count && end <= count) { - System.arraycopy(value, start, buffer, index, end - start); - return; - } - } catch (IndexOutOfBoundsException e) { - } - throw new ArrayIndexOutOfBoundsException(); + public synchronized void getChars(int start, int end, char[] buffer, int idx) { + super.getChars(start, end, buffer, idx); } /** @@ -470,13 +329,8 @@ * when chars is null */ public synchronized StringBuffer insert(int index, char[] chars) { - if (0 <= index && index <= count) { - move(chars.length, index); - System.arraycopy(chars, 0, value, index, chars.length); - count += chars.length; - return this; - } - throw new StringIndexOutOfBoundsException(index); + insert0(index, chars); + return this; } /** @@ -502,17 +356,8 @@ */ public synchronized StringBuffer insert(int index, char chars[], int start, int length) { - if (0 <= index && index <= count) { - // start + length could overflow, start/length maybe MaxInt - if (start >= 0 && 0 <= length && length <= chars.length - start) { - move(length, index); - System.arraycopy(chars, start, value, index, length); - count += length; - return this; - } - throw new StringIndexOutOfBoundsException(); - } - throw new StringIndexOutOfBoundsException(index); + insert0(index, chars, start, length); + return this; } /** @@ -529,13 +374,8 @@ * index > length() */ public synchronized StringBuffer insert(int index, char ch) { - if (0 <= index && index <= count) { - move(1, index); - value[index] = ch; - count++; - return this; - } - throw new ArrayIndexOutOfBoundsException(index); + insert0(index, ch); + return this; } /** @@ -553,7 +393,7 @@ * index > length() */ public StringBuffer insert(int index, double d) { - return insert(index, String.valueOf(d)); + return insert(index, Double.toString(d)); } /** @@ -571,7 +411,7 @@ * index > length() */ public StringBuffer insert(int index, float f) { - return insert(index, String.valueOf(f)); + return insert(index, Float.toString(f)); } /** @@ -625,7 +465,7 @@ * index > length() */ public StringBuffer insert(int index, Object obj) { - return insert(index, String.valueOf(obj)); + return insert(index, obj == null ? "null" : obj.toString()); } /** @@ -642,16 +482,8 @@ * index > length() */ public synchronized StringBuffer insert(int index, String string) { - if (0 <= index && index <= count) { - if (string == null) - string = String.valueOf(string); - int min = string.length(); - move(min, index); - string.getChars(0, min, value, index); - count += min; - return this; - } - throw new StringIndexOutOfBoundsException(index); + insert0(index, string); + return this; } /** @@ -669,41 +501,10 @@ * index > length() */ public StringBuffer insert(int index, boolean b) { - return insert(index, String.valueOf(b)); + return insert(index, b ? "true" : "false"); } /** - * Answers the size of this StringBuffer. - * - * @return the number of characters in this StringBuffer - */ - public int length() { - return count; - } - - private void move(int size, int index) { - int newSize; - if (value.length - count >= size) { - if (!shared) { - System.arraycopy(value, index, value, index + size, count - - index); // index == count case is no-op - return; - } - newSize = value.length; - } else { - int a = count + size, b = (value.length << 1) + 2; - newSize = a > b ? a : b; - } - - char[] newData = new char[newSize]; - System.arraycopy(value, 0, newData, 0, index); - // index == count case is no-op - System.arraycopy(value, index, newData, index + size, count - index); - value = newData; - shared = false; - } - - /** * Replace a range of characters with the characters in the specified * String. * @@ -719,44 +520,8 @@ * when start < 0 or start > end */ public synchronized StringBuffer replace(int start, int end, String string) { - if (start >= 0) { - if (end > count) - end = count; - if (end > start) { - int stringLength = string.length(); - int diff = end - start - stringLength; - if (diff > 0) { // replacing with fewer characters - if (!shared) { - // index == count case is no-op - System.arraycopy(value, end, value, start - + stringLength, count - end); - } else { - char[] newData = new char[value.length]; - System.arraycopy(value, 0, newData, 0, start); - // index == count case is no-op - System.arraycopy(value, end, newData, start - + stringLength, count - end); - value = newData; - shared = false; - } - } else if (diff < 0) { - // replacing with more characters...need some room - move(-diff, end); - } else if (shared) { - value = (char[]) value.clone(); - shared = false; - } - string.getChars(0, stringLength, value, start); - count -= diff; - return this; - } - if (start == end) { - if (string == null) - throw new NullPointerException(); - return insert(start, string); - } - } - throw new StringIndexOutOfBoundsException(); + replace0(start, end, string); + return this; } /** @@ -765,24 +530,8 @@ * @return this StringBuffer */ public synchronized StringBuffer reverse() { - if (count < 2) { - return this; - } - if (!shared) { - for (int i = 0, end = count, mid = count / 2; i < mid; i++) { - char temp = value[--end]; - value[end] = value[i]; - value[i] = temp; - } - } else { - char[] newData = new char[value.length]; - for (int i = 0, end = count; i < count; i++) { - newData[--end] = value[i]; - } - value = newData; - shared = false; - } - return this; + reverse0(); + return this; } /** @@ -798,14 +547,7 @@ * index >= length() */ public synchronized void setCharAt(int index, char ch) { - if (shared) { - value = (char[]) value.clone(); - shared = false; - } - if (0 <= index && index < count) - value[index] = ch; - else - throw new StringIndexOutOfBoundsException(index); + super.setCharAt(index, ch); } /** @@ -823,27 +565,7 @@ * @see #length */ public synchronized void setLength(int length) { - if (length > value.length) - ensureCapacityImpl(length); - if (count > length) { - if (!shared) { - // NOTE: delete & replace do not void characters orphaned at the - // end - try { - Arrays.fill(value, length, count, (char) 0); - } catch (ArrayIndexOutOfBoundsException e) { - throw new IndexOutOfBoundsException(); - } - } else { - char[] newData = new char[value.length]; - if (length > 0) { - System.arraycopy(value, 0, newData, 0, length); - } - value = newData; - shared = false; - } - } - count = length; + super.setLength(length); } /** @@ -859,11 +581,7 @@ * start > length() */ public synchronized String substring(int start) { - if (0 <= start && start <= count) { - shared = true; - return new String(start, count - start, value); - } - throw new StringIndexOutOfBoundsException(start); + return super.substring(start); } /** @@ -880,11 +598,7 @@ * end > length() */ public synchronized String substring(int start, int end) { - if (0 <= start && start <= end && end <= count) { - shared = true; - return new String(value, start, end - start); - } - throw new StringIndexOutOfBoundsException(); + return super.substring(start, end); } /** @@ -893,35 +607,9 @@ * @return a String containing the characters in this StringBuffer */ public synchronized String toString() { - if (count >= 256 && count <= (value.length >> 1)) - return new String(value, 0, count); - shared = true; - return new String(0, count, value); + return super.toString(); } - /* - * Return the underlying buffer and set the shared flag. - * - */ - char[] shareValue() { - shared = true; - return value; - } - - private synchronized void writeObject(ObjectOutputStream stream) - throws IOException { - stream.defaultWriteObject(); - } - - private void readObject(ObjectInputStream stream) throws IOException, - ClassNotFoundException { - stream.defaultReadObject(); - if (count > value.length) - throw new InvalidObjectException(org.apache.harmony.luni.util.Msg - .getString("K0199")); - shared = false; - } - /** * Adds the specified StringBuffer to the end of this StringBuffer. * @@ -931,21 +619,14 @@ * * @since 1.4 */ - public synchronized StringBuffer append(StringBuffer sbuffer) { - if (sbuffer == null) - return append((String) null); - synchronized (sbuffer) { - int adding = sbuffer.count; - int newSize = count + adding; - if (newSize > value.length) { - ensureCapacityImpl(newSize); - } else if (shared) { - value = (char[]) value.clone(); - shared = false; - } - System.arraycopy(sbuffer.value, 0, value, count, adding); - count = newSize; - } + public synchronized StringBuffer append(StringBuffer sb) { + if (sb == null) { + appendNull(); + } else { + synchronized (sb) { + append0(sb.getValue(), 0, sb.length()); + } + } return this; } @@ -964,30 +645,11 @@ * * @since 1.4 */ - public CharSequence subSequence(int start, int end) { - return substring(start, end); + public synchronized CharSequence subSequence(int start, int end) { + return super.substring(start, end); } /** - * Searches in this StringBuffer for the first index of the specified - * character. The search for the character starts at the beginning and moves - * towards the end. - * - * - * @param string - * the string to find - * @return the index in this StringBuffer of the specified character, -1 if - * the character isn't found - * - * @see #lastIndexOf(String) - * - * @since 1.4 - */ - public int indexOf(String string) { - return indexOf(string, 0); - } - - /** * Searches in this StringBuffer for the index of the specified character. * The search for the character starts at the specified offset and moves * towards the end. @@ -1004,54 +666,10 @@ * @since 1.4 */ public synchronized int indexOf(String subString, int start) { - if (start < 0) - start = 0; - int subCount = subString.length(); - if (subCount > 0) { - if (subCount + start > count) - return -1; - char firstChar = subString.charAt(0); - while (true) { - int i = start; - boolean found = false; - for (; i < count; i++) - if (value[i] == firstChar) { - found = true; - break; - } - if (!found || subCount + i > count) - return -1; // handles subCount > count || start >= count - int o1 = i, o2 = 0; - while (++o2 < subCount && value[++o1] == subString.charAt(o2)) { - // Intentionally empty - } - if (o2 == subCount) - return i; - start = i + 1; - } - } - return (start < count || start == 0) ? start : count; + return super.indexOf(subString, start); } /** - * Searches in this StringBuffer for the last index of the specified - * character. The search for the character starts at the end and moves - * towards the beginning. - * - * @param string - * the string to find - * @return the index in this StringBuffer of the specified character, -1 if - * the character isn't found - * - * @see #indexOf(String) - * - * @since 1.4 - */ - public synchronized int lastIndexOf(String string) { - return lastIndexOf(string, count); - } - - /** * Searches in this StringBuffer for the index of the specified character. * The search for the character starts at the specified offset and moves * towards the beginning. @@ -1068,46 +686,10 @@ * @since 1.4 */ public synchronized int lastIndexOf(String subString, int start) { - int subCount = subString.length(); - if (subCount <= count && start >= 0) { - if (subCount > 0) { - if (start > count - subCount) - start = count - subCount; // count and subCount are both - // >= 1 - char firstChar = subString.charAt(0); - while (true) { - int i = start; - boolean found = false; - for (; i >= 0; --i) - if (value[i] == firstChar) { - found = true; - break; - } - if (!found) - return -1; - int o1 = i, o2 = 0; - while (++o2 < subCount - && value[++o1] == subString.charAt(o2)) { - // Intentionally empty - } - if (o2 == subCount) - return i; - start = i - 1; - } - } - return start < count ? start : count; - } - return -1; - } + return super.lastIndexOf(subString, start); + } - /* - * Returns the character array for this StringBuffer. - */ - char[] getValue() { - return value; - } - - /** + /** *

* Trims the storage capacity of this buffer down to the size of the current * character sequence. Execution of this method may change the results @@ -1117,12 +699,7 @@ * @since 1.5 */ public synchronized void trimToSize() { - if (count < value.length) { - char[] newValue = new char[count]; - System.arraycopy(value, 0, newValue, 0, count); - value = newValue; - shared = false; - } + super.trimToSize(); } /** @@ -1140,9 +717,7 @@ * @since 1.5 */ public synchronized int codePointAt(int index) { - if (index < 0 || index >= count) - throw new IndexOutOfBoundsException(); - return Character.codePointAt(value, index, count); + return super.codePointAt(index); } /** @@ -1161,9 +736,7 @@ * @since 1.5 */ public synchronized int codePointBefore(int index) { - if (index < 1 || index > count) - throw new IndexOutOfBoundsException(); - return Character.codePointBefore(value, index); + return super.codePointBefore(index); } /** @@ -1181,10 +754,7 @@ * @since 1.5 */ public synchronized int codePointCount(int beginIndex, int endIndex) { - if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) - throw new IndexOutOfBoundsException(); - return Character.codePointCount(value, beginIndex, endIndex - - beginIndex); + return super.codePointCount(beginIndex, endIndex); } /** @@ -1203,8 +773,7 @@ * @since 1.5 */ public synchronized int offsetByCodePoints(int index, int codePointOffset) { - return Character.offsetByCodePoints(value, 0, count, index, - codePointOffset); + return super.offsetByCodePoints(index, codePointOffset); } /** @@ -1215,10 +784,11 @@ * @return A reference to this object. * @since 1.5 */ - public StringBuffer append(CharSequence s) { + public synchronized StringBuffer append(CharSequence s) { if (s == null) - s = "null"; - append(s.toString()); + appendNull(); + else + append0(s.toString()); return this; } @@ -1233,13 +803,8 @@ * @since 1.5 * @throws IndexOutOfBoundsException if start or end are negative, start is greater than end or end is greater than the length of s. */ - public StringBuffer append(CharSequence s, int start, int end) { - if (s == null) - s = "null"; - if (start < 0 || end < 0 || start > end || end > s.length()) - throw new IndexOutOfBoundsException(); - - append(s.subSequence(start, end)); + public synchronized StringBuffer append(CharSequence s, int start, int end) { + append0(s, start, end); return this; } @@ -1269,10 +834,8 @@ * @since 1.5 * @throws IndexOutOfBoundsException if the index is invalid. */ - public StringBuffer insert(int index, CharSequence s) { - if (s == null) - s = "null"; - insert(index, s.toString()); + public synchronized StringBuffer insert(int index, CharSequence s) { + insert0(index, s == null ? "null" : s.toString()); return this; } @@ -1297,13 +860,31 @@ * than end or end is greater than the * length of s. */ - public StringBuffer insert(int index, CharSequence s, int start, int end) { - if (s == null) - s = "null"; - if (index < 0 || index > count || start < 0 || end < 0 || start > end - || end > s.length()) - throw new IndexOutOfBoundsException(); - insert(index, s.subSequence(start, end)); + public synchronized StringBuffer insert(int index, CharSequence s, int start, int end) { + insert0(index, s, start, end); return this; } + + private static final ObjectStreamField serialPersistentFields[] = { + new ObjectStreamField("count", int.class), + new ObjectStreamField("shared", boolean.class), + new ObjectStreamField("value", char[].class), + }; + + private synchronized void writeObject(ObjectOutputStream out) + throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("count", length()); + fields.put("shared", false); + fields.put("value", getValue()); + out.writeFields(); + } + + private void readObject(ObjectInputStream in) throws IOException, + ClassNotFoundException { + ObjectInputStream.GetField fields = in.readFields(); + int count = fields.get("count", 0); + char[] value = (char[])fields.get("value", null); + set(value, count); + } } Index: src/main/java/java/lang/StringBuilder.java =================================================================== --- src/main/java/java/lang/StringBuilder.java (revision 412006) +++ src/main/java/java/lang/StringBuilder.java (working copy) @@ -44,22 +44,11 @@ * * @author Nathan Beyer (Harmony) */ -public final class StringBuilder implements Appendable, CharSequence, Serializable { +public final class StringBuilder extends AbstractStringBuilder +implements Appendable, CharSequence, Serializable { private static final long serialVersionUID = 4383685877147921099L; - private static final String EMPTY_STRING = ""; //$NON-NLS-1$ - - private static final String NULL_STRING = "null"; //$NON-NLS-1$ - - private static final char[] NULL_CHAR_ARRAY = NULL_STRING.toCharArray(); - - private static final int INITIAL_CAPACITY = 16; - - private transient char[] buffer; - - private transient int length; - /** *

* Constructs an instance with an initial capacity of 16. @@ -69,7 +58,6 @@ */ public StringBuilder() { super(); - this.buffer = new char[INITIAL_CAPACITY]; } /** @@ -85,10 +73,7 @@ * @see #capacity() */ public StringBuilder(int capacity) { - super(); - if (capacity < 0) - throw new NegativeArraySizeException(); - this.buffer = new char[capacity]; + super(capacity); } /** @@ -103,14 +88,7 @@ * null. */ public StringBuilder(CharSequence seq) { - super(); - if (seq == null) - throw new NullPointerException(); - this.length = seq.length(); - this.buffer = new char[length + 16]; - for (int i = 0; i < length; i++) { - this.buffer[i] = seq.charAt(i); - } + super(seq.toString()); } /** @@ -125,7 +103,7 @@ * null. */ public StringBuilder(String str) { - this((CharSequence) str); + super(str); } /** @@ -141,7 +119,8 @@ * @see String#valueOf(boolean) */ public StringBuilder append(boolean b) { - return append(String.valueOf(b)); + append0(b ? "true" : "false"); + return this; } /** @@ -157,7 +136,8 @@ * @see String#valueOf(char) */ public StringBuilder append(char c) { - return append(String.valueOf(c)); + append0(c); + return this; } /** @@ -172,8 +152,9 @@ * * @see String#valueOf(char[]) */ - public StringBuilder append(char[] str) { - return append(String.valueOf(str)); + public StringBuilder append(char[] ch) { + append0(ch); + return this; } /** @@ -194,7 +175,8 @@ * @see String#valueOf(char[],int,int) */ public StringBuilder append(char[] str, int offset, int len) { - return append(String.valueOf(str, offset, len)); + append0(str, offset, len); + return this; } /** @@ -209,7 +191,11 @@ * @return A reference to this object. */ public StringBuilder append(CharSequence csq) { - return append((String) (csq == null ? null : csq.toString())); + if (csq == null) + appendNull(); + else + append0(csq.toString()); + return this; } /** @@ -227,9 +213,8 @@ * @return A reference to this object. */ public StringBuilder append(CharSequence csq, int start, int end) { - if (csq == null) - csq = NULL_STRING; - return append(csq.subSequence(start, end)); + append0(csq, start, end); + return this; } /** @@ -245,7 +230,8 @@ * @see String#valueOf(double) */ public StringBuilder append(double d) { - return append(String.valueOf(d)); + append0(Double.toString(d)); + return this; } /** @@ -261,7 +247,8 @@ * @see String#valueOf(float) */ public StringBuilder append(float f) { - return append(String.valueOf(f)); + append0(Float.toString(f)); + return this; } /** @@ -277,7 +264,8 @@ * @see String#valueOf(int) */ public StringBuilder append(int i) { - return append(String.valueOf(i)); + append0(Integer.toString(i)); + return this; } /** @@ -293,7 +281,8 @@ * @see String#valueOf(long) */ public StringBuilder append(long lng) { - return append(String.valueOf(lng)); + append0(Long.toString(lng)); + return this; } /** @@ -309,7 +298,11 @@ * @see String#valueOf(Object) */ public StringBuilder append(Object obj) { - return append(String.valueOf(obj)); + if (obj == null) + appendNull(); + else + append0(obj.toString()); + return this; } /** @@ -322,18 +315,7 @@ * @return A reference to this object. */ public StringBuilder append(String str) { - // if null or interned "null" string append "null" - if (str == null || str == NULL_STRING) { - ensureCapacity(length + 4); - System.arraycopy(NULL_CHAR_ARRAY, 0, buffer, length, 4); - length += 4; - } else { - int len = str.length(); - ensureCapacity(length + len); - for (int i = 0; i < len; i++) { - buffer[length++] = str.charAt(i); - } - } + append0(str); return this; } @@ -348,7 +330,12 @@ * @return A reference to this object. */ public StringBuilder append(StringBuffer sb) { - return append((CharSequence) sb); + if (sb == null) { + appendNull(); + } else { + append0(sb.getValue(), 0, sb.length()); + } + return this; } /** @@ -363,97 +350,12 @@ * @see Character#toChars(int) */ public StringBuilder appendCodePoint(int codePoint) { - return append(Character.toChars(codePoint)); + append0(Character.toChars(codePoint)); + return this; } /** *

- * The current capacity of this object. - *

- * - * @return An int value representing the capacity. - */ - public int capacity() { - return buffer.length; - } - - /** - *

- * Retrieves the character at the index. - *

- * - * @param The index of character in this object to retrieve. - * @return The char value. - * @throws IndexOutOfBoundsException if index is negative or - * greater than or equal to the current {@link #length()}. - */ - public char charAt(int index) { - if (index < 0 || index >= length) - throw new IndexOutOfBoundsException(); - return buffer[index]; - } - - /** - *

- * Retrieves the Unicode code point value at the index. - *

- * - * @param index The index to the char code unit within this - * object. - * @return The Unicode code point value. - * @throws IndexOutOfBoundsException if index is negative or - * greater than or equal to {@link #length()}. - * @see Character - * @see Character#codePointAt(char[], int, int) - */ - public int codePointAt(int index) { - if (index < 0 || index >= length) - throw new IndexOutOfBoundsException(); - return Character.codePointAt(buffer, index, length); - } - - /** - *

- * Retrieves the Unicode code point value that precedes the - * index. - *

- * - * @param index The index to the char code unit within this - * object. - * @return The Unicode code point value. - * @throws IndexOutOfBoundsException if index is less than 1 - * or greater than {@link #length()}. - * @see Character - * @see Character#codePointBefore(char[], int, int) - */ - public int codePointBefore(int index) { - if (index < 1 || index > length) - throw new IndexOutOfBoundsException(); - return Character.codePointBefore(buffer, index); - } - - /** - *

- * Calculates the number of Unicode code points between - * beginIndex and endIndex. - *

- * - * @param beginIndex The inclusive beginning index of the subsequence. - * @param endIndex The exclusive end index of the subsequence. - * @return The number of Unicode code points in the subsequence. - * @throws IndexOutOfBoundsException if beginIndex is - * negative or greater than endIndex or - * endIndex is greater than {@link #length()}. - */ - public int codePointCount(int beginIndex, int endIndex) { - if (beginIndex < 0 || endIndex > length || beginIndex > endIndex) - throw new IndexOutOfBoundsException(); - return Character.codePointCount(buffer, beginIndex, endIndex - - beginIndex); - } - - /** - *

* Deletes a sequence of characters within this object, shifts any remaining * characters to the left and adjusts the {@link #length()} of this object. *

@@ -466,17 +368,7 @@ * end. */ public StringBuilder delete(int start, int end) { - if (start < 0 || start > length || start > end) - throw new StringIndexOutOfBoundsException(); - if (start != end) { - // massage end if it's too long - if (end > length) - end = length; - // shift chars left - System.arraycopy(buffer, end, buffer, start, length - end); - // adjust length - length -= (end - start); - } + delete0(start, end); return this; } @@ -492,122 +384,12 @@ * than zero or is greater than or equal to the current length. */ public StringBuilder deleteCharAt(int index) { - // check for index values past length, as 'delete' will massage them out - if (index >= length) - throw new StringIndexOutOfBoundsException(); - return delete(index, index + 1); + deleteCharAt0(index); + return this; } /** *

- * Ensures that this object has a minimum capacity available before - * requiring the internal buffer to be enlarged. The general policy of this - * method is that if the minimumCapacity is larger than the - * current {@link #capacity()}, then the capacity will be increased to the - * largest value of either the minimumCapacity or the current - * capacity multiplied by two plus two. Although this is the general policy, - * there is no guarantee that the capacity will change. - *

- * - * @param minimumCapacity The new minimum capacity to set. - */ - public void ensureCapacity(int minimumCapacity) { - if (minimumCapacity > buffer.length) { - /* - * Create a new buffer that's the greater of the requested capacity - * or the current capacity multiplied by 2 plus 2. - */ - char[] newbuffer = new char[Math.max(minimumCapacity, - (buffer.length * 2) + 2)]; - // copy the original buffer's contents - System.arraycopy(buffer, 0, newbuffer, 0, length); - // assign new buffer to instance field - buffer = newbuffer; - } - } - - /** - *

- * Copies the requested sequence of characters to be copied to the - * char[] passed. - *

- * - * @param srcBegin The inclusive start index of the characters to copy from - * this object. - * @param srcEnd The exclusive end index of the characters to copy from this - * object. - * @param dst The char[] to copy the characters to. - * @param dstBegin The inclusive start index of the dst - * parameter to begin copying to. - * @throws IndexOutOfBoundsException if the srcBegin is - * negative, the dstBegin is negative, the - * srcBegin is greater than srcEnd, - * the srcEnd is greater than the current - * {@link #length()} or dstBegin + srcEnd - srcBegin - * is greater than dst.lenbth. - */ - public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { - if (dst == null) - throw new NullPointerException(); - if (srcBegin < 0 || dstBegin < 0 || srcBegin > srcEnd - || srcEnd > length - || (dstBegin + srcEnd - srcBegin) > dst.length) - throw new IndexOutOfBoundsException(); - - System.arraycopy(buffer, srcBegin, dst, dstBegin, srcEnd - srcBegin); - } - - /** - *

- * Searches this object for a match to the String passed and returns the - * index of the first character that matches or -1 if a match - * wasn't found. This method follows the same rules as the - * {@link String#indexOf(java.lang.String)}. - *

- * - * @param str The pattern to search for. - * @return The beginning index of the matching sequence or -1 - * if no match was found. - * - * @throws NullPointerException if the str parameter is - * null. - * - * @see String#indexOf(java.lang.String) - */ - public int indexOf(String str) { - if (str == null) - throw new NullPointerException(); - return indexOf(str, 0); - } - - /** - *

- * Searches this object, starting at the fromIndex, for a - * match to the String passed and returns the index of the first character - * that matches or -1 if a match wasn't found. This method - * follows the same rules as the - * {@link String#indexOf(java.lang.String,int)}. - *

- * - * @param str The pattern to search for. - * @param fromIndex The index of this object to begin searching at. - * @return The beginning index of the matching sequence or -1 - * if no match was found. - * - * @throws NullPointerException if the str parameter is - * null. - * - * @see String#indexOf(java.lang.String,int) - */ - public int indexOf(String str, int fromIndex) { - if (str == null) - throw new NullPointerException(); - //TODO optimize - return this.toString().indexOf(str, fromIndex); - } - - /** - *

* Inserts the String representation of the boolean value * passed into this object at the offset passed. The * boolean value is converted to a String according to the @@ -624,10 +406,8 @@ * @see String#valueOf(boolean) */ public StringBuilder insert(int offset, boolean b) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(b)); + insert0(offset, b ? "true" : "false"); + return this; } /** @@ -648,10 +428,8 @@ * @see String#valueOf(char) */ public StringBuilder insert(int offset, char c) { - if (offset < 0 || offset > length) - throw new ArrayIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(c)); + insert0(offset, c); + return this; } /** @@ -663,7 +441,7 @@ *

* * @param offset The index of this object to insert the value. - * @param str The char[] value to insert into this object. + * @param ch The char[] value to insert into this object. * @return A reference to this object. * * @throws StringIndexOutOfBoundsException if offset is @@ -671,11 +449,9 @@ * * @see String#valueOf(char[]) */ - public StringBuilder insert(int offset, char[] str) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(str)); + public StringBuilder insert(int offset, char[] ch) { + insert0(offset, ch); + return this; } /** @@ -702,10 +478,8 @@ */ public StringBuilder insert(int offset, char[] str, int strOffset, int strLen) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(str, strOffset, strLen)); + insert0(offset, str, strOffset, strLen); + return this; } /** @@ -728,10 +502,8 @@ * @see CharSequence#toString() */ public StringBuilder insert(int offset, CharSequence s) { - if (offset < 0 || offset > length) - throw new IndexOutOfBoundsException(); - - return insert(offset, (s == null ? (String) null : s.toString())); + insert0(offset, s == null ? "null" : s.toString()); + return this; } /** @@ -759,13 +531,8 @@ * @see CharSequence#subSequence(int, int) */ public StringBuilder insert(int offset, CharSequence s, int start, int end) { - if (offset < 0 || offset > length) - throw new IndexOutOfBoundsException(); - - if (s == null) - s = NULL_STRING; - - return insert(offset, s.subSequence(start, end)); + insert0(offset, s, start, end); + return this; } /** @@ -786,10 +553,8 @@ * @see String#valueOf(double) */ public StringBuilder insert(int offset, double d) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(d)); + insert0(offset, Double.toString(d)); + return this; } /** @@ -810,10 +575,8 @@ * @see String#valueOf(float) */ public StringBuilder insert(int offset, float f) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(f)); + insert0(offset, Float.toString(f)); + return this; } /** @@ -834,10 +597,8 @@ * @see String#valueOf(int) */ public StringBuilder insert(int offset, int i) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(i)); + insert0(offset, Integer.toString(i)); + return this; } /** @@ -858,10 +619,8 @@ * @see String#valueOf(long) */ public StringBuilder insert(int offset, long l) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(l)); + insert0(offset, Long.toString(l)); + return this; } /** @@ -882,10 +641,8 @@ * @see String#valueOf(Object) */ public StringBuilder insert(int offset, Object obj) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - return insert(offset, String.valueOf(obj)); + insert0(offset, obj == null ? "null" : obj.toString()); + return this; } /** @@ -903,105 +660,13 @@ * negative or greater than the current {@link #length()}. */ public StringBuilder insert(int offset, String str) { - if (offset < 0 || offset > length) - throw new StringIndexOutOfBoundsException(); - - if (str == null) - str = NULL_STRING; - - int len = str.length(); - ensureCapacity(length + len); - // shift chars right - System.arraycopy(buffer, offset, buffer, offset + len, length - offset); - // adjust length - length += len; - // copy in new chars - for (int i = 0, j = offset; i < len; i++, j++) - buffer[j] = str.charAt(i); + insert0(offset, str); return this; } - /** - *

- * Searches this object for the last match to the String passed and returns - * the index of the first character that matches or -1 if a - * match wasn't found. This method follows the same rules as the - * {@link String#lastIndexOf(java.lang.String)}. - *

- * - * @param str The pattern to search for. - * @return The beginning index of the matching sequence or -1 - * if no match was found. - * - * @throws NullPointerException if the str parameter is - * null. - * - * @see String#lastIndexOf(java.lang.String) - */ - public int lastIndexOf(String str) { - if (str == null) - throw new NullPointerException(); - return lastIndexOf(str, length); - } /** *

- * Searches this object, starting at the fromIndex, for the - * last match to the String passed and returns the index of the first - * character that matches or -1 if a match wasn't found. This - * method follows the same rules as the - * {@link String#lastIndexOf(java.lang.String,int)}. - *

- * - * @param str The pattern to search for. - * @param fromIndex The index of this object to begin searching at. - * @return The beginning index of the matching sequence or -1 - * if no match was found. - * - * @throws NullPointerException if the str parameter is - * null. - * - * @see String#lastIndexOf(java.lang.String,int) - */ - public int lastIndexOf(String str, int fromIndex) { - if (str == null) - throw new NullPointerException(); - // TODO optimize - return this.toString().lastIndexOf(str, fromIndex); - } - - /** - *

- * The current length of this object. - *

- * - * @return The current length. - */ - public int length() { - return length; - } - - /** - *

- * Returns the index within this object that is offset from - * index by codePointOffset code points. - *

- * - * @param index The index within this object to calculate the offset from. - * @param codePointOffset The number of code points to count. - * @return The index within this object that is the offset. - * @throws IndexOutOfBoundsException if index is negative or - * greater than {@link #length()} or if there aren't enough code - * points before or after index to match - * codePointOffset. - */ - public int offsetByCodePoints(int index, int codePointOffset) { - return Character.offsetByCodePoints(buffer, 0, length, index, - codePointOffset); - } - - /** - *

* Replaces the indicated subsequence of this object with the String passed. * If the String passed is longer or shorter than the subsequence, then this * object will be adjusted appropriately. @@ -1020,32 +685,7 @@ * null. */ public StringBuilder replace(int start, int end, String str) { - if (start < 0 || start > length || start > end) - throw new StringIndexOutOfBoundsException(); - - if (str == null) // TODO verify this undocumented NPE - throw new NullPointerException(); - - // if the start is just past last char, then treat it like an append - if (start == length) { - return append(str); - } - if(end > length) { - end = length; - } - int sbLen = end - start; - int strLen = str.length(); - if (strLen > sbLen) { - // shift chars with an insert of the difference - // this will handle capacity and length management - insert(start, new char[strLen - sbLen]); - } - if(strLen < sbLen) { - delete(start, start + sbLen-strLen); - } - // copy in new chars - for (int i = 0, j = start; i < strLen; i++, j++) - buffer[j] = str.charAt(i); + replace0(start, end, str); return this; } @@ -1057,146 +697,12 @@ * @return A reference to this object. */ public StringBuilder reverse() { - if (length > 1) { // only reverse if necessary - for (int i = 0, j = length - 1; i <= j - 1; i++, j--) { - char c = buffer[j]; - buffer[j] = buffer[i]; - buffer[i] = c; - } - } + reverse0(); return this; } /** *

- * Sets the character at the index in this object. - *

- * - * @param index The index of the character to replace. - * @param ch The character to set. - * @throws IndexOutOfBoundsException if index is negative or - * greater than or equal to the current {@link #length()}. - */ - public void setCharAt(int index, char ch) { - if (index < 0 || index >= length) - throw new IndexOutOfBoundsException(); - buffer[index] = ch; - } - - /** - *

- * Sets the current length to a new value. If the new length is larger than - * the current length, then the new characters at the end of this object - * will contain the char value of \u0000. - *

- * - * @param newLength The new length to set this object to. - * @throws IndexOutOfBoundsException if the newLength - * parameter is negative. - */ - public void setLength(int newLength) { - if (newLength < 0) - throw new IndexOutOfBoundsException(); - if (newLength > length) { - // expand if necessary - ensureCapacity(newLength); - // null out any new chars at the sequence end - for (int i = length; i < newLength; i++) - buffer[i] = 0; - } - length = newLength; - } - - /** - *

- * Returns a CharSequence of the subsequence of this object - * from the start index to the start index. - *

- * - * @param start The inclusive start index to begin the subsequence. - * @param end The exclusive end index to end the subsequence. - * @return A CharSequence containing the subsequence. - * @throws IndexOutOfBoundsException if start is negative, - * greater than the current {@link #length()} or greater than - * end. - */ - public CharSequence subSequence(int start, int end) { - return substring(start, end); - } - - /** - *

- * Returns the String value of the subsequence of this object from the - * start index to the current end. - *

- * - * @param start The inclusive start index to begin the subsequence. - * @return A String containing the subsequence. - * @throws StringIndexOutOfBoundsException if start is - * negative or greater than the current {@link #length()}. - */ - public String substring(int start) { - if (start < 0 || start > length) - throw new StringIndexOutOfBoundsException(); - - int ssCharCnt = length - start; - if (ssCharCnt == 0) - return EMPTY_STRING; - return new String(buffer, start, ssCharCnt); - } - - /** - *

- * Returns the String value of the subsequence of this object from the - * start index to the start index. - *

- * - * @param start The inclusive start index to begin the subsequence. - * @param end The exclusive end index to end the subsequence. - * @return A String containing the subsequence. - * @throws StringIndexOutOfBoundsException if start is - * negative, greater than the current {@link #length()} or greater - * than end. - */ - public String substring(int start, int end) { - if (start < 0 || end > length || start > end) - throw new StringIndexOutOfBoundsException(); - - int ssCharCnt = end - start; - if (ssCharCnt == 0) - return EMPTY_STRING; - return new String(buffer, start, end - start); - } - - /** - *

- * Returns the current String representation of this object. - *

- * - * @return The current String representation of this object. - */ - public String toString() { - if (length == 0) - return EMPTY_STRING; - return new String(buffer, 0, length); - } - - /** - *

- * Trims off any extra capacity beyond the current length. Note, this method - * is NOT guaranteed to change the capacity of this object. - *

- */ - public void trimToSize() { - if (length < buffer.length) { - char[] newbuffer = new char[length]; - System.arraycopy(buffer, 0, newbuffer, 0, length); - buffer = newbuffer; - } - } - - /** - *

* Reads the state of a StringBuilder from the passed stream * and restores it to this instance. *

@@ -1208,8 +714,9 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - length = in.readInt(); - buffer = (char[]) in.readObject(); + int count = in.readInt(); + char[] value = (char[]) in.readObject(); + set(value, count); } /** @@ -1225,7 +732,7 @@ */ private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); - out.writeInt(length); - out.writeObject(buffer); + out.writeInt(length()); + out.writeObject(getValue()); } }