001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package java.lang;
017:
018: /**
019: * A fast way to create strings using multiple appends. This implementation is
020: * optimized for fast appends. Most methods will give expected performance
021: * results, with the notable exception of {@link #setCharAt(int, char)}, which
022: * is extremely slow and should be avoided if possible.
023: */
024: public final class StringBuffer implements CharSequence {
025:
026: private static native String setLength(String[] stringArray,
027: int length) /*-{
028: stringArray.length = length;
029: }-*/;
030:
031: private static native String join(String[] stringArray) /*-{
032: return stringArray.join('');
033: }-*/;
034:
035: private String[] stringArray = new String[0];
036:
037: private int arrayLen = 0;
038:
039: private int stringLength = 0;
040:
041: public StringBuffer() {
042: }
043:
044: /**
045: * This implementation does not track capacity; using this constructor is
046: * functionally equivalent to using the zero-argument constructor.
047: */
048: public StringBuffer(int ignoredLength) {
049: }
050:
051: public StringBuffer(String s) {
052: append(s);
053: }
054:
055: public StringBuffer append(boolean x) {
056: return append(String.valueOf(x));
057: }
058:
059: public StringBuffer append(char x) {
060: return append(String.valueOf(x));
061: }
062:
063: public StringBuffer append(char[] x) {
064: return append(String.valueOf(x));
065: }
066:
067: public StringBuffer append(char[] x, int start, int len) {
068: return append(String.valueOf(x, start, len));
069: }
070:
071: public StringBuffer append(double x) {
072: return append(String.valueOf(x));
073: }
074:
075: public StringBuffer append(float x) {
076: return append(String.valueOf(x));
077: }
078:
079: public StringBuffer append(int x) {
080: return append(String.valueOf(x));
081: }
082:
083: public StringBuffer append(long x) {
084: return append(String.valueOf(x));
085: }
086:
087: public StringBuffer append(Object x) {
088: return append(String.valueOf(x));
089: }
090:
091: public StringBuffer append(String toAppend) {
092: // Coerce to "null" if null.
093: if (toAppend == null) {
094: toAppend = "null";
095: }
096: int appendLength = toAppend.length();
097: if (appendLength > 0) {
098: stringArray[arrayLen++] = toAppend;
099: stringLength += appendLength;
100: /*
101: * If we hit 1k elements, let's do a join to reduce the array size. This
102: * number was arrived at experimentally through benchmarking.
103: */
104: if (arrayLen > 1024) {
105: toString();
106: // Preallocate the next 1024 (faster on FF).
107: setLength(stringArray, 1024);
108: }
109: }
110: return this ;
111: };
112:
113: public StringBuffer append(StringBuffer x) {
114: return append(String.valueOf(x));
115: }
116:
117: public char charAt(int index) {
118: return toString().charAt(index);
119: }
120:
121: public StringBuffer delete(int start, int end) {
122: return replace(start, end, "");
123: }
124:
125: public StringBuffer deleteCharAt(int start) {
126: return delete(start, start + 1);
127: }
128:
129: public void getChars(int srcStart, int srcEnd, char[] dst,
130: int dstStart) {
131: String.__checkBounds(stringLength, srcStart, srcEnd);
132: String.__checkBounds(dst.length, dstStart, dstStart
133: + (srcEnd - srcStart));
134: String s = toString();
135: while (srcStart < srcEnd) {
136: dst[dstStart++] = s.charAt(srcStart++);
137: }
138: }
139:
140: public int indexOf(String x) {
141: return toString().indexOf(x);
142: }
143:
144: public int indexOf(String x, int start) {
145: return toString().indexOf(x, start);
146: }
147:
148: public StringBuffer insert(int index, boolean x) {
149: return insert(index, String.valueOf(x));
150: }
151:
152: public StringBuffer insert(int index, char x) {
153: return insert(index, String.valueOf(x));
154: }
155:
156: public StringBuffer insert(int index, char[] x) {
157: return insert(index, String.valueOf(x));
158: }
159:
160: public StringBuffer insert(int index, char[] x, int offset, int len) {
161: return insert(index, String.valueOf(x, offset, len));
162: }
163:
164: public StringBuffer insert(int index, double x) {
165: return insert(index, String.valueOf(x));
166: }
167:
168: public StringBuffer insert(int index, float x) {
169: return insert(index, String.valueOf(x));
170: }
171:
172: public StringBuffer insert(int index, int x) {
173: return insert(index, String.valueOf(x));
174: }
175:
176: public StringBuffer insert(int index, long x) {
177: return insert(index, String.valueOf(x));
178: }
179:
180: public StringBuffer insert(int index, Object x) {
181: return insert(index, String.valueOf(x));
182: }
183:
184: public StringBuffer insert(int index, String x) {
185: return replace(index, index, x);
186: }
187:
188: public int lastIndexOf(String s) {
189: return toString().lastIndexOf(s);
190: }
191:
192: public int lastIndexOf(String s, int start) {
193: return toString().lastIndexOf(s, start);
194: }
195:
196: public int length() {
197: return stringLength;
198: }
199:
200: public StringBuffer replace(int start, int end, String toInsert) {
201: // Get the joined string.
202: String s = toString();
203:
204: // Build a new buffer in pieces (will throw exceptions).
205: stringArray = new String[] { s.substring(0, start), toInsert,
206: s.substring(end) };
207: arrayLen = 3;
208:
209: // Calculate the new string length.
210: stringLength += toInsert.length() - (end - start);
211:
212: return this ;
213: }
214:
215: /**
216: * Warning! This method is <b>much</b> slower than the JRE implementation. If
217: * you need to do character level manipulation, you are strongly advised to
218: * use a char[] directly.
219: */
220: public void setCharAt(int index, char x) {
221: replace(index, index + 1, String.valueOf(x));
222: }
223:
224: public void setLength(int newLength) {
225: int oldLength = stringLength;
226: if (newLength < oldLength) {
227: delete(newLength, oldLength);
228: } else if (newLength > oldLength) {
229: append(new char[newLength - oldLength]);
230: }
231: }
232:
233: public CharSequence subSequence(int start, int end) {
234: return this .substring(start, end);
235: }
236:
237: public String substring(int begin) {
238: return toString().substring(begin);
239: }
240:
241: public String substring(int begin, int end) {
242: return toString().substring(begin, end);
243: }
244:
245: @Override
246: public String toString() {
247: /*
248: * Normalize the array to exactly one element (even if it's completely
249: * empty), so we can unconditionally grab the first element.
250: */
251: if (arrayLen != 1) {
252: setLength(stringArray, arrayLen);
253: String s = join(stringArray);
254: // Create a new array to allow everything to get GC'd.
255: stringArray = new String[] { s };
256: arrayLen = 1;
257: }
258: return stringArray[0];
259: }
260:
261: }
|