1 /*
2  * ComplexVector.java
3  *
4  * Copyright (C) 2002-2007 Peter Graves
5  * $Id$
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  *
21  * As a special exception, the copyright holders of this library give you
22  * permission to link this library with independent modules to produce an
23  * executable, regardless of the license terms of these independent
24  * modules, and to copy and distribute the resulting executable under
25  * terms of your choice, provided that you also meet, for each linked
26  * independent module, the terms and conditions of the license of that
27  * module.  An independent module is a module which is not derived from
28  * or based on this library.  If you modify this library, you may extend
29  * this exception to your version of the library, but you are not
30  * obligated to do so.  If you do not wish to do so, delete this
31  * exception statement from your version.
32  */
33 
34 package org.armedbear.lisp;
35 
36 import static org.armedbear.lisp.Lisp.*;
37 
38 // A vector that is displaced to another array, has a fill pointer, and/or is
39 // expressly adjustable. It can hold elements of any type.
40 public final class ComplexVector extends AbstractVector
41 {
42     private int capacity;
43     private int fillPointer = -1; // -1 indicates no fill pointer.
44     private boolean isDisplaced;
45 
46     // For non-displaced arrays.
47     private LispObject[] elements;
48 
49     // For displaced arrays.
50     private AbstractArray array;
51     private int displacement;
52 
ComplexVector(int capacity)53     public ComplexVector(int capacity)
54     {
55         elements = new LispObject[capacity];
56         for (int i = capacity; i-- > 0;)
57             elements[i] = Fixnum.ZERO;
58         this.capacity = capacity;
59     }
60 
ComplexVector(int capacity, AbstractArray array, int displacement)61     public ComplexVector(int capacity, AbstractArray array, int displacement)
62     {
63         this.capacity = capacity;
64         this.array = array;
65         this.displacement = displacement;
66         isDisplaced = true;
67     }
68 
69     @Override
typeOf()70     public LispObject typeOf()
71     {
72         return list(Symbol.VECTOR, T, Fixnum.getInstance(capacity));
73     }
74 
75     @Override
classOf()76     public LispObject classOf()
77     {
78         return BuiltInClass.VECTOR;
79     }
80 
81     @Override
hasFillPointer()82     public boolean hasFillPointer()
83     {
84         return fillPointer >= 0;
85     }
86 
87     @Override
getFillPointer()88     public int getFillPointer()
89     {
90         return fillPointer;
91     }
92 
93     @Override
setFillPointer(int n)94     public void setFillPointer(int n)
95     {
96         fillPointer = n;
97     }
98 
99     @Override
setFillPointer(LispObject obj)100     public void setFillPointer(LispObject obj)
101     {
102         if (obj == T)
103             fillPointer = capacity();
104         else {
105             int n = Fixnum.getValue(obj);
106             if (n > capacity()) {
107                 StringBuffer sb = new StringBuffer("The new fill pointer (");
108                 sb.append(n);
109                 sb.append(") exceeds the capacity of the vector (");
110                 sb.append(capacity());
111                 sb.append(").");
112                 error(new LispError(sb.toString()));
113             } else if (n < 0) {
114                 StringBuffer sb = new StringBuffer("The new fill pointer (");
115                 sb.append(n);
116                 sb.append(") is negative.");
117                 error(new LispError(sb.toString()));
118             } else
119                 fillPointer = n;
120         }
121     }
122 
123     @Override
isDisplaced()124     public boolean isDisplaced()
125     {
126         return isDisplaced;
127     }
128 
129     @Override
arrayDisplacement()130     public LispObject arrayDisplacement()
131     {
132         LispObject value1, value2;
133         if (array != null) {
134             value1 = array;
135             value2 = Fixnum.getInstance(displacement);
136         } else {
137             value1 = NIL;
138             value2 = Fixnum.ZERO;
139         }
140         return LispThread.currentThread().setValues(value1, value2);
141     }
142 
143     @Override
getElementType()144     public LispObject getElementType()
145     {
146         return T;
147     }
148 
149     @Override
isSimpleVector()150     public boolean isSimpleVector()
151     {
152         return false;
153     }
154 
155     @Override
capacity()156     public int capacity()
157     {
158         return capacity;
159     }
160 
161     @Override
length()162     public int length()
163     {
164         return fillPointer >= 0 ? fillPointer : capacity;
165     }
166 
167     @Override
elt(int index)168     public LispObject elt(int index)
169     {
170         final int limit = length();
171         if (index < 0 || index >= limit)
172             badIndex(index, limit);
173         return AREF(index);
174     }
175 
176     // Ignores fill pointer.
177     @Override
AREF(int index)178     public LispObject AREF(int index)
179     {
180         if (elements != null) {
181             try {
182                 return elements[index];
183             }
184             catch (ArrayIndexOutOfBoundsException e) {
185                 badIndex(index, elements.length);
186                 return NIL; // Not reached.
187             }
188         } else {
189             // Displaced array.
190             if (index < 0 || index >= capacity)
191                 badIndex(index, capacity);
192             return array.AREF(index + displacement);
193         }
194     }
195 
196     @Override
aset(int index, LispObject newValue)197     public void aset(int index, LispObject newValue)
198     {
199         if (elements != null) {
200             try {
201                 elements[index] = newValue;
202             }
203             catch (ArrayIndexOutOfBoundsException e) {
204                 badIndex(index, elements.length);
205             }
206         } else {
207             // Displaced array.
208             if (index < 0 || index >= capacity)
209                 badIndex(index, capacity);
210             else
211                 array.aset(index + displacement, newValue);
212         }
213     }
214 
215     @Override
subseq(int start, int end)216     public LispObject subseq(int start, int end)
217     {
218         SimpleVector v = new SimpleVector(end - start);
219         int i = start, j = 0;
220         try {
221             while (i < end)
222                 v.aset(j++, AREF(i++));
223             return v;
224         }
225         catch (ArrayIndexOutOfBoundsException e) {
226             return error(new TypeError("Array index out of bounds: " + i + "."));
227         }
228     }
229 
230     @Override
fill(LispObject obj)231     public void fill(LispObject obj)
232     {
233         for (int i = capacity; i-- > 0;)
234             elements[i] = obj;
235     }
236 
237     @Override
shrink(int n)238     public void shrink(int n)
239     {
240         if (elements != null) {
241             if (n < elements.length) {
242                 LispObject[] newArray = new LispObject[n];
243                 System.arraycopy(elements, 0, newArray, 0, n);
244                 elements = newArray;
245                 capacity = n;
246                 return;
247             }
248             if (n == elements.length)
249                 return;
250         }
251         error(new LispError());
252     }
253 
254     @Override
reverse()255     public LispObject reverse()
256     {
257         int length = length();
258         SimpleVector result = new SimpleVector(length);
259         int i, j;
260         for (i = 0, j = length - 1; i < length; i++, j--)
261             result.aset(i, AREF(j));
262         return result;
263     }
264 
265     @Override
nreverse()266     public LispObject nreverse()
267     {
268         if (elements != null) {
269             int i = 0;
270             int j = length() - 1;
271             while (i < j) {
272                 LispObject temp = elements[i];
273                 elements[i] = elements[j];
274                 elements[j] = temp;
275                 ++i;
276                 --j;
277             }
278         } else {
279             // Displaced array.
280             int length = length();
281             LispObject[] data = new LispObject[length];
282             int i, j;
283             for (i = 0, j = length - 1; i < length; i++, j--)
284                 data[i] = AREF(j);
285             elements = data;
286             capacity = length;
287             array = null;
288             displacement = 0;
289             isDisplaced = false;
290             fillPointer = -1;
291         }
292         return this;
293     }
294 
295     @Override
vectorPushExtend(LispObject element)296     public void vectorPushExtend(LispObject element)
297 
298     {
299         if (fillPointer < 0)
300             noFillPointer();
301         if (fillPointer >= capacity) {
302             // Need to extend vector.
303             ensureCapacity(capacity * 2 + 1);
304         }
305         aset(fillPointer++, element);
306     }
307 
308     @Override
VECTOR_PUSH_EXTEND(LispObject element)309     public LispObject VECTOR_PUSH_EXTEND(LispObject element)
310 
311     {
312         vectorPushExtend(element);
313         return Fixnum.getInstance(fillPointer - 1);
314     }
315 
316     @Override
VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)317     public LispObject VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)
318 
319     {
320         int ext = Fixnum.getValue(extension);
321         if (fillPointer < 0)
322             noFillPointer();
323         if (fillPointer >= capacity) {
324             // Need to extend vector.
325             ext = Math.max(ext, capacity + 1);
326             ensureCapacity(capacity + ext);
327         }
328         aset(fillPointer, element);
329         return Fixnum.getInstance(fillPointer++);
330     }
331 
ensureCapacity(int minCapacity)332     private final void ensureCapacity(int minCapacity)
333     {
334         if (elements != null) {
335             if (capacity < minCapacity) {
336                 LispObject[] newArray = new LispObject[minCapacity];
337                 System.arraycopy(elements, 0, newArray, 0, capacity);
338                 elements = newArray;
339                 capacity = minCapacity;
340             }
341         } else {
342             // Displaced array.
343             Debug.assertTrue(array != null);
344             if (capacity < minCapacity ||
345                 array.getTotalSize() - displacement < minCapacity)
346             {
347                 // Copy array.
348                 elements = new LispObject[minCapacity];
349                 final int limit =
350                     Math.min(capacity, array.getTotalSize() - displacement);
351                 for (int i = 0; i < limit; i++)
352                     elements[i] = array.AREF(displacement + i);
353                 capacity = minCapacity;
354                 array = null;
355                 displacement = 0;
356                 isDisplaced = false;
357             }
358         }
359     }
360 
361     @Override
adjustArray(int newCapacity, LispObject initialElement, LispObject initialContents)362     public AbstractVector adjustArray(int newCapacity,
363                                        LispObject initialElement,
364                                        LispObject initialContents)
365 
366     {
367         if (initialContents != null) {
368             // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE-
369             // ARRAY. In this case none of the original contents of array
370             // appears in the resulting array."
371             LispObject[] newElements = new LispObject[newCapacity];
372             if (initialContents.listp()) {
373                 LispObject list = initialContents;
374                 for (int i = 0; i < newCapacity; i++) {
375                     newElements[i] = list.car();
376                     list = list.cdr();
377                 }
378             } else if (initialContents.vectorp()) {
379                 for (int i = 0; i < newCapacity; i++)
380                     newElements[i] = initialContents.elt(i);
381             } else
382                 type_error(initialContents, Symbol.SEQUENCE);
383             elements = newElements;
384         } else {
385             if (elements == null) {
386                 // Displaced array. Copy existing elements.
387                 elements = new LispObject[newCapacity];
388                 final int limit = Math.min(capacity, newCapacity);
389                 for (int i = 0; i < limit; i++)
390                     elements[i] = array.AREF(displacement + i);
391             } else if (capacity != newCapacity) {
392                 LispObject[] newElements = new LispObject[newCapacity];
393                 System.arraycopy(elements, 0, newElements, 0,
394                                  Math.min(capacity, newCapacity));
395                 elements = newElements;
396             }
397             // Initialize new elements (if any).
398             if (initialElement != null)
399                 for (int i = capacity; i < newCapacity; i++)
400                     elements[i] = initialElement;
401         }
402         capacity = newCapacity;
403         array = null;
404         displacement = 0;
405         isDisplaced = false;
406         return this;
407     }
408 
409     @Override
adjustArray(int newCapacity, AbstractArray displacedTo, int displacement)410     public AbstractVector adjustArray(int newCapacity,
411                                        AbstractArray displacedTo,
412                                        int displacement)
413 
414     {
415         capacity = newCapacity;
416         array = displacedTo;
417         this.displacement = displacement;
418         elements = null;
419         isDisplaced = true;
420         return this;
421     }
422 }
423