001: /*
002: * ComplexVector.java
003: *
004: * Copyright (C) 2002-2004 Peter Graves
005: * $Id: ComplexVector.java,v 1.13 2004/05/27 17:10:36 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: // A vector that is displaced to another array, has a fill pointer, and/or is
025: // expressly adjustable. It can hold elements of any type.
026: public final class ComplexVector extends AbstractVector {
027: private int capacity;
028: private int fillPointer = -1; // -1 indicates no fill pointer.
029: private boolean isDisplaced;
030:
031: // For non-displaced arrays.
032: private LispObject[] elements;
033:
034: // For displaced arrays.
035: private AbstractArray array;
036: private int displacement;
037:
038: public ComplexVector(int capacity) {
039: elements = new LispObject[capacity];
040: for (int i = capacity; i-- > 0;)
041: elements[i] = NIL;
042: this .capacity = capacity;
043: }
044:
045: public ComplexVector(int capacity, AbstractArray array,
046: int displacement) {
047: this .capacity = capacity;
048: this .array = array;
049: this .displacement = displacement;
050: isDisplaced = true;
051: }
052:
053: public LispObject typeOf() {
054: return list3(Symbol.VECTOR, T, new Fixnum(capacity));
055: }
056:
057: public LispClass classOf() {
058: return BuiltInClass.VECTOR;
059: }
060:
061: public boolean hasFillPointer() {
062: return fillPointer >= 0;
063: }
064:
065: public int getFillPointer() {
066: return fillPointer;
067: }
068:
069: public void setFillPointer(int n) {
070: fillPointer = n;
071: }
072:
073: public void setFillPointer(LispObject obj)
074: throws ConditionThrowable {
075: if (obj == T)
076: fillPointer = capacity();
077: else {
078: int n = Fixnum.getValue(obj);
079: if (n > capacity()) {
080: StringBuffer sb = new StringBuffer(
081: "The new fill pointer (");
082: sb.append(n);
083: sb.append(") exceeds the capacity of the vector (");
084: sb.append(capacity());
085: sb.append(").");
086: signal(new LispError(sb.toString()));
087: } else if (n < 0) {
088: StringBuffer sb = new StringBuffer(
089: "The new fill pointer (");
090: sb.append(n);
091: sb.append(") is negative.");
092: signal(new LispError(sb.toString()));
093: } else
094: fillPointer = n;
095: }
096: }
097:
098: public boolean isDisplaced() {
099: return isDisplaced;
100: }
101:
102: public LispObject arrayDisplacement() throws ConditionThrowable {
103: LispObject value1, value2;
104: if (array != null) {
105: value1 = array;
106: value2 = new Fixnum(displacement);
107: } else {
108: value1 = NIL;
109: value2 = Fixnum.ZERO;
110: }
111: return LispThread.currentThread().setValues(value1, value2);
112: }
113:
114: public LispObject getElementType() {
115: return T;
116: }
117:
118: public boolean isSimpleVector() {
119: return false;
120: }
121:
122: public int capacity() {
123: return capacity;
124: }
125:
126: public int length() {
127: return fillPointer >= 0 ? fillPointer : capacity;
128: }
129:
130: public LispObject elt(int index) throws ConditionThrowable {
131: final int limit = length();
132: if (index < 0 || index >= limit)
133: badIndex(index, limit);
134: return getRowMajor(index);
135: }
136:
137: // Ignores fill pointer.
138: // FIXME inline
139: public LispObject AREF(LispObject index) throws ConditionThrowable {
140: return getRowMajor(Fixnum.getValue(index));
141: }
142:
143: public LispObject getRowMajor(int index) throws ConditionThrowable {
144: if (elements != null) {
145: try {
146: return elements[index];
147: } catch (ArrayIndexOutOfBoundsException e) {
148: badIndex(index, elements.length);
149: return NIL; // Not reached.
150: }
151: } else
152: return array.getRowMajor(index + displacement);
153: }
154:
155: public void setRowMajor(int index, LispObject newValue)
156: throws ConditionThrowable {
157: if (elements != null) {
158: try {
159: elements[index] = newValue;
160: } catch (ArrayIndexOutOfBoundsException e) {
161: badIndex(index, elements.length);
162: }
163: } else
164: array.setRowMajor(index + displacement, newValue);
165: }
166:
167: public LispObject subseq(int start, int end)
168: throws ConditionThrowable {
169: SimpleVector v = new SimpleVector(end - start);
170: int i = start, j = 0;
171: try {
172: while (i < end)
173: v.setRowMajor(j++, getRowMajor(i++));
174: return v;
175: } catch (ArrayIndexOutOfBoundsException e) {
176: return signal(new TypeError("Array index out of bounds: "
177: + i + "."));
178: }
179: }
180:
181: public void fill(LispObject obj) throws ConditionThrowable {
182: for (int i = capacity; i-- > 0;)
183: elements[i] = obj;
184: }
185:
186: public void shrink(int n) throws ConditionThrowable {
187: if (elements != null) {
188: if (n < elements.length) {
189: LispObject[] newArray = new LispObject[n];
190: System.arraycopy(elements, 0, newArray, 0, n);
191: elements = newArray;
192: capacity = n;
193: return;
194: }
195: if (n == elements.length)
196: return;
197: }
198: signal(new LispError());
199: }
200:
201: public LispObject reverse() throws ConditionThrowable {
202: int length = length();
203: SimpleVector result = new SimpleVector(length);
204: int i, j;
205: for (i = 0, j = length - 1; i < length; i++, j--)
206: result.setRowMajor(i, getRowMajor(j));
207: return result;
208: }
209:
210: public LispObject nreverse() throws ConditionThrowable {
211: int i = 0;
212: int j = length() - 1;
213: while (i < j) {
214: LispObject temp = elements[i];
215: elements[i] = elements[j];
216: elements[j] = temp;
217: ++i;
218: --j;
219: }
220: return this ;
221: }
222:
223: public LispObject vectorPushExtend(LispObject element)
224: throws ConditionThrowable {
225: if (fillPointer < 0)
226: noFillPointer();
227: if (fillPointer >= capacity) {
228: // Need to extend vector.
229: ensureCapacity(capacity * 2 + 1);
230: }
231: setRowMajor(fillPointer, element);
232: return new Fixnum(fillPointer++);
233: }
234:
235: public LispObject vectorPushExtend(LispObject element,
236: LispObject extension) throws ConditionThrowable {
237: int ext = Fixnum.getValue(extension);
238: if (fillPointer < 0)
239: noFillPointer();
240: if (fillPointer >= capacity) {
241: // Need to extend vector.
242: ext = Math.max(ext, capacity + 1);
243: ensureCapacity(capacity + ext);
244: }
245: setRowMajor(fillPointer, element);
246: return new Fixnum(fillPointer++);
247: }
248:
249: private final void ensureCapacity(int minCapacity)
250: throws ConditionThrowable {
251: if (elements != null) {
252: if (capacity < minCapacity) {
253: LispObject[] newArray = new LispObject[minCapacity];
254: System.arraycopy(elements, 0, newArray, 0, capacity);
255: elements = newArray;
256: capacity = minCapacity;
257: }
258: } else {
259: Debug.assertTrue(array != null);
260: if (array.getTotalSize() - displacement < minCapacity) {
261: // Copy array.
262: elements = new LispObject[minCapacity];
263: final int limit = array.getTotalSize() - displacement;
264: for (int i = 0; i < limit; i++)
265: elements[i] = array.getRowMajor(displacement + i);
266: capacity = minCapacity;
267: array = null;
268: displacement = 0;
269: isDisplaced = false;
270: }
271: }
272: }
273:
274: public AbstractVector adjustVector(int newCapacity,
275: LispObject initialElement, LispObject initialContents)
276: throws ConditionThrowable {
277: if (initialContents != NIL) {
278: // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE-
279: // ARRAY. In this case none of the original contents of array
280: // appears in the resulting array."
281: LispObject[] newElements = new LispObject[newCapacity];
282: if (initialContents.listp()) {
283: LispObject list = initialContents;
284: for (int i = 0; i < newCapacity; i++) {
285: newElements[i] = list.car();
286: list = list.cdr();
287: }
288: } else if (initialContents.vectorp()) {
289: for (int i = 0; i < newCapacity; i++)
290: newElements[i] = initialContents.elt(i);
291: } else
292: signal(new TypeError(initialContents, Symbol.SEQUENCE));
293: elements = newElements;
294: } else {
295: if (elements == null) {
296: // Displaced array. Copy existing elements.
297: elements = new LispObject[newCapacity];
298: final int limit = Math.min(capacity, newCapacity);
299: for (int i = 0; i < limit; i++)
300: elements[i] = array.getRowMajor(displacement + i);
301: } else if (capacity != newCapacity) {
302: LispObject[] newElements = new LispObject[newCapacity];
303: System.arraycopy(elements, 0, newElements, 0, Math.min(
304: capacity, newCapacity));
305: elements = newElements;
306: }
307: // Initialize new elements (if any).
308: for (int i = capacity; i < newCapacity; i++)
309: elements[i] = initialElement;
310: }
311: capacity = newCapacity;
312: array = null;
313: displacement = 0;
314: isDisplaced = false;
315: return this ;
316: }
317:
318: public AbstractVector adjustVector(int newCapacity,
319: AbstractArray displacedTo, int displacement)
320: throws ConditionThrowable {
321: capacity = newCapacity;
322: array = displacedTo;
323: this .displacement = displacement;
324: elements = null;
325: isDisplaced = true;
326: return this;
327: }
328: }
|