001: /*
002: * SimpleString.java
003: *
004: * Copyright (C) 2004 Peter Graves
005: * $Id: SimpleString.java,v 1.18 2004/09/21 00:38:29 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: public final class SimpleString extends AbstractString {
025: private int capacity;
026: private char[] chars;
027:
028: public SimpleString(LispCharacter c) {
029: chars = new char[1];
030: chars[0] = c.getValue();
031: capacity = 1;
032: }
033:
034: public SimpleString(char c) {
035: chars = new char[1];
036: chars[0] = c;
037: capacity = 1;
038: }
039:
040: public SimpleString(int capacity) {
041: this .capacity = capacity;
042: chars = new char[capacity];
043: }
044:
045: public SimpleString(String s) {
046: capacity = s.length();
047: chars = s.toCharArray();
048: }
049:
050: public SimpleString(StringBuffer sb) {
051: chars = new char[capacity = sb.length()];
052: sb.getChars(0, capacity, chars, 0);
053: }
054:
055: private SimpleString(char[] chars) {
056: this .chars = chars;
057: capacity = chars.length;
058: }
059:
060: public char[] chars() {
061: return chars;
062: }
063:
064: public char[] getStringChars() {
065: return chars;
066: }
067:
068: // Used by jvm compiler.
069: public static SimpleString getInstance(String s) {
070: return new SimpleString(s);
071: }
072:
073: public LispObject typeOf() {
074: return list2(Symbol.SIMPLE_STRING, new Fixnum(capacity));
075: }
076:
077: public LispClass classOf() {
078: return BuiltInClass.SIMPLE_STRING;
079: }
080:
081: public LispObject getDescription() {
082: StringBuffer sb = new StringBuffer("A simple-string (");
083: sb.append(capacity);
084: sb.append(") \"");
085: sb.append(chars);
086: sb.append('"');
087: return new SimpleString(sb);
088: }
089:
090: public LispObject typep(LispObject type) throws ConditionThrowable {
091: if (type == Symbol.SIMPLE_STRING)
092: return T;
093: if (type == Symbol.SIMPLE_BASE_STRING)
094: return T;
095: if (type == Symbol.SIMPLE_ARRAY)
096: return T;
097: if (type == BuiltInClass.SIMPLE_STRING)
098: return T;
099: if (type == BuiltInClass.SIMPLE_ARRAY)
100: return T;
101: return super .typep(type);
102: }
103:
104: public LispObject SIMPLE_STRING_P() {
105: return T;
106: }
107:
108: public boolean hasFillPointer() {
109: return false;
110: }
111:
112: public boolean isAdjustable() {
113: return false;
114: }
115:
116: public boolean equal(LispObject obj) throws ConditionThrowable {
117: if (this == obj)
118: return true;
119: if (obj instanceof SimpleString) {
120: SimpleString string = (SimpleString) obj;
121: if (string.capacity != capacity)
122: return false;
123: for (int i = capacity; i-- > 0;)
124: if (string.chars[i] != chars[i])
125: return false;
126: return true;
127: }
128: if (obj instanceof AbstractString) {
129: AbstractString string = (AbstractString) obj;
130: if (string.length() != capacity)
131: return false;
132: for (int i = length(); i-- > 0;)
133: if (string.getChar(i) != chars[i])
134: return false;
135: return true;
136: }
137: if (obj instanceof NilVector)
138: return obj.equal(this );
139: return false;
140: }
141:
142: public boolean equalp(LispObject obj) throws ConditionThrowable {
143: if (this == obj)
144: return true;
145: if (obj instanceof SimpleString) {
146: SimpleString string = (SimpleString) obj;
147: if (string.capacity != capacity)
148: return false;
149: for (int i = capacity; i-- > 0;) {
150: if (string.chars[i] != chars[i]) {
151: if (Utilities.toLowerCase(string.chars[i]) != Utilities
152: .toLowerCase(chars[i]))
153: return false;
154: }
155: }
156: return true;
157: }
158: if (obj instanceof AbstractString) {
159: AbstractString string = (AbstractString) obj;
160: if (string.length() != capacity)
161: return false;
162: for (int i = length(); i-- > 0;) {
163: if (string.getChar(i) != chars[i]) {
164: if (Utilities.toLowerCase(string.getChar(i)) != Utilities
165: .toLowerCase(chars[i]))
166: return false;
167: }
168: }
169: return true;
170: }
171: if (obj instanceof AbstractArray)
172: return obj.equalp(this );
173: return false;
174: }
175:
176: public LispObject subseq(int start, int end)
177: throws ConditionThrowable {
178: SimpleString s = new SimpleString(end - start);
179: int i = start, j = 0;
180: try {
181: while (i < end)
182: s.chars[j++] = chars[i++];
183: return s;
184: } catch (ArrayIndexOutOfBoundsException e) {
185: return signal(new TypeError("Array index out of bounds: "
186: + i));
187: }
188: }
189:
190: public void fill(LispObject obj) throws ConditionThrowable {
191: fill(LispCharacter.getValue(obj));
192: }
193:
194: public void fill(char c) {
195: for (int i = capacity; i-- > 0;)
196: chars[i] = c;
197: }
198:
199: public void shrink(int n) throws ConditionThrowable {
200: if (n < capacity) {
201: char[] newArray = new char[n];
202: System.arraycopy(chars, 0, newArray, 0, n);
203: chars = newArray;
204: capacity = n;
205: return;
206: }
207: if (n == capacity)
208: return;
209: signal(new LispError());
210: }
211:
212: public LispObject reverse() throws ConditionThrowable {
213: SimpleString result = new SimpleString(capacity);
214: int i, j;
215: for (i = 0, j = capacity - 1; i < capacity; i++, j--)
216: result.chars[i] = chars[j];
217: return result;
218: }
219:
220: public LispObject nreverse() throws ConditionThrowable {
221: int i = 0;
222: int j = capacity - 1;
223: while (i < j) {
224: char temp = chars[i];
225: chars[i] = chars[j];
226: chars[j] = temp;
227: ++i;
228: --j;
229: }
230: return this ;
231: }
232:
233: public LispObject getRowMajor(int index) throws ConditionThrowable {
234: try {
235: return LispCharacter.getInstance(chars[index]);
236: } catch (ArrayIndexOutOfBoundsException e) {
237: badIndex(index, capacity);
238: return NIL; // Not reached.
239: }
240: }
241:
242: public void setRowMajor(int index, LispObject newValue)
243: throws ConditionThrowable {
244: try {
245: chars[index] = LispCharacter.getValue(newValue);
246: } catch (ArrayIndexOutOfBoundsException e) {
247: badIndex(index, capacity);
248: }
249: }
250:
251: public char getChar(int index) throws ConditionThrowable {
252: try {
253: return chars[index];
254: } catch (ArrayIndexOutOfBoundsException e) {
255: badIndex(index, capacity);
256: return 0; // Not reached.
257: }
258: }
259:
260: public void setChar(int index, char c) throws ConditionThrowable {
261: try {
262: chars[index] = c;
263: } catch (ArrayIndexOutOfBoundsException e) {
264: badIndex(index, capacity);
265: }
266: }
267:
268: public String getStringValue() {
269: return new String(chars);
270: }
271:
272: public Object javaInstance() {
273: return new String(chars);
274: }
275:
276: public Object javaInstance(Class c) {
277: return javaInstance();
278: }
279:
280: public final int capacity() {
281: return capacity;
282: }
283:
284: public final int length() {
285: return capacity;
286: }
287:
288: public LispObject elt(int index) throws ConditionThrowable {
289: try {
290: return LispCharacter.getInstance(chars[index]);
291: } catch (ArrayIndexOutOfBoundsException e) {
292: badIndex(index, capacity);
293: return NIL; // Not reached.
294: }
295: }
296:
297: // Ignores fill pointer.
298: public LispObject AREF(LispObject index) throws ConditionThrowable {
299: try {
300: return LispCharacter
301: .getInstance(chars[((Fixnum) index).value]);
302: } catch (ClassCastException e) {
303: return signal(new TypeError(index, Symbol.FIXNUM));
304: } catch (ArrayIndexOutOfBoundsException e) {
305: badIndex(((Fixnum) index).value, capacity);
306: return NIL; // Not reached.
307: }
308: }
309:
310: public int sxhash() {
311: int hashCode = 0;
312: for (int i = 0; i < capacity; i++)
313: hashCode = hashCode * 31 + chars[i];
314: return (hashCode & 0x7fffffff);
315: }
316:
317: // For EQUALP hash tables.
318: public int psxhash() {
319: int hashCode = 0;
320: for (int i = 0; i < capacity; i++)
321: hashCode = hashCode * 31 + Character.toUpperCase(chars[i]);
322: return (hashCode & 0x7fffffff);
323: }
324:
325: public AbstractVector adjustVector(int newCapacity,
326: LispObject initialElement, LispObject initialContents)
327: throws ConditionThrowable {
328: if (initialContents != NIL) {
329: char[] newChars = new char[newCapacity];
330: if (initialContents.listp()) {
331: LispObject list = initialContents;
332: for (int i = 0; i < newCapacity; i++) {
333: newChars[i] = LispCharacter.getValue(list.car());
334: list = list.cdr();
335: }
336: } else if (initialContents.vectorp()) {
337: for (int i = 0; i < newCapacity; i++)
338: newChars[i] = LispCharacter
339: .getValue(initialContents.elt(i));
340: } else
341: signal(new TypeError(initialContents, Symbol.SEQUENCE));
342: return new SimpleString(newChars);
343: }
344: if (capacity != newCapacity) {
345: char[] newChars = new char[newCapacity];
346: System.arraycopy(chars, 0, newChars, 0, Math.min(
347: newCapacity, capacity));
348: if (initialElement != NIL && capacity < newCapacity) {
349: final char c = LispCharacter.getValue(initialElement);
350: for (int i = capacity; i < newCapacity; i++)
351: newChars[i] = c;
352: }
353: return new SimpleString(newChars);
354: }
355: // No change.
356: return this ;
357: }
358:
359: public AbstractVector adjustVector(int newCapacity,
360: AbstractArray displacedTo, int displacement)
361: throws ConditionThrowable {
362: return new ComplexString(newCapacity, displacedTo, displacement);
363: }
364:
365: // ### schar
366: private static final Primitive2 SCHAR = new Primitive2("schar",
367: "string index") {
368: public LispObject execute(LispObject first, LispObject second)
369: throws ConditionThrowable {
370: try {
371: return LispCharacter
372: .getInstance(((SimpleString) first).chars[((Fixnum) second).value]);
373: } catch (ClassCastException e) {
374: if (first instanceof SimpleString)
375: return signal(new TypeError(second, Symbol.FIXNUM));
376: else
377: return signal(new TypeError(first,
378: Symbol.SIMPLE_STRING));
379: } catch (ArrayIndexOutOfBoundsException e) {
380: return signal(new TypeError(
381: "Array index out of bounds: "
382: + ((Fixnum) second).value));
383: }
384: }
385: };
386:
387: // ### %set-schar
388: private static final Primitive3 _SET_SCHAR = new Primitive3(
389: "%set-schar", PACKAGE_SYS, false) {
390: public LispObject execute(LispObject first, LispObject second,
391: LispObject third) throws ConditionThrowable {
392: try {
393: ((SimpleString) first).chars[((Fixnum) second).value] = ((LispCharacter) third).value;
394: return third;
395: } catch (ClassCastException e) {
396: if (!(first instanceof SimpleString))
397: return signal(new TypeError(first,
398: Symbol.SIMPLE_STRING));
399: if (!(second instanceof Fixnum))
400: return signal(new TypeError(second, Symbol.FIXNUM));
401: return signal(new TypeError(third, Symbol.CHARACTER));
402: } catch (ArrayIndexOutOfBoundsException e) {
403: return signal(new TypeError(
404: "Array index out of bounds: "
405: + ((Fixnum) second).value));
406: }
407: }
408: };
409: }
|