001: /*
002: * ComplexString.java
003: *
004: * Copyright (C) 2002-2004 Peter Graves
005: * $Id: ComplexString.java,v 1.18 2004/09/21 00:39:04 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 ComplexString extends AbstractString {
025: private int capacity;
026: private int fillPointer = -1; // -1 indicates no fill pointer.
027: private boolean isDisplaced;
028:
029: // For non-displaced arrays.
030: private char[] chars;
031:
032: // For displaced arrays.
033: private AbstractArray array;
034: private int displacement;
035:
036: public ComplexString(int capacity) {
037: this .capacity = capacity;
038: chars = new char[capacity];
039: isDisplaced = false;
040: }
041:
042: public ComplexString(int capacity, AbstractArray array,
043: int displacement) {
044: this .capacity = capacity;
045: this .array = array;
046: this .displacement = displacement;
047: isDisplaced = true;
048: }
049:
050: public LispObject typeOf() {
051: return list2(Symbol.STRING, number(capacity()));
052: }
053:
054: public LispClass classOf() {
055: return BuiltInClass.STRING;
056: }
057:
058: public boolean hasFillPointer() {
059: return fillPointer >= 0;
060: }
061:
062: public int getFillPointer() {
063: return fillPointer;
064: }
065:
066: public void setFillPointer(int n) {
067: fillPointer = n;
068: }
069:
070: public void setFillPointer(LispObject obj)
071: throws ConditionThrowable {
072: if (obj == T)
073: fillPointer = capacity();
074: else {
075: int n = Fixnum.getValue(obj);
076: if (n > capacity()) {
077: StringBuffer sb = new StringBuffer(
078: "The new fill pointer (");
079: sb.append(n);
080: sb.append(") exceeds the capacity of the vector (");
081: sb.append(capacity());
082: sb.append(").");
083: signal(new LispError(sb.toString()));
084: } else if (n < 0) {
085: StringBuffer sb = new StringBuffer(
086: "The new fill pointer (");
087: sb.append(n);
088: sb.append(") is negative.");
089: signal(new LispError(sb.toString()));
090: } else
091: fillPointer = n;
092: }
093: }
094:
095: public boolean isDisplaced() {
096: return isDisplaced;
097: }
098:
099: public LispObject arrayDisplacement() throws ConditionThrowable {
100: LispObject value1, value2;
101: if (array != null) {
102: value1 = array;
103: value2 = new Fixnum(displacement);
104: } else {
105: value1 = NIL;
106: value2 = Fixnum.ZERO;
107: }
108: return LispThread.currentThread().setValues(value1, value2);
109: }
110:
111: public char[] chars() throws ConditionThrowable {
112: if (chars != null)
113: return chars;
114: Debug.assertTrue(array != null);
115: char[] chars = new char[capacity];
116: System.arraycopy(array.chars(), displacement, chars, 0,
117: capacity);
118: return chars;
119: }
120:
121: public char[] getStringChars() throws ConditionThrowable {
122: if (fillPointer < 0)
123: return chars();
124: char[] ret = new char[fillPointer];
125: System.arraycopy(chars(), 0, ret, 0, fillPointer);
126: return ret;
127: }
128:
129: public boolean equal(LispObject obj) throws ConditionThrowable {
130: if (this == obj)
131: return true;
132: if (obj instanceof AbstractString) {
133: AbstractString string = (AbstractString) obj;
134: if (string.length() != length())
135: return false;
136: for (int i = length(); i-- > 0;)
137: if (string.getChar(i) != getChar(i))
138: return false;
139: return true;
140: }
141: if (obj instanceof NilVector)
142: return obj.equal(this );
143: return false;
144: }
145:
146: public boolean equalp(LispObject obj) throws ConditionThrowable {
147: if (this == obj)
148: return true;
149: if (obj instanceof AbstractString) {
150: AbstractString string = (AbstractString) obj;
151: if (string.length() != length())
152: return false;
153: for (int i = length(); i-- > 0;) {
154: if (string.getChar(i) != getChar(i)) {
155: if (Utilities.toLowerCase(string.getChar(i)) != Utilities
156: .toLowerCase(getChar(i)))
157: return false;
158: }
159: }
160: return true;
161: }
162: if (obj instanceof AbstractArray)
163: return obj.equalp(this );
164: return false;
165: }
166:
167: public LispObject subseq(int start, int end)
168: throws ConditionThrowable {
169: SimpleString s = new SimpleString(end - start);
170: int i = start, j = 0;
171: while (i < end)
172: s.setChar(j++, getChar(i++));
173: return s;
174: }
175:
176: public void fill(LispObject obj) throws ConditionThrowable {
177: fill(LispCharacter.getValue(obj));
178: }
179:
180: public void fill(char c) throws ConditionThrowable {
181: for (int i = length(); i-- > 0;)
182: setChar(i, c);
183: }
184:
185: public void shrink(int n) throws ConditionThrowable {
186: if (chars != null) {
187: if (n < capacity) {
188: char[] newArray = new char[n];
189: System.arraycopy(chars, 0, newArray, 0, n);
190: chars = newArray;
191: capacity = n;
192: return;
193: }
194: if (n == capacity)
195: return;
196: }
197: signal(new LispError());
198: }
199:
200: public LispObject reverse() throws ConditionThrowable {
201: int length = length();
202: SimpleString result = new SimpleString(length);
203: int i, j;
204: for (i = 0, j = length - 1; i < length; i++, j--)
205: result.setChar(i, getChar(j));
206: return result;
207: }
208:
209: public LispObject nreverse() throws ConditionThrowable {
210: int i = 0;
211: int j = length() - 1;
212: while (i < j) {
213: char temp = getChar(i);
214: setChar(i, getChar(j));
215: setChar(j, temp);
216: ++i;
217: --j;
218: }
219: return this ;
220: }
221:
222: public LispObject getRowMajor(int index) throws ConditionThrowable {
223: return LispCharacter.getInstance(getChar(index));
224: }
225:
226: public void setRowMajor(int index, LispObject newValue)
227: throws ConditionThrowable {
228: setChar(index, LispCharacter.getValue(newValue));
229: }
230:
231: public char getChar(int index) throws ConditionThrowable {
232: if (chars != null) {
233: try {
234: return chars[index];
235: } catch (ArrayIndexOutOfBoundsException e) {
236: badIndex(index, capacity);
237: return 0; // Not reached.
238: }
239: } else
240: return LispCharacter.getValue(array.getRowMajor(index
241: + displacement));
242: }
243:
244: public void setChar(int index, char c) throws ConditionThrowable {
245: if (chars != null) {
246: try {
247: chars[index] = c;
248: } catch (ArrayIndexOutOfBoundsException e) {
249: badIndex(index, capacity);
250: }
251: } else
252: array.setRowMajor(index + displacement, LispCharacter
253: .getInstance(c));
254: }
255:
256: public String getStringValue() throws ConditionThrowable {
257: if (fillPointer >= 0)
258: return new String(chars(), 0, fillPointer);
259: else
260: return new String(chars());
261: }
262:
263: public Object javaInstance() throws ConditionThrowable {
264: return new String(chars());
265: }
266:
267: public Object javaInstance(Class c) throws ConditionThrowable {
268: return javaInstance();
269: }
270:
271: public final int capacity() {
272: return capacity;
273: }
274:
275: public AbstractVector adjustVector(int newCapacity,
276: LispObject initialElement, LispObject initialContents)
277: throws ConditionThrowable {
278: if (initialContents != NIL) {
279: // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE-
280: // ARRAY. In this case none of the original contents of array
281: // appears in the resulting array."
282: char[] newChars = new char[newCapacity];
283: if (initialContents.listp()) {
284: LispObject list = initialContents;
285: for (int i = 0; i < newCapacity; i++) {
286: newChars[i] = LispCharacter.getValue(list.car());
287: list = list.cdr();
288: }
289: } else if (initialContents.vectorp()) {
290: for (int i = 0; i < newCapacity; i++)
291: newChars[i] = LispCharacter
292: .getValue(initialContents.elt(i));
293: } else
294: signal(new TypeError(initialContents, Symbol.SEQUENCE));
295: chars = newChars;
296: } else {
297: if (chars == null) {
298: // Displaced array. Copy existing characters.
299: chars = new char[newCapacity];
300: final int limit = Math.min(capacity, newCapacity);
301: if (array instanceof AbstractString) {
302: AbstractString string = (AbstractString) array;
303: for (int i = 0; i < limit; i++) {
304: chars[i] = string.getChar(displacement + i);
305: }
306: } else {
307: for (int i = 0; i < limit; i++) {
308: LispCharacter character = (LispCharacter) array
309: .getRowMajor(displacement + i);
310: chars[i] = character.value;
311: }
312: }
313: } else if (capacity != newCapacity) {
314: char[] newElements = new char[newCapacity];
315: System.arraycopy(chars, 0, newElements, 0, Math.min(
316: capacity, newCapacity));
317: chars = newElements;
318: }
319: if (initialElement != NIL && capacity < newCapacity) {
320: // Initialize new elements.
321: final char c = LispCharacter.getValue(initialElement);
322: for (int i = capacity; i < newCapacity; i++)
323: chars[i] = c;
324: }
325: }
326: capacity = newCapacity;
327: array = null;
328: displacement = 0;
329: isDisplaced = false;
330: return this ;
331: }
332:
333: public AbstractVector adjustVector(int newCapacity,
334: AbstractArray displacedTo, int displacement)
335: throws ConditionThrowable {
336: capacity = newCapacity;
337: array = displacedTo;
338: this .displacement = displacement;
339: chars = null;
340: isDisplaced = true;
341: return this ;
342: }
343:
344: public final int length() {
345: return fillPointer >= 0 ? fillPointer : capacity;
346: }
347:
348: public LispObject elt(int index) throws ConditionThrowable {
349: final int limit = length();
350: if (index < 0 || index >= limit)
351: badIndex(index, limit);
352: return LispCharacter.getInstance(getChar(index));
353: }
354:
355: // Ignores fill pointer.
356: public LispObject AREF(LispObject index) throws ConditionThrowable {
357: return LispCharacter
358: .getInstance(getChar(Fixnum.getValue(index)));
359: }
360:
361: public LispObject vectorPushExtend(LispObject element)
362: throws ConditionThrowable {
363: if (fillPointer < 0)
364: noFillPointer();
365: if (fillPointer >= capacity) {
366: // Need to extend vector.
367: ensureCapacity(capacity * 2 + 1);
368: }
369: if (chars != null) {
370: try {
371: chars[fillPointer] = ((LispCharacter) element).value;
372: } catch (ClassCastException e) {
373: signal(new TypeError(element, Symbol.CHARACTER));
374: }
375: } else
376: array.setRowMajor(fillPointer + displacement, element);
377: return new Fixnum(fillPointer++);
378: }
379:
380: public LispObject vectorPushExtend(LispObject element,
381: LispObject extension) throws ConditionThrowable {
382: int ext = Fixnum.getValue(extension);
383: if (fillPointer < 0)
384: noFillPointer();
385: if (fillPointer >= capacity) {
386: // Need to extend vector.
387: ext = Math.max(ext, capacity + 1);
388: ensureCapacity(capacity + ext);
389: }
390: if (chars != null) {
391: try {
392: chars[fillPointer] = ((LispCharacter) element).value;
393: } catch (ClassCastException e) {
394: signal(new TypeError(element, Symbol.CHARACTER));
395: }
396: } else
397: array.setRowMajor(fillPointer + displacement, element);
398: return new Fixnum(fillPointer++);
399: }
400:
401: public final void ensureCapacity(int minCapacity)
402: throws ConditionThrowable {
403: if (chars != null) {
404: if (capacity < minCapacity) {
405: char[] newArray = new char[minCapacity];
406: System.arraycopy(chars, 0, newArray, 0, capacity);
407: chars = newArray;
408: capacity = minCapacity;
409: }
410: } else {
411: Debug.assertTrue(array != null);
412: if (array.getTotalSize() - displacement < minCapacity) {
413: // Copy array.
414: chars = new char[minCapacity];
415: final int limit = array.getTotalSize() - displacement;
416: if (array instanceof AbstractString) {
417: AbstractString string = (AbstractString) array;
418: for (int i = 0; i < limit; i++) {
419: chars[i] = string.getChar(displacement + i);
420: }
421: } else {
422: for (int i = 0; i < limit; i++) {
423: LispCharacter character = (LispCharacter) array
424: .getRowMajor(displacement + i);
425: chars[i] = character.value;
426: }
427: }
428: capacity = minCapacity;
429: array = null;
430: displacement = 0;
431: isDisplaced = false;
432: }
433: }
434: }
435:
436: public int hashCode() {
437: int hashCode = 0;
438: try {
439: final int limit = length();
440: for (int i = 0; i < limit; i++)
441: hashCode = hashCode * 31 + getChar(i);
442: } catch (ConditionThrowable t) {
443: // Shouldn't happen.
444: Debug.trace(t);
445: }
446: return hashCode;
447: }
448: }
|