001: // Copyright (c) 2001, 2004 Per M.A. Bothner and Brainfood Inc.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.lists;
005:
006: import java.io.*;
007:
008: /** Simple adjustable-length vector whose elements are 32-bit floats.
009: * Used for the Scheme string type.
010: * @author Per Bothner
011: */
012:
013: public class FString extends SimpleVector implements
014: /* #ifdef JAVA2 */
015: Comparable,
016: /* #endif */
017: /* #ifdef JAVA5 */
018: // Appendable,
019: /* #endif */
020: CharSeq, Externalizable, Consumable {
021: public char[] data;
022: protected static char[] empty = new char[0];
023:
024: public FString() {
025: data = empty;
026: }
027:
028: public FString(int num) {
029: size = num;
030: data = new char[num];
031: }
032:
033: public FString(int num, char value) {
034: char[] array = new char[num];
035: data = array;
036: size = num;
037: while (--num >= 0)
038: array[num] = value;
039: }
040:
041: /** Create an FString from a char[].
042: * Note that this contructor does *not* copy the argument. */
043: public FString(char[] values) {
044: size = values.length;
045: data = values;
046: }
047:
048: public FString(String str) {
049: data = str.toCharArray();
050: size = data.length;
051: }
052:
053: public FString(StringBuffer buffer) {
054: this (buffer, 0, buffer.length());
055: }
056:
057: public FString(StringBuffer buffer, int offset, int length) {
058: this .size = length;
059: data = new char[length];
060: if (length > 0)
061: buffer.getChars(offset, offset + length, data, 0);
062: }
063:
064: public FString(char[] buffer, int offset, int length) {
065: this .size = length;
066: data = new char[length];
067: System.arraycopy(buffer, offset, data, 0, length);
068: }
069:
070: public FString(Sequence seq) {
071: this .data = new char[seq.size()];
072: addAll(seq);
073: }
074:
075: public FString(CharSeq seq) {
076: int size = seq.size();
077: char[] data = new char[size];
078: seq.getChars(0, size, data, 0);
079: this .data = data;
080: this .size = size;
081: }
082:
083: public FString(CharSeq seq, int offset, int length) {
084: char[] data = new char[length];
085: seq.getChars(offset, offset + length, data, 0);
086: this .data = data;
087: this .size = length;
088: }
089:
090: public int length() {
091: return size;
092: }
093:
094: /** Get the allocated length of the data buffer. */
095: public int getBufferLength() {
096: return data.length;
097: }
098:
099: public void setBufferLength(int length) {
100: int oldLength = data.length;
101: if (oldLength != length) {
102: char[] tmp = new char[length];
103: System.arraycopy(data, 0, tmp, 0,
104: oldLength < length ? oldLength : length);
105: data = tmp;
106: }
107: }
108:
109: public void ensureBufferLength(int sz) {
110: if (sz > data.length) {
111: char[] d = new char[sz < 60 ? 120 : 2 * sz];
112: System.arraycopy(data, 0, d, 0, sz);
113: data = d;
114: }
115: }
116:
117: protected Object getBuffer() {
118: return data;
119: }
120:
121: public final Object getBuffer(int index) {
122: return Convert.toObject(data[index]);
123: }
124:
125: public final Object setBuffer(int index, Object value) {
126: Object old = Convert.toObject(data[index]);
127: data[index] = Convert.toChar(value);
128: return old;
129: }
130:
131: public final Object get(int index) {
132: if (index >= size)
133: throw new ArrayIndexOutOfBoundsException();
134: return Convert.toObject(data[index]);
135: }
136:
137: public final char charAt(int index) {
138: if (index >= size)
139: throw new StringIndexOutOfBoundsException(index);
140: return data[index];
141: }
142:
143: public final char charAtBuffer(int index) {
144: return data[index];
145: }
146:
147: public void getChars(int srcBegin, int srcEnd, char dst[],
148: int dstBegin) {
149: if (srcBegin < 0 || srcBegin > srcEnd)
150: throw new StringIndexOutOfBoundsException(srcBegin);
151: if (srcEnd > size)
152: throw new StringIndexOutOfBoundsException(srcEnd);
153: if (dstBegin + srcEnd - srcBegin > dst.length)
154: throw new StringIndexOutOfBoundsException(dstBegin);
155: if (srcBegin < srcEnd)
156: System.arraycopy(data, srcBegin, dst, dstBegin, srcEnd
157: - srcBegin);
158: }
159:
160: public void getChars(int srcBegin, int srcEnd, StringBuffer dst) {
161: if (srcBegin < 0 || srcBegin > srcEnd)
162: throw new StringIndexOutOfBoundsException(srcBegin);
163: if (srcEnd > size)
164: throw new StringIndexOutOfBoundsException(srcEnd);
165: if (srcBegin < srcEnd)
166: dst.append(data, srcBegin, srcEnd - srcBegin);
167: }
168:
169: public void getChars(StringBuffer dst) {
170: dst.append(data, 0, size);
171: }
172:
173: /** Return a char[] contain the characters of this string.
174: * It is unspecified if the result is a copy or shares with this FString.
175: */
176: public char[] toCharArray() {
177: int val_length = data.length;
178: int seq_length = size;
179: if (seq_length == val_length)
180: return data;
181: else {
182: char[] tmp = new char[seq_length];
183: System.arraycopy(data, 0, tmp, 0, seq_length);
184: return tmp;
185: }
186: }
187:
188: public void shift(int srcStart, int dstStart, int count) {
189: System.arraycopy(data, srcStart, data, dstStart, count);
190: }
191:
192: public FString copy(int start, int end) {
193: char[] copy = new char[end - start];
194: for (int i = start; i < end; i++)
195: copy[i - start] = data[i];
196: return new FString(copy);
197: }
198:
199: /** Append all the characters of another <code>FString</code>. */
200: public boolean addAll(FString s) {
201: int newSize = size + s.size;
202: if (data.length < newSize)
203: setBufferLength(newSize);
204: System.arraycopy(s.data, 0, data, size, s.size);
205: size = newSize;
206: return s.size > 0;
207: }
208:
209: /** Append arguments to this FString.
210: * Used to implement Scheme's string-append and string-append/shared.
211: * @param args an array of FString value
212: * @param startIndex index of first string in <code>args</code> to use
213: */
214: public void addAllStrings(Object[] args, int startIndex) {
215: int total = size;
216: for (int i = startIndex; i < args.length; ++i)
217: total += ((FString) args[i]).size;
218: if (data.length < total)
219: setBufferLength(total);
220:
221: for (int i = startIndex; i < args.length; ++i)
222: addAll((FString) args[i]);
223: }
224:
225: public String toString() {
226: return new String(data, 0, size);
227: }
228:
229: public String substring(int start, int end) {
230: return new String(data, start, end - start);
231: }
232:
233: /* #ifdef use:java.lang.CharSequence */
234: public CharSequence subSequence(int start, int end) {
235: return new FString(data, start, end - start);
236: }
237:
238: /* #endif */
239:
240: public void setCharAt(int index, char ch) {
241: if (index < 0 || index >= size)
242: throw new StringIndexOutOfBoundsException(index);
243: data[index] = ch;
244: }
245:
246: public void setCharAtBuffer(int index, char ch) {
247: data[index] = ch;
248: }
249:
250: /** Set all the elements to a given character. */
251: public final void fill(char ch) {
252: for (int i = size; --i >= 0;)
253: data[i] = ch;
254: }
255:
256: public void fill(int fromIndex, int toIndex, char value) {
257: if (fromIndex < 0 || toIndex > size)
258: throw new IndexOutOfBoundsException();
259: for (int i = fromIndex; i < toIndex; i++)
260: data[i] = value;
261: }
262:
263: protected void clearBuffer(int start, int count) {
264: while (--count >= 0)
265: data[start++] = 0;
266: }
267:
268: public void replace(int where, char[] chars, int start, int count) {
269: System.arraycopy(chars, start, data, where, count);
270: }
271:
272: public void replace(int where, String string) {
273: string.getChars(0, string.length(), data, where);
274: }
275:
276: public int hashCode() {
277: /* Matches String.hashCode specification, as updated specification in
278: http://www.javasoft.com/docs/books/jls/clarify.html. */
279: char[] val = data;
280: int len = size;
281: int hash = 0;
282: for (int i = 0; i < len; i++)
283: hash = 31 * hash + val[i];
284: return hash;
285: }
286:
287: public boolean equals(Object obj) {
288: if (obj == null || !(obj instanceof FString))
289: return false;
290: char[] str = ((FString) obj).data;
291: int n = size;
292: if (str == null || str.length != n)
293: return false;
294: for (int i = n; --i >= 0;) {
295: if (data[i] != str[i])
296: return false;
297: }
298: return true;
299: }
300:
301: public int compareTo(Object obj) {
302: FString str2 = (FString) obj;
303: char[] cs1 = data;
304: char[] cs2 = str2.data;
305: int n1 = size;
306: int n2 = str2.size;
307: int n = n1 > n2 ? n2 : n1;
308: for (int i = 0; i < n; i++) {
309: char c1 = cs1[i];
310: char c2 = cs2[i];
311: int d = c1 - c2;
312: if (d != 0)
313: return d;
314: }
315: return n1 - n2;
316: }
317:
318: public int getElementKind() {
319: return CHAR_VALUE;
320: }
321:
322: public void consume(Consumer out) {
323: out.write(data, 0, data.length);
324: }
325:
326: public boolean consumeNext(int ipos, Consumer out) {
327: int index = ipos >>> 1;
328: if (index >= size)
329: return false;
330: out.write(data[index]);
331: return true;
332: }
333:
334: public void consumePosRange(int iposStart, int iposEnd, Consumer out) {
335: if (out.ignoring())
336: return;
337: int i = iposStart >>> 1;
338: int end = iposEnd >>> 1;
339: if (end > size)
340: end = size;
341: if (end > i)
342: out.write(data, i, end - i);
343: }
344:
345: public FString append(char c) {
346: int sz = size;
347: if (sz >= data.length)
348: ensureBufferLength(sz + 1);
349: char[] d = data;
350: d[sz] = c;
351: size = sz + 1;
352: return this ;
353: }
354:
355: /* #ifdef use:java.lang.CharSequence */
356: public FString append(CharSequence csq) {
357: if (csq == null)
358: csq = "null";
359: return append(csq, 0, csq.length());
360: }
361:
362: public FString append(CharSequence csq, int start, int end) {
363: if (csq == null)
364: csq = "null";
365: /* FIXME optimize to use getChars if csq is a CharSeq. */
366: for (int i = start; i < end; i++)
367: append(csq.charAt(i));
368: return this ;
369: }
370:
371: /* #else */
372: // public FString append (String str)
373: // {
374: // int len = str.length();
375: // ensureBufferLength(size+len);
376: // str.getChars(0, len, data, size);
377: // size += len;
378: // return this;
379: // }
380: /* #endif */
381:
382: /* #ifdef JAVA5 */
383: // public void writeTo(int start, int count, Appendable dest)
384: // throws java.io.IOException
385: // {
386: // if (dest instanceof java.io.Writer)
387: // {
388: // try
389: // {
390: // ((java.io.Writer) dest).write(data, start, count);
391: // }
392: // catch (java.io.IOException ex)
393: // {
394: // throw new RuntimeException(ex);
395: // }
396: // }
397: // else
398: // {
399: // dest.append(this, start, start+count);
400: // }
401: // }
402: // public void writeTo(Appendable dest) throws java.io.IOException
403: // {
404: // writeTo(0, size, dest);
405: // }
406: /* #else */
407: public void writeTo(int start, int count, java.io.Writer dest)
408: throws java.io.IOException {
409: dest.write(data, start, count);
410: }
411:
412: public void writeTo(java.io.Writer dest) throws java.io.IOException {
413: dest.write(data, 0, size);
414: }
415:
416: /* #endif */
417:
418: /**
419: * @serialData Write 'size' (using writeInt),
420: * followed by 'size' elements in order (using writeChar).
421: */
422: public void writeExternal(ObjectOutput out) throws IOException {
423: int size = this .size;
424: out.writeInt(size);
425: for (int i = 0; i < size; i++)
426: out.writeChar(data[i]);
427: }
428:
429: public void readExternal(ObjectInput in) throws IOException,
430: ClassNotFoundException {
431: int size = in.readInt();
432: char[] data = new char[size];
433: for (int i = 0; i < size; i++)
434: data[i] = in.readChar();
435: this.data = data;
436: this.size = size;
437: }
438: }
|